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 structure. Unrecognised 32 * facilities are written to the debug log file. 33 */ 34 int x25_parse_facilities(struct sk_buff *skb, 35 struct x25_facilities *facilities, 36 unsigned long *vc_fac_mask) 37 { 38 unsigned char *p = skb->data; 39 unsigned int len = *p++; 40 41 *vc_fac_mask = 0; 42 43 while (len > 0) { 44 switch (*p & X25_FAC_CLASS_MASK) { 45 case X25_FAC_CLASS_A: 46 switch (*p) { 47 case X25_FAC_REVERSE: 48 if((p[1] & 0x81) == 0x81) { 49 facilities->reverse = p[1] & 0x81; 50 *vc_fac_mask |= X25_MASK_REVERSE; 51 break; 52 } 53 54 if((p[1] & 0x01) == 0x01) { 55 facilities->reverse = p[1] & 0x01; 56 *vc_fac_mask |= X25_MASK_REVERSE; 57 break; 58 } 59 60 if((p[1] & 0x80) == 0x80) { 61 facilities->reverse = p[1] & 0x80; 62 *vc_fac_mask |= X25_MASK_REVERSE; 63 break; 64 } 65 66 if(p[1] == 0x00) { 67 facilities->reverse 68 = X25_DEFAULT_REVERSE; 69 *vc_fac_mask |= X25_MASK_REVERSE; 70 break; 71 } 72 73 case X25_FAC_THROUGHPUT: 74 facilities->throughput = p[1]; 75 *vc_fac_mask |= X25_MASK_THROUGHPUT; 76 break; 77 default: 78 printk(KERN_DEBUG "X.25: unknown facility " 79 "%02X, value %02X\n", 80 p[0], p[1]); 81 break; 82 } 83 p += 2; 84 len -= 2; 85 break; 86 case X25_FAC_CLASS_B: 87 switch (*p) { 88 case X25_FAC_PACKET_SIZE: 89 facilities->pacsize_in = p[1]; 90 facilities->pacsize_out = p[2]; 91 *vc_fac_mask |= X25_MASK_PACKET_SIZE; 92 break; 93 case X25_FAC_WINDOW_SIZE: 94 facilities->winsize_in = p[1]; 95 facilities->winsize_out = p[2]; 96 *vc_fac_mask |= X25_MASK_WINDOW_SIZE; 97 break; 98 default: 99 printk(KERN_DEBUG "X.25: unknown facility " 100 "%02X, values %02X, %02X\n", 101 p[0], p[1], p[2]); 102 break; 103 } 104 p += 3; 105 len -= 3; 106 break; 107 case X25_FAC_CLASS_C: 108 printk(KERN_DEBUG "X.25: unknown facility %02X, " 109 "values %02X, %02X, %02X\n", 110 p[0], p[1], p[2], p[3]); 111 p += 4; 112 len -= 4; 113 break; 114 case X25_FAC_CLASS_D: 115 printk(KERN_DEBUG "X.25: unknown facility %02X, " 116 "length %d, values %02X, %02X, %02X, %02X\n", 117 p[0], p[1], p[2], p[3], p[4], p[5]); 118 len -= p[1] + 2; 119 p += p[1] + 2; 120 break; 121 } 122 } 123 124 return p - skb->data; 125 } 126 127 /* 128 * Create a set of facilities. 129 */ 130 int x25_create_facilities(unsigned char *buffer, 131 struct x25_facilities *facilities, 132 unsigned long facil_mask) 133 { 134 unsigned char *p = buffer + 1; 135 int len; 136 137 if (!facil_mask) { 138 /* 139 * Length of the facilities field in call_req or 140 * call_accept packets 141 */ 142 buffer[0] = 0; 143 len = 1; /* 1 byte for the length field */ 144 return len; 145 } 146 147 if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) { 148 *p++ = X25_FAC_REVERSE; 149 *p++ = facilities->reverse; 150 } 151 152 if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) { 153 *p++ = X25_FAC_THROUGHPUT; 154 *p++ = facilities->throughput; 155 } 156 157 if ((facilities->pacsize_in || facilities->pacsize_out) && 158 (facil_mask & X25_MASK_PACKET_SIZE)) { 159 *p++ = X25_FAC_PACKET_SIZE; 160 *p++ = facilities->pacsize_in ? : facilities->pacsize_out; 161 *p++ = facilities->pacsize_out ? : facilities->pacsize_in; 162 } 163 164 if ((facilities->winsize_in || facilities->winsize_out) && 165 (facil_mask & X25_MASK_WINDOW_SIZE)) { 166 *p++ = X25_FAC_WINDOW_SIZE; 167 *p++ = facilities->winsize_in ? : facilities->winsize_out; 168 *p++ = facilities->winsize_out ? : facilities->winsize_in; 169 } 170 171 len = p - buffer; 172 buffer[0] = len - 1; 173 174 return len; 175 } 176 177 /* 178 * Try to reach a compromise on a set of facilities. 179 * 180 * The only real problem is with reverse charging. 181 */ 182 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, 183 struct x25_facilities *new) 184 { 185 struct x25_sock *x25 = x25_sk(sk); 186 struct x25_facilities *ours = &x25->facilities; 187 struct x25_facilities theirs; 188 int len; 189 190 memset(&theirs, 0, sizeof(theirs)); 191 memcpy(new, ours, sizeof(*new)); 192 193 len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask); 194 195 /* 196 * They want reverse charging, we won't accept it. 197 */ 198 if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) { 199 SOCK_DEBUG(sk, "X.25: rejecting reverse charging request"); 200 return -1; 201 } 202 203 new->reverse = theirs.reverse; 204 205 if (theirs.throughput) { 206 if (theirs.throughput < ours->throughput) { 207 SOCK_DEBUG(sk, "X.25: throughput negotiated down"); 208 new->throughput = theirs.throughput; 209 } 210 } 211 212 if (theirs.pacsize_in && theirs.pacsize_out) { 213 if (theirs.pacsize_in < ours->pacsize_in) { 214 SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down"); 215 new->pacsize_in = theirs.pacsize_in; 216 } 217 if (theirs.pacsize_out < ours->pacsize_out) { 218 SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down"); 219 new->pacsize_out = theirs.pacsize_out; 220 } 221 } 222 223 if (theirs.winsize_in && theirs.winsize_out) { 224 if (theirs.winsize_in < ours->winsize_in) { 225 SOCK_DEBUG(sk, "X.25: window size inwards negotiated down"); 226 new->winsize_in = theirs.winsize_in; 227 } 228 if (theirs.winsize_out < ours->winsize_out) { 229 SOCK_DEBUG(sk, "X.25: window size outwards negotiated down"); 230 new->winsize_out = theirs.winsize_out; 231 } 232 } 233 234 return len; 235 } 236 237 /* 238 * Limit values of certain facilities according to the capability of the 239 * currently attached x25 link. 240 */ 241 void x25_limit_facilities(struct x25_facilities *facilities, 242 struct x25_neigh *nb) 243 { 244 245 if (!nb->extended) { 246 if (facilities->winsize_in > 7) { 247 printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); 248 facilities->winsize_in = 7; 249 } 250 if (facilities->winsize_out > 7) { 251 facilities->winsize_out = 7; 252 printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); 253 } 254 } 255 } 256