2 * X.25 Packet Layer release 002
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.
7 * This code REQUIRES 2.1.15 or higher
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.
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
20 * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh.
23 #include <linux/errno.h>
24 #include <linux/types.h>
25 #include <linux/socket.h>
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/timer.h>
30 #include <linux/string.h>
31 #include <linux/sockios.h>
32 #include <linux/net.h>
33 #include <linux/inet.h>
34 #include <linux/netdevice.h>
35 #include <linux/skbuff.h>
37 #include <asm/segment.h>
38 #include <asm/system.h>
39 #include <asm/uaccess.h>
40 #include <linux/fcntl.h>
42 #include <linux/interrupt.h>
43 #include <linux/init.h>
46 static struct x25_neigh *x25_neigh_list /* = NULL initially */;
48 static void x25_t20timer_expiry(unsigned long);
51 * Linux set/reset timer routines
53 static void x25_start_t20timer(struct x25_neigh *neigh)
55 del_timer(&neigh->t20timer);
57 neigh->t20timer.data = (unsigned long)neigh;
58 neigh->t20timer.function = &x25_t20timer_expiry;
59 neigh->t20timer.expires = jiffies + neigh->t20;
61 add_timer(&neigh->t20timer);
64 static void x25_t20timer_expiry(unsigned long param)
66 struct x25_neigh *neigh = (struct x25_neigh *)param;
68 x25_transmit_restart_request(neigh);
70 x25_start_t20timer(neigh);
73 static void x25_stop_t20timer(struct x25_neigh *neigh)
75 del_timer(&neigh->t20timer);
78 static int x25_t20timer_pending(struct x25_neigh *neigh)
80 return timer_pending(&neigh->t20timer);
84 * This handles all restart and diagnostic frames.
86 void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned short frametype)
92 case X25_RESTART_REQUEST:
93 confirm = !x25_t20timer_pending(neigh);
94 x25_stop_t20timer(neigh);
95 neigh->state = X25_LINK_STATE_3;
96 if (confirm) x25_transmit_restart_confirmation(neigh);
99 case X25_RESTART_CONFIRMATION:
100 x25_stop_t20timer(neigh);
101 neigh->state = X25_LINK_STATE_3;
105 printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
109 printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", frametype);
113 if (neigh->state == X25_LINK_STATE_3) {
114 while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
115 x25_send_frame(skbn, neigh);
120 * This routine is called when a Restart Request is needed
122 void x25_transmit_restart_request(struct x25_neigh *neigh)
128 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
130 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
133 skb_reserve(skb, X25_MAX_L2_LEN);
135 dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
137 *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
139 *dptr++ = X25_RESTART_REQUEST;
145 x25_send_frame(skb, neigh);
149 * This routine is called when a Restart Confirmation is needed
151 void x25_transmit_restart_confirmation(struct x25_neigh *neigh)
157 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
159 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
162 skb_reserve(skb, X25_MAX_L2_LEN);
164 dptr = skb_put(skb, X25_STD_MIN_LEN);
166 *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
168 *dptr++ = X25_RESTART_CONFIRMATION;
172 x25_send_frame(skb, neigh);
176 * This routine is called when a Diagnostic is required.
178 void x25_transmit_diagnostic(struct x25_neigh *neigh, unsigned char diag)
184 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
186 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
189 skb_reserve(skb, X25_MAX_L2_LEN);
191 dptr = skb_put(skb, X25_STD_MIN_LEN + 1);
193 *dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
195 *dptr++ = X25_DIAGNOSTIC;
200 x25_send_frame(skb, neigh);
204 * This routine is called when a Clear Request is needed outside of the context
205 * of a connected socket.
207 void x25_transmit_clear_request(struct x25_neigh *neigh, unsigned int lci, unsigned char cause)
213 len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
215 if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
218 skb_reserve(skb, X25_MAX_L2_LEN);
220 dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
222 *dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ);
223 *dptr++ = ((lci >> 0) & 0xFF);
224 *dptr++ = X25_CLEAR_REQUEST;
230 x25_send_frame(skb, neigh);
233 void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
235 switch (neigh->state) {
236 case X25_LINK_STATE_0:
237 skb_queue_tail(&neigh->queue, skb);
238 neigh->state = X25_LINK_STATE_1;
239 x25_establish_link(neigh);
241 case X25_LINK_STATE_1:
242 case X25_LINK_STATE_2:
243 skb_queue_tail(&neigh->queue, skb);
245 case X25_LINK_STATE_3:
246 x25_send_frame(skb, neigh);
252 * Called when the link layer has become established.
254 void x25_link_established(struct x25_neigh *neigh)
256 switch (neigh->state) {
257 case X25_LINK_STATE_0:
258 neigh->state = X25_LINK_STATE_2;
260 case X25_LINK_STATE_1:
261 x25_transmit_restart_request(neigh);
262 neigh->state = X25_LINK_STATE_2;
263 x25_start_t20timer(neigh);
269 * Called when the link layer has terminated, or an establishment
270 * request has failed.
273 void x25_link_terminated(struct x25_neigh *neigh)
275 neigh->state = X25_LINK_STATE_0;
276 /* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
277 x25_kill_by_neigh(neigh);
283 void x25_link_device_up(struct net_device *dev)
285 struct x25_neigh *x25_neigh;
288 if ((x25_neigh = kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL)
291 skb_queue_head_init(&x25_neigh->queue);
293 init_timer(&x25_neigh->t20timer);
296 x25_neigh->dev = dev;
297 x25_neigh->state = X25_LINK_STATE_0;
298 x25_neigh->extended = 0;
299 x25_neigh->global_facil_mask = (X25_MASK_REVERSE | X25_MASK_THROUGHPUT | X25_MASK_PACKET_SIZE | X25_MASK_WINDOW_SIZE); /* enables negotiation */
300 x25_neigh->t20 = sysctl_x25_restart_request_timeout;
302 save_flags(flags); cli();
303 x25_neigh->next = x25_neigh_list;
304 x25_neigh_list = x25_neigh;
305 restore_flags(flags);
308 static void x25_remove_neigh(struct x25_neigh *x25_neigh)
313 skb_queue_purge(&x25_neigh->queue);
315 x25_stop_t20timer(x25_neigh);
317 save_flags(flags); cli();
319 if ((s = x25_neigh_list) == x25_neigh) {
320 x25_neigh_list = x25_neigh->next;
321 restore_flags(flags);
326 while (s != NULL && s->next != NULL) {
327 if (s->next == x25_neigh) {
328 s->next = x25_neigh->next;
329 restore_flags(flags);
337 restore_flags(flags);
341 * A device has been removed, remove its links.
343 void x25_link_device_down(struct net_device *dev)
345 struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
347 while (x25_neigh != NULL) {
349 x25_neigh = x25_neigh->next;
351 if (neigh->dev == dev){
352 x25_remove_neigh(neigh);
359 * Given a device, return the neighbour address.
361 struct x25_neigh *x25_get_neigh(struct net_device *dev)
363 struct x25_neigh *x25_neigh;
365 for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next)
366 if (x25_neigh->dev == dev)
373 * Handle the ioctls that control the subscription functions.
375 int x25_subscr_ioctl(unsigned int cmd, void *arg)
377 struct x25_subscrip_struct x25_subscr;
378 struct x25_neigh *x25_neigh;
379 struct net_device *dev;
383 case SIOCX25GSUBSCRIP:
384 if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
386 if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
388 if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
393 x25_subscr.extended = x25_neigh->extended;
394 x25_subscr.global_facil_mask = x25_neigh->global_facil_mask;
395 if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
399 case SIOCX25SSUBSCRIP:
400 if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
402 if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
404 if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
409 if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
411 x25_neigh->extended = x25_subscr.extended;
412 x25_neigh->global_facil_mask = x25_subscr.global_facil_mask;
424 * Release all memory associated with X.25 neighbour structures.
426 void __exit x25_link_free(void)
428 struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
430 while (x25_neigh != NULL) {
432 x25_neigh = x25_neigh->next;
434 x25_remove_neigh(neigh);