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>
