Ethernet Bridge development
 help / color / mirror / Atom feed
* [Bridge] (no subject)
@ 2004-02-25 14:30 Dan Eble
  2004-02-25 16:27 ` Stephen Hemminger
  0 siblings, 1 reply; 12+ messages in thread
From: Dan Eble @ 2004-02-25 14:30 UTC (permalink / raw)
  To: bridge; +Cc: john.wise

[-- Attachment #1: Type: TEXT/PLAIN, Size: 695 bytes --]

Attached is the BCP patch for pppd 2.4.1.  In addition to BCP, there are
also a few changes to support a pppd plugin for devices using the kernel
generic HDLC layer.  The plugin itself is not included in this patch.

There were some changes to log messages that I tried to remove by hand.  
The patch applies cleanly and compiles on 686.  It has never been tested
on 686, though, only on powerpc.  I would appreciate hearing about any
difficulties you encounter.

You must patch the kernel too.  I will send those changes in a separate
mail.

-- 
Dan Eble <dane@aiinet.com>  _____  .
Software Engineer          |  _  |/|
Applied Innovation Inc.    | |_| | |
http://www.aiinet.com/     |__/|_|_|

[-- Attachment #2: Type: TEXT/PLAIN, Size: 71837 bytes --]

diff -wbBurN pppd-2.4.1/include/linux/ppp_defs.h pppd-ai/include/linux/ppp_defs.h
--- pppd-2.4.1/include/linux/ppp_defs.h	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/include/linux/ppp_defs.h	2004-02-25 08:34:47.000000000 -0500
@@ -70,13 +70,16 @@
 #define PPP_IPX		0x2b	/* IPX protocol */
 #define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
 #define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_BRIDGE	0x31	/* Bridged LAN traffic or BPDU */
 #define PPP_MP		0x3d	/* Multilink protocol */
 #define PPP_IPV6	0x57	/* Internet Protocol Version 6 */
 #define PPP_COMPFRAG	0xfb	/* fragment compressed below bundle */
 #define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_BPDU_IEEE	0x0201	/* IEEE 802.1 (D or G) bridge PDU */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
 #define PPP_IPXCP	0x802b	/* IPX Control Protocol */
+#define PPP_BCP		0x8031	/* Bridging Control Protocol */
 #define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
 #define PPP_CCPFRAG	0x80fb	/* CCP at link level (below MP bundle) */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
diff -wbBurN pppd-2.4.1/include/net/ppp_defs.h pppd-ai/include/net/ppp_defs.h
--- pppd-2.4.1/include/net/ppp_defs.h	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/include/net/ppp_defs.h	2004-02-25 08:34:47.000000000 -0500
@@ -72,11 +72,14 @@
 #define PPP_IPX		0x2b	/* IPX protocol */
 #define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
 #define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_BRIDGE	0x31	/* Bridged LAN traffic or BPDU */
 #define PPP_IPV6	0x57	/* Internet Protocol Version 6 */
 #define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_BPDU_IEEE	0x0201	/* IEEE 802.1 (D or G) bridge PDU */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
 #define PPP_IPXCP	0x802b	/* IPX Control Protocol */
+#define PPP_BCP		0x8031	/* Bridging Control Protocol */
 #define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
 #define PPP_LCP		0xc021	/* Link Control Protocol */
diff -wbBurN pppd-2.4.1/pppd/auth.c pppd-ai/pppd/auth.c
--- pppd-2.4.1/pppd/auth.c	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/auth.c	2004-02-25 08:34:47.000000000 -0500
@@ -103,9 +103,31 @@
 /* Extra options to apply, from the secrets file entry for the peer. */
 static struct wordlist *extra_options;
 
+/* Bits 0, 8, 14, and 15 are the same in all network protocol numbers, so
+ * remove them to save space in np_running[][]. */
+#define NP_BRIEF(np) ((int)((((np) & 0x3E00) >> 2) | (((np) & 0x00FE) >> 1)))
+#define NP_ARRAY_BYTE(np)	(NP_BRIEF(np) / 8)
+#define NP_ARRAY_BIT(np)	((unsigned char)(1 << (NP_BRIEF(np) % 8)))
+
+/* Flags for running protocols.  One bit per protocol per PPP unit. */
+static unsigned char np_running[NP_ARRAY_BYTE(0xBEFF)+1][NUM_PPP];
+
 /* Number of network protocols which we have opened. */
 static int num_np_open;
 
+#define NP_RUNNING(unit, np) \
+    (np_running[unit][NP_ARRAY_BYTE(np)] & NP_ARRAY_BIT(np))
+
+#define MARK_NP_RUNNING(unit, np) do {	\
+    np_running[unit][NP_ARRAY_BYTE(np)] |= NP_ARRAY_BIT(np);	\
+    ++num_np_open;	\
+    } while (0)
+
+#define MARK_NP_FINISHED(unit, np) do {	\
+    np_running[unit][NP_ARRAY_BYTE(np)] &= ~NP_ARRAY_BIT(np);	\
+    --num_np_open;	\
+    } while (0)
+
 /* Number of network protocols which have come up. */
 static int num_np_up;
 
@@ -421,6 +443,8 @@
         if (protp->protocol < 0xC000 && protp->close != NULL)
 	    (*protp->close)(unit, "LCP down");
     }
+
+    memset(np_running, 0, sizeof(np_running));
     num_np_open = 0;
     num_np_up = 0;
     if (phase != PHASE_DEAD)
@@ -565,7 +589,7 @@
 	    && protp->open != NULL) {
 	    (*protp->open)(0);
 	    if (protp->protocol != PPP_CCP)
-		++num_np_open;
+                MARK_NP_RUNNING(0, protp->protocol);
 	}
 
     if (num_np_open == 0)
@@ -732,17 +756,32 @@
 }
 
 /*
+ * np_start - a network protocol is starting to use the link.
+ */
+void
+np_start(unit, proto)
+    int unit, proto;
+{
+    if (!NP_RUNNING(unit, proto))
+        MARK_NP_RUNNING(unit, proto);
+}
+
+/*
  * np_finished - a network protocol has finished using the link.
  */
 void
 np_finished(unit, proto)
     int unit, proto;
 {
-    if (--num_np_open <= 0) {
+    if (NP_RUNNING(unit, proto)) {
+        MARK_NP_FINISHED(unit, proto);
+
+        if (num_np_open <= 0) {
 	/* no further use for the link: shut up shop. */
 	lcp_close(0, "No network protocols running");
     }
 }
+}
 
 /*
  * check_idle - check whether the link has been idle for long
diff -wbBurN pppd-2.4.1/pppd/bcp.c pppd-ai/pppd/bcp.c
--- pppd-2.4.1/pppd/bcp.c	1969-12-31 19:00:00.000000000 -0500
+++ pppd-ai/pppd/bcp.c	2004-02-25 08:34:47.000000000 -0500
@@ -0,0 +1,1743 @@
+/*
+ * bcp.c - PPP Bridge Control Protocol.
+ *
+ * Copyright (c) 2001-2004 Applied Innovation Inc.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms.  The name of Applied Innovation Inc.
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "bcp.h"
+#include "pathnames.h"
+
+/* global vars */
+bcp_options bcp_wantoptions[NUM_PPP];	/* Options that we want to request */
+bcp_options bcp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
+bcp_options bcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+bcp_options bcp_hisoptions[NUM_PPP];	/* Options that we ack'd */
+
+/* local vars */
+static int bcp_is_up;			/* have called np_up() */
+
+static bool bcp_maclocal_valid;
+static u_char bcp_maclocal[ETH_ALEN];
+static char bcp_maclocal_str[3*ETH_ALEN]; /* string form of "maclocal" arg */
+
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void bcp_resetci __P((fsm *));	/* Reset our CI */
+static int  bcp_cilen __P((fsm *));	        /* Return length of our CI */
+static void bcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int  bcp_ackci __P((fsm *, u_char *, int));	/* Peer ack'd our CI */
+static int  bcp_nakci __P((fsm *, u_char *, int));	/* Peer nak'd our CI */
+static int  bcp_rejci __P((fsm *, u_char *, int));	/* Peer rej'd our CI */
+static int  bcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void bcp_up __P((fsm *));		/* We're UP */
+static void bcp_down __P((fsm *));		/* We're DOWN */
+static void bcp_start __P((fsm *));	/* Need lower layer */
+static void bcp_finished __P((fsm *));	/* Don't need lower layer */
+
+fsm bcp_fsm[NUM_PPP];		/* BCP fsm structure */
+
+static fsm_callbacks bcp_callbacks = { /* BCP callback routines */
+    bcp_resetci,		/* Reset our Configuration Information */
+    bcp_cilen,			/* Length of our Configuration Information */
+    bcp_addci,			/* Add our Configuration Information */
+    bcp_ackci,			/* ACK our Configuration Information */
+    bcp_nakci,			/* NAK our Configuration Information */
+    bcp_rejci,			/* Reject our Configuration Information */
+    bcp_reqci,			/* Request peer's Configuration Information */
+    bcp_up,			/* Called when fsm reaches OPENED state */
+    bcp_down,			/* Called when fsm leaves OPENED state */
+    bcp_start,			/* Called when we want the lower layer up */
+    bcp_finished,		/* Called when we want the lower layer down */
+    NULL,			/* Called when Protocol-Reject received */
+    NULL,			/* Retransmission is necessary */
+    NULL,			/* Called to handle protocol-specific codes */
+    "BCP"			/* String name of protocol */
+};
+
+/*
+ * Command-line options.
+ */
+static int bcp_setmaclocal __P((char **));
+
+static option_t bcp_option_list[] = {
+    { "nobcp", o_bool, &bcp_protent.enabled_flag, "Disable BCP" },
+    { "maclocal", o_special, (void *)bcp_setmaclocal, "set local MAC address",
+      OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bcp_maclocal_str },
+    { NULL }			/* terminating entry */
+};
+/*
+ * Protocol entry points from main code.
+ */
+static void bcp_init __P((int));
+static void bcp_open __P((int));
+static void bcp_close __P((int, char *));
+static void bcp_lowerup __P((int));
+static void bcp_lowerdown __P((int));
+static void bcp_input __P((int, u_char *, int));
+static void bcp_protrej __P((int));
+static int  bcp_printpkt __P((u_char *, int,
+			       void (*) __P((void *, char *, ...)), void *));
+static void bcp_check_options __P((void));
+
+struct protent bcp_protent = {
+    PPP_BCP,
+    bcp_init,
+    bcp_input,
+    bcp_protrej,
+    bcp_lowerup,
+    bcp_lowerdown,
+    bcp_open,
+    bcp_close,
+    bcp_printpkt,
+    NULL,
+    1,
+    "BCP",
+    "Bridging",
+    bcp_option_list,
+    bcp_check_options,
+    NULL,
+    NULL
+};
+
+static void bcp_script __P((fsm *, char *));	/* Run an up/down script */
+static void bcp_script_done __P((void *));
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID	2
+#define CILEN_BRIDGELINEID	4
+#define CILEN_MACSUPPORT 3
+#define CILEN_TINYGRAM 3
+#define CILEN_LANID 3
+#define CILEN_MACADDR 8
+#define CILEN_SPANTREE 3
+#define CILEN_IEEE_802_TAGGED_FRAME 3
+#define CILEN_MGMT_INLINE 2
+
+#define CODENAME(x)	((x) == CONFACK ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * This state variable is used to ensure that we don't
+ * run an bcp-up/down script while one is already running.
+ */
+static enum script_state {
+    s_down,
+    s_up,
+} bcp_script_state;
+static pid_t bcp_script_pid;
+
+/*
+ * Convert a MAC address from a string to an array of bytes.
+ */
+static int
+mac_aton(const char *cp, u_char *mac)
+{
+    unsigned int args[ETH_ALEN];
+    int n;
+
+    if (sscanf(cp, "%2x:%2x:%2x:%2x:%2x:%2x%n",
+               &args[0], &args[1], &args[2],
+               &args[3], &args[4], &args[5], &n) >= ETH_ALEN)
+    {
+        if (!cp[n]) /* expect to have reached the end of the string */
+        {
+            int i;
+            for (i = 0; i < ETH_ALEN; ++i)
+            {
+                mac[i] = args[i];
+            }
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Print a MAC address into a buffer and return the length.
+ */
+static int
+slprintmac(char *buf, int buflen, const u_char *mac)
+{
+    return slprintf(buf, buflen, "%x:%x:%x:%x:%x:%x",
+		    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+/*
+ * bcp_setmaclocal - set the MAC address to be used on the local interface.
+ * Returns 0 on error, 1 on success.
+ */
+static int
+bcp_setmaclocal(argv)
+    char **argv;
+{
+    bcp_maclocal_valid = mac_aton(argv[0], bcp_maclocal);
+
+    if (bcp_maclocal_valid && (bcp_maclocal[0] & BCP_MULTICAST))
+	bcp_maclocal_valid = 0;
+
+    if (!bcp_maclocal_valid)
+    {
+	option_error("invalid maclocal value '%s'", argv[0]);
+	return 0;
+    }
+
+    slprintmac(bcp_maclocal_str, sizeof(bcp_maclocal_str), bcp_maclocal);
+    return 1;
+}
+
+/*
+ * bcp_init - Initialize BCP.
+ */
+static void
+bcp_init(unit)
+    int unit;
+{
+    fsm *f = &bcp_fsm[unit];
+    bcp_options *wo = &bcp_wantoptions[unit];
+    bcp_options *ao = &bcp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_BCP;
+    f->callbacks = &bcp_callbacks;
+    fsm_init(&bcp_fsm[unit]);
+
+    memset(wo, 0, sizeof(*wo));
+    memset(ao, 0, sizeof(*ao));
+
+    wo->neg_macsupport = 1;
+    wo->macsupport[0] = MAC_IEEE_802_3;
+
+    /* Try Management-Inline first, but prepare to fall back on
+     * Spanning-Tree-Protocol if it fails. */
+    wo->neg_mgmt_inline = 1;
+    wo->neg_spantree = 0;
+    wo->spantree = SPAN_IEEE_802_1D;
+
+    wo->neg_tinygram = 1;
+    wo->tinygram = 1;			/* Linux can receive Tinygrams. */
+
+    ao->neg_macsupport = 1;
+    ao->neg_tinygram = 1;
+    ao->neg_macaddr = 1;
+
+    ao->neg_mgmt_inline = 1;
+    ao->neg_spantree = 1;
+}
+
+
+/*
+ * bcp_open - BCP is allowed to come up.
+ */
+static void
+bcp_open(unit)
+    int unit;
+{
+    fsm_open(&bcp_fsm[unit]);
+}
+
+
+/*
+ * bcp_close - Take BCP down.
+ */
+static void
+bcp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm_close(&bcp_fsm[unit], reason);
+}
+
+
+/*
+ * bcp_lowerup - The lower layer is up.
+ */
+static void
+bcp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&bcp_fsm[unit]);
+}
+
+
+/*
+ * bcp_lowerdown - The lower layer is down.
+ */
+static void
+bcp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&bcp_fsm[unit]);
+}
+
+
+/*
+ * bcp_input - Input BCP packet.
+ */
+static void
+bcp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm_input(&bcp_fsm[unit], p, len);
+}
+
+
+/*
+ * bcp_protrej - A Protocol-Reject was received for BCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+bcp_protrej(unit)
+    int unit;
+{
+  fsm_lowerdown(&bcp_fsm[unit]);
+}
+
+
+/*
+ * bcp_resetci - Reset our CI.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static void
+bcp_resetci(f)
+    fsm *f;
+{
+    bcp_options *wo = &bcp_wantoptions[f->unit];
+    bcp_options *go = &bcp_gotoptions[f->unit];
+
+    /* Either announce our MAC address to the other side, or request one from
+     * the other side.  (Another possibility is not to negotiate at all, but
+     * that seems useless.) */
+    wo->neg_macaddr = 1;
+    if (bcp_maclocal_valid)
+	memcpy(wo->macaddr, bcp_maclocal, sizeof(wo->macaddr));
+    else
+	memset(wo->macaddr, 0, sizeof(wo->macaddr));
+
+    *go = *wo;
+}
+
+
+/*
+ * bcp_cilen - Return length of our CI.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static int
+bcp_cilen(f)
+    fsm *f;
+{
+    bcp_options *go = &bcp_gotoptions[f->unit];
+
+    int macsupport_len = 0;
+    int mac = 0;
+    for (mac=0; mac<ETH_ALEN; mac++)
+    {
+      if (go->macsupport[mac])
+      {
+        macsupport_len += CILEN_MACSUPPORT;
+      }
+    }
+
+#define LENCIBRIDGELINEID(neg)	((neg) ? CILEN_BRIDGELINEID : 0)
+#define LENCITINYGRAM(neg)	((neg) ? CILEN_TINYGRAM : 0)
+#define LENCILANID(neg)	((neg) ? CILEN_LANID : 0)
+#define LENCIMACADDR(neg)	((neg) ? CILEN_MACADDR : 0)
+#define LENCISPANTREE(neg)	((neg) ? CILEN_SPANTREE : 0)
+#define LENCIMGMTINLINE(neg)	((neg) ? CILEN_MGMT_INLINE : 0)
+
+
+    return (LENCIBRIDGELINEID(go->neg_bridgeid) +
+            LENCIBRIDGELINEID(go->neg_lineid) +
+            macsupport_len +
+            LENCITINYGRAM(go->neg_tinygram) +
+            LENCILANID(go->neg_lanid) +
+            LENCIMACADDR(go->neg_macaddr) +
+            LENCISPANTREE(go->neg_spantree) +
+	    LENCIMGMTINLINE(go->neg_mgmt_inline));
+}
+
+/*
+ * bcp_addci - Add our desired CIs to a packet.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static void
+bcp_addci(f, ucp, lenp)
+    fsm *f;
+    u_char *ucp;
+    int *lenp;
+{
+    bcp_options *go = &bcp_gotoptions[f->unit];
+    int len = *lenp;
+
+#define ADDCIBRIDGELINEID(opt, neg, lan_bridge_segno) \
+    if (neg) { \
+	if (len >= CILEN_BRIDGELINEID) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_BRIDGELINEID, ucp); \
+	    PUTSHORT(lan_bridge_segno, ucp); \
+	    len -= CILEN_BRIDGELINEID; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCIMACSUPPORT(opt, neg, macsupport) \
+    if (neg && macsupport) { \
+	if (len >= CILEN_MACSUPPORT) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_MACSUPPORT, ucp); \
+	    PUTCHAR(macsupport, ucp); \
+	    len -= CILEN_MACSUPPORT; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCITINYGRAM(opt, neg, tinygram) \
+    if (neg) { \
+	if (len >= CILEN_TINYGRAM) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_TINYGRAM, ucp); \
+	    PUTCHAR(tinygram, ucp); \
+	    len -= CILEN_TINYGRAM; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCILANID(opt, neg, lanid) \
+    if (neg) { \
+	if (len >= CILEN_LANID) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_LANID, ucp); \
+	    PUTCHAR(lanid, ucp); \
+	    len -= CILEN_LANID; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCIMACADDR(opt, neg, macaddr) \
+    if (neg) { \
+	if (len >= CILEN_MACADDR) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_MACADDR, ucp); \
+	    PUTCHAR(macaddr[0], ucp); \
+	    PUTCHAR(macaddr[1], ucp); \
+	    PUTCHAR(macaddr[2], ucp); \
+	    PUTCHAR(macaddr[3], ucp); \
+	    PUTCHAR(macaddr[4], ucp); \
+	    PUTCHAR(macaddr[5], ucp); \
+	    len -= CILEN_MACADDR; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCISPANTREE(opt, neg, spantree) \
+    if (neg) { \
+	if (len >= CILEN_SPANTREE) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_SPANTREE, ucp); \
+	    PUTCHAR(spantree, ucp); \
+	    len -= CILEN_SPANTREE; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCIMGMTINLINE(opt, neg) \
+    if (neg) { \
+	if (len >= CILEN_MGMT_INLINE) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_MGMT_INLINE, ucp); \
+	    len -= CILEN_MGMT_INLINE; \
+	} else \
+	    neg = 0; \
+    }
+
+    ADDCIBRIDGELINEID(CI_BRIDGE_IDENTIFICATION, go->neg_bridgeid, go->lan_bridge_segno);
+
+    ADDCIBRIDGELINEID(CI_LINE_IDENTIFICATION, go->neg_lineid, go->lan_bridge_segno);
+
+    ADDCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[0]);
+    ADDCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[1]);
+    ADDCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[2]);
+    ADDCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[3]);
+    ADDCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[4]);
+    ADDCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[5]);
+
+    ADDCITINYGRAM(CI_TINYGRAM_COMPRESSION, go->neg_tinygram, go->tinygram);
+
+    ADDCILANID(CI_LAN_IDENTIFICATION, go->neg_lanid, go->lanid);
+
+    ADDCIMACADDR(CI_MAC_ADDRESS, go->neg_macaddr, go->macaddr);
+
+    ADDCISPANTREE(CI_SPANNING_TREE_PROTOCOL, go->neg_spantree, go->spantree);
+
+    ADDCIMGMTINLINE(CI_MANAGEMENT_INLINE, go->neg_mgmt_inline);
+
+    *lenp -= len;
+}
+
+
+/*
+ * bcp_ackci - Ack our CIs.
+ * Called by fsm_rconfack, Receive Configure ACK.
+ *
+ * Returns:
+ *	0 - Ack was bad.
+ *	1 - Ack was good.
+ */
+static int
+bcp_ackci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    bcp_options *go = &bcp_gotoptions[f->unit];
+    u_char cilen, citype, cichar;
+    u_short cishort;
+
+    /*
+     * CIs must be in exactly the same order that we sent...
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define ACKCIBRIDGELINEID(opt, neg, lan_bridge_segno) \
+    if (neg) { \
+	if ((len -= CILEN_BRIDGELINEID) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_BRIDGELINEID || citype != opt) \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (lan_bridge_segno != cishort) \
+	    goto bad; \
+    }
+
+#define ACKCIMACSUPPORT(opt, neg, macsupport) \
+    if (neg && macsupport) { \
+	if ((len -= CILEN_MACSUPPORT) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_MACSUPPORT || citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macsupport != cichar) \
+	    goto bad; \
+    }
+
+#define ACKCITINYGRAM(opt, neg, tinygram) \
+    if (neg) { \
+	if ((len -= CILEN_TINYGRAM) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_TINYGRAM || citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (tinygram != cichar) \
+	    goto bad; \
+    }
+
+#define ACKCILANID(opt, neg, lanid) \
+    if (neg) { \
+	if ((len -= CILEN_LANID) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_LANID || citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (lanid != cichar) \
+	    goto bad; \
+    }
+
+#define ACKCIMACADDR(opt, neg, macaddr) \
+    if (neg) { \
+	if ((len -= CILEN_MACADDR) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_MACADDR || citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[0] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[1] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[2] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[3] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[4] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[5] != cichar) \
+	    goto bad; \
+    }
+
+#define ACKCISPANTREE(opt, neg, spantree) \
+    if (neg) { \
+	if ((len -= CILEN_SPANTREE) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_SPANTREE || citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (spantree != cichar) \
+	    goto bad; \
+    }
+
+#define ACKMGMTINLINE(opt, neg) \
+    if (neg) { \
+	if ((len -= CILEN_MGMT_INLINE) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_MGMT_INLINE || citype != opt) \
+	    goto bad; \
+    }
+
+
+
+    ACKCIBRIDGELINEID(CI_BRIDGE_IDENTIFICATION, go->neg_bridgeid, go->lan_bridge_segno);
+
+    ACKCIBRIDGELINEID(CI_LINE_IDENTIFICATION, go->neg_lineid, go->lan_bridge_segno);
+
+    ACKCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[0]);
+    ACKCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[1]);
+    ACKCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[2]);
+    ACKCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[3]);
+    ACKCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[4]);
+    ACKCIMACSUPPORT(CI_MAC_SUPPORT, go->neg_macsupport, go->macsupport[5]);
+
+    ACKCITINYGRAM(CI_TINYGRAM_COMPRESSION, go->neg_tinygram, go->tinygram);
+
+    ACKCILANID(CI_LAN_IDENTIFICATION, go->neg_lanid, go->lanid);
+
+    ACKCIMACADDR(CI_MAC_ADDRESS, go->neg_macaddr, go->macaddr);
+
+    ACKCISPANTREE(CI_SPANNING_TREE_PROTOCOL, go->neg_spantree, go->spantree);
+
+    ACKMGMTINLINE(CI_MANAGEMENT_INLINE, go->neg_mgmt_inline);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+
+bad:
+    BCPDEBUG(("bcp_ackci: received bad Ack!"));
+    return (0);
+}
+
+/*
+ * bcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if BCP is in the OPENED state.
+ * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ *
+ * Returns:
+ *	0 - Nak was bad.
+ *	1 - Nak was good.
+ */
+static int
+bcp_nakci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    bcp_options *go = &bcp_gotoptions[f->unit];
+    u_char cichar;
+    u_char citype, cilen, *next;
+    u_short cishort;
+    bcp_options no;		/* options we've seen Naks for */
+    bcp_options try;		/* options to request next time */
+    u_char bridge_id;
+    u_short lan_segno;
+    u_char macaddr[ETH_ALEN];
+    int mac;
+
+    BZERO(&no, sizeof(no));
+    try = *go;
+
+    /*
+     * Any Nak'd CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define NAKCIBRIDGELINEID(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_BRIDGELINEID) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+	code \
+    }
+
+#define NAKCIMACADDR(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_MACADDR) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	no.neg = 1; \
+  GETCHAR(macaddr[0], p); \
+  GETCHAR(macaddr[1], p); \
+  GETCHAR(macaddr[2], p); \
+  GETCHAR(macaddr[3], p); \
+  GETCHAR(macaddr[4], p); \
+  GETCHAR(macaddr[5], p); \
+	code \
+    }
+
+#define NAKCISPANTREE(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_SPANTREE) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	no.neg = 1; \
+	GETCHAR(cichar, p); \
+	code \
+    }
+
+#define NAKCIMGMTINLINE(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_MGMT_INLINE) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	no.neg = 1; \
+	code \
+    }
+
+    /*
+     * Accept the peer's value of bridge_id provided that it
+     * is greater than what we asked for.
+     */
+    NAKCIBRIDGELINEID(CI_BRIDGE_IDENTIFICATION, neg_bridgeid,
+      bridge_id = cishort & 0xf;
+      if (bridge_id > 0 &&
+          bridge_id > (go->lan_bridge_segno & 0xf))
+      {
+        try.lan_bridge_segno = cishort;
+      }
+	    );
+
+    /*
+     * Accept the peer's value of lan_segno provided that it
+     * is greater than what we asked for.
+     */
+    NAKCIBRIDGELINEID(CI_LINE_IDENTIFICATION, neg_lineid,
+      lan_segno = cishort >> 4;
+      if (lan_segno > 0 &&
+          lan_segno > (go->lan_bridge_segno >> 4))
+      {
+        try.lan_bridge_segno = cishort;
+      }
+	    );
+
+    /*
+     * Peer is not supposed to send Mac-Support in a Configure-Nak.
+     */
+
+    /*
+     * Peer is not supposed to send TinyGram-Compression in a Configure-Nak
+     * if we already sent it in a Configure-Request already.
+     */
+
+
+    /*
+     * Peer is not supposed to send LAN-Identification in a Configure-Nak.
+     */
+
+    /*
+     * Accept the peer's value of macaddr provided that we requested
+     * an address of 00-00-00-00-00-00 and the suggested address does
+     * NOT have the multicast bit set.
+     */
+    NAKCIMACADDR(CI_MAC_ADDRESS, neg_macaddr,
+      for (mac=0; mac<ETH_ALEN; mac++)
+      {
+        if (go->macaddr[mac] != 0)
+          break;
+      }
+      if (mac == ETH_ALEN)
+      {
+        if (!(macaddr[0] & BCP_MULTICAST))
+        {
+          try.macaddr[0] = macaddr[0];
+          try.macaddr[1] = macaddr[1];
+          try.macaddr[2] = macaddr[2];
+          try.macaddr[3] = macaddr[3];
+          try.macaddr[4] = macaddr[4];
+          try.macaddr[5] = macaddr[5];
+        }
+      }
+	    );
+
+    /*
+     * Accept the peer's value of spantree provided it has a lower
+     * protocol Id than the one we requested.
+     */
+    NAKCISPANTREE(CI_SPANNING_TREE_PROTOCOL, neg_spantree,
+      if (cichar < go->spantree)
+      {
+        try.spantree = cichar;
+      }
+	    );
+
+    NAKCIMGMTINLINE(CI_MANAGEMENT_INLINE, neg_mgmt_inline,
+      do {} while(0);
+	    );
+
+    /*
+     * There may be remaining CIs, if the peer is requesting negotiation
+     * on an option that we didn't include in our request packet.
+     * If we see an option that we requested, or one we've already seen
+     * in this packet, then this packet is bad.
+     * If we wanted to respond by starting to negotiate on the requested
+     * option(s), we could, but we don't, because if we are not negotiating
+     * an option, it is because we were told not to.
+     */
+    while (len > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if( (len -= cilen) < 0 )
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_BRIDGE_IDENTIFICATION:
+	    if (go->neg_bridgeid || no.neg_bridgeid || cilen != CILEN_BRIDGELINEID)
+		goto bad;
+	    break;
+	case CI_LINE_IDENTIFICATION:
+	    if (go->neg_lineid || no.neg_lineid || cilen != CILEN_BRIDGELINEID)
+		goto bad;
+	    break;
+	case CI_TINYGRAM_COMPRESSION:
+	    if (go->neg_tinygram || cilen != CILEN_TINYGRAM)
+		goto bad;
+	    break;
+	case CI_LAN_IDENTIFICATION:
+	    if (go->neg_lanid || cilen != CILEN_LANID)
+		goto bad;
+	    break;
+	case CI_MAC_ADDRESS:
+	    if (go->neg_macaddr || cilen != CILEN_MACADDR)
+		goto bad;
+	    break;
+	case CI_SPANNING_TREE_PROTOCOL:
+	    if (go->neg_spantree || cilen != CILEN_SPANTREE)
+		goto bad;
+	    break;
+	case CI_MANAGEMENT_INLINE:
+	    if (go->neg_mgmt_inline || cilen != CILEN_MGMT_INLINE)
+		goto bad;
+	    break;
+	}
+	p = next;
+    }
+
+    /*
+     * OK, the Nak is good.  Now we can update state.
+     * If there are any remaining options, we ignore them.
+     */
+    if (f->state != OPENED)
+	*go = try;
+
+    return 1;
+
+bad:
+    BCPDEBUG(("bcp_nakci: received bad Nak!"));
+    return 0;
+}
+
+
+/*
+ * bcp_rejci - Reject some of our CIs.
+ * Callback from fsm_rconfnakrej.
+ */
+static int
+bcp_rejci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    bcp_options *go = &bcp_gotoptions[f->unit];
+    u_char cilen, cichar;
+    u_short cishort;
+    bcp_options try;		/* options to request next time */
+
+    try = *go;
+
+    /*
+     * Any Rejected CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define REJCIBRIDGELINEID(opt, neg, lan_bridge_segno) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_BRIDGELINEID) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	/* Check rejected value. */ \
+	if (cishort != lan_bridge_segno) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+#define REJCIMACSUPPORT(opt, neg, macsupport) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_MACSUPPORT) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cichar != macsupport) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+#define REJCITINYGRAM(opt, neg, tinygram) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_TINYGRAM) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cichar != tinygram) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+#define REJCILANID(opt, neg, lanid) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_LANID) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cichar != lanid) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+#define REJCIMACADDR(opt, neg, macaddr) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_MACADDR) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	/* Check rejected value. */ \
+	GETCHAR(cichar, p); \
+	if (macaddr[0] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[1] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[2] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[3] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[4] != cichar) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (macaddr[5] != cichar) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+#define REJCISPANTREE(opt, neg, spantree) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_SPANTREE) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cichar != spantree) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+#define REJCIMGMTINLINE(opt, neg) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_MGMT_INLINE) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	try.neg = 0; \
+    }
+
+    REJCIBRIDGELINEID(CI_BRIDGE_IDENTIFICATION, neg_bridgeid, go->lan_bridge_segno);
+
+    REJCIBRIDGELINEID(CI_LINE_IDENTIFICATION, neg_lineid, go->lan_bridge_segno);
+
+    REJCIMACSUPPORT(CI_MAC_SUPPORT, neg_macsupport, go->macsupport[0]);
+    REJCIMACSUPPORT(CI_MAC_SUPPORT, neg_macsupport, go->macsupport[1]);
+    REJCIMACSUPPORT(CI_MAC_SUPPORT, neg_macsupport, go->macsupport[2]);
+    REJCIMACSUPPORT(CI_MAC_SUPPORT, neg_macsupport, go->macsupport[3]);
+    REJCIMACSUPPORT(CI_MAC_SUPPORT, neg_macsupport, go->macsupport[4]);
+    REJCIMACSUPPORT(CI_MAC_SUPPORT, neg_macsupport, go->macsupport[5]);
+
+    REJCITINYGRAM(CI_TINYGRAM_COMPRESSION, neg_tinygram, go->tinygram);
+
+    REJCILANID(CI_LAN_IDENTIFICATION, neg_lanid, go->lanid);
+
+    REJCIMACADDR(CI_MAC_ADDRESS, neg_macaddr, go->macaddr);
+
+    REJCISPANTREE(CI_SPANNING_TREE_PROTOCOL, neg_spantree, go->spantree);
+
+    REJCIMGMTINLINE(CI_MANAGEMENT_INLINE, neg_mgmt_inline);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+
+    /* If Management-Inline was rejected, try to negotiate a
+     * Spanning-Tree-Protocol instead. */
+    if (go->neg_mgmt_inline && !try.neg_mgmt_inline)
+	try.neg_spantree = 1;
+
+    /*
+     * Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    BCPDEBUG(("bcp_rejci: received bad Reject!"));
+    return 0;
+}
+
+
+/*
+ * bcp_reqci - Check the peer's requested CIs and send appropriate response.
+ * Callback from fsm_rconfreq, Receive Configure Request
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+bcp_reqci(f, inp, len, reject_if_disagree)
+    fsm *f;
+    u_char *inp;		/* Requested CIs */
+    int *len;			/* Length of requested CIs */
+    int reject_if_disagree;
+{
+    bcp_options *ho = &bcp_hisoptions[f->unit];
+    bcp_options *ao = &bcp_allowoptions[f->unit];
+    bcp_options *go = &bcp_gotoptions[f->unit];
+    u_char *cip, *next;		/* Pointer to current and next CIs */
+    u_short cilen, citype;	/* Parsed len, type */
+    u_short cishort;		/* Parsed short value */
+    u_char cichar;		/* Parsed char value */
+    u_char bridge_id;
+    u_short lan_segno;
+    int mac;
+    u_char macaddr[ETH_ALEN];
+
+    int rc = CONFACK;		/* Final packet return code */
+    int orc;			/* Individual option return code */
+    u_char *p;			/* Pointer to next char to parse */
+    u_char *ucp = inp;		/* Pointer to current output char */
+    int l = *len;		/* Length left */
+
+    /*
+     * Reset all his options.
+     */
+    BZERO(ho, sizeof(*ho));
+
+    /*
+     * Process all his options.
+     */
+    next = inp;
+    while (l) {
+	orc = CONFACK;			/* Assume success */
+	cip = p = next;			/* Remember begining of CI */
+	if (l < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    BCPDEBUG(("bcp_reqci: bad CI length!"));
+	    orc = CONFREJ;		/* Reject bad CI */
+	    cilen = l;			/* Reject till end of packet */
+	    l = 0;			/* Don't loop again */
+	    goto endswitch;
+	}
+	GETCHAR(citype, p);		/* Parse CI type */
+	GETCHAR(cilen, p);		/* Parse CI length */
+	l -= cilen;			/* Adjust remaining length */
+	next += cilen;			/* Step to next CI */
+
+	switch (citype) {		/* Check CI type */
+  case CI_BRIDGE_IDENTIFICATION:
+     if (!ao->neg_bridgeid ||		/* Allow option? */
+         cilen != CILEN_BRIDGELINEID)   /* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     GETSHORT(cishort, p); /* Parse lan_bridge_segno */
+
+     /*
+      * If we are also negotiating bridgeid, then
+      * both sides must agree on the higher bridgeid.
+      */
+     bridge_id = cishort & 0xf;
+     if ((bridge_id < (go->lan_bridge_segno & 0xf)) &&
+         go->neg_bridgeid)
+     {
+       orc = CONFNAK;		/* Nak CI */
+       DECPTR(sizeof(u_short), p);
+       PUTSHORT(go->lan_bridge_segno, p);	/* Give him a hint */
+       break;
+     }
+     ho->neg_bridgeid = 1;		/* Remember he negotiated this item */
+     ho->lan_bridge_segno = cishort;		/* And remember value */
+     break;
+
+  case CI_LINE_IDENTIFICATION:
+     if (!ao->neg_lineid ||		/* Allow option? */
+         cilen != CILEN_BRIDGELINEID)   /* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     GETSHORT(cishort, p); /* Parse lan_bridge_segno */
+
+     /*
+      * If we are also negotiating lineid, then
+      * both sides must agree on the higher lan_segno.
+      */
+     lan_segno = cishort >> 4;
+     if ((lan_segno < (go->lan_bridge_segno >> 4)) &&
+         go->neg_lineid)
+     {
+       orc = CONFNAK;		/* Nak CI */
+       DECPTR(sizeof(u_short), p);
+       PUTSHORT(go->lan_bridge_segno, p);	/* Give him a hint */
+       break;
+     }
+     ho->neg_lineid = 1;		/* Remember he negotiated this item */
+     ho->lan_bridge_segno = cishort;		/* And remember value */
+     break;
+
+   case CI_MAC_SUPPORT:
+     if (!ao->neg_macsupport ||		/* Allow option? */
+         cilen != CILEN_MACSUPPORT)   /* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     GETCHAR(cichar, p); /* Parse macsupport value */
+
+     /*
+      * Ensure a valid value, else reject.
+      */
+     switch (cichar)
+     {
+     case MAC_IEEE_802_3:
+     case MAC_IEEE_802_4:
+     case MAC_IEEE_802_5_NON:
+     case MAC_FDDI_NON:
+     case MAC_IEEE_802_5:
+     case MAC_FDDI:
+       ho->neg_macsupport = 1;
+       for (mac=0; mac<ETH_ALEN; mac++)
+       {
+         if (ho->macsupport[mac] == 0)
+           ho->macsupport[mac] = cichar;
+       }
+       break;
+     default:
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     break;
+
+   case CI_TINYGRAM_COMPRESSION:
+     if (!ao->neg_tinygram ||		/* Allow option? */
+         cilen != CILEN_TINYGRAM)   /* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     GETCHAR(cichar, p); /* Parse tinygram value */
+
+     /*
+      * Ensure a valid value, else reject.
+      */
+     if (cichar != 1 && cichar !=2)
+     {
+       orc = CONFREJ;  /* Reject CI */
+       break;
+     }
+     ho->neg_tinygram = 1;		/* Remember he negotiated this item */
+     ho->tinygram = cichar;		/* And remember value */
+     break;
+
+   case CI_LAN_IDENTIFICATION:
+     if (!ao->neg_lanid ||		/* Allow option? */
+         cilen != CILEN_LANID)   /* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     GETCHAR(cichar, p); /* Parse lanid value */
+
+     /*
+      * Ensure a valid value, else reject.
+      */
+     if (cichar != 1 && cichar !=2)
+     {
+       orc = CONFREJ;  /* Reject CI */
+       break;
+     }
+     ho->neg_lanid = 1;		/* Remember he negotiated this item */
+     ho->lanid = cichar;		/* And remember value */
+     break;
+
+
+   case CI_MAC_ADDRESS:
+     if (!ao->neg_macaddr ||		/* Allow option? */
+         cilen != CILEN_MACADDR)   /* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     GETCHAR(macaddr[0], p); /* Parse macaddr value */
+     GETCHAR(macaddr[1], p);
+     GETCHAR(macaddr[2], p);
+     GETCHAR(macaddr[3], p);
+     GETCHAR(macaddr[4], p);
+     GETCHAR(macaddr[5], p);
+
+    /*
+     * Reject macaddr if it has the multicast bit set or
+     * if it is all zeroes.  (All zeroes is a request for
+     * us to assign a MAC address, which we could do, but...)
+     */
+     for (mac=0; mac<ETH_ALEN; mac++)
+     {
+       if (go->macaddr[mac] != 0)
+         break;
+     }
+     if ((mac == ETH_ALEN) || (macaddr[0] & BCP_MULTICAST))
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+
+     ho->neg_macaddr = 1;		/* Remember he negotiated this item */
+     ho->macaddr[0] = macaddr[0];		/* And remember value */
+     ho->macaddr[1] = macaddr[1];
+     ho->macaddr[2] = macaddr[2];
+     ho->macaddr[3] = macaddr[3];
+     ho->macaddr[4] = macaddr[4];
+     ho->macaddr[5] = macaddr[5];
+     break;
+
+   case CI_SPANNING_TREE_PROTOCOL:
+     if (!ao->neg_spantree ||		/* Allow option? */
+         cilen != CILEN_SPANTREE)   /* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+     GETCHAR(cichar, p); /* Parse spantree value */
+
+     /*
+      * Ensure a valid value, else reject.
+      */
+     if (cichar > MAX_SPANTREE)
+     {
+       orc = CONFREJ;  /* Reject CI */
+       break;
+     }
+
+     if ((cichar > go->spantree) && go->neg_spantree)
+     {
+       orc = CONFNAK;		/* Nak CI */
+       DECPTR(sizeof(u_short), p);
+       PUTSHORT(go->spantree, p);	/* Give him a hint */
+       break;
+     }
+
+     ho->neg_spantree = 1;		/* Remember he negotiated this item */
+     ho->spantree = cichar;		/* And remember value */
+     break;
+
+   case CI_MANAGEMENT_INLINE:
+     if (!ao->neg_mgmt_inline ||	/* Allow option? */
+         cilen != CILEN_MGMT_INLINE)	/* Check CI length */
+     {
+       orc = CONFREJ;		/* Reject CI */
+       break;
+     }
+
+     ho->neg_mgmt_inline = 1;		/* Remember he negotiated this item */
+     break;
+
+	default:
+	    orc = CONFREJ;
+	    break;
+	}
+endswitch:
+	if (orc == CONFACK &&		/* Good CI */
+	    rc != CONFACK)		/*  but prior CI wasnt? */
+	    continue;			/* Don't send this one */
+
+	if (orc == CONFNAK) {		/* Nak this CI? */
+	    if (reject_if_disagree)	/* Getting fed up with sending NAKs? */
+		orc = CONFREJ;		/* Get tough if so */
+	    else {
+		if (rc == CONFREJ)	/* Rejecting prior CI? */
+		    continue;		/* Don't send this one */
+		if (rc == CONFACK) {	/* Ack'd all prior CIs? */
+		    rc = CONFNAK;	/* Not anymore... */
+		    ucp = inp;		/* Backup */
+		}
+	    }
+	}
+
+	if (orc == CONFREJ &&		/* Reject this CI */
+	    rc != CONFREJ) {		/*  but no prior ones? */
+	    rc = CONFREJ;
+	    ucp = inp;			/* Backup */
+	}
+
+	/* Need to move CI? */
+	if (ucp != cip)
+	    BCOPY(cip, ucp, cilen);	/* Move it */
+
+	/* Update output pointer */
+	INCPTR(cilen, ucp);
+    }
+
+    *len = ucp - inp;			/* Compute output length */
+    BCPDEBUG(("bcp: returning Configure-%s", CODENAME(rc)));
+    return (rc);			/* Return final code */
+}
+
+
+/*
+ * bcp_up - BCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+static void
+bcp_up(f)
+    fsm *f;
+{
+    bcp_options *go = &bcp_gotoptions[f->unit];
+    bcp_options *ho = &bcp_hisoptions[f->unit];
+    bcp_options *wo = &bcp_wantoptions[f->unit];
+    u_char *maclocal;
+    char buf[32];
+
+    BCPDEBUG(("bcp: up"));
+
+    /* Choose which MAC address (if any) to assign to the interface. */
+    if (go->neg_macaddr)
+	maclocal = go->macaddr;
+    else if (wo->neg_macaddr) {
+	int i;
+
+	/* If the wanted MAC address is all zeroes, it means we wanted the peer
+	 * to assign us one.  Since we didn't get one, there's a problem. */
+	for (i = 0; i < ETH_ALEN; ++i) {
+	    if (wo->macaddr[i] != 0)
+		break;
+	}
+
+	if (i == ETH_ALEN) {
+	    error("Could not determine local MAC address");
+	    bcp_close(f->unit, "Could not determine local MAC address");
+	    return;
+	}
+
+	maclocal = wo->macaddr;
+    } else
+	maclocal = NULL;
+
+    /* If Management-Inline is not supported, tell the kernel to encapsulate
+     * bridge PDUs in the old RFC 1638 format. */
+    if (!go->neg_mgmt_inline)
+    {
+        sifnpmode(ifunit, PPP_BPDU_IEEE, NPMODE_PASS);
+    }
+
+    /* After this the "bcp%d" device will exist. */
+    sifnpmode(ifunit, PPP_BRIDGE, NPMODE_PASS);
+
+    if (maclocal) {
+        char eth_ifname[16];
+        slprintf(eth_ifname, sizeof(eth_ifname), "bcp%d", ifunit);
+	if (set_if_hwaddr(maclocal, eth_ifname) < 0) {
+	    if (debug)
+		warn("Failed to set hardware address");
+	    bcp_close(f->unit, "Interface configuration failed");
+	    return;
+        }
+    }
+
+    /*
+     * Set up /etc/ppp/eth-up environment.
+     */
+
+    /* MACLOCAL contains the MAC address of the BCP interface, if it has one.
+     * Otherwise, MACLOCAL is defined as an empty string. */
+    if (maclocal)
+	slprintmac(buf, sizeof(buf), maclocal);
+    else
+	buf[0] = '\0';
+    script_setenv("MACLOCAL", buf, 0);
+
+    /* MACREMOTE contains the MAC address of the peer's BCP interface, if the
+     * peer published it during negotiation.  Otherwise, MACREMOTE is defined
+     * as an empty string. */
+    if (ho->neg_macaddr)
+	slprintmac(buf, sizeof(buf), ho->macaddr);
+    else
+	buf[0] = '\0';
+    script_setenv("MACREMOTE", buf, 0);
+
+    np_up(f->unit, PPP_BRIDGE);
+    bcp_is_up = 1;
+
+    /*
+     * Execute the eth-up script, like this:
+     *	/etc/ppp/eth-up interface tty speed local-IP remote-IP
+     */
+    if (bcp_script_state == s_down && bcp_script_pid == 0) {
+	bcp_script_state = s_up;
+	bcp_script(f, _PATH_ETHUP);
+    }
+}
+
+
+/*
+ * bcp_down - BCP has gone DOWN.
+ *
+ */
+static void
+bcp_down(f)
+    fsm *f;
+{
+    /* Execute the eth-down script */
+    if (bcp_script_state == s_up && bcp_script_pid == 0) {
+	bcp_script_state = s_down;
+	bcp_script(f, _PATH_ETHDOWN);
+    }
+
+    /* After this the "bcp%d" device will not exist. */
+    sifnpmode(ifunit, PPP_BRIDGE, NPMODE_DROP);
+
+    sifnpmode(ifunit, PPP_BPDU_IEEE, NPMODE_DROP);
+
+    BCPDEBUG(("bcp: down"));
+    if (bcp_is_up)
+    {
+      bcp_is_up = 0;
+      np_down(f->unit, PPP_BRIDGE);
+    }
+}
+
+
+/*
+ * bcp_start - called when we want the lower layer up.
+ */
+static void
+bcp_start(f)
+    fsm *f;
+{
+    np_start(f->unit, PPP_BRIDGE);
+}
+
+
+/*
+ * bcp_finished - possibly shut down the lower layers.
+ */
+static void
+bcp_finished(f)
+    fsm *f;
+{
+    np_finished(f->unit, PPP_BRIDGE);
+}
+
+
+/*
+ * bcp_script_done - called when the ip-up or ip-down script
+ * has finished.
+ */
+static void
+bcp_script_done(vp_f)
+    void *vp_f;
+{
+    fsm *f = vp_f;
+
+    bcp_script_pid = 0;
+    switch (bcp_script_state) {
+    case s_up:
+	if (f->state != OPENED) {
+	    bcp_script_state = s_down;
+	    bcp_script(f, _PATH_ETHDOWN);
+	}
+	break;
+    case s_down:
+	if (f->state == OPENED) {
+	    bcp_script_state = s_up;
+	    bcp_script(f, _PATH_ETHUP);
+	}
+	break;
+    }
+}
+
+
+/*
+ * bcp_script - Execute a script with arguments
+ * bcp-interface-name phys-interface-name
+ */
+static void
+bcp_script(f, script)
+    fsm *f;
+    char *script;
+{
+    char eth_ifname[16];
+    char *argv[8];
+
+    slprintf(eth_ifname, sizeof(eth_ifname), "bcp%d", ifunit);
+
+    argv[0] = script;
+    argv[1] = eth_ifname;	/* bridge device (e.g. bcp<N>) */
+    argv[2] = devnam;		/* physical device (e.g. hdlc<N>) */
+    argv[3] = NULL;
+    argv[4] = NULL;
+    argv[5] = NULL;
+    argv[6] = NULL;
+    argv[7] = NULL;
+    bcp_script_pid = run_program(script, argv, 0, bcp_script_done, f);
+}
+
+/*
+ * bcp_printpkt - print the contents of an BCP packet.
+ */
+static char *bcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+static int
+bcp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int code, id, len, olen;
+    u_char *pstart, *optend;
+    u_short cishort;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(bcp_codenames) / sizeof(char *))
+	printer(arg, " %s", bcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+            case CI_BRIDGE_IDENTIFICATION:
+                if (olen == CILEN_BRIDGELINEID) {
+                    p += 2;
+                    GETSHORT(cishort, p);
+                    printer(arg, "Bridge-ID LAN=0x%03x Bridge=0x%X",
+                            (cishort & 0xFFF0) >> 4,
+                            cishort & 0x000F);
+                }
+                break;
+
+            case CI_LINE_IDENTIFICATION:
+                if (olen == CILEN_BRIDGELINEID) {
+                    p += 2;
+                    GETSHORT(cishort, p);
+                    printer(arg, "Line-ID LAN=0x%03x Bridge=0x%X",
+                            (cishort & 0xFFF0) >> 4,
+                            cishort & 0x000F);
+                }
+                break;
+
+            case CI_MAC_SUPPORT:
+                if (olen == CILEN_MACSUPPORT) {
+                    p += 2;
+                    printer(arg, "MAC-Support");
+                }
+                break;
+
+            case CI_TINYGRAM_COMPRESSION:
+                if (olen == CILEN_TINYGRAM) {
+                    p += 2;
+                    printer(arg, "Tinygram-Compression");
+                }
+                break;
+
+            case CI_LAN_IDENTIFICATION:
+                if (olen == CILEN_LANID) {
+                    p += 2;
+                    printer(arg, "LAN-ID (obsolete)");
+                }
+                break;
+
+            case CI_MAC_ADDRESS:
+                if (olen == CILEN_MACADDR) {
+                    p += 2;
+                    printer(arg, "MAC-Address");
+                }
+                break;
+
+            case CI_SPANNING_TREE_PROTOCOL:
+                if (olen >= CILEN_SPANTREE) {
+                    p += 2;
+                    printer(arg, "Spanning-Tree-Protocol (old format)");
+                }
+                break;
+
+            case CI_IEEE_802_TAGGED_FRAME:
+                if (olen == CILEN_IEEE_802_TAGGED_FRAME) {
+                    p += 2;
+                    printer(arg, "IEEE-802-Tagged-Frame");
+                }
+                break;
+
+            case CI_MANAGEMENT_INLINE:
+                if (olen == CILEN_VOID) {
+                    p += 2;
+                    printer(arg, "Management-Inline");
+                }
+                break;
+
+            default:
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string((char *)p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/*
+ * bcp_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+bcp_check_options()
+{
+}
+
+
diff -wbBurN pppd-2.4.1/pppd/bcp.h pppd-ai/pppd/bcp.h
--- pppd-2.4.1/pppd/bcp.h	1969-12-31 19:00:00.000000000 -0500
+++ pppd-ai/pppd/bcp.h	2004-02-25 08:34:47.000000000 -0500
@@ -0,0 +1,73 @@
+/*
+ * bcp.h - Bridge Control Protocol definitions.
+ *
+ * Copyright (c) 2001-2004 Applied Innovation Inc.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms.  The name of Applied Innovation Inc.
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Options.
+ */
+#define CI_BRIDGE_IDENTIFICATION	1
+#define CI_LINE_IDENTIFICATION		2
+#define CI_MAC_SUPPORT			3
+#define CI_TINYGRAM_COMPRESSION		4
+#define CI_LAN_IDENTIFICATION		5	/* obsolete (since RFC 2878) */
+#define CI_MAC_ADDRESS			6
+#define CI_SPANNING_TREE_PROTOCOL	7	/* old format (RFC 1638) */
+#define CI_IEEE_802_TAGGED_FRAME	8
+#define CI_MANAGEMENT_INLINE		9	/* new format (RFC 2878) */
+
+/* values for MAC Support */
+#define MAC_IEEE_802_3			1
+#define MAC_IEEE_802_4			2
+#define MAC_IEEE_802_5_NON		3
+#define MAC_FDDI_NON			4
+#define MAC_IEEE_802_5			11
+#define MAC_FDDI			12
+
+/* Multicast bit */
+#define BCP_MULTICAST			1
+
+/* values for Spanning Tree protocol */
+#define SPAN_NONE			0
+#define SPAN_IEEE_802_1D		1
+#define SPAN_IEEE_802_1G		2
+#define SPAN_IBM			3
+#define SPAN_DEC			4
+#define MAX_SPANTREE			SPAN_DEC
+
+#define ETH_ALEN			6	/* ethernet address length */
+
+typedef struct bcp_options {
+    u_int16_t	lan_bridge_segno;
+    u_char	macsupport[6];	/* MAC support */
+    u_char	tinygram;	/* Tinygram Compression 1=enable, 2=disable */
+    u_char	lanid;		/* Lan ID 1=enable, 2=disable*/
+    u_char	macaddr[ETH_ALEN];	/* MAC Address */
+    u_char	spantree;	/* Spanning Tree Protocol */
+    bool	neg_bridgeid;
+    bool	neg_lineid;
+    bool	neg_macsupport;
+    bool	neg_tinygram;
+    bool	neg_lanid;
+    bool	neg_macaddr;
+    bool	neg_spantree;
+    bool	neg_mgmt_inline;
+} bcp_options;
+
+extern fsm bcp_fsm[];
+extern bcp_options bcp_wantoptions[];
+extern bcp_options bcp_gotoptions[];
+extern bcp_options bcp_allowoptions[];
+extern bcp_options bcp_hisoptions[];
+
+extern struct protent bcp_protent;
diff -wbBurN pppd-2.4.1/pppd/fsm.c pppd-ai/pppd/fsm.c
--- pppd-2.4.1/pppd/fsm.c	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/fsm.c	2004-02-25 08:34:48.000000000 -0500
@@ -195,6 +195,8 @@
     switch( f->state ){
     case STARTING:
 	f->state = INITIAL;
+        if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
 	break;
     case STOPPED:
 	f->state = CLOSED;
diff -wbBurN pppd-2.4.1/pppd/ipcp.c pppd-ai/pppd/ipcp.c
--- pppd-2.4.1/pppd/ipcp.c	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/ipcp.c	2004-02-25 08:34:48.000000000 -0500
@@ -80,6 +80,7 @@
 static int  ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
 static void ipcp_up __P((fsm *));		/* We're UP */
 static void ipcp_down __P((fsm *));		/* We're DOWN */
+static void ipcp_start __P((fsm *));	/* Need lower layer */
 static void ipcp_finished __P((fsm *));	/* Don't need lower layer */
 
 fsm ipcp_fsm[NUM_PPP];		/* IPCP fsm structure */
@@ -94,7 +95,7 @@
     ipcp_reqci,			/* Request peer's Configuration Information */
     ipcp_up,			/* Called when fsm reaches OPENED state */
     ipcp_down,			/* Called when fsm leaves OPENED state */
-    NULL,			/* Called when we want the lower layer up */
+    ipcp_start,			/* Called when we want the lower layer up */
     ipcp_finished,		/* Called when we want the lower layer down */
     NULL,			/* Called when Protocol-Reject received */
     NULL,			/* Retransmission is necessary */
@@ -1789,6 +1790,17 @@
 
 
 /*
+ * ipcp_start - called when we want the lower layer up.
+ */
+static void
+ipcp_start(f)
+    fsm *f;
+{
+    np_start(f->unit, PPP_IP);
+}
+
+
+/*
  * ipcp_finished - possibly shut down the lower layers.
  */
 static void
diff -wbBurN pppd-2.4.1/pppd/ipv6cp.c pppd-ai/pppd/ipv6cp.c
--- pppd-2.4.1/pppd/ipv6cp.c	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/ipv6cp.c	2004-02-25 08:34:48.000000000 -0500
@@ -146,6 +146,7 @@
 static int  ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
 static void ipv6cp_up __P((fsm *));		/* We're UP */
 static void ipv6cp_down __P((fsm *));		/* We're DOWN */
+static void ipv6cp_start __P((fsm *));		/* Need lower layer */
 static void ipv6cp_finished __P((fsm *));	/* Don't need lower layer */
 
 fsm ipv6cp_fsm[NUM_PPP];		/* IPV6CP fsm structure */
@@ -160,7 +161,7 @@
     ipv6cp_reqci,		/* Request peer's Configuration Information */
     ipv6cp_up,			/* Called when fsm reaches OPENED state */
     ipv6cp_down,		/* Called when fsm leaves OPENED state */
-    NULL,			/* Called when we want the lower layer up */
+    ipv6cp_start,		/* Called when we want the lower layer up */
     ipv6cp_finished,		/* Called when we want the lower layer down */
     NULL,			/* Called when Protocol-Reject received */
     NULL,			/* Retransmission is necessary */
@@ -1309,6 +1310,17 @@
 
 
 /*
+ * ipv6cp_start - called when we want the lower layer up.
+ */
+static void
+ipv6cp_start(f)
+    fsm *f;
+{
+    np_start(f->unit, PPP_IPV6);
+}
+
+
+/*
  * ipv6cp_finished - possibly shut down the lower layers.
  */
 static void
diff -wbBurN pppd-2.4.1/pppd/ipxcp.c pppd-ai/pppd/ipxcp.c
--- pppd-2.4.1/pppd/ipxcp.c	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/ipxcp.c	2004-02-25 08:34:48.000000000 -0500
@@ -64,6 +64,7 @@
 static int  ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
 static void ipxcp_up __P((fsm *));		/* We're UP */
 static void ipxcp_down __P((fsm *));		/* We're DOWN */
+static void ipxcp_start __P((fsm *));		/* Need lower layer */
 static void ipxcp_finished __P((fsm *));	/* Don't need lower layer */
 static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */
 
@@ -79,7 +80,7 @@
     ipxcp_reqci,		/* Request peer's Configuration Information */
     ipxcp_up,			/* Called when fsm reaches OPENED state */
     ipxcp_down,			/* Called when fsm leaves OPENED state */
-    NULL,			/* Called when we want the lower layer up */
+    ipxcp_start,		/* Called when we want the lower layer up */
     ipxcp_finished,		/* Called when we want the lower layer down */
     NULL,			/* Called when Protocol-Reject received */
     NULL,			/* Retransmission is necessary */
@@ -1358,6 +1359,17 @@
 
 
 /*
+ * ipxcp_start - called when we want the lower layer up.
+ */
+static void
+ipxcp_start(f)
+    fsm *f;
+{
+    np_start(f->unit, PPP_IPX);
+}
+
+
+/*
  * ipxcp_finished - possibly shut down the lower layers.
  */
 static void
diff -wbBurN pppd-2.4.1/pppd/main.c pppd-ai/pppd/main.c
--- pppd-2.4.1/pppd/main.c	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/main.c	2004-02-25 08:34:48.000000000 -0500
@@ -45,6 +45,7 @@
 #include "pppd.h"
 #include "magic.h"
 #include "fsm.h"
+#include "bcp.h"
 #include "lcp.h"
 #include "ipcp.h"
 #ifdef INET6
@@ -212,6 +213,7 @@
 #ifdef AT_CHANGE
     &atcp_protent,
 #endif
+    &bcp_protent,
     NULL
 };
 
diff -wbBurN pppd-2.4.1/pppd/Makefile.linux pppd-ai/pppd/Makefile.linux
--- pppd-2.4.1/pppd/Makefile.linux	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/Makefile.linux	2004-02-25 08:34:47.000000000 -0500
@@ -7,13 +7,13 @@
 BINDIR = /usr/sbin
 MANDIR = /usr/man
 
-PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
+PPPDSRCS = main.c magic.c fsm.c bcp.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
 	   ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c cbcp.c \
 	   demand.c utils.c multilink.c tdb.c tty.c
 HEADERS =  callout.h pathnames.h patchlevel.h chap.h md5.h chap_ms.h md4.h \
 	   ipxcp.h cbcp.h tdb.h
 MANPAGES = pppd.8
-PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
+PPPDOBJS = main.o magic.o fsm.o bcp.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
 	   auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o \
 	   tdb.o tty.o
 
diff -wbBurN pppd-2.4.1/pppd/pathnames.h pppd-ai/pppd/pathnames.h
--- pppd-2.4.1/pppd/pathnames.h	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/pathnames.h	2004-02-25 08:34:48.000000000 -0500
@@ -29,6 +29,8 @@
 #define _PATH_CONNERRS	 _ROOT_PATH "/etc/ppp/connect-errors"
 #define _PATH_PEERFILES	 _ROOT_PATH "/etc/ppp/peers/"
 #define _PATH_RESOLV	 _ROOT_PATH "/etc/ppp/resolv.conf"
+#define _PATH_ETHUP	 _ROOT_PATH "/etc/ppp/eth-up"
+#define _PATH_ETHDOWN	 _ROOT_PATH "/etc/ppp/eth-down"
 
 #define _PATH_USEROPT	 ".ppprc"
 
diff -wbBurN pppd-2.4.1/pppd/pppd.h pppd-ai/pppd/pppd.h
--- pppd-2.4.1/pppd/pppd.h	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/pppd.h	2004-02-25 08:34:48.000000000 -0500
@@ -450,6 +450,7 @@
 void start_networks __P((void));  /* start all the network control protos */
 void np_up __P((int, int));	  /* a network protocol has come up */
 void np_down __P((int, int));	  /* a network protocol has gone down */
+void np_start __P((int, int));    /* a network protocol needs link */
 void np_finished __P((int, int)); /* a network protocol no longer needs link */
 void auth_peer_fail __P((int, int));
 				/* peer failed to authenticate itself */
@@ -496,6 +497,8 @@
 int  open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
 int  tty_establish_ppp __P((int));  /* Turn serial port into a ppp interface */
 void tty_disestablish_ppp __P((int)); /* Restore port to normal operation */
+void generic_disestablish_ppp __P((int dev_fd)); /* Restore device setting */
+int  generic_establish_ppp __P((int dev_fd, int chindex)); /* Make a ppp interface */
 void make_new_bundle __P((int, int, int, int)); /* Create new bundle */
 int  bundle_attach __P((int));	/* Attach link to existing bundle */
 void cfg_bundle __P((int, int, int, int)); /* Configure existing bundle */
@@ -566,6 +569,7 @@
 int  sipxfaddr __P((int, unsigned long, unsigned char *));
 int  cipxfaddr __P((int));
 #endif
+int  set_if_hwaddr __P((const u_char *addr, const char *name));
 int  get_if_hwaddr __P((u_char *addr, char *name));
 char *get_first_ethernet __P((void));
 
@@ -700,6 +704,7 @@
 #ifdef DEBUGALL
 #define DEBUGMAIN	1
 #define DEBUGFSM	1
+#define DEBUGBCP	1
 #define DEBUGLCP	1
 #define DEBUGIPCP	1
 #define DEBUGIPV6CP	1
@@ -735,6 +740,12 @@
 #define FSMDEBUG(x)
 #endif
 
+#ifdef DEBUGBCP
+#define BCPDEBUG(x)	if (debug) dbglog x
+#else
+#define BCPDEBUG(x)
+#endif
+
 #ifdef DEBUGLCP
 #define LCPDEBUG(x)	if (debug) dbglog x
 #else
diff -wbBurN pppd-2.4.1/pppd/sys-linux.c pppd-ai/pppd/sys-linux.c
--- pppd-2.4.1/pppd/sys-linux.c	2004-02-25 08:27:34.000000000 -0500
+++ pppd-ai/pppd/sys-linux.c	2004-02-25 08:34:48.000000000 -0500
@@ -128,7 +128,6 @@
 static int sock6_fd = -1;
 #endif /* INET6 */
 static int ppp_dev_fd = -1;	/* fd for /dev/ppp (new style driver) */
-static int chindex;		/* channel index (new style driver) */
 
 static fd_set in_fds;		/* set of fds that wait_input waits for */
 static int max_in_fd;		/* highest fd set in in_fds */
@@ -141,7 +140,7 @@
 static int restore_term        = 0;	/* 1 => we've munged the terminal */
 static struct termios inittermios;	/* Initial TTY termios */
 
-static int new_style_driver = 0;
+int new_style_driver = 0;
 
 static char loop_name[20];
 static unsigned char inbuf[512]; /* buffer for chars read from loopback */
@@ -359,9 +359,7 @@
 
 int tty_establish_ppp (int tty_fd)
 {
-    int x;
-    int fd = -1;
-
+    int ret_fd;
 /*
  * Ensure that the tty device is in exclusive mode.
  */
@@ -370,14 +368,6 @@
 	    warn("Couldn't make tty exclusive: %m");
     }
 /*
- * Demand mode - prime the old ppp device to relinquish the unit.
- */
-    if (!new_style_driver && looped
-	&& ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) {
-	error("ioctl(transfer ppp unit): %m");
-	return -1;
-    }
-/*
  * Set the current tty to the PPP discpline
  */
 
@@ -393,21 +383,62 @@
     }
 
     if (new_style_driver) {
-	/* Open another instance of /dev/ppp and connect the channel to it */
-	int flags;
-
+        int chindex;
 	if (ioctl(tty_fd, PPPIOCGCHAN, &chindex) == -1) {
 	    error("Couldn't get channel number: %m");
-	    goto err;
+            ret_fd = -1;
+        } else {
+            ret_fd = generic_establish_ppp(tty_fd, chindex);
+        }
+    } else {
+        ret_fd = generic_establish_ppp(tty_fd, -1);
+    }
+
+    if (ret_fd < 0) {
+        if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
+            warn("Couldn't reset tty to normal line discipline: %m");
+    }
+    else
+    {
+#define SC_RCVB	(SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
+#define SC_LOGB	(SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
+		 | SC_LOG_FLUSH)
+
+    set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
+		       | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+    }
+
+    return ret_fd;
+}
+
+/********************************************************************
+ *
+ * generic_establish_ppp - Turn the fd into a ppp interface.
+ */
+int generic_establish_ppp (int fd, int channel)
+{
+    int x;
+/*
+ * Demand mode - prime the old ppp device to relinquish the unit.
+ */
+    if (!new_style_driver && looped
+	&& ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) {
+	error("ioctl(transfer ppp unit): %m");
+	return -1;
 	}
-	dbglog("using channel %d", chindex);
+
+    if (new_style_driver) {
+	/* Open another instance of /dev/ppp and connect the channel to it */
+	int flags;
+
+	dbglog("using channel %d", channel);
 	fd = open("/dev/ppp", O_RDWR);
 	if (fd < 0) {
 	    error("Couldn't reopen /dev/ppp: %m");
 	    goto err;
 	}
-	if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
-	    error("Couldn't attach to channel %d: %m", chindex);
+	if (ioctl(fd, PPPIOCATTCHAN, &channel) < 0) {
+	    error("Couldn't attach to channel %d: %m", channel);
 	    goto err_close;
 	}
 	flags = fcntl(fd, F_GETFL);
@@ -440,8 +472,8 @@
 	/*
 	 * Old-style driver: find out which interface we were given.
 	 */
-	set_ppp_fd (tty_fd);
-	if (ioctl(tty_fd, PPPIOCGUNIT, &x) < 0) {	
+	set_ppp_fd (fd);
+	if (ioctl(fd, PPPIOCGUNIT, &x) < 0) {
 	    if (ok_error (errno))
 		goto err;
 	    fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
@@ -454,9 +486,9 @@
 	/*
 	 * Fetch the initial file flags and reset blocking mode on the file.
 	 */
-	initfdflags = fcntl(tty_fd, F_GETFL);
+	initfdflags = fcntl(fd, F_GETFL);
 	if (initfdflags == -1 ||
-	    fcntl(tty_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+	    fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
 	    if ( ! ok_error (errno))
 		warn("Couldn't set device to non-blocking mode: %m");
 	}
@@ -470,13 +503,6 @@
     if (!looped)
 	set_kdebugflag (kdebugflag);
 
-#define SC_RCVB	(SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
-#define SC_LOGB	(SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
-		 | SC_LOG_FLUSH)
-
-    set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
-		       | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
-
     SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
 	    driver_version, driver_modification, driver_patch));
 
@@ -485,22 +511,19 @@
  err_close:
     close(fd);
  err:
-    if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
-	warn("Couldn't reset tty to normal line discipline: %m");
     return -1;
 }
 
 /********************************************************************
  *
- * tty_disestablish_ppp - Restore the serial port to normal operation,
- * and reconnect the ppp unit to the loopback if in demand mode.
+ * tty_disestablish_ppp - Restore the serial port to normal operation.
  * This shouldn't call die() because it's called from die().
  */
 
 void tty_disestablish_ppp(int tty_fd)
 {
-    if (demand)
-	restore_loop();
+    generic_disestablish_ppp(tty_fd);
+
     if (!hungup) {
 /*
  * Flush the tty output buffer so that the TIOCSETD doesn't hang.
@@ -526,13 +549,47 @@
 		warn("Couldn't restore device fd flags: %m");
 	}
     }
+}
+
+/********************************************************************
+ *
+ * generic_disestablish_ppp - Restore device components to normal
+ * operation, and reconnect the ppp unit to the loopback if in demand
+ * mode.  This shouldn't call die() because it's called from die().
+*/
+void generic_disestablish_ppp(int dev_fd){
+
+    /* Restore loop if needed */
+    if(demand)
+	restore_loop();
+
+    /* Finally detach the device */
     initfdflags = -1;
 
     if (new_style_driver) {
+	if (!multilink && ioctl(ppp_fd, PPPIOCDISCONN) < 0)
+	    error("Couldn't detach from PPP unit %d: %m", ifunit);
+
 	close(ppp_fd);
 	ppp_fd = -1;
-	if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
+
+	if (!looped && ifunit >= 0) {
+	    if (ioctl(ppp_dev_fd, PPPIOCDETACH) < 0) {
+		/* linux/Documentation/networking/ppp_generic.txt says,
+		 *
+		 *     This ioctl is deprecated since the same effect can be
+		 *     achieved by closing the instance.  In order to prevent
+		 *     possible races this ioctl will fail with an EINVAL error
+		 *     if more than one file descriptor refers to this instance
+		 *     (i.e. as a result of dup(), dup2() or fork()).
+		 *
+		 * Testers report seeing this message, therefore I have quelled
+		 * the error when EINVAL is returned. -- Dan Eble
+		 */
+		if (errno != EINVAL)
 	    error("Couldn't release PPP unit: %m");
+	    }
+	}
 	if (!multilink)
 	    remove_fd(ppp_dev_fd);
     }
@@ -1712,6 +1771,30 @@
 }
 
 /*
+ * set_if_hwaddr - set the hardware address for the specified
+ * network interface device.
+ */
+int
+set_if_hwaddr(const u_char *addr, const char *name)
+{
+	struct ifreq ifreq;
+	int ret, sock_fd;
+
+	sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock_fd < 0)
+		return 0;
+	memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+	strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
+	ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq);
+        if (ret >= 0) {
+            memcpy(ifreq.ifr_hwaddr.sa_data, addr, 6);
+            ret = ioctl(sock_fd, SIOCSIFHWADDR, &ifreq);
+        }
+	close(sock_fd);
+	return ret;
+}
+
+/*
  * get_if_hwaddr - get the hardware address for the specified
  * network interface device.
  */
@@ -2567,7 +2650,7 @@
  * Just to be sure, set the real serial port to the normal discipline.
  */
 
-static void
+void
 restore_loop(void)
 {
     looped = 1;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2004-02-25 15:36 Dan Eble
  0 siblings, 0 replies; 12+ messages in thread
From: Dan Eble @ 2004-02-25 15:36 UTC (permalink / raw)
  To: bridge; +Cc: jwise03

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1696 bytes --]

Attached are the kernel changes (ppc 2.4.21-pre4) that match the pppd 
changes I posted earlier today.

I hope I found all the relevant changes. :-)  If you have any problems,
feel free to contact me, especially if you find any bugs.

Some documentation:

When pppd negotiates BCP, it tells the kernel PPP driver to enable
bridging.  The kernel creates a device named "bcpX" where X matches the
"pppX" device that would be used for IP communication (assuming I did not
make a mistake).  Pppd runs the script /etc/ppp/eth-up, which is a good
place to add bcpX to your bridge and "ifconfig up" it.  If the link goes
down, the kernel should handle all cleanup, but pppd also calls
/etc/ppp/eth-down in case you should find something you want to run at
that time.  Don't access the bcpX device from eth-down, as it is probably
already gone.

It should be possible to run BCP and IPCP (and other protocols)  
simultaneously, although we haven't tested it much because it seems silly.  
The options "noip", "nobcp", etc. are helpful to restrict the behavior of
pppd.

The pppd option "maclocal" will tell pppd what hardware address to assign
bcpX.  Without this option, pppd will attempt to use an address assigned
by the peer.  BCP negotiation will fail if it can not determine a hardware
address.  Change the source code if that doesn't suit your application.  
I don't know how the bridge driver handles interfaces without hardware
addresses, though.  You might have to turn off STP in that case to avoid
unintended consequences.

Happy hacking,

-- 
Dan Eble <dane@aiinet.com>  _____  .
Software Engineer          |  _  |/|
Applied Innovation Inc.    | |_| | |
http://www.aiinet.com/     |__/|_|_|

[-- Attachment #2: Type: TEXT/PLAIN, Size: 19669 bytes --]

diff -wbBurN linux-2.4.21-pre4/include/linux/ppp_defs.h linux-ai/include/linux/ppp_defs.h
--- linux-2.4.21-pre4/include/linux/ppp_defs.h	2004-02-25 08:26:46.000000000 -0500
+++ linux-ai/include/linux/ppp_defs.h	2004-02-25 08:35:18.000000000 -0500
@@ -70,13 +70,16 @@
 #define PPP_IPX		0x2b	/* IPX protocol */
 #define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
 #define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_BRIDGE	0x31	/* Bridged LAN traffic or BPDU */
 #define PPP_MP		0x3d	/* Multilink protocol */
 #define PPP_IPV6	0x57	/* Internet Protocol Version 6 */
 #define PPP_COMPFRAG	0xfb	/* fragment compressed below bundle */
 #define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_BPDU_IEEE	0x0201	/* IEEE 802.1 (D or G) bridge PDU */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
 #define PPP_IPXCP	0x802b	/* IPX Control Protocol */
+#define PPP_BCP		0x8031	/* Bridging Control Protocol */
 #define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
 #define PPP_CCPFRAG	0x80fb	/* CCP at link level (below MP bundle) */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
@@ -174,6 +177,34 @@
     time_t recv_idle;		/* time since last NP packet received */
 };
 
+/*
+ * Bridging Control Protocol (BCP)
+ */
+struct bcp_hdr {
+	__u8	flags;
+	__u8	mactype;
+	__u8	padbyte;	/* not used (present when "control" is also) */
+	__u8	control;	/* 802.4, 802.5, and FDDI only */
+};
+#define BCP_802_3_HDRLEN	2
+
+/*
+ * Fields in bcp_hdr::flags.
+ */
+#define BCP_LAN_FCS		0x80	/* set when LAN FCS is present */
+#define BCP_ZERO_PAD		0x20	/* set to pad 802.3 to min size */
+#define BCP_PADS_MASK		0x0F	/* 0-15 bytes padding before PPP FCS */
+
+/*
+ * Values for bcp_hdr::mactype.
+ */
+#define BCP_MAC_802_3		0x01	/* 802.3 / Ethernet */
+#define BCP_MAC_802_4		0x02
+#define BCP_MAC_802_5_NC	0x03	/* with non-canonical address */
+#define BCP_MAC_FDDI_NC		0x04	/* with non-canonical address */
+#define BCP_MAC_802_5		0x0B	/* with canonical address */
+#define BCP_MAC_FDDI		0x0C	/* with canonical address */
+
 #ifndef __P
 #ifdef __STDC__
 #define __P(x)	x
diff -wbBurN linux-2.4.21-pre4/drivers/net/ppp_generic.c linux-ai/drivers/net/ppp_generic.c
--- linux-2.4.21-pre4/drivers/net/ppp_generic.c	2004-02-25 08:26:18.000000000 -0500
+++ linux-ai/drivers/net/ppp_generic.c	2004-02-25 08:35:08.000000000 -0500
@@ -30,6 +30,7 @@
 #include <linux/list.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
 #include <linux/filter.h>
@@ -37,6 +38,7 @@
 #include <linux/ppp_channel.h>
 #include <linux/ppp-comp.h>
 #include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
 #include <linux/rtnetlink.h>
 #include <linux/if_arp.h>
 #include <linux/ip.h>
@@ -57,7 +59,9 @@
 #define NP_IPV6	1		/* Internet Protocol V6 */
 #define NP_IPX	2		/* IPX protocol */
 #define NP_AT	3		/* Appletalk protocol */
-#define NUM_NP	4		/* Number of NPs. */
+#define NP_BRIDGE	4	/* Bridged LAN packets */
+#define NP_BPDU_IEEE	5	/* IEEE 802.1 (D or G) bridge PDU */
+#define NUM_NP	6		/* Number of NPs. */
 
 #define MPHDRLEN	6	/* multilink protocol header length */
 #define MPHDRLEN_SSN	4	/* ditto with short sequence numbers */
@@ -88,6 +92,8 @@
 
 #define ROUNDUP(n, x)		(((n) + (x) - 1) / (x))
 
+struct bcp_device;
+
 /*
  * Data structure describing one ppp unit.
  * A ppp unit corresponds to a ppp network interface device
@@ -116,6 +122,7 @@
 	unsigned long	last_xmit;	/* jiffies when last pkt sent 9c */
 	unsigned long	last_recv;	/* jiffies when last pkt rcvd a0 */
 	struct net_device *dev;		/* network interface device a4 */
+	struct bcp_device *bcp;		/* net. interface for bridging */
 #ifdef CONFIG_PPP_MULTILINK
 	int		nxchan;		/* next channel to send something on */
 	u32		nxseq;		/* next sequence number to send */
@@ -131,6 +138,28 @@
 #endif /* CONFIG_PPP_FILTER */
 };
 
+struct bcp_device {
+	struct net_device dev;		/* ->priv points to struct ppp */
+	struct net_device_stats stats;	/* statistics */
+};
+
+/* this looks better than a cast in the code */
+static __inline__ struct bcp_device* dev_to_bcp(struct net_device* dev)
+{
+	return (struct bcp_device*)dev;
+}
+
+/* this looks better than a cast in the code */
+static __inline__ struct net_device* bcp_to_dev(struct bcp_device* bcp)
+{
+	return (struct net_device*)bcp;
+}
+
+static __inline__ struct ppp* bcp_to_ppp(struct bcp_device* bcp)
+{
+	return bcp ? (struct ppp *)bcp_to_dev(bcp)->priv : NULL;
+}
+
 /*
  * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
  * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
@@ -237,6 +266,9 @@
 /* Prototypes. */
 static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
 				unsigned int cmd, unsigned long arg);
+static int ppp_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int ppp_common_start_xmit(int npi, struct sk_buff *skb,
+				 struct net_device *dev);
 static void ppp_xmit_process(struct ppp *ppp);
 static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
 static void ppp_push(struct ppp *ppp);
@@ -268,6 +300,12 @@
 static int ppp_connect_channel(struct channel *pch, int unit);
 static int ppp_disconnect_channel(struct channel *pch);
 static void ppp_destroy_channel(struct channel *pch);
+static int ppp_create_bcp(struct ppp *ppp);
+static void ppp_shutdown_bcp(struct ppp *ppp);
+static struct net_device_stats *bcp_net_stats(struct net_device *dev);
+static int bcp_net_ioctl(struct net_device *, struct ifreq *ifr, int cmd);
+static int bcp_net_change_mtu(struct net_device *dev, int new_mtu);
+static int bcp_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* Translates a PPP protocol number to a NP index (NP == network protocol) */
 static inline int proto_to_npindex(int proto)
@@ -281,6 +319,10 @@
 		return NP_IPX;
 	case PPP_AT:
 		return NP_AT;
+	case PPP_BRIDGE:
+		return NP_BRIDGE;
+	case PPP_BPDU_IEEE:
+		return NP_BPDU_IEEE;
 	}
 	return -EINVAL;
 }
@@ -291,6 +333,8 @@
 	PPP_IPV6,
 	PPP_IPX,
 	PPP_AT,
+	PPP_BRIDGE,
+	PPP_BPDU_IEEE,
 };
 	
 /* Translates an ethertype into an NP index */
@@ -318,6 +362,13 @@
 	ETH_P_PPPTALK,
 };
 
+/* IEEE 802.1D bridge PDU destination address */
+static const __u8 IEEE_802_1D_DSTADDR[ETH_ALEN] = { 1, 0x80, 0xC2, 0, 0, 0 };
+
+/* A few bytes that are present when and IEEE 802.1D bridge PDU is
+ * packed into an IEEE 802.3 frame. */
+static const __u8 IEEE_802_1D_802_3_HDR[] = { 0x42, 0x42, 0x03 };
+
 /*
  * Locking shorthand.
  */
@@ -440,6 +491,10 @@
 		goto err1;
 	}
 
+	/* Increase the priority of control protocol packets so that
+	 * they are not impeded by plain old data packets. */
+	skb->priority = TC_PRIO_CONTROL;
+
 	skb_queue_tail(&pf->xq, skb);
 
 	switch (pf->kind) {
@@ -642,7 +697,20 @@
 			if (copy_to_user((void *) arg, &npi, sizeof(npi)))
 				break;
 		} else {
+			if (i == NP_BRIDGE) {
+				if (npi.mode == NPMODE_PASS) {
+					err = ppp_create_bcp(ppp);
+					if (err < 0)
+						break;
+					ppp->npmode[i] = npi.mode;
+				} else {
+					ppp->npmode[NP_BRIDGE] = npi.mode;
+					ppp->npmode[NP_BPDU_IEEE] = npi.mode;
+					ppp_shutdown_bcp(ppp);
+				}
+			} else {
 			ppp->npmode[i] = npi.mode;
+			}
 			/* we may be able to transmit more packets now (??) */
 			netif_wake_queue(ppp->dev);
 		}
@@ -800,11 +868,18 @@
 static int
 ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	int npi = ethertype_to_npindex(ntohs(skb->protocol));
+	return ppp_common_start_xmit(npi, skb, dev);
+}
+
+/* Called by PPP and BCP transmission routines. */
+static int
+ppp_common_start_xmit(int npi, struct sk_buff *skb, struct net_device *dev)
+{
 	struct ppp *ppp = (struct ppp *) dev->priv;
-	int npi, proto;
+	int proto;
 	unsigned char *pp;
 
-	npi = ethertype_to_npindex(ntohs(skb->protocol));
 	if (npi < 0)
 		goto err1;
 
@@ -1104,7 +1179,8 @@
 
 		spin_lock_bh(&pch->downl);
 		if (pch->chan) {
-			if (pch->chan->ops->start_xmit(pch->chan, skb))
+			if (skb_queue_len(&pch->file.xq) == 0
+			    && pch->chan->ops->start_xmit(pch->chan, skb))
 				ppp->xmit_pending = 0;
 		} else {
 			/* channel got unregistered */
@@ -1411,6 +1487,104 @@
 		slhc_toss(ppp->vj);
 }
 
+/* Decapsulate a packet from BCP. */
+static __inline__ struct sk_buff* bcp_decap(struct sk_buff *skb)
+{
+	/** @todo cope with PADS field in BCP header? */
+
+	struct net_device *const dev = skb->dev;
+	__u8 bcp_flags;
+
+        /* Make sure that the data we examine are present. */
+	if (!pskb_may_pull(skb, BCP_802_3_HDRLEN))
+		goto drop;
+
+	/* Currently, only 802.3/Ethernet bridging is supported. */
+	if (((struct bcp_hdr*)skb->data)->mactype != BCP_MAC_802_3)
+		goto drop;
+
+	bcp_flags = ((struct bcp_hdr*)skb->data)->flags;
+
+	skb_pull(skb, BCP_802_3_HDRLEN);
+	skb->mac.raw = skb->data;
+
+	/* remove LAN FCS */
+	if (bcp_flags & BCP_LAN_FCS)
+	{
+		if (skb->len < ETH_FCS_LEN)
+			goto drop;
+		skb_trim(skb, skb->len - ETH_FCS_LEN);
+	}
+
+	/* decompress "Tinygrams" */
+	if ((bcp_flags & BCP_ZERO_PAD) && (skb->len < ETH_ZLEN)) {
+		const int pad_len = ETH_ZLEN - skb->len;
+
+		if ((skb_tailroom(skb) < pad_len) || skb_cloned(skb)) {
+			struct sk_buff *old_skb = skb;
+			skb = skb_copy_expand(old_skb, 0, pad_len, GFP_ATOMIC);
+			kfree_skb(old_skb);
+			if (!skb)
+				goto dropped;
+		}
+
+		skb_put(skb, pad_len);
+		memset(skb->tail - pad_len, 0, pad_len);
+	}
+
+	/* Parse the ethernet header.  Because of the increased
+	 * hard_header_len, eth_type_trans() skips too much, so push
+	 * some back afterward. */
+	skb->protocol = eth_type_trans(skb, dev);
+	skb_push(skb, dev->hard_header_len - ETH_HLEN);
+
+	return skb;
+
+ drop:
+	kfree_skb(skb);
+ dropped:
+	return 0;
+}
+
+/* Decapsulate an IEEE 802.1 (D or G) PDU. */
+static __inline__ struct sk_buff* bpdu_ieee_decap(struct sk_buff *skb)
+{
+	struct net_device *const dev = skb->dev;
+	struct ethhdr *eth;
+
+	if ((skb_headroom(skb) < ETH_HLEN + sizeof(IEEE_802_1D_802_3_HDR))
+	    || skb_cloned(skb)) {
+		struct sk_buff *old_skb = skb;
+		skb = skb_copy_expand(old_skb,
+				      ETH_HLEN + sizeof(IEEE_802_1D_802_3_HDR),
+				      0, GFP_ATOMIC);
+		kfree_skb(old_skb);
+		if (!skb)
+			goto dropped;
+	}
+
+	/* Prepend the 802.3 SAP and control byte. */
+	memcpy(skb_push(skb, sizeof(IEEE_802_1D_802_3_HDR)),
+	       IEEE_802_1D_802_3_HDR, sizeof(IEEE_802_1D_802_3_HDR));
+
+	/* Prepend an ethernet header. */
+	eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+	memcpy(eth->h_dest, IEEE_802_1D_DSTADDR, ETH_ALEN);
+	memset(eth->h_source, 0, ETH_ALEN);
+	eth->h_proto = htons(skb->len - ETH_HLEN);
+
+	/* Parse the ethernet header.  Because of the increased
+	 * hard_header_len, eth_type_trans() skips too much, so push
+	 * some back afterward. */
+	skb->protocol = eth_type_trans(skb, dev);
+	skb_push(skb, dev->hard_header_len - ETH_HLEN);
+
+	return skb;
+
+ dropped:
+	return 0;
+}
+
 static void
 ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
 {
@@ -1488,6 +1662,7 @@
 
 	} else {
 		/* network protocol frame - give it to the kernel */
+		struct net_device *rxdev;
 
 #ifdef CONFIG_PPP_FILTER
 		/* check if the packet passes the pass and active filters */
@@ -1511,22 +1686,58 @@
 		ppp->last_recv = jiffies;
 #endif /* CONFIG_PPP_FILTER */
 
-		if ((ppp->dev->flags & IFF_UP) == 0
-		    || ppp->npmode[npi] != NPMODE_PASS) {
+		switch (npi) {
+		case NP_BRIDGE:
+		case NP_BPDU_IEEE:
+			rxdev = bcp_to_dev(ppp->bcp);
+			break;
+		default:
+			rxdev = ppp->dev;
+			break;
+		}
+
+		if ((ppp->npmode[npi] != NPMODE_PASS)
+		    || !rxdev
+		    || (rxdev->flags & IFF_UP) == 0) {
 			kfree_skb(skb);
 		} else {
 			skb_pull(skb, 2);	/* chop off protocol */
-			skb->dev = ppp->dev;
+			skb->dev = rxdev;
+
+			switch (npi) {
+			case NP_BRIDGE:
+				skb = bcp_decap(skb);
+				if (!skb) {
+					++ppp->bcp->stats.rx_dropped;
+					goto dropped;
+				}
+				++ppp->bcp->stats.rx_packets;
+				break;
+
+			case NP_BPDU_IEEE:
+				skb = bpdu_ieee_decap(skb);
+				if (!skb) {
+					++ppp->bcp->stats.rx_dropped;
+					goto dropped;
+				}
+				++ppp->bcp->stats.rx_packets;
+				break;
+
+			default:
 			skb->protocol = htons(npindex_to_ethertype[npi]);
 			skb->mac.raw = skb->data;
+				break;
+			}
+
 			netif_rx(skb);
-			ppp->dev->last_rx = jiffies;
+			rxdev->last_rx = jiffies;
 		}
 	}
 	return;
 
  err:
 	kfree_skb(skb);
+ dropped:
 	ppp_receive_error(ppp);
 }
 
@@ -2255,6 +2466,8 @@
 	ppp->file.hdrlen = PPP_HDRLEN - 2;	/* don't count proto bytes */
 	for (i = 0; i < NUM_NP; ++i)
 		ppp->npmode[i] = NPMODE_PASS;
+	ppp->npmode[NP_BRIDGE] = NPMODE_DROP;
+	ppp->npmode[NP_BPDU_IEEE] = NPMODE_DROP;
 	INIT_LIST_HEAD(&ppp->channels);
 	spin_lock_init(&ppp->rlock);
 	spin_lock_init(&ppp->wlock);
@@ -2316,6 +2529,8 @@
 {
 	struct net_device *dev;
 
+	ppp_shutdown_bcp(ppp);
+
 	down(&all_ppp_sem);
 	ppp_lock(ppp);
 	dev = ppp->dev;
@@ -2620,6 +2835,230 @@
 	*pmap = NULL;
 }
 
+/*
+ * Create interface for bridging.
+ */
+static int
+ppp_create_bcp(struct ppp *ppp)
+{
+	struct bcp_device *bcp;
+	struct net_device *dev;
+	int ret;
+
+	/* If it already exists, ignore the request. */
+	if (ppp->bcp)
+		return 0;
+
+	/* create a new BCP dev */
+	ret = -ENOMEM;
+	bcp = kmalloc(sizeof(struct bcp_device), GFP_KERNEL);
+	if (!bcp)
+		goto err;
+	memset(bcp, 0, sizeof(struct bcp_device));
+	dev = bcp_to_dev(bcp);
+
+	ether_setup(dev);
+
+	dev->hard_header_len = ppp->dev->hard_header_len
+		+ BCP_802_3_HDRLEN + ETH_HLEN;
+
+	/* ETH_FCS_LEN is not subtracted from the PPP MTU here because
+	 * bcp_start_xmit() never adds the FCS. */
+	dev->mtu = ppp->dev->mtu - (BCP_802_3_HDRLEN + ETH_HLEN);
+
+	if (dev->mtu > ETH_DATA_LEN)
+		dev->mtu = ETH_DATA_LEN;
+
+	dev->hard_start_xmit = bcp_start_xmit;
+	dev->get_stats = bcp_net_stats;
+	dev->do_ioctl = bcp_net_ioctl;
+	dev->change_mtu = bcp_net_change_mtu;
+	dev->tx_queue_len = 0; /* let PPP device queue packets */
+	dev->features |= NETIF_F_DYNALLOC;
+	sprintf(dev->name, "bcp%d", ppp->file.index);
+
+	rtnl_lock();
+	ret = register_netdevice(dev);
+	rtnl_unlock();
+	if (ret != 0) {
+		printk(KERN_ERR "PPP: couldn't register device %s (%d)\n",
+		       dev->name, ret);
+		goto err;
+	}
+	else {
+		/* Associate the devices.  Since register_netdevice()
+		 * would fail if there were already a bcp<n> device
+		 * registered for this ppp<n>, there is no need to
+		 * worry about overwriting a valid ppp->bcp.dev. */
+		ppp_lock(ppp);
+		ppp->bcp = bcp;
+		dev->priv = ppp;
+		ppp_unlock(ppp);
+	}
+
+	return 0;
+
+ err:
+	if (bcp)
+		kfree(bcp);
+	return ret;
+}
+
+/*
+ * Take down a bcp interface.
+ */
+static void
+ppp_shutdown_bcp(struct ppp *ppp)
+{
+	struct bcp_device *bcp;
+
+	ppp_lock(ppp);
+	bcp = ppp->bcp;
+	ppp->bcp = 0;
+	ppp_unlock(ppp);
+
+	if (bcp) {
+		rtnl_lock();
+		dev_close(bcp_to_dev(bcp));
+		unregister_netdevice(bcp_to_dev(bcp));
+		rtnl_unlock();
+	}
+}
+
+static struct net_device_stats *
+bcp_net_stats(struct net_device *dev)
+{
+	struct bcp_device *const bcp = dev_to_bcp(dev);
+	return &bcp->stats;
+}
+
+static int
+bcp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+static int
+bcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* MTU is negotiated by the PPP daemon and should not be changed. */
+	return -EOPNOTSUPP;
+}
+
+/* input:  ethernet frame in non-shared skbuff
+ * output: bcp-encapsulated frame in non-shared and non-cloned skbuff
+ */
+static __inline__
+struct sk_buff* bcp_encap(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bcp_hdr *bhdr;
+	int pad_len;
+
+	/* @todo Calculate FCS?  NB: If you add this, be sure to
+	 * change the MTU calculation in ppp_create_bcp() to account
+	 * for it. */
+
+	/* There is currently no communication from pppd regarding the
+	 * peer's Tinygram-Compression option.  Therefore, we always
+	 * pad short frames to minimum Ethernet size in case the peer
+	 * does not support Tinygrams. */
+	pad_len = (skb->len < ETH_ZLEN) ? (ETH_ZLEN - skb->len) : 0;
+
+	/* Add a BCP header and pad to minimum frame size.
+	 *
+	 * Observations:
+	 *   - Tailroom is always inadequate for short packets like ARP.
+	 *   - Headroom is usually adequate, because the kernel usually
+	 *     checks dev->hard_header_len; however, it is possible to
+	 *     be given a buffer that was originally allocated for another
+	 *     device.  (I have not seen it during testing.)
+	 *   - It is not possible for a buffer to be shared, because
+	 *     bcp_start_xmit() calls skb_share_check().
+	 *   - I do not know when a buffer might be cloned; perhaps it
+	 *     is possible in a bridging application where the same
+	 *     packet needs to be transmitted to multiple interfaces.
+	 */
+	if ((skb_tailroom(skb) < pad_len)
+	    || (skb_headroom(skb) < dev->hard_header_len)
+	    || skb_cloned(skb)) {
+		struct sk_buff *old_skb = skb;
+		skb = skb_copy_expand(old_skb,
+				      dev->hard_header_len, pad_len,
+				      GFP_ATOMIC);
+		kfree_skb(old_skb);
+		if (!skb)
+			goto dropped;
+	}
+
+	bhdr = (struct bcp_hdr*)skb_push(skb, BCP_802_3_HDRLEN);
+	bhdr->flags = 0;		/* no LAN FCS, not a tinygram */
+	bhdr->mactype = BCP_MAC_802_3;	/* 802.3 / Ethernet */
+
+	return skb;
+
+ dropped:
+	return 0;
+}
+
+/* input:  BPDU ethernet frame in non-shared skbuff
+ * output: naked BPDU in non-shared and non-cloned skbuff
+ */
+static __inline__
+struct sk_buff* bpdu_ieee_encap(struct sk_buff *skb, struct net_device *dev)
+{
+	/* pull off the link header */
+	skb_pull(skb, ETH_HLEN + sizeof(IEEE_802_1D_802_3_HDR));
+
+	if (skb_cloned(skb)) {
+		struct sk_buff *old_skb = skb;
+		skb = skb_copy_expand(old_skb, dev->hard_header_len, 0,
+				      GFP_ATOMIC);
+		kfree_skb(old_skb);
+	}
+
+	return skb;
+}
+
+static int
+bcp_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bcp_device *const bcp = dev_to_bcp(dev);
+	struct ppp *const ppp = bcp_to_ppp(bcp);
+	int npi;
+
+	/* make sure we can push/pull without side effects */
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (!skb)
+		goto dropped;
+
+	/* When configured to encapsulate 802.1D bridge PDUs in the
+	 * obsolete manner of RFC 1638, do it.  Otherwise, send it
+	 * like any other packet. */
+	if ((ppp->npmode[NP_BPDU_IEEE] == NPMODE_PASS) &&
+	    pskb_may_pull(skb, ETH_HLEN + sizeof(IEEE_802_1D_802_3_HDR)) &&
+	    (0 == memcmp(skb->data, IEEE_802_1D_DSTADDR, ETH_ALEN)) &&
+	    (0 == memcmp(&skb->data[ETH_HLEN], IEEE_802_1D_802_3_HDR,
+			 sizeof(IEEE_802_1D_802_3_HDR)))) {
+		skb = bpdu_ieee_encap(skb, dev);
+		npi = NP_BPDU_IEEE;
+	} else {
+		skb = bcp_encap(skb, dev);
+		npi = NP_BRIDGE;
+	}
+
+	if (!skb)
+		goto dropped;
+
+	/* send packet through the PPP interface */
+	skb->dev = ppp->dev;
+	++bcp->stats.tx_packets;
+	return ppp_common_start_xmit(npi, skb, skb->dev);
+
+ dropped:
+	++bcp->stats.tx_dropped;
+	return 0;
+}
+
 /* Module/initialization stuff */
 
 module_init(ppp_init);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Bridge] (no subject)
  2004-02-25 14:30 Dan Eble
@ 2004-02-25 16:27 ` Stephen Hemminger
  0 siblings, 0 replies; 12+ messages in thread
From: Stephen Hemminger @ 2004-02-25 16:27 UTC (permalink / raw)
  To: dane; +Cc: john.wise, bridge

On Wed, 25 Feb 2004 09:30:07 -0500 (EST)
Dan Eble <dane@aiinet.com> wrote:

> Attached is the BCP patch for pppd 2.4.1.  In addition to BCP, there are
> also a few changes to support a pppd plugin for devices using the kernel
> generic HDLC layer.  The plugin itself is not included in this patch.
> 
> There were some changes to log messages that I tried to remove by hand.  
> The patch applies cleanly and compiles on 686.  It has never been tested
> on 686, though, only on powerpc.  I would appreciate hearing about any
> difficulties you encounter.
> 
> You must patch the kernel too.  I will send those changes in a separate
> mail.
> 
> -- 
> Dan Eble <dane@aiinet.com>  _____  .
> Software Engineer          |  _  |/|
> Applied Innovation Inc.    | |_| | |
> http://www.aiinet.com/     |__/|_|_|

Could you send this to the ppp list as well?

Also, it is old style K&R C code, perhaps you could convert it to current taste.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2004-03-12  5:17 申锟铠
  0 siblings, 0 replies; 12+ messages in thread
From: 申锟铠 @ 2004-03-12  5:17 UTC (permalink / raw)
  To: bridge@osdl.org


[-- Attachment #1.1: Type: text/plain, Size: 1272 bytes --]

 hi!
 My linux is 2.4.20, I have two Interl netcard, driver is e100.o, when I add eth0 and eth1 to br0, all is right, then I remove eth0 or eth1 from br0, then add, remove,add. repeat some times, my kernel panic, screen show dev.c: call skb_checksum_help(): 947 conduce this problem.

    skb_checksum_help() as follows:

struct sk_buff * skb_checksum_help(struct sk_buff *skb)
{
 int offset;
 unsigned int csum;
 offset = skb->h.raw - skb->data;
 if (offset > (int)skb->len)
  BUG();
 csum = skb_checksum(skb, offset, skb->len-offset, 0);
 offset = skb->tail - skb->h.raw;
 if (offset <= 0)
  BUG();
 if (skb->csum+2 > offset)
  BUG();    // this is the 947 line in dev.c    
 *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
 skb->ip_summed = CHECKSUM_NONE;
 return skb;
} 

 
     before kernel panic,somtimes, when I use ifconfig config eth1 ip address,appear a error: Multicast setup failed, then my compute can't ping any other host. I find "Multicast setup failed" in e100's src(e100_main.c).
     while I replace eepro100.o with e100.o, all is right, no panic, and no "Multicast setup failed".
    but I want use e100.o, Could you tell me how to resolve this problem?
    
    thanks!

                    Kunkai Shen

                   E-Mail: skkwish@263.net

[-- Attachment #1.2: Type: text/html, Size: 5486 bytes --]

[-- Attachment #2: SpamAssassinReport.txt --]
[-- Type: text/plain, Size: 1276 bytes --]

This mail is probably spam.  The original message has been attached
along with this report, so you can recognize or block similar unwanted
mail in future.  See http://spamassassin.org/tag/ for more details.

Content preview:  --====\02_Dragon738264534364_====Content-Type:
  text/plain; charset="GB2312" Content-Transfer-Encoding: 7bit hi! My
  linux is 2.4.20, I have two Interl netcard, driver is e100.o, when I
  add eth0 and eth1 to br0, all is right, then I remove eth0 or eth1 from
  br0, then add, remove,add. repeat some times, my kernel panic, screen
  show dev.c: call skb_checksum_help(): 947 conduce this problem. [...] 

Content analysis details:   (5.40 points, 5 required)
HTML_40_50         (1.1 points)  BODY: Message is 40% to 50% HTML
HTML_FONT_FACE_ODD (0.1 points)  BODY: HTML font face is not a commonly used face
HTML_MESSAGE       (0.1 points)  BODY: HTML included in message
HTML_FONT_BIG      (0.2 points)  BODY: FONT Size +2 and up or 3 and up
HTML_TAG_EXISTS_TBODY (0.5 points)  BODY: HTML has "tbody" tag
MIME_LONG_LINE_QP  (0.3 points)  RAW: Quoted-printable line longer than 76 characters
MSG_ID_ADDED_BY_MTA_2 (1.0 points)  'Message-Id' was added by a relay (2)
CHARSET_FARAWAY_HEADERS (2.1 points)  A foreign language charset used in headers



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2004-04-08 13:44 Small, Jim
  0 siblings, 0 replies; 12+ messages in thread
From: Small, Jim @ 2004-04-08 13:44 UTC (permalink / raw)
  To: bridge

Thanks to Santiago (Santi) Leon for providing the following fix to me to
enable bridging on the Sparc64 platform.  I have tested it under Debian
unstable, using Kernel 2.4.25, and bridge-utils-0.9.6.tar.gz.

The fix is as follows:
Download bridge-utils-0.9.6.tar.gz source from bridge.sourceforge.net, untar
it, edit 
bridge-utils/libbridge/libbridge_devif.c and search for a line that has
this:
  return ioctl(br_socket_fd, SIOCDEVPRIVATE + 3, &ifr);
and replace it with this:
  return ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
(basically just remove the +3)... run make and again and try:

(After you rebuild the bridge utilities, these should work beautifully!)
bridge-utils/brctl/brctl addbr br0
bridge-utils/brctl/brctl adddif br0 eth0
bridge-utils/brctl/brctl show

Santi mentioned that the newer kernels don't make SIOCDEVPRIVATE+3 a 64-bit
compatible 
ioctl and that's why it doesn't work on the Sparc64 architecture.  He also
mentioned that the same fix works for the PowerPC64 Architecture so it might
help for other 64bit architecture platforms.

Note also that this is not scheduled to be fixed in bridge-tuils-0.9.7, so
for now this seems to be the best work around for 64bit platforms.

Here is a diff too:
# diff -Nru bridge-utils/libbridge/libbridge_devif.c
bridge-utils/libbridge/libbridge_devif.c.orig 
--- bridge-utils/libbridge/libbridge_devif.c    2004-04-01
21:10:55.000000000 -0500
+++ bridge-utils/libbridge/libbridge_devif.c.orig       2002-01-16
07:04:45.000000000 -0500
@@ -56,7 +56,7 @@
        memcpy(ifr.ifr_name, br->ifname, IFNAMSIZ);
        ((unsigned long long *)(&ifr.ifr_data))[0] = (unsigned long
long)(unsigned long)args;
 
-       return ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+       return ioctl(br_socket_fd, SIOCDEVPRIVATE + 3, &ifr);
 }
 #endif

Thanks again Santi,
   <> Jim


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2004-12-10  8:22 walou
  0 siblings, 0 replies; 12+ messages in thread
From: walou @ 2004-12-10  8:22 UTC (permalink / raw)
  To: bridge

Hi,
Is it possible to bridge a ppp connection so that another machine gets
the public IP address ?

Klaas



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2005-03-17 17:30 dyf
  2005-03-17 17:45 ` Stephen Hemminger
  0 siblings, 1 reply; 12+ messages in thread
From: dyf @ 2005-03-17 17:30 UTC (permalink / raw)
  To: bridge

hi:
i want to build a bridge through my ethernet card and my wireless device,which connects with
the mainboard by synchronization serial controller.

anybody can give me some ideas? 

and can i get the idea in this maillist??

thanks for ur answer!!
 				

        dyf
        duziziii@163.com
          2005-03-18


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Bridge] (no subject)
  2005-03-17 17:30 dyf
@ 2005-03-17 17:45 ` Stephen Hemminger
  0 siblings, 0 replies; 12+ messages in thread
From: Stephen Hemminger @ 2005-03-17 17:45 UTC (permalink / raw)
  To: dyf; +Cc: bridge

On Fri, 18 Mar 2005 01:30:43 +0800
"dyf" <duziziii@163.com> wrote:

> hi:
> i want to build a bridge through my ethernet card and my wireless device,which connects with
> the mainboard by synchronization serial controller.
> 
> anybody can give me some ideas? 
> 
> and can i get the idea in this maillist??


Read the FAQ, at http://bridge.sourceforge.net
Most wireless devices, won't work as bridges because they can't send with different
Ethernet source address.  Also, devices that don't use Ethernet framing (like Irda, PPP)
will not work in a bridge.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
       [not found] <200603032000.k23K05Db002837@smtp.osdl.org>
@ 2006-03-04  1:31 ` zhangliang
  0 siblings, 0 replies; 12+ messages in thread
From: zhangliang @ 2006-03-04  1:31 UTC (permalink / raw)
  To: bridge


Modify your MAC address? I think you can.
-----邮件原件-----
发件人: bridge-bounces@lists.osdl.org [mailto:bridge-bounces@lists.osdl.org]
代表 bridge-request@lists.osdl.org
发送时间: 2006年3月4日 4:01
收件人: bridge@lists.osdl.org
主题: Bridge Digest, Vol 31, Issue 2

Send Bridge mailing list submissions to
	bridge@lists.osdl.org

To subscribe or unsubscribe via the World Wide Web, visit
	https://lists.osdl.org/mailman/listinfo/bridge
or, via email, send a message with subject or body 'help' to
	bridge-request@lists.osdl.org

You can reach the person managing the list at
	bridge-owner@lists.osdl.org

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Bridge digest..."


Today's Topics:

   1. Re: bridge MAC address (Stephen Hemminger)
   2. RE: bridge MAC address (Levi Ariel-BAL023)
   3. Re: bridge MAC address (Stephen Hemminger)


----------------------------------------------------------------------

Message: 1
Date: Thu, 2 Mar 2006 12:31:02 -0800
From: Stephen Hemminger <shemminger@osdl.org>
Subject: Re: [Bridge] bridge MAC address
To: "Levi Ariel-BAL023" <ariel.levi@motorola.com>
Cc: bridge@lists.osdl.org
Message-ID: <20060302123102.04a82598@localhost.localdomain>
Content-Type: text/plain; charset=US-ASCII

On Thu, 2 Mar 2006 20:20:38 +0200
"Levi Ariel-BAL023" <ariel.levi@motorola.com> wrote:

> Hi,
> 
>  
> 
> I have notice that the bridge gets the "lowest" MAC address of its
> interfaces.
> 
> Function: br_stp_recalculate_bridge_id()
> 
>  
> 
> Is there a meaning behind this or not?
> 
>  
> 
> Thanks, 
> 
>  Ariel 
> 

It's part of the Spanning Tree Protocol in the 802.1d standard.
In later kernels you can reset the address to be the same as any
of the interfaces being bridged.

------------------------------

Message: 2
Date: Fri, 3 Mar 2006 10:03:04 +0200
From: "Levi Ariel-BAL023" <ariel.levi@motorola.com>
Subject: RE: [Bridge] bridge MAC address
To: "Stephen Hemminger" <shemminger@osdl.org>
Cc: bridge@lists.osdl.org
Message-ID:
	<37A954DFE3784244A7831AF8412790B5D18ECF@zil01exm61.ds.mot.com>
Content-Type: text/plain;	charset="us-ascii"


Stephen,

Thanks for your quick respond.

What do you mean by "later kernels"? I curently use kernel 2.4.20
Can I add a ioctl that enables modifying the bridge MAC address?

Thanks,
  Ariel


-----Original Message-----
From: Stephen Hemminger [mailto:shemminger@osdl.org] 
Sent: Thursday, March 02, 2006 10:31 PM
To: Levi Ariel-BAL023
Cc: bridge@lists.osdl.org
Subject: Re: [Bridge] bridge MAC address

On Thu, 2 Mar 2006 20:20:38 +0200
"Levi Ariel-BAL023" <ariel.levi@motorola.com> wrote:

> Hi,
> 
>  
> 
> I have notice that the bridge gets the "lowest" MAC address of its 
> interfaces.
> 
> Function: br_stp_recalculate_bridge_id()
> 
>  
> 
> Is there a meaning behind this or not?
> 
>  
> 
> Thanks,
> 
>  Ariel
> 

It's part of the Spanning Tree Protocol in the 802.1d standard.
In later kernels you can reset the address to be the same as any
of the interfaces being bridged.


------------------------------

Message: 3
Date: Fri, 3 Mar 2006 07:38:09 -0800
From: Stephen Hemminger <shemminger@osdl.org>
Subject: Re: [Bridge] bridge MAC address
To: "Levi Ariel-BAL023" <ariel.levi@motorola.com>
Cc: bridge@lists.osdl.org
Message-ID: <20060303073809.2028af01@localhost.localdomain>
Content-Type: text/plain; charset=US-ASCII

On Fri, 3 Mar 2006 10:03:04 +0200
"Levi Ariel-BAL023" <ariel.levi@motorola.com> wrote:

> 
> Stephen,
> 
> Thanks for your quick respond.
> 
> What do you mean by "later kernels"? I curently use kernel 2.4.20
> Can I add a ioctl that enables modifying the bridge MAC address?
> 
> Thanks,
>   Ariel
> 

I think I added it for 2.6.15

------------------------------

_______________________________________________
Bridge mailing list
Bridge@lists.osdl.org
https://lists.osdl.org/mailman/listinfo/bridge


End of Bridge Digest, Vol 31, Issue 2
*************************************




^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2007-07-06  7:37 EBI
  0 siblings, 0 replies; 12+ messages in thread
From: EBI @ 2007-07-06  7:37 UTC (permalink / raw)
  To: bridge



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2007-07-18 13:06 rajneesh rana
  0 siblings, 0 replies; 12+ messages in thread
From: rajneesh rana @ 2007-07-18 13:06 UTC (permalink / raw)
  To: bridge

[-- Attachment #1: Type: text/plain, Size: 301 bytes --]

I'm trying to trap ethernet frames from a user process over the wire,
using the linux tap device. I see a lot of docs/threads about using tun
device, but none for tap device.

I am able to open Tap device and attach it to bridge but getting no clue how
to read and write  data from tap device.

thanx

[-- Attachment #2: Type: text/html, Size: 337 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Bridge] (no subject)
@ 2011-03-26 15:38 debasis das
  0 siblings, 0 replies; 12+ messages in thread
From: debasis das @ 2011-03-26 15:38 UTC (permalink / raw)
  To: bindu, bipinbarik, bipinbarik, biswojit.dash, rajesh.c, bridge,
	burnali.das

http%3A%2F%2Fwww%2Ealiantedizioni%2Eit%2F23i42%2Ehtml

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-03-26 15:38 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-06  7:37 [Bridge] (no subject) EBI
  -- strict thread matches above, loose matches on Subject: below --
2011-03-26 15:38 debasis das
2007-07-18 13:06 rajneesh rana
     [not found] <200603032000.k23K05Db002837@smtp.osdl.org>
2006-03-04  1:31 ` zhangliang
2005-03-17 17:30 dyf
2005-03-17 17:45 ` Stephen Hemminger
2004-12-10  8:22 walou
2004-04-08 13:44 Small, Jim
2004-03-12  5:17 申锟铠
2004-02-25 15:36 Dan Eble
2004-02-25 14:30 Dan Eble
2004-02-25 16:27 ` Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox