1 /* 2 * X.25 Packet Layer release 002 3 * 4 * This is ALPHA test software. This code may break your machine, 5 * randomly fail to work with new releases, misbehave and/or generally 6 * screw up. It might even work. 7 * 8 * This code REQUIRES 2.1.15 or higher 9 * 10 * This module: 11 * This module is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 14 * 2 of the License, or (at your option) any later version. 15 * 16 * History 17 * X.25 001 Split from x25_subr.c 18 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities 19 * negotiation. 20 * apr/14/05 Shaun Pereira - Allow fast select with no restriction 21 * on response. 22 */ 23 24 #include <linux/kernel.h> 25 #include <linux/string.h> 26 #include <linux/skbuff.h> 27 #include <net/sock.h> 28 #include <net/x25.h> 29 30 /* 31 * Parse a set of facilities into the facilities structures. Unrecognised 32 * facilities are written to the debug log file. 33 */ 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) 36 { 37 unsigned char *p = skb->data; 38 unsigned int len; 39 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)); 52 53 if (skb->len < 1) 54 return 0; 55 56 len = *p++; 57 58 if (len >= skb->len) 59 return -1; 60 61 while (len > 0) { 62 switch (*p & X25_FAC_CLASS_MASK) { 63 case X25_FAC_CLASS_A: 64 if (len < 2) 65 return 0; 66 switch (*p) { 67 case X25_FAC_REVERSE: 68 if((p[1] & 0x81) == 0x81) { 69 facilities->reverse = p[1] & 0x81; 70 *vc_fac_mask |= X25_MASK_REVERSE; 71 break; 72 } 73 74 if((p[1] & 0x01) == 0x01) { 75 facilities->reverse = p[1] & 0x01; 76 *vc_fac_mask |= X25_MASK_REVERSE; 77 break; 78 } 79 80 if((p[1] & 0x80) == 0x80) { 81 facilities->reverse = p[1] & 0x80; 82 *vc_fac_mask |= X25_MASK_REVERSE; 83 break; 84 } 85 86 if(p[1] == 0x00) { 87 facilities->reverse 88 = X25_DEFAULT_REVERSE; 89 *vc_fac_mask |= X25_MASK_REVERSE; 90 break; 91 } 92 93 case X25_FAC_THROUGHPUT: 94 facilities->throughput = p[1]; 95 *vc_fac_mask |= X25_MASK_THROUGHPUT; 96 break; 97 case X25_MARKER: 98 break; 99 default: 100 printk(KERN_DEBUG "X.25: unknown facility " 101 "%02X, value %02X\n", 102 p[0], p[1]); 103 break; 104 } 105 p += 2; 106 len -= 2; 107 break; 108 case X25_FAC_CLASS_B: 109 if (len < 3) 110 return 0; 111 switch (*p) { 112 case X25_FAC_PACKET_SIZE: 113 facilities->pacsize_in = p[1]; 114 facilities->pacsize_out = p[2]; 115 *vc_fac_mask |= X25_MASK_PACKET_SIZE; 116 break; 117 case X25_FAC_WINDOW_SIZE: 118 facilities->winsize_in = p[1]; 119 facilities->winsize_out = p[2]; 120 *vc_fac_mask |= X25_MASK_WINDOW_SIZE; 121 break; 122 default: 123 printk(KERN_DEBUG "X.25: unknown facility " 124 "%02X, values %02X, %02X\n", 125 p[0], p[1], p[2]); 126 break; 127 } 128 p += 3; 129 len -= 3; 130 break; 131 case X25_FAC_CLASS_C: 132 if (len < 4) 133 return 0; 134 printk(KERN_DEBUG "X.25: unknown facility %02X, " 135 "values %02X, %02X, %02X\n", 136 p[0], p[1], p[2], p[3]); 137 p += 4; 138 len -= 4; 139 break; 140 case X25_FAC_CLASS_D: 141 if (len < p[1] + 2) 142 return 0; 143 switch (*p) { 144 case X25_FAC_CALLING_AE: 145 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 146 return 0; 147 dte_facs->calling_len = p[2]; 148 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); 149 *vc_fac_mask |= X25_MASK_CALLING_AE; 150 break; 151 case X25_FAC_CALLED_AE: 152 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 153 return 0; 154 dte_facs->called_len = p[2]; 155 memcpy(dte_facs->called_ae, &p[3], p[1] - 1); 156 *vc_fac_mask |= X25_MASK_CALLED_AE; 157 break; 158 default: 159 printk(KERN_DEBUG "X.25: unknown facility %02X," 160 "length %d\n", p[0], p[1]); 161 break; 162 } 163 len -= p[1] + 2; 164 p += p[1] + 2; 165 break; 166 } 167 } 168 169 return p - skb->data; 170 } 171 172 /* 173 * Create a set of facilities. 174 */ 175 int x25_create_facilities(unsigned char *buffer, 176 struct x25_facilities *facilities, 177 struct x25_dte_facilities *dte_facs, unsigned long facil_mask) 178 { 179 unsigned char *p = buffer + 1; 180 int len; 181 182 if (!facil_mask) { 183 /* 184 * Length of the facilities field in call_req or 185 * call_accept packets 186 */ 187 buffer[0] = 0; 188 len = 1; /* 1 byte for the length field */ 189 return len; 190 } 191 192 if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) { 193 *p++ = X25_FAC_REVERSE; 194 *p++ = facilities->reverse; 195 } 196 197 if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) { 198 *p++ = X25_FAC_THROUGHPUT; 199 *p++ = facilities->throughput; 200 } 201 202 if ((facilities->pacsize_in || facilities->pacsize_out) && 203 (facil_mask & X25_MASK_PACKET_SIZE)) { 204 *p++ = X25_FAC_PACKET_SIZE; 205 *p++ = facilities->pacsize_in ? : facilities->pacsize_out; 206 *p++ = facilities->pacsize_out ? : facilities->pacsize_in; 207 } 208 209 if ((facilities->winsize_in || facilities->winsize_out) && 210 (facil_mask & X25_MASK_WINDOW_SIZE)) { 211 *p++ = X25_FAC_WINDOW_SIZE; 212 *p++ = facilities->winsize_in ? : facilities->winsize_out; 213 *p++ = facilities->winsize_out ? : facilities->winsize_in; 214 } 215 216 if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) { 217 *p++ = X25_MARKER; 218 *p++ = X25_DTE_SERVICES; 219 } 220 221 if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { 222 unsigned bytecount = (dte_facs->calling_len + 1) >> 1; 223 *p++ = X25_FAC_CALLING_AE; 224 *p++ = 1 + bytecount; 225 *p++ = dte_facs->calling_len; 226 memcpy(p, dte_facs->calling_ae, bytecount); 227 p += bytecount; 228 } 229 230 if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { 231 unsigned bytecount = (dte_facs->called_len % 2) ? 232 dte_facs->called_len / 2 + 1 : 233 dte_facs->called_len / 2; 234 *p++ = X25_FAC_CALLED_AE; 235 *p++ = 1 + bytecount; 236 *p++ = dte_facs->called_len; 237 memcpy(p, dte_facs->called_ae, bytecount); 238 p+=bytecount; 239 } 240 241 len = p - buffer; 242 buffer[0] = len - 1; 243 244 return len; 245 } 246 247 /* 248 * Try to reach a compromise on a set of facilities. 249 * 250 * The only real problem is with reverse charging. 251 */ 252 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, 253 struct x25_facilities *new, struct x25_dte_facilities *dte) 254 { 255 struct x25_sock *x25 = x25_sk(sk); 256 struct x25_facilities *ours = &x25->facilities; 257 struct x25_facilities theirs; 258 int len; 259 260 memset(&theirs, 0, sizeof(theirs)); 261 memcpy(new, ours, sizeof(*new)); 262 263 len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); 264 if (len < 0) 265 return len; 266 267 /* 268 * They want reverse charging, we won't accept it. 269 */ 270 if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) { 271 SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n"); 272 return -1; 273 } 274 275 new->reverse = theirs.reverse; 276 277 if (theirs.throughput) { 278 int theirs_in = theirs.throughput & 0x0f; 279 int theirs_out = theirs.throughput & 0xf0; 280 int ours_in = ours->throughput & 0x0f; 281 int ours_out = ours->throughput & 0xf0; 282 if (!ours_in || theirs_in < ours_in) { 283 SOCK_DEBUG(sk, "X.25: inbound throughput negotiated\n"); 284 new->throughput = (new->throughput & 0xf0) | theirs_in; 285 } 286 if (!ours_out || theirs_out < ours_out) { 287 SOCK_DEBUG(sk, 288 "X.25: outbound throughput negotiated\n"); 289 new->throughput = (new->throughput & 0x0f) | theirs_out; 290 } 291 } 292 293 if (theirs.pacsize_in && theirs.pacsize_out) { 294 if (theirs.pacsize_in < ours->pacsize_in) { 295 SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n"); 296 new->pacsize_in = theirs.pacsize_in; 297 } 298 if (theirs.pacsize_out < ours->pacsize_out) { 299 SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n"); 300 new->pacsize_out = theirs.pacsize_out; 301 } 302 } 303 304 if (theirs.winsize_in && theirs.winsize_out) { 305 if (theirs.winsize_in < ours->winsize_in) { 306 SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n"); 307 new->winsize_in = theirs.winsize_in; 308 } 309 if (theirs.winsize_out < ours->winsize_out) { 310 SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n"); 311 new->winsize_out = theirs.winsize_out; 312 } 313 } 314 315 return len; 316 } 317 318 /* 319 * Limit values of certain facilities according to the capability of the 320 * currently attached x25 link. 321 */ 322 void x25_limit_facilities(struct x25_facilities *facilities, 323 struct x25_neigh *nb) 324 { 325 326 if (!nb->extended) { 327 if (facilities->winsize_in > 7) { 328 printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); 329 facilities->winsize_in = 7; 330 } 331 if (facilities->winsize_out > 7) { 332 facilities->winsize_out = 7; 333 printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); 334 } 335 } 336 } 337