xref: /f-stack/freebsd/net/if_spppfr.c (revision a9643ea8)
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, <[email protected]>
10  *
11  * Copyright (C) 1999-2004 Cronyx Engineering.
12  * Author: Kurakin Roman, <[email protected]>
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__)
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 
sppp_fr_input(struct sppp * sp,struct mbuf * m)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  */
sppp_fr_header(struct sppp * sp,struct mbuf * m,int family)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  */
sppp_fr_keepalive(struct sppp * sp)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  */
sppp_fr_arp(struct sppp * sp,struct arp_req * req,u_short his_hardware_address)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  */
sppp_fr_signal(struct sppp * sp,unsigned char * h,int len)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 }
612