if_spppfr.c revision 139365
1139365Srik/*
2139365Srik * Synchronous Frame Relay link level subroutines.
3139365Srik * ANSI T1.617-compaible link management signaling
4139365Srik * implemented for Frame Relay mode.
5139365Srik * Cisco-type Frame Relay framing added, thanks Alex Tutubalin.
6139365Srik * Only one DLCI per channel for now.
7139365Srik *
8139365Srik * Copyright (C) 1994-2000 Cronyx Engineering.
9139365Srik * Author: Serge Vakulenko, <vak@cronyx.ru>
10139365Srik *
11139365Srik * Copyright (C) 1999-2004 Cronyx Engineering.
12139365Srik * Author: Kurakin Roman, <rik@cronyx.ru>
13139365Srik *
14139365Srik * This software is distributed with NO WARRANTIES, not even the implied
15139365Srik * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16139365Srik *
17139365Srik * Authors grant any other persons or organisations a permission to use,
18139365Srik * modify and redistribute this software in source and binary forms,
19139365Srik * as long as this message is kept with the software, all derivative
20139365Srik * works or modified versions.
21139365Srik *
22139365Srik * $Cronyx Id: if_spppfr.c,v 1.1.2.10 2004/06/29 09:02:30 rik Exp $
23139365Srik * $FreeBSD: head/sys/net/if_spppfr.c 139365 2004-12-28 00:07:57Z rik $
24139365Srik */
25139365Srik
26139365Srik#include <sys/param.h>
27139365Srik
28139365Srik#if defined(__FreeBSD__) && __FreeBSD__ >= 3
29139365Srik#include "opt_inet.h"
30139365Srik#include "opt_inet6.h"
31139365Srik#include "opt_ipx.h"
32139365Srik#endif
33139365Srik
34139365Srik#ifdef NetBSD1_3
35139365Srik#  if NetBSD1_3 > 6
36139365Srik#      include "opt_inet.h"
37139365Srik#      include "opt_inet6.h"
38139365Srik#      include "opt_iso.h"
39139365Srik#  endif
40139365Srik#endif
41139365Srik
42139365Srik#include <sys/systm.h>
43139365Srik#include <sys/kernel.h>
44139365Srik#include <sys/module.h>
45139365Srik#include <sys/sockio.h>
46139365Srik#include <sys/socket.h>
47139365Srik#include <sys/syslog.h>
48139365Srik#if defined(__FreeBSD__) && __FreeBSD__ >= 3
49139365Srik#include <sys/random.h>
50139365Srik#endif
51139365Srik#include <sys/malloc.h>
52139365Srik#include <sys/mbuf.h>
53139365Srik
54139365Srik#if defined (__OpenBSD__)
55139365Srik#include <sys/md5k.h>
56139365Srik#else
57139365Srik#include <sys/md5.h>
58139365Srik#endif
59139365Srik
60139365Srik#include <net/if.h>
61139365Srik#include <net/netisr.h>
62139365Srik#include <net/if_types.h>
63139365Srik#include <net/route.h>
64139365Srik#include <netinet/in.h>
65139365Srik#include <netinet/in_systm.h>
66139365Srik#include <netinet/ip.h>
67139365Srik#include <net/slcompress.h>
68139365Srik
69139365Srik#if defined (__NetBSD__) || defined (__OpenBSD__)
70139365Srik#include <machine/cpu.h> /* XXX for softnet */
71139365Srik#endif
72139365Srik
73139365Srik#include <machine/stdarg.h>
74139365Srik
75139365Srik#include <netinet/in_var.h>
76139365Srik#ifdef INET
77139365Srik#include <netinet/ip.h>
78139365Srik#include <netinet/tcp.h>
79139365Srik#endif
80139365Srik
81139365Srik#if defined (__FreeBSD__) || defined (__OpenBSD__)
82139365Srik#  include <netinet/if_ether.h>
83139365Srik#else
84139365Srik#  include <net/ethertypes.h>
85139365Srik#endif
86139365Srik
87139365Srik#ifdef IPX
88139365Srik#include <netipx/ipx.h>
89139365Srik#include <netipx/ipx_if.h>
90139365Srik#endif
91139365Srik
92139365Srik#include <net/if_sppp.h>
93139365Srik
94139365Srik/*
95139365Srik * Frame Relay.
96139365Srik */
97139365Srik#define FR_UI		0x03	/* Unnumbered Information */
98139365Srik#define FR_IP           0xCC    /* IP protocol identifier */
99139365Srik#define FR_PADDING      0x00    /* NLPID padding */
100139365Srik#define FR_SIGNALING    0x08    /* Q.933/T1.617 signaling identifier */
101139365Srik#define FR_SNAP         0x80    /* NLPID snap */
102139365Srik
103139365Srik/*
104139365Srik * Header flags.
105139365Srik */
106139365Srik#define FR_DE           0x02    /* discard eligibility */
107139365Srik#define FR_FECN         0x04    /* forward notification */
108139365Srik#define FR_BECN         0x08    /* backward notification */
109139365Srik
110139365Srik/*
111139365Srik * Signaling message types.
112139365Srik */
113139365Srik#define FR_MSG_ENQUIRY  0x75    /* status enquiry */
114139365Srik#define FR_MSG_STATUS   0x7d    /* status */
115139365Srik
116139365Srik#define FR_ENQUIRY_SIZE	14
117139365Srik
118139365Srik/*
119139365Srik * Message field types.
120139365Srik */
121139365Srik#define FR_FLD_RTYPE    0x01    /* report type */
122139365Srik#define FR_FLD_VERIFY   0x03    /* link verification */
123139365Srik#define FR_FLD_PVC      0x07    /* PVC status */
124139365Srik#define FR_FLD_LSHIFT5  0x95    /* locking shift 5 */
125139365Srik
126139365Srik/*
127139365Srik * Report types.
128139365Srik */
129139365Srik#define FR_RTYPE_FULL   0       /* full status */
130139365Srik#define FR_RTYPE_SHORT  1       /* link verification only */
131139365Srik#define FR_RTYPE_SINGLE 2       /* single PVC status */
132139365Srik
133139365Srik/* PVC status field. */
134139365Srik#define FR_DLCI_DELETE  0x04    /* PVC is deleted */
135139365Srik#define FR_DLCI_ACTIVE  0x02    /* PVC is operational */
136139365Srik#define FR_DLCI_NEW     0x08    /* PVC is new */
137139365Srik
138139365Srikstruct arp_req {
139139365Srik	unsigned short  htype;          /* hardware type = ARPHRD_FRELAY */
140139365Srik	unsigned short  ptype;          /* protocol type = ETHERTYPE_IP */
141139365Srik	unsigned char   halen;          /* hardware address length = 2 */
142139365Srik	unsigned char   palen;          /* protocol address length = 4 */
143139365Srik	unsigned short  op;             /* ARP/RARP/InARP request/reply */
144139365Srik	unsigned short  hsource;        /* hardware source address */
145139365Srik	unsigned short  psource1;       /* protocol source */
146139365Srik	unsigned short  psource2;
147139365Srik	unsigned short  htarget;        /* hardware target address */
148139365Srik	unsigned short  ptarget1;       /* protocol target */
149139365Srik	unsigned short  ptarget2;
150139365Srik} __packed;
151139365Srik
152139365Srik#if defined(__FreeBSD__) && __FreeBSD__ >= 3 && __FreeBSD_version < 501113
153139365Srik#define	SPP_FMT		"%s%d: "
154139365Srik#define	SPP_ARGS(ifp)	(ifp)->if_name, (ifp)->if_unit
155139365Srik#else
156139365Srik#define	SPP_FMT		"%s: "
157139365Srik#define	SPP_ARGS(ifp)	(ifp)->if_xname
158139365Srik#endif
159139365Srik
160139365Srik/* almost every function needs these */
161139365Srik#define STDDCL							\
162139365Srik	struct ifnet *ifp = &sp->pp_if;				\
163139365Srik	int debug = ifp->if_flags & IFF_DEBUG
164139365Srik
165139365Srikstatic void sppp_fr_arp (struct sppp *sp, struct arp_req *req, u_short addr);
166139365Srikstatic void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len);
167139365Srik
168139365Srikvoid sppp_fr_input (struct sppp *sp, struct mbuf *m)
169139365Srik{
170139365Srik	STDDCL;
171139365Srik	u_char *h = mtod (m, u_char*);
172139365Srik	int isr = -1;
173139365Srik	int dlci, hlen, proto;
174139365Srik
175139365Srik	/* Get the DLCI number. */
176139365Srik	if (m->m_pkthdr.len < 10) {
177139365Srikbad:            m_freem (m);
178139365Srik		return;
179139365Srik	}
180139365Srik	dlci = (h[0] << 2 & 0x3f0) | (h[1] >> 4 & 0x0f);
181139365Srik
182139365Srik	/* Process signaling packets. */
183139365Srik	if (dlci == 0) {
184139365Srik		sppp_fr_signal (sp, h, m->m_pkthdr.len);
185139365Srik		m_freem (m);
186139365Srik		return;
187139365Srik	}
188139365Srik
189139365Srik	if (dlci != sp->fr_dlci) {
190139365Srik		if (debug)
191139365Srik			printf (SPP_FMT "Received packet from invalid DLCI %d\n",
192139365Srik				SPP_ARGS(ifp), dlci);
193139365Srik		goto bad;
194139365Srik	}
195139365Srik
196139365Srik	/* Process the packet. */
197139365Srik	if (ntohs (*(short*) (h+2)) == ETHERTYPE_IP) {
198139365Srik                /* Prehistoric IP framing? */
199139365Srik		h[2] = FR_UI;
200139365Srik		h[3] = FR_IP;
201139365Srik	}
202139365Srik	if (h[2] != FR_UI) {
203139365Srik		if (debug)
204139365Srik			printf (SPP_FMT "Invalid frame relay header flag 0x%02x\n",
205139365Srik				SPP_ARGS(ifp), h[2]);
206139365Srik		goto bad;
207139365Srik	}
208139365Srik	switch (h[3]) {
209139365Srik	default:
210139365Srik		if (debug)
211139365Srik			printf (SPP_FMT "Unsupported NLPID 0x%02x\n",
212139365Srik				SPP_ARGS(ifp), h[3]);
213139365Srik		goto bad;
214139365Srik
215139365Srik	case FR_PADDING:
216139365Srik		if (h[4] != FR_SNAP) {
217139365Srik			if (debug)
218139365Srik				printf (SPP_FMT "Bad NLPID 0x%02x\n",
219139365Srik					SPP_ARGS(ifp), h[4]);
220139365Srik			goto bad;
221139365Srik		}
222139365Srik		if (h[5] || h[6] || h[7]) {
223139365Srik			if (debug)
224139365Srik				printf (SPP_FMT "Bad OID 0x%02x-0x%02x-0x%02x\n",
225139365Srik					SPP_ARGS(ifp),
226139365Srik					h[5], h[6], h[7]);
227139365Srik			goto bad;
228139365Srik		}
229139365Srik		proto = ntohs (*(short*) (h+8));
230139365Srik		if (proto == ETHERTYPE_ARP) {
231139365Srik			/* Process the ARP request. */
232139365Srik			if (m->m_pkthdr.len != 10 + sizeof (struct arp_req)) {
233139365Srik				if (debug)
234139365Srik					printf (SPP_FMT "Bad ARP request size = %d bytes\n",
235139365Srik						SPP_ARGS(ifp),
236139365Srik						m->m_pkthdr.len);
237139365Srik				goto bad;
238139365Srik			}
239139365Srik			sppp_fr_arp (sp, (struct arp_req*) (h + 10),
240139365Srik				h[0] << 8 | h[1]);
241139365Srik			m_freem (m);
242139365Srik			return;
243139365Srik		}
244139365Srik		hlen = 10;
245139365Srik		break;
246139365Srik
247139365Srik	case FR_IP:
248139365Srik		proto = ETHERTYPE_IP;
249139365Srik		hlen = 4;
250139365Srik		break;
251139365Srik	}
252139365Srik
253139365Srik	/* Remove frame relay header. */
254139365Srik	m_adj (m, hlen);
255139365Srik
256139365Srik	switch (proto) {
257139365Srik	default:
258139365Srik		++ifp->if_noproto;
259139365Srikdrop:		++ifp->if_ierrors;
260139365Srik		++ifp->if_iqdrops;
261139365Srik		m_freem (m);
262139365Srik		return;
263139365Srik#ifdef INET
264139365Srik	case ETHERTYPE_IP:
265139365Srik		isr = NETISR_IP;
266139365Srik		break;
267139365Srik#endif
268139365Srik#ifdef IPX
269139365Srik	case ETHERTYPE_IPX:
270139365Srik		isr = NETISR_IPX;
271139365Srik		break;
272139365Srik#endif
273139365Srik#ifdef NETATALK
274139365Srik        case ETHERTYPE_AT:
275139365Srik		isr = NETISR_ATALK;
276139365Srik                break;
277139365Srik#endif
278139365Srik	}
279139365Srik
280139365Srik	if (! (ifp->if_flags & IFF_UP))
281139365Srik		goto drop;
282139365Srik
283139365Srik	/* Check queue. */
284139365Srik	if (netisr_queue(isr, m)) {	/* (0) on success. */
285139365Srik		if (debug)
286139365Srik			log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n",
287139365Srik				SPP_ARGS(ifp));
288139365Srik	}
289139365Srik}
290139365Srik
291139365Srik/*
292139365Srik * Add the frame relay header to the packet.
293139365Srik * For IP the header length is 4 bytes,
294139365Srik * for all other protocols - 10 bytes (RFC 1490).
295139365Srik */
296139365Srikstruct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m,
297139365Srik	int family)
298139365Srik{
299139365Srik	STDDCL;
300139365Srik	u_char *h;
301139365Srik	int type, hlen;
302139365Srik
303139365Srik	/* Prepend the space for Frame Relay header. */
304139365Srik	hlen = (family == AF_INET) ? 4 : 10;
305139365Srik	M_PREPEND (m, hlen, M_DONTWAIT);
306139365Srik	if (! m)
307139365Srik		return 0;
308139365Srik	h = mtod (m, u_char*);
309139365Srik
310139365Srik	/* Fill the header. */
311139365Srik	h[0] = sp->fr_dlci >> 2 & 0xfc;
312139365Srik	h[1] = sp->fr_dlci << 4 | 1;
313139365Srik	h[2] = FR_UI;
314139365Srik
315139365Srik	switch (family) {
316139365Srik	default:
317139365Srik		if (debug)
318139365Srik			printf (SPP_FMT "Cannot handle address family %d\n",
319139365Srik				SPP_ARGS(ifp), family);
320139365Srik		m_freem (m);
321139365Srik		return 0;
322139365Srik#ifdef INET
323139365Srik	case AF_INET:
324139365Srik#if 0 /* Crashes on fragmented packets */
325139365Srik		/*
326139365Srik		 * Set the discard eligibility bit, if:
327139365Srik		 * 1) no fragmentation
328139365Srik		 * 2) length > 400 bytes
329139365Srik		 * 3a) the protocol is UDP or
330139365Srik		 * 3b) TCP data (no control bits)
331139365Srik		 */
332139365Srik		{
333139365Srik		struct ip *ip = (struct ip*) (h + hlen);
334139365Srik		struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
335139365Srik
336139365Srik		if (! (ip->ip_off & ~IP_DF) && ip->ip_len > 400 &&
337139365Srik		    (ip->ip_p == IPPROTO_UDP ||
338139365Srik		    ip->ip_p == IPPROTO_TCP && ! tcp->th_flags))
339139365Srik			h[1] |= FR_DE;
340139365Srik		}
341139365Srik#endif
342139365Srik		h[3] = FR_IP;
343139365Srik		return m;
344139365Srik#endif
345139365Srik#ifdef IPX
346139365Srik	case AF_IPX:
347139365Srik		type = ETHERTYPE_IPX;
348139365Srik		break;
349139365Srik#endif
350139365Srik#ifdef NS
351139365Srik	case AF_NS:
352139365Srik		type = 0x8137;
353139365Srik		break;
354139365Srik#endif
355139365Srik#ifdef NETATALK
356139365Srik	case AF_APPLETALK:
357139365Srik		type = ETHERTYPE_AT;
358139365Srik		break;
359139365Srik#endif
360139365Srik	}
361139365Srik	h[3] = FR_PADDING;
362139365Srik	h[4] = FR_SNAP;
363139365Srik	h[5] = 0;
364139365Srik	h[6] = 0;
365139365Srik	h[7] = 0;
366139365Srik	*(short*) (h+8) = htons(type);
367139365Srik	return m;
368139365Srik}
369139365Srik
370139365Srik/*
371139365Srik * Send periodical frame relay link verification messages via DLCI 0.
372139365Srik * Called every 10 seconds (default value of T391 timer is 10 sec).
373139365Srik * Every 6-th message is a full status request
374139365Srik * (default value of N391 counter is 6).
375139365Srik */
376139365Srikvoid sppp_fr_keepalive (struct sppp *sp)
377139365Srik{
378139365Srik	STDDCL;
379139365Srik	unsigned char *h, *p;
380139365Srik	struct mbuf *m;
381139365Srik
382139365Srik	MGETHDR (m, M_DONTWAIT, MT_DATA);
383139365Srik	if (! m)
384139365Srik		return;
385139365Srik	m->m_pkthdr.rcvif = 0;
386139365Srik
387139365Srik	h = mtod (m, u_char*);
388139365Srik	p = h;
389139365Srik	*p++ = 0;                       /* DLCI = 0 */
390139365Srik	*p++ = 1;
391139365Srik	*p++ = FR_UI;
392139365Srik	*p++ = FR_SIGNALING;            /* NLPID = UNI call control */
393139365Srik
394139365Srik	*p++ = 0;                       /* call reference length = 0 */
395139365Srik	*p++ = FR_MSG_ENQUIRY;          /* message type = status enquiry */
396139365Srik
397139365Srik	*p++ = FR_FLD_LSHIFT5;          /* locking shift 5 */
398139365Srik
399139365Srik	*p++ = FR_FLD_RTYPE;            /* report type field */
400139365Srik	*p++ = 1;                       /* report type length = 1 */
401139365Srik	if (sp->pp_seq[IDX_LCP] % 6)
402139365Srik		*p++ = FR_RTYPE_SHORT;  /* link verification only */
403139365Srik	else
404139365Srik		*p++ = FR_RTYPE_FULL;   /* full status needed */
405139365Srik
406139365Srik	if (sp->pp_seq[IDX_LCP] >= 255)
407139365Srik		sp->pp_seq[IDX_LCP] = 0;
408139365Srik	*p++ = FR_FLD_VERIFY;           /* link verification type field */
409139365Srik	*p++ = 2;                       /* link verification field length = 2 */
410139365Srik	*p++ = ++sp->pp_seq[IDX_LCP];   /* our sequence number */
411139365Srik	*p++ = sp->pp_rseq[IDX_LCP];    /* last received sequence number */
412139365Srik
413139365Srik	m->m_pkthdr.len = m->m_len = p - h;
414139365Srik	if (debug)
415139365Srik		printf (SPP_FMT "send lmi packet, seq=%d, rseq=%d\n",
416139365Srik			SPP_ARGS(ifp), (u_char) sp->pp_seq[IDX_LCP],
417139365Srik			(u_char) sp->pp_rseq[IDX_LCP]);
418139365Srik
419139365Srik	if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
420139365Srik		++ifp->if_oerrors;
421139365Srik}
422139365Srik
423139365Srik/*
424139365Srik * Process the frame relay Inverse ARP request.
425139365Srik */
426139365Srikstatic void sppp_fr_arp (struct sppp *sp, struct arp_req *req,
427139365Srik	u_short his_hardware_address)
428139365Srik{
429139365Srik	STDDCL;
430139365Srik	struct mbuf *m;
431139365Srik	struct arp_req *reply;
432139365Srik	u_char *h;
433139365Srik	u_short my_hardware_address;
434139365Srik	u_long his_ip_address, my_ip_address;
435139365Srik
436139365Srik	if ((ntohs (req->htype) != ARPHRD_FRELAY ||
437139365Srik	    ntohs (req->htype) != 16) || /* for BayNetworks routers */
438139365Srik	    ntohs (req->ptype) != ETHERTYPE_IP) {
439139365Srik		if (debug)
440139365Srik			printf (SPP_FMT "Invalid ARP hardware/protocol type = 0x%x/0x%x\n",
441139365Srik				SPP_ARGS(ifp),
442139365Srik				ntohs (req->htype), ntohs (req->ptype));
443139365Srik		return;
444139365Srik	}
445139365Srik	if (req->halen != 2 || req->palen != 4) {
446139365Srik		if (debug)
447139365Srik			printf (SPP_FMT "Invalid ARP hardware/protocol address length = %d/%d\n",
448139365Srik				SPP_ARGS(ifp),
449139365Srik				req->halen, req->palen);
450139365Srik		return;
451139365Srik	}
452139365Srik	switch (ntohs (req->op)) {
453139365Srik	default:
454139365Srik		if (debug)
455139365Srik			printf (SPP_FMT "Invalid ARP op = 0x%x\n",
456139365Srik				SPP_ARGS(ifp), ntohs (req->op));
457139365Srik		return;
458139365Srik
459139365Srik	case ARPOP_INVREPLY:
460139365Srik		/* Ignore. */
461139365Srik		return;
462139365Srik
463139365Srik	case ARPOP_INVREQUEST:
464139365Srik		my_hardware_address = ntohs (req->htarget);
465139365Srik		his_ip_address = ntohs (req->psource1) << 16 |
466139365Srik			ntohs (req->psource2);
467139365Srik		my_ip_address = ntohs (req->ptarget1) << 16 |
468139365Srik			ntohs (req->ptarget2);
469139365Srik		break;
470139365Srik	}
471139365Srik	if (debug)
472139365Srik		printf (SPP_FMT "got ARP request, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
473139365Srik			SPP_ARGS(ifp), ntohs (req->hsource),
474139365Srik			(unsigned char) (his_ip_address >> 24),
475139365Srik			(unsigned char) (his_ip_address >> 16),
476139365Srik			(unsigned char) (his_ip_address >> 8),
477139365Srik			(unsigned char) his_ip_address,
478139365Srik			my_hardware_address,
479139365Srik			(unsigned char) (my_ip_address >> 24),
480139365Srik			(unsigned char) (my_ip_address >> 16),
481139365Srik			(unsigned char) (my_ip_address >> 8),
482139365Srik			(unsigned char) my_ip_address);
483139365Srik
484139365Srik	sppp_get_ip_addrs (sp, &my_ip_address, 0, 0);
485139365Srik	if (! my_ip_address)
486139365Srik		return;         /* nothing to reply */
487139365Srik
488139365Srik	if (debug)
489139365Srik		printf (SPP_FMT "send ARP reply, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
490139365Srik			SPP_ARGS(ifp), my_hardware_address,
491139365Srik			(unsigned char) (my_ip_address >> 24),
492139365Srik			(unsigned char) (my_ip_address >> 16),
493139365Srik			(unsigned char) (my_ip_address >> 8),
494139365Srik			(unsigned char) my_ip_address,
495139365Srik			his_hardware_address,
496139365Srik			(unsigned char) (his_ip_address >> 24),
497139365Srik			(unsigned char) (his_ip_address >> 16),
498139365Srik			(unsigned char) (his_ip_address >> 8),
499139365Srik			(unsigned char) his_ip_address);
500139365Srik
501139365Srik	/* Send the Inverse ARP reply. */
502139365Srik	MGETHDR (m, M_DONTWAIT, MT_DATA);
503139365Srik	if (! m)
504139365Srik		return;
505139365Srik	m->m_pkthdr.len = m->m_len = 10 + sizeof (*reply);
506139365Srik	m->m_pkthdr.rcvif = 0;
507139365Srik
508139365Srik	h = mtod (m, u_char*);
509139365Srik	reply = (struct arp_req*) (h + 10);
510139365Srik
511139365Srik	h[0] = his_hardware_address >> 8;
512139365Srik	h[1] = his_hardware_address;
513139365Srik	h[2] = FR_UI;
514139365Srik	h[3] = FR_PADDING;
515139365Srik	h[4] = FR_SNAP;
516139365Srik	h[5] = 0;
517139365Srik	h[6] = 0;
518139365Srik	h[7] = 0;
519139365Srik	*(short*) (h+8) = htons (ETHERTYPE_ARP);
520139365Srik
521139365Srik	reply->htype    = htons (ARPHRD_FRELAY);
522139365Srik	reply->ptype    = htons (ETHERTYPE_IP);
523139365Srik	reply->halen    = 2;
524139365Srik	reply->palen    = 4;
525139365Srik	reply->op       = htons (ARPOP_INVREPLY);
526139365Srik	reply->hsource  = htons (my_hardware_address);
527139365Srik	reply->psource1 = htonl (my_ip_address);
528139365Srik	reply->psource2 = htonl (my_ip_address) >> 16;
529139365Srik	reply->htarget  = htons (his_hardware_address);
530139365Srik	reply->ptarget1 = htonl (his_ip_address);
531139365Srik	reply->ptarget2 = htonl (his_ip_address) >> 16;
532139365Srik
533139365Srik	if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
534139365Srik		++ifp->if_oerrors;
535139365Srik}
536139365Srik
537139365Srik/*
538139365Srik * Process the input signaling packet (DLCI 0).
539139365Srik * The implemented protocol is ANSI T1.617 Annex D.
540139365Srik */
541139365Srikstatic void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len)
542139365Srik{
543139365Srik	STDDCL;
544139365Srik	u_char *p;
545139365Srik	int dlci;
546139365Srik
547139365Srik	if (h[2] != FR_UI || h[3] != FR_SIGNALING || h[4] != 0) {
548139365Srik		if (debug)
549139365Srik			printf (SPP_FMT "Invalid signaling header\n",
550139365Srik				SPP_ARGS(ifp));
551139365Srikbad:            if (debug) {
552139365Srik			printf ("%02x", *h++);
553139365Srik			while (--len > 0)
554139365Srik				printf ("-%02x", *h++);
555139365Srik			printf ("\n");
556139365Srik		}
557139365Srik		return;
558139365Srik	}
559139365Srik	if (h[5] == FR_MSG_ENQUIRY) {
560139365Srik		if (len == FR_ENQUIRY_SIZE &&
561139365Srik		    h[12] == (u_char) sp->pp_seq[IDX_LCP]) {
562139365Srik			sp->pp_seq[IDX_LCP] = random();
563139365Srik			printf (SPP_FMT "loopback detected\n",
564139365Srik				SPP_ARGS(ifp));
565139365Srik		}
566139365Srik		return;
567139365Srik	}
568139365Srik	if (h[5] != FR_MSG_STATUS) {
569139365Srik		if (debug)
570139365Srik			printf (SPP_FMT "Unknown signaling message: 0x%02x\n",
571139365Srik				SPP_ARGS(ifp), h[5]);
572139365Srik		goto bad;
573139365Srik	}
574139365Srik
575139365Srik	/* Parse message fields. */
576139365Srik	for (p=h+6; p<h+len; ) {
577139365Srik		switch (*p) {
578139365Srik		default:
579139365Srik			if (debug)
580139365Srik				printf (SPP_FMT "Unknown signaling field 0x%x\n",
581139365Srik					SPP_ARGS(ifp), *p);
582139365Srik			break;
583139365Srik		case FR_FLD_LSHIFT5:
584139365Srik		case FR_FLD_RTYPE:
585139365Srik			/* Ignore. */
586139365Srik			break;
587139365Srik		case FR_FLD_VERIFY:
588139365Srik			if (p[1] != 2) {
589139365Srik				if (debug)
590139365Srik					printf (SPP_FMT "Invalid signaling verify field length %d\n",
591139365Srik						SPP_ARGS(ifp), p[1]);
592139365Srik				break;
593139365Srik			}
594139365Srik			sp->pp_rseq[IDX_LCP] = p[2];
595139365Srik			if (debug) {
596139365Srik				printf (SPP_FMT "got lmi reply rseq=%d, seq=%d",
597139365Srik					SPP_ARGS(ifp), p[2], p[3]);
598139365Srik				if (p[3] != (u_char) sp->pp_seq[IDX_LCP])
599139365Srik					printf (" (really %d)",
600139365Srik						(u_char) sp->pp_seq[IDX_LCP]);
601139365Srik				printf ("\n");
602139365Srik			}
603139365Srik			break;
604139365Srik		case FR_FLD_PVC:
605139365Srik			if (p[1] < 3) {
606139365Srik				if (debug)
607139365Srik					printf (SPP_FMT "Invalid PVC status length %d\n",
608139365Srik						SPP_ARGS(ifp), p[1]);
609139365Srik				break;
610139365Srik			}
611139365Srik			dlci = (p[2] << 4 & 0x3f0) | (p[3] >> 3 & 0x0f);
612139365Srik			if (! sp->fr_dlci)
613139365Srik				sp->fr_dlci = dlci;
614139365Srik			if (sp->fr_status != p[4])
615139365Srik				printf (SPP_FMT "DLCI %d %s%s\n",
616139365Srik					SPP_ARGS(ifp), dlci,
617139365Srik					p[4] & FR_DLCI_DELETE ? "deleted" :
618139365Srik					p[4] & FR_DLCI_ACTIVE ? "active" : "passive",
619139365Srik					p[4] & FR_DLCI_NEW ? ", new" : "");
620139365Srik			sp->fr_status = p[4];
621139365Srik			break;
622139365Srik		}
623139365Srik		if (*p & 0x80)
624139365Srik			++p;
625139365Srik		else if (p < h+len+1 && p[1])
626139365Srik			p += 2 + p[1];
627139365Srik		else {
628139365Srik			if (debug)
629139365Srik				printf (SPP_FMT "Invalid signaling field 0x%x\n",
630139365Srik					SPP_ARGS(ifp), *p);
631139365Srik			goto bad;
632139365Srik		}
633139365Srik	}
634139365Srik}
635