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

Linux Cross Reference
Linux/net/x25/x25_subr.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   Centralised disconnection processing.
 18  *      mar/20/00       Daniela Squassoni Disabling/enabling of facilities 
 19  *                                        negotiation.
 20  */
 21 
 22 #include <linux/config.h>
 23 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
 24 #include <linux/errno.h>
 25 #include <linux/types.h>
 26 #include <linux/socket.h>
 27 #include <linux/in.h>
 28 #include <linux/kernel.h>
 29 #include <linux/sched.h>
 30 #include <linux/timer.h>
 31 #include <linux/string.h>
 32 #include <linux/sockios.h>
 33 #include <linux/net.h>
 34 #include <linux/inet.h>
 35 #include <linux/netdevice.h>
 36 #include <linux/skbuff.h>
 37 #include <net/sock.h>
 38 #include <asm/segment.h>
 39 #include <asm/system.h>
 40 #include <linux/fcntl.h>
 41 #include <linux/mm.h>
 42 #include <linux/interrupt.h>
 43 #include <net/x25.h>
 44 
 45 /*
 46  *      This routine purges all of the queues of frames.
 47  */
 48 void x25_clear_queues(struct sock *sk)
 49 {
 50         struct sk_buff *skb;
 51 
 52         while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
 53                 kfree_skb(skb);
 54 
 55         while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL)
 56                 kfree_skb(skb);
 57 
 58         while ((skb = skb_dequeue(&sk->protinfo.x25->interrupt_in_queue)) != NULL)
 59                 kfree_skb(skb);
 60 
 61         while ((skb = skb_dequeue(&sk->protinfo.x25->interrupt_out_queue)) != NULL)
 62                 kfree_skb(skb);
 63 
 64         while ((skb = skb_dequeue(&sk->protinfo.x25->fragment_queue)) != NULL)
 65                 kfree_skb(skb);
 66 }
 67 
 68 
 69 /*
 70  * This routine purges the input queue of those frames that have been
 71  * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
 72  * SDL diagram.
 73 */
 74 void x25_frames_acked(struct sock *sk, unsigned short nr)
 75 {
 76         struct sk_buff *skb;
 77         int modulus;
 78 
 79         modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
 80 
 81         /*
 82          * Remove all the ack-ed frames from the ack queue.
 83          */
 84         if (sk->protinfo.x25->va != nr) {
 85                 while (skb_peek(&sk->protinfo.x25->ack_queue) != NULL && sk->protinfo.x25->va != nr) {
 86                         skb = skb_dequeue(&sk->protinfo.x25->ack_queue);
 87                         kfree_skb(skb);
 88                         sk->protinfo.x25->va = (sk->protinfo.x25->va + 1) % modulus;
 89                 }
 90         }
 91 }
 92 
 93 void x25_requeue_frames(struct sock *sk)
 94 {
 95         struct sk_buff *skb, *skb_prev = NULL;
 96 
 97         /*
 98          * Requeue all the un-ack-ed frames on the output queue to be picked
 99          * up by x25_kick. This arrangement handles the possibility of an empty
100          * output queue.
101          */
102         while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL) {
103                 if (skb_prev == NULL)
104                         skb_queue_head(&sk->write_queue, skb);
105                 else
106                         skb_append(skb_prev, skb);
107                 skb_prev = skb;
108         }
109 }
110 
111 /*
112  *      Validate that the value of nr is between va and vs. Return true or
113  *      false for testing.
114  */
115 int x25_validate_nr(struct sock *sk, unsigned short nr)
116 {
117         unsigned short vc = sk->protinfo.x25->va;
118         int modulus;
119 
120         modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
121 
122         while (vc != sk->protinfo.x25->vs) {
123                 if (nr == vc) return 1;
124                 vc = (vc + 1) % modulus;
125         }
126 
127         if (nr == sk->protinfo.x25->vs) return 1;
128 
129         return 0;
130 }
131 
132 /* 
133  *  This routine is called when the packet layer internally generates a
134  *  control frame.
135  */
136 void x25_write_internal(struct sock *sk, int frametype)
137 {
138         struct sk_buff *skb;
139         unsigned char  *dptr;
140         unsigned char  facilities[X25_MAX_FAC_LEN];
141         unsigned char  addresses[1 + X25_ADDR_LEN];
142         unsigned char  lci1, lci2;
143         int len;
144 
145         /*
146          *      Default safe frame size.
147          */
148         len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
149 
150         /*
151          *      Adjust frame size.
152          */
153         switch (frametype) {
154                 case X25_CALL_REQUEST:
155                         len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
156                         break;
157                 case X25_CALL_ACCEPTED:
158                         len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
159                         break;
160                 case X25_CLEAR_REQUEST:
161                 case X25_RESET_REQUEST:
162                         len += 2;
163                         break;
164                 case X25_RR:
165                 case X25_RNR:
166                 case X25_REJ:
167                 case X25_CLEAR_CONFIRMATION:
168                 case X25_INTERRUPT_CONFIRMATION:
169                 case X25_RESET_CONFIRMATION:
170                         break;
171                 default:
172                         printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype);
173                         return;
174         }
175 
176         if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
177                 return;
178 
179         /*
180          *      Space for Ethernet and 802.2 LLC headers.
181          */
182         skb_reserve(skb, X25_MAX_L2_LEN);
183 
184         /*
185          *      Make space for the GFI and LCI, and fill them in.
186          */
187         dptr = skb_put(skb, 2);
188 
189         lci1 = (sk->protinfo.x25->lci >> 8) & 0x0F;
190         lci2 = (sk->protinfo.x25->lci >> 0) & 0xFF;
191 
192         if (sk->protinfo.x25->neighbour->extended) {
193                 *dptr++ = lci1 | X25_GFI_EXTSEQ;
194                 *dptr++ = lci2;
195         } else {
196                 *dptr++ = lci1 | X25_GFI_STDSEQ;
197                 *dptr++ = lci2;
198         }
199 
200         /*
201          *      Now fill in the frame type specific information.
202          */
203         switch (frametype) {
204 
205                 case X25_CALL_REQUEST:
206                         dptr    = skb_put(skb, 1);
207                         *dptr++ = X25_CALL_REQUEST;
208                         len     = x25_addr_aton(addresses, &sk->protinfo.x25->dest_addr, &sk->protinfo.x25->source_addr);
209                         dptr    = skb_put(skb, len);
210                         memcpy(dptr, addresses, len);
211                         len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities, sk->protinfo.x25->neighbour->global_facil_mask);
212                         dptr    = skb_put(skb, len);
213                         memcpy(dptr, facilities, len);
214                         dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
215                         memcpy(dptr, sk->protinfo.x25->calluserdata.cuddata, sk->protinfo.x25->calluserdata.cudlength);
216                         sk->protinfo.x25->calluserdata.cudlength = 0;
217                         break;
218 
219                 case X25_CALL_ACCEPTED:
220                         dptr    = skb_put(skb, 2);
221                         *dptr++ = X25_CALL_ACCEPTED;
222                         *dptr++ = 0x00;         /* Address lengths */
223                         len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities, sk->protinfo.x25->vc_facil_mask);
224                         dptr    = skb_put(skb, len);
225                         memcpy(dptr, facilities, len);
226                         dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
227                         memcpy(dptr, sk->protinfo.x25->calluserdata.cuddata, sk->protinfo.x25->calluserdata.cudlength);
228                         sk->protinfo.x25->calluserdata.cudlength = 0;
229                         break;
230 
231                 case X25_CLEAR_REQUEST:
232                 case X25_RESET_REQUEST:
233                         dptr    = skb_put(skb, 3);
234                         *dptr++ = frametype;
235                         *dptr++ = 0x00;         /* XXX */
236                         *dptr++ = 0x00;         /* XXX */
237                         break;
238 
239                 case X25_RR:
240                 case X25_RNR:
241                 case X25_REJ:
242                         if (sk->protinfo.x25->neighbour->extended) {
243                                 dptr     = skb_put(skb, 2);
244                                 *dptr++  = frametype;
245                                 *dptr++  = (sk->protinfo.x25->vr << 1) & 0xFE;
246                         } else {
247                                 dptr     = skb_put(skb, 1);
248                                 *dptr    = frametype;
249                                 *dptr++ |= (sk->protinfo.x25->vr << 5) & 0xE0;
250                         }
251                         break;
252 
253                 case X25_CLEAR_CONFIRMATION:
254                 case X25_INTERRUPT_CONFIRMATION:
255                 case X25_RESET_CONFIRMATION:
256                         dptr  = skb_put(skb, 1);
257                         *dptr = frametype;
258                         break;
259         }
260 
261         x25_transmit_link(skb, sk->protinfo.x25->neighbour);
262 }
263 
264 /*
265  *      Unpick the contents of the passed X.25 Packet Layer frame.
266  */
267 int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
268 {
269         unsigned char *frame;
270 
271         frame = skb->data;
272 
273         *ns = *nr = *q = *d = *m = 0;
274 
275         switch (frame[2]) {
276                 case X25_CALL_REQUEST:
277                 case X25_CALL_ACCEPTED:
278                 case X25_CLEAR_REQUEST:
279                 case X25_CLEAR_CONFIRMATION:
280                 case X25_INTERRUPT:
281                 case X25_INTERRUPT_CONFIRMATION:
282                 case X25_RESET_REQUEST:
283                 case X25_RESET_CONFIRMATION:
284                 case X25_RESTART_REQUEST:
285                 case X25_RESTART_CONFIRMATION:
286                 case X25_REGISTRATION_REQUEST:
287                 case X25_REGISTRATION_CONFIRMATION:
288                 case X25_DIAGNOSTIC:
289                         return frame[2];
290         }
291 
292         if (sk->protinfo.x25->neighbour->extended) {
293                 if (frame[2] == X25_RR  ||
294                     frame[2] == X25_RNR ||
295                     frame[2] == X25_REJ) {
296                         *nr = (frame[3] >> 1) & 0x7F;
297                         return frame[2];
298                 }
299         } else {
300                 if ((frame[2] & 0x1F) == X25_RR  ||
301                     (frame[2] & 0x1F) == X25_RNR ||
302                     (frame[2] & 0x1F) == X25_REJ) {
303                         *nr = (frame[2] >> 5) & 0x07;
304                         return frame[2] & 0x1F;
305                 }
306         }
307 
308         if (sk->protinfo.x25->neighbour->extended) {
309                 if ((frame[2] & 0x01) == X25_DATA) {
310                         *q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
311                         *d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
312                         *m  = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
313                         *nr = (frame[3] >> 1) & 0x7F;
314                         *ns = (frame[2] >> 1) & 0x7F;
315                         return X25_DATA;
316                 }
317         } else {
318                 if ((frame[2] & 0x01) == X25_DATA) {
319                         *q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
320                         *d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
321                         *m  = (frame[2] & X25_STD_M_BIT) == X25_STD_M_BIT;
322                         *nr = (frame[2] >> 5) & 0x07;
323                         *ns = (frame[2] >> 1) & 0x07;
324                         return X25_DATA;
325                 }
326         }
327 
328         printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n", frame[0], frame[1], frame[2]);
329 
330         return X25_ILLEGAL;
331 }
332 
333 void x25_disconnect(struct sock *sk, int reason, unsigned char cause, unsigned char diagnostic)
334 {
335         x25_clear_queues(sk);
336         x25_stop_timer(sk);
337 
338         sk->protinfo.x25->lci   = 0;
339         sk->protinfo.x25->state = X25_STATE_0;
340 
341         sk->protinfo.x25->causediag.cause      = cause;
342         sk->protinfo.x25->causediag.diagnostic = diagnostic;
343 
344         sk->state     = TCP_CLOSE;
345         sk->err       = reason;
346         sk->shutdown |= SEND_SHUTDOWN;
347 
348         if (!sk->dead)
349                 sk->state_change(sk);
350 
351         sk->dead = 1;
352 }
353 
354 #endif
355 

~ [ 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.