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