Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Nov 1999 19:02:06 +0300 (MSK)
From:      vak@cronyx.ru
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/14843: Added Frame Relay support
Message-ID:  <199911121602.TAA00364@crox.cronyx.ru>

next in thread | raw e-mail | index | archive | help

>Number:         14843
>Category:       kern
>Synopsis:       Added support of Frame Relay protocol
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Nov 12 08:00:01 PST 1999
>Closed-Date:
>Last-Modified:
>Originator:     Serge V.Vakulenko
>Release:        FreeBSD 3.3-RELEASE i386
>Organization:
Cronyx
>Environment:

	FreeBSD router with serial adapters installed.

>Description:

	The in-kernel implementation of point-to-point protocols
	supported only PPP and Cisco/HDLC protocols.
	This patch adds Frame Relay support, with
	ANSI T1.617 signaling.

>How-To-Repeat:
>Fix:

--- if_sppp33.h	Fri Nov 12 17:09:39 1999
+++ if_sppp.h	Fri Nov 12 17:10:20 1999
@@ -99,6 +99,8 @@
 	struct sipcp ipcp;		/* IPCP params */
 	struct sauth myauth;		/* auth params, i'm peer */
 	struct sauth hisauth;		/* auth params, i'm authenticator */
+	u_short fr_dlci;		/* Frame Relay DLCI number, 16..1023 */
+	u_char fr_status;		/* PVC status, active/new/delete */
 	/*
 	 * These functions are filled in by sppp_attach(), and are
 	 * expected to be used by the lower layer (hardware) drivers
@@ -133,7 +135,7 @@

 #define PP_KEEPALIVE    0x01    /* use keepalive protocol */
 #define PP_CISCO        0x02    /* use Cisco protocol instead of PPP */
-				/* 0x04 was PP_TIMO */
+#define PP_FR		0x04	/* use Frame Relay protocol instead of PPP */
 #define PP_CALLIN	0x08	/* we are being called */
 #define PP_NEEDAUTH	0x10	/* remote requested authentication */

--- if_sppps33.c	Fri Nov 12 18:21:18 1999
+++ if_spppsubr.c	Fri Nov 12 18:50:57 1999
@@ -1,8 +1,12 @@
 /*
- * Synchronous PPP/Cisco link level subroutines.
+ * Synchronous PPP/Cisco/Frame Relay link level subroutines.
  * Keepalive protocol implemented in both Cisco and PPP modes.
+ * ANSI T1.617-compaible link management signaling
+ * implemented for Frame Relay mode.
+ * Cisco-type Frame Relay framing added, thanks Alex Tutubalin.
+ * Only one DLCI per channel for now.
  *
- * Copyright (C) 1994-1996 Cronyx Engineering Ltd.
+ * Copyright (C) 1994-1999 Cronyx Engineering Ltd.
  * Author: Serge Vakulenko, <vak@cronyx.ru>
  *
  * Heavily revamped to conform to RFC 1661.
@@ -226,6 +230,63 @@
 #define CISCO_PACKET_LEN 18

 /*
+ * Frame Relay.
+ */
+#define FR_IP           0xCC    /* IP protocol identifier */
+#define FR_PADDING      0x00    /* NLPID padding */
+#define FR_SIGNALING    0x08    /* Q.933/T1.617 signaling identifier */
+#define FR_SNAP         0x80    /* NLPID snap */
+
+/*
+ * Header flags.
+ */
+#define FR_DE           0x02    /* discard eligibility */
+#define FR_FECN         0x04    /* forward notification */
+#define FR_BECN         0x08    /* backward notification */
+
+/*
+ * Signaling message types.
+ */
+#define FR_MSG_ENQUIRY  0x75    /* status enquiry */
+#define FR_MSG_STATUS   0x7d    /* status */
+
+#define FR_ENQUIRY_SIZE	14
+
+/*
+ * Message field types.
+ */
+#define FR_FLD_RTYPE    0x01    /* report type */
+#define FR_FLD_VERIFY   0x03    /* link verification */
+#define FR_FLD_PVC      0x07    /* PVC status */
+#define FR_FLD_LSHIFT5  0x95    /* locking shift 5 */
+
+/*
+ * Report types.
+ */
+#define FR_RTYPE_FULL   0       /* full status */
+#define FR_RTYPE_SHORT  1       /* link verification only */
+#define FR_RTYPE_SINGLE 2       /* single PVC status */
+
+/* PVC status field. */
+#define FR_DLCI_DELETE  0x04    /* PVC is deleted */
+#define FR_DLCI_ACTIVE  0x02    /* PVC is operational */
+#define FR_DLCI_NEW     0x08    /* PVC is new */
+
+struct arp_req {
+	unsigned short  htype;          /* hardware type = ARPHRD_FRELAY */
+	unsigned short  ptype;          /* protocol type = ETHERTYPE_IP */
+	unsigned char   halen;          /* hardware address length = 2 */
+	unsigned char   palen;          /* protocol address length = 4 */
+	unsigned short  op;             /* ARP/RARP/InARP request/reply */
+	unsigned short  hsource;        /* hardware source address */
+	unsigned short  psource1;       /* protocol source */
+	unsigned short  psource2;
+	unsigned short  htarget;        /* hardware target address */
+	unsigned short  ptarget1;       /* protocol target */
+	unsigned short  ptarget2;
+};
+
+/*
  * We follow the spelling and capitalization of RFC 1661 here, to make
  * it easier comparing with the standard.  Please refer to this RFC in
  * case you can't make sense out of these abbreviation; it will also
@@ -295,6 +356,12 @@
 static void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2);
 static void sppp_cisco_input(struct sppp *sp, struct mbuf *m);

+static void sppp_fr_input (struct sppp *sp, struct mbuf *m);
+static struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m, int fam);
+static void sppp_fr_keepalive (struct sppp *sp);
+static void sppp_fr_arp (struct sppp *sp, struct arp_req *req, u_short addr);
+static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len);
+
 static void sppp_cp_input(const struct cp *cp, struct sppp *sp,
 			  struct mbuf *m);
 static void sppp_cp_send(struct sppp *sp, u_short proto, u_char type,
@@ -458,6 +525,11 @@
 		return;
 	}

+	if (sp->pp_flags & PP_FR) {
+		sppp_fr_input (sp, m);
+		return;
+	}
+
 	/* Get PPP header. */
 	h = mtod (m, struct ppp_header*);
 	m_adj (m, PPP_HEADER_LEN);
@@ -663,7 +735,7 @@
 		 * become invalid. So we
 		 * - don't let packets with src ip addr 0 thru
 		 * - we flag TCP packets with src ip 0 as an error
-		 */
+		 */

 		if(ip->ip_src.s_addr == INADDR_ANY)	/* -hm */
 		{
@@ -674,7 +746,7 @@
 			else
 				return(0);
 		}
-
+
 		/*
 		 * Put low delay, telnet, rlogin and ftp control packets
 		 * in front of the queue.
@@ -694,12 +766,20 @@
 	}
 #endif

+	if (sp->pp_flags & PP_FR) {
+		/* Add frame relay header. */
+		m = sppp_fr_header (sp, m, dst->sa_family);
+		if (! m)
+			goto nobufs;
+		goto out;
+	}
+
 	/*
 	 * Prepend general data packet PPP header. For now, IP only.
 	 */
 	M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT);
 	if (! m) {
-		if (debug)
+nobufs:		if (debug)
 			log(LOG_DEBUG, SPP_FMT "no memory for transmit header\n",
 				SPP_ARGS(ifp));
 		++ifp->if_oerrors;
@@ -771,7 +851,7 @@
 	 * Queue message on interface, and start output if interface
 	 * not yet active.
 	 */
-	if (IF_QFULL (ifq)) {
+out:	if (IF_QFULL (ifq)) {
 		IF_DROP (&ifp->if_snd);
 		m_freem (m);
 		++ifp->if_oerrors;
@@ -898,7 +978,8 @@
 	 */
 	IF_DEQUEUE(&sp->pp_cpq, m);
 	if (m == NULL &&
-	    (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) {
+	    (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0 ||
+	    (sp->pp_flags & PP_FR) != 0)) {
 		IF_DEQUEUE(&sp->pp_fastq, m);
 		if (m == NULL)
 			IF_DEQUEUE (&sp->pp_if.if_snd, m);
@@ -922,7 +1003,8 @@
 	m = sp->pp_cpq.ifq_head;
 	if (m == NULL &&
 	    (sp->pp_phase == PHASE_NETWORK ||
-	     (sp->pp_flags & PP_CISCO) != 0))
+	     (sp->pp_flags & PP_CISCO) != 0 ||
+	     (sp->pp_flags & PP_FR) != 0))
 		if ((m = sp->pp_fastq.ifq_head) == NULL)
 			m = sp->pp_if.if_snd.ifq_head;
 	splx (s);
@@ -963,11 +1045,14 @@
 		}

 		if (going_up || going_down)
-			lcp.Close(sp);
+ 			if (! (sp->pp_flags & PP_CISCO) &&
+ 			    ! (sp->pp_flags & PP_FR))
+				lcp.Close(sp);
 		if (going_up && newmode == 0) {
 			/* neither auto-dial nor passive */
 			ifp->if_flags |= IFF_RUNNING;
-			if (!(sp->pp_flags & PP_CISCO))
+ 			if (! (sp->pp_flags & PP_CISCO) &&
+ 			    ! (sp->pp_flags & PP_FR))
 				lcp.Open(sp);
 		} else if (going_down) {
 			sppp_flush(ifp);
@@ -1117,7 +1202,7 @@
 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
 	getmicrouptime(&tv);
 #endif
-
+
 	MGETHDR (m, M_DONTWAIT, MT_DATA);
 	if (! m)
 		return;
@@ -1738,7 +1823,7 @@
 		case STATE_STOPPING:
 			sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq,
 				     0, 0);
-			TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout,
+			TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout,
 			    sp->ch[cp->protoidx]);
 			break;
 		case STATE_REQ_SENT:
@@ -1779,7 +1864,7 @@
 	case STATE_REQ_SENT:
 	case STATE_ACK_RCVD:
 	case STATE_ACK_SENT:
-		TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout,
+		TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout,
 		    sp->ch[cp->protoidx]);
 		break;
 	}
@@ -2322,7 +2407,7 @@
 	/* notify low-level driver of state change */
 	if (sp->pp_chg)
 		sp->pp_chg(sp, (int)sp->pp_phase);
-
+
 	if (sp->pp_phase == PHASE_NETWORK)
 		/* if no NCP is starting, close down */
 		sppp_lcp_check_and_close(sp);
@@ -2641,7 +2726,7 @@
 			    (hisaddr == 1 && desiredaddr != 0)) {
 				/*
 				 * Peer's address is same as our value,
-				 * or we have set it to 0.0.0.1 to
+				 * or we have set it to 0.0.0.1 to
 				 * indicate that we do not really care,
 				 * this is agreeable.  Gonna conf-ack
 				 * it.
@@ -3026,7 +3111,7 @@
 			}
 			break;
 		}
-
+
 		if (debug) {
 			log(LOG_DEBUG,
 			    SPP_FMT "chap input <%s id=0x%x len=%d name=",
@@ -3136,7 +3221,7 @@
 			sppp_print_string(sp->hisauth.name,
 					  sppp_strnlen(sp->hisauth.name, AUTHNAMELEN));
 			addlog("\n");
-		}
+		}
 		if (debug) {
 			log(LOG_DEBUG, SPP_FMT "chap input(%s) "
 			    "<%s id=0x%x len=%d name=",
@@ -3812,6 +3897,11 @@
 		    ! (ifp->if_flags & IFF_RUNNING))
 			continue;

+		if (sp->pp_flags & PP_FR) {
+			sppp_fr_keepalive (sp);
+			continue;
+		}
+
 		/* No keepalive in PPP mode if LCP not opened yet. */
 		if (! (sp->pp_flags & PP_CISCO) &&
 		    sp->pp_phase < PHASE_AUTHENTICATE)
@@ -3958,7 +4048,7 @@
 		si->sin_addr.s_addr = htonl(src);

 		/* add new route */
-		error = rtinit(ifa, (int)RTM_ADD, RTF_HOST);
+		error = rtinit(ifa, (int)RTM_ADD, RTF_HOST);
 		if (debug && error)
 		{
 			log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d",
@@ -3966,7 +4056,7 @@
 		}
 #endif
 	}
-}
+}

 static int
 sppp_params(struct sppp *sp, u_long cmd, void *data)
@@ -4098,7 +4188,7 @@
 	/* if no NCP is starting, all this was in vain, close down */
 	sppp_lcp_check_and_close(sp);
 }
-
+

 static const char *
 sppp_cp_type_name(u_char type)
@@ -4271,4 +4361,500 @@
 sppp_null(struct sppp *unused)
 {
 	/* do just nothing */
+}
+
+/*
+ * Frame Relay link level subroutines.
+ * ANSI T1.617-compatible link management signaling implemented.
+ * Only one DLCI per channel for now.
+ * Copyright (C) 1994-1999 Cronyx Engineering Ltd.
+ * Author: Serge Vakulenko, <vak@cronyx.ru>
+ */
+static void sppp_fr_input (struct sppp *sp, struct mbuf *m)
+{
+	STDDCL;
+	u_char *h = mtod (m, u_char*);
+	struct ifqueue *inq;
+	int dlci, hlen, proto, s;
+
+	/* Get the DLCI number. */
+	if (m->m_pkthdr.len < 10) {
+bad:            m_freem (m);
+		return;
+	}
+	dlci = (h[0] << 2 & 0x3f0) | (h[1] >> 4 & 0x0f);
+
+	/* Process signaling packets. */
+	if (dlci == 0) {
+		sppp_fr_signal (sp, h, m->m_pkthdr.len);
+		m_freem (m);
+		return;
+	}
+
+	if (dlci != sp->fr_dlci) {
+		if (debug)
+			printf ("%s%d: Received packet from invalid DLCI %d\n",
+				ifp->if_name, ifp->if_unit, dlci);
+		goto bad;
+	}
+
+	/* Process the packet. */
+	if (ntohs (*(short*) (h+2)) == ETHERTYPE_IP)
+		goto proto_ip;          /* cisco framing */
+	if (h[2] != PPP_UI) {
+		if (debug)
+			printf ("%s%d: Invalid frame relay header flag 0x%02x\n",
+				ifp->if_name, ifp->if_unit, h[2]);
+		goto bad;
+	}
+	switch (h[3]) {
+	default:
+		if (debug)
+			printf ("%s%d: Unsupported NLPID 0x%02x\n",
+				ifp->if_name, ifp->if_unit, h[3]);
+		goto bad;
+
+	case FR_PADDING:
+		if (h[4] != FR_SNAP) {
+			if (debug)
+				printf ("%s%d: Bad NLPID 0x%02x\n",
+					ifp->if_name, ifp->if_unit, h[4]);
+			goto bad;
+		}
+		if (h[5] || h[6] || h[7]) {
+			if (debug)
+				printf ("%s%d: Bad OID 0x%02x-0x%02x-0x%02x\n",
+					ifp->if_name, ifp->if_unit,
+					h[5], h[6], h[7]);
+			goto bad;
+		}
+		proto = ntohs (*(short*) (h+8));
+		if (proto == ETHERTYPE_ARP) {
+			/* Process the ARP request. */
+			if (m->m_pkthdr.len != 10 + sizeof (struct arp_req)) {
+				if (debug)
+					printf ("%s%d: Bad ARP request size = %d bytes\n",
+						ifp->if_name, ifp->if_unit,
+						m->m_pkthdr.len);
+				goto bad;
+			}
+			sppp_fr_arp (sp, (struct arp_req*) (h + 10),
+				h[0] << 8 | h[1]);
+			m_freem (m);
+			return;
+		}
+		hlen = 10;
+		break;
+
+	case FR_IP:
+proto_ip:       proto = ETHERTYPE_IP;
+		hlen = 4;
+		break;
+	}
+
+	/* Remove frame relay header. */
+	m_adj (m, hlen);
+
+	switch (proto) {
+	default:
+		++ifp->if_noproto;
+drop:		++ifp->if_ierrors;
+		++ifp->if_iqdrops;
+		m_freem (m);
+		return;
+#ifdef INET
+	case ETHERTYPE_IP:
+		schednetisr (NETISR_IP);
+		inq = &ipintrq;
+		break;
+#endif
+#ifdef IPX
+	case ETHERTYPE_IPX:
+		schednetisr (NETISR_IPX);
+		inq = &ipxintrq;
+		break;
+#endif
+#ifdef NS
+	case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */
+		schednetisr (NETISR_NS);
+		inq = &nsintrq;
+		break;
+#endif
+#ifdef NETATALK
+        case ETHERTYPE_AT:
+		schednetisr (NETISR_ATALK);
+		inq = &atintrq1;
+                break;
+#endif
+	}
+
+	if (! (ifp->if_flags & IFF_UP))
+		goto drop;
+
+	/* Check queue. */
+	s = splimp();
+	if (IF_QFULL (inq)) {
+		/* Queue overflow. */
+		IF_DROP(inq);
+		splx(s);
+		if (debug)
+			log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n",
+				SPP_ARGS(ifp));
+		goto drop;
+	}
+	IF_ENQUEUE(inq, m);
+	splx(s);
+}
+
+/*
+ * Add the frame relay header to the packet.
+ * For IP the header length is 4 bytes,
+ * for all other protocols - 10 bytes (RFC 1490).
+ */
+static struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m,
+	int family)
+{
+	STDDCL;
+	u_char *h;
+	int type, hlen;
+
+	/* Prepend the space for Frame Relay header. */
+	hlen = (family == AF_INET) ? 4 : 10;
+	M_PREPEND (m, hlen, M_DONTWAIT);
+	if (! m)
+		return 0;
+	h = mtod (m, u_char*);
+
+	/* Fill the header. */
+	h[0] = sp->fr_dlci >> 2 & 0xfc;
+	h[1] = sp->fr_dlci << 4 | 1;
+	h[2] = PPP_UI;
+
+	switch (family) {
+	default:
+		if (debug)
+			printf ("%s%d: cannot handle address family %d\n",
+				ifp->if_name, ifp->if_unit, family);
+		m_freem (m);
+		return 0;
+#ifdef INET
+	case AF_INET:
+#if 0 /* Crashes on fragmented packets */
+		/*
+		 * Set the discard eligibility bit, if:
+		 * 1) no fragmentation
+		 * 2) length > 400 bytes
+		 * 3a) the protocol is UDP or
+		 * 3b) TCP data (no control bits)
+		 */
+		{
+		struct ip *ip = (struct ip*) (h + hlen);
+		struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
+
+		if (! (ip->ip_off & ~IP_DF) && ip->ip_len > 400 &&
+		    (ip->ip_p == IPPROTO_UDP ||
+		    ip->ip_p == IPPROTO_TCP && ! tcp->th_flags))
+			h[1] |= FR_DE;
+		}
+#endif
+		h[3] = FR_IP;
+		return m;
+#endif
+#ifdef IPX
+	case AF_IPX:
+		type = ETHERTYPE_IPX;
+		break;
+#endif
+#ifdef NS
+	case AF_NS:
+		type = 0x8137;
+		break;
+#endif
+#ifdef NETATALK
+	case AF_APPLETALK:
+		type = ETHERTYPE_AT;
+		break;
+#endif
+	}
+	h[3] = FR_PADDING;
+	h[4] = FR_SNAP;
+	h[5] = 0;
+	h[6] = 0;
+	h[7] = 0;
+	*(short*) (h+8) = htons(type);
+	return m;
+}
+
+/*
+ * Send periodical frame relay link verification messages via DLCI 0.
+ * Called every 10 seconds (default value of T391 timer is 10 sec).
+ * Every 6-th message is a full status request
+ * (default value of N391 counter is 6).
+ */
+static void sppp_fr_keepalive (struct sppp *sp)
+{
+	STDDCL;
+	unsigned char *h, *p;
+	struct mbuf *m;
+
+	MGETHDR (m, M_DONTWAIT, MT_DATA);
+	if (! m)
+		return;
+	m->m_pkthdr.rcvif = 0;
+
+	h = mtod (m, u_char*);
+	p = h;
+	*p++ = 0;                       /* DLCI = 0 */
+	*p++ = 1;
+	*p++ = PPP_UI;
+	*p++ = FR_SIGNALING;            /* NLPID = UNI call control */
+
+	*p++ = 0;                       /* call reference length = 0 */
+	*p++ = FR_MSG_ENQUIRY;          /* message type = status enquiry */
+
+	*p++ = FR_FLD_LSHIFT5;          /* locking shift 5 */
+
+	*p++ = FR_FLD_RTYPE;            /* report type field */
+	*p++ = 1;                       /* report type length = 1 */
+	if (sp->pp_seq % 6)
+		*p++ = FR_RTYPE_SHORT;  /* link verification only */
+	else
+		*p++ = FR_RTYPE_FULL;   /* full status needed */
+
+	*p++ = FR_FLD_VERIFY;           /* link verification type field */
+	*p++ = 2;                       /* link verification field length = 2 */
+	*p++ = ++sp->pp_seq;            /* our sequence number */
+	*p++ = sp->pp_rseq;             /* last received sequence number */
+
+	m->m_pkthdr.len = m->m_len = p - h;
+	if (debug)
+		printf ("%s%d: send lmi packet, seq=%d, rseq=%d\n",
+			ifp->if_name, ifp->if_unit, (u_char) sp->pp_seq,
+			(u_char) sp->pp_rseq);
+
+	if (IF_QFULL (&sp->pp_fastq)) {
+		IF_DROP (&ifp->if_snd);
+		m_freem (m);
+	} else
+		IF_ENQUEUE (&sp->pp_fastq, m);
+	if (! (ifp->if_flags & IFF_OACTIVE))
+		(*ifp->if_start) (ifp);
+	ifp->if_obytes += m->m_pkthdr.len + 3;
+}
+
+/*
+ * Process the frame relay Inverse ARP request.
+ */
+static void sppp_fr_arp (struct sppp *sp, struct arp_req *req,
+	u_short his_hardware_address)
+{
+	STDDCL;
+	struct mbuf *m;
+	struct arp_req *reply;
+	u_char *h;
+	u_short my_hardware_address;
+	u_long his_ip_address, my_ip_address;
+
+	if ((ntohs (req->htype) != ARPHRD_FRELAY ||
+	    ntohs (req->htype) != 16) || /* for BayNetworks routers */
+	    ntohs (req->ptype) != ETHERTYPE_IP) {
+		if (debug)
+			printf ("%s%d: Invalid ARP hardware/protocol type = 0x%x/0x%x\n",
+				ifp->if_name, ifp->if_unit,
+				ntohs (req->htype), ntohs (req->ptype));
+		return;
+	}
+	if (req->halen != 2 || req->palen != 4) {
+		if (debug)
+			printf ("%s%d: Invalid ARP hardware/protocol address length = %d/%d\n",
+				ifp->if_name, ifp->if_unit,
+				req->halen, req->palen);
+		return;
+	}
+	switch (ntohs (req->op)) {
+	default:
+		if (debug)
+			printf ("%s%d: Invalid ARP op = 0x%x\n",
+				ifp->if_name, ifp->if_unit, ntohs (req->op));
+		return;
+
+	case ARPOP_INVREPLY:
+		/* Ignore. */
+		return;
+
+	case ARPOP_INVREQUEST:
+		sppp_get_ip_addrs (sp, &my_ip_address, 0, 0);
+		if (! my_ip_address)
+			return;         /* nothing to reply */
+		my_hardware_address = ntohs (req->htarget);
+		his_ip_address = ntohs (req->psource1) << 16 |
+			ntohs (req->psource2);
+		my_ip_address = ntohs (req->ptarget1) << 16 |
+			ntohs (req->ptarget2);
+		break;
+	}
+	if (debug) {
+		printf ("%s%d: got ARP request, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
+			ifp->if_name, ifp->if_unit, ntohs (req->hsource),
+			(unsigned char) (his_ip_address >> 24),
+			(unsigned char) (his_ip_address >> 16),
+			(unsigned char) (his_ip_address >> 8),
+			(unsigned char) his_ip_address,
+			my_hardware_address,
+			(unsigned char) (my_ip_address >> 24),
+			(unsigned char) (my_ip_address >> 16),
+			(unsigned char) (my_ip_address >> 8),
+			(unsigned char) my_ip_address);
+		printf ("%s%d: send ARP reply, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
+			ifp->if_name, ifp->if_unit, my_hardware_address,
+			(unsigned char) (my_ip_address >> 24),
+			(unsigned char) (my_ip_address >> 16),
+			(unsigned char) (my_ip_address >> 8),
+			(unsigned char) my_ip_address,
+			his_hardware_address,
+			(unsigned char) (his_ip_address >> 24),
+			(unsigned char) (his_ip_address >> 16),
+			(unsigned char) (his_ip_address >> 8),
+			(unsigned char) his_ip_address);
+	}
+
+	/* Send the Inverse ARP reply. */
+	MGETHDR (m, M_DONTWAIT, MT_DATA);
+	if (! m)
+		return;
+	m->m_pkthdr.len = m->m_len = 10 + sizeof (*reply);
+	m->m_pkthdr.rcvif = 0;
+
+	h = mtod (m, u_char*);
+	reply = (struct arp_req*) (h + 10);
+
+	h[0] = his_hardware_address >> 8;
+	h[1] = his_hardware_address;
+	h[2] = PPP_UI;
+	h[3] = FR_PADDING;
+	h[4] = FR_SNAP;
+	h[5] = 0;
+	h[6] = 0;
+	h[7] = 0;
+	*(short*) (h+8) = htons (ETHERTYPE_ARP);
+
+	reply->htype    = htons (ARPHRD_FRELAY);
+	reply->ptype    = htons (ETHERTYPE_IP);
+	reply->halen    = 2;
+	reply->palen    = 4;
+	reply->op       = htons (ARPOP_INVREPLY);
+	reply->hsource  = htons (my_hardware_address);
+	reply->psource1 = htonl (my_ip_address);
+	reply->psource2 = htonl (my_ip_address) >> 16;
+	reply->htarget  = htons (his_hardware_address);
+	reply->ptarget1 = htonl (his_ip_address);
+	reply->ptarget2 = htonl (his_ip_address) >> 16;
+
+	if (IF_QFULL (&sp->pp_fastq)) {
+		IF_DROP (&ifp->if_snd);
+		m_freem (m);
+	} else
+		IF_ENQUEUE (&sp->pp_fastq, m);
+	if (! (ifp->if_flags & IFF_OACTIVE))
+		(*ifp->if_start) (ifp);
+	ifp->if_obytes += m->m_pkthdr.len + 3;
+}
+
+/*
+ * Process the input signaling packet (DLCI 0).
+ * The implemented protocol is ANSI T1.617 Annex D.
+ */
+static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len)
+{
+	STDDCL;
+	u_char *p;
+	int dlci;
+
+	if (h[2] != PPP_UI || h[3] != FR_SIGNALING || h[4] != 0) {
+		if (debug)
+			printf ("%s%d: Invalid signaling header\n",
+				ifp->if_name, ifp->if_unit);
+bad:            if (debug) {
+			printf ("%02x", *h++);
+			while (--len > 0)
+				printf ("-%02x", *h++);
+			printf ("\n");
+		}
+		return;
+	}
+	if (h[5] == FR_MSG_ENQUIRY) {
+		if (len == FR_ENQUIRY_SIZE &&
+		    h[12] == (u_char) sp->pp_seq) {
+			sp->pp_seq = random();
+			printf ("%s%d: loopback detected\n",
+				ifp->if_name, ifp->if_unit);
+		}
+		return;
+	}
+	if (h[5] != FR_MSG_STATUS) {
+		if (debug)
+			printf ("%s%d: Unknown signaling message: 0x%02x\n",
+				ifp->if_name, ifp->if_unit, h[5]);
+		goto bad;
+	}
+
+	/* Parse message fields. */
+	for (p=h+6; p<h+len; ) {
+		switch (*p) {
+		default:
+			if (debug)
+				printf ("%s%d: Unknown signaling field 0x%x\n",
+					ifp->if_name, ifp->if_unit, *p);
+			break;
+		case FR_FLD_LSHIFT5:
+		case FR_FLD_RTYPE:
+			/* Ignore. */
+			break;
+		case FR_FLD_VERIFY:
+			if (p[1] != 2) {
+				if (debug)
+					printf ("%s%d: Invalid signaling verify field length %d\n",
+						ifp->if_name, ifp->if_unit, p[1]);
+				break;
+			}
+			sp->pp_rseq = p[2];
+			if (debug) {
+				printf ("%s%d: got lmi reply rseq=%d, seq=%d",
+					ifp->if_name, ifp->if_unit, p[2], p[3]);
+				if (p[3] != (u_char) sp->pp_seq)
+					printf (" (really %d)",
+						(u_char) sp->pp_seq);
+				printf ("\n");
+			}
+			break;
+		case FR_FLD_PVC:
+			if (p[1] < 3) {
+				if (debug)
+					printf ("%s%d: Invalid PVC status length %d\n",
+						ifp->if_name, ifp->if_unit, p[1]);
+				break;
+			}
+			dlci = (p[2] << 4 & 0x3f0) | (p[3] >> 3 & 0x0f);
+			if (! sp->fr_dlci)
+				sp->fr_dlci = dlci;
+			if (sp->fr_status != p[4])
+				printf ("%s%d: DLCI %d %s%s\n",
+					ifp->if_name, ifp->if_unit, dlci,
+					p[4] & FR_DLCI_DELETE ? "deleted" :
+					p[4] & FR_DLCI_ACTIVE ? "active" : "passive",
+					p[4] & FR_DLCI_NEW ? ", new" : "");
+			sp->fr_status = p[4];
+			break;
+		}
+		if (*p & 0x80)
+			++p;
+		else if (p < h+len+1 && p[1])
+			p += 2 + p[1];
+		else {
+			if (debug)
+				printf ("%s%d: Invalid signaling field 0x%x\n",
+					ifp->if_name, ifp->if_unit, *p);
+			goto bad;
+		}
+	}
 }

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199911121602.TAA00364>