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 + 1) >> 1; 209 *p++ = X25_FAC_CALLING_AE; 210 *p++ = 1 + bytecount; 211 *p++ = dte_facs->calling_len; 212 memcpy(p, dte_facs->calling_ae, bytecount); 213 p += bytecount; 214 } 215 216 if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { 217 unsigned bytecount = (dte_facs->called_len % 2) ? 218 dte_facs->called_len / 2 + 1 : 219 dte_facs->called_len / 2; 220 *p++ = X25_FAC_CALLED_AE; 221 *p++ = 1 + bytecount; 222 *p++ = dte_facs->called_len; 223 memcpy(p, dte_facs->called_ae, bytecount); 224 p+=bytecount; 225 } 226 227 len = p - buffer; 228 buffer[0] = len - 1; 229 230 return len; 231 } 232 233 /* 234 * Try to reach a compromise on a set of facilities. 235 * 236 * The only real problem is with reverse charging. 237 */ 238 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, 239 struct x25_facilities *new, struct x25_dte_facilities *dte) 240 { 241 struct x25_sock *x25 = x25_sk(sk); 242 struct x25_facilities *ours = &x25->facilities; 243 struct x25_facilities theirs; 244 int len; 245 246 memset(&theirs, 0, sizeof(theirs)); 247 memcpy(new, ours, sizeof(*new)); 248 249 len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); 250 251 /* 252 * They want reverse charging, we won't accept it. 253 */ 254 if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) { 255 SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n"); 256 return -1; 257 } 258 259 new->reverse = theirs.reverse; 260 261 if (theirs.throughput) { 262 if (theirs.throughput < ours->throughput) { 263 SOCK_DEBUG(sk, "X.25: throughput negotiated down\n"); 264 new->throughput = theirs.throughput; 265 } 266 } 267 268 if (theirs.pacsize_in && theirs.pacsize_out) { 269 if (theirs.pacsize_in < ours->pacsize_in) { 270 SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n"); 271 new->pacsize_in = theirs.pacsize_in; 272 } 273 if (theirs.pacsize_out < ours->pacsize_out) { 274 SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n"); 275 new->pacsize_out = theirs.pacsize_out; 276 } 277 } 278 279 if (theirs.winsize_in && theirs.winsize_out) { 280 if (theirs.winsize_in < ours->winsize_in) { 281 SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n"); 282 new->winsize_in = theirs.winsize_in; 283 } 284 if (theirs.winsize_out < ours->winsize_out) { 285 SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n"); 286 new->winsize_out = theirs.winsize_out; 287 } 288 } 289 290 return len; 291 } 292 293 /* 294 * Limit values of certain facilities according to the capability of the 295 * currently attached x25 link. 296 */ 297 void x25_limit_facilities(struct x25_facilities *facilities, 298 struct x25_neigh *nb) 299 { 300 301 if (!nb->extended) { 302 if (facilities->winsize_in > 7) { 303 printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); 304 facilities->winsize_in = 7; 305 } 306 if (facilities->winsize_out > 7) { 307 facilities->winsize_out = 7; 308 printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); 309 } 310 } 311 } 312