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