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 Jonathan Naylor Started coding.
17 * X.25 002 Jonathan Naylor New timer architecture.
18 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
19 * negotiation.
20 * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh.
21 */
22
23 #include <linux/config.h>
24 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
25 #include <linux/errno.h>
26 #include <linux/types.h>
27 #include <linux/socket.h>
28 #include <linux/in.h>
29 #include <linux/kernel.h>
30 #include <linux/sched.h>
31 #include <linux/timer.h>
32 #include <linux/string.h>
33 #include <linux/sockios.h>
34 #include <linux/net.h>
35 #include <linux/inet.h>
36 #include <linux/netdevice.h>
37 #include <linux/skbuff.h>
38 #include <net/sock.h>
39 #include <asm/segment.h>
40 #include <asm/system.h>
41 #include <asm/uaccess.h>
42 #include <linux/fcntl.h>
43 #include <linux/mm.h>
44 #include <linux/interrupt.h>
45 #include <net/x25.h>
46
47 static struct x25_neigh *x25_neigh_list = NULL;
48
49 static void x25_t20timer_expiry(unsigned long);
50
51 /*
52 * Linux set/reset timer routines
53 */
54 static void x25_start_t20timer(struct x25_neigh *neigh)
55 {
56 del_timer(&neigh->t20timer);
57
58 neigh->t20timer.data = (unsigned long)neigh;
59 neigh->t20timer.function = &x25_t20timer_expiry;
60 neigh->t20timer.expires = jiffies + neigh->t20;
61
62 add_timer(&neigh->t20timer);
63 }
64
65 static void x25_t20timer_expiry(unsigned long param)
66 {
67 struct x25_neigh *neigh = (struct x25_neigh *)param;
68
69 x25_transmit_restart_request(neigh);
70
71 x25_start_t20timer(neigh);
72 }
73
74 static void x25_stop_t20timer(struct x25_neigh *neigh)
75 {
76 del_timer(&neigh->t20timer);
77 }
78
79 static int x25_t20timer_pending(struct x25_neigh *neigh)
80 {
81 return timer_pending(&neigh->t20timer);
82 }
83
84 /*
85 * This handles all restart and diagnostic frames.
86 */
87 void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned short frametype)
88 {
89 struct sk_buff *skbn;
90 int confirm;
91
92 switch (frametype) {
93 case X25_RESTART_REQUEST:
94 confirm = !x25_t20timer_pending(neigh);
95 x25_stop_t20timer(neigh);
96 neigh->state = X25_LINK_STATE_3;
97 if (confirm) x25_transmit_restart_confirmation(neigh);
98 break;
99
100 case X25_RESTART_CONFIRMATION:
101 x25_stop_t20timer(neigh);
102 neigh->state = X25_LINK_STATE_3;
103 break;
104
105 case X25_DIAGNOSTIC:
106 printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
107 break;
108
109 default:
110 printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", frametype);
111 break;
112 }
113
114 if (neigh->state == X25_LINK_STATE_3) {
115 while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
116 x25_send_frame(skbn, neigh);
117 }
118 }
119
120 /*
121 * This routine is called when a Restart Request is needed
122 */
123 void x25_transmit_restart_request(struct x25_neigh *neigh)
124 {
125 struct sk_buff *skb;
126 unsigned char *dptr;
127 int len;
128
129 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
130
131 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
132 return;
133
134 skb_reserve(skb, X25_MAX_L2_LEN);
135
136 dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
137
138 *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
139 *dptr++ = 0x00;
140 *dptr++ = X25_RESTART_REQUEST;
141 *dptr++ = 0x00;
142 *dptr++ = 0;
143
144 skb->sk = NULL;
145
146 x25_send_frame(skb, neigh);
147 }
148
149 /*
150 * This routine is called when a Restart Confirmation is needed
151 */
152 void x25_transmit_restart_confirmation(struct x25_neigh *neigh)
153 {
154 struct sk_buff *skb;
155 unsigned char *dptr;
156 int len;
157
158 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
159
160 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
161 return;
162
163 skb_reserve(skb, X25_MAX_L2_LEN);
164
165 dptr = skb_put(skb, X25_STD_MIN_LEN);
166
167 *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
168 *dptr++ = 0x00;
169 *dptr++ = X25_RESTART_CONFIRMATION;
170
171 skb->sk = NULL;
172
173 x25_send_frame(skb, neigh);
174 }
175
176 /*
177 * This routine is called when a Diagnostic is required.
178 */
179 void x25_transmit_diagnostic(struct x25_neigh *neigh, unsigned char diag)
180 {
181 struct sk_buff *skb;
182 unsigned char *dptr;
183 int len;
184
185 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
186
187 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
188 return;
189
190 skb_reserve(skb, X25_MAX_L2_LEN);
191
192 dptr = skb_put(skb, X25_STD_MIN_LEN + 1);
193
194 *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
195 *dptr++ = 0x00;
196 *dptr++ = X25_DIAGNOSTIC;
197 *dptr++ = diag;
198
199 skb->sk = NULL;
200
201 x25_send_frame(skb, neigh);
202 }
203
204 /*
205 * This routine is called when a Clear Request is needed outside of the context
206 * of a connected socket.
207 */
208 void x25_transmit_clear_request(struct x25_neigh *neigh, unsigned int lci, unsigned char cause)
209 {
210 struct sk_buff *skb;
211 unsigned char *dptr;
212 int len;
213
214 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
215
216 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
217 return;
218
219 skb_reserve(skb, X25_MAX_L2_LEN);
220
221 dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
222
223 *dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
224 *dptr++ = ((lci >> 0) & 0xFF);
225 *dptr++ = X25_CLEAR_REQUEST;
226 *dptr++ = cause;
227 *dptr++ = 0x00;
228
229 skb->sk = NULL;
230
231 x25_send_frame(skb, neigh);
232 }
233
234 void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
235 {
236 switch (neigh->state) {
237 case X25_LINK_STATE_0:
238 skb_queue_tail(&neigh->queue, skb);
239 neigh->state = X25_LINK_STATE_1;
240 x25_establish_link(neigh);
241 break;
242 case X25_LINK_STATE_1:
243 case X25_LINK_STATE_2:
244 skb_queue_tail(&neigh->queue, skb);
245 break;
246 case X25_LINK_STATE_3:
247 x25_send_frame(skb, neigh);
248 break;
249 }
250 }
251
252 /*
253 * Called when the link layer has become established.
254 */
255 void x25_link_established(struct x25_neigh *neigh)
256 {
257 switch (neigh->state) {
258 case X25_LINK_STATE_0:
259 neigh->state = X25_LINK_STATE_2;
260 break;
261 case X25_LINK_STATE_1:
262 x25_transmit_restart_request(neigh);
263 neigh->state = X25_LINK_STATE_2;
264 x25_start_t20timer(neigh);
265 break;
266 }
267 }
268
269 /*
270 * Called when the link layer has terminated, or an establishment
271 * request has failed.
272 */
273
274 void x25_link_terminated(struct x25_neigh *neigh)
275 {
276 neigh->state = X25_LINK_STATE_0;
277 /* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
278 x25_kill_by_neigh(neigh);
279 }
280
281 /*
282 * Add a new device.
283 */
284 void x25_link_device_up(struct net_device *dev)
285 {
286 struct x25_neigh *x25_neigh;
287 unsigned long flags;
288
289 if ((x25_neigh = kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL)
290 return;
291
292 skb_queue_head_init(&x25_neigh->queue);
293
294 init_timer(&x25_neigh->t20timer);
295
296 dev_hold(dev);
297 x25_neigh->dev = dev;
298 x25_neigh->state = X25_LINK_STATE_0;
299 x25_neigh->extended = 0;
300 x25_neigh->global_facil_mask = (X25_MASK_REVERSE | X25_MASK_THROUGHPUT | X25_MASK_PACKET_SIZE | X25_MASK_WINDOW_SIZE); /* enables negotiation */
301 x25_neigh->t20 = sysctl_x25_restart_request_timeout;
302
303 save_flags(flags); cli();
304 x25_neigh->next = x25_neigh_list;
305 x25_neigh_list = x25_neigh;
306 restore_flags(flags);
307 }
308
309 static void x25_remove_neigh(struct x25_neigh *x25_neigh)
310 {
311 struct x25_neigh *s;
312 unsigned long flags;
313 struct sk_buff *skb;
314
315 while ((skb = skb_dequeue(&x25_neigh->queue)) != NULL)
316 kfree_skb(skb);
317
318 x25_stop_t20timer(x25_neigh);
319
320 save_flags(flags); cli();
321
322 if ((s = x25_neigh_list) == x25_neigh) {
323 x25_neigh_list = x25_neigh->next;
324 restore_flags(flags);
325 kfree(x25_neigh);
326 return;
327 }
328
329 while (s != NULL && s->next != NULL) {
330 if (s->next == x25_neigh) {
331 s->next = x25_neigh->next;
332 restore_flags(flags);
333 kfree(x25_neigh);
334 return;
335 }
336
337 s = s->next;
338 }
339
340 restore_flags(flags);
341 }
342
343 /*
344 * A device has been removed, remove its links.
345 */
346 void x25_link_device_down(struct net_device *dev)
347 {
348 struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
349
350 while (x25_neigh != NULL) {
351 neigh = x25_neigh;
352 x25_neigh = x25_neigh->next;
353
354 if (neigh->dev == dev){
355 x25_remove_neigh(neigh);
356 dev_put(dev);
357 }
358 }
359 }
360
361 /*
362 * Given a device, return the neighbour address.
363 */
364 struct x25_neigh *x25_get_neigh(struct net_device *dev)
365 {
366 struct x25_neigh *x25_neigh;
367
368 for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next)
369 if (x25_neigh->dev == dev)
370 return x25_neigh;
371
372 return NULL;
373 }
374
375 /*
376 * Handle the ioctls that control the subscription functions.
377 */
378 int x25_subscr_ioctl(unsigned int cmd, void *arg)
379 {
380 struct x25_subscrip_struct x25_subscr;
381 struct x25_neigh *x25_neigh;
382 struct net_device *dev;
383
384 switch (cmd) {
385
386 case SIOCX25GSUBSCRIP:
387 if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
388 return -EFAULT;
389 if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
390 return -EINVAL;
391 if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
392 dev_put(dev);
393 return -EINVAL;
394 }
395 dev_put(dev);
396 x25_subscr.extended = x25_neigh->extended;
397 x25_subscr.global_facil_mask = x25_neigh->global_facil_mask;
398 if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
399 return -EFAULT;
400 break;
401
402 case SIOCX25SSUBSCRIP:
403 if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
404 return -EFAULT;
405 if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
406 return -EINVAL;
407 if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
408 dev_put(dev);
409 return -EINVAL;
410 }
411 dev_put(dev);
412 if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
413 return -EINVAL;
414 x25_neigh->extended = x25_subscr.extended;
415 x25_neigh->global_facil_mask = x25_subscr.global_facil_mask;
416 break;
417
418 default:
419 return -EINVAL;
420 }
421
422 return 0;
423 }
424
425 #ifdef MODULE
426
427 /*
428 * Release all memory associated with X.25 neighbour structures.
429 */
430 void x25_link_free(void)
431 {
432 struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
433
434 while (x25_neigh != NULL) {
435 neigh = x25_neigh;
436 x25_neigh = x25_neigh->next;
437
438 x25_remove_neigh(neigh);
439 }
440 }
441
442 #endif
443
444 #endif
445
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.