File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / pppoe.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:39:23 2021 UTC (4 years ago) by misho
Branches: mpd, MAIN
CVS tags: v5_9p16, v5_9, HEAD
mpd 5.9

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

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