From vak@crox.cronyx.ru Fri Nov 12 07:59:20 1999
Return-Path: <vak@crox.cronyx.ru>
Received: from crox.cronyx.ru (crox.cronyx.ru [144.206.181.72])
	by hub.freebsd.org (Postfix) with ESMTP id D528714E38
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 12 Nov 1999 07:59:01 -0800 (PST)
	(envelope-from vak@crox.cronyx.ru)
Received: (from vak@localhost)
	by crox.cronyx.ru (8.9.3/8.9.3) id TAA00364;
	Fri, 12 Nov 1999 19:02:06 +0300 (MSK)
	(envelope-from vak)
Message-Id: <199911121602.TAA00364@crox.cronyx.ru>
Date: Fri, 12 Nov 1999 19:02:06 +0300 (MSK)
From: vak@cronyx.ru
Sender: vak@crox.cronyx.ru
To: FreeBSD-gnats-submit@freebsd.org
Subject: Added Frame Relay support
X-Send-Pr-Version: 3.2

>Number:         14843
>Category:       kern
>Synopsis:       Added support of Frame Relay protocol
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Nov 12 08:00:01 PST 1999
>Closed-Date:    Fri Nov 12 11:44:01 PST 1999
>Last-Modified:  Fri Nov 12 11:44:14 PST 1999
>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:

From: Bill Fumerola <billf@chc-chimes.com>
To: vak@cronyx.ru
Cc: FreeBSD-gnats-submit@freebsd.org
Subject: Re: kern/14843: Added Frame Relay support
Date: Fri, 12 Nov 1999 11:02:50 -0500 (EST)

 I am not offering a code review below, just a style review. If you
 hate people who nitpick your style, you might not want to read on.
 However, if you want to contribute code to FreeBSD, we typically follow
 KNF as detailed in style(9).
 
 On with the show..
 
 On Fri, 12 Nov 1999 vak@cronyx.ru wrote:
 
 > @@ -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);
 >  		}
 > -
 > +
 
 Whitespace changes, avoid.
 
 > @@ -1117,7 +1202,7 @@
 >  #if defined(__FreeBSD__) && __FreeBSD__ >= 3
 >  	getmicrouptime(&tv);
 >  #endif
 > -
 > +
 >  	MGETHDR (m, M_DONTWAIT, MT_DATA);
 >  	if (! m)
 >  		return;
 
 Ditto.
 
 > @@ -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]);
 
 Ditto.
 
 > @@ -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,
 
 Ditto.
 
 > @@ -2322,7 +2407,7 @@
 >  	/* notify low-level driver of state change */
 >  	if (sp->pp_chg)
 >  		sp->pp_chg(sp, (int)sp->pp_phase);
 > -
 > +
 
 Ditto. :>
 
 > @@ -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) {
 
 
 And all of the above.
 
 > @@ -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);
 
 
 Here too.
 
 > @@ -3966,7 +4056,7 @@
 >  		}
 >  #endif
 >  	}
 > -}
 > +}
 
 And here.
 
 > 
 >  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)
 
 Here too
 
 > @@ -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)
 
 
 static void
 sppp_fr_input (struct sppp *sp, struct mbuf *m)
 {
 ...
 
 
 This allows for "grep -e '^functionname' foo.c".
 
 > +{
 > +	STDDCL;
 > +	u_char *h = mtod (m, u_char*);
 
 Please initialilize and declare on differnt lines.
 
 > +
 > +/*
 > + * 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)
 
 Same as above.
 
 > +	if (! m)
 > +		return 0;
 
 I didn't mention this before because that was changing an old file, but
 in this file you'll want
 
 if (m == '\0') or at least if (!m)
 
 > +	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;
 
 Default belongs as the bottom.
 
 > +/*
 > + * 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)
 
 Same as above.
 
 > +	MGETHDR (m, M_DONTWAIT, MT_DATA);
 > +	if (! m)
 > +		return;
 
 Same as above.
 
 > +/*
 > + * Process the frame relay Inverse ARP request.
 > + */
 > +static void sppp_fr_arp (struct sppp *sp, struct arp_req *req,
 > +	u_short his_hardware_address)
 
 Same as above.`
 
 > +	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;
 
 Default belongs at the bottom.
 
 > +	case ARPOP_INVREQUEST:
 > +		sppp_get_ip_addrs (sp, &my_ip_address, 0, 0);
 > +		if (! my_ip_address)
 > +			return;         /* nothing to reply */
 
 if (my_ip_address != '\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;
 
 All of those spaces between functionname(and_the, variables)
 needs to be dropped.
 
 Spaces only come after the keywords if, while, for, return and switch
 Everything else uses functionname(variables)
 
 
 Some of the same style snafus are made throughout the file, so I tried
 not to point out every single one of them when they were repeated.
 
 Please read style(9) for the source for most of these comments.
 
 
 -- 
 - bill fumerola - billf@chc-chimes.com - BF1560 - computer horizons corp -
 - ph:(800) 252-2421 - bfumerol@computerhorizons.com - billf@FreeBSD.org  -
 
 
 
 
 

From: "Serge Vakulenko" <vak@cronyx.ru>
To: "Bill Fumerola" <billf@chc-chimes.com>
Cc: <FreeBSD-gnats-submit@freebsd.org>
Subject: Re: kern/14843: Added Frame Relay support
Date: Fri, 12 Nov 1999 20:51:21 +0300

 >I am not offering a code review below, just a style review. If you
 >hate people who nitpick your style, you might not want to read on.
 >However, if you want to contribute code to FreeBSD, we typically follow
 >KNF as detailed in style(9).
 >
 >On with the show..
 >...
 
 Oh, it seems I am somewhat behind the times...
 I will prepare and submit the correct patch.
 
 Thanks,
 Serge
 
 
 
State-Changed-From-To: open->closed  
State-Changed-By: cpiazza 
State-Changed-When: Fri Nov 12 11:44:01 PST 1999 
State-Changed-Why:  
Superseded by PR 14848 
>Unformatted:
