0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #define pr_fmt(fmt) "X25: " fmt
0020
0021 #include <linux/kernel.h>
0022 #include <linux/string.h>
0023 #include <linux/skbuff.h>
0024 #include <net/sock.h>
0025 #include <net/x25.h>
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
0042 struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
0043 {
0044 unsigned char *p;
0045 unsigned int len;
0046
0047 *vc_fac_mask = 0;
0048
0049
0050
0051
0052
0053
0054
0055 dte_facs->calling_len = 0;
0056 dte_facs->called_len = 0;
0057 memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
0058 memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
0059
0060 if (!pskb_may_pull(skb, 1))
0061 return 0;
0062
0063 len = skb->data[0];
0064
0065 if (!pskb_may_pull(skb, 1 + len))
0066 return -1;
0067
0068 p = skb->data + 1;
0069
0070 while (len > 0) {
0071 switch (*p & X25_FAC_CLASS_MASK) {
0072 case X25_FAC_CLASS_A:
0073 if (len < 2)
0074 return -1;
0075 switch (*p) {
0076 case X25_FAC_REVERSE:
0077 if((p[1] & 0x81) == 0x81) {
0078 facilities->reverse = p[1] & 0x81;
0079 *vc_fac_mask |= X25_MASK_REVERSE;
0080 break;
0081 }
0082
0083 if((p[1] & 0x01) == 0x01) {
0084 facilities->reverse = p[1] & 0x01;
0085 *vc_fac_mask |= X25_MASK_REVERSE;
0086 break;
0087 }
0088
0089 if((p[1] & 0x80) == 0x80) {
0090 facilities->reverse = p[1] & 0x80;
0091 *vc_fac_mask |= X25_MASK_REVERSE;
0092 break;
0093 }
0094
0095 if(p[1] == 0x00) {
0096 facilities->reverse
0097 = X25_DEFAULT_REVERSE;
0098 *vc_fac_mask |= X25_MASK_REVERSE;
0099 break;
0100 }
0101 fallthrough;
0102 case X25_FAC_THROUGHPUT:
0103 facilities->throughput = p[1];
0104 *vc_fac_mask |= X25_MASK_THROUGHPUT;
0105 break;
0106 case X25_MARKER:
0107 break;
0108 default:
0109 pr_debug("unknown facility "
0110 "%02X, value %02X\n",
0111 p[0], p[1]);
0112 break;
0113 }
0114 p += 2;
0115 len -= 2;
0116 break;
0117 case X25_FAC_CLASS_B:
0118 if (len < 3)
0119 return -1;
0120 switch (*p) {
0121 case X25_FAC_PACKET_SIZE:
0122 facilities->pacsize_in = p[1];
0123 facilities->pacsize_out = p[2];
0124 *vc_fac_mask |= X25_MASK_PACKET_SIZE;
0125 break;
0126 case X25_FAC_WINDOW_SIZE:
0127 facilities->winsize_in = p[1];
0128 facilities->winsize_out = p[2];
0129 *vc_fac_mask |= X25_MASK_WINDOW_SIZE;
0130 break;
0131 default:
0132 pr_debug("unknown facility "
0133 "%02X, values %02X, %02X\n",
0134 p[0], p[1], p[2]);
0135 break;
0136 }
0137 p += 3;
0138 len -= 3;
0139 break;
0140 case X25_FAC_CLASS_C:
0141 if (len < 4)
0142 return -1;
0143 pr_debug("unknown facility %02X, "
0144 "values %02X, %02X, %02X\n",
0145 p[0], p[1], p[2], p[3]);
0146 p += 4;
0147 len -= 4;
0148 break;
0149 case X25_FAC_CLASS_D:
0150 if (len < p[1] + 2)
0151 return -1;
0152 switch (*p) {
0153 case X25_FAC_CALLING_AE:
0154 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
0155 return -1;
0156 if (p[2] > X25_MAX_AE_LEN)
0157 return -1;
0158 dte_facs->calling_len = p[2];
0159 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
0160 *vc_fac_mask |= X25_MASK_CALLING_AE;
0161 break;
0162 case X25_FAC_CALLED_AE:
0163 if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
0164 return -1;
0165 if (p[2] > X25_MAX_AE_LEN)
0166 return -1;
0167 dte_facs->called_len = p[2];
0168 memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
0169 *vc_fac_mask |= X25_MASK_CALLED_AE;
0170 break;
0171 default:
0172 pr_debug("unknown facility %02X,"
0173 "length %d\n", p[0], p[1]);
0174 break;
0175 }
0176 len -= p[1] + 2;
0177 p += p[1] + 2;
0178 break;
0179 }
0180 }
0181
0182 return p - skb->data;
0183 }
0184
0185
0186
0187
0188 int x25_create_facilities(unsigned char *buffer,
0189 struct x25_facilities *facilities,
0190 struct x25_dte_facilities *dte_facs, unsigned long facil_mask)
0191 {
0192 unsigned char *p = buffer + 1;
0193 int len;
0194
0195 if (!facil_mask) {
0196
0197
0198
0199
0200 buffer[0] = 0;
0201 len = 1;
0202 return len;
0203 }
0204
0205 if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) {
0206 *p++ = X25_FAC_REVERSE;
0207 *p++ = facilities->reverse;
0208 }
0209
0210 if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) {
0211 *p++ = X25_FAC_THROUGHPUT;
0212 *p++ = facilities->throughput;
0213 }
0214
0215 if ((facilities->pacsize_in || facilities->pacsize_out) &&
0216 (facil_mask & X25_MASK_PACKET_SIZE)) {
0217 *p++ = X25_FAC_PACKET_SIZE;
0218 *p++ = facilities->pacsize_in ? : facilities->pacsize_out;
0219 *p++ = facilities->pacsize_out ? : facilities->pacsize_in;
0220 }
0221
0222 if ((facilities->winsize_in || facilities->winsize_out) &&
0223 (facil_mask & X25_MASK_WINDOW_SIZE)) {
0224 *p++ = X25_FAC_WINDOW_SIZE;
0225 *p++ = facilities->winsize_in ? : facilities->winsize_out;
0226 *p++ = facilities->winsize_out ? : facilities->winsize_in;
0227 }
0228
0229 if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) {
0230 *p++ = X25_MARKER;
0231 *p++ = X25_DTE_SERVICES;
0232 }
0233
0234 if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) {
0235 unsigned int bytecount = (dte_facs->calling_len + 1) >> 1;
0236 *p++ = X25_FAC_CALLING_AE;
0237 *p++ = 1 + bytecount;
0238 *p++ = dte_facs->calling_len;
0239 memcpy(p, dte_facs->calling_ae, bytecount);
0240 p += bytecount;
0241 }
0242
0243 if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) {
0244 unsigned int bytecount = (dte_facs->called_len % 2) ?
0245 dte_facs->called_len / 2 + 1 :
0246 dte_facs->called_len / 2;
0247 *p++ = X25_FAC_CALLED_AE;
0248 *p++ = 1 + bytecount;
0249 *p++ = dte_facs->called_len;
0250 memcpy(p, dte_facs->called_ae, bytecount);
0251 p+=bytecount;
0252 }
0253
0254 len = p - buffer;
0255 buffer[0] = len - 1;
0256
0257 return len;
0258 }
0259
0260
0261
0262
0263
0264
0265 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
0266 struct x25_facilities *new, struct x25_dte_facilities *dte)
0267 {
0268 struct x25_sock *x25 = x25_sk(sk);
0269 struct x25_facilities *ours = &x25->facilities;
0270 struct x25_facilities theirs;
0271 int len;
0272
0273 memset(&theirs, 0, sizeof(theirs));
0274 memcpy(new, ours, sizeof(*new));
0275 memset(dte, 0, sizeof(*dte));
0276
0277 len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask);
0278 if (len < 0)
0279 return len;
0280
0281
0282
0283
0284 if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) {
0285 SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n");
0286 return -1;
0287 }
0288
0289 new->reverse = theirs.reverse;
0290
0291 if (theirs.throughput) {
0292 int theirs_in = theirs.throughput & 0x0f;
0293 int theirs_out = theirs.throughput & 0xf0;
0294 int ours_in = ours->throughput & 0x0f;
0295 int ours_out = ours->throughput & 0xf0;
0296 if (!ours_in || theirs_in < ours_in) {
0297 SOCK_DEBUG(sk, "X.25: inbound throughput negotiated\n");
0298 new->throughput = (new->throughput & 0xf0) | theirs_in;
0299 }
0300 if (!ours_out || theirs_out < ours_out) {
0301 SOCK_DEBUG(sk,
0302 "X.25: outbound throughput negotiated\n");
0303 new->throughput = (new->throughput & 0x0f) | theirs_out;
0304 }
0305 }
0306
0307 if (theirs.pacsize_in && theirs.pacsize_out) {
0308 if (theirs.pacsize_in < ours->pacsize_in) {
0309 SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n");
0310 new->pacsize_in = theirs.pacsize_in;
0311 }
0312 if (theirs.pacsize_out < ours->pacsize_out) {
0313 SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n");
0314 new->pacsize_out = theirs.pacsize_out;
0315 }
0316 }
0317
0318 if (theirs.winsize_in && theirs.winsize_out) {
0319 if (theirs.winsize_in < ours->winsize_in) {
0320 SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n");
0321 new->winsize_in = theirs.winsize_in;
0322 }
0323 if (theirs.winsize_out < ours->winsize_out) {
0324 SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n");
0325 new->winsize_out = theirs.winsize_out;
0326 }
0327 }
0328
0329 return len;
0330 }
0331
0332
0333
0334
0335
0336 void x25_limit_facilities(struct x25_facilities *facilities,
0337 struct x25_neigh *nb)
0338 {
0339
0340 if (!nb->extended) {
0341 if (facilities->winsize_in > 7) {
0342 pr_debug("incoming winsize limited to 7\n");
0343 facilities->winsize_in = 7;
0344 }
0345 if (facilities->winsize_out > 7) {
0346 facilities->winsize_out = 7;
0347 pr_debug("outgoing winsize limited to 7\n");
0348 }
0349 }
0350 }