Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Jul 2001 14:54:23 +0400
From:      Kurakin Roman <rik@cronyx.ru>
To:        Serge Vakulenko <vak@cronyx.ru>, mike@FreeBSD.org, freebsd-bugs@FreeBSD.org
Subject:   Re: kern/14848: Frame Relay support, corrected
Message-ID:  <3B5C025F.3080101@cronyx.ru>
References:  <000901c1134b$827a69a0$48b5ce90@crox>

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

[-- Attachment #1 --]
Hi,
   Please check kern/21771 for more recent report. Also I attached patch 
that was sent a week
ago to freebsd-net mailing list. (This patch was made relative 4.current 
and it contains last changes)

Best regards,
                       Roman Kurakin




Serge Vakulenko wrote:

> ----- Original Message ----- 
> From: <mike@FreeBSD.org>
> To: <vak@cronyx.ru>; <mike@FreeBSD.org>; <freebsd-bugs@FreeBSD.org>
> Sent: Saturday, July 21, 2001 6:56 AM
> Subject: Re: kern/14848: Frame Relay support, corrected
> 
> 
>> Synopsis: Frame Relay support, corrected
>> 
>> State-Changed-From-To: open->suspended
>> State-Changed-By: mike
>> State-Changed-When: Fri Jul 20 19:54:47 PDT 2001
>> State-Changed-Why: 
>> 
>> With a little bit of work, this could probably be committed.
>> Awaiting committer.
>> 
>> http://www.FreeBSD.org/cgi/query-pr.cgi?pr=14848
>> 


[-- Attachment #2 --]
--- if_spppsubr_c.c	Wed Jul  4 18:59:22 2001
+++ if_spppsubr.c	Fri Jul 13 18:42:16 2001
@@ -1,30 +1,36 @@
 /*
- * 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-2000 Cronyx Engineering Ltd.
  * Author: Serge Vakulenko, <vak@cronyx.ru>
  *
  * Heavily revamped to conform to RFC 1661.
  * Copyright (C) 1997, Joerg Wunsch.
  *
+ * Slightly revamped to conform to real life.
+ * Copyright (C) 1999-2000 Cronyx Engineering Ltd.
+ * Author: Kurakin Roman, <rik@cronyx.ru>
+ *
  * This software is distributed with NO WARRANTIES, not even the implied
  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  *
  * Authors grant any other persons or organisations permission to use
  * or modify this software as long as this message is kept with the software,
  * all derivative works or modified versions.
- *
- * From: Version 2.4, Thu Apr 30 17:17:21 MSD 1997
- *
- * $FreeBSD: src/sys/net/if_spppsubr.c,v 1.59.2.6 2001/07/03 11:01:41 ume Exp $
  */
 
 #include <sys/param.h>
 
 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
 #include "opt_inet.h"
-#include "opt_inet6.h"
+#if __FreeBSD__ >= 420000
+#  include "opt_inet6.h"
+#endif
 #include "opt_ipx.h"
 #endif
 
@@ -43,7 +49,11 @@
 #include <sys/socket.h>
 #include <sys/syslog.h>
 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#if __FreeBSD_version >= 410000
 #include <sys/random.h>
+#else
+#include <machine/random.h>
+#endif
 #endif
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
@@ -222,7 +232,64 @@
 	u_short time0;
 	u_short time1;
 };
-#define CISCO_PACKET_LEN 18
+#define CISCO_PACKET_LEN 14
+
+/*
+ * 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
@@ -294,6 +361,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,
@@ -520,6 +593,11 @@
 		return;
 	}
 
+	if (sp->pp_mode == PP_FR) {
+		sppp_fr_input (sp, m);
+		return;
+	}
+
 	/* Get PPP header. */
 	h = mtod (m, struct ppp_header*);
 	m_adj (m, PPP_HEADER_LEN);
@@ -539,16 +617,16 @@
 		}
 		switch (ntohs (h->protocol)) {
 		default:
+			if (sp->state[IDX_LCP] == STATE_OPENED)
+				sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
+					++sp->pp_seq[IDX_LCP],
+					m->m_pkthdr.len + 2, &h->protocol);
 			if (debug)
 				log(LOG_DEBUG,
-				    SPP_FMT "rejecting protocol "
+				    SPP_FMT "invalid input protocol "
 				    "<addr=0x%x ctrl=0x%x proto=0x%x>\n",
 				    SPP_ARGS(ifp),
 				    h->address, h->control, ntohs(h->protocol));
-			if (sp->state[IDX_LCP] == STATE_OPENED)
-				sppp_cp_send (sp, PPP_LCP, PROTO_REJ,
-					++sp->pp_seq[IDX_LCP], m->m_pkthdr.len + 2,
-					&h->protocol);
 			++ifp->if_noproto;
 			goto drop;
 		case PPP_LCP:
@@ -767,18 +845,25 @@
 	}
 #endif
 
+	if (sp->pp_mode == PP_FR) {
+		/* Add frame relay header. */
+		m = sppp_fr_header (sp, m, dst->sa_family);
+		if (! m)
+			goto nobufs;
+		goto out;
 #ifdef INET6
 	if (dst->sa_family == AF_INET6) {
 		/* XXX do something tricky here? */
 	}
 #endif
+	}
 
 	/*
 	 * 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;
@@ -863,7 +948,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;
@@ -904,9 +989,9 @@
 #if 0
 	sp->pp_flags = PP_KEEPALIVE;
 #endif
- 	sp->pp_if.if_snd.ifq_maxlen = 32;
- 	sp->pp_fastq.ifq_maxlen = 32;
- 	sp->pp_cpq.ifq_maxlen = 20;
+ 	sp->pp_if.if_snd.ifq_maxlen = 50;
+ 	sp->pp_fastq.ifq_maxlen = 50;
+ 	sp->pp_cpq.ifq_maxlen = 50;
 	sp->pp_loopcnt = 0;
 	sp->pp_alivecnt = 0;
 	bzero(&sp->pp_seq[0], sizeof(sp->pp_seq));
@@ -992,7 +1077,8 @@
 	 */
 	IF_DEQUEUE(&sp->pp_cpq, m);
 	if (m == NULL &&
-	    (sppp_ncp_check(sp) || sp->pp_mode == IFF_CISCO)) {
+	    (sppp_ncp_check(sp) || sp->pp_mode == IFF_CISCO ||
+	     sp->pp_mode == PP_FR)) {
 		IF_DEQUEUE(&sp->pp_fastq, m);
 		if (m == NULL)
 			IF_DEQUEUE (&sp->pp_if.if_snd, m);
@@ -1015,7 +1101,9 @@
 
 	m = sp->pp_cpq.ifq_head;
 	if (m == NULL &&
-	    (sp->pp_phase == PHASE_NETWORK || sp->pp_mode == IFF_CISCO))
+	    (sp->pp_phase == PHASE_NETWORK ||
+	     sp->pp_mode == IFF_CISCO ||
+	     sp->pp_mode == PP_FR))
 		if ((m = sp->pp_fastq.ifq_head) == NULL)
 			m = sp->pp_if.if_snd.ifq_head;
 	splx (s);
@@ -1054,9 +1142,13 @@
 			newmode = ifp->if_flags & IFF_AUTO;
 		if (!newmode)
 			newmode = ifp->if_flags & IFF_CISCO;
+
 		ifp->if_flags &= ~(IFF_PASSIVE | IFF_AUTO | IFF_CISCO);
 		ifp->if_flags |= newmode;
 
+		if (!newmode)
+			newmode = sp->pp_flags & PP_FR;
+
 		if (newmode != sp->pp_mode) {
 			going_down = 1;
 			if (!going_up)
@@ -1064,26 +1156,30 @@
 		}
 
 		if (going_down) {
-			if (sp->pp_mode != IFF_CISCO)
+			if (sp->pp_mode != IFF_CISCO &&
+			    sp->pp_mode != PP_FR)
 				lcp.Close(sp);
-			else if (sp->pp_tlf)
-				(sp->pp_tlf)(sp);
+/*			else if (sp->pp_tlf)
+				(sp->pp_tlf)(sp);*/
+			
 			sppp_flush(ifp);
 			ifp->if_flags &= ~IFF_RUNNING;
 			sp->pp_mode = newmode;
 		}
 
 		if (going_up) {
-			if (sp->pp_mode != IFF_CISCO)
+			if (sp->pp_mode != IFF_CISCO &&
+			    sp->pp_mode != PP_FR)
 				lcp.Close(sp);
 			sp->pp_mode = newmode;
 			if (sp->pp_mode == 0) {
 				ifp->if_flags |= IFF_RUNNING;
 				lcp.Open(sp);
 			}
-			if (sp->pp_mode == IFF_CISCO) {
-				if (sp->pp_tls)
-					(sp->pp_tls)(sp);
+			if ((sp->pp_mode == IFF_CISCO) ||
+			    (sp->pp_mode == PP_FR)) {
+/*				if (sp->pp_tls)
+					(sp->pp_tls)(sp);*/
 				ifp->if_flags |= IFF_RUNNING;
 			}
 		}
@@ -1133,6 +1229,7 @@
 	return rv;
 }
 
+
 /*
  * Cisco framing implementation.
  */
@@ -1390,16 +1487,6 @@
 			/* fall through... */
 		case STATE_ACK_SENT:
 		case STATE_REQ_SENT:
-			/*
-			 * sppp_cp_change_state() have the side effect of
-			 * restarting the timeouts. We want to avoid that
-			 * if the state don't change, otherwise we won't
-			 * ever timeout and resend a configuration request
-			 * that got lost.
-			 */
-			if (sp->state[cp->protoidx] == (rv ? STATE_ACK_SENT:
-			    STATE_REQ_SENT))
-				break;
 			sppp_cp_change_state(cp, sp, rv?
 					     STATE_ACK_SENT: STATE_REQ_SENT);
 			break;
@@ -1492,17 +1579,11 @@
 		case STATE_STOPPED:
 			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
 			break;
-		case STATE_REQ_SENT:
 		case STATE_ACK_SENT:
-			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
-			/*
-			 * Slow things down a bit if we think we might be
-			 * in loopback. Depend on the timeout to send the
-			 * next configuration request.
-			 */
-			if (sp->pp_loopcnt)
-				break;
 			(cp->scr)(sp);
+/*			sppp_cp_change_state (cp, sp, STATE_REQ_SENT);*/
+		case STATE_REQ_SENT:
+			sp->rst_counter[cp->protoidx] = sp->lcp.max_configure;
 			break;
 		case STATE_OPENED:
 			(cp->tld)(sp);
@@ -1534,7 +1615,6 @@
 		case STATE_CLOSING:
 		case STATE_STOPPING:
 		case STATE_REQ_SENT:
-		  sta:
 			/* Send Terminate-Ack packet. */
 			if (debug)
 				log(LOG_DEBUG, SPP_FMT "%s send terminate-ack\n",
@@ -1545,7 +1625,11 @@
 			(cp->tld)(sp);
 			sp->rst_counter[cp->protoidx] = 0;
 			sppp_cp_change_state(cp, sp, STATE_STOPPING);
-			goto sta;
+			/* Send Terminate-Ack packet. */
+			if (debug)
+				log(LOG_DEBUG, SPP_FMT "%s send terminate-ack\n",
+				    SPP_ARGS(ifp), cp->name);
+			sppp_cp_send(sp, cp->proto, TERM_ACK, h->ident, 0, 0);
 			break;
 		default:
 			printf(SPP_FMT "%s illegal %s in state %s\n",
@@ -1563,12 +1647,12 @@
 		case STATE_ACK_SENT:
 			break;
 		case STATE_CLOSING:
-			sppp_cp_change_state(cp, sp, STATE_CLOSED);
 			(cp->tlf)(sp);
+			sppp_cp_change_state(cp, sp, STATE_CLOSED);
 			break;
 		case STATE_STOPPING:
-			sppp_cp_change_state(cp, sp, STATE_STOPPED);
 			(cp->tlf)(sp);
+			sppp_cp_change_state(cp, sp, STATE_STOPPED);
 			break;
 		case STATE_ACK_RCVD:
 			sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
@@ -1640,14 +1724,9 @@
 		    ntohl (*(long*)(h+1)) == sp->lcp.magic) {
 			/* Line loopback mode detected. */
 			printf(SPP_FMT "loopback\n", SPP_ARGS(ifp));
-			sp->pp_loopcnt = MAXALIVECNT * 5;
-			if_down (ifp);
-			sppp_qflush (&sp->pp_cpq);
-
 			/* Shut down the PPP link. */
-			/* XXX */
-			lcp.Down(sp);
-			lcp.Up(sp);
+			lcp.Close(sp);
+			lcp.Open(sp);
 			break;
 		}
 		*(long*)(h+1) = htonl (sp->lcp.magic);
@@ -1780,28 +1859,21 @@
 		sppp_cp_change_state(cp, sp, STATE_REQ_SENT);
 		break;
 	case STATE_STOPPED:
-		/*
-		 * Try escaping stopped state.  This seems to bite
-		 * people occasionally, in particular for IPCP,
-		 * presumably following previous IPCP negotiation
-		 * aborts.  Somehow, we must have missed a Down event
-		 * which would have caused a transition into starting
-		 * state, so as a bandaid we force the Down event now.
-		 * This effectively implements (something like the)
-		 * `restart' option mentioned in the state transition
-		 * table of RFC 1661.
-		 */
-		sppp_cp_change_state(cp, sp, STATE_STARTING);
-		(cp->tls)(sp);
-		break;
 	case STATE_STOPPING:
+	case STATE_OPENED:
+	/* As said in Implementation Option */
+		cp->Down(sp);
+		cp->Up(sp);
+		break;
 	case STATE_REQ_SENT:
 	case STATE_ACK_RCVD:
 	case STATE_ACK_SENT:
-	case STATE_OPENED:
 		break;
 	case STATE_CLOSING:
+	/* As said in Implementation Option */
 		sppp_cp_change_state(cp, sp, STATE_STOPPING);
+		cp->Down(sp);
+		cp->Up(sp);
 		break;
 	}
 }
@@ -1823,8 +1895,8 @@
 	case STATE_CLOSING:
 		break;
 	case STATE_STARTING:
-		sppp_cp_change_state(cp, sp, STATE_INITIAL);
 		(cp->tlf)(sp);
+		sppp_cp_change_state(cp, sp, STATE_INITIAL);
 		break;
 	case STATE_STOPPED:
 		sppp_cp_change_state(cp, sp, STATE_CLOSED);
@@ -1863,18 +1935,18 @@
 		/* TO- event */
 		switch (sp->state[cp->protoidx]) {
 		case STATE_CLOSING:
-			sppp_cp_change_state(cp, sp, STATE_CLOSED);
 			(cp->tlf)(sp);
+			sppp_cp_change_state(cp, sp, STATE_CLOSED);
 			break;
 		case STATE_STOPPING:
-			sppp_cp_change_state(cp, sp, STATE_STOPPED);
 			(cp->tlf)(sp);
+			sppp_cp_change_state(cp, sp, STATE_STOPPED);
 			break;
 		case STATE_REQ_SENT:
 		case STATE_ACK_RCVD:
 		case STATE_ACK_SENT:
-			sppp_cp_change_state(cp, sp, STATE_STOPPED);
 			(cp->tlf)(sp);
+			sppp_cp_change_state(cp, sp, STATE_STOPPED);
 			break;
 		}
 	else
@@ -2008,9 +2080,8 @@
 	 */
 	if ((ifp->if_flags & (IFF_AUTO | IFF_PASSIVE)) == 0) {
 		log(LOG_INFO,
-		    SPP_FMT "Down event, taking interface down.\n",
+		    SPP_FMT "Down event, continuing.\n",
 		    SPP_ARGS(ifp));
-		if_down(ifp);
 	} else {
 		if (debug)
 			log(LOG_DEBUG,
@@ -2085,7 +2156,7 @@
 			if (len >= 6 && p[1] == 6)
 				continue;
 			if (debug)
-				log(-1, "[invalid] ");
+				addlog("[invalid] ");
 			break;
 		case LCP_OPT_ASYNC_MAP:
 			/* Async control character map. */
@@ -2164,12 +2235,11 @@
 			nmagic = (u_long)p[2] << 24 |
 				(u_long)p[3] << 16 | p[4] << 8 | p[5];
 			if (nmagic != sp->lcp.magic) {
-				sp->pp_loopcnt = 0;
 				if (debug)
 					addlog("0x%lx ", nmagic);
 				continue;
 			}
-			if (debug && sp->pp_loopcnt < MAXALIVECNT*5)
+			if (debug)
 				addlog("[glitch] ");
 			++sp->pp_loopcnt;
 			/*
@@ -2234,31 +2304,23 @@
 		rlen += p[1];
 	}
 	if (rlen) {
-		/*
-		 * Local and remote magics equal -- loopback?
-		 */
-		if (sp->pp_loopcnt >= MAXALIVECNT*5) {
-			if (sp->pp_loopcnt == MAXALIVECNT*5)
-				printf (SPP_FMT "loopback\n",
-					SPP_ARGS(ifp));
-			if (ifp->if_flags & IFF_UP) {
-				if_down(ifp);
-				sppp_qflush(&sp->pp_cpq);
-				/* XXX ? */
-				lcp.Down(sp);
-				lcp.Up(sp);
-			}
-		} else if (++sp->fail_counter[IDX_LCP] >= sp->lcp.max_failure) {
-			if (debug)
-				addlog(" max_failure (%d) exceeded, "
-				       "send conf-rej\n",
-				       sp->lcp.max_failure);
-			sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf);
-		} else {
+		if (++sp->fail_counter[IDX_LCP] < sp->lcp.max_failure) {
 			if (debug)
-				addlog(" send conf-nak\n");
+				addlog("send conf-nak\n");
 			sppp_cp_send (sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf);
+			return 0;
 		}
+		if (debug)
+			addlog("max_failure (%d) exceeded, closing\n",
+			       sp->lcp.max_failure);
+		if (sp->pp_loopcnt >= MAXALIVECNT)
+			printf ("%s%d: loopback\n",
+				ifp->if_name, ifp->if_unit);
+		lcp.Close(sp);
+		sp->fail_counter[IDX_LCP] = 0;
+		sp->pp_loopcnt = 0;
+		lcp.Open(sp);
+		return 0;
 	} else {
 		if (debug)
 			addlog(" send conf-ack\n");
@@ -2658,6 +2720,17 @@
 
 	sp->ipcp.flags &= ~(IPCP_HISADDR_SEEN|IPCP_MYADDR_SEEN|IPCP_MYADDR_DYN);
 
+	/* To prevent IPCP lock up in stopped state. */
+	if (sp->state[IDX_IPCP] == STATE_STOPPED)
+		sp->state[IDX_IPCP] = STATE_CLOSED;
+
+	/*
+	 * If no other opend NCP at this momenet, we should indicate
+	 * to LCP our presens.
+	 */
+	if (!sppp_ncp_check (sp))
+		sp->state[IDX_IPCP] = STATE_INITIAL;
+
 	sppp_get_ip_addrs(sp, &myaddr, &hisaddr, 0);
 	/*
 	 * If we don't have his address, this probably means our
@@ -2809,11 +2882,11 @@
 					addlog("%s [not agreed] ",
 						sppp_dotted_quad(desiredaddr));
 
-			}
 			p[2] = hisaddr >> 24;
 			p[3] = hisaddr >> 16;
 			p[4] = hisaddr >> 8;
 			p[5] = hisaddr;
+			}
 			break;
 		}
 		/* Add the option to nak'ed list. */
@@ -2989,6 +3062,8 @@
 	/* we no longer need LCP */
 	sp->lcp.protos &= ~(1 << IDX_IPCP);
 	sppp_lcp_check_and_close(sp);
+	if (!sppp_ncp_check(sp))
+		lcp.Open (sp);
 }
 
 static void
@@ -3396,6 +3471,7 @@
 	free (buf, M_TEMP);
 	return;
 }
+
 static void
 sppp_ipv6cp_tlu(struct sppp *sp)
 {
@@ -3999,8 +4075,7 @@
 		       sp->myauth.name,
 		       0);
 }
-
-/*
+/*
  *--------------------------------------------------------------------------*
  *                                                                          *
  *                        The PAP implementation.                           *
@@ -4432,6 +4507,11 @@
 		    ! (ifp->if_flags & IFF_RUNNING))
 			continue;
 
+		if (sp->pp_mode == PP_FR) {
+			sppp_fr_keepalive (sp);
+			continue;
+		}
+
 		/* No keepalive in PPP mode if LCP not opened yet. */
 		if (sp->pp_mode != IFF_CISCO &&
 		    sp->pp_phase < PHASE_AUTHENTICATE)
@@ -4440,14 +4520,13 @@
 		if (sp->pp_alivecnt == MAXALIVECNT) {
 			/* No keepalive packets got.  Stop the interface. */
 			printf (SPP_FMT "down\n", SPP_ARGS(ifp));
+			if (sp->pp_mode == IFF_CISCO) {
 			if_down (ifp);
 			sppp_qflush (&sp->pp_cpq);
-			if (sp->pp_mode != IFF_CISCO) {
-				/* XXX */
+			} else {
 				/* Shut down the PPP link. */
-				lcp.Down(sp);
-				/* Initiate negotiation. XXX */
-				lcp.Up(sp);
+				lcp.Close(sp);
+				lcp.Open(sp);
 			}
 		}
 		if (sp->pp_alivecnt <= MAXALIVECNT)
@@ -4865,7 +4944,6 @@
 	sppp_lcp_check_and_close(sp);
 }
 
-
 static const char *
 sppp_cp_type_name(u_char type)
 {
@@ -5051,4 +5129,509 @@
 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. */
+	inq = 0;
+	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) {
+                /* Prehistoric IP framing? */
+		h[2] = PPP_UI;
+		h[3] = FR_IP;
+	}
+	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 = 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[IDX_LCP] % 6)
+		*p++ = FR_RTYPE_SHORT;  /* link verification only */
+	else
+		*p++ = FR_RTYPE_FULL;   /* full status needed */
+
+	if (sp->pp_seq[IDX_LCP] >= 255)
+		sp->pp_seq[IDX_LCP] = 0;
+	*p++ = FR_FLD_VERIFY;           /* link verification type field */
+	*p++ = 2;                       /* link verification field length = 2 */
+	*p++ = ++sp->pp_seq[IDX_LCP];   /* our sequence number */
+	*p++ = sp->pp_rseq[IDX_LCP];    /* 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[IDX_LCP],
+			(u_char) sp->pp_rseq[IDX_LCP]);
+
+	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:
+		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);
+
+	sppp_get_ip_addrs (sp, &my_ip_address, 0, 0);
+	if (! my_ip_address)
+		return;         /* nothing to reply */
+
+	if (debug)
+		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[IDX_LCP]) {
+			sp->pp_seq[IDX_LCP] = 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[IDX_LCP] = 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[IDX_LCP])
+					printf (" (really %d)",
+						(u_char) sp->pp_seq[IDX_LCP]);
+				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;
+		}
+	}
 }

[-- Attachment #3 --]
--- if_sppp_c.h	Wed Jul  4 18:59:21 2001
+++ if_sppp.h	Fri Jul 13 17:43:37 2001
@@ -1,8 +1,9 @@
 /*
  * Defines for synchronous PPP/Cisco link level subroutines.
  *
- * Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@cronyx.ru>
+ * Copyright (C) 1994-2001 Cronyx Ltd.
+ * Authors: Serge Vakulenko, <vak@cronyx.ru>
+ *          Roman Kurakin, <rik@cronyx.ru>
  *
  * Heavily revamped to conform to RFC 1661.
  * Copyright (C) 1997, Joerg Wunsch.
@@ -16,7 +17,6 @@
  *
  * From: Version 2.0, Fri Oct  6 20:39:21 MSK 1995
  *
- * $FreeBSD: src/sys/net/if_sppp.h,v 1.16.2.1 2001/07/03 11:01:41 ume Exp $
  */
 
 #ifndef _NET_IF_SPPP_H_
@@ -106,6 +106,8 @@
 	struct sipcp ipv6cp;		/* IPv6CP 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
@@ -139,6 +141,7 @@
 };
 
 #define PP_KEEPALIVE    0x01    /* use keepalive protocol */
+#define PP_FR		0x04	/* use Frame Relay protocol instead of PPP */
 				/* 0x04 was PP_TIMO */
 #define PP_CALLIN	0x08	/* we are being called */
 #define PP_NEEDAUTH	0x10	/* remote requested authentication */
@@ -167,7 +170,8 @@
 	struct sppp defs;
 };
 
-#ifdef _KERNEL
+#if (__FreeBSD_version >= 400000 && defined _KERNEL) \
+	|| (__FreeBSD_version < 400000 && defined KERNEL)
 void sppp_attach (struct ifnet *ifp);
 void sppp_detach (struct ifnet *ifp);
 void sppp_input (struct ifnet *ifp, struct mbuf *m);

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