Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[X25]: allow ITU-T DTE facilities for x25

Allows use of the optional user facility to insert ITU-T
(http://www.itu.int/ITU-T/) specified DTE facilities in call set-up x25
packets. This feature is optional; no facilities will be added if the ioctl
is not used, and call setup packet remains the same as before.

If the ioctls provided by the patch are used, then a facility marker will be
added to the x25 packet header so that the called dte address extension
facility can be differentiated from other types of facilities (as described in
the ITU-T X.25 recommendation) that are also allowed in the x25 packet header.

Facility markers are made up of two octets, and may be present in the x25
packet headers of call-request, incoming call, call accepted, clear request,
and clear indication packets. The first of the two octets represents the
facility code field and is set to zero by this patch. The second octet of the
marker represents the facility parameter field and is set to 0x0F because the
marker will be inserted before ITU-T type DTE facilities.

Since according to ITU-T X.25 Recommendation X.25(10/96)- 7.1 "All networks
will support the facility markers with a facility parameter field set to all
ones or to 00001111", therefore this patch should work with all x.25 networks.

While there are many ITU-T DTE facilities, this patch implements only the
called and calling address extension, with placeholders in the
x25_dte_facilities structure for the rest of the facilities.

Testing:

This patch was tested using a cisco xot router connected on its serial ports
to an X.25 network, and on its lan ports to a host running an xotd daemon.

It is also possible to test this patch using an xotd daemon and an x25tap
patch, where the xotd daemons work back-to-back without actually using an x.25
network. See www.fyonne.net for details on how to do this.

Signed-off-by: Shaun Pereira <spereira@tusc.com.au>
Acked-by: Andrew Hendry <ahendry@tusc.com.au>
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
a64b7b93 bac37ec8

+163 -20
+26
include/linux/x25.h
··· 11 11 #ifndef X25_KERNEL_H 12 12 #define X25_KERNEL_H 13 13 14 + #include <linux/types.h> 15 + 14 16 #define SIOCX25GSUBSCRIP (SIOCPROTOPRIVATE + 0) 15 17 #define SIOCX25SSUBSCRIP (SIOCPROTOPRIVATE + 1) 16 18 #define SIOCX25GFACILITIES (SIOCPROTOPRIVATE + 2) ··· 23 21 #define SIOCX25SCUDMATCHLEN (SIOCPROTOPRIVATE + 7) 24 22 #define SIOCX25CALLACCPTAPPRV (SIOCPROTOPRIVATE + 8) 25 23 #define SIOCX25SENDCALLACCPT (SIOCPROTOPRIVATE + 9) 24 + #define SIOCX25GDTEFACILITIES (SIOCPROTOPRIVATE + 10) 25 + #define SIOCX25SDTEFACILITIES (SIOCPROTOPRIVATE + 11) 26 26 27 27 /* 28 28 * Values for {get,set}sockopt. ··· 81 77 #define X25_MASK_PACKET_SIZE 0x04 82 78 #define X25_MASK_WINDOW_SIZE 0x08 83 79 80 + #define X25_MASK_CALLING_AE 0x10 81 + #define X25_MASK_CALLED_AE 0x20 84 82 85 83 86 84 /* ··· 102 96 unsigned int pacsize_in, pacsize_out; 103 97 unsigned int throughput; 104 98 unsigned int reverse; 99 + }; 100 + 101 + /* 102 + * ITU DTE facilities 103 + * Only the called and calling address 104 + * extension are currently implemented. 105 + * The rest are in place to avoid the struct 106 + * changing size if someone needs them later 107 + */ 108 + 109 + struct x25_dte_facilities { 110 + __u16 delay_cumul; 111 + __u16 delay_target; 112 + __u16 delay_max; 113 + __u8 min_throughput; 114 + __u8 expedited; 115 + __u8 calling_len; 116 + __u8 called_len; 117 + __u8 calling_ae[20]; 118 + __u8 called_ae[20]; 105 119 }; 106 120 107 121 /*
+17 -4
include/net/x25.h
··· 101 101 #define X25_FAC_PACKET_SIZE 0x42 102 102 #define X25_FAC_WINDOW_SIZE 0x43 103 103 104 - #define X25_MAX_FAC_LEN 20 /* Plenty to spare */ 104 + #define X25_MAX_FAC_LEN 60 105 105 #define X25_MAX_CUD_LEN 128 106 + 107 + #define X25_FAC_CALLING_AE 0xCB 108 + #define X25_FAC_CALLED_AE 0xC9 109 + 110 + #define X25_MARKER 0x00 111 + #define X25_DTE_SERVICES 0x0F 112 + #define X25_MAX_AE_LEN 40 /* Max num of semi-octets in AE - OSI Nw */ 113 + #define X25_MAX_DTE_FACIL_LEN 21 /* Max length of DTE facility params */ 106 114 107 115 /** 108 116 * struct x25_route - x25 routing entry ··· 156 148 struct timer_list timer; 157 149 struct x25_causediag causediag; 158 150 struct x25_facilities facilities; 151 + struct x25_dte_facilities dte_facilities; 159 152 struct x25_calluserdata calluserdata; 160 153 unsigned long vc_facil_mask; /* inc_call facilities mask */ 161 154 }; ··· 189 180 extern void x25_terminate_link(struct x25_neigh *); 190 181 191 182 /* x25_facilities.c */ 192 - extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *, unsigned long *); 193 - extern int x25_create_facilities(unsigned char *, struct x25_facilities *, unsigned long); 194 - extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *); 183 + extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *, 184 + struct x25_dte_facilities *, unsigned long *); 185 + extern int x25_create_facilities(unsigned char *, struct x25_facilities *, 186 + struct x25_dte_facilities *, unsigned long); 187 + extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, 188 + struct x25_facilities *, 189 + struct x25_dte_facilities *); 195 190 extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); 196 191 197 192 /* x25_in.c */
+44 -1
net/x25/af_x25.c
··· 525 525 x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; 526 526 x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; 527 527 x25->facilities.reverse = X25_DEFAULT_REVERSE; 528 + x25->dte_facilities.calling_len = 0; 529 + x25->dte_facilities.called_len = 0; 530 + memset(x25->dte_facilities.called_ae, '\0', 531 + sizeof(x25->dte_facilities.called_ae)); 532 + memset(x25->dte_facilities.calling_ae, '\0', 533 + sizeof(x25->dte_facilities.calling_ae)); 534 + 528 535 rc = 0; 529 536 out: 530 537 return rc; ··· 568 561 x25->t2 = ox25->t2; 569 562 x25->facilities = ox25->facilities; 570 563 x25->qbitincl = ox25->qbitincl; 564 + x25->dte_facilities = ox25->dte_facilities; 571 565 x25->cudmatchlength = ox25->cudmatchlength; 572 566 x25->accptapprv = ox25->accptapprv; 573 567 ··· 848 840 struct x25_sock *makex25; 849 841 struct x25_address source_addr, dest_addr; 850 842 struct x25_facilities facilities; 843 + struct x25_dte_facilities dte_facilities; 851 844 int len, rc; 852 845 853 846 /* ··· 885 876 /* 886 877 * Try to reach a compromise on the requested facilities. 887 878 */ 888 - if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) 879 + len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities); 880 + if (len == -1) 889 881 goto out_sock_put; 890 882 891 883 /* ··· 917 907 makex25->source_addr = source_addr; 918 908 makex25->neighbour = nb; 919 909 makex25->facilities = facilities; 910 + makex25->dte_facilities= dte_facilities; 920 911 makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; 921 912 /* ensure no reverse facil on accept */ 922 913 makex25->vc_facil_mask &= ~X25_MASK_REVERSE; 914 + /* ensure no calling address extension on accept */ 915 + makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE; 923 916 makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; 924 917 925 918 /* Normally all calls are accepted immediatly */ ··· 1325 1312 (facilities.reverse | 0x81)!= 0x81) 1326 1313 break; 1327 1314 x25->facilities = facilities; 1315 + rc = 0; 1316 + break; 1317 + } 1318 + 1319 + case SIOCX25GDTEFACILITIES: { 1320 + rc = copy_to_user(argp, &x25->dte_facilities, 1321 + sizeof(x25->dte_facilities)); 1322 + if (rc) 1323 + rc = -EFAULT; 1324 + break; 1325 + } 1326 + 1327 + case SIOCX25SDTEFACILITIES: { 1328 + struct x25_dte_facilities dtefacs; 1329 + rc = -EFAULT; 1330 + if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) 1331 + break; 1332 + rc = -EINVAL; 1333 + if (sk->sk_state != TCP_LISTEN && 1334 + sk->sk_state != TCP_CLOSE) 1335 + break; 1336 + if (dtefacs.calling_len > X25_MAX_AE_LEN) 1337 + break; 1338 + if (dtefacs.calling_ae == NULL) 1339 + break; 1340 + if (dtefacs.called_len > X25_MAX_AE_LEN) 1341 + break; 1342 + if (dtefacs.called_ae == NULL) 1343 + break; 1344 + x25->dte_facilities = dtefacs; 1328 1345 rc = 0; 1329 1346 break; 1330 1347 }
+70 -12
net/x25/x25_facilities.c
··· 28 28 #include <net/x25.h> 29 29 30 30 /* 31 - * Parse a set of facilities into the facilities structure. Unrecognised 31 + * Parse a set of facilities into the facilities structures. Unrecognised 32 32 * facilities are written to the debug log file. 33 33 */ 34 - int x25_parse_facilities(struct sk_buff *skb, 35 - struct x25_facilities *facilities, 36 - unsigned long *vc_fac_mask) 34 + int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, 35 + struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) 37 36 { 38 37 unsigned char *p = skb->data; 39 38 unsigned int len = *p++; 40 39 41 40 *vc_fac_mask = 0; 41 + 42 + /* 43 + * The kernel knows which facilities were set on an incoming call but 44 + * currently this information is not available to userspace. Here we 45 + * give userspace who read incoming call facilities 0 length to indicate 46 + * it wasn't set. 47 + */ 48 + dte_facs->calling_len = 0; 49 + dte_facs->called_len = 0; 50 + memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); 51 + memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); 42 52 43 53 while (len > 0) { 44 54 switch (*p & X25_FAC_CLASS_MASK) { ··· 83 73 case X25_FAC_THROUGHPUT: 84 74 facilities->throughput = p[1]; 85 75 *vc_fac_mask |= X25_MASK_THROUGHPUT; 76 + break; 77 + case X25_MARKER: 86 78 break; 87 79 default: 88 80 printk(KERN_DEBUG "X.25: unknown facility " ··· 124 112 len -= 4; 125 113 break; 126 114 case X25_FAC_CLASS_D: 127 - printk(KERN_DEBUG "X.25: unknown facility %02X, " 128 - "length %d, values %02X, %02X, %02X, %02X\n", 129 - p[0], p[1], p[2], p[3], p[4], p[5]); 115 + switch (*p) { 116 + case X25_FAC_CALLING_AE: 117 + if (p[1] > X25_MAX_DTE_FACIL_LEN) 118 + break; 119 + dte_facs->calling_len = p[2]; 120 + memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); 121 + *vc_fac_mask |= X25_MASK_CALLING_AE; 122 + break; 123 + case X25_FAC_CALLED_AE: 124 + if (p[1] > X25_MAX_DTE_FACIL_LEN) 125 + break; 126 + dte_facs->called_len = p[2]; 127 + memcpy(dte_facs->called_ae, &p[3], p[1] - 1); 128 + *vc_fac_mask |= X25_MASK_CALLED_AE; 129 + break; 130 + default: 131 + printk(KERN_DEBUG "X.25: unknown facility %02X," 132 + "length %d, values %02X, %02X, " 133 + "%02X, %02X\n", 134 + p[0], p[1], p[2], p[3], p[4], p[5]); 135 + break; 136 + } 130 137 len -= p[1] + 2; 131 - p += p[1] + 2; 138 + p += p[1] + 2; 132 139 break; 133 140 } 134 141 } ··· 159 128 * Create a set of facilities. 160 129 */ 161 130 int x25_create_facilities(unsigned char *buffer, 162 - struct x25_facilities *facilities, 163 - unsigned long facil_mask) 131 + struct x25_facilities *facilities, 132 + struct x25_dte_facilities *dte_facs, unsigned long facil_mask) 164 133 { 165 134 unsigned char *p = buffer + 1; 166 135 int len; ··· 199 168 *p++ = facilities->winsize_out ? : facilities->winsize_in; 200 169 } 201 170 171 + if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) { 172 + *p++ = X25_MARKER; 173 + *p++ = X25_DTE_SERVICES; 174 + } 175 + 176 + if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { 177 + unsigned bytecount = (dte_facs->calling_len % 2) ? 178 + dte_facs->calling_len / 2 + 1 : 179 + dte_facs->calling_len / 2; 180 + *p++ = X25_FAC_CALLING_AE; 181 + *p++ = 1 + bytecount; 182 + *p++ = dte_facs->calling_len; 183 + memcpy(p, dte_facs->calling_ae, bytecount); 184 + p += bytecount; 185 + } 186 + 187 + if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { 188 + unsigned bytecount = (dte_facs->called_len % 2) ? 189 + dte_facs->called_len / 2 + 1 : 190 + dte_facs->called_len / 2; 191 + *p++ = X25_FAC_CALLED_AE; 192 + *p++ = 1 + bytecount; 193 + *p++ = dte_facs->called_len; 194 + memcpy(p, dte_facs->called_ae, bytecount); 195 + p+=bytecount; 196 + } 197 + 202 198 len = p - buffer; 203 199 buffer[0] = len - 1; 204 200 ··· 238 180 * The only real problem is with reverse charging. 239 181 */ 240 182 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, 241 - struct x25_facilities *new) 183 + struct x25_facilities *new, struct x25_dte_facilities *dte) 242 184 { 243 185 struct x25_sock *x25 = x25_sk(sk); 244 186 struct x25_facilities *ours = &x25->facilities; ··· 248 190 memset(&theirs, 0, sizeof(theirs)); 249 191 memcpy(new, ours, sizeof(*new)); 250 192 251 - len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask); 193 + len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); 252 194 253 195 /* 254 196 * They want reverse charging, we won't accept it.
+2 -1
net/x25/x25_in.c
··· 106 106 skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); 107 107 skb_pull(skb, 108 108 x25_parse_facilities(skb, &x25->facilities, 109 - &x25->vc_facil_mask)); 109 + &x25->dte_facilities, 110 + &x25->vc_facil_mask)); 110 111 /* 111 112 * Copy any Call User Data. 112 113 */
+4 -2
net/x25/x25_subr.c
··· 190 190 dptr = skb_put(skb, len); 191 191 memcpy(dptr, addresses, len); 192 192 len = x25_create_facilities(facilities, 193 - &x25->facilities, 194 - x25->neighbour->global_facil_mask); 193 + &x25->facilities, 194 + &x25->dte_facilities, 195 + x25->neighbour->global_facil_mask); 195 196 dptr = skb_put(skb, len); 196 197 memcpy(dptr, facilities, len); 197 198 dptr = skb_put(skb, x25->calluserdata.cudlength); ··· 207 206 *dptr++ = 0x00; /* Address lengths */ 208 207 len = x25_create_facilities(facilities, 209 208 &x25->facilities, 209 + &x25->dte_facilities, 210 210 x25->vc_facil_mask); 211 211 dptr = skb_put(skb, len); 212 212 memcpy(dptr, facilities, len);