]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/net/if_spppfr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / net / if_spppfr.c
1 /*-
2  * Synchronous Frame Relay link level subroutines.
3  * ANSI T1.617-compaible link management signaling
4  * implemented for Frame Relay mode.
5  * Cisco-type Frame Relay framing added, thanks Alex Tutubalin.
6  * Only one DLCI per channel for now.
7  *
8  * Copyright (C) 1994-2000 Cronyx Engineering.
9  * Author: Serge Vakulenko, <vak@cronyx.ru>
10  *
11  * Copyright (C) 1999-2004 Cronyx Engineering.
12  * Author: Kurakin Roman, <rik@cronyx.ru>
13  *
14  * This software is distributed with NO WARRANTIES, not even the implied
15  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * Authors grant any other persons or organisations a permission to use,
18  * modify and redistribute this software in source and binary forms,
19  * as long as this message is kept with the software, all derivative
20  * works or modified versions.
21  *
22  * $Cronyx Id: if_spppfr.c,v 1.1.2.10 2004/06/29 09:02:30 rik Exp $
23  * $FreeBSD$
24  */
25
26 #include <sys/param.h>
27
28 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
29 #include "opt_inet.h"
30 #include "opt_inet6.h"
31 #include "opt_ipx.h"
32 #endif
33
34 #ifdef NetBSD1_3
35 #  if NetBSD1_3 > 6
36 #      include "opt_inet.h"
37 #      include "opt_inet6.h"
38 #      include "opt_iso.h"
39 #  endif
40 #endif
41
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/sockio.h>
46 #include <sys/socket.h>
47 #include <sys/syslog.h>
48 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
49 #include <sys/random.h>
50 #endif
51 #include <sys/malloc.h>
52 #include <sys/mbuf.h>
53
54 #if defined (__OpenBSD__)
55 #include <sys/md5k.h>
56 #else
57 #include <sys/md5.h>
58 #endif
59
60 #include <net/if.h>
61 #include <net/netisr.h>
62 #include <net/if_types.h>
63 #include <net/route.h>
64 #include <netinet/in.h>
65 #include <netinet/in_systm.h>
66 #include <netinet/ip.h>
67 #include <net/slcompress.h>
68
69 #if defined (__NetBSD__) || defined (__OpenBSD__)
70 #include <machine/cpu.h> /* XXX for softnet */
71 #endif
72
73 #include <machine/stdarg.h>
74
75 #include <netinet/in_var.h>
76 #ifdef INET
77 #include <netinet/ip.h>
78 #include <netinet/tcp.h>
79 #endif
80
81 #if defined (__FreeBSD__) || defined (__OpenBSD__)
82 #  include <netinet/if_ether.h>
83 #else
84 #  include <net/ethertypes.h>
85 #endif
86
87 #ifdef IPX
88 #include <netipx/ipx.h>
89 #include <netipx/ipx_if.h>
90 #endif
91
92 #include <net/if_sppp.h>
93
94 /*
95  * Frame Relay.
96  */
97 #define FR_UI           0x03    /* Unnumbered Information */
98 #define FR_IP           0xCC    /* IP protocol identifier */
99 #define FR_PADDING      0x00    /* NLPID padding */
100 #define FR_SIGNALING    0x08    /* Q.933/T1.617 signaling identifier */
101 #define FR_SNAP         0x80    /* NLPID snap */
102
103 /*
104  * Header flags.
105  */
106 #define FR_DE           0x02    /* discard eligibility */
107 #define FR_FECN         0x04    /* forward notification */
108 #define FR_BECN         0x08    /* backward notification */
109
110 /*
111  * Signaling message types.
112  */
113 #define FR_MSG_ENQUIRY  0x75    /* status enquiry */
114 #define FR_MSG_STATUS   0x7d    /* status */
115
116 #define FR_ENQUIRY_SIZE 14
117
118 /*
119  * Message field types.
120  */
121 #define FR_FLD_RTYPE    0x01    /* report type */
122 #define FR_FLD_VERIFY   0x03    /* link verification */
123 #define FR_FLD_PVC      0x07    /* PVC status */
124 #define FR_FLD_LSHIFT5  0x95    /* locking shift 5 */
125
126 /*
127  * Report types.
128  */
129 #define FR_RTYPE_FULL   0       /* full status */
130 #define FR_RTYPE_SHORT  1       /* link verification only */
131 #define FR_RTYPE_SINGLE 2       /* single PVC status */
132
133 /* PVC status field. */
134 #define FR_DLCI_DELETE  0x04    /* PVC is deleted */
135 #define FR_DLCI_ACTIVE  0x02    /* PVC is operational */
136 #define FR_DLCI_NEW     0x08    /* PVC is new */
137
138 struct arp_req {
139         unsigned short  htype;          /* hardware type = ARPHRD_FRELAY */
140         unsigned short  ptype;          /* protocol type = ETHERTYPE_IP */
141         unsigned char   halen;          /* hardware address length = 2 */
142         unsigned char   palen;          /* protocol address length = 4 */
143         unsigned short  op;             /* ARP/RARP/InARP request/reply */
144         unsigned short  hsource;        /* hardware source address */
145         unsigned short  psource1;       /* protocol source */
146         unsigned short  psource2;
147         unsigned short  htarget;        /* hardware target address */
148         unsigned short  ptarget1;       /* protocol target */
149         unsigned short  ptarget2;
150 } __packed;
151
152 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 && __FreeBSD_version < 501113
153 #define SPP_FMT         "%s%d: "
154 #define SPP_ARGS(ifp)   (ifp)->if_name, (ifp)->if_unit
155 #else
156 #define SPP_FMT         "%s: "
157 #define SPP_ARGS(ifp)   (ifp)->if_xname
158 #endif
159
160 /* almost every function needs these */
161 #define STDDCL                                                  \
162         struct ifnet *ifp = SP2IFP(sp);                         \
163         int debug = ifp->if_flags & IFF_DEBUG
164
165 static void sppp_fr_arp (struct sppp *sp, struct arp_req *req, u_short addr);
166 static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len);
167
168 void sppp_fr_input (struct sppp *sp, struct mbuf *m)
169 {
170         STDDCL;
171         u_char *h = mtod (m, u_char*);
172         int isr = -1;
173         int dlci, hlen, proto;
174
175         /* Get the DLCI number. */
176         if (m->m_pkthdr.len < 10) {
177 bad:            m_freem (m);
178                 return;
179         }
180         dlci = (h[0] << 2 & 0x3f0) | (h[1] >> 4 & 0x0f);
181
182         /* Process signaling packets. */
183         if (dlci == 0) {
184                 sppp_fr_signal (sp, h, m->m_pkthdr.len);
185                 m_freem (m);
186                 return;
187         }
188
189         if (dlci != sp->fr_dlci) {
190                 if (debug)
191                         printf (SPP_FMT "Received packet from invalid DLCI %d\n",
192                                 SPP_ARGS(ifp), dlci);
193                 goto bad;
194         }
195
196         /* Process the packet. */
197         if (ntohs (*(short*) (h+2)) == ETHERTYPE_IP) {
198                 /* Prehistoric IP framing? */
199                 h[2] = FR_UI;
200                 h[3] = FR_IP;
201         }
202         if (h[2] != FR_UI) {
203                 if (debug)
204                         printf (SPP_FMT "Invalid frame relay header flag 0x%02x\n",
205                                 SPP_ARGS(ifp), h[2]);
206                 goto bad;
207         }
208         switch (h[3]) {
209         default:
210                 if (debug)
211                         printf (SPP_FMT "Unsupported NLPID 0x%02x\n",
212                                 SPP_ARGS(ifp), h[3]);
213                 goto bad;
214
215         case FR_PADDING:
216                 if (h[4] != FR_SNAP) {
217                         if (debug)
218                                 printf (SPP_FMT "Bad NLPID 0x%02x\n",
219                                         SPP_ARGS(ifp), h[4]);
220                         goto bad;
221                 }
222                 if (h[5] || h[6] || h[7]) {
223                         if (debug)
224                                 printf (SPP_FMT "Bad OID 0x%02x-0x%02x-0x%02x\n",
225                                         SPP_ARGS(ifp),
226                                         h[5], h[6], h[7]);
227                         goto bad;
228                 }
229                 proto = ntohs (*(short*) (h+8));
230                 if (proto == ETHERTYPE_ARP) {
231                         /* Process the ARP request. */
232                         if (m->m_pkthdr.len != 10 + sizeof (struct arp_req)) {
233                                 if (debug)
234                                         printf (SPP_FMT "Bad ARP request size = %d bytes\n",
235                                                 SPP_ARGS(ifp),
236                                                 m->m_pkthdr.len);
237                                 goto bad;
238                         }
239                         sppp_fr_arp (sp, (struct arp_req*) (h + 10),
240                                 h[0] << 8 | h[1]);
241                         m_freem (m);
242                         return;
243                 }
244                 hlen = 10;
245                 break;
246
247         case FR_IP:
248                 proto = ETHERTYPE_IP;
249                 hlen = 4;
250                 break;
251         }
252
253         /* Remove frame relay header. */
254         m_adj (m, hlen);
255
256         switch (proto) {
257         default:
258                 ++ifp->if_noproto;
259 drop:           ++ifp->if_ierrors;
260                 ++ifp->if_iqdrops;
261                 m_freem (m);
262                 return;
263 #ifdef INET
264         case ETHERTYPE_IP:
265                 isr = NETISR_IP;
266                 break;
267 #endif
268 #ifdef IPX
269         case ETHERTYPE_IPX:
270                 isr = NETISR_IPX;
271                 break;
272 #endif
273 #ifdef NETATALK
274         case ETHERTYPE_AT:
275                 isr = NETISR_ATALK;
276                 break;
277 #endif
278         }
279
280         if (! (ifp->if_flags & IFF_UP))
281                 goto drop;
282
283         M_SETFIB(m, ifp->if_fib);
284
285         /* Check queue. */
286         if (netisr_queue(isr, m)) {     /* (0) on success. */
287                 if (debug)
288                         log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n",
289                                 SPP_ARGS(ifp));
290         }
291 }
292
293 /*
294  * Add the frame relay header to the packet.
295  * For IP the header length is 4 bytes,
296  * for all other protocols - 10 bytes (RFC 1490).
297  */
298 struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m,
299         int family)
300 {
301         STDDCL;
302         u_char *h;
303         int type, hlen;
304
305         /* Prepend the space for Frame Relay header. */
306         hlen = (family == AF_INET) ? 4 : 10;
307         M_PREPEND (m, hlen, M_DONTWAIT);
308         if (! m)
309                 return 0;
310         h = mtod (m, u_char*);
311
312         /* Fill the header. */
313         h[0] = sp->fr_dlci >> 2 & 0xfc;
314         h[1] = sp->fr_dlci << 4 | 1;
315         h[2] = FR_UI;
316
317         switch (family) {
318         default:
319                 if (debug)
320                         printf (SPP_FMT "Cannot handle address family %d\n",
321                                 SPP_ARGS(ifp), family);
322                 m_freem (m);
323                 return 0;
324 #ifdef INET
325         case AF_INET:
326 #if 0 /* Crashes on fragmented packets */
327                 /*
328                  * Set the discard eligibility bit, if:
329                  * 1) no fragmentation
330                  * 2) length > 400 bytes
331                  * 3a) the protocol is UDP or
332                  * 3b) TCP data (no control bits)
333                  */
334                 {
335                 struct ip *ip = (struct ip*) (h + hlen);
336                 struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
337
338                 if (! (ip->ip_off & ~IP_DF) && ip->ip_len > 400 &&
339                     (ip->ip_p == IPPROTO_UDP ||
340                     ip->ip_p == IPPROTO_TCP && ! tcp->th_flags))
341                         h[1] |= FR_DE;
342                 }
343 #endif
344                 h[3] = FR_IP;
345                 return m;
346 #endif
347 #ifdef IPX
348         case AF_IPX:
349                 type = ETHERTYPE_IPX;
350                 break;
351 #endif
352 #ifdef NS
353         case AF_NS:
354                 type = 0x8137;
355                 break;
356 #endif
357 #ifdef NETATALK
358         case AF_APPLETALK:
359                 type = ETHERTYPE_AT;
360                 break;
361 #endif
362         }
363         h[3] = FR_PADDING;
364         h[4] = FR_SNAP;
365         h[5] = 0;
366         h[6] = 0;
367         h[7] = 0;
368         *(short*) (h+8) = htons(type);
369         return m;
370 }
371
372 /*
373  * Send periodical frame relay link verification messages via DLCI 0.
374  * Called every 10 seconds (default value of T391 timer is 10 sec).
375  * Every 6-th message is a full status request
376  * (default value of N391 counter is 6).
377  */
378 void sppp_fr_keepalive (struct sppp *sp)
379 {
380         STDDCL;
381         unsigned char *h, *p;
382         struct mbuf *m;
383
384         MGETHDR (m, M_DONTWAIT, MT_DATA);
385         if (! m)
386                 return;
387         m->m_pkthdr.rcvif = 0;
388
389         h = mtod (m, u_char*);
390         p = h;
391         *p++ = 0;                       /* DLCI = 0 */
392         *p++ = 1;
393         *p++ = FR_UI;
394         *p++ = FR_SIGNALING;            /* NLPID = UNI call control */
395
396         *p++ = 0;                       /* call reference length = 0 */
397         *p++ = FR_MSG_ENQUIRY;          /* message type = status enquiry */
398
399         *p++ = FR_FLD_LSHIFT5;          /* locking shift 5 */
400
401         *p++ = FR_FLD_RTYPE;            /* report type field */
402         *p++ = 1;                       /* report type length = 1 */
403         if (sp->pp_seq[IDX_LCP] % 6)
404                 *p++ = FR_RTYPE_SHORT;  /* link verification only */
405         else
406                 *p++ = FR_RTYPE_FULL;   /* full status needed */
407
408         if (sp->pp_seq[IDX_LCP] >= 255)
409                 sp->pp_seq[IDX_LCP] = 0;
410         *p++ = FR_FLD_VERIFY;           /* link verification type field */
411         *p++ = 2;                       /* link verification field length = 2 */
412         *p++ = ++sp->pp_seq[IDX_LCP];   /* our sequence number */
413         *p++ = sp->pp_rseq[IDX_LCP];    /* last received sequence number */
414
415         m->m_pkthdr.len = m->m_len = p - h;
416         if (debug)
417                 printf (SPP_FMT "send lmi packet, seq=%d, rseq=%d\n",
418                         SPP_ARGS(ifp), (u_char) sp->pp_seq[IDX_LCP],
419                         (u_char) sp->pp_rseq[IDX_LCP]);
420
421         if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
422                 ++ifp->if_oerrors;
423 }
424
425 /*
426  * Process the frame relay Inverse ARP request.
427  */
428 static void sppp_fr_arp (struct sppp *sp, struct arp_req *req,
429         u_short his_hardware_address)
430 {
431         STDDCL;
432         struct mbuf *m;
433         struct arp_req *reply;
434         u_char *h;
435         u_short my_hardware_address;
436         u_long his_ip_address, my_ip_address;
437
438         if ((ntohs (req->htype) != ARPHRD_FRELAY ||
439             ntohs (req->htype) != 16) || /* for BayNetworks routers */
440             ntohs (req->ptype) != ETHERTYPE_IP) {
441                 if (debug)
442                         printf (SPP_FMT "Invalid ARP hardware/protocol type = 0x%x/0x%x\n",
443                                 SPP_ARGS(ifp),
444                                 ntohs (req->htype), ntohs (req->ptype));
445                 return;
446         }
447         if (req->halen != 2 || req->palen != 4) {
448                 if (debug)
449                         printf (SPP_FMT "Invalid ARP hardware/protocol address length = %d/%d\n",
450                                 SPP_ARGS(ifp),
451                                 req->halen, req->palen);
452                 return;
453         }
454         switch (ntohs (req->op)) {
455         default:
456                 if (debug)
457                         printf (SPP_FMT "Invalid ARP op = 0x%x\n",
458                                 SPP_ARGS(ifp), ntohs (req->op));
459                 return;
460
461         case ARPOP_INVREPLY:
462                 /* Ignore. */
463                 return;
464
465         case ARPOP_INVREQUEST:
466                 my_hardware_address = ntohs (req->htarget);
467                 his_ip_address = ntohs (req->psource1) << 16 |
468                         ntohs (req->psource2);
469                 my_ip_address = ntohs (req->ptarget1) << 16 |
470                         ntohs (req->ptarget2);
471                 break;
472         }
473         if (debug)
474                 printf (SPP_FMT "got ARP request, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
475                         SPP_ARGS(ifp), ntohs (req->hsource),
476                         (unsigned char) (his_ip_address >> 24),
477                         (unsigned char) (his_ip_address >> 16),
478                         (unsigned char) (his_ip_address >> 8),
479                         (unsigned char) his_ip_address,
480                         my_hardware_address,
481                         (unsigned char) (my_ip_address >> 24),
482                         (unsigned char) (my_ip_address >> 16),
483                         (unsigned char) (my_ip_address >> 8),
484                         (unsigned char) my_ip_address);
485
486         sppp_get_ip_addrs (sp, &my_ip_address, 0, 0);
487         if (! my_ip_address)
488                 return;         /* nothing to reply */
489
490         if (debug)
491                 printf (SPP_FMT "send ARP reply, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
492                         SPP_ARGS(ifp), my_hardware_address,
493                         (unsigned char) (my_ip_address >> 24),
494                         (unsigned char) (my_ip_address >> 16),
495                         (unsigned char) (my_ip_address >> 8),
496                         (unsigned char) my_ip_address,
497                         his_hardware_address,
498                         (unsigned char) (his_ip_address >> 24),
499                         (unsigned char) (his_ip_address >> 16),
500                         (unsigned char) (his_ip_address >> 8),
501                         (unsigned char) his_ip_address);
502
503         /* Send the Inverse ARP reply. */
504         MGETHDR (m, M_DONTWAIT, MT_DATA);
505         if (! m)
506                 return;
507         m->m_pkthdr.len = m->m_len = 10 + sizeof (*reply);
508         m->m_pkthdr.rcvif = 0;
509
510         h = mtod (m, u_char*);
511         reply = (struct arp_req*) (h + 10);
512
513         h[0] = his_hardware_address >> 8;
514         h[1] = his_hardware_address;
515         h[2] = FR_UI;
516         h[3] = FR_PADDING;
517         h[4] = FR_SNAP;
518         h[5] = 0;
519         h[6] = 0;
520         h[7] = 0;
521         *(short*) (h+8) = htons (ETHERTYPE_ARP);
522
523         reply->htype    = htons (ARPHRD_FRELAY);
524         reply->ptype    = htons (ETHERTYPE_IP);
525         reply->halen    = 2;
526         reply->palen    = 4;
527         reply->op       = htons (ARPOP_INVREPLY);
528         reply->hsource  = htons (my_hardware_address);
529         reply->psource1 = htonl (my_ip_address);
530         reply->psource2 = htonl (my_ip_address) >> 16;
531         reply->htarget  = htons (his_hardware_address);
532         reply->ptarget1 = htonl (his_ip_address);
533         reply->ptarget2 = htonl (his_ip_address) >> 16;
534
535         if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
536                 ++ifp->if_oerrors;
537 }
538
539 /*
540  * Process the input signaling packet (DLCI 0).
541  * The implemented protocol is ANSI T1.617 Annex D.
542  */
543 static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len)
544 {
545         STDDCL;
546         u_char *p;
547         int dlci;
548
549         if (h[2] != FR_UI || h[3] != FR_SIGNALING || h[4] != 0) {
550                 if (debug)
551                         printf (SPP_FMT "Invalid signaling header\n",
552                                 SPP_ARGS(ifp));
553 bad:            if (debug) {
554                         printf ("%02x", *h++);
555                         while (--len > 0)
556                                 printf ("-%02x", *h++);
557                         printf ("\n");
558                 }
559                 return;
560         }
561         if (h[5] == FR_MSG_ENQUIRY) {
562                 if (len == FR_ENQUIRY_SIZE &&
563                     h[12] == (u_char) sp->pp_seq[IDX_LCP]) {
564                         sp->pp_seq[IDX_LCP] = random();
565                         printf (SPP_FMT "loopback detected\n",
566                                 SPP_ARGS(ifp));
567                 }
568                 return;
569         }
570         if (h[5] != FR_MSG_STATUS) {
571                 if (debug)
572                         printf (SPP_FMT "Unknown signaling message: 0x%02x\n",
573                                 SPP_ARGS(ifp), h[5]);
574                 goto bad;
575         }
576
577         /* Parse message fields. */
578         for (p=h+6; p<h+len; ) {
579                 switch (*p) {
580                 default:
581                         if (debug)
582                                 printf (SPP_FMT "Unknown signaling field 0x%x\n",
583                                         SPP_ARGS(ifp), *p);
584                         break;
585                 case FR_FLD_LSHIFT5:
586                 case FR_FLD_RTYPE:
587                         /* Ignore. */
588                         break;
589                 case FR_FLD_VERIFY:
590                         if (p[1] != 2) {
591                                 if (debug)
592                                         printf (SPP_FMT "Invalid signaling verify field length %d\n",
593                                                 SPP_ARGS(ifp), p[1]);
594                                 break;
595                         }
596                         sp->pp_rseq[IDX_LCP] = p[2];
597                         if (debug) {
598                                 printf (SPP_FMT "got lmi reply rseq=%d, seq=%d",
599                                         SPP_ARGS(ifp), p[2], p[3]);
600                                 if (p[3] != (u_char) sp->pp_seq[IDX_LCP])
601                                         printf (" (really %d)",
602                                                 (u_char) sp->pp_seq[IDX_LCP]);
603                                 printf ("\n");
604                         }
605                         break;
606                 case FR_FLD_PVC:
607                         if (p[1] < 3) {
608                                 if (debug)
609                                         printf (SPP_FMT "Invalid PVC status length %d\n",
610                                                 SPP_ARGS(ifp), p[1]);
611                                 break;
612                         }
613                         dlci = (p[2] << 4 & 0x3f0) | (p[3] >> 3 & 0x0f);
614                         if (! sp->fr_dlci)
615                                 sp->fr_dlci = dlci;
616                         if (sp->fr_status != p[4])
617                                 printf (SPP_FMT "DLCI %d %s%s\n",
618                                         SPP_ARGS(ifp), dlci,
619                                         p[4] & FR_DLCI_DELETE ? "deleted" :
620                                         p[4] & FR_DLCI_ACTIVE ? "active" : "passive",
621                                         p[4] & FR_DLCI_NEW ? ", new" : "");
622                         sp->fr_status = p[4];
623                         break;
624                 }
625                 if (*p & 0x80)
626                         ++p;
627                 else if (p < h+len+1 && p[1])
628                         p += 2 + p[1];
629                 else {
630                         if (debug)
631                                 printf (SPP_FMT "Invalid signaling field 0x%x\n",
632                                         SPP_ARGS(ifp), *p);
633                         goto bad;
634                 }
635         }
636 }