aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShaun Pereira <spereira@tusc.com.au>2005-06-23 01:15:01 -0400
committerDavid S. Miller <davem@davemloft.net>2005-06-23 01:15:01 -0400
commitcb65d506c34c86df5bcef939ce5a8666a451bd8b (patch)
tree4cf281ba2e90c9c20d28a80d1efc8292aaba699a
parent68d318720052154bc6b2513b0f15d0d947cc53c9 (diff)
[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>
-rw-r--r--include/linux/x25.h10
-rw-r--r--include/net/x25.h3
-rw-r--r--net/x25/af_x25.c73
-rw-r--r--net/x25/x25_subr.c18
4 files changed, 59 insertions, 45 deletions
diff --git a/include/linux/x25.h b/include/linux/x25.h
index 7531cfed5885..6f43b3d20248 100644
--- a/include/linux/x25.h
+++ b/include/linux/x25.h
@@ -4,6 +4,8 @@
4 * History 4 * History
5 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities 5 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
6 * negotiation. 6 * negotiation.
7 * apr/02/05 Shaun Pereira Selective sub address matching with
8 * call user data
7 */ 9 */
8 10
9#ifndef X25_KERNEL_H 11#ifndef X25_KERNEL_H
@@ -16,6 +18,7 @@
16#define SIOCX25GCALLUSERDATA (SIOCPROTOPRIVATE + 4) 18#define SIOCX25GCALLUSERDATA (SIOCPROTOPRIVATE + 4)
17#define SIOCX25SCALLUSERDATA (SIOCPROTOPRIVATE + 5) 19#define SIOCX25SCALLUSERDATA (SIOCPROTOPRIVATE + 5)
18#define SIOCX25GCAUSEDIAG (SIOCPROTOPRIVATE + 6) 20#define SIOCX25GCAUSEDIAG (SIOCPROTOPRIVATE + 6)
21#define SIOCX25SCUDMATCHLEN (SIOCPROTOPRIVATE + 7)
19 22
20/* 23/*
21 * Values for {get,set}sockopt. 24 * Values for {get,set}sockopt.
@@ -109,4 +112,11 @@ struct x25_causediag {
109 unsigned char diagnostic; 112 unsigned char diagnostic;
110}; 113};
111 114
115/*
116 * Further optional call user data match length selection
117 */
118struct x25_subaddr {
119 unsigned int cudmatchlength;
120};
121
112#endif 122#endif
diff --git a/include/net/x25.h b/include/net/x25.h
index 7a1ba5bbb868..9dd70dd4a9b7 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -134,7 +134,7 @@ struct x25_sock {
134 struct sock sk; 134 struct sock sk;
135 struct x25_address source_addr, dest_addr; 135 struct x25_address source_addr, dest_addr;
136 struct x25_neigh *neighbour; 136 struct x25_neigh *neighbour;
137 unsigned int lci; 137 unsigned int lci, cudmatchlength;
138 unsigned char state, condition, qbitincl, intflag; 138 unsigned char state, condition, qbitincl, intflag;
139 unsigned short vs, vr, va, vl; 139 unsigned short vs, vr, va, vl;
140 unsigned long t2, t21, t22, t23; 140 unsigned long t2, t21, t22, t23;
@@ -242,7 +242,6 @@ extern int x25_validate_nr(struct sock *, unsigned short);
242extern void x25_write_internal(struct sock *, int); 242extern void x25_write_internal(struct sock *, int);
243extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *); 243extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *);
244extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char); 244extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char);
245extern int x25_check_calluserdata(struct x25_calluserdata *,struct x25_calluserdata *);
246 245
247/* x25_timer.c */ 246/* x25_timer.c */
248extern void x25_start_heartbeat(struct sock *); 247extern void x25_start_heartbeat(struct sock *);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 2a24b243b841..e17d84a55d5e 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -29,6 +29,8 @@
29 * 2000-11-14 Henner Eisen Closing datalink from NETDEV_GOING_DOWN 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 30 * 2002-10-06 Arnaldo C. Melo Get rid of cli/sti, move proc stuff to
31 * x25_proc.c, using seq_file 31 * x25_proc.c, using seq_file
32 * 2005-04-02 Shaun Pereira Selective sub address matching
33 * with call user data
32 */ 34 */
33 35
34#include <linux/config.h> 36#include <linux/config.h>
@@ -219,7 +221,8 @@ static void x25_insert_socket(struct sock *sk)
219 * Note: if a listening socket has cud set it must only get calls 221 * Note: if a listening socket has cud set it must only get calls
220 * with matching cud. 222 * with matching cud.
221 */ 223 */
222static struct sock *x25_find_listener(struct x25_address *addr, struct x25_calluserdata *calluserdata) 224static struct sock *x25_find_listener(struct x25_address *addr,
225 struct sk_buff *skb)
223{ 226{
224 struct sock *s; 227 struct sock *s;
225 struct sock *next_best; 228 struct sock *next_best;
@@ -230,22 +233,23 @@ static struct sock *x25_find_listener(struct x25_address *addr, struct x25_callu
230 233
231 sk_for_each(s, node, &x25_list) 234 sk_for_each(s, node, &x25_list)
232 if ((!strcmp(addr->x25_addr, 235 if ((!strcmp(addr->x25_addr,
233 x25_sk(s)->source_addr.x25_addr) || 236 x25_sk(s)->source_addr.x25_addr) ||
234 !strcmp(addr->x25_addr, 237 !strcmp(addr->x25_addr,
235 null_x25_address.x25_addr)) && 238 null_x25_address.x25_addr)) &&
236 s->sk_state == TCP_LISTEN) { 239 s->sk_state == TCP_LISTEN) {
237
238 /* 240 /*
239 * Found a listening socket, now check the incoming 241 * Found a listening socket, now check the incoming
240 * call user data vs this sockets call user data 242 * call user data vs this sockets call user data
241 */ 243 */
242 if (x25_check_calluserdata(&x25_sk(s)->calluserdata, calluserdata)) { 244 if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
243 sock_hold(s); 245 if((memcmp(x25_sk(s)->calluserdata.cuddata,
244 goto found; 246 skb->data,
245 } 247 x25_sk(s)->cudmatchlength)) == 0) {
246 if (x25_sk(s)->calluserdata.cudlength == 0) { 248 sock_hold(s);
249 goto found;
250 }
251 } else
247 next_best = s; 252 next_best = s;
248 }
249 } 253 }
250 if (next_best) { 254 if (next_best) {
251 s = next_best; 255 s = next_best;
@@ -497,6 +501,7 @@ static int x25_create(struct socket *sock, int protocol)
497 x25->t23 = sysctl_x25_clear_request_timeout; 501 x25->t23 = sysctl_x25_clear_request_timeout;
498 x25->t2 = sysctl_x25_ack_holdback_timeout; 502 x25->t2 = sysctl_x25_ack_holdback_timeout;
499 x25->state = X25_STATE_0; 503 x25->state = X25_STATE_0;
504 x25->cudmatchlength = 0;
500 505
501 x25->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE; 506 x25->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE;
502 x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE; 507 x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
@@ -545,6 +550,7 @@ static struct sock *x25_make_new(struct sock *osk)
545 x25->t2 = ox25->t2; 550 x25->t2 = ox25->t2;
546 x25->facilities = ox25->facilities; 551 x25->facilities = ox25->facilities;
547 x25->qbitincl = ox25->qbitincl; 552 x25->qbitincl = ox25->qbitincl;
553 x25->cudmatchlength = ox25->cudmatchlength;
548 554
549 x25_init_timers(sk); 555 x25_init_timers(sk);
550out: 556out:
@@ -822,7 +828,6 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
822 struct x25_sock *makex25; 828 struct x25_sock *makex25;
823 struct x25_address source_addr, dest_addr; 829 struct x25_address source_addr, dest_addr;
824 struct x25_facilities facilities; 830 struct x25_facilities facilities;
825 struct x25_calluserdata calluserdata;
826 int len, rc; 831 int len, rc;
827 832
828 /* 833 /*
@@ -845,19 +850,10 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
845 skb_pull(skb,len); 850 skb_pull(skb,len);
846 851
847 /* 852 /*
848 * Incoming Call User Data.
849 */
850 if (skb->len >= 0) {
851 memcpy(calluserdata.cuddata, skb->data, skb->len);
852 calluserdata.cudlength = skb->len;
853 }
854
855 skb_push(skb,len);
856
857 /*
858 * Find a listener for the particular address/cud pair. 853 * Find a listener for the particular address/cud pair.
859 */ 854 */
860 sk = x25_find_listener(&source_addr,&calluserdata); 855 sk = x25_find_listener(&source_addr,skb);
856 skb_push(skb,len);
861 857
862 /* 858 /*
863 * We can't accept the Call Request. 859 * We can't accept the Call Request.
@@ -900,12 +896,22 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
900 makex25->neighbour = nb; 896 makex25->neighbour = nb;
901 makex25->facilities = facilities; 897 makex25->facilities = facilities;
902 makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; 898 makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
903 makex25->calluserdata = calluserdata; 899 /* ensure no reverse facil on accept */
900 makex25->vc_facil_mask &= ~X25_MASK_REVERSE;
901 makex25->cudmatchlength = x25_sk(sk)->cudmatchlength;
904 902
905 x25_write_internal(make, X25_CALL_ACCEPTED); 903 x25_write_internal(make, X25_CALL_ACCEPTED);
906 904
907 makex25->state = X25_STATE_3; 905 makex25->state = X25_STATE_3;
908 906
907 /*
908 * Incoming Call User Data.
909 */
910 if (skb->len >= 0) {
911 memcpy(makex25->calluserdata.cuddata, skb->data, skb->len);
912 makex25->calluserdata.cudlength = skb->len;
913 }
914
909 sk->sk_ack_backlog++; 915 sk->sk_ack_backlog++;
910 916
911 x25_insert_socket(make); 917 x25_insert_socket(make);
@@ -1325,6 +1331,23 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
1325 break; 1331 break;
1326 } 1332 }
1327 1333
1334 case SIOCX25SCUDMATCHLEN: {
1335 struct x25_subaddr sub_addr;
1336 rc = -EINVAL;
1337 if(sk->sk_state != TCP_CLOSE)
1338 break;
1339 rc = -EFAULT;
1340 if (copy_from_user(&sub_addr, argp,
1341 sizeof(sub_addr)))
1342 break;
1343 rc = -EINVAL;
1344 if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
1345 break;
1346 x25->cudmatchlength = sub_addr.cudmatchlength;
1347 rc = 0;
1348 break;
1349 }
1350
1328 default: 1351 default:
1329 rc = dev_ioctl(cmd, argp); 1352 rc = dev_ioctl(cmd, argp);
1330 break; 1353 break;
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index 183fea3bba67..c349bbd61684 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -354,21 +354,3 @@ void x25_check_rbuf(struct sock *sk)
354 } 354 }
355} 355}
356 356
357/*
358 * Compare 2 calluserdata structures, used to find correct listening sockets
359 * when call user data is used.
360 */
361int 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