Subject: in-kernel PPPoE server (include patch)
To: None <tech-net@netbsd.org>
From: Masaru OKI <oki@netbsd.org>
List: tech-net
Date: 06/12/2003 14:55:40
Hi,
I implement in-kernel PPPoE server code.
Usage:
ifconfig pppoe0 create
ifconfig pppoe0 link0
pppoectl -e xxx0 pppoe0
pppoectl pppoe0 hisauthproto=chap hisauthname=NAME hisautosecret=SECRET
ifconfig pppoe0 MYADDRESS remote REMOTEADDRESS
comments?
Index: if_pppoe.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_pppoe.c,v
retrieving revision 1.42
diff -u -r1.42 if_pppoe.c
--- if_pppoe.c 2003/03/01 15:50:15 1.42
+++ if_pppoe.c 2003/06/12 05:23:58
@@ -119,6 +119,11 @@
#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */
#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */
+#ifdef PPPOE_SERVER
+/* from if_spppsubr.c */
+#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */
+#endif
+
struct pppoe_softc {
struct sppp sc_sppp; /* contains a struct ifnet as first element */
LIST_ENTRY(pppoe_softc) sc_list;
@@ -132,6 +137,10 @@
char *sc_concentrator_name; /* if != NULL: requested concentrator id */
u_int8_t *sc_ac_cookie; /* content of AC cookie we must echo back */
size_t sc_ac_cookie_len; /* length of cookie data */
+#ifdef PPPOE_SERVER
+ u_int8_t *sc_hunique; /* content of host unique we must echo back */
+ size_t sc_hunique_len; /* length of host unique */
+#endif
struct callout sc_timeout; /* timeout while not in session state */
int sc_padi_retried; /* number of PADI retries already done */
int sc_padr_retried; /* number of PADR retries already done */
@@ -173,6 +182,10 @@
/* sending actual protocol controll packets */
static int pppoe_send_padi(struct pppoe_softc *);
static int pppoe_send_padr(struct pppoe_softc *);
+#ifdef PPPOE_SERVER
+static int pppoe_send_pado(struct pppoe_softc *);
+static int pppoe_send_pads(struct pppoe_softc *);
+#endif
static int pppoe_send_padt(struct ifnet *, u_int, const u_int8_t *);
/* raw output */
@@ -389,6 +402,10 @@
const char *err_msg = NULL;
u_int8_t *ac_cookie;
size_t ac_cookie_len;
+#ifdef PPPOE_SERVER
+ u_int8_t *hunique;
+ size_t hunique_len;
+#endif
struct pppoehdr *ph;
struct pppoetag *pt;
struct mbuf *n;
@@ -405,6 +422,10 @@
ac_cookie = NULL;
ac_cookie_len = 0;
+#ifdef PPPOE_SERVER
+ hunique = NULL;
+ hunique_len = 0;
+#endif
session = 0;
if (m->m_pkthdr.len - off <= PPPOE_HEADERLEN) {
printf("pppoe: packet too short: %d\n", m->m_pkthdr.len);
@@ -468,6 +489,10 @@
m = NULL;
goto done;
}
+#ifdef PPPOE_SERVER
+ hunique = mtod(n, caddr_t) + noff;
+ hunique_len = len;
+#endif
sc = pppoe_find_softc_by_hunique(mtod(n, caddr_t) + noff,
len, m->m_pkthdr.rcvif);
break;
@@ -505,9 +530,81 @@
breakbreak:;
switch (ph->code) {
case PPPOE_CODE_PADI:
+#ifdef PPPOE_SERVER
+ /*
+ * got service name, concentrator name, and/or host unique.
+ * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.
+ */
+ if (LIST_EMPTY(&pppoe_softc_list))
+ goto done;
+ LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
+ if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP))
+ continue;
+ if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE))
+ continue;
+ if (sc->sc_state == PPPOE_STATE_INITIAL)
+ break;
+ }
+ if (sc == NULL) {
+/* printf("pppoe: free passive interface is not found\n");*/
+ goto done;
+ }
+ if (hunique) {
+ if (sc->sc_hunique)
+ free(sc->sc_hunique, M_DEVBUF);
+ sc->sc_hunique = malloc(hunique_len, M_DEVBUF,
+ M_DONTWAIT);
+ if (sc->sc_hunique == NULL)
+ goto done;
+ sc->sc_hunique_len = hunique_len;
+ memcpy(sc->sc_hunique, hunique, hunique_len);
+ }
+ sc->sc_state = PPPOE_STATE_PADO_SENT;
+ pppoe_send_pado(sc);
+ break;
+#endif /* PPPOE_SERVER */
case PPPOE_CODE_PADR:
+#ifdef PPPOE_SERVER
+ /*
+ * get sc from ac_cookie if IFF_PASSIVE
+ */
+ if (ac_cookie == NULL) {
+ /* be quiet if there is not a single pppoe instance */
+ printf("pppoe: received PADR but not includes ac_cookie\n");
+ goto done;
+ }
+ sc = pppoe_find_softc_by_hunique(ac_cookie,
+ ac_cookie_len,
+ m->m_pkthdr.rcvif);
+ if (sc == NULL) {
+ /* be quiet if there is not a single pppoe instance */
+ if (!LIST_EMPTY(&pppoe_softc_list))
+ printf("pppoe: received PADR but could not find request for it\n");
+ goto done;
+ }
+ if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
+ printf("%s: received unexpected PADR\n",
+ sc->sc_sppp.pp_if.if_xname);
+ goto done;
+ }
+ if (hunique) {
+ if (sc->sc_hunique)
+ free(sc->sc_hunique, M_DEVBUF);
+ sc->sc_hunique = malloc(hunique_len, M_DEVBUF,
+ M_DONTWAIT);
+ if (sc->sc_hunique == NULL)
+ goto done;
+ sc->sc_hunique_len = hunique_len;
+ memcpy(sc->sc_hunique, hunique, hunique_len);
+ }
+ pppoe_send_pads(sc);
+ sc->sc_state = PPPOE_STATE_SESSION;
+ sc->sc_sppp.pp_up(&sc->sc_sppp);
+ break;
+#else
/* ignore, we are no access concentrator */
goto done;
+#endif /* PPPOE_SERVER */
case PPPOE_CODE_PADO:
if (sc == NULL) {
/* be quiet if there is not a single pppoe instance */
@@ -978,6 +1075,11 @@
if (sc->sc_state != PPPOE_STATE_INITIAL)
return EBUSY;
+#ifdef PPPOE_SERVER
+ /* wait PADI if IFF_PASSIVE */
+ if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE))
+ return 0;
+#endif
x = splnet();
/* save state, in case we fail to send PADI */
retry = sc->sc_padr_retried;
@@ -1027,6 +1129,13 @@
sc->sc_ac_cookie = NULL;
}
sc->sc_ac_cookie_len = 0;
+#ifdef PPPOE_SERVER
+ if (sc->sc_hunique) {
+ free(sc->sc_hunique, M_DEVBUF);
+ sc->sc_hunique = NULL;
+ }
+ sc->sc_hunique_len = 0;
+#endif
sc->sc_session = 0;
/* notify upper layer */
@@ -1128,6 +1237,77 @@
m0->m_flags &= ~(M_BCAST|M_MCAST);
return outgoing_if->if_output(outgoing_if, m0, &dst, NULL);
}
+
+#idef PPPOE_SERVER
+static int
+pppoe_send_pado(struct pppoe_softc *sc)
+{
+ struct mbuf *m0;
+ u_int8_t *p;
+ size_t len;
+
+ if (sc->sc_state != PPPOE_STATE_PADO_SENT)
+ return EIO;
+
+ /* calc length */
+ len = 0;
+ /* include ac_cookie */
+ len += 2 + 2 + sizeof(sc);
+ /* include hunique */
+ len += 2 + 2 + sc->sc_hunique_len;
+ m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN);
+ if (!m0)
+ return EIO;
+ p = mtod(m0, u_int8_t *);
+ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);
+ PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
+ PPPOE_ADD_16(p, sizeof(sc));
+ memcpy(p, &sc, sizeof(sc));
+ p += sizeof(sc);
+ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
+ PPPOE_ADD_16(p, sc->sc_hunique_len);
+ memcpy(p, sc->sc_hunique, sc->sc_hunique_len);
+ return pppoe_output(sc, m0);
+}
+
+static int
+pppoe_send_pads(struct pppoe_softc *sc)
+{
+ struct mbuf *m0;
+ u_int8_t *p;
+ size_t len, l1;
+
+ if (sc->sc_state != PPPOE_STATE_PADO_SENT)
+ return EIO;
+
+ sc->sc_session = mono_time.tv_sec % 0xff + 1;
+ /* calc length */
+ len = 0;
+ /* include hunique */
+ len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/
+ if (sc->sc_service_name != NULL) { /* service name tag maybe empty */
+ l1 = strlen(sc->sc_service_name);
+ len += l1;
+ }
+ m0 = pppoe_get_mbuf(len + PPPOE_HEADERLEN);
+ if (!m0)
+ return ENOBUFS;
+ p = mtod(m0, u_int8_t *);
+ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);
+ PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
+ if (sc->sc_service_name != NULL) {
+ PPPOE_ADD_16(p, l1);
+ memcpy(p, sc->sc_service_name, l1);
+ p += l1;
+ } else {
+ PPPOE_ADD_16(p, 0);
+ }
+ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
+ PPPOE_ADD_16(p, sc->sc_hunique_len);
+ memcpy(p, sc->sc_hunique, sc->sc_hunique_len);
+ return pppoe_output(sc, m0);
+}
+#endif
static void
pppoe_tls(struct sppp *sp)
Index: if_pppoe.h
===================================================================
RCS file: /cvsroot/src/sys/net/if_pppoe.h,v
retrieving revision 1.3
diff -u -r1.3 if_pppoe.h
--- if_pppoe.h 2002/04/14 12:24:28 1.3
+++ if_pppoe.h 2003/06/12 05:23:58
@@ -53,6 +53,8 @@
#define PPPOE_STATE_PADR_SENT 2
#define PPPOE_STATE_SESSION 3
#define PPPOE_STATE_CLOSING 4
+/* passive */
+#define PPPOE_STATE_PADO_SENT 1
struct pppoeconnectionstate {
char ifname[IFNAMSIZ]; /* pppoe interface name */
--
Masaru OKI <oki@netbsd.org>