1 /*
2  *	X.25 Packet Layer release 002
3  *
4  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new
5  *	releases, misbehave and/or generally screw up. It might even work.
6  *
7  *	This code REQUIRES 2.1.15 or higher
8  *
9  *	This module:
10  *		This module is free software; you can redistribute it and/or
11  *		modify it under the terms of the GNU General Public License
12  *		as published by the Free Software Foundation; either version
13  *		2 of the License, or (at your option) any later version.
14  *
15  *	History
16  *	X.25 001	Split from x25_subr.c
17  *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities
18  *					  negotiation.
19  */
20 
21 #include <linux/errno.h>
22 #include <linux/types.h>
23 #include <linux/socket.h>
24 #include <linux/in.h>
25 #include <linux/kernel.h>
26 #include <linux/sched.h>
27 #include <linux/timer.h>
28 #include <linux/string.h>
29 #include <linux/sockios.h>
30 #include <linux/net.h>
31 #include <linux/inet.h>
32 #include <linux/netdevice.h>
33 #include <linux/skbuff.h>
34 #include <net/sock.h>
35 #include <asm/segment.h>
36 #include <asm/system.h>
37 #include <linux/fcntl.h>
38 #include <linux/mm.h>
39 #include <linux/interrupt.h>
40 #include <net/x25.h>
41 
42 /*
43  *	Parse a set of facilities into the facilities structure. Unrecognised
44  *	facilities are written to the debug log file.
45  */
x25_parse_facilities(struct sk_buff * skb,struct x25_facilities * facilities,unsigned long * vc_fac_mask)46 int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, unsigned long *vc_fac_mask)
47 {
48 	unsigned int len;
49 	unsigned char *p = skb->data;
50 
51 	len = *p++;
52 	*vc_fac_mask = 0;
53 
54 	while (len > 0) {
55 		switch (*p & X25_FAC_CLASS_MASK) {
56 			case X25_FAC_CLASS_A:
57 				switch (*p) {
58 					case X25_FAC_REVERSE:
59 						facilities->reverse = (p[1] & 0x01);
60 						*vc_fac_mask |= X25_MASK_REVERSE;
61 						break;
62 					case X25_FAC_THROUGHPUT:
63 						facilities->throughput = p[1];
64 						*vc_fac_mask |= X25_MASK_THROUGHPUT;
65 						break;
66 					default:
67 						printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]);
68 						break;
69 				}
70 				p   += 2;
71 				len -= 2;
72 				break;
73 
74 			case X25_FAC_CLASS_B:
75 				switch (*p) {
76 					case X25_FAC_PACKET_SIZE:
77 						facilities->pacsize_in  = p[1];
78 						facilities->pacsize_out = p[2];
79 						*vc_fac_mask |= X25_MASK_PACKET_SIZE;
80 						break;
81 					case X25_FAC_WINDOW_SIZE:
82 						facilities->winsize_in  = p[1];
83 						facilities->winsize_out = p[2];
84 						*vc_fac_mask |= X25_MASK_WINDOW_SIZE;
85 						break;
86 					default:
87 						printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]);
88 						break;
89 				}
90 				p   += 3;
91 				len -= 3;
92 				break;
93 
94 			case X25_FAC_CLASS_C:
95 				printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X, %02X\n", p[0], p[1], p[2], p[3]);
96 				p   += 4;
97 				len -= 4;
98 				break;
99 
100 			case X25_FAC_CLASS_D:
101 				printk(KERN_DEBUG "X.25: unknown facility %02X, length %d, values %02X, %02X, %02X, %02X\n", p[0], p[1], p[2], p[3], p[4], p[5]);
102 				len -= p[1] + 2;
103 				p   += p[1] + 2;
104 				break;
105 		}
106 	}
107 
108 	return p - skb->data;
109 }
110 
111 /*
112  *	Create a set of facilities.
113  */
x25_create_facilities(unsigned char * buffer,struct x25_facilities * facilities,unsigned long facil_mask)114 int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities, unsigned long facil_mask)
115 {
116 	unsigned char *p = buffer + 1;
117 	int len;
118 
119 	if (facil_mask == 0) {
120 		buffer [0] = 0; /* length of the facilities field in call_req or call_accept packets */
121 		len = 1; /* 1 byte for the length field */
122 		return len;
123 	}
124 
125 	if ((facilities->reverse != 0) && (facil_mask & X25_MASK_REVERSE)) {
126 		*p++ = X25_FAC_REVERSE;
127 		*p++ = (facilities->reverse) ? 0x01 : 0x00;
128 	}
129 
130 	if ((facilities->throughput != 0) && (facil_mask & X25_MASK_THROUGHPUT)) {
131 		*p++ = X25_FAC_THROUGHPUT;
132 		*p++ = facilities->throughput;
133 	}
134 
135 	if ((facilities->pacsize_in != 0 || facilities->pacsize_out != 0) && (facil_mask & X25_MASK_PACKET_SIZE)) {
136 		*p++ = X25_FAC_PACKET_SIZE;
137 		*p++ = (facilities->pacsize_in  == 0) ? facilities->pacsize_out : facilities->pacsize_in;
138 		*p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in  : facilities->pacsize_out;
139 	}
140 
141 	if ((facilities->winsize_in != 0 || facilities->winsize_out != 0) && (facil_mask & X25_MASK_WINDOW_SIZE)) {
142 		*p++ = X25_FAC_WINDOW_SIZE;
143 		*p++ = (facilities->winsize_in  == 0) ? facilities->winsize_out : facilities->winsize_in;
144 		*p++ = (facilities->winsize_out == 0) ? facilities->winsize_in  : facilities->winsize_out;
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  */
x25_negotiate_facilities(struct sk_buff * skb,struct sock * sk,struct x25_facilities * new)158 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_facilities *new)
159 {
160 	struct x25_facilities *ours;
161 	struct x25_facilities theirs;
162 	int len;
163 
164 	memset(&theirs, 0x00, sizeof(struct x25_facilities));
165 
166 	ours = &sk->protinfo.x25->facilities;
167 
168 	*new = *ours;
169 
170 	len = x25_parse_facilities(skb, &theirs, &sk->protinfo.x25->vc_facil_mask);
171 
172 	/*
173 	 *	They want reverse charging, we won't accept it.
174 	 */
175 	if (theirs.reverse != 0 && ours->reverse == 0) {
176 		SOCK_DEBUG(sk, "X.25: rejecting reverse charging request");
177 		return -1;
178 	}
179 
180 	new->reverse = theirs.reverse;
181 
182 	if (theirs.throughput != 0) {
183 		if (theirs.throughput < ours->throughput) {
184 			SOCK_DEBUG(sk, "X.25: throughput negotiated down");
185 			new->throughput = theirs.throughput;
186 		}
187 	}
188 
189 	if (theirs.pacsize_in != 0 && theirs.pacsize_out != 0) {
190 		if (theirs.pacsize_in < ours->pacsize_in) {
191 			SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down");
192 			new->pacsize_in = theirs.pacsize_in;
193 		}
194 		if (theirs.pacsize_out < ours->pacsize_out) {
195 			SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down");
196 			new->pacsize_out = theirs.pacsize_out;
197 		}
198 	}
199 
200 	if (theirs.winsize_in != 0 && theirs.winsize_out != 0) {
201 		if (theirs.winsize_in < ours->winsize_in) {
202 			SOCK_DEBUG(sk, "X.25: window size inwards negotiated down");
203 			new->winsize_in = theirs.winsize_in;
204 		}
205 		if (theirs.winsize_out < ours->winsize_out) {
206 			SOCK_DEBUG(sk, "X.25: window size outwards negotiated down");
207 			new->winsize_out = theirs.winsize_out;
208 		}
209 	}
210 
211 	return len;
212 }
213 
214 /*
215  *	Limit values of certain facilities according to the capability of the
216  *      currently attached x25 link.
217  */
x25_limit_facilities(struct x25_facilities * facilities,struct x25_neigh * neighbour)218 void x25_limit_facilities(struct x25_facilities *facilities,
219 			  struct x25_neigh *neighbour)
220 {
221 
222 	if( ! neighbour->extended ){
223 		if( facilities->winsize_in  > 7 ){
224 			printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
225 			facilities->winsize_in = 7;
226 		}
227 		if( facilities->winsize_out > 7 ){
228 			facilities->winsize_out = 7;
229 			printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
230 		}
231 	}
232 }
233