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>