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