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