~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/x25/x25_link.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.