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 = *p++; 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 while (len > 0) { 54 switch (*p & X25_FAC_CLASS_MASK) { 55 case X25_FAC_CLASS_A: 56 switch (*p) { 57 case X25_FAC_REVERSE: 58 if((p[1] & 0x81) == 0x81) { 59 facilities->reverse = p[1] & 0x81; 60 *vc_fac_mask |= X25_MASK_REVERSE; 61 break; 62 } 63 64 if((p[1] & 0x01) == 0x01) { 65 facilities->reverse = p[1] & 0x01; 66 *vc_fac_mask |= X25_MASK_REVERSE; 67 break; 68 } 69 70 if((p[1] & 0x80) == 0x80) { 71 facilities->reverse = p[1] & 0x80; 72 *vc_fac_mask |= X25_MASK_REVERSE; 73 break; 74 } 75 76 if(p[1] == 0x00) { 77 facilities->reverse 78 = X25_DEFAULT_REVERSE; 79 *vc_fac_mask |= X25_MASK_REVERSE; 80 break; 81 } 82 83 case X25_FAC_THROUGHPUT: 84 facilities->throughput = p[1]; 85 *vc_fac_mask |= X25_MASK_THROUGHPUT; 86 break; 87 case X25_MARKER: 88 break; 89 default: 90 printk(KERN_DEBUG "X.25: unknown facility " 91 "%02X, value %02X\n", 92 p[0], p[1]); 93 break; 94 } 95 p += 2; 96 len -= 2; 97 break; 98 case X25_FAC_CLASS_B: 99 switch (*p) { 100 case X25_FAC_PACKET_SIZE: 101 facilities->pacsize_in = p[1]; 102 facilities->pacsize_out = p[2]; 103 *vc_fac_mask |= X25_MASK_PACKET_SIZE; 104 break; 105 case X25_FAC_WINDOW_SIZE: 106 facilities->winsize_in = p[1]; 107 facilities->winsize_out = p[2]; 108 *vc_fac_mask |= X25_MASK_WINDOW_SIZE; 109 break; 110 default: 111 printk(KERN_DEBUG "X.25: unknown facility " 112 "%02X, values %02X, %02X\n", 113 p[0], p[1], p[2]); 114 break; 115 } 116 p += 3; 117 len -= 3; 118 break; 119 case X25_FAC_CLASS_C: 120 printk(KERN_DEBUG "X.25: unknown facility %02X, " 121 "values %02X, %02X, %02X\n", 122 p[0], p[1], p[2], p[3]); 123 p += 4; 124 len -= 4; 125 break; 126 case X25_FAC_CLASS_D: 127 switch (*p) { 128 case X25_FAC_CALLING_AE: 129 if (p[1] > X25_MAX_DTE_FACIL_LEN) 130 break; 131 dte_facs->calling_len = p[2]; 132 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); 133 *vc_fac_mask |= X25_MASK_CALLING_AE; 134 break; 135 case X25_FAC_CALLED_AE: 136 if (p[1] > X25_MAX_DTE_FACIL_LEN) 137 break; 138 dte_facs->called_len = p[2]; 139 memcpy(dte_facs->called_ae, &p[3], p[1] - 1); 140 *vc_fac_mask |= X25_MASK_CALLED_AE; 141 break; 142 default: 143 printk(KERN_DEBUG "X.25: unknown facility %02X," 144 "length %d, values %02X, %02X, " 145 "%02X, %02X\n", 146 p[0], p[1], p[2], p[3], p[4], p[5]); 147 break; 148 } 149 len -= p[1] + 2; 150 p += p[1] + 2; 151 break; 152 } 153 } 154 155 return p - skb->data; 156 } 157 158 /* 159 * Create a set of facilities. 160 */ 161 int x25_create_facilities(unsigned char *buffer, 162 struct x25_facilities *facilities, 163 struct x25_dte_facilities *dte_facs, unsigned long facil_mask) 164 { 165 unsigned char *p = buffer + 1; 166 int len; 167 168 if (!facil_mask) { 169 /* 170 * Length of the facilities field in call_req or 171 * call_accept packets 172 */ 173 buffer[0] = 0; 174 len = 1; /* 1 byte for the length field */ 175 return len; 176 } 177 178 if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) { 179 *p++ = X25_FAC_REVERSE; 180 *p++ = facilities->reverse; 181 } 182 183 if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) { 184 *p++ = X25_FAC_THROUGHPUT; 185 *p++ = facilities->throughput; 186 } 187 188 if ((facilities->pacsize_in || facilities->pacsize_out) && 189 (facil_mask & X25_MASK_PACKET_SIZE)) { 190 *p++ = X25_FAC_PACKET_SIZE; 191 *p++ = facilities->pacsize_in ? : facilities->pacsize_out; 192 *p++ = facilities->pacsize_out ? : facilities->pacsize_in; 193 } 194 195 if ((facilities->winsize_in || facilities->winsize_out) && 196 (facil_mask & X25_MASK_WINDOW_SIZE)) { 197 *p++ = X25_FAC_WINDOW_SIZE; 198 *p++ = facilities->winsize_in ? : facilities->winsize_out; 199 *p++ = facilities->winsize_out ? : facilities->winsize_in; 200 } 201 202 if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) { 203 *p++ = X25_MARKER; 204 *p++ = X25_DTE_SERVICES; 205 } 206 207 if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { 208 unsigned bytecount = (dte_facs->calling_len % 2) ? 209 dte_facs->calling_len / 2 + 1 : 210 dte_facs->calling_len / 2; 211 *p++ = X25_FAC_CALLING_AE; 212 *p++ = 1 + bytecount; 213 *p++ = dte_facs->calling_len; 214 memcpy(p, dte_facs->calling_ae, bytecount); 215 p += bytecount; 216 } 217 218 if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { 219 unsigned bytecount = (dte_facs->called_len % 2) ? 220 dte_facs->called_len / 2 + 1 : 221 dte_facs->called_len / 2; 222 *p++ = X25_FAC_CALLED_AE; 223 *p++ = 1 + bytecount; 224 *p++ = dte_facs->called_len; 225 memcpy(p, dte_facs->called_ae, bytecount); 226 p+=bytecount; 227 } 228 229 len = p - buffer; 230 buffer[0] = len - 1; 231 232 return len; 233 } 234 235 /* 236 * Try to reach a compromise on a set of facilities. 237 * 238 * The only real problem is with reverse charging. 239 */ 240 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, 241 struct x25_facilities *new, struct x25_dte_facilities *dte) 242 { 243 struct x25_sock *x25 = x25_sk(sk); 244 struct x25_facilities *ours = &x25->facilities; 245 struct x25_facilities theirs; 246 int len; 247 248 memset(&theirs, 0, sizeof(theirs)); 249 memcpy(new, ours, sizeof(*new)); 250 251 len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); 252 253 /* 254 * They want reverse charging, we won't accept it. 255 */ 256 if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) { 257 SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n"); 258 return -1; 259 } 260 261 new->reverse = theirs.reverse; 262 263 if (theirs.throughput) { 264 if (theirs.throughput < ours->throughput) { 265 SOCK_DEBUG(sk, "X.25: throughput negotiated down\n"); 266 new->throughput = theirs.throughput; 267 } 268 } 269 270 if (theirs.pacsize_in && theirs.pacsize_out) { 271 if (theirs.pacsize_in < ours->pacsize_in) { 272 SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n"); 273 new->pacsize_in = theirs.pacsize_in; 274 } 275 if (theirs.pacsize_out < ours->pacsize_out) { 276 SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n"); 277 new->pacsize_out = theirs.pacsize_out; 278 } 279 } 280 281 if (theirs.winsize_in && theirs.winsize_out) { 282 if (theirs.winsize_in < ours->winsize_in) { 283 SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n"); 284 new->winsize_in = theirs.winsize_in; 285 } 286 if (theirs.winsize_out < ours->winsize_out) { 287 SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n"); 288 new->winsize_out = theirs.winsize_out; 289 } 290 } 291 292 return len; 293 } 294 295 /* 296 * Limit values of certain facilities according to the capability of the 297 * currently attached x25 link. 298 */ 299 void x25_limit_facilities(struct x25_facilities *facilities, 300 struct x25_neigh *nb) 301 { 302 303 if (!nb->extended) { 304 if (facilities->winsize_in > 7) { 305 printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); 306 facilities->winsize_in = 7; 307 } 308 if (facilities->winsize_out > 7) { 309 facilities->winsize_out = 7; 310 printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); 311 } 312 } 313 } 314