File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / pppoe.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    1: 
    2: /*
    3:  * pppoe.c
    4:  *
    5:  * Written by Archie Cobbs <archie@freebsd.org>
    6:  * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
    7:  * See ``COPYRIGHT.whistle''
    8:  */
    9: 
   10: #include "ppp.h"
   11: #include "pppoe.h"
   12: #include "ngfunc.h"
   13: #include "log.h"
   14: #include "util.h"
   15: 
   16: #include <paths.h>
   17: #include <net/ethernet.h>
   18: #include <netgraph/ng_message.h>
   19: #include <netgraph/ng_pppoe.h>
   20: #include <netgraph/ng_ether.h>
   21: #include <netgraph/ng_tee.h>
   22: #include <netgraph.h>
   23: 
   24: #include <sys/param.h>
   25: #include <sys/linker.h>
   26: 
   27: /*
   28:  * DEFINITIONS
   29:  */
   30: 
   31: #define PPPOE_MTU		1492	/* allow room for PPPoE overhead */
   32: #define PPPOE_MRU		1492
   33: 
   34: #define PPPOE_CONNECT_TIMEOUT	9
   35: 
   36: #define ETHER_DEFAULT_HOOK	NG_ETHER_HOOK_ORPHAN
   37: 
   38: #ifndef SMALL_SYSTEM
   39: #define PPPOE_MAXPARENTIFS	4096
   40: #else
   41: #define PPPOE_MAXPARENTIFS	32
   42: #endif
   43: 
   44: #define MAX_PATH		64	/* XXX should be NG_PATHSIZ */
   45: #define MAX_SESSION		64	/* max length of PPPoE session name */
   46: 
   47: #ifndef PTT_MAX_PAYL			/* PPP-Max-Payload (RFC4638) */
   48: #if BYTE_ORDER == BIG_ENDIAN
   49: #define PTT_MAX_PAYL		(0x0120)
   50: #else
   51: #define PTT_MAX_PAYL		(0x2001)
   52: #endif
   53: #endif
   54: 
   55: /* https://tools.ietf.org/html/rfc4937 */
   56: #if BYTE_ORDER == BIG_ENDIAN
   57: #define MPD_PTT_CREDITS		(0x0106)
   58: #define MPD_PTT_METRICS		(0x0107)
   59: #define MPD_PTT_SEQ_NUMBER	(0x0108)
   60: #define MPD_PTT_HURL		(0x0111)
   61: #define MPD_PTT_MOTM		(0x0112)
   62: #define MPD_PTT_IP_ROUTE_ADD	(0x0121)
   63: #else
   64: #define MPD_PTT_CREDITS		(0x0601)
   65: #define MPD_PTT_METRICS		(0x0701)
   66: #define MPD_PTT_SEQ_NUMBER	(0x0801)
   67: #define MPD_PTT_HURL		(0x1101)
   68: #define MPD_PTT_MOTM		(0x1201)
   69: #define MPD_PTT_IP_ROUTE_ADD	(0x2101)
   70: #endif
   71: 
   72: /* Per link private info */
   73: struct pppoeinfo {
   74: 	char		path[MAX_PATH];		/* PPPoE node path */
   75: 	char		hook[NG_HOOKSIZ];	/* hook on that node */
   76: 	char		session[MAX_SESSION];	/* session name */
   77: 	char		acname[PPPOE_SERVICE_NAME_SIZE];	/* AC name */
   78: 	uint16_t	max_payload;		/* PPP-Max-Payload (RFC4638) */
   79: 	int		mac_format;		/* MAC address format */
   80: 	u_char		peeraddr[6];		/* Peer MAC address */
   81: 	char		real_session[MAX_SESSION]; /* real session name */
   82: 	char		agent_cid[64];		/* Agent Circuit ID */
   83: 	char		agent_rid[64];		/* Agent Remote ID */
   84: 	u_char		incoming;		/* incoming vs. outgoing */
   85: 	u_char		opened;			/* PPPoE opened by phys */
   86: 	u_char		mp_reply;		/* PPP-Max-Payload reply from server */
   87: 	struct optinfo	options;
   88: 	struct PppoeIf  *PIf;			/* pointer on parent ng_pppoe info */
   89: 	struct PppoeList *list;
   90: 	struct pppTimer	connectTimer;		/* connection timeout timer */
   91: };
   92: typedef struct pppoeinfo	*PppoeInfo;
   93: 
   94: static u_char gNgEtherLoaded = FALSE;
   95: 
   96: /* Set menu options */
   97: enum {
   98: 	SET_IFACE,
   99: 	SET_SESSION,
  100: 	SET_ACNAME,
  101: 	SET_MAX_PAYLOAD,
  102: 	SET_MAC_FORMAT
  103: };
  104: 
  105: /* MAC format options */
  106: enum {
  107:     MAC_UNFORMATTED = 0,
  108:     MAC_UNIX_LIKE,
  109:     MAC_CISCO_LIKE,
  110:     MAC_IETF
  111: };
  112: 
  113: /*
  114:    Invariants:
  115:    ----------
  116: 
  117:    PPPOE_DOWN
  118: 	- ng_pppoe(4) node does not exist
  119: 	- pe->csock == -1
  120: 	- Connect timeout timer is not running
  121: 
  122:    PPPOE_CONNECTING
  123: 	- ng_pppoe(4) node exists and is connected to ether and ppp nodes
  124: 	- pe->csock != -1
  125: 	- Listening for control messages rec'd on pe->csock
  126: 	- Connect timeout timer is running
  127: 	- NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
  128: 	    no response has been received yet
  129: 
  130:    PPPOE_UP
  131: 	- ng_pppoe(4) node exists and is connected to ether and ppp nodes
  132: 	- pe->csock != -1
  133: 	- Listening for control messages rec'd on pe->csock
  134: 	- Connect timeout timer is not running
  135: 	- NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
  136: 	    a NGM_PPPOE_SUCCESS has been received
  137: */
  138: 
  139: /*
  140:  * INTERNAL FUNCTIONS
  141:  */
  142: 
  143: static int	PppoeInit(Link l);
  144: static int	PppoeInst(Link l, Link lt);
  145: static void	PppoeOpen(Link l);
  146: static void	PppoeClose(Link l);
  147: static void	PppoeShutdown(Link l);
  148: static int	PppoePeerMacAddr(Link l, void *buf, size_t buf_len);
  149: static int	PppoePeerIface(Link l, void *buf, size_t buf_len);
  150: static int	PppoeCallingNum(Link l, void *buf, size_t buf_len);
  151: static int	PppoeCalledNum(Link l, void *buf, size_t buf_len);
  152: static int	PppoeSelfName(Link l, void *buf, size_t buf_len);
  153: static int	PppoePeerName(Link l, void *buf, size_t buf_len);
  154: static u_short	PppoeGetMtu(Link l, int conf);
  155: static u_short	PppoeGetMru(Link l, int conf);
  156: static void	PppoeCtrlReadEvent(int type, void *arg);
  157: static void	PppoeConnectTimeout(void *arg);
  158: static void	PppoeStat(Context ctx);
  159: static int	PppoeSetCommand(Context ctx, int ac, char *av[], void *arg);
  160: static int	PppoeOriginated(Link l);
  161: static int	PppoeIsSync(Link l);
  162: static void	PppoeGetNode(Link l);
  163: static void	PppoeReleaseNode(Link l);
  164: static int 	PppoeListen(Link l);
  165: static int 	PppoeUnListen(Link l);
  166: static void	PppoeNodeUpdate(Link l);
  167: static void	PppoeListenEvent(int type, void *arg);
  168: static int 	CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook);
  169: 
  170: static void	PppoeDoClose(Link l);
  171: 
  172: /*
  173:  * GLOBAL VARIABLES
  174:  */
  175: 
  176: const struct phystype gPppoePhysType = {
  177:     .name		= "pppoe",
  178:     .descr		= "PPP over Ethernet",
  179:     .mtu		= PPPOE_MTU,
  180:     .mru		= PPPOE_MRU,
  181:     .tmpl		= 1,
  182:     .init		= PppoeInit,
  183:     .inst		= PppoeInst,
  184:     .open		= PppoeOpen,
  185:     .close		= PppoeClose,
  186:     .update		= PppoeNodeUpdate,
  187:     .shutdown		= PppoeShutdown,
  188:     .showstat		= PppoeStat,
  189:     .originate		= PppoeOriginated,
  190:     .issync		= PppoeIsSync,
  191:     .peeraddr		= PppoePeerMacAddr,
  192:     .peermacaddr	= PppoePeerMacAddr,
  193:     .peeriface		= PppoePeerIface,
  194:     .callingnum		= PppoeCallingNum,
  195:     .callednum		= PppoeCalledNum,
  196:     .selfname		= PppoeSelfName,
  197:     .peername		= PppoePeerName,
  198:     .getmtu		= PppoeGetMtu,
  199:     .getmru		= PppoeGetMru
  200: };
  201: 
  202: const struct cmdtab PppoeSetCmds[] = {
  203:       { "iface {name}",		"Set ethernet interface to use",
  204: 	  PppoeSetCommand, NULL, 2, (void *)SET_IFACE },
  205:       { "service {name}",	"Set PPPoE session name",
  206: 	  PppoeSetCommand, NULL, 2, (void *)SET_SESSION },
  207:       { "acname {name}",	"Set PPPoE access concentrator name",
  208: 	  PppoeSetCommand, NULL, 2, (void *)SET_ACNAME },
  209: #ifdef NGM_PPPOE_SETMAXP_COOKIE
  210:       { "max-payload {size}",	"Set PPP-Max-Payload tag",
  211: 	  PppoeSetCommand, NULL, 2, (void *)SET_MAX_PAYLOAD },
  212: #endif
  213:       { "mac-format {format}",	"Set RADIUS attribute 31 MAC format",
  214: 	  PppoeSetCommand, NULL, 2, (void *)SET_MAC_FORMAT },
  215:       { NULL }
  216: };
  217: 
  218: /* 
  219:  * INTERNAL VARIABLES 
  220:  */
  221: 
  222: struct PppoeList {
  223:     char	session[MAX_SESSION];
  224:     int		refs;
  225:     SLIST_ENTRY(PppoeList)	next;
  226: };
  227: 
  228: struct PppoeIf {
  229:     char	ifnodepath[MAX_PATH];
  230:     ng_ID_t	node_id;		/* pppoe node id */
  231:     int		refs;
  232:     int		csock;                  /* netgraph Control socket */
  233:     int		dsock;                  /* netgraph Data socket */
  234:     EventRef	ctrlEvent;		/* listen for ctrl messages */
  235:     EventRef	dataEvent;		/* listen for data messages */
  236:     SLIST_HEAD(, PppoeList) list;
  237: };
  238: 
  239: int PppoeIfCount=0;
  240: struct PppoeIf PppoeIfs[PPPOE_MAXPARENTIFS];
  241: 
  242: struct tagname {
  243:     int		tag;
  244:     const char	*name;
  245: };
  246: 
  247: static const struct tagname tag2str[] = {
  248:     { PTT_EOL, "End-Of-List" },
  249:     { PTT_SRV_NAME, "Service-Name" },
  250:     { PTT_AC_NAME, "AC-Name" },
  251:     { PTT_HOST_UNIQ, "Host-Uniq" },
  252:     { PTT_AC_COOKIE, "AC-Cookie" },
  253:     { PTT_VENDOR, "Vendor-Specific" },
  254:     { PTT_RELAY_SID, "Relay-Session-Id" },
  255:     { PTT_MAX_PAYL, "PPP-Max-Payload" },
  256:     { PTT_SRV_ERR, "Service-Name-Error" },
  257:     { PTT_SYS_ERR, "AC-System-Error" },
  258:     { PTT_GEN_ERR, "Generic-Error" },
  259:     /* RFC 4937 */
  260:     { MPD_PTT_CREDITS, "Credits" },
  261:     { MPD_PTT_METRICS, "Metrics" },
  262:     { MPD_PTT_SEQ_NUMBER, "Sequence Number" },
  263:     { MPD_PTT_HURL, "HURL" },
  264:     { MPD_PTT_MOTM, "MOTM" },
  265:     { MPD_PTT_IP_ROUTE_ADD, "IP_Route_Add" },
  266:     { 0, "UNKNOWN" }
  267: };
  268: #define NUM_TAG_NAMES	(sizeof(tag2str) / sizeof(*tag2str))
  269: 
  270: 
  271: /*
  272:  * PppoeInit()
  273:  *
  274:  * Initialize device-specific data in physical layer info
  275:  */
  276: static int
  277: PppoeInit(Link l)
  278: {
  279: 	PppoeInfo pe;
  280: 
  281: 	/* Allocate private struct */
  282: 	pe = (PppoeInfo)(l->info = Malloc(MB_PHYS, sizeof(*pe)));
  283: 	pe->incoming = 0;
  284: 	pe->opened = 0;
  285: 	snprintf(pe->path, sizeof(pe->path), "undefined:");
  286: 	snprintf(pe->hook, sizeof(pe->hook), "undefined");
  287: 	snprintf(pe->session, sizeof(pe->session), "*");
  288: 	memset(pe->peeraddr, 0x00, ETHER_ADDR_LEN);
  289: 	strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
  290: 	pe->agent_cid[0] = 0;
  291: 	pe->agent_rid[0] = 0;
  292: 	pe->PIf = NULL;
  293: 	pe->max_payload = 0;
  294: 	pe->mac_format = MAC_UNFORMATTED;
  295: 	pe->mp_reply = 0;
  296: 
  297: 	/* Done */
  298: 	return(0);
  299: }
  300: 
  301: /*
  302:  * PppoeInst()
  303:  *
  304:  * Instantiate device
  305:  */
  306: static int
  307: PppoeInst(Link l, Link lt)
  308: {
  309: 	PppoeInfo pi;
  310: 	l->info = Mdup(MB_PHYS, lt->info, sizeof(struct pppoeinfo));
  311: 	pi = (PppoeInfo)l->info;
  312: 	if (pi->PIf)
  313: 	    pi->PIf->refs++;
  314: 	if (pi->list)
  315: 	    pi->list->refs++;
  316: 
  317: 	/* Done */
  318: 	return(0);
  319: }
  320: 
  321: /*
  322:  * PppoeOpen()
  323:  */
  324: static void
  325: PppoeOpen(Link l)
  326: {
  327: 	PppoeInfo pe = (PppoeInfo)l->info;
  328: 	struct ngm_connect	cn;
  329: 	union {
  330: 	    u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
  331: 	    struct ngpppoe_init_data	poeid;
  332: 	} u;
  333: 	struct ngpppoe_init_data *const idata = &u.poeid;
  334: 	char path[NG_PATHSIZ];
  335: 	char session_hook[NG_HOOKSIZ];
  336: 
  337: 	pe->opened=1;
  338: 
  339: 	Disable(&l->conf.options, LINK_CONF_ACFCOMP);	/* RFC 2516 */
  340: 	Deny(&l->conf.options, LINK_CONF_ACFCOMP);	/* RFC 2516 */
  341: 
  342: 	snprintf(session_hook, sizeof(session_hook), "mpd%d-%d", 
  343: 	    gPid, l->id);
  344: 	
  345: 	if (pe->incoming == 1) {
  346: 		Log(LG_PHYS2, ("[%s] PppoeOpen() on incoming call", l->name));
  347: 
  348: 		/* Path to the ng_tee node */
  349: 		snprintf(path, sizeof(path), "[%x]:%s", 
  350: 		    pe->PIf->node_id, session_hook);
  351: 
  352: 		/* Connect ng_tee(4) node to the ng_ppp(4) node. */
  353: 		memset(&cn, 0, sizeof(cn));
  354: 		if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
  355: 		    Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
  356: 		    goto fail3;
  357: 		}
  358: 		snprintf(cn.ourhook, sizeof(cn.ourhook), "right");
  359: 		if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
  360: 		    &cn, sizeof(cn)) < 0) {
  361: 			Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
  362: 	    		    l->name, path, cn.ourhook, cn.path, cn.peerhook);
  363: 			goto fail3;
  364: 		}
  365: 
  366: 		/* Shutdown ng_tee node */
  367: 		if (NgFuncShutdownNode(pe->PIf->csock, l->name, path) < 0) {
  368: 			Perror("[%s] PPPoE: Shutdown ng_tee node %s error",
  369: 			    l->name, path);
  370: 		}
  371: 
  372: 		if (l->state==PHYS_STATE_READY) {
  373: 		    TimerStop(&pe->connectTimer);
  374: 		    l->state = PHYS_STATE_UP;
  375: 		    PhysUp(l);
  376: 		}
  377: 		return;
  378: 	}
  379: 
  380: 	/* Sanity check. */
  381: 	if (l->state != PHYS_STATE_DOWN) {
  382: 		Log(LG_PHYS, ("[%s] PPPoE allready active", l->name));
  383: 		return;
  384: 	};
  385: 
  386: 	/* Create PPPoE node if necessary. */
  387: 	PppoeGetNode(l);
  388: 
  389: 	if (!pe->PIf) {
  390: 	    Log(LG_ERR, ("[%s] PPPoE node for link is not initialized",
  391: 	        l->name));
  392: 	    goto fail;
  393: 	}
  394: 
  395: 	/* Connect our ng_ppp(4) node link hook to the ng_pppoe(4) node. */
  396: 	strlcpy(cn.ourhook, session_hook, sizeof(cn.ourhook));
  397: 	snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
  398: 
  399: 	if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
  400: 	    Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
  401: 	    goto fail2;
  402: 	}
  403: 	
  404: 	if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
  405: 	    &cn, sizeof(cn)) < 0) {
  406: 		Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
  407:     		    l->name, path, cn.ourhook, cn.path, cn.peerhook);
  408: 		goto fail2;
  409: 	}
  410: 	
  411: #ifdef NGM_PPPOE_SETMAXP_COOKIE
  412: 	if (pe->max_payload > 0)
  413: 	    Log(LG_PHYS, ("[%s] PPPoE: Set PPP-Max-Payload to '%u'",
  414: 		l->name, pe->max_payload));
  415: 	/* Tell the PPPoE node to set PPP-Max-Payload value (unset if 0). */
  416: 	if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_SETMAXP,
  417: 	    &pe->max_payload, sizeof(uint16_t)) < 0) {
  418: 		Perror("[%s] PPPoE can't set PPP-Max-Payload value", l->name);
  419: 		goto fail2;
  420: 	}
  421: #endif
  422: 
  423: 	Log(LG_PHYS, ("[%s] PPPoE: Connecting to '%s'", l->name, pe->session));
  424: 	
  425: 	/* Tell the PPPoE node to try to connect to a server. */
  426: 	memset(idata, 0, sizeof(struct ngpppoe_init_data));
  427: 	strlcpy(idata->hook, session_hook, sizeof(idata->hook));
  428: 	idata->data_len = strlen(pe->session);
  429: 	strncpy(idata->data, pe->session, MAX_SESSION);
  430: 	if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT,
  431: 	    idata, sizeof(*idata) + idata->data_len) < 0) {
  432: 		Perror("[%s] PPPoE can't request connection to server", l->name);
  433: 		goto fail2;
  434: 	}
  435: 
  436: 	/* Set a timer to limit connection time. */
  437: 	TimerInit(&pe->connectTimer, "PPPoE-connect",
  438: 	    PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
  439: 	TimerStart(&pe->connectTimer);
  440: 
  441: 	/* OK */
  442: 	l->state = PHYS_STATE_CONNECTING;
  443: 	strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
  444: 	pe->agent_cid[0] = 0;
  445: 	pe->agent_rid[0] = 0;
  446: 	pe->mp_reply = 0;
  447: 	return;
  448: 
  449: fail3:
  450: 	snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
  451: fail2:
  452: 	NgFuncDisconnect(pe->PIf->csock, l->name, path, session_hook);
  453: fail:	
  454: 	PhysDown(l, STR_ERROR, NULL);
  455: 	return;
  456: }
  457: 
  458: /*
  459:  * PppoeConnectTimeout()
  460:  */
  461: static void
  462: PppoeConnectTimeout(void *arg)
  463: {
  464: 	const Link l = (Link)arg;
  465: 
  466: 	/* Cancel connection. */
  467: 	Log(LG_PHYS, ("[%s] PPPoE connection timeout after %d seconds",
  468: 	    l->name, PPPOE_CONNECT_TIMEOUT));
  469: 	PppoeDoClose(l);
  470: 	PhysDown(l, STR_CON_FAILED0, NULL);
  471: }
  472: 
  473: /*
  474:  * PppoeClose()
  475:  */
  476: static void
  477: PppoeClose(Link l)
  478: {
  479: 	const PppoeInfo pe = (PppoeInfo)l->info;
  480: 
  481: 	pe->opened = 0;
  482: 	if (l->state == PHYS_STATE_DOWN)
  483: 		return;
  484: 	PppoeDoClose(l);
  485: 	PhysDown(l, STR_MANUALLY, NULL);
  486: }
  487: 
  488: /*
  489:  * PppoeShutdown()
  490:  *
  491:  * Shut everything down and go to the PHYS_STATE_DOWN state.
  492:  */
  493: static void
  494: PppoeShutdown(Link l)
  495: {
  496: 	PppoeDoClose(l);
  497: 	PppoeUnListen(l);
  498: 	PppoeReleaseNode(l);
  499: 	Freee(l->info);
  500: }
  501: 
  502: /*
  503:  * PppoeDoClose()
  504:  *
  505:  * Shut everything down and go to the PHYS_STATE_DOWN state.
  506:  */
  507: static void
  508: PppoeDoClose(Link l)
  509: {
  510: 	const PppoeInfo pi = (PppoeInfo)l->info;
  511: 	char path[NG_PATHSIZ];
  512: 	char session_hook[NG_HOOKSIZ];
  513: 
  514: 	if (l->state == PHYS_STATE_DOWN)
  515: 		return;
  516: 
  517: 	snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
  518: 	snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
  519: 	    gPid, l->id);
  520: 	NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
  521: 
  522: 	TimerStop(&pi->connectTimer);
  523: 	l->state = PHYS_STATE_DOWN;
  524: 	pi->incoming = 0;
  525: 	memset(pi->peeraddr, 0x00, ETHER_ADDR_LEN);
  526: 	pi->real_session[0] = 0;
  527: 	pi->agent_cid[0] = 0;
  528: 	pi->agent_rid[0] = 0;
  529: 	pi->mp_reply = 0;
  530: }
  531: 
  532: /*
  533:  * PppoeCtrlReadEvent()
  534:  *
  535:  * Receive an incoming control message from the PPPoE node
  536:  */
  537: static void
  538: PppoeCtrlReadEvent(int type, void *arg)
  539: {
  540: 	union {
  541: #ifdef NGM_PPPOE_SETMAXP_COOKIE
  542: 	    u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_maxp)];
  543: #else
  544: 	    u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
  545: #endif
  546: 	    struct ng_mesg resp;
  547: 	} u;
  548: 	char path[NG_PATHSIZ];
  549: 	Link l = NULL;
  550: 	PppoeInfo pi = NULL;
  551: 	
  552: 	struct PppoeIf  *PIf = (struct PppoeIf*)arg;
  553: 	
  554: 	/* Read control message. */
  555: 	if (NgRecvMsg(PIf->csock, &u.resp, sizeof(u), path) < 0) {
  556: 		Perror("PPPoE: error reading message from \"%s\"", path);
  557: 		return;
  558: 	}
  559: 	if (u.resp.header.typecookie != NGM_PPPOE_COOKIE) {
  560: 		Log(LG_ERR, ("PPPoE: rec'd cookie %lu from \"%s\"",
  561: 		    (u_long)u.resp.header.typecookie, path));
  562: 		return;
  563: 	}
  564: 
  565: 	switch (u.resp.header.cmd) {
  566: 	    case NGM_PPPOE_SUCCESS:
  567: 	    case NGM_PPPOE_FAIL:
  568: 	    case NGM_PPPOE_CLOSE:
  569: #ifdef NGM_PPPOE_SETMAXP_COOKIE
  570: 	    case NGM_PPPOE_SETMAXP:
  571: #endif
  572: 	    {
  573: 		char	ppphook[NG_HOOKSIZ];
  574: 		char	*linkname, *rest;
  575: 		int	id;
  576: 
  577: 		/* Check hook name prefix */
  578: 		linkname = ((struct ngpppoe_sts *)u.resp.data)->hook;
  579: 		if (strncmp(linkname, "listen-", 7) == 0)
  580: 		    return;	/* We do not need them */
  581: 		snprintf(ppphook, NG_HOOKSIZ, "mpd%d-", gPid);
  582: 		if (strncmp(linkname, ppphook, strlen(ppphook))) {
  583: 		    Log(LG_ERR, ("PPPoE: message %d from unknown hook \"%s\"",
  584: 			u.resp.header.cmd, ((struct ngpppoe_sts *)u.resp.data)->hook));
  585: 		    return;
  586: 		}
  587: 		linkname += strlen(ppphook);
  588: 		id = strtol(linkname, &rest, 10);
  589: 		if (rest[0] != 0 ||
  590: 		  !gLinks[id] ||
  591: 		  gLinks[id]->type != &gPppoePhysType ||
  592: 		  PIf != ((PppoeInfo)gLinks[id]->info)->PIf) {
  593: 		    Log((u.resp.header.cmd == NGM_PPPOE_SUCCESS)?LG_ERR:LG_PHYS,
  594: 			("PPPoE: message %d from unexisting link \"%s\"",
  595: 			    u.resp.header.cmd, linkname));
  596: 		    return;
  597: 		}
  598: 		
  599: 		l = gLinks[id];
  600: 		pi = (PppoeInfo)l->info;
  601: 
  602: 		if (l->state == PHYS_STATE_DOWN) {
  603: 		    if (u.resp.header.cmd != NGM_PPPOE_CLOSE) 
  604: 			Log(LG_PHYS, ("[%s] PPPoE: message %d in DOWN state",
  605: 			    l->name, u.resp.header.cmd));
  606: 		    return;
  607: 		}
  608: 	    }
  609: 	}
  610: 
  611: 	/* Decode message. */
  612: 	switch (u.resp.header.cmd) {
  613: 	    case NGM_PPPOE_SESSIONID: /* XXX: I do not know what to do with this? */
  614: 		Log(LG_PHYS3, ("PPPoE: rec'd SESSIONID %u from \"%s\"",
  615: 		  ntohs((uint16_t)u.resp.data), path));
  616: 		break;
  617: 	    case NGM_PPPOE_SUCCESS:
  618: 		Log(LG_PHYS, ("[%s] PPPoE: connection successful", l->name));
  619: 		if (pi->opened) {
  620: 		    TimerStop(&pi->connectTimer);
  621: 		    l->state = PHYS_STATE_UP;
  622: 		    PhysUp(l);
  623: 		} else {
  624: 		    l->state = PHYS_STATE_READY;
  625: 		}
  626: 		break;
  627: 	    case NGM_PPPOE_FAIL:
  628: 		Log(LG_PHYS, ("[%s] PPPoE: connection failed", l->name));
  629: 		PppoeDoClose(l);
  630: 		PhysDown(l, STR_CON_FAILED0, NULL);
  631: 		break;
  632: 	    case NGM_PPPOE_CLOSE:
  633: 		Log(LG_PHYS, ("[%s] PPPoE: connection closed", l->name));
  634: 		PppoeDoClose(l);
  635: 		PhysDown(l, STR_DROPPED, NULL);
  636: 		break;
  637: 	    case NGM_PPPOE_ACNAME:
  638: 		Log(LG_PHYS, ("PPPoE: rec'd ACNAME \"%s\"",
  639: 		  ((struct ngpppoe_sts *)u.resp.data)->hook));
  640: 		break;
  641: #ifdef NGM_PPPOE_SETMAXP_COOKIE
  642: 	    case NGM_PPPOE_SETMAXP:
  643: 	    {
  644: 		struct ngpppoe_maxp *maxp;
  645: 		
  646: 		maxp = ((struct ngpppoe_maxp *)u.resp.data);
  647: 		Log(LG_PHYS, ("[%s] PPPoE: rec'd PPP-Max-Payload '%u'",
  648: 		  l->name, maxp->data));
  649: 		if (pi->max_payload > 0) {
  650: 		    if (pi->max_payload == maxp->data)
  651: 			pi->mp_reply = 1;
  652: 		    else
  653: 			Log(LG_PHYS,
  654: 			  ("[%s] PPPoE: sent and returned values are not equal",
  655: 			  l->name));
  656: 		} else
  657: 		    Log(LG_PHYS, ("[%s] PPPoE: server sent tag PPP-Max-Payload"
  658: 		      " without request from the client",
  659: 		      l->name));
  660: 		break;
  661: 	    }
  662: #endif
  663: 	    default:
  664: 		Log(LG_PHYS, ("PPPoE: rec'd command %lu from \"%s\"",
  665: 		    (u_long)u.resp.header.cmd, path));
  666: 		break;
  667: 	}
  668: }
  669: 
  670: /*
  671:  * PppoeStat()
  672:  */
  673: void
  674: PppoeStat(Context ctx)
  675: {
  676: 	const PppoeInfo pe = (PppoeInfo)ctx->lnk->info;
  677: 	char	buf[32];
  678: 
  679: 	switch (pe->mac_format) {
  680: 	    case MAC_UNFORMATTED:
  681: 		sprintf(buf, "unformatted");
  682: 		break;
  683: 	    case MAC_UNIX_LIKE:
  684: 		sprintf(buf, "unix-like");
  685: 		break;
  686: 	    case MAC_CISCO_LIKE:
  687: 		sprintf(buf, "cisco-like");
  688: 		break;
  689: 	    case MAC_IETF:
  690: 		sprintf(buf, "ietf");
  691: 		break;
  692: 	    default:
  693: 		sprintf(buf, "unknown");
  694: 		break;
  695: 	}
  696: 
  697: 	Printf("PPPoE configuration:\r\n");
  698: 	Printf("\tIface Node   : %s\r\n", pe->path);
  699: 	Printf("\tIface Hook   : %s\r\n", pe->hook);
  700: 	Printf("\tSession      : %s\r\n", pe->session);
  701: #ifdef NGM_PPPOE_SETMAXP_COOKIE
  702: 	Printf("\tMax-Payload  : %u\r\n", pe->max_payload);
  703: #endif
  704: 	Printf("\tMAC format   : %s\r\n", buf);
  705: 	Printf("PPPoE status:\r\n");
  706: 	if (ctx->lnk->state != PHYS_STATE_DOWN) {
  707: 	    Printf("\tOpened       : %s\r\n", (pe->opened?"YES":"NO"));
  708: 	    Printf("\tIncoming     : %s\r\n", (pe->incoming?"YES":"NO"));
  709: 	    PppoePeerMacAddr(ctx->lnk, buf, sizeof(buf));
  710: 	    Printf("\tCurrent peer : %s\r\n", buf);
  711: 	    Printf("\tSession      : %s\r\n", pe->real_session);
  712: 	    Printf("\tMax-Payload  : %s\r\n", (pe->mp_reply?"YES":"NO"));
  713: 	    Printf("\tCircuit-ID   : %s\r\n", pe->agent_cid);
  714: 	    Printf("\tRemote-ID    : %s\r\n", pe->agent_rid);
  715: 	}
  716: }
  717: 
  718: /*
  719:  * PppoeOriginated()
  720:  */
  721: static int
  722: PppoeOriginated(Link l)
  723: {
  724: 	PppoeInfo      const pppoe = (PppoeInfo)l->info;
  725: 
  726: 	return (pppoe->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
  727: }
  728: 
  729: /*
  730:  * PppoeIsSync()
  731:  */
  732: static int
  733: PppoeIsSync(Link l)
  734: {
  735: 	return (1);
  736: }
  737: 
  738: static int
  739: PppoePeerMacAddr(Link l, void *buf, size_t buf_len)
  740: {
  741: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  742: 
  743: 	ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
  744: 	return (0);
  745: }
  746: 
  747: static int
  748: PppoePeerIface(Link l, void *buf, size_t buf_len)
  749: {
  750: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  751: 	char iface[IFNAMSIZ];
  752: 
  753: 	strlcpy(iface, pppoe->path, sizeof(iface));
  754: 	if (iface[strlen(iface) - 1] == ':')
  755: 		iface[strlen(iface) - 1] = '\0';
  756: 	strlcpy(buf, iface, buf_len);
  757: 	return (0);
  758: }
  759: 
  760: static int
  761: PppoeCallingNum(Link l, void *buf, size_t buf_len)
  762: {
  763: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  764: 
  765: 	if (pppoe->incoming) {
  766: 	    switch (pppoe->mac_format) {
  767: 		case MAC_UNFORMATTED:
  768: 		    snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
  769: 		    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
  770: 		    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  771: 		    break;
  772: 		case MAC_UNIX_LIKE:
  773: 		    ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
  774: 		    break;
  775: 		case MAC_CISCO_LIKE:
  776: 		    snprintf(buf, buf_len, "%02x%02x.%02x%02x.%02x%02x",
  777: 		    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
  778: 		    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  779: 		    break;
  780: 		case MAC_IETF:
  781: 		    snprintf(buf, buf_len, "%02x-%02x-%02x-%02x-%02x-%02x",
  782: 		    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
  783: 		    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  784: 		    break;
  785: 		default:
  786: 		    sprintf(buf, "unknown");
  787: 		    return(-1);
  788: 		    break;
  789: 	    }
  790: 	} else {
  791: 	    strlcpy(buf, pppoe->real_session, buf_len);
  792: 	}
  793: 
  794: 	return (0);
  795: }
  796: 
  797: static int
  798: PppoeCalledNum(Link l, void *buf, size_t buf_len)
  799: {
  800: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  801: 
  802: 	if (!pppoe->incoming) {
  803: 	    switch (pppoe->mac_format) {
  804: 		case MAC_UNFORMATTED:
  805: 		    snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
  806: 		    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
  807: 		    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  808: 		    break;
  809: 		case MAC_UNIX_LIKE:
  810: 		    ether_ntoa_r((struct ether_addr *)pppoe->peeraddr, buf);
  811: 		    break;
  812: 		case MAC_CISCO_LIKE:
  813: 		    snprintf(buf, buf_len, "%02x%02x.%02x%02x.%02x%02x",
  814: 		    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
  815: 		    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  816: 		    break;
  817: 		case MAC_IETF:
  818: 		    snprintf(buf, buf_len, "%02x-%02x-%02x-%02x-%02x-%02x",
  819: 		    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2],
  820: 		    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  821: 		    break;
  822: 		default:
  823: 		    sprintf(buf, "unknown");
  824: 		    return(-1);
  825: 		    break;
  826: 	    }
  827: 	} else {
  828: 	    strlcpy(buf, pppoe->real_session, buf_len);
  829: 	}
  830: 
  831: 	return (0);
  832: }
  833: 
  834: static int
  835: PppoeSelfName(Link l, void *buf, size_t buf_len)
  836: {
  837: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  838: 
  839: 	strlcpy(buf, pppoe->agent_cid, buf_len);
  840: 
  841: 	return (0);
  842: }
  843: 
  844: static int
  845: PppoePeerName(Link l, void *buf, size_t buf_len)
  846: {
  847: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  848: 
  849: 	strlcpy(buf, pppoe->agent_rid, buf_len);
  850: 
  851: 	return (0);
  852: }
  853: 
  854: static u_short
  855: PppoeGetMtu(Link l, int conf)
  856: {
  857: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  858: 
  859: 	if (pppoe->max_payload > 0 && pppoe->mp_reply > 0)
  860: 	    return (pppoe->max_payload);
  861: 	else
  862: 	    if (conf == 0)
  863: 		return (l->type->mtu);
  864: 	    else
  865: 		return (l->conf.mtu);
  866: }
  867: 
  868: static u_short
  869: PppoeGetMru(Link l, int conf)
  870: {
  871: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  872: 
  873: 	if (pppoe->max_payload > 0 && pppoe->mp_reply > 0)
  874: 	    return (pppoe->max_payload);
  875: 	else
  876: 	    if (conf == 0)
  877: 		return (l->type->mru);
  878: 	    else
  879: 		return (l->conf.mru);
  880: }
  881: 
  882: static int 
  883: CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook)
  884: {
  885:         union {
  886: 		u_char          buf[sizeof(struct ng_mesg) + 2048];
  887: 		struct ng_mesg  reply;
  888: 	} u;
  889: 	struct ng_mesg *resp;
  890: 	const struct hooklist *hlist;
  891: 	const struct nodeinfo *ninfo;
  892: 	uint32_t f;
  893: 
  894: 	/* Make sure interface is up. */
  895: 	char iface[IFNAMSIZ];
  896: 
  897: 	strlcpy(iface, path, sizeof(iface));
  898: 	if (iface[strlen(iface) - 1] == ':')
  899: 		iface[strlen(iface) - 1] = '\0';
  900: 	if (ExecCmdNosh(LG_PHYS2, iface, "%s %s up", _PATH_IFCONFIG, iface) != 0) {
  901: 		Log(LG_ERR, ("PPPoE: can't bring up interface %s",
  902: 		    iface));
  903: 		return (0);
  904: 	}
  905: 
  906: 	/* Create a new netgraph node */
  907: 	if (NgMkSockNode(NULL, &PIf->csock, &PIf->dsock) < 0) {
  908: 		Perror("[%s] PPPoE: can't create ctrl socket", iface);
  909: 		return(0);
  910: 	}
  911: 	(void)fcntl(PIf->csock, F_SETFD, 1);
  912: 	(void)fcntl(PIf->dsock, F_SETFD, 1);
  913: 
  914: 	/* Check if NG_ETHER_NODE_TYPE is available. */
  915: 	if (gNgEtherLoaded == FALSE) {
  916: 		const struct typelist *tlist;
  917: 
  918: 		/* Ask for a list of available node types. */
  919: 		if (NgSendMsg(PIf->csock, "", NGM_GENERIC_COOKIE, NGM_LISTTYPES,
  920: 		    NULL, 0) < 0) {
  921: 			Perror("[%s] PPPoE: Cannot send a netgraph message",
  922: 			    iface);
  923: 			close(PIf->csock);
  924: 			close(PIf->dsock);
  925: 			return (0);
  926: 		}
  927: 
  928: 		/* Get response. */
  929: 		resp = &u.reply;
  930: 		if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
  931: 			Perror("[%s] PPPoE: Cannot get netgraph response",
  932: 			    iface);
  933: 			close(PIf->csock);
  934: 			close(PIf->dsock);
  935: 			return (0);
  936: 		}
  937: 
  938: 		/* Look for NG_ETHER_NODE_TYPE. */
  939: 		tlist = (const struct typelist*) resp->data;
  940: 		for (f = 0; f < tlist->numtypes; f++)
  941: 			if (strncmp(tlist->typeinfo[f].type_name,
  942: 			    NG_ETHER_NODE_TYPE,
  943: 			    sizeof(NG_ETHER_NODE_TYPE) - 1) == 0)
  944: 				gNgEtherLoaded = TRUE;
  945: 
  946: 		/* If not found try to load ng_ether and repeat the check. */
  947: 		if (gNgEtherLoaded == FALSE && (kldload("ng_ether") < 0)) {
  948: 			Perror("PPPoE: Cannot load ng_ether");
  949: 			close(PIf->csock);
  950: 			close(PIf->dsock);
  951: 			assert (0);
  952: 		}
  953: 		gNgEtherLoaded = TRUE;
  954: 	}
  955: 
  956: 	/*
  957: 	 * Ask for a list of hooks attached to the "ether" node. This node
  958: 	 * should magically exist as a way of hooking stuff onto an ethernet
  959: 	 * device.
  960: 	 */
  961: 	if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
  962: 	    NULL, 0) < 0) {
  963: 		Perror("[%s] Cannot send a netgraph message: %s", iface, path);
  964: 		close(PIf->csock);
  965: 		close(PIf->dsock);
  966: 		return (0);
  967: 	}
  968: 
  969: 	/* Get our list back. */
  970: 	resp = &u.reply;
  971: 	if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
  972: 		Perror("[%s] Cannot get netgraph response", iface);
  973: 		close(PIf->csock);
  974: 		close(PIf->dsock);
  975: 		return (0);
  976: 	}
  977: 
  978: 	hlist = (const struct hooklist *)resp->data;
  979: 	ninfo = &hlist->nodeinfo;
  980: 
  981: 	/* Make sure we've got the right type of node. */
  982: 	if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
  983: 	    sizeof(NG_ETHER_NODE_TYPE) - 1)) {
  984: 		Log(LG_ERR, ("[%s] Unexpected node type ``%s'' (wanted ``"
  985: 		    NG_ETHER_NODE_TYPE "'') on %s",
  986: 		    iface, ninfo->type, path));
  987: 		close(PIf->csock);
  988: 		close(PIf->dsock);
  989: 		return (0);
  990: 	}
  991: 
  992: 	/* Look for a hook already attached. */
  993: 	for (f = 0; f < ninfo->hooks; f++) {
  994: 		const struct linkinfo *nlink = &hlist->link[f];
  995: 
  996: 		/* Search for "orphans" hook. */
  997: 		if (strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) &&
  998: 		    strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT))
  999: 			continue;
 1000: 
 1001: 		/*
 1002: 		 * Something is using the data coming out of this ``ether''
 1003: 		 * node. If it's a PPPoE node, we use that node, otherwise
 1004: 		 * we complain that someone else is using the node.
 1005: 		 */
 1006: 		if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) {
 1007: 			Log(LG_ERR, ("%s Node type ``%s'' is currently "
 1008: 			    " using orphan hook\n",
 1009: 			    path, nlink->nodeinfo.type));
 1010: 			close(PIf->csock);
 1011: 			close(PIf->dsock);
 1012: 			return (0);
 1013: 		}
 1014: 		PIf->node_id = nlink->nodeinfo.id;
 1015: 		break;
 1016: 	}
 1017: 
 1018: 	if (f == ninfo->hooks) {
 1019: 		struct ngm_mkpeer mp;
 1020: 		char	path2[NG_PATHSIZ];
 1021: 
 1022: 		/* Create new PPPoE node. */
 1023: 		memset(&mp, 0, sizeof(mp));
 1024: 		strcpy(mp.type, NG_PPPOE_NODE_TYPE);
 1025: 		strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
 1026: 		strcpy(mp.peerhook, NG_PPPOE_HOOK_ETHERNET);
 1027: 		if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mp,
 1028: 		    sizeof(mp)) < 0) {
 1029: 			Perror("[%s] can't create %s peer to %s,%s",
 1030: 			    iface, NG_PPPOE_NODE_TYPE, path, hook);
 1031: 			close(PIf->csock);
 1032: 			close(PIf->dsock);
 1033: 			return (0);
 1034: 		}
 1035: 
 1036: 		snprintf(path2, sizeof(path2), "%s%s", path, hook);
 1037: 		/* Get pppoe node ID */
 1038: 		if ((PIf->node_id = NgGetNodeID(PIf->csock, path2)) == 0) {
 1039: 			Perror("[%s] Cannot get pppoe node id", iface);
 1040: 			close(PIf->csock);
 1041: 			close(PIf->dsock);
 1042: 			return (0);
 1043: 		};
 1044: 	};
 1045: 
 1046: 	/* Register an event listening to the control and data sockets. */
 1047: 	EventRegister(&(PIf->ctrlEvent), EVENT_READ, PIf->csock,
 1048: 	    EVENT_RECURRING, PppoeCtrlReadEvent, PIf);
 1049: 	EventRegister(&(PIf->dataEvent), EVENT_READ, PIf->dsock,
 1050: 	    EVENT_RECURRING, PppoeListenEvent, PIf);
 1051: 
 1052: 	return (1);
 1053: }
 1054: 
 1055: /*
 1056:  * Look for a tag of a specific type.
 1057:  * Don't trust any length the other end says,
 1058:  * but assume we already sanity checked ph->length.
 1059:  */
 1060: static const struct pppoe_tag*
 1061: get_tag(const struct pppoe_hdr* ph, uint16_t idx)
 1062: {
 1063: 	const char *const end = ((const char *)(ph + 1))
 1064: 	            + ntohs(ph->length);
 1065: 	const struct pppoe_tag *pt = (const void *)(ph + 1);
 1066: 	const char *ptn;
 1067: 
 1068: 	/*
 1069: 	 * Keep processing tags while a tag header will still fit.
 1070: 	 */
 1071: 	while((const char*)(pt + 1) <= end) {
 1072: 		/*
 1073: 		 * If the tag data would go past the end of the packet, abort.
 1074: 		 */
 1075: 		ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
 1076: 		if (ptn > end)
 1077: 			return (NULL);
 1078: 		if (pt->tag_type == idx)
 1079: 			return (pt);
 1080: 
 1081: 		pt = (const struct pppoe_tag*)ptn;
 1082: 	}
 1083: 
 1084: 	return (NULL);
 1085: }
 1086: 
 1087: static const struct pppoe_tag*
 1088: get_vs_tag(const struct pppoe_hdr* ph, uint32_t idx)
 1089: {
 1090: 	const char *const end = ((const char *)(ph + 1))
 1091: 	            + ntohs(ph->length);
 1092: 	const struct pppoe_tag *pt = (const void *)(ph + 1);
 1093: 	const char *ptn;
 1094: 
 1095: 	/*
 1096: 	 * Keep processing tags while a tag header will still fit.
 1097: 	 */
 1098: 	while((const char*)(pt + 1) <= end) {
 1099: 		/*
 1100: 		 * If the tag data would go past the end of the packet, abort.
 1101: 		 */
 1102: 		ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
 1103: 		if (ptn > end)
 1104: 			return (NULL);
 1105: 		if (pt->tag_type == PTT_VENDOR &&
 1106: 		    ntohs(pt->tag_len) >= 4 &&
 1107: 		    *(const uint32_t*)(pt + 1) == idx)
 1108: 			return (pt);
 1109: 
 1110: 		pt = (const struct pppoe_tag*)ptn;
 1111: 	}
 1112: 
 1113: 	return (NULL);
 1114: }
 1115: 
 1116: static void
 1117: print_tags(const struct pppoe_hdr* ph)
 1118: {
 1119: 	const char *const end = ((const char *)(ph + 1))
 1120: 	            + ntohs(ph->length);
 1121: 	const struct pppoe_tag *pt = (const void *)(ph + 1);
 1122: 	const char *ptn;
 1123: 	const void *v;
 1124: 	char buf[1024], tag[32];
 1125: 	size_t len, k;
 1126: 
 1127: 	/*
 1128: 	 * Keep processing tags while a tag header will still fit.
 1129: 	 */
 1130: 	while((const char*)(pt + 1) <= end) {
 1131: 		/*
 1132: 		 * If the tag data would go past the end of the packet, abort.
 1133: 		 */
 1134: 		v = pt + 1;
 1135: 		ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
 1136: 		if (ptn > end)
 1137: 			return;
 1138: 		len = ntohs(pt->tag_len);
 1139: 		buf[0] = 0;
 1140: 		switch (pt->tag_type) {
 1141: 		    case PTT_EOL:
 1142: 			if (len != 0)
 1143: 			    sprintf(buf, "TAG_LENGTH is not zero!");
 1144: 			break;
 1145: 		    case PTT_SRV_NAME:
 1146: 			if (len >= sizeof(buf))
 1147: 			    len = sizeof(buf)-1;
 1148: 			memcpy(buf, pt + 1, len);
 1149: 			buf[len] = 0;
 1150: 			if (len == 0)
 1151: 			    sprintf(buf, "Any service is acceptable");
 1152: 			break;
 1153: 		    case PTT_AC_NAME:
 1154: 			if (len >= sizeof(buf))
 1155: 			    len = sizeof(buf)-1;
 1156: 			memcpy(buf, pt + 1, len);
 1157: 			buf[len] = 0;
 1158: 			break;
 1159: 		    case PTT_HOST_UNIQ:
 1160: 		    case PTT_AC_COOKIE:
 1161: 		    case PTT_RELAY_SID:
 1162: 			snprintf(buf, sizeof(buf), "0x%s", Bin2Hex(v, len));
 1163: 			break;
 1164: 		    case PTT_VENDOR:
 1165: 			if (len >= 4) {
 1166: 			    if ((uint8_t)*(uint8_t*)v != 0) {
 1167: 				snprintf(buf, sizeof(buf),
 1168: 				    "First byte of VENDOR is not zero! 0x%s",
 1169: 				    Bin2Hex(v, len));
 1170: 			    } else {
 1171: 				snprintf(buf, sizeof(buf), "0x%s 0x%s",
 1172: 				Bin2Hex(v, 4),
 1173: 				Bin2Hex((const uint8_t*)v + 4, len - 4));
 1174: 			    }
 1175: 			} else {
 1176: 			    sprintf(buf, "TAG_LENGTH must be >= 4 !");
 1177: 			}
 1178: 			break;
 1179: 		    case PTT_MAX_PAYL:
 1180: 			if (len != 2) {
 1181: 			    sprintf(buf, "TAG_LENGTH is not 2!");
 1182: 			} else {
 1183: 			    sprintf(buf, "%u", *(uint16_t*)(pt + 1));
 1184: 			}
 1185: 			break;
 1186: 		    case PTT_SRV_ERR:
 1187: 			if (len > 0 && (const char *)(pt + 1)+4 !=0) {
 1188: 			    if (len >= sizeof(buf))
 1189: 				len = sizeof(buf)-1;
 1190: 			    memcpy(buf, pt + 1, len);
 1191: 			    buf[len] = 0;
 1192: 			}
 1193: 			break;
 1194: 		    case PTT_SYS_ERR:
 1195: 		    case PTT_GEN_ERR:
 1196: 			if (len >= sizeof(buf))
 1197: 			    len = sizeof(buf)-1;
 1198: 			memcpy(buf, pt + 1, len);
 1199: 			buf[len] = 0;
 1200: 			break;
 1201: 		    case MPD_PTT_CREDITS:
 1202: 		    case MPD_PTT_METRICS:
 1203: 		    case MPD_PTT_SEQ_NUMBER:
 1204: 		    case MPD_PTT_HURL:
 1205: 		    case MPD_PTT_MOTM:
 1206: 		    case MPD_PTT_IP_ROUTE_ADD:
 1207: 			sprintf(buf, "Not implemented");
 1208: 			break;
 1209: 		    default:
 1210: 			sprintf(buf, "0x%04x", pt->tag_type);
 1211: 			break;
 1212: 		}
 1213: 		/* First check our stat list for known tags */
 1214: 		for (k = 0; k < NUM_TAG_NAMES; k++) {
 1215: 		    if (pt->tag_type == tag2str[k].tag) {
 1216: 			sprintf(tag, "%s", tag2str[k].name);
 1217: 			break;
 1218: 		    }
 1219: 		}
 1220: 		Log(LG_PHYS3, ("TAG: %s, Value: %s", tag, buf));
 1221: 		pt = (const struct pppoe_tag*)ptn;
 1222: 	}
 1223: }
 1224: 
 1225: static void
 1226: PppoeListenEvent(int type, void *arg)
 1227: {
 1228: 	int			k, sz;
 1229: 	struct PppoeIf		*PIf = (struct PppoeIf *)(arg);
 1230: 	char			rhook[NG_HOOKSIZ];
 1231: 	unsigned char		response[1024];
 1232: 
 1233: 	char			path[NG_PATHSIZ];
 1234: 	char			path1[NG_PATHSIZ];
 1235: 	char			session_hook[NG_HOOKSIZ];
 1236: 	char			*session;
 1237: 	char			real_session[MAX_SESSION];
 1238: 	char			agent_cid[64];
 1239: 	char			agent_rid[64];
 1240: 	struct ngm_connect      cn;
 1241: 	struct ngm_mkpeer 	mp;
 1242: 	Link 			l = NULL;
 1243: 	PppoeInfo		pi = NULL;
 1244: 	const struct pppoe_full_hdr	*wh;
 1245: 	const struct pppoe_hdr	*ph;
 1246: 	const struct pppoe_tag  *tag;
 1247: 
 1248: 	union {
 1249: 	    u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
 1250: 	    struct ngpppoe_init_data poeid;
 1251: 	} u;
 1252: 	struct ngpppoe_init_data *const idata = &u.poeid;
 1253: 
 1254: 	switch (sz = NgRecvData(PIf->dsock, response, sizeof(response), rhook)) {
 1255:           case -1:
 1256: 	    Log(LG_ERR, ("NgRecvData: %d", sz));
 1257:             return;
 1258:           case 0:
 1259:             Log(LG_ERR, ("NgRecvData: socket closed"));
 1260:             return;
 1261:         }
 1262: 
 1263: 	if (strncmp(rhook, "listen-", 7)) {
 1264: 		Log(LG_ERR, ("PPPoE: data from unknown hook \"%s\"", rhook));
 1265: 		return;
 1266: 	}
 1267: 
 1268: 	session = rhook + 7;
 1269: 
 1270: 	if (sz < sizeof(struct pppoe_full_hdr)) {
 1271: 		Log(LG_PHYS, ("Incoming truncated PPPoE connection request via %s for "
 1272: 		    "service \"%s\"", PIf->ifnodepath, session));
 1273: 		return;
 1274: 	}
 1275: 
 1276: 	wh = (struct pppoe_full_hdr *)response;
 1277: 	ph = &wh->ph;
 1278: 	if ((tag = get_tag(ph, PTT_SRV_NAME))) {
 1279: 	    int len = ntohs(tag->tag_len);
 1280: 	    if (len >= sizeof(real_session))
 1281: 		len = sizeof(real_session)-1;
 1282: 	    memcpy(real_session, tag + 1, len);
 1283: 	    real_session[len] = 0;
 1284: 	} else {
 1285: 	    strlcpy(real_session, session, sizeof(real_session));
 1286: 	}
 1287: 	bzero(agent_cid, sizeof(agent_cid));
 1288: 	bzero(agent_rid, sizeof(agent_rid));
 1289: 	if ((tag = get_vs_tag(ph, htonl(0x00000DE9)))) {
 1290: 	    int len = ntohs(tag->tag_len) - 4, pos = 0;
 1291: 	    const char *b = (const char *)(tag + 1) + 4;
 1292: 	    while (pos + 1 <= len) {
 1293: 		int len1 = b[pos + 1];
 1294: 		if (len1 > len - pos - 2)
 1295: 		    break;
 1296: 		if (len1 >= sizeof(agent_rid))
 1297: 		    len1 = sizeof(agent_rid) - 1;
 1298: 		switch (b[pos]) {
 1299: 		    case 1:
 1300: 			strncpy(agent_cid, &b[pos + 2], len1);
 1301: 			break;
 1302: 		    case 2:
 1303: 			strncpy(agent_rid, &b[pos + 2], len1);
 1304: 			break;
 1305: 		}
 1306: 		pos += 2 + len1;
 1307: 	    }
 1308: 	}
 1309: 
 1310: 	Log(LG_PHYS, ("Incoming PPPoE connection request via %s for "
 1311: 	    "service \"%s\" from %s", PIf->ifnodepath, real_session,
 1312: 	    ether_ntoa((struct  ether_addr *)&wh->eh.ether_shost)));
 1313: 
 1314: 	if (gLogOptions & LG_PHYS3)
 1315: 	    print_tags(ph);
 1316: 
 1317: 	if (gShutdownInProgress) {
 1318: 		Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
 1319: 		return;
 1320: 	}
 1321: 
 1322: 	if (OVERLOAD()) {
 1323: 		Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
 1324: 		return;
 1325: 	}
 1326: 
 1327: 	/* Examine all PPPoE links. */
 1328: 	for (k = 0; k < gNumLinks; k++) {
 1329: 		Link l2;
 1330: 	        PppoeInfo pi2;
 1331: 
 1332: 		if (!gLinks[k] || gLinks[k]->type != &gPppoePhysType)
 1333: 			continue;
 1334: 
 1335: 		l2 = gLinks[k];
 1336: 		pi2 = (PppoeInfo)l2->info;
 1337: 
 1338: 		if ((!PhysIsBusy(l2)) &&
 1339: 		    (pi2->PIf == PIf) &&
 1340: 		    (strcmp(pi2->session, session) == 0) &&
 1341: 		    Enabled(&l2->conf.options, LINK_CONF_INCOMING)) {
 1342: 			l = l2;
 1343: 			break;
 1344: 		}
 1345: 	}
 1346: 	
 1347: 	if (l != NULL && l->tmpl)
 1348: 	    l = LinkInst(l, NULL, 0, 0);
 1349: 
 1350: 	if (l == NULL) {
 1351: 		Log(LG_PHYS, ("No free PPPoE link with requested parameters "
 1352: 		    "was found"));
 1353: 		return;
 1354: 	}
 1355: 	pi = (PppoeInfo)l->info;
 1356: 	
 1357: 	Log(LG_PHYS, ("[%s] Accepting PPPoE connection", l->name));
 1358: 
 1359: 	/* Path to the ng_pppoe */
 1360: 	snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
 1361: 
 1362: 	/* Name of ng_pppoe session hook */
 1363: 	snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
 1364: 	    gPid, l->id);
 1365: 		
 1366: 	/* Create ng_tee(4) node and connect it to ng_pppoe(4). */
 1367: 	memset(&mp, 0, sizeof(mp));
 1368: 	strcpy(mp.type, NG_TEE_NODE_TYPE);
 1369: 	strlcpy(mp.ourhook, session_hook, sizeof(mp.ourhook));
 1370: 	snprintf(mp.peerhook, sizeof(mp.peerhook), "left");
 1371: 	if (NgSendMsg(pi->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
 1372: 	    &mp, sizeof(mp)) < 0) {
 1373: 		Perror("[%s] PPPoE: can't create %s peer to %s,%s",
 1374: 		    l->name, NG_TEE_NODE_TYPE, path, "left");
 1375: 		goto close_socket;
 1376: 	}
 1377: 
 1378: 	/* Path to the ng_tee */
 1379: 	snprintf(path1, sizeof(path), "%s%s", path, session_hook);
 1380: 
 1381: 	/* Connect our socket node link hook to the ng_tee(4) node. */
 1382: 	memset(&cn, 0, sizeof(cn));
 1383: 	strlcpy(cn.ourhook, l->name, sizeof(cn.ourhook));
 1384: 	strlcpy(cn.path, path1, sizeof(cn.path));
 1385: 	strcpy(cn.peerhook, "left2right");
 1386: 	if (NgSendMsg(pi->PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
 1387: 	    &cn, sizeof(cn)) < 0) {
 1388: 		Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 1389: 		    l->name, ".:", cn.ourhook, cn.path, cn.peerhook);
 1390: 		goto shutdown_tee;
 1391: 	}
 1392: 
 1393: 	/* Put the PPPoE node into OFFER mode. */
 1394: 	memset(idata, 0, sizeof(*idata));
 1395: 	strlcpy(idata->hook, session_hook, sizeof(idata->hook));
 1396: 	if (pi->acname[0] != 0) {
 1397: 		strlcpy(idata->data, pi->acname, MAX_SESSION);
 1398: 	} else {
 1399: 		if (gethostname(idata->data, MAX_SESSION) == -1) {
 1400: 			Log(LG_ERR, ("[%s] PPPoE: gethostname() failed",
 1401: 			    l->name));
 1402: 			idata->data[0] = 0;
 1403: 		}
 1404: 		if (idata->data[0] == 0)
 1405: 			strlcpy(idata->data, "NONAME", MAX_SESSION);
 1406: 	}
 1407: 	idata->data_len=strlen(idata->data);
 1408: 
 1409: 	if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER,
 1410: 	    idata, sizeof(*idata) + idata->data_len) < 0) {
 1411: 		Perror("[%s] PPPoE: can't send NGM_PPPOE_OFFER to %s,%s ",
 1412: 		    l->name, path, idata->hook);
 1413: 		goto shutdown_tee;
 1414: 	}
 1415: 
 1416: 	memset(idata, 0, sizeof(*idata));
 1417: 	strlcpy(idata->hook, session_hook, sizeof(idata->hook));
 1418: 	idata->data_len = strlen(pi->session);
 1419: 	strncpy(idata->data, pi->session, MAX_SESSION);
 1420: 
 1421: 	if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE,
 1422: 	    NGM_PPPOE_SERVICE, idata,
 1423: 	    sizeof(*idata) + idata->data_len) < 0) {
 1424: 		Perror("[%s] PPPoE: can't send NGM_PPPOE_SERVICE to %s,%s",
 1425: 		    l->name, path, idata->hook);
 1426: 		goto shutdown_tee;
 1427: 	}
 1428: 
 1429: 	/* And send our request data to the waiting node. */
 1430: 	if (NgSendData(pi->PIf->dsock, l->name, response, sz) == -1) {
 1431: 		Perror("[%s] PPPoE: Cannot send original request", l->name);
 1432: 		goto shutdown_tee;
 1433: 	}
 1434: 		
 1435: 	if (NgFuncDisconnect(pi->PIf->csock, l->name, ".:", l->name) < 0) {
 1436: 		Perror("[%s] PPPoE: can't remove hook %s", l->name, l->name);
 1437: 		goto shutdown_tee;
 1438:     	}
 1439: 	l->state = PHYS_STATE_CONNECTING;
 1440: 	pi->incoming = 1;
 1441: 	/* Record the peer's MAC address */
 1442: 	memcpy(pi->peeraddr, wh->eh.ether_shost, 6);
 1443: 	strlcpy(pi->real_session, real_session, sizeof(pi->real_session));
 1444: 	strlcpy(pi->agent_cid, agent_cid, sizeof(pi->agent_cid));
 1445: 	strlcpy(pi->agent_rid, agent_rid, sizeof(pi->agent_rid));
 1446: 
 1447: 	Log(LG_PHYS2, ("[%s] PPPoE response sent", l->name));
 1448: 
 1449: 	/* Set a timer to limit connection time. */
 1450: 	TimerInit(&pi->connectTimer, "PPPoE-connect",
 1451: 	    PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
 1452: 	TimerStart(&pi->connectTimer);
 1453: 
 1454: 	PhysIncoming(l);
 1455: 	return;
 1456: 
 1457: shutdown_tee:
 1458: 	if (NgFuncShutdownNode(pi->PIf->csock, l->name, path1) < 0) {
 1459: 	    Perror("[%s] Shutdown ng_tee node %s error", l->name, path1);
 1460: 	};
 1461: 
 1462: close_socket:
 1463: 	Log(LG_PHYS, ("[%s] PPPoE connection not accepted due to error",
 1464: 	    l->name));
 1465: 
 1466: 	/* If link is not static - shutdown it. */
 1467: 	if (!l->stay)
 1468: 	    LinkShutdown(l);
 1469: }
 1470: 
 1471: /*
 1472:  * PppoeGetNode()
 1473:  */
 1474: 
 1475: static void
 1476: PppoeGetNode(Link l)
 1477: {
 1478:     int i, j = -1, free = -1;
 1479:     PppoeInfo pi = (PppoeInfo)l->info;
 1480: 
 1481:     if (pi->PIf) // Do this only once for interface
 1482: 	return;
 1483: 
 1484:     if (!strcmp(pi->path, "undefined:")) {
 1485:     	    Log(LG_ERR, ("[%s] PPPoE: Skipping link \"%s\" with undefined "
 1486: 	        "interface", l->name, l->name));
 1487: 	    return;
 1488:     }
 1489: 
 1490:     for (i = 0; i < PPPOE_MAXPARENTIFS; i++) {
 1491: 	if (PppoeIfs[i].ifnodepath[0] == 0) {
 1492: 	    free = i;
 1493: 	} else if (strcmp(PppoeIfs[i].ifnodepath, pi->path) == 0) {
 1494:     	    j = i;
 1495: 	    break;
 1496: 	}
 1497:     }
 1498:     if (j == -1) {
 1499: 	if (free == -1) {
 1500: 		Log(LG_ERR, ("[%s] PPPoE: Too many different parent interfaces! ", 
 1501: 		    l->name));
 1502: 		return;
 1503: 	}
 1504: 	if (CreatePppoeNode(&PppoeIfs[free], pi->path, pi->hook)) {
 1505: 		strlcpy(PppoeIfs[free].ifnodepath,
 1506: 		    pi->path,
 1507: 		    sizeof(PppoeIfs[free].ifnodepath));
 1508: 		PppoeIfs[free].refs = 1;
 1509: 		pi->PIf = &PppoeIfs[free];
 1510: 	} else {
 1511: 		Log(LG_ERR, ("[%s] PPPoE: Error creating ng_pppoe "
 1512: 		    "node on %s", l->name, pi->path));
 1513: 		return;
 1514: 	}
 1515:     } else {
 1516: 	PppoeIfs[j].refs++;
 1517:         pi->PIf = &PppoeIfs[j];
 1518:     }
 1519: }
 1520: 
 1521: /*
 1522:  * PppoeReleaseNode()
 1523:  */
 1524: 
 1525: static void
 1526: PppoeReleaseNode(Link l)
 1527: {
 1528:     PppoeInfo pi = (PppoeInfo)l->info;
 1529: 
 1530:     if (!pi->PIf) // Do this only once for interface
 1531: 	return;
 1532: 
 1533:     pi->PIf->refs--;
 1534:     if (pi->PIf->refs == 0) {
 1535: 	pi->PIf->ifnodepath[0] = 0;
 1536: 	pi->PIf->node_id = 0;
 1537: 	EventUnRegister(&pi->PIf->ctrlEvent);
 1538: 	EventUnRegister(&pi->PIf->dataEvent);
 1539: 	close(pi->PIf->csock);
 1540: 	pi->PIf->csock = -1;
 1541: 	close(pi->PIf->dsock);
 1542: 	pi->PIf->dsock = -1;
 1543:     }
 1544: 
 1545:     pi->PIf = NULL;
 1546: }
 1547: 
 1548: static int 
 1549: PppoeListen(Link l)
 1550: {
 1551: 	PppoeInfo pi = (PppoeInfo)l->info;
 1552: 	struct PppoeIf *PIf = pi->PIf;
 1553: 	struct PppoeList *pl;
 1554: 	union {
 1555: 	    u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
 1556: 	    struct ngpppoe_init_data	poeid;
 1557: 	} u;
 1558: 	struct ngpppoe_init_data *const idata = &u.poeid;
 1559: 	char path[NG_PATHSIZ];
 1560: 	struct ngm_connect	cn;
 1561: 
 1562: 	if (pi->list || !pi->PIf)
 1563: 	    return(1);	/* Do this only once */
 1564: 
 1565: 	SLIST_FOREACH(pl, &pi->PIf->list, next) {
 1566: 	    if (strcmp(pl->session, pi->session) == 0)
 1567: 		break;
 1568: 	}
 1569: 	if (pl) {
 1570: 	    pl->refs++;
 1571: 	    pi->list = pl;
 1572: 	    return (1);
 1573: 	}
 1574: 	
 1575: 	pl = Malloc(MB_PHYS, sizeof(*pl));
 1576: 	strlcpy(pl->session, pi->session, sizeof(pl->session));
 1577: 	pl->refs = 1;
 1578: 	pi->list = pl;
 1579: 	SLIST_INSERT_HEAD(&pi->PIf->list, pl, next);
 1580: 
 1581: 	snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
 1582: 	
 1583: 	/* Connect our socket node link hook to the ng_pppoe(4) node. */
 1584: 	memset(&cn, 0, sizeof(cn));
 1585: 	strcpy(cn.path, path);
 1586: 	snprintf(cn.ourhook, sizeof(cn.peerhook), "listen-%s", pi->session);
 1587: 	strcpy(cn.peerhook, cn.ourhook);
 1588: 
 1589: 	if (NgSendMsg(PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
 1590: 	    sizeof(cn)) < 0) {
 1591: 		Perror("PPPoE: Can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 1592: 		    ".:", cn.ourhook, cn.path, cn.peerhook);
 1593: 		return(0);
 1594: 	}
 1595: 
 1596: 	/* Tell the PPPoE node to be a server. */
 1597: 	memset(idata, 0, sizeof(*idata));
 1598: 	snprintf(idata->hook, sizeof(idata->hook), "listen-%s", pi->session);
 1599: 	idata->data_len = strlen(pi->session);
 1600: 	strncpy(idata->data, pi->session, MAX_SESSION);
 1601: 
 1602: 	if (NgSendMsg(PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN,
 1603: 	    idata, sizeof(*idata) + idata->data_len) < 0) {
 1604: 		Perror("PPPoE: Can't send NGM_PPPOE_LISTEN to %s hook %s",
 1605: 		     path, idata->hook);
 1606: 		return (0);
 1607: 	}
 1608: 
 1609: 	Log(LG_PHYS, ("PPPoE: waiting for connection on %s, service \"%s\"",
 1610: 		PIf->ifnodepath, idata->data));
 1611: 	    
 1612: 	return (1);
 1613: }
 1614: 
 1615: static int 
 1616: PppoeUnListen(Link l)
 1617: {
 1618: 	PppoeInfo pi = (PppoeInfo)l->info;
 1619: 	struct PppoeIf *PIf = pi->PIf;
 1620: 	char path[NG_PATHSIZ];
 1621: 	char session_hook[NG_HOOKSIZ];
 1622: 
 1623: 	if (!pi->list)
 1624: 	    return(1);	/* Do this only once */
 1625: 
 1626: 	pi->list->refs--;
 1627: 	
 1628: 	if (pi->list->refs == 0) {
 1629: 	
 1630: 	    snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
 1631: 	    snprintf(session_hook, sizeof(session_hook), "listen-%s", pi->list->session);
 1632: 	    NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
 1633: 
 1634: 	    Log(LG_PHYS, ("PPPoE: stop waiting for connection on %s, service \"%s\"",
 1635: 		PIf->ifnodepath, pi->list->session));
 1636: 		
 1637: 	    SLIST_REMOVE(&PIf->list, pi->list, PppoeList, next);
 1638: 	    Freee(pi->list);
 1639: 	}
 1640: 	    
 1641: 	pi->list = NULL;
 1642: 	return (1);
 1643: }
 1644: 
 1645: /*
 1646:  * PppoeNodeUpdate()
 1647:  */
 1648: 
 1649: static void
 1650: PppoeNodeUpdate(Link l)
 1651: {
 1652:     PppoeInfo pi = (PppoeInfo)l->info;
 1653:     if (!pi->list) {
 1654: 	if (Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
 1655: 	    PppoeGetNode(l);
 1656: 	    PppoeListen(l);
 1657: 	}
 1658:     } else {
 1659: 	if (!Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
 1660: 	    PppoeUnListen(l);
 1661: 	    if (l->state == PHYS_STATE_DOWN)
 1662: 		PppoeReleaseNode(l);
 1663: 	}
 1664:     }
 1665: }
 1666: 
 1667: /*
 1668:  * PppoeSetCommand()
 1669:  */
 1670:  
 1671: static int
 1672: PppoeSetCommand(Context ctx, int ac, char *av[], void *arg)
 1673: {
 1674: 	const PppoeInfo pi = (PppoeInfo) ctx->lnk->info;
 1675: 	const char *hookname = ETHER_DEFAULT_HOOK;
 1676: 	const char *colon;
 1677: #ifdef NGM_PPPOE_SETMAXP_COOKIE
 1678: 	int ap;
 1679: #endif
 1680: 	switch ((intptr_t)arg) {
 1681: 	case SET_IFACE:
 1682: 		switch (ac) {
 1683: 		case 2:
 1684: 			hookname = av[1];
 1685: 			/* fall through */
 1686: 		case 1:
 1687: 			colon = (av[0][strlen(av[0]) - 1] == ':') ? "" : ":";
 1688: 			snprintf(pi->path, sizeof(pi->path),
 1689: 			    "%s%s", av[0], colon);
 1690: 			strlcpy(pi->hook, hookname, sizeof(pi->hook));
 1691: 			break;
 1692: 		default:
 1693: 			return(-1);
 1694: 		}
 1695: 		if (pi->list) {
 1696: 		    PppoeUnListen(ctx->lnk);
 1697: 		    PppoeReleaseNode(ctx->lnk);
 1698: 		    PppoeGetNode(ctx->lnk);
 1699: 		    PppoeListen(ctx->lnk);
 1700: 		}
 1701: 		break;
 1702: 	case SET_SESSION:
 1703: 		if (ac != 1)
 1704: 			return(-1);
 1705: 		strlcpy(pi->session, av[0], sizeof(pi->session));
 1706: 		if (pi->list) {
 1707: 		    PppoeUnListen(ctx->lnk);
 1708: 		    PppoeListen(ctx->lnk);
 1709: 		}
 1710: 		break;
 1711: 	case SET_ACNAME:
 1712: 		if (ac != 1)
 1713: 			return(-1);
 1714: 		strlcpy(pi->acname, av[0], sizeof(pi->acname));
 1715: 		break;
 1716: #ifdef NGM_PPPOE_SETMAXP_COOKIE
 1717: 	case SET_MAX_PAYLOAD:
 1718: 		if (ac != 1)
 1719: 			return(-1);
 1720: 		ap = atoi(av[0]);
 1721: 		if (ap < PPPOE_MRU || ap > ETHER_MAX_LEN - 8)
 1722: 			Error("PPP-Max-Payload value \"%s\"", av[0]);
 1723: 		pi->max_payload = ap;
 1724: 		break;
 1725: #endif
 1726: 	case SET_MAC_FORMAT:
 1727: 		if (ac != 1)
 1728: 			return(-1);
 1729: 		if (strcmp(av[0], "unformatted") == 0) {
 1730: 		    pi->mac_format = MAC_UNFORMATTED;
 1731: 		} else if (strcmp(av[0], "unix-like") == 0) {
 1732: 		    pi->mac_format = MAC_UNIX_LIKE;
 1733: 		} else if (strcmp(av[0], "cisco-like") == 0) {
 1734: 		    pi->mac_format = MAC_CISCO_LIKE;
 1735: 		} else if (strcmp(av[0], "ietf") == 0) {
 1736: 		    pi->mac_format = MAC_IETF;
 1737: 		} else {
 1738: 		    Error("Incorrect PPPoE mac-format \"%s\"", av[0]);
 1739: 		}
 1740: 		break;
 1741: 	default:
 1742: 		assert(0);
 1743: 	}
 1744: 	return(0);
 1745: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>