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

Linux Cross Reference
Linux/net/rose/rose_subr.c

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

  1 /*
  2  *      ROSE release 003
  3  *
  4  *      This code REQUIRES 2.1.15 or higher/ NET3.038
  5  *
  6  *      This module:
  7  *              This module is free software; you can redistribute it and/or
  8  *              modify it under the terms of the GNU General Public License
  9  *              as published by the Free Software Foundation; either version
 10  *              2 of the License, or (at your option) any later version.
 11  *
 12  *      History
 13  *      ROSE 001        Jonathan(G4KLX) Cloned from nr_subr.c
 14  *      ROSE 002        Jonathan(G4KLX) Centralised disconnect processing.
 15  *      ROSE 003        Jonathan(G4KLX) Added use count to neighbours.
 16  */
 17 
 18 #include <linux/errno.h>
 19 #include <linux/types.h>
 20 #include <linux/socket.h>
 21 #include <linux/in.h>
 22 #include <linux/kernel.h>
 23 #include <linux/sched.h>
 24 #include <linux/timer.h>
 25 #include <linux/string.h>
 26 #include <linux/sockios.h>
 27 #include <linux/net.h>
 28 #include <net/ax25.h>
 29 #include <linux/inet.h>
 30 #include <linux/netdevice.h>
 31 #include <linux/skbuff.h>
 32 #include <net/sock.h>
 33 #include <asm/segment.h>
 34 #include <asm/system.h>
 35 #include <linux/fcntl.h>
 36 #include <linux/mm.h>
 37 #include <linux/interrupt.h>
 38 #include <net/rose.h>
 39 
 40 /*
 41  *      This routine purges all of the queues of frames.
 42  */
 43 void rose_clear_queues(struct sock *sk)
 44 {
 45         struct sk_buff *skb;
 46 
 47         while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
 48                 kfree_skb(skb);
 49 
 50         while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL)
 51                 kfree_skb(skb);
 52 }
 53 
 54 /*
 55  * This routine purges the input queue of those frames that have been
 56  * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
 57  * SDL diagram.
 58  */
 59 void rose_frames_acked(struct sock *sk, unsigned short nr)
 60 {
 61         struct sk_buff *skb;
 62 
 63         /*
 64          * Remove all the ack-ed frames from the ack queue.
 65          */
 66         if (sk->protinfo.rose->va != nr) {
 67                 while (skb_peek(&sk->protinfo.rose->ack_queue) != NULL && sk->protinfo.rose->va != nr) {
 68                         skb = skb_dequeue(&sk->protinfo.rose->ack_queue);
 69                         kfree_skb(skb);
 70                         sk->protinfo.rose->va = (sk->protinfo.rose->va + 1) % ROSE_MODULUS;
 71                 }
 72         }
 73 }
 74 
 75 void rose_requeue_frames(struct sock *sk)
 76 {
 77         struct sk_buff *skb, *skb_prev = NULL;
 78 
 79         /*
 80          * Requeue all the un-ack-ed frames on the output queue to be picked
 81          * up by rose_kick. This arrangement handles the possibility of an
 82          * empty output queue.
 83          */
 84         while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL) {
 85                 if (skb_prev == NULL)
 86                         skb_queue_head(&sk->write_queue, skb);
 87                 else
 88                         skb_append(skb_prev, skb);
 89                 skb_prev = skb;
 90         }
 91 }
 92 
 93 /*
 94  *      Validate that the value of nr is between va and vs. Return true or
 95  *      false for testing.
 96  */
 97 int rose_validate_nr(struct sock *sk, unsigned short nr)
 98 {
 99         unsigned short vc = sk->protinfo.rose->va;
100 
101         while (vc != sk->protinfo.rose->vs) {
102                 if (nr == vc) return 1;
103                 vc = (vc + 1) % ROSE_MODULUS;
104         }
105 
106         if (nr == sk->protinfo.rose->vs) return 1;
107 
108         return 0;
109 }
110 
111 /* 
112  *  This routine is called when the packet layer internally generates a
113  *  control frame.
114  */
115 void rose_write_internal(struct sock *sk, int frametype)
116 {
117         struct sk_buff *skb;
118         unsigned char  *dptr;
119         unsigned char  lci1, lci2;
120         char buffer[100];
121         int len, faclen = 0;
122 
123         len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
124 
125         switch (frametype) {
126                 case ROSE_CALL_REQUEST:
127                         len   += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
128                         faclen = rose_create_facilities(buffer, sk->protinfo.rose);
129                         len   += faclen;
130                         break;
131                 case ROSE_CALL_ACCEPTED:
132                 case ROSE_CLEAR_REQUEST:
133                 case ROSE_RESET_REQUEST:
134                         len   += 2;
135                         break;
136         }
137 
138         if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
139                 return;
140 
141         /*
142          *      Space for AX.25 header and PID.
143          */
144         skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1);
145         
146         dptr = skb_put(skb, skb_tailroom(skb));
147 
148         lci1 = (sk->protinfo.rose->lci >> 8) & 0x0F;
149         lci2 = (sk->protinfo.rose->lci >> 0) & 0xFF;
150 
151         switch (frametype) {
152 
153                 case ROSE_CALL_REQUEST:
154                         *dptr++ = ROSE_GFI | lci1;
155                         *dptr++ = lci2;
156                         *dptr++ = frametype;
157                         *dptr++ = 0xAA;
158                         memcpy(dptr, &sk->protinfo.rose->dest_addr,  ROSE_ADDR_LEN);
159                         dptr   += ROSE_ADDR_LEN;
160                         memcpy(dptr, &sk->protinfo.rose->source_addr, ROSE_ADDR_LEN);
161                         dptr   += ROSE_ADDR_LEN;
162                         memcpy(dptr, buffer, faclen);
163                         dptr   += faclen;
164                         break;
165 
166                 case ROSE_CALL_ACCEPTED:
167                         *dptr++ = ROSE_GFI | lci1;
168                         *dptr++ = lci2;
169                         *dptr++ = frametype;
170                         *dptr++ = 0x00;         /* Address length */
171                         *dptr++ = 0;            /* Facilities length */
172                         break;
173 
174                 case ROSE_CLEAR_REQUEST:
175                         *dptr++ = ROSE_GFI | lci1;
176                         *dptr++ = lci2;
177                         *dptr++ = frametype;
178                         *dptr++ = sk->protinfo.rose->cause;
179                         *dptr++ = sk->protinfo.rose->diagnostic;
180                         break;
181 
182                 case ROSE_RESET_REQUEST:
183                         *dptr++ = ROSE_GFI | lci1;
184                         *dptr++ = lci2;
185                         *dptr++ = frametype;
186                         *dptr++ = ROSE_DTE_ORIGINATED;
187                         *dptr++ = 0;
188                         break;
189 
190                 case ROSE_RR:
191                 case ROSE_RNR:
192                         *dptr++ = ROSE_GFI | lci1;
193                         *dptr++ = lci2;
194                         *dptr   = frametype;
195                         *dptr++ |= (sk->protinfo.rose->vr << 5) & 0xE0;
196                         break;
197 
198                 case ROSE_CLEAR_CONFIRMATION:
199                 case ROSE_RESET_CONFIRMATION:
200                         *dptr++ = ROSE_GFI | lci1;
201                         *dptr++ = lci2;
202                         *dptr++  = frametype;
203                         break;
204 
205                 default:
206                         printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype);
207                         kfree_skb(skb);
208                         return;
209         }
210 
211         rose_transmit_link(skb, sk->protinfo.rose->neighbour);
212 }
213 
214 int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
215 {
216         unsigned char *frame;
217 
218         frame = skb->data;
219 
220         *ns = *nr = *q = *d = *m = 0;
221 
222         switch (frame[2]) {
223                 case ROSE_CALL_REQUEST:
224                 case ROSE_CALL_ACCEPTED:
225                 case ROSE_CLEAR_REQUEST:
226                 case ROSE_CLEAR_CONFIRMATION:
227                 case ROSE_RESET_REQUEST:
228                 case ROSE_RESET_CONFIRMATION:
229                         return frame[2];
230                 default:
231                         break;
232         }
233 
234         if ((frame[2] & 0x1F) == ROSE_RR  ||
235             (frame[2] & 0x1F) == ROSE_RNR) {
236                 *nr = (frame[2] >> 5) & 0x07;
237                 return frame[2] & 0x1F;
238         }
239 
240         if ((frame[2] & 0x01) == ROSE_DATA) {
241                 *q  = (frame[0] & ROSE_Q_BIT) == ROSE_Q_BIT;
242                 *d  = (frame[0] & ROSE_D_BIT) == ROSE_D_BIT;
243                 *m  = (frame[2] & ROSE_M_BIT) == ROSE_M_BIT;
244                 *nr = (frame[2] >> 5) & 0x07;
245                 *ns = (frame[2] >> 1) & 0x07;
246                 return ROSE_DATA;
247         }
248 
249         return ROSE_ILLEGAL;
250 }
251 
252 static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len)
253 {
254         unsigned char *pt;
255         unsigned char l, lg, n = 0;
256         int fac_national_digis_received = 0;
257 
258         do {
259                 switch (*p & 0xC0) {
260                         case 0x00:
261                                 p   += 2;
262                                 n   += 2;
263                                 len -= 2;
264                                 break;
265 
266                         case 0x40:
267                                 if (*p == FAC_NATIONAL_RAND)
268                                         facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
269                                 p   += 3;
270                                 n   += 3;
271                                 len -= 3;
272                                 break;
273 
274                         case 0x80:
275                                 p   += 4;
276                                 n   += 4;
277                                 len -= 4;
278                                 break;
279 
280                         case 0xC0:
281                                 l = p[1];
282                                 if (*p == FAC_NATIONAL_DEST_DIGI) {
283                                         if (!fac_national_digis_received) {
284                                                 memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
285                                                 facilities->source_ndigis = 1;
286                                         }
287                                 }
288                                 else if (*p == FAC_NATIONAL_SRC_DIGI) {
289                                         if (!fac_national_digis_received) {
290                                                 memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
291                                                 facilities->dest_ndigis = 1;
292                                         }
293                                 }
294                                 else if (*p == FAC_NATIONAL_FAIL_CALL) {
295                                         memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
296                                 }
297                                 else if (*p == FAC_NATIONAL_FAIL_ADD) {
298                                         memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
299                                 }
300                                 else if (*p == FAC_NATIONAL_DIGIS) {
301                                         fac_national_digis_received = 1;
302                                         facilities->source_ndigis = 0;
303                                         facilities->dest_ndigis   = 0;
304                                         for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
305                                                 if (pt[6] & AX25_HBIT)
306                                                         memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
307                                                 else
308                                                         memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
309                                         }
310                                 }
311                                 p   += l + 2;
312                                 n   += l + 2;
313                                 len -= l + 2;
314                                 break;
315                 }
316         } while (*p != 0x00 && len > 0);
317 
318         return n;
319 }
320 
321 static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len)
322 {
323         unsigned char l, n = 0;
324         char callsign[11];
325 
326         do {
327                 switch (*p & 0xC0) {
328                         case 0x00:
329                                 p   += 2;
330                                 n   += 2;
331                                 len -= 2;
332                                 break;
333 
334                         case 0x40:
335                                 p   += 3;
336                                 n   += 3;
337                                 len -= 3;
338                                 break;
339 
340                         case 0x80:
341                                 p   += 4;
342                                 n   += 4;
343                                 len -= 4;
344                                 break;
345 
346                         case 0xC0:
347                                 l = p[1];
348                                 if (*p == FAC_CCITT_DEST_NSAP) {
349                                         memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
350                                         memcpy(callsign, p + 12,   l - 10);
351                                         callsign[l - 10] = '\0';
352                                         facilities->source_call = *asc2ax(callsign);
353                                 }
354                                 if (*p == FAC_CCITT_SRC_NSAP) {
355                                         memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
356                                         memcpy(callsign, p + 12, l - 10);
357                                         callsign[l - 10] = '\0';
358                                         facilities->dest_call = *asc2ax(callsign);
359                                 }
360                                 p   += l + 2;
361                                 n   += l + 2;
362                                 len -= l + 2;
363                                 break;
364                 }
365         } while (*p != 0x00 && len > 0);
366 
367         return n;
368 }
369 
370 int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facilities)
371 {
372         int facilities_len, len;
373 
374         facilities_len = *p++;
375 
376         if (facilities_len == 0)
377                 return 0;
378 
379         while (facilities_len > 0) {
380                 if (*p == 0x00) {
381                         facilities_len--;
382                         p++;
383 
384                         switch (*p) {
385                                 case FAC_NATIONAL:              /* National */
386                                         len = rose_parse_national(p + 1, facilities, facilities_len - 1);
387                                         facilities_len -= len + 1;
388                                         p += len + 1;
389                                         break;
390 
391                                 case FAC_CCITT:         /* CCITT */
392                                         len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
393                                         facilities_len -= len + 1;
394                                         p += len + 1;
395                                         break;
396 
397                                 default:
398                                         printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
399                                         facilities_len--;
400                                         p++;
401                                         break;
402                         }
403                 }
404                 else break;     /* Error in facilities format */
405         }
406 
407         return 1;
408 }
409 
410 int rose_create_facilities(unsigned char *buffer, rose_cb *rose)
411 {
412         unsigned char *p = buffer + 1;
413         char *callsign;
414         int len, nb;
415 
416         /* National Facilities */
417         if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) {
418                 *p++ = 0x00;
419                 *p++ = FAC_NATIONAL;
420 
421                 if (rose->rand != 0) {
422                         *p++ = FAC_NATIONAL_RAND;
423                         *p++ = (rose->rand >> 8) & 0xFF;
424                         *p++ = (rose->rand >> 0) & 0xFF;
425                 }
426 
427                 /* Sent before older facilities */
428                 if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) {
429                         int maxdigi = 0;
430                         *p++ = FAC_NATIONAL_DIGIS;
431                         *p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis);
432                         for (nb = 0 ; nb < rose->source_ndigis ; nb++) {
433                                 if (++maxdigi >= ROSE_MAX_DIGIS)
434                                         break;
435                                 memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN);
436                                 p[6] |= AX25_HBIT;
437                                 p += AX25_ADDR_LEN;
438                         }
439                         for (nb = 0 ; nb < rose->dest_ndigis ; nb++) {
440                                 if (++maxdigi >= ROSE_MAX_DIGIS)
441                                         break;
442                                 memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN);
443                                 p[6] &= ~AX25_HBIT;
444                                 p += AX25_ADDR_LEN;
445                         }
446                 }
447 
448                 /* For compatibility */
449                 if (rose->source_ndigis > 0) {
450                         *p++ = FAC_NATIONAL_SRC_DIGI;
451                         *p++ = AX25_ADDR_LEN;
452                         memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN);
453                         p   += AX25_ADDR_LEN;
454                 }
455 
456                 /* For compatibility */
457                 if (rose->dest_ndigis > 0) {
458                         *p++ = FAC_NATIONAL_DEST_DIGI;
459                         *p++ = AX25_ADDR_LEN;
460                         memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN);
461                         p   += AX25_ADDR_LEN;
462                 }
463         }
464 
465         *p++ = 0x00;
466         *p++ = FAC_CCITT;
467 
468         *p++ = FAC_CCITT_DEST_NSAP;
469 
470         callsign = ax2asc(&rose->dest_call);
471 
472         *p++ = strlen(callsign) + 10;
473         *p++ = (strlen(callsign) + 9) * 2;              /* ??? */
474 
475         *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
476         *p++ = ROSE_ADDR_LEN * 2;
477         memcpy(p, &rose->dest_addr, ROSE_ADDR_LEN);
478         p   += ROSE_ADDR_LEN;
479 
480         memcpy(p, callsign, strlen(callsign));
481         p   += strlen(callsign);
482 
483         *p++ = FAC_CCITT_SRC_NSAP;
484 
485         callsign = ax2asc(&rose->source_call);
486 
487         *p++ = strlen(callsign) + 10;
488         *p++ = (strlen(callsign) + 9) * 2;              /* ??? */
489 
490         *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
491         *p++ = ROSE_ADDR_LEN * 2;
492         memcpy(p, &rose->source_addr, ROSE_ADDR_LEN);
493         p   += ROSE_ADDR_LEN;
494 
495         memcpy(p, callsign, strlen(callsign));
496         p   += strlen(callsign);
497 
498         len       = p - buffer;
499         buffer[0] = len - 1;
500 
501         return len;
502 }
503 
504 void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic)
505 {
506         rose_stop_timer(sk);
507         rose_stop_idletimer(sk);
508 
509         rose_clear_queues(sk);
510 
511         sk->protinfo.rose->lci   = 0;
512         sk->protinfo.rose->state = ROSE_STATE_0;
513 
514         if (cause != -1)
515                 sk->protinfo.rose->cause = cause;
516 
517         if (diagnostic != -1)
518                 sk->protinfo.rose->diagnostic = diagnostic;
519 
520         sk->state     = TCP_CLOSE;
521         sk->err       = reason;
522         sk->shutdown |= SEND_SHUTDOWN;
523 
524         if (!sk->dead)
525                 sk->state_change(sk);
526 
527         sk->dead  = 1;
528 }
529 

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