summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrik <rik@FreeBSD.org>2004-12-28 00:07:57 +0000
committerrik <rik@FreeBSD.org>2004-12-28 00:07:57 +0000
commit43775c98bdbe446ff68bfc14cd23d9f53625b95e (patch)
tree7433bf1374127facc9c84e9711fd78a06a4b0727
parent4eebca2138d71cf530bfe31fb0500b951dd9a7ea (diff)
downloadFreeBSD-src-43775c98bdbe446ff68bfc14cd23d9f53625b95e.zip
FreeBSD-src-43775c98bdbe446ff68bfc14cd23d9f53625b95e.tar.gz
Add FR support to sppp (MFCronyx).
Silence on: net@, current@, hackers@. No objections: joerg Requested by: by many (mostly Cronyx) users for a long long time. MFC after: 10 days PR: kern/21771, kern/66348
-rw-r--r--sys/conf/files2
-rw-r--r--sys/modules/sppp/Makefile2
-rw-r--r--sys/net/if_sppp.h15
-rw-r--r--sys/net/if_spppfr.c634
-rw-r--r--sys/net/if_spppsubr.c50
5 files changed, 688 insertions, 15 deletions
diff --git a/sys/conf/files b/sys/conf/files
index b8c7587..f651f1e 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1251,6 +1251,8 @@ net/if_media.c standard
net/if_mib.c standard
net/if_ppp.c optional ppp
net/if_sl.c optional sl
+net/if_spppfr.c optional sppp
+net/if_spppfr.c optional i4bisppp
net/if_spppsubr.c optional sppp
net/if_spppsubr.c optional i4bisppp
net/if_stf.c optional stf
diff --git a/sys/modules/sppp/Makefile b/sys/modules/sppp/Makefile
index 7353089..030f843 100644
--- a/sys/modules/sppp/Makefile
+++ b/sys/modules/sppp/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../net
KMOD= sppp
-SRCS= if_spppsubr.c slcompress.c
+SRCS= if_spppfr.c if_spppsubr.c slcompress.c
SRCS+= opt_inet.h opt_inet6.h opt_ipx.h
EXPORT_SYMS= sppp_attach \
diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h
index d253ee7..4149663 100644
--- a/sys/net/if_sppp.h
+++ b/sys/net/if_sppp.h
@@ -1,7 +1,7 @@
/*
- * Defines for synchronous PPP/Cisco link level subroutines.
+ * Defines for synchronous PPP/Cisco/Frame Relay link level subroutines.
*
- * Copyright (C) 1994 Cronyx Ltd.
+ * Copyright (C) 1994-2000 Cronyx Engineering.
* Author: Serge Vakulenko, <vak@cronyx.ru>
*
* Heavily revamped to conform to RFC 1661.
@@ -165,6 +165,8 @@ struct sppp {
struct sauth myauth; /* auth params, i'm peer */
struct sauth hisauth; /* auth params, i'm authenticator */
struct slcompress *pp_comp; /* for VJ compression */
+ 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
@@ -204,6 +206,7 @@ struct sppp {
/* bits for pp_flags */
#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 */
@@ -216,6 +219,14 @@ struct mbuf *sppp_dequeue (struct ifnet *ifp);
struct mbuf *sppp_pick(struct ifnet *ifp);
int sppp_isempty (struct ifnet *ifp);
void sppp_flush (struct ifnet *ifp);
+
+/* Internal functions */
+void sppp_fr_input (struct sppp *sp, struct mbuf *m);
+struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m, int fam);
+void sppp_fr_keepalive (struct sppp *sp);
+void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst,
+ u_long *srcmask);
+
#endif
#endif /* _NET_IF_SPPP_H_ */
diff --git a/sys/net/if_spppfr.c b/sys/net/if_spppfr.c
new file mode 100644
index 0000000..0cd9fcb
--- /dev/null
+++ b/sys/net/if_spppfr.c
@@ -0,0 +1,634 @@
+/*
+ * Synchronous Frame Relay link level subroutines.
+ * 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-2000 Cronyx Engineering.
+ * Author: Serge Vakulenko, <vak@cronyx.ru>
+ *
+ * Copyright (C) 1999-2004 Cronyx Engineering.
+ * 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 a permission to use,
+ * modify and redistribute this software in source and binary forms,
+ * as long as this message is kept with the software, all derivative
+ * works or modified versions.
+ *
+ * $Cronyx Id: if_spppfr.c,v 1.1.2.10 2004/06/29 09:02:30 rik Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_ipx.h"
+#endif
+
+#ifdef NetBSD1_3
+# if NetBSD1_3 > 6
+# include "opt_inet.h"
+# include "opt_inet6.h"
+# include "opt_iso.h"
+# endif
+#endif
+
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/random.h>
+#endif
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+
+#if defined (__OpenBSD__)
+#include <sys/md5k.h>
+#else
+#include <sys/md5.h>
+#endif
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/slcompress.h>
+
+#if defined (__NetBSD__) || defined (__OpenBSD__)
+#include <machine/cpu.h> /* XXX for softnet */
+#endif
+
+#include <machine/stdarg.h>
+
+#include <netinet/in_var.h>
+#ifdef INET
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#endif
+
+#if defined (__FreeBSD__) || defined (__OpenBSD__)
+# include <netinet/if_ether.h>
+#else
+# include <net/ethertypes.h>
+#endif
+
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
+#include <net/if_sppp.h>
+
+/*
+ * Frame Relay.
+ */
+#define FR_UI 0x03 /* Unnumbered Information */
+#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;
+} __packed;
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3 && __FreeBSD_version < 501113
+#define SPP_FMT "%s%d: "
+#define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit
+#else
+#define SPP_FMT "%s: "
+#define SPP_ARGS(ifp) (ifp)->if_xname
+#endif
+
+/* almost every function needs these */
+#define STDDCL \
+ struct ifnet *ifp = &sp->pp_if; \
+ int debug = ifp->if_flags & IFF_DEBUG
+
+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);
+
+void sppp_fr_input (struct sppp *sp, struct mbuf *m)
+{
+ STDDCL;
+ u_char *h = mtod (m, u_char*);
+ int isr = -1;
+ int dlci, hlen, proto;
+
+ /* 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 (SPP_FMT "Received packet from invalid DLCI %d\n",
+ SPP_ARGS(ifp), dlci);
+ goto bad;
+ }
+
+ /* Process the packet. */
+ if (ntohs (*(short*) (h+2)) == ETHERTYPE_IP) {
+ /* Prehistoric IP framing? */
+ h[2] = FR_UI;
+ h[3] = FR_IP;
+ }
+ if (h[2] != FR_UI) {
+ if (debug)
+ printf (SPP_FMT "Invalid frame relay header flag 0x%02x\n",
+ SPP_ARGS(ifp), h[2]);
+ goto bad;
+ }
+ switch (h[3]) {
+ default:
+ if (debug)
+ printf (SPP_FMT "Unsupported NLPID 0x%02x\n",
+ SPP_ARGS(ifp), h[3]);
+ goto bad;
+
+ case FR_PADDING:
+ if (h[4] != FR_SNAP) {
+ if (debug)
+ printf (SPP_FMT "Bad NLPID 0x%02x\n",
+ SPP_ARGS(ifp), h[4]);
+ goto bad;
+ }
+ if (h[5] || h[6] || h[7]) {
+ if (debug)
+ printf (SPP_FMT "Bad OID 0x%02x-0x%02x-0x%02x\n",
+ SPP_ARGS(ifp),
+ 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 (SPP_FMT "Bad ARP request size = %d bytes\n",
+ SPP_ARGS(ifp),
+ 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:
+ isr = NETISR_IP;
+ break;
+#endif
+#ifdef IPX
+ case ETHERTYPE_IPX:
+ isr = NETISR_IPX;
+ break;
+#endif
+#ifdef NETATALK
+ case ETHERTYPE_AT:
+ isr = NETISR_ATALK;
+ break;
+#endif
+ }
+
+ if (! (ifp->if_flags & IFF_UP))
+ goto drop;
+
+ /* Check queue. */
+ if (netisr_queue(isr, m)) { /* (0) on success. */
+ if (debug)
+ log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n",
+ SPP_ARGS(ifp));
+ }
+}
+
+/*
+ * Add the frame relay header to the packet.
+ * For IP the header length is 4 bytes,
+ * for all other protocols - 10 bytes (RFC 1490).
+ */
+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] = FR_UI;
+
+ switch (family) {
+ default:
+ if (debug)
+ printf (SPP_FMT "Cannot handle address family %d\n",
+ SPP_ARGS(ifp), 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).
+ */
+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++ = FR_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 (SPP_FMT "send lmi packet, seq=%d, rseq=%d\n",
+ SPP_ARGS(ifp), (u_char) sp->pp_seq[IDX_LCP],
+ (u_char) sp->pp_rseq[IDX_LCP]);
+
+ if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
+ ++ifp->if_oerrors;
+}
+
+/*
+ * 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 (SPP_FMT "Invalid ARP hardware/protocol type = 0x%x/0x%x\n",
+ SPP_ARGS(ifp),
+ ntohs (req->htype), ntohs (req->ptype));
+ return;
+ }
+ if (req->halen != 2 || req->palen != 4) {
+ if (debug)
+ printf (SPP_FMT "Invalid ARP hardware/protocol address length = %d/%d\n",
+ SPP_ARGS(ifp),
+ req->halen, req->palen);
+ return;
+ }
+ switch (ntohs (req->op)) {
+ default:
+ if (debug)
+ printf (SPP_FMT "Invalid ARP op = 0x%x\n",
+ SPP_ARGS(ifp), 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 (SPP_FMT "got ARP request, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
+ SPP_ARGS(ifp), 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 (SPP_FMT "send ARP reply, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
+ SPP_ARGS(ifp), 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] = FR_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_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
+ ++ifp->if_oerrors;
+}
+
+/*
+ * 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] != FR_UI || h[3] != FR_SIGNALING || h[4] != 0) {
+ if (debug)
+ printf (SPP_FMT "Invalid signaling header\n",
+ SPP_ARGS(ifp));
+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 (SPP_FMT "loopback detected\n",
+ SPP_ARGS(ifp));
+ }
+ return;
+ }
+ if (h[5] != FR_MSG_STATUS) {
+ if (debug)
+ printf (SPP_FMT "Unknown signaling message: 0x%02x\n",
+ SPP_ARGS(ifp), h[5]);
+ goto bad;
+ }
+
+ /* Parse message fields. */
+ for (p=h+6; p<h+len; ) {
+ switch (*p) {
+ default:
+ if (debug)
+ printf (SPP_FMT "Unknown signaling field 0x%x\n",
+ SPP_ARGS(ifp), *p);
+ break;
+ case FR_FLD_LSHIFT5:
+ case FR_FLD_RTYPE:
+ /* Ignore. */
+ break;
+ case FR_FLD_VERIFY:
+ if (p[1] != 2) {
+ if (debug)
+ printf (SPP_FMT "Invalid signaling verify field length %d\n",
+ SPP_ARGS(ifp), p[1]);
+ break;
+ }
+ sp->pp_rseq[IDX_LCP] = p[2];
+ if (debug) {
+ printf (SPP_FMT "got lmi reply rseq=%d, seq=%d",
+ SPP_ARGS(ifp), 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 (SPP_FMT "Invalid PVC status length %d\n",
+ SPP_ARGS(ifp), 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 (SPP_FMT "DLCI %d %s%s\n",
+ SPP_ARGS(ifp), 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 (SPP_FMT "Invalid signaling field 0x%x\n",
+ SPP_ARGS(ifp), *p);
+ goto bad;
+ }
+ }
+}
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index 638f91f..94f9c83 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -1,8 +1,8 @@
/*
- * Synchronous PPP/Cisco link level subroutines.
+ * Synchronous PPP/Cisco/Frame Relay link level subroutines.
* Keepalive protocol implemented in both Cisco and PPP modes.
*
- * Copyright (C) 1994-1996 Cronyx Engineering Ltd.
+ * Copyright (C) 1994-2000 Cronyx Engineering.
* Author: Serge Vakulenko, <vak@cronyx.ru>
*
* Heavily revamped to conform to RFC 1661.
@@ -409,8 +409,6 @@ static const char *sppp_proto_name(u_short proto);
static const char *sppp_state_name(int state);
static int sppp_params(struct sppp *sp, u_long cmd, void *data);
static int sppp_strnlen(u_char *p, int max);
-static void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst,
- u_long *srcmask);
static void sppp_keepalive(void *dummy);
static void sppp_phase_network(struct sppp *sp);
static void sppp_print_bytes(const u_char *p, u_short len);
@@ -551,6 +549,12 @@ sppp_input(struct ifnet *ifp, struct mbuf *m)
return;
}
+ if (sp->pp_mode == PP_FR) {
+ sppp_fr_input (sp, m);
+ SPPP_UNLOCK(sp);
+ return;
+ }
+
/* Get PPP header. */
h = mtod (m, struct ppp_header*);
m_adj (m, PPP_HEADER_LEN);
@@ -887,7 +891,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
/*
* Do IP Header compression
*/
- if (sp->pp_mode != IFF_CISCO &&
+ if (sp->pp_mode != IFF_CISCO && sp->pp_mode != PP_FR &&
(sp->ipcp.flags & IPCP_VJ) && ip->ip_p == IPPROTO_TCP)
switch (sl_compress_tcp(m, ip, sp->pp_comp,
sp->ipcp.compress_cid)) {
@@ -915,12 +919,20 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
}
#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;
+ }
+
/*
* 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;
@@ -1000,6 +1012,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m,
* Queue message on interface, and start output if interface
* not yet active.
*/
+out:
if (ifq != NULL)
error = !(IF_HANDOFF_ADJ(ifq, m, ifp, 3));
else
@@ -1162,7 +1175,8 @@ sppp_dequeue(struct ifnet *ifp)
*/
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);
@@ -1188,7 +1202,8 @@ sppp_pick(struct ifnet *ifp)
m = sp->pp_cpq.ifq_head;
if (m == NULL &&
(sp->pp_phase == PHASE_NETWORK ||
- sp->pp_mode == IFF_CISCO))
+ 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;
SPPP_UNLOCK(sp);
@@ -1233,6 +1248,9 @@ sppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data)
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)
@@ -1240,7 +1258,8 @@ sppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data)
}
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);
@@ -1250,14 +1269,16 @@ sppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, void *data)
}
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_mode == IFF_CISCO) ||
+ (sp->pp_mode == PP_FR)) {
if (sp->pp_tls)
(sp->pp_tls)(sp);
ifp->if_flags |= IFF_RUNNING;
@@ -4769,6 +4790,11 @@ sppp_keepalive(void *dummy)
! (ifp->if_flags & IFF_RUNNING))
goto out;
+ if (sp->pp_mode == PP_FR) {
+ sppp_fr_keepalive (sp);
+ goto out;
+ }
+
/* No keepalive in PPP mode if LCP not opened yet. */
if (sp->pp_mode != IFF_CISCO &&
sp->pp_phase < PHASE_AUTHENTICATE)
@@ -4808,7 +4834,7 @@ out:
/*
* Get both IP addresses.
*/
-static void
+void
sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask)
{
struct ifnet *ifp = &sp->pp_if;
OpenPOWER on IntegriCloud