[X25]: Selective sub-address matching with call user data.

From: Shaun Pereira <spereira@tusc.com.au>

This is the first (independent of the second) patch of two that I am
working on with x25 on linux (tested with xot on a cisco router). Details
are as follows.

Current state of module:

A server using the current implementation (2.6.11.7) of the x25 module will
accept a call request/ incoming call packet at the listening x.25 address,
from all callers to that address, as long as NO call user data is present
in the packet header.

If the server needs to choose to accept a particular call request/ incoming
call packet arriving at its listening x25 address, then the kernel has to
allow a match of call user data present in the call request packet with its
own. This is required when multiple servers listen at the same x25 address
and device interface. The kernel currently matches ALL call user data, if
present.

Current Changes:

This patch is a follow up to the patch submitted previously by Andrew
Hendry, and allows the user to selectively control the number of octets of
call user data in the call request packet, that the kernel will match. By
default no call user data is matched, even if call user data is present.
To allow call user data matching, a cudmatchlength > 0 has to be passed
into the kernel after which the passed number of octets will be matched.
Otherwise the kernel behavior is exactly as the original implementation.

This patch also ensures that as is normally the case, no call user data
will be present in the Call accepted / call connected packet sent back to
the caller

Future Changes on next patch:

There are cases however when call user data may be present in the call
accepted packet. According to the X.25 recommendation (ITU-T 10/96)
section 5.2.3.2 call user data may be present in the call accepted packet
provided the fast select facility is used. My next patch will include this
fast select utility and the ability to send up to 128 octets call user data
in the call accepted packet provided the fast select facility is used. I
am currently testing this, again with xot on linux and cisco.

Signed-off-by: Shaun Pereira <spereira@tusc.com.au>

(With a fix from Alexey Dobriyan <adobriyan@gmail.com>)
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Shaun Pereira and committed by David S. Miller cb65d506 68d31872

+59 -45
+10
include/linux/x25.h
··· 4 * History 5 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities 6 * negotiation. 7 */ 8 9 #ifndef X25_KERNEL_H ··· 18 #define SIOCX25GCALLUSERDATA (SIOCPROTOPRIVATE + 4) 19 #define SIOCX25SCALLUSERDATA (SIOCPROTOPRIVATE + 5) 20 #define SIOCX25GCAUSEDIAG (SIOCPROTOPRIVATE + 6) 21 22 /* 23 * Values for {get,set}sockopt. ··· 110 struct x25_causediag { 111 unsigned char cause; 112 unsigned char diagnostic; 113 }; 114 115 #endif
··· 4 * History 5 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities 6 * negotiation. 7 + * apr/02/05 Shaun Pereira Selective sub address matching with 8 + * call user data 9 */ 10 11 #ifndef X25_KERNEL_H ··· 16 #define SIOCX25GCALLUSERDATA (SIOCPROTOPRIVATE + 4) 17 #define SIOCX25SCALLUSERDATA (SIOCPROTOPRIVATE + 5) 18 #define SIOCX25GCAUSEDIAG (SIOCPROTOPRIVATE + 6) 19 + #define SIOCX25SCUDMATCHLEN (SIOCPROTOPRIVATE + 7) 20 21 /* 22 * Values for {get,set}sockopt. ··· 107 struct x25_causediag { 108 unsigned char cause; 109 unsigned char diagnostic; 110 + }; 111 + 112 + /* 113 + * Further optional call user data match length selection 114 + */ 115 + struct x25_subaddr { 116 + unsigned int cudmatchlength; 117 }; 118 119 #endif
+1 -2
include/net/x25.h
··· 134 struct sock sk; 135 struct x25_address source_addr, dest_addr; 136 struct x25_neigh *neighbour; 137 - unsigned int lci; 138 unsigned char state, condition, qbitincl, intflag; 139 unsigned short vs, vr, va, vl; 140 unsigned long t2, t21, t22, t23; ··· 242 extern void x25_write_internal(struct sock *, int); 243 extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *); 244 extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char); 245 - extern int x25_check_calluserdata(struct x25_calluserdata *,struct x25_calluserdata *); 246 247 /* x25_timer.c */ 248 extern void x25_start_heartbeat(struct sock *);
··· 134 struct sock sk; 135 struct x25_address source_addr, dest_addr; 136 struct x25_neigh *neighbour; 137 + unsigned int lci, cudmatchlength; 138 unsigned char state, condition, qbitincl, intflag; 139 unsigned short vs, vr, va, vl; 140 unsigned long t2, t21, t22, t23; ··· 242 extern void x25_write_internal(struct sock *, int); 243 extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *); 244 extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char); 245 246 /* x25_timer.c */ 247 extern void x25_start_heartbeat(struct sock *);
+48 -25
net/x25/af_x25.c
··· 29 * 2000-11-14 Henner Eisen Closing datalink from NETDEV_GOING_DOWN 30 * 2002-10-06 Arnaldo C. Melo Get rid of cli/sti, move proc stuff to 31 * x25_proc.c, using seq_file 32 */ 33 34 #include <linux/config.h> ··· 221 * Note: if a listening socket has cud set it must only get calls 222 * with matching cud. 223 */ 224 - static struct sock *x25_find_listener(struct x25_address *addr, struct x25_calluserdata *calluserdata) 225 { 226 struct sock *s; 227 struct sock *next_best; ··· 233 234 sk_for_each(s, node, &x25_list) 235 if ((!strcmp(addr->x25_addr, 236 - x25_sk(s)->source_addr.x25_addr) || 237 - !strcmp(addr->x25_addr, 238 - null_x25_address.x25_addr)) && 239 - s->sk_state == TCP_LISTEN) { 240 - 241 /* 242 * Found a listening socket, now check the incoming 243 * call user data vs this sockets call user data 244 */ 245 - if (x25_check_calluserdata(&x25_sk(s)->calluserdata, calluserdata)) { 246 - sock_hold(s); 247 - goto found; 248 - } 249 - if (x25_sk(s)->calluserdata.cudlength == 0) { 250 next_best = s; 251 - } 252 } 253 if (next_best) { 254 s = next_best; ··· 501 x25->t23 = sysctl_x25_clear_request_timeout; 502 x25->t2 = sysctl_x25_ack_holdback_timeout; 503 x25->state = X25_STATE_0; 504 505 x25->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE; 506 x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE; ··· 550 x25->t2 = ox25->t2; 551 x25->facilities = ox25->facilities; 552 x25->qbitincl = ox25->qbitincl; 553 554 x25_init_timers(sk); 555 out: ··· 828 struct x25_sock *makex25; 829 struct x25_address source_addr, dest_addr; 830 struct x25_facilities facilities; 831 - struct x25_calluserdata calluserdata; 832 int len, rc; 833 834 /* ··· 850 skb_pull(skb,len); 851 852 /* 853 - * Incoming Call User Data. 854 - */ 855 - if (skb->len >= 0) { 856 - memcpy(calluserdata.cuddata, skb->data, skb->len); 857 - calluserdata.cudlength = skb->len; 858 - } 859 - 860 - skb_push(skb,len); 861 - 862 - /* 863 * Find a listener for the particular address/cud pair. 864 */ 865 - sk = x25_find_listener(&source_addr,&calluserdata); 866 867 /* 868 * We can't accept the Call Request. ··· 896 makex25->neighbour = nb; 897 makex25->facilities = facilities; 898 makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; 899 - makex25->calluserdata = calluserdata; 900 901 x25_write_internal(make, X25_CALL_ACCEPTED); 902 903 makex25->state = X25_STATE_3; 904 905 sk->sk_ack_backlog++; 906 ··· 1328 causediag = x25->causediag; 1329 rc = copy_to_user(argp, &causediag, 1330 sizeof(causediag)) ? -EFAULT : 0; 1331 break; 1332 } 1333
··· 29 * 2000-11-14 Henner Eisen Closing datalink from NETDEV_GOING_DOWN 30 * 2002-10-06 Arnaldo C. Melo Get rid of cli/sti, move proc stuff to 31 * x25_proc.c, using seq_file 32 + * 2005-04-02 Shaun Pereira Selective sub address matching 33 + * with call user data 34 */ 35 36 #include <linux/config.h> ··· 219 * Note: if a listening socket has cud set it must only get calls 220 * with matching cud. 221 */ 222 + static struct sock *x25_find_listener(struct x25_address *addr, 223 + struct sk_buff *skb) 224 { 225 struct sock *s; 226 struct sock *next_best; ··· 230 231 sk_for_each(s, node, &x25_list) 232 if ((!strcmp(addr->x25_addr, 233 + x25_sk(s)->source_addr.x25_addr) || 234 + !strcmp(addr->x25_addr, 235 + null_x25_address.x25_addr)) && 236 + s->sk_state == TCP_LISTEN) { 237 /* 238 * Found a listening socket, now check the incoming 239 * call user data vs this sockets call user data 240 */ 241 + if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) { 242 + if((memcmp(x25_sk(s)->calluserdata.cuddata, 243 + skb->data, 244 + x25_sk(s)->cudmatchlength)) == 0) { 245 + sock_hold(s); 246 + goto found; 247 + } 248 + } else 249 next_best = s; 250 } 251 if (next_best) { 252 s = next_best; ··· 497 x25->t23 = sysctl_x25_clear_request_timeout; 498 x25->t2 = sysctl_x25_ack_holdback_timeout; 499 x25->state = X25_STATE_0; 500 + x25->cudmatchlength = 0; 501 502 x25->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE; 503 x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE; ··· 545 x25->t2 = ox25->t2; 546 x25->facilities = ox25->facilities; 547 x25->qbitincl = ox25->qbitincl; 548 + x25->cudmatchlength = ox25->cudmatchlength; 549 550 x25_init_timers(sk); 551 out: ··· 822 struct x25_sock *makex25; 823 struct x25_address source_addr, dest_addr; 824 struct x25_facilities facilities; 825 int len, rc; 826 827 /* ··· 845 skb_pull(skb,len); 846 847 /* 848 * Find a listener for the particular address/cud pair. 849 */ 850 + sk = x25_find_listener(&source_addr,skb); 851 + skb_push(skb,len); 852 853 /* 854 * We can't accept the Call Request. ··· 900 makex25->neighbour = nb; 901 makex25->facilities = facilities; 902 makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; 903 + /* ensure no reverse facil on accept */ 904 + makex25->vc_facil_mask &= ~X25_MASK_REVERSE; 905 + makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; 906 907 x25_write_internal(make, X25_CALL_ACCEPTED); 908 909 makex25->state = X25_STATE_3; 910 + 911 + /* 912 + * Incoming Call User Data. 913 + */ 914 + if (skb->len >= 0) { 915 + memcpy(makex25->calluserdata.cuddata, skb->data, skb->len); 916 + makex25->calluserdata.cudlength = skb->len; 917 + } 918 919 sk->sk_ack_backlog++; 920 ··· 1322 causediag = x25->causediag; 1323 rc = copy_to_user(argp, &causediag, 1324 sizeof(causediag)) ? -EFAULT : 0; 1325 + break; 1326 + } 1327 + 1328 + case SIOCX25SCUDMATCHLEN: { 1329 + struct x25_subaddr sub_addr; 1330 + rc = -EINVAL; 1331 + if(sk->sk_state != TCP_CLOSE) 1332 + break; 1333 + rc = -EFAULT; 1334 + if (copy_from_user(&sub_addr, argp, 1335 + sizeof(sub_addr))) 1336 + break; 1337 + rc = -EINVAL; 1338 + if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) 1339 + break; 1340 + x25->cudmatchlength = sub_addr.cudmatchlength; 1341 + rc = 0; 1342 break; 1343 } 1344
-18
net/x25/x25_subr.c
··· 354 } 355 } 356 357 - /* 358 - * Compare 2 calluserdata structures, used to find correct listening sockets 359 - * when call user data is used. 360 - */ 361 - int x25_check_calluserdata(struct x25_calluserdata *ours, struct x25_calluserdata *theirs) 362 - { 363 - int i; 364 - if (ours->cudlength != theirs->cudlength) 365 - return 0; 366 - 367 - for (i=0;i<ours->cudlength;i++) { 368 - if (ours->cuddata[i] != theirs->cuddata[i]) { 369 - return 0; 370 - } 371 - } 372 - return 1; 373 - } 374 -
··· 354 } 355 } 356