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#define pr_fmt(fmt) "X25: " fmt 25 26#include <linux/kernel.h> 27#include <linux/string.h> 28#include <linux/skbuff.h> 29#include <net/sock.h> 30#include <net/x25.h> 31 32/** 33 * x25_parse_facilities - Parse facilities from skb into the facilities structs 34 * 35 * @skb: sk_buff to parse 36 * @facilities: Regular facilities, updated as facilities are found 37 * @dte_facs: ITU DTE facilities, updated as DTE facilities are found 38 * @vc_fac_mask: mask is updated with all facilities found 39 * 40 * Return codes: 41 * -1 - Parsing error, caller should drop call and clean up 42 * 0 - Parse OK, this skb has no facilities 43 * >0 - Parse OK, returns the length of the facilities header 44 * 45 */ 46int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, 47 struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) 48{ 49 unsigned char *p; 50 unsigned int len; 51 52 *vc_fac_mask = 0; 53 54 /* 55 * The kernel knows which facilities were set on an incoming call but 56 * currently this information is not available to userspace. Here we 57 * give userspace who read incoming call facilities 0 length to indicate 58 * it wasn't set. 59 */ 60 dte_facs->calling_len = 0; 61 dte_facs->called_len = 0; 62 memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); 63 memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); 64 65 if (!pskb_may_pull(skb, 1)) 66 return 0; 67 68 len = skb->data[0]; 69 70 if (!pskb_may_pull(skb, 1 + len)) 71 return -1; 72 73 p = skb->data + 1; 74 75 while (len > 0) { 76 switch (*p & X25_FAC_CLASS_MASK) { 77 case X25_FAC_CLASS_A: 78 if (len < 2) 79 return -1; 80 switch (*p) { 81 case X25_FAC_REVERSE: 82 if((p[1] & 0x81) == 0x81) { 83 facilities->reverse = p[1] & 0x81; 84 *vc_fac_mask |= X25_MASK_REVERSE; 85 break; 86 } 87 88 if((p[1] & 0x01) == 0x01) { 89 facilities->reverse = p[1] & 0x01; 90 *vc_fac_mask |= X25_MASK_REVERSE; 91 break; 92 } 93 94 if((p[1] & 0x80) == 0x80) { 95 facilities->reverse = p[1] & 0x80; 96 *vc_fac_mask |= X25_MASK_REVERSE; 97 break; 98 } 99 100 if(p[1] == 0x00) { 101 facilities->reverse 102 = X25_DEFAULT_REVERSE; 103 *vc_fac_mask |= X25_MASK_REVERSE; 104 break; 105 } 106 107 case X25_FAC_THROUGHPUT: 108 facilities->throughput = p[1]; 109 *vc_fac_mask |= X25_MASK_THROUGHPUT; 110 break; 111 case X25_MARKER: 112 break; 113 default: 114 pr_debug("unknown facility " 115 "%02X, value %02X\n", 116 p[0], p[1]); 117 break; 118 } 119 p += 2; 120 len -= 2; 121 break; 122 case X25_FAC_CLASS_B: 123 if (len < 3) 124 return -1; 125 switch (*p) { 126 case X25_FAC_PACKET_SIZE: 127 facilities->pacsize_in = p[1]; 128 facilities->pacsize_out = p[2]; 129 *vc_fac_mask |= X25_MASK_PACKET_SIZE; 130 break; 131 case X25_FAC_WINDOW_SIZE: 132 facilities->winsize_in = p[1]; 133 facilities->winsize_out = p[2]; 134 *vc_fac_mask |= X25_MASK_WINDOW_SIZE; 135 break; 136 default: 137 pr_debug("unknown facility " 138 "%02X, values %02X, %02X\n", 139 p[0], p[1], p[2]); 140 break; 141 } 142 p += 3; 143 len -= 3; 144 break; 145 case X25_FAC_CLASS_C: 146 if (len < 4) 147 return -1; 148 pr_debug("unknown facility %02X, " 149 "values %02X, %02X, %02X\n", 150 p[0], p[1], p[2], p[3]); 151 p += 4; 152 len -= 4; 153 break; 154 case X25_FAC_CLASS_D: 155 if (len < p[1] + 2) 156 return -1; 157 switch (*p) { 158 case X25_FAC_CALLING_AE: 159 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 160 return -1; 161 if (p[2] > X25_MAX_AE_LEN) 162 return -1; 163 dte_facs->calling_len = p[2]; 164 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); 165 *vc_fac_mask |= X25_MASK_CALLING_AE; 166 break; 167 case X25_FAC_CALLED_AE: 168 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 169 return -1; 170 if (p[2] > X25_MAX_AE_LEN) 171 return -1; 172 dte_facs->called_len = p[2]; 173 memcpy(dte_facs->called_ae, &p[3], p[1] - 1); 174 *vc_fac_mask |= X25_MASK_CALLED_AE; 175 break; 176 default: 177 pr_debug("unknown facility %02X," 178 "length %d\n", p[0], p[1]); 179 break; 180 } 181 len -= p[1] + 2; 182 p += p[1] + 2; 183 break; 184 } 185 } 186 187 return p - skb->data; 188} 189 190/* 191 * Create a set of facilities. 192 */ 193int x25_create_facilities(unsigned char *buffer, 194 struct x25_facilities *facilities, 195 struct x25_dte_facilities *dte_facs, unsigned long facil_mask) 196{ 197 unsigned char *p = buffer + 1; 198 int len; 199 200 if (!facil_mask) { 201 /* 202 * Length of the facilities field in call_req or 203 * call_accept packets 204 */ 205 buffer[0] = 0; 206 len = 1; /* 1 byte for the length field */ 207 return len; 208 } 209 210 if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) { 211 *p++ = X25_FAC_REVERSE; 212 *p++ = facilities->reverse; 213 } 214 215 if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) { 216 *p++ = X25_FAC_THROUGHPUT; 217 *p++ = facilities->throughput; 218 } 219 220 if ((facilities->pacsize_in || facilities->pacsize_out) && 221 (facil_mask & X25_MASK_PACKET_SIZE)) { 222 *p++ = X25_FAC_PACKET_SIZE; 223 *p++ = facilities->pacsize_in ? : facilities->pacsize_out; 224 *p++ = facilities->pacsize_out ? : facilities->pacsize_in; 225 } 226 227 if ((facilities->winsize_in || facilities->winsize_out) && 228 (facil_mask & X25_MASK_WINDOW_SIZE)) { 229 *p++ = X25_FAC_WINDOW_SIZE; 230 *p++ = facilities->winsize_in ? : facilities->winsize_out; 231 *p++ = facilities->winsize_out ? : facilities->winsize_in; 232 } 233 234 if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) { 235 *p++ = X25_MARKER; 236 *p++ = X25_DTE_SERVICES; 237 } 238 239 if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { 240 unsigned int bytecount = (dte_facs->calling_len + 1) >> 1; 241 *p++ = X25_FAC_CALLING_AE; 242 *p++ = 1 + bytecount; 243 *p++ = dte_facs->calling_len; 244 memcpy(p, dte_facs->calling_ae, bytecount); 245 p += bytecount; 246 } 247 248 if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { 249 unsigned int bytecount = (dte_facs->called_len % 2) ? 250 dte_facs->called_len / 2 + 1 : 251 dte_facs->called_len / 2; 252 *p++ = X25_FAC_CALLED_AE; 253 *p++ = 1 + bytecount; 254 *p++ = dte_facs->called_len; 255 memcpy(p, dte_facs->called_ae, bytecount); 256 p+=bytecount; 257 } 258 259 len = p - buffer; 260 buffer[0] = len - 1; 261 262 return len; 263} 264 265/* 266 * Try to reach a compromise on a set of facilities. 267 * 268 * The only real problem is with reverse charging. 269 */ 270int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, 271 struct x25_facilities *new, struct x25_dte_facilities *dte) 272{ 273 struct x25_sock *x25 = x25_sk(sk); 274 struct x25_facilities *ours = &x25->facilities; 275 struct x25_facilities theirs; 276 int len; 277 278 memset(&theirs, 0, sizeof(theirs)); 279 memcpy(new, ours, sizeof(*new)); 280 281 len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); 282 if (len < 0) 283 return len; 284 285 /* 286 * They want reverse charging, we won't accept it. 287 */ 288 if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) { 289 SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n"); 290 return -1; 291 } 292 293 new->reverse = theirs.reverse; 294 295 if (theirs.throughput) { 296 int theirs_in = theirs.throughput & 0x0f; 297 int theirs_out = theirs.throughput & 0xf0; 298 int ours_in = ours->throughput & 0x0f; 299 int ours_out = ours->throughput & 0xf0; 300 if (!ours_in || theirs_in < ours_in) { 301 SOCK_DEBUG(sk, "X.25: inbound throughput negotiated\n"); 302 new->throughput = (new->throughput & 0xf0) | theirs_in; 303 } 304 if (!ours_out || theirs_out < ours_out) { 305 SOCK_DEBUG(sk, 306 "X.25: outbound throughput negotiated\n"); 307 new->throughput = (new->throughput & 0x0f) | theirs_out; 308 } 309 } 310 311 if (theirs.pacsize_in && theirs.pacsize_out) { 312 if (theirs.pacsize_in < ours->pacsize_in) { 313 SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n"); 314 new->pacsize_in = theirs.pacsize_in; 315 } 316 if (theirs.pacsize_out < ours->pacsize_out) { 317 SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n"); 318 new->pacsize_out = theirs.pacsize_out; 319 } 320 } 321 322 if (theirs.winsize_in && theirs.winsize_out) { 323 if (theirs.winsize_in < ours->winsize_in) { 324 SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n"); 325 new->winsize_in = theirs.winsize_in; 326 } 327 if (theirs.winsize_out < ours->winsize_out) { 328 SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n"); 329 new->winsize_out = theirs.winsize_out; 330 } 331 } 332 333 return len; 334} 335 336/* 337 * Limit values of certain facilities according to the capability of the 338 * currently attached x25 link. 339 */ 340void x25_limit_facilities(struct x25_facilities *facilities, 341 struct x25_neigh *nb) 342{ 343 344 if (!nb->extended) { 345 if (facilities->winsize_in > 7) { 346 pr_debug("incoming winsize limited to 7\n"); 347 facilities->winsize_in = 7; 348 } 349 if (facilities->winsize_out > 7) { 350 facilities->winsize_out = 7; 351 pr_debug("outgoing winsize limited to 7\n"); 352 } 353 } 354} 355