11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * X.25 Packet Layer release 002 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is ALPHA test software. This code may break your machine, 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * randomly fail to work with new releases, misbehave and/or generally 6f8e1d20183bf56f889d60edadd48f54912b9277fYOSHIFUJI Hideaki * screw up. It might even work. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code REQUIRES 2.1.15 or higher 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This module: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This module is free software; you can redistribute it and/or 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * History 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * X.25 001 Split from x25_subr.c 18f8e1d20183bf56f889d60edadd48f54912b9277fYOSHIFUJI Hideaki * mar/20/00 Daniela Squassoni Disabling/enabling of facilities 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiation. 20ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira * apr/14/05 Shaun Pereira - Allow fast select with no restriction 21ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira * on response. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong#define pr_fmt(fmt) "X25: " fmt 25b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/x25.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3295c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry/** 3395c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * x25_parse_facilities - Parse facilities from skb into the facilities structs 3495c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * 3595c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * @skb: sk_buff to parse 3625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * @facilities: Regular facilities, updated as facilities are found 3795c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * @dte_facs: ITU DTE facilities, updated as DTE facilities are found 3895c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * @vc_fac_mask: mask is updated with all facilities found 3995c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * 4095c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * Return codes: 4195c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * -1 - Parsing error, caller should drop call and clean up 4295c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * 0 - Parse OK, this skb has no facilities 4395c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * >0 - Parse OK, returns the length of the facilities header 4495c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry * 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereiraint x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, 47a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49cb101ed2c3c7c0224d16953fe77bfb9d6c2cb9dfMatthew Daley unsigned char *p; 50f5eb917b861828da18dc28854308068c66d1449aJohn Hughes unsigned int len; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vc_fac_mask = 0; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira /* 55a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira * The kernel knows which facilities were set on an incoming call but 56a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira * currently this information is not available to userspace. Here we 57a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira * give userspace who read incoming call facilities 0 length to indicate 58a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira * it wasn't set. 59a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira */ 60a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira dte_facs->calling_len = 0; 61a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira dte_facs->called_len = 0; 62a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); 63a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); 64a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira 65cb101ed2c3c7c0224d16953fe77bfb9d6c2cb9dfMatthew Daley if (!pskb_may_pull(skb, 1)) 66f5eb917b861828da18dc28854308068c66d1449aJohn Hughes return 0; 67f5eb917b861828da18dc28854308068c66d1449aJohn Hughes 68cb101ed2c3c7c0224d16953fe77bfb9d6c2cb9dfMatthew Daley len = skb->data[0]; 69f5eb917b861828da18dc28854308068c66d1449aJohn Hughes 70cb101ed2c3c7c0224d16953fe77bfb9d6c2cb9dfMatthew Daley if (!pskb_may_pull(skb, 1 + len)) 71f5eb917b861828da18dc28854308068c66d1449aJohn Hughes return -1; 72f5eb917b861828da18dc28854308068c66d1449aJohn Hughes 73cb101ed2c3c7c0224d16953fe77bfb9d6c2cb9dfMatthew Daley p = skb->data + 1; 74cb101ed2c3c7c0224d16953fe77bfb9d6c2cb9dfMatthew Daley 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len > 0) { 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (*p & X25_FAC_CLASS_MASK) { 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_CLASS_A: 785ef41308f94dcbb3b7afc56cdef1c2ba53fa5d2fDan Rosenberg if (len < 2) 7995c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry return -1; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (*p) { 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_REVERSE: 82ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira if((p[1] & 0x81) == 0x81) { 83ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira facilities->reverse = p[1] & 0x81; 84ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira *vc_fac_mask |= X25_MASK_REVERSE; 85ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira break; 86ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira } 87ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira 88ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira if((p[1] & 0x01) == 0x01) { 89ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira facilities->reverse = p[1] & 0x01; 90ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira *vc_fac_mask |= X25_MASK_REVERSE; 91ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira break; 92ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira } 93ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira 94ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira if((p[1] & 0x80) == 0x80) { 95ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira facilities->reverse = p[1] & 0x80; 96ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira *vc_fac_mask |= X25_MASK_REVERSE; 97ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira break; 98ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira } 99ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira 100ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira if(p[1] == 0x00) { 101ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira facilities->reverse 102ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira = X25_DEFAULT_REVERSE; 103ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira *vc_fac_mask |= X25_MASK_REVERSE; 104ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira break; 105ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira } 106ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_THROUGHPUT: 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds facilities->throughput = p[1]; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vc_fac_mask |= X25_MASK_THROUGHPUT; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 111a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira case X25_MARKER: 112a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira break; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 114b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong pr_debug("unknown facility " 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%02X, value %02X\n", 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p[0], p[1]); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p += 2; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= 2; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_CLASS_B: 1235ef41308f94dcbb3b7afc56cdef1c2ba53fa5d2fDan Rosenberg if (len < 3) 12495c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry return -1; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (*p) { 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_PACKET_SIZE: 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds facilities->pacsize_in = p[1]; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds facilities->pacsize_out = p[2]; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vc_fac_mask |= X25_MASK_PACKET_SIZE; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_WINDOW_SIZE: 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds facilities->winsize_in = p[1]; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds facilities->winsize_out = p[2]; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vc_fac_mask |= X25_MASK_WINDOW_SIZE; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 137b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong pr_debug("unknown facility " 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%02X, values %02X, %02X\n", 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p[0], p[1], p[2]); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p += 3; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= 3; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_CLASS_C: 1465ef41308f94dcbb3b7afc56cdef1c2ba53fa5d2fDan Rosenberg if (len < 4) 14795c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry return -1; 148b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong pr_debug("unknown facility %02X, " 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "values %02X, %02X, %02X\n", 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p[0], p[1], p[2], p[3]); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p += 4; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= 4; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case X25_FAC_CLASS_D: 1555ef41308f94dcbb3b7afc56cdef1c2ba53fa5d2fDan Rosenberg if (len < p[1] + 2) 15695c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry return -1; 157a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira switch (*p) { 158f8e1d20183bf56f889d60edadd48f54912b9277fYOSHIFUJI Hideaki case X25_FAC_CALLING_AE: 159a6331d6f9a4298173b413cf99a40cc86a9d92c37andrew hendry if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 16095c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry return -1; 16180aa4e10963cc7d9b5dd5b2568ce28d74af20bf9Dan Carpenter if (p[2] > X25_MAX_AE_LEN) 16280aa4e10963cc7d9b5dd5b2568ce28d74af20bf9Dan Carpenter return -1; 163a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira dte_facs->calling_len = p[2]; 164a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); 165a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *vc_fac_mask |= X25_MASK_CALLING_AE; 166a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira break; 167a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira case X25_FAC_CALLED_AE: 168a6331d6f9a4298173b413cf99a40cc86a9d92c37andrew hendry if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1) 16995c3043008ca8449feb96aba5481fe31c2ea750bandrew hendry return -1; 17080aa4e10963cc7d9b5dd5b2568ce28d74af20bf9Dan Carpenter if (p[2] > X25_MAX_AE_LEN) 17180aa4e10963cc7d9b5dd5b2568ce28d74af20bf9Dan Carpenter return -1; 172a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira dte_facs->called_len = p[2]; 173a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira memcpy(dte_facs->called_ae, &p[3], p[1] - 1); 174a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *vc_fac_mask |= X25_MASK_CALLED_AE; 175a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira break; 176a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira default: 177b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong pr_debug("unknown facility %02X," 1785ef41308f94dcbb3b7afc56cdef1c2ba53fa5d2fDan Rosenberg "length %d\n", p[0], p[1]); 179a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira break; 180a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira } 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= p[1] + 2; 182a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira p += p[1] + 2; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return p - skb->data; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create a set of facilities. 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint x25_create_facilities(unsigned char *buffer, 194a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira struct x25_facilities *facilities, 195a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira struct x25_dte_facilities *dte_facs, unsigned long facil_mask) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *p = buffer + 1; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!facil_mask) { 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Length of the facilities field in call_req or 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * call_accept packets 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer[0] = 0; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 1; /* 1 byte for the length field */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = X25_FAC_REVERSE; 212ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira *p++ = facilities->reverse; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = X25_FAC_THROUGHPUT; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = facilities->throughput; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((facilities->pacsize_in || facilities->pacsize_out) && 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (facil_mask & X25_MASK_PACKET_SIZE)) { 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = X25_FAC_PACKET_SIZE; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = facilities->pacsize_in ? : facilities->pacsize_out; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = facilities->pacsize_out ? : facilities->pacsize_in; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((facilities->winsize_in || facilities->winsize_out) && 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (facil_mask & X25_MASK_WINDOW_SIZE)) { 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = X25_FAC_WINDOW_SIZE; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = facilities->winsize_in ? : facilities->winsize_out; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = facilities->winsize_out ? : facilities->winsize_in; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 234a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) { 235a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = X25_MARKER; 236a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = X25_DTE_SERVICES; 237a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira } 238a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira 239a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { 24095c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet unsigned int bytecount = (dte_facs->calling_len + 1) >> 1; 241a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = X25_FAC_CALLING_AE; 242a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = 1 + bytecount; 243a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = dte_facs->calling_len; 244a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira memcpy(p, dte_facs->calling_ae, bytecount); 245a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira p += bytecount; 246a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira } 247a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira 248a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { 24995c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet unsigned int bytecount = (dte_facs->called_len % 2) ? 250a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira dte_facs->called_len / 2 + 1 : 251a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira dte_facs->called_len / 2; 252a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = X25_FAC_CALLED_AE; 253a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = 1 + bytecount; 254a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira *p++ = dte_facs->called_len; 255a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira memcpy(p, dte_facs->called_ae, bytecount); 256a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira p+=bytecount; 257a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira } 258a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = p - buffer; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer[0] = len - 1; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to reach a compromise on a set of facilities. 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The only real problem is with reverse charging. 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, 271a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira struct x25_facilities *new, struct x25_dte_facilities *dte) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct x25_sock *x25 = x25_sk(sk); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct x25_facilities *ours = &x25->facilities; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct x25_facilities theirs; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&theirs, 0, sizeof(theirs)); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(new, ours, sizeof(*new)); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281a64b7b936dcd926ace745c07c14f45ecfaddb034Shaun Pereira len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); 282f5eb917b861828da18dc28854308068c66d1449aJohn Hughes if (len < 0) 283f5eb917b861828da18dc28854308068c66d1449aJohn Hughes return len; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * They want reverse charging, we won't accept it. 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 288ebc3f64b864fc16a594c2e63bf55a55c7d42084bShaun Pereira if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) { 289d2e7543c41755f4ec75385536b109d5f084fe734Andrew Hendry SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n"); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new->reverse = theirs.reverse; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (theirs.throughput) { 296ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes int theirs_in = theirs.throughput & 0x0f; 297ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes int theirs_out = theirs.throughput & 0xf0; 298ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes int ours_in = ours->throughput & 0x0f; 299ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes int ours_out = ours->throughput & 0xf0; 300ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes if (!ours_in || theirs_in < ours_in) { 301ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes SOCK_DEBUG(sk, "X.25: inbound throughput negotiated\n"); 302ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes new->throughput = (new->throughput & 0xf0) | theirs_in; 303ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes } 304ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes if (!ours_out || theirs_out < ours_out) { 305ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes SOCK_DEBUG(sk, 306ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes "X.25: outbound throughput negotiated\n"); 307ddd0451fc8dbf94446c81500ff0dcee06c4057cbJohn Hughes new->throughput = (new->throughput & 0x0f) | theirs_out; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (theirs.pacsize_in && theirs.pacsize_out) { 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (theirs.pacsize_in < ours->pacsize_in) { 313d2e7543c41755f4ec75385536b109d5f084fe734Andrew Hendry SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n"); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new->pacsize_in = theirs.pacsize_in; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (theirs.pacsize_out < ours->pacsize_out) { 317d2e7543c41755f4ec75385536b109d5f084fe734Andrew Hendry SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n"); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new->pacsize_out = theirs.pacsize_out; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (theirs.winsize_in && theirs.winsize_out) { 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (theirs.winsize_in < ours->winsize_in) { 324d2e7543c41755f4ec75385536b109d5f084fe734Andrew Hendry SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n"); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new->winsize_in = theirs.winsize_in; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (theirs.winsize_out < ours->winsize_out) { 328d2e7543c41755f4ec75385536b109d5f084fe734Andrew Hendry SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n"); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new->winsize_out = theirs.winsize_out; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 337f8e1d20183bf56f889d60edadd48f54912b9277fYOSHIFUJI Hideaki * Limit values of certain facilities according to the capability of the 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * currently attached x25 link. 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid x25_limit_facilities(struct x25_facilities *facilities, 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct x25_neigh *nb) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!nb->extended) { 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (facilities->winsize_in > 7) { 346b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong pr_debug("incoming winsize limited to 7\n"); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds facilities->winsize_in = 7; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (facilities->winsize_out > 7) { 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds facilities->winsize_out = 7; 351b73e9e3cf06ef8180c75a6bd28cdd1b833d22a3awangweidong pr_debug("outgoing winsize limited to 7\n"); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 355