File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / pppoe.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:32:47 2012 UTC (12 years, 5 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_6, HEAD
mpd

    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 <net/ethernet.h>
   17: #include <netgraph/ng_message.h>
   18: #include <netgraph/ng_pppoe.h>
   19: #include <netgraph/ng_ether.h>
   20: #include <netgraph/ng_tee.h>
   21: #include <netgraph.h>
   22: 
   23: #include <sys/param.h>
   24: #include <sys/linker.h>
   25: 
   26: /*
   27:  * DEFINITIONS
   28:  */
   29: 
   30: #define PPPOE_MTU		1492	/* allow room for PPPoE overhead */
   31: #define PPPOE_MRU		1492
   32: 
   33: #define PPPOE_CONNECT_TIMEOUT	9
   34: 
   35: #define ETHER_DEFAULT_HOOK	NG_ETHER_HOOK_ORPHAN
   36: 
   37: #define PPPOE_MAXPARENTIFS	1024
   38: 
   39: #define MAX_PATH		64	/* XXX should be NG_PATHSIZ */
   40: #define MAX_SESSION		64	/* max length of PPPoE session name */
   41: 
   42: /* Per link private info */
   43: struct pppoeinfo {
   44: 	char		path[MAX_PATH];		/* PPPoE node path */
   45: 	char		hook[NG_HOOKSIZ];	/* hook on that node */
   46: 	char		session[MAX_SESSION];	/* session name */
   47: 	char		acname[PPPOE_SERVICE_NAME_SIZE];	/* AC name */
   48: 	u_char		peeraddr[6];		/* Peer MAC address */
   49: 	char		real_session[MAX_SESSION]; /* real session name */
   50: 	char		agent_cid[64];		/* Agent Circuit ID */
   51: 	char		agent_rid[64];		/* Agent Remote ID */
   52: 	u_char		incoming;		/* incoming vs. outgoing */
   53: 	u_char		opened;			/* PPPoE opened by phys */
   54: 	struct optinfo	options;
   55: 	struct PppoeIf  *PIf;			/* pointer on parent ng_pppoe info */
   56: 	struct PppoeList *list;
   57: 	struct pppTimer	connectTimer;		/* connection timeout timer */
   58: };
   59: typedef struct pppoeinfo	*PppoeInfo;
   60: 
   61: static u_char gNgEtherLoaded = FALSE;
   62: 
   63: /* Set menu options */
   64: enum {
   65: 	SET_IFACE,
   66: 	SET_SESSION,
   67: 	SET_ACNAME
   68: };
   69: 
   70: /*
   71:    Invariants:
   72:    ----------
   73: 
   74:    PPPOE_DOWN
   75: 	- ng_pppoe(4) node does not exist
   76: 	- pe->csock == -1
   77: 	- Connect timeout timer is not running
   78: 
   79:    PPPOE_CONNECTING
   80: 	- ng_pppoe(4) node exists and is connected to ether and ppp nodes
   81: 	- pe->csock != -1
   82: 	- Listening for control messages rec'd on pe->csock
   83: 	- Connect timeout timer is running
   84: 	- NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
   85: 	    no response has been received yet
   86: 
   87:    PPPOE_UP
   88: 	- ng_pppoe(4) node exists and is connected to ether and ppp nodes
   89: 	- pe->csock != -1
   90: 	- Listening for control messages rec'd on pe->csock
   91: 	- Connect timeout timer is not running
   92: 	- NGM_PPPOE_CONNECT has been sent to the ng_pppoe(4) node, and
   93: 	    a NGM_PPPOE_SUCCESS has been received
   94: */
   95: 
   96: /*
   97:  * INTERNAL FUNCTIONS
   98:  */
   99: 
  100: static int	PppoeInit(Link l);
  101: static int	PppoeInst(Link l, Link lt);
  102: static void	PppoeOpen(Link l);
  103: static void	PppoeClose(Link l);
  104: static void	PppoeShutdown(Link l);
  105: static int	PppoePeerMacAddr(Link l, void *buf, size_t buf_len);
  106: static int	PppoePeerIface(Link l, void *buf, size_t buf_len);
  107: static int	PppoeCallingNum(Link l, void *buf, size_t buf_len);
  108: static int	PppoeCalledNum(Link l, void *buf, size_t buf_len);
  109: static int	PppoeSelfName(Link l, void *buf, size_t buf_len);
  110: static int	PppoePeerName(Link l, void *buf, size_t buf_len);
  111: static void	PppoeCtrlReadEvent(int type, void *arg);
  112: static void	PppoeConnectTimeout(void *arg);
  113: static void	PppoeStat(Context ctx);
  114: static int	PppoeSetCommand(Context ctx, int ac, char *av[], void *arg);
  115: static int	PppoeOriginated(Link l);
  116: static int	PppoeIsSync(Link l);
  117: static void	PppoeGetNode(Link l);
  118: static void	PppoeReleaseNode(Link l);
  119: static int 	PppoeListen(Link l);
  120: static int 	PppoeUnListen(Link l);
  121: static void	PppoeNodeUpdate(Link l);
  122: static void	PppoeListenEvent(int type, void *arg);
  123: static int 	CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook);
  124: 
  125: static void	PppoeDoClose(Link l);
  126: 
  127: /*
  128:  * GLOBAL VARIABLES
  129:  */
  130: 
  131: const struct phystype gPppoePhysType = {
  132:     .name		= "pppoe",
  133:     .descr		= "PPP over Ethernet",
  134:     .mtu		= PPPOE_MTU,
  135:     .mru		= PPPOE_MRU,
  136:     .tmpl		= 1,
  137:     .init		= PppoeInit,
  138:     .inst		= PppoeInst,
  139:     .open		= PppoeOpen,
  140:     .close		= PppoeClose,
  141:     .update		= PppoeNodeUpdate,
  142:     .shutdown		= PppoeShutdown,
  143:     .showstat		= PppoeStat,
  144:     .originate		= PppoeOriginated,
  145:     .issync		= PppoeIsSync,
  146:     .peeraddr		= PppoePeerMacAddr,
  147:     .peermacaddr	= PppoePeerMacAddr,
  148:     .peeriface		= PppoePeerIface,
  149:     .callingnum		= PppoeCallingNum,
  150:     .callednum		= PppoeCalledNum,
  151:     .selfname		= PppoeSelfName,
  152:     .peername		= PppoePeerName,
  153: };
  154: 
  155: const struct cmdtab PppoeSetCmds[] = {
  156:       { "iface {name}",		"Set ethernet interface to use",
  157: 	  PppoeSetCommand, NULL, 2, (void *)SET_IFACE },
  158:       { "service {name}",	"Set PPPoE session name",
  159: 	  PppoeSetCommand, NULL, 2, (void *)SET_SESSION },
  160:       { "acname {name}",	"Set PPPoE access concentrator name",
  161: 	  PppoeSetCommand, NULL, 2, (void *)SET_ACNAME },
  162:       { NULL },
  163: };
  164: 
  165: /* 
  166:  * INTERNAL VARIABLES 
  167:  */
  168: 
  169: struct PppoeList {
  170:     char	session[MAX_SESSION];
  171:     int		refs;
  172:     SLIST_ENTRY(PppoeList)	next;
  173: };
  174: 
  175: struct PppoeIf {
  176:     char	ifnodepath[MAX_PATH];
  177:     ng_ID_t	node_id;		/* pppoe node id */
  178:     int		refs;
  179:     int		csock;                  /* netgraph Control socket */
  180:     int		dsock;                  /* netgraph Data socket */
  181:     EventRef	ctrlEvent;		/* listen for ctrl messages */
  182:     EventRef	dataEvent;		/* listen for data messages */
  183:     SLIST_HEAD(, PppoeList) list;
  184: };
  185: 
  186: int PppoeIfCount=0;
  187: struct PppoeIf PppoeIfs[PPPOE_MAXPARENTIFS];
  188: 
  189: /*
  190:  * PppoeInit()
  191:  *
  192:  * Initialize device-specific data in physical layer info
  193:  */
  194: static int
  195: PppoeInit(Link l)
  196: {
  197: 	PppoeInfo pe;
  198: 
  199: 	/* Allocate private struct */
  200: 	pe = (PppoeInfo)(l->info = Malloc(MB_PHYS, sizeof(*pe)));
  201: 	pe->incoming = 0;
  202: 	pe->opened = 0;
  203: 	snprintf(pe->path, sizeof(pe->path), "undefined:");
  204: 	snprintf(pe->hook, sizeof(pe->hook), "undefined");
  205: 	snprintf(pe->session, sizeof(pe->session), "*");
  206: 	memset(pe->peeraddr, 0x00, ETHER_ADDR_LEN);
  207: 	strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
  208: 	pe->agent_cid[0] = 0;
  209: 	pe->agent_rid[0] = 0;
  210: 	pe->PIf = NULL;
  211: 
  212: 	/* Done */
  213: 	return(0);
  214: }
  215: 
  216: /*
  217:  * PppoeInst()
  218:  *
  219:  * Instantiate device
  220:  */
  221: static int
  222: PppoeInst(Link l, Link lt)
  223: {
  224: 	PppoeInfo pi;
  225: 	l->info = Mdup(MB_PHYS, lt->info, sizeof(struct pppoeinfo));
  226: 	pi = (PppoeInfo)l->info;
  227: 	if (pi->PIf)
  228: 	    pi->PIf->refs++;
  229: 	if (pi->list)
  230: 	    pi->list->refs++;
  231: 
  232: 	/* Done */
  233: 	return(0);
  234: }
  235: 
  236: /*
  237:  * PppoeOpen()
  238:  */
  239: static void
  240: PppoeOpen(Link l)
  241: {
  242: 	PppoeInfo pe = (PppoeInfo)l->info;
  243: 	struct ngm_connect	cn;
  244: 	union {
  245: 	    u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
  246: 	    struct ngpppoe_init_data	poeid;
  247: 	} u;
  248: 	struct ngpppoe_init_data *const idata = &u.poeid;
  249: 	char path[NG_PATHSIZ];
  250: 	char session_hook[NG_HOOKSIZ];
  251: 
  252: 	pe->opened=1;
  253: 
  254: 	Disable(&l->conf.options, LINK_CONF_ACFCOMP);	/* RFC 2516 */
  255: 	Deny(&l->conf.options, LINK_CONF_ACFCOMP);	/* RFC 2516 */
  256: 
  257: 	snprintf(session_hook, sizeof(session_hook), "mpd%d-%d", 
  258: 	    gPid, l->id);
  259: 	
  260: 	if (pe->incoming == 1) {
  261: 		Log(LG_PHYS2, ("[%s] PppoeOpen() on incoming call", l->name));
  262: 
  263: 		/* Path to the ng_tee node */
  264: 		snprintf(path, sizeof(path), "[%x]:%s", 
  265: 		    pe->PIf->node_id, session_hook);
  266: 
  267: 		/* Connect ng_tee(4) node to the ng_ppp(4) node. */
  268: 		memset(&cn, 0, sizeof(cn));
  269: 		if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
  270: 		    Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
  271: 		    goto fail3;
  272: 		}
  273: 		snprintf(cn.ourhook, sizeof(cn.ourhook), "right");
  274: 		if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
  275: 		    &cn, sizeof(cn)) < 0) {
  276: 			Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
  277: 	    		    l->name, path, cn.ourhook, cn.path, cn.peerhook);
  278: 			goto fail3;
  279: 		}
  280: 
  281: 		/* Shutdown ng_tee node */
  282: 		if (NgFuncShutdownNode(pe->PIf->csock, l->name, path) < 0) {
  283: 			Perror("[%s] PPPoE: Shutdown ng_tee node %s error",
  284: 			    l->name, path);
  285: 		}
  286: 
  287: 		if (l->state==PHYS_STATE_READY) {
  288: 		    TimerStop(&pe->connectTimer);
  289: 		    l->state = PHYS_STATE_UP;
  290: 		    PhysUp(l);
  291: 		}
  292: 		return;
  293: 	}
  294: 
  295: 	/* Sanity check. */
  296: 	if (l->state != PHYS_STATE_DOWN) {
  297: 		Log(LG_PHYS, ("[%s] PPPoE allready active", l->name));
  298: 		return;
  299: 	};
  300: 
  301: 	/* Create PPPoE node if necessary. */
  302: 	PppoeGetNode(l);
  303: 
  304: 	if (!pe->PIf) {
  305: 	    Log(LG_ERR, ("[%s] PPPoE node for link is not initialized",
  306: 	        l->name));
  307: 	    goto fail;
  308: 	}
  309: 
  310: 	/* Connect our ng_ppp(4) node link hook to the ng_pppoe(4) node. */
  311: 	strlcpy(cn.ourhook, session_hook, sizeof(cn.ourhook));
  312: 	snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
  313: 
  314: 	if (!PhysGetUpperHook(l, cn.path, cn.peerhook)) {
  315: 	    Log(LG_PHYS, ("[%s] PPPoE: can't get upper hook", l->name));
  316: 	    goto fail2;
  317: 	}
  318: 	
  319: 	if (NgSendMsg(pe->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, 
  320: 	    &cn, sizeof(cn)) < 0) {
  321: 		Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
  322:     		    l->name, path, cn.ourhook, cn.path, cn.peerhook);
  323: 		goto fail2;
  324: 	}
  325: 
  326: 	Log(LG_PHYS, ("[%s] PPPoE: Connecting to '%s'", l->name, pe->session));
  327: 	
  328: 	/* Tell the PPPoE node to try to connect to a server. */
  329: 	memset(idata, 0, sizeof(idata));
  330: 	strlcpy(idata->hook, session_hook, sizeof(idata->hook));
  331: 	idata->data_len = strlen(pe->session);
  332: 	strncpy(idata->data, pe->session, MAX_SESSION);
  333: 	if (NgSendMsg(pe->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT,
  334: 	    idata, sizeof(*idata) + idata->data_len) < 0) {
  335: 		Perror("[%s] PPPoE can't request connection to server", l->name);
  336: 		goto fail2;
  337: 	}
  338: 
  339: 	/* Set a timer to limit connection time. */
  340: 	TimerInit(&pe->connectTimer, "PPPoE-connect",
  341: 	    PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
  342: 	TimerStart(&pe->connectTimer);
  343: 
  344: 	/* OK */
  345: 	l->state = PHYS_STATE_CONNECTING;
  346: 	strlcpy(pe->real_session, pe->session, sizeof(pe->real_session));
  347: 	pe->agent_cid[0] = 0;
  348: 	pe->agent_rid[0] = 0;
  349: 	return;
  350: 
  351: fail3:
  352: 	snprintf(path, sizeof(path), "[%x]:", pe->PIf->node_id);
  353: fail2:
  354: 	NgFuncDisconnect(pe->PIf->csock, l->name, path, session_hook);
  355: fail:	
  356: 	PhysDown(l, STR_ERROR, NULL);
  357: 	return;
  358: }
  359: 
  360: /*
  361:  * PppoeConnectTimeout()
  362:  */
  363: static void
  364: PppoeConnectTimeout(void *arg)
  365: {
  366: 	const Link l = (Link)arg;
  367: 
  368: 	/* Cancel connection. */
  369: 	Log(LG_PHYS, ("[%s] PPPoE connection timeout after %d seconds",
  370: 	    l->name, PPPOE_CONNECT_TIMEOUT));
  371: 	PppoeDoClose(l);
  372: 	PhysDown(l, STR_CON_FAILED0, NULL);
  373: }
  374: 
  375: /*
  376:  * PppoeClose()
  377:  */
  378: static void
  379: PppoeClose(Link l)
  380: {
  381: 	const PppoeInfo pe = (PppoeInfo)l->info;
  382: 
  383: 	pe->opened = 0;
  384: 	if (l->state == PHYS_STATE_DOWN)
  385: 		return;
  386: 	PppoeDoClose(l);
  387: 	PhysDown(l, STR_MANUALLY, NULL);
  388: }
  389: 
  390: /*
  391:  * PppoeShutdown()
  392:  *
  393:  * Shut everything down and go to the PHYS_STATE_DOWN state.
  394:  */
  395: static void
  396: PppoeShutdown(Link l)
  397: {
  398: 	PppoeDoClose(l);
  399: 	PppoeUnListen(l);
  400: 	PppoeReleaseNode(l);
  401: 	Freee(l->info);
  402: }
  403: 
  404: /*
  405:  * PppoeDoClose()
  406:  *
  407:  * Shut everything down and go to the PHYS_STATE_DOWN state.
  408:  */
  409: static void
  410: PppoeDoClose(Link l)
  411: {
  412: 	const PppoeInfo pi = (PppoeInfo)l->info;
  413: 	char path[NG_PATHSIZ];
  414: 	char session_hook[NG_HOOKSIZ];
  415: 
  416: 	if (l->state == PHYS_STATE_DOWN)
  417: 		return;
  418: 
  419: 	snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
  420: 	snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
  421: 	    gPid, l->id);
  422: 	NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
  423: 
  424: 	TimerStop(&pi->connectTimer);
  425: 	l->state = PHYS_STATE_DOWN;
  426: 	pi->incoming = 0;
  427: 	memset(pi->peeraddr, 0x00, ETHER_ADDR_LEN);
  428: 	pi->real_session[0] = 0;
  429: 	pi->agent_cid[0] = 0;
  430: 	pi->agent_rid[0] = 0;
  431: }
  432: 
  433: /*
  434:  * PppoeCtrlReadEvent()
  435:  *
  436:  * Receive an incoming control message from the PPPoE node
  437:  */
  438: static void
  439: PppoeCtrlReadEvent(int type, void *arg)
  440: {
  441: 	union {
  442: 	    u_char buf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
  443: 	    struct ng_mesg resp;
  444: 	} u;
  445: 	char path[NG_PATHSIZ];
  446: 	Link l = NULL;
  447: 	PppoeInfo pi = NULL;
  448: 	
  449: 	struct PppoeIf  *PIf = (struct PppoeIf*)arg;
  450: 	
  451: 	/* Read control message. */
  452: 	if (NgRecvMsg(PIf->csock, &u.resp, sizeof(u), path) < 0) {
  453: 		Perror("PPPoE: error reading message from \"%s\"", path);
  454: 		return;
  455: 	}
  456: 	if (u.resp.header.typecookie != NGM_PPPOE_COOKIE) {
  457: 		Log(LG_ERR, ("PPPoE: rec'd cookie %lu from \"%s\"",
  458: 		    (u_long)u.resp.header.typecookie, path));
  459: 		return;
  460: 	}
  461: 
  462: 	switch (u.resp.header.cmd) {
  463: 	    case NGM_PPPOE_SUCCESS:
  464: 	    case NGM_PPPOE_FAIL:
  465: 	    case NGM_PPPOE_CLOSE:
  466: 	    {
  467: 		char	ppphook[NG_HOOKSIZ];
  468: 		char	*linkname, *rest;
  469: 		int	id;
  470: 
  471: 		/* Check hook name prefix */
  472: 		linkname = ((struct ngpppoe_sts *)u.resp.data)->hook;
  473: 		if (strncmp(linkname, "listen-", 7) == 0)
  474: 		    return;	/* We do not need them */
  475: 		snprintf(ppphook, NG_HOOKSIZ, "mpd%d-", gPid);
  476: 		if (strncmp(linkname, ppphook, strlen(ppphook))) {
  477: 		    Log(LG_ERR, ("PPPoE: message %d from unknown hook \"%s\"",
  478: 			u.resp.header.cmd, ((struct ngpppoe_sts *)u.resp.data)->hook));
  479: 		    return;
  480: 		}
  481: 		linkname += strlen(ppphook);
  482: 		id = strtol(linkname, &rest, 10);
  483: 		if (rest[0] != 0 ||
  484: 		  !gLinks[id] ||
  485: 		  gLinks[id]->type != &gPppoePhysType ||
  486: 		  PIf != ((PppoeInfo)gLinks[id]->info)->PIf) {
  487: 		    Log((u.resp.header.cmd == NGM_PPPOE_SUCCESS)?LG_ERR:LG_PHYS,
  488: 			("PPPoE: message %d from unexisting link \"%s\"",
  489: 			    u.resp.header.cmd, linkname));
  490: 		    return;
  491: 		}
  492: 		
  493: 		l = gLinks[id];
  494: 		pi = (PppoeInfo)l->info;
  495: 
  496: 		if (l->state == PHYS_STATE_DOWN) {
  497: 		    if (u.resp.header.cmd != NGM_PPPOE_CLOSE) 
  498: 			Log(LG_PHYS, ("[%s] PPPoE: message %d in DOWN state",
  499: 			    l->name, u.resp.header.cmd));
  500: 		    return;
  501: 		}
  502: 	    }
  503: 	}
  504: 
  505: 	/* Decode message. */
  506: 	switch (u.resp.header.cmd) {
  507: 	    case NGM_PPPOE_SESSIONID: /* XXX: I do not know what to do with this? */
  508: 		break;
  509: 	    case NGM_PPPOE_SUCCESS:
  510: 		Log(LG_PHYS, ("[%s] PPPoE: connection successful", l->name));
  511: 		if (pi->opened) {
  512: 		    TimerStop(&pi->connectTimer);
  513: 		    l->state = PHYS_STATE_UP;
  514: 		    PhysUp(l);
  515: 		} else {
  516: 		    l->state = PHYS_STATE_READY;
  517: 		}
  518: 		break;
  519: 	    case NGM_PPPOE_FAIL:
  520: 		Log(LG_PHYS, ("[%s] PPPoE: connection failed", l->name));
  521: 		PppoeDoClose(l);
  522: 		PhysDown(l, STR_CON_FAILED0, NULL);
  523: 		break;
  524: 	    case NGM_PPPOE_CLOSE:
  525: 		Log(LG_PHYS, ("[%s] PPPoE: connection closed", l->name));
  526: 		PppoeDoClose(l);
  527: 		PhysDown(l, STR_DROPPED, NULL);
  528: 		break;
  529: 	    case NGM_PPPOE_ACNAME:
  530: 		Log(LG_PHYS, ("PPPoE: rec'd ACNAME \"%s\"",
  531: 		  ((struct ngpppoe_sts *)u.resp.data)->hook));
  532: 		break;
  533: 	    default:
  534: 		Log(LG_PHYS, ("PPPoE: rec'd command %lu from \"%s\"",
  535: 		    (u_long)u.resp.header.cmd, path));
  536: 		break;
  537: 	}
  538: }
  539: 
  540: /*
  541:  * PppoeStat()
  542:  */
  543: void
  544: PppoeStat(Context ctx)
  545: {
  546: 	const PppoeInfo pe = (PppoeInfo)ctx->lnk->info;
  547: 	char	buf[32];
  548: 
  549: 	Printf("PPPoE configuration:\r\n");
  550: 	Printf("\tIface Node   : %s\r\n", pe->path);
  551: 	Printf("\tIface Hook   : %s\r\n", pe->hook);
  552: 	Printf("\tSession      : %s\r\n", pe->session);
  553: 	Printf("PPPoE status:\r\n");
  554: 	if (ctx->lnk->state != PHYS_STATE_DOWN) {
  555: 	    Printf("\tOpened       : %s\r\n", (pe->opened?"YES":"NO"));
  556: 	    Printf("\tIncoming     : %s\r\n", (pe->incoming?"YES":"NO"));
  557: 	    PppoePeerMacAddr(ctx->lnk, buf, sizeof(buf));
  558: 	    Printf("\tCurrent peer : %s\r\n", buf);
  559: 	    Printf("\tSession      : %s\r\n", pe->real_session);
  560: 	    Printf("\tCircuit-ID   : %s\r\n", pe->agent_cid);
  561: 	    Printf("\tRemote-ID    : %s\r\n", pe->agent_rid);
  562: 	}
  563: }
  564: 
  565: /*
  566:  * PppoeOriginated()
  567:  */
  568: static int
  569: PppoeOriginated(Link l)
  570: {
  571: 	PppoeInfo      const pppoe = (PppoeInfo)l->info;
  572: 
  573: 	return (pppoe->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
  574: }
  575: 
  576: /*
  577:  * PppoeIsSync()
  578:  */
  579: static int
  580: PppoeIsSync(Link l)
  581: {
  582: 	return (1);
  583: }
  584: 
  585: static int
  586: PppoePeerMacAddr(Link l, void *buf, size_t buf_len)
  587: {
  588: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  589: 
  590: 	snprintf(buf, buf_len, "%02x:%02x:%02x:%02x:%02x:%02x",
  591: 	    pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2], 
  592: 	    pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  593: 
  594: 	return (0);
  595: }
  596: 
  597: static int
  598: PppoePeerIface(Link l, void *buf, size_t buf_len)
  599: {
  600: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  601: 	char iface[IFNAMSIZ];
  602: 
  603: 	strlcpy(iface, pppoe->path, sizeof(iface));
  604: 	if (iface[strlen(iface) - 1] == ':')
  605: 		iface[strlen(iface) - 1] = '\0';
  606: 	strlcpy(buf, iface, buf_len);
  607: 	return (0);
  608: }
  609: 
  610: static int
  611: PppoeCallingNum(Link l, void *buf, size_t buf_len)
  612: {
  613: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  614: 
  615: 	if (pppoe->incoming) {
  616: 	    snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
  617: 		pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2], 
  618: 		pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  619: 	} else {
  620: 	    strlcpy(buf, pppoe->real_session, buf_len);
  621: 	}
  622: 
  623: 	return (0);
  624: }
  625: 
  626: static int
  627: PppoeCalledNum(Link l, void *buf, size_t buf_len)
  628: {
  629: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  630: 
  631: 	if (!pppoe->incoming) {
  632: 	    snprintf(buf, buf_len, "%02x%02x%02x%02x%02x%02x",
  633: 		pppoe->peeraddr[0], pppoe->peeraddr[1], pppoe->peeraddr[2], 
  634: 		pppoe->peeraddr[3], pppoe->peeraddr[4], pppoe->peeraddr[5]);
  635: 	} else {
  636: 	    strlcpy(buf, pppoe->real_session, buf_len);
  637: 	}
  638: 
  639: 	return (0);
  640: }
  641: 
  642: static int
  643: PppoeSelfName(Link l, void *buf, size_t buf_len)
  644: {
  645: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  646: 
  647: 	strlcpy(buf, pppoe->agent_cid, buf_len);
  648: 
  649: 	return (0);
  650: }
  651: 
  652: static int
  653: PppoePeerName(Link l, void *buf, size_t buf_len)
  654: {
  655: 	PppoeInfo	const pppoe = (PppoeInfo)l->info;
  656: 
  657: 	strlcpy(buf, pppoe->agent_rid, buf_len);
  658: 
  659: 	return (0);
  660: }
  661: 
  662: static int 
  663: CreatePppoeNode(struct PppoeIf *PIf, const char *path, const char *hook)
  664: {
  665:         union {
  666: 		u_char          buf[sizeof(struct ng_mesg) + 2048];
  667: 		struct ng_mesg  reply;
  668: 	} u;
  669: 	struct ng_mesg *resp;
  670: 	const struct hooklist *hlist;
  671: 	const struct nodeinfo *ninfo;
  672: 	int f;
  673: 
  674: 	/* Make sure interface is up. */
  675: 	char iface[IFNAMSIZ];
  676: 
  677: 	strlcpy(iface, path, sizeof(iface));
  678: 	if (iface[strlen(iface) - 1] == ':')
  679: 		iface[strlen(iface) - 1] = '\0';
  680: 	if (ExecCmdNosh(LG_PHYS2, iface, "%s %s up", PATH_IFCONFIG, iface) != 0) {
  681: 		Log(LG_ERR, ("PPPoE: can't bring up interface %s",
  682: 		    iface));
  683: 		return (0);
  684: 	}
  685: 
  686: 	/* Create a new netgraph node */
  687: 	if (NgMkSockNode(NULL, &PIf->csock, &PIf->dsock) < 0) {
  688: 		Perror("[%s] PPPoE: can't create ctrl socket", iface);
  689: 		return(0);
  690: 	}
  691: 	(void)fcntl(PIf->csock, F_SETFD, 1);
  692: 	(void)fcntl(PIf->dsock, F_SETFD, 1);
  693: 
  694: 	/* Check if NG_ETHER_NODE_TYPE is available. */
  695: 	if (gNgEtherLoaded == FALSE) {
  696: 		const struct typelist *tlist;
  697: 
  698: 		/* Ask for a list of available node types. */
  699: 		if (NgSendMsg(PIf->csock, "", NGM_GENERIC_COOKIE, NGM_LISTTYPES,
  700: 		    NULL, 0) < 0) {
  701: 			Perror("[%s] PPPoE: Cannot send a netgraph message",
  702: 			    iface);
  703: 			close(PIf->csock);
  704: 			close(PIf->dsock);
  705: 			return (0);
  706: 		}
  707: 
  708: 		/* Get response. */
  709: 		resp = &u.reply;
  710: 		if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
  711: 			Perror("[%s] PPPoE: Cannot get netgraph response",
  712: 			    iface);
  713: 			close(PIf->csock);
  714: 			close(PIf->dsock);
  715: 			return (0);
  716: 		}
  717: 
  718: 		/* Look for NG_ETHER_NODE_TYPE. */
  719: 		tlist = (const struct typelist*) resp->data;
  720: 		for (f = 0; f < tlist->numtypes; f++)
  721: 			if (strncmp(tlist->typeinfo[f].type_name,
  722: 			    NG_ETHER_NODE_TYPE,
  723: 			    sizeof(NG_ETHER_NODE_TYPE) - 1) == 0)
  724: 				gNgEtherLoaded = TRUE;
  725: 
  726: 		/* If not found try to load ng_ether and repeat the check. */
  727: 		if (gNgEtherLoaded == FALSE && (kldload("ng_ether") < 0)) {
  728: 			Perror("PPPoE: Cannot load ng_ether");
  729: 			close(PIf->csock);
  730: 			close(PIf->dsock);
  731: 			assert (0);
  732: 		}
  733: 		gNgEtherLoaded = TRUE;
  734: 	}
  735: 
  736: 	/*
  737: 	 * Ask for a list of hooks attached to the "ether" node. This node
  738: 	 * should magically exist as a way of hooking stuff onto an ethernet
  739: 	 * device.
  740: 	 */
  741: 	if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
  742: 	    NULL, 0) < 0) {
  743: 		Perror("[%s] Cannot send a netgraph message: %s", iface, path);
  744: 		close(PIf->csock);
  745: 		close(PIf->dsock);
  746: 		return (0);
  747: 	}
  748: 
  749: 	/* Get our list back. */
  750: 	resp = &u.reply;
  751: 	if (NgRecvMsg(PIf->csock, resp, sizeof(u.buf), NULL) <= 0) {
  752: 		Perror("[%s] Cannot get netgraph response", iface);
  753: 		close(PIf->csock);
  754: 		close(PIf->dsock);
  755: 		return (0);
  756: 	}
  757: 
  758: 	hlist = (const struct hooklist *)resp->data;
  759: 	ninfo = &hlist->nodeinfo;
  760: 
  761: 	/* Make sure we've got the right type of node. */
  762: 	if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
  763: 	    sizeof(NG_ETHER_NODE_TYPE) - 1)) {
  764: 		Log(LG_ERR, ("[%s] Unexpected node type ``%s'' (wanted ``"
  765: 		    NG_ETHER_NODE_TYPE "'') on %s",
  766: 		    iface, ninfo->type, path));
  767: 		close(PIf->csock);
  768: 		close(PIf->dsock);
  769: 		return (0);
  770: 	}
  771: 
  772: 	/* Look for a hook already attached. */
  773: 	for (f = 0; f < ninfo->hooks; f++) {
  774: 		const struct linkinfo *nlink = &hlist->link[f];
  775: 
  776: 		/* Search for "orphans" hook. */
  777: 		if (strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) &&
  778: 		    strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT))
  779: 			continue;
  780: 
  781: 		/*
  782: 		 * Something is using the data coming out of this ``ether''
  783: 		 * node. If it's a PPPoE node, we use that node, otherwise
  784: 		 * we complain that someone else is using the node.
  785: 		 */
  786: 		if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) {
  787: 			Log(LG_ERR, ("%s Node type ``%s'' is currently "
  788: 			    " using orphan hook\n",
  789: 			    path, nlink->nodeinfo.type));
  790: 			close(PIf->csock);
  791: 			close(PIf->dsock);
  792: 			return (0);
  793: 		}
  794: 		PIf->node_id = nlink->nodeinfo.id;
  795: 		break;
  796: 	}
  797: 
  798: 	if (f == ninfo->hooks) {
  799: 		struct ngm_mkpeer mp;
  800: 		char	path2[NG_PATHSIZ];
  801: 
  802: 		/* Create new PPPoE node. */
  803: 		memset(&mp, 0, sizeof(mp));
  804: 		strcpy(mp.type, NG_PPPOE_NODE_TYPE);
  805: 		strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
  806: 		strcpy(mp.peerhook, NG_PPPOE_HOOK_ETHERNET);
  807: 		if (NgSendMsg(PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, &mp,
  808: 		    sizeof(mp)) < 0) {
  809: 			Perror("[%s] can't create %s peer to %s,%s",
  810: 			    iface, NG_PPPOE_NODE_TYPE, path, hook);
  811: 			close(PIf->csock);
  812: 			close(PIf->dsock);
  813: 			return (0);
  814: 		}
  815: 
  816: 		snprintf(path2, sizeof(path2), "%s%s", path, hook);
  817: 		/* Get pppoe node ID */
  818: 		if ((PIf->node_id = NgGetNodeID(PIf->csock, path2)) == 0) {
  819: 			Perror("[%s] Cannot get pppoe node id", iface);
  820: 			close(PIf->csock);
  821: 			close(PIf->dsock);
  822: 			return (0);
  823: 		};
  824: 	};
  825: 
  826: 	/* Register an event listening to the control and data sockets. */
  827: 	EventRegister(&(PIf->ctrlEvent), EVENT_READ, PIf->csock,
  828: 	    EVENT_RECURRING, PppoeCtrlReadEvent, PIf);
  829: 	EventRegister(&(PIf->dataEvent), EVENT_READ, PIf->dsock,
  830: 	    EVENT_RECURRING, PppoeListenEvent, PIf);
  831: 
  832: 	return (1);
  833: }
  834: 
  835: /*
  836:  * Look for a tag of a specific type.
  837:  * Don't trust any length the other end says,
  838:  * but assume we already sanity checked ph->length.
  839:  */
  840: static const struct pppoe_tag*
  841: get_tag(const struct pppoe_hdr* ph, uint16_t idx)
  842: {
  843: 	const char *const end = ((const char *)(ph + 1))
  844: 	            + ntohs(ph->length);
  845: 	const struct pppoe_tag *pt = (const void *)(ph + 1);
  846: 	const char *ptn;
  847: 
  848: 	/*
  849: 	 * Keep processing tags while a tag header will still fit.
  850: 	 */
  851: 	while((const char*)(pt + 1) <= end) {
  852: 		/*
  853: 		 * If the tag data would go past the end of the packet, abort.
  854: 		 */
  855: 		ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
  856: 		if (ptn > end)
  857: 			return (NULL);
  858: 		if (pt->tag_type == idx)
  859: 			return (pt);
  860: 
  861: 		pt = (const struct pppoe_tag*)ptn;
  862: 	}
  863: 
  864: 	return (NULL);
  865: }
  866: 
  867: static const struct pppoe_tag*
  868: get_vs_tag(const struct pppoe_hdr* ph, uint32_t idx)
  869: {
  870: 	const char *const end = ((const char *)(ph + 1))
  871: 	            + ntohs(ph->length);
  872: 	const struct pppoe_tag *pt = (const void *)(ph + 1);
  873: 	const char *ptn;
  874: 
  875: 	/*
  876: 	 * Keep processing tags while a tag header will still fit.
  877: 	 */
  878: 	while((const char*)(pt + 1) <= end) {
  879: 		/*
  880: 		 * If the tag data would go past the end of the packet, abort.
  881: 		 */
  882: 		ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
  883: 		if (ptn > end)
  884: 			return (NULL);
  885: 		if (pt->tag_type == PTT_VENDOR &&
  886: 		    ntohs(pt->tag_len) >= 4 &&
  887: 		    *(const uint32_t*)(pt + 1) == idx)
  888: 			return (pt);
  889: 
  890: 		pt = (const struct pppoe_tag*)ptn;
  891: 	}
  892: 
  893: 	return (NULL);
  894: }
  895: 
  896: static void
  897: PppoeListenEvent(int type, void *arg)
  898: {
  899: 	int			k, sz;
  900: 	struct PppoeIf		*PIf = (struct PppoeIf *)(arg);
  901: 	char			rhook[NG_HOOKSIZ];
  902: 	unsigned char		response[1024];
  903: 
  904: 	char			path[NG_PATHSIZ];
  905: 	char			path1[NG_PATHSIZ];
  906: 	char			session_hook[NG_HOOKSIZ];
  907: 	char			*session;
  908: 	char			real_session[MAX_SESSION];
  909: 	char			agent_cid[64];
  910: 	char			agent_rid[64];
  911: 	struct ngm_connect      cn;
  912: 	struct ngm_mkpeer 	mp;
  913: 	Link 			l = NULL;
  914: 	PppoeInfo		pi = NULL;
  915: 	const struct pppoe_full_hdr	*wh;
  916: 	const struct pppoe_hdr	*ph;
  917: 	const struct pppoe_tag  *tag;
  918: 
  919: 	union {
  920: 	    u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
  921: 	    struct ngpppoe_init_data poeid;
  922: 	} u;
  923: 	struct ngpppoe_init_data *const idata = &u.poeid;
  924: 
  925: 	switch (sz = NgRecvData(PIf->dsock, response, sizeof(response), rhook)) {
  926:           case -1:
  927: 	    Log(LG_ERR, ("NgRecvData: %d", sz));
  928:             return;
  929:           case 0:
  930:             Log(LG_ERR, ("NgRecvData: socket closed"));
  931:             return;
  932:         }
  933: 
  934: 	if (strncmp(rhook, "listen-", 7)) {
  935: 		Log(LG_ERR, ("PPPoE: data from unknown hook \"%s\"", rhook));
  936: 		return;
  937: 	}
  938: 
  939: 	session = rhook + 7;
  940: 
  941: 	if (sz < sizeof(struct pppoe_full_hdr)) {
  942: 		Log(LG_PHYS, ("Incoming truncated PPPoE connection request via %s for "
  943: 		    "service \"%s\"", PIf->ifnodepath, session));
  944: 		return;
  945: 	}
  946: 
  947: 	wh = (struct pppoe_full_hdr *)response;
  948: 	ph = &wh->ph;
  949: 	if ((tag = get_tag(ph, PTT_SRV_NAME))) {
  950: 	    int len = ntohs(tag->tag_len);
  951: 	    if (len >= sizeof(real_session))
  952: 		len = sizeof(real_session)-1;
  953: 	    memcpy(real_session, tag + 1, len);
  954: 	    real_session[len] = 0;
  955: 	} else {
  956: 	    strlcpy(real_session, session, sizeof(real_session));
  957: 	}
  958: 	bzero(agent_cid, sizeof(agent_cid));
  959: 	bzero(agent_rid, sizeof(agent_rid));
  960: 	if ((tag = get_vs_tag(ph, htonl(0x00000DE9)))) {
  961: 	    int len = ntohs(tag->tag_len) - 4, pos = 0;
  962: 	    const char *b = (const char *)(tag + 1) + 4;
  963: 	    while (pos + 1 <= len) {
  964: 		int len1 = b[pos + 1];
  965: 		if (len1 > len - pos - 2)
  966: 		    break;
  967: 		if (len1 >= sizeof(agent_rid))
  968: 		    len1 = sizeof(agent_rid) - 1;
  969: 		switch (b[pos]) {
  970: 		    case 1:
  971: 			strncpy(agent_cid, &b[pos + 2], len1);
  972: 			break;
  973: 		    case 2:
  974: 			strncpy(agent_rid, &b[pos + 2], len1);
  975: 			break;
  976: 		}
  977: 		pos += 2 + len1;
  978: 	    }
  979: 	}
  980: 	Log(LG_PHYS, ("Incoming PPPoE connection request via %s for "
  981: 	    "service \"%s\" from %s", PIf->ifnodepath, real_session,
  982: 	    ether_ntoa((struct  ether_addr *)&wh->eh.ether_shost)));
  983: 
  984: 	if (gShutdownInProgress) {
  985: 		Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
  986: 		return;
  987: 	}
  988: 
  989: 	if (OVERLOAD()) {
  990: 		Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
  991: 		return;
  992: 	}
  993: 
  994: 	/* Examine all PPPoE links. */
  995: 	for (k = 0; k < gNumLinks; k++) {
  996: 		Link l2;
  997: 	        PppoeInfo pi2;
  998: 
  999: 		if (!gLinks[k] || gLinks[k]->type != &gPppoePhysType)
 1000: 			continue;
 1001: 
 1002: 		l2 = gLinks[k];
 1003: 		pi2 = (PppoeInfo)l2->info;
 1004: 
 1005: 		if ((!PhysIsBusy(l2)) &&
 1006: 		    (pi2->PIf == PIf) &&
 1007: 		    (strcmp(pi2->session, session) == 0) &&
 1008: 		    Enabled(&l2->conf.options, LINK_CONF_INCOMING)) {
 1009: 			l = l2;
 1010: 			break;
 1011: 		}
 1012: 	}
 1013: 	
 1014: 	if (l != NULL && l->tmpl)
 1015: 	    l = LinkInst(l, NULL, 0, 0);
 1016: 
 1017: 	if (l == NULL) {
 1018: 		Log(LG_PHYS, ("No free PPPoE link with requested parameters "
 1019: 		    "was found"));
 1020: 		return;
 1021: 	}
 1022: 	pi = (PppoeInfo)l->info;
 1023: 	
 1024: 	Log(LG_PHYS, ("[%s] Accepting PPPoE connection", l->name));
 1025: 
 1026: 	/* Path to the ng_pppoe */
 1027: 	snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
 1028: 
 1029: 	/* Name of ng_pppoe session hook */
 1030: 	snprintf(session_hook, sizeof(session_hook), "mpd%d-%d",
 1031: 	    gPid, l->id);
 1032: 		
 1033: 	/* Create ng_tee(4) node and connect it to ng_pppoe(4). */
 1034: 	memset(&mp, 0, sizeof(mp));
 1035: 	strcpy(mp.type, NG_TEE_NODE_TYPE);
 1036: 	strlcpy(mp.ourhook, session_hook, sizeof(mp.ourhook));
 1037: 	snprintf(mp.peerhook, sizeof(mp.peerhook), "left");
 1038: 	if (NgSendMsg(pi->PIf->csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
 1039: 	    &mp, sizeof(mp)) < 0) {
 1040: 		Perror("[%s] PPPoE: can't create %s peer to %s,%s",
 1041: 		    l->name, NG_TEE_NODE_TYPE, path, "left");
 1042: 		goto close_socket;
 1043: 	}
 1044: 
 1045: 	/* Path to the ng_tee */
 1046: 	snprintf(path1, sizeof(path), "%s%s", path, session_hook);
 1047: 
 1048: 	/* Connect our socket node link hook to the ng_tee(4) node. */
 1049: 	memset(&cn, 0, sizeof(cn));
 1050: 	strlcpy(cn.ourhook, l->name, sizeof(cn.ourhook));
 1051: 	strlcpy(cn.path, path1, sizeof(cn.path));
 1052: 	strcpy(cn.peerhook, "left2right");
 1053: 	if (NgSendMsg(pi->PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
 1054: 	    &cn, sizeof(cn)) < 0) {
 1055: 		Perror("[%s] PPPoE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 1056: 		    l->name, ".:", cn.ourhook, cn.path, cn.peerhook);
 1057: 		goto shutdown_tee;
 1058: 	}
 1059: 
 1060: 	/* Put the PPPoE node into OFFER mode. */
 1061: 	memset(idata, 0, sizeof(*idata));
 1062: 	strlcpy(idata->hook, session_hook, sizeof(idata->hook));
 1063: 	if (pi->acname[0] != 0) {
 1064: 		strlcpy(idata->data, pi->acname, MAX_SESSION);
 1065: 	} else {
 1066: 		if (gethostname(idata->data, MAX_SESSION) == -1) {
 1067: 			Log(LG_ERR, ("[%s] PPPoE: gethostname() failed",
 1068: 			    l->name));
 1069: 			idata->data[0] = 0;
 1070: 		}
 1071: 		if (idata->data[0] == 0)
 1072: 			strlcpy(idata->data, "NONAME", MAX_SESSION);
 1073: 	}
 1074: 	idata->data_len=strlen(idata->data);
 1075: 
 1076: 	if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER,
 1077: 	    idata, sizeof(*idata) + idata->data_len) < 0) {
 1078: 		Perror("[%s] PPPoE: can't send NGM_PPPOE_OFFER to %s,%s ",
 1079: 		    l->name, path, idata->hook);
 1080: 		goto shutdown_tee;
 1081: 	}
 1082: 
 1083: 	memset(idata, 0, sizeof(*idata));
 1084: 	strlcpy(idata->hook, session_hook, sizeof(idata->hook));
 1085: 	idata->data_len = strlen(pi->session);
 1086: 	strncpy(idata->data, pi->session, MAX_SESSION);
 1087: 
 1088: 	if (NgSendMsg(pi->PIf->csock, path, NGM_PPPOE_COOKIE,
 1089: 	    NGM_PPPOE_SERVICE, idata,
 1090: 	    sizeof(*idata) + idata->data_len) < 0) {
 1091: 		Perror("[%s] PPPoE: can't send NGM_PPPOE_SERVICE to %s,%s",
 1092: 		    l->name, path, idata->hook);
 1093: 		goto shutdown_tee;
 1094: 	}
 1095: 
 1096: 	/* And send our request data to the waiting node. */
 1097: 	if (NgSendData(pi->PIf->dsock, l->name, response, sz) == -1) {
 1098: 		Perror("[%s] PPPoE: Cannot send original request", l->name);
 1099: 		goto shutdown_tee;
 1100: 	}
 1101: 		
 1102: 	if (NgFuncDisconnect(pi->PIf->csock, l->name, ".:", l->name) < 0) {
 1103: 		Perror("[%s] PPPoE: can't remove hook %s", l->name, l->name);
 1104: 		goto shutdown_tee;
 1105:     	}
 1106: 	l->state = PHYS_STATE_CONNECTING;
 1107: 	pi->incoming = 1;
 1108: 	/* Record the peer's MAC address */
 1109: 	memcpy(pi->peeraddr, wh->eh.ether_shost, 6);
 1110: 	strlcpy(pi->real_session, real_session, sizeof(pi->real_session));
 1111: 	strlcpy(pi->agent_cid, agent_cid, sizeof(pi->agent_cid));
 1112: 	strlcpy(pi->agent_rid, agent_rid, sizeof(pi->agent_rid));
 1113: 
 1114: 	Log(LG_PHYS2, ("[%s] PPPoE response sent", l->name));
 1115: 
 1116: 	/* Set a timer to limit connection time. */
 1117: 	TimerInit(&pi->connectTimer, "PPPoE-connect",
 1118: 	    PPPOE_CONNECT_TIMEOUT * SECONDS, PppoeConnectTimeout, l);
 1119: 	TimerStart(&pi->connectTimer);
 1120: 
 1121: 	PhysIncoming(l);
 1122: 	return;
 1123: 
 1124: shutdown_tee:
 1125: 	if (NgFuncShutdownNode(pi->PIf->csock, l->name, path1) < 0) {
 1126: 	    Perror("[%s] Shutdown ng_tee node %s error", l->name, path1);
 1127: 	};
 1128: 
 1129: close_socket:
 1130: 	Log(LG_PHYS, ("[%s] PPPoE connection not accepted due to error",
 1131: 	    l->name));
 1132: 
 1133: 	/* If link is not static - shutdown it. */
 1134: 	if (!l->stay)
 1135: 	    LinkShutdown(l);
 1136: }
 1137: 
 1138: /*
 1139:  * PppoeGetNode()
 1140:  */
 1141: 
 1142: static void
 1143: PppoeGetNode(Link l)
 1144: {
 1145:     int i, j = -1, free = -1;
 1146:     PppoeInfo pi = (PppoeInfo)l->info;
 1147: 
 1148:     if (pi->PIf) // Do this only once for interface
 1149: 	return;
 1150: 
 1151:     if (!strcmp(pi->path, "undefined:")) {
 1152:     	    Log(LG_ERR, ("[%s] PPPoE: Skipping link \"%s\" with undefined "
 1153: 	        "interface", l->name, l->name));
 1154: 	    return;
 1155:     }
 1156: 
 1157:     for (i = 0; i < PPPOE_MAXPARENTIFS; i++) {
 1158: 	if (PppoeIfs[i].ifnodepath[0] == 0) {
 1159: 	    free = i;
 1160: 	} else if (strcmp(PppoeIfs[i].ifnodepath, pi->path) == 0) {
 1161:     	    j = i;
 1162: 	    break;
 1163: 	}
 1164:     }
 1165:     if (j == -1) {
 1166: 	if (free == -1) {
 1167: 		Log(LG_ERR, ("[%s] PPPoE: Too many different parent interfaces! ", 
 1168: 		    l->name));
 1169: 		return;
 1170: 	}
 1171: 	if (CreatePppoeNode(&PppoeIfs[free], pi->path, pi->hook)) {
 1172: 		strlcpy(PppoeIfs[free].ifnodepath,
 1173: 		    pi->path,
 1174: 		    sizeof(PppoeIfs[free].ifnodepath));
 1175: 		PppoeIfs[free].refs = 1;
 1176: 		pi->PIf = &PppoeIfs[free];
 1177: 	} else {
 1178: 		Log(LG_ERR, ("[%s] PPPoE: Error creating ng_pppoe "
 1179: 		    "node on %s", l->name, pi->path));
 1180: 		return;
 1181: 	}
 1182:     } else {
 1183: 	PppoeIfs[j].refs++;
 1184:         pi->PIf = &PppoeIfs[j];
 1185:     }
 1186: }
 1187: 
 1188: /*
 1189:  * PppoeReleaseNode()
 1190:  */
 1191: 
 1192: static void
 1193: PppoeReleaseNode(Link l)
 1194: {
 1195:     PppoeInfo pi = (PppoeInfo)l->info;
 1196: 
 1197:     if (!pi->PIf) // Do this only once for interface
 1198: 	return;
 1199: 
 1200:     pi->PIf->refs--;
 1201:     if (pi->PIf->refs == 0) {
 1202: 	pi->PIf->ifnodepath[0] = 0;
 1203: 	pi->PIf->node_id = 0;
 1204: 	EventUnRegister(&pi->PIf->ctrlEvent);
 1205: 	EventUnRegister(&pi->PIf->dataEvent);
 1206: 	close(pi->PIf->csock);
 1207: 	pi->PIf->csock = -1;
 1208: 	close(pi->PIf->dsock);
 1209: 	pi->PIf->dsock = -1;
 1210:     }
 1211: 
 1212:     pi->PIf = NULL;
 1213: }
 1214: 
 1215: static int 
 1216: PppoeListen(Link l)
 1217: {
 1218: 	PppoeInfo pi = (PppoeInfo)l->info;
 1219: 	struct PppoeIf *PIf = pi->PIf;
 1220: 	struct PppoeList *pl;
 1221: 	union {
 1222: 	    u_char buf[sizeof(struct ngpppoe_init_data) + MAX_SESSION];
 1223: 	    struct ngpppoe_init_data	poeid;
 1224: 	} u;
 1225: 	struct ngpppoe_init_data *const idata = &u.poeid;
 1226: 	char path[NG_PATHSIZ];
 1227: 	struct ngm_connect	cn;
 1228: 
 1229: 	if (pi->list || !pi->PIf)
 1230: 	    return(1);	/* Do this only once */
 1231: 
 1232: 	SLIST_FOREACH(pl, &pi->PIf->list, next) {
 1233: 	    if (strcmp(pl->session, pi->session) == 0)
 1234: 		break;
 1235: 	}
 1236: 	if (pl) {
 1237: 	    pl->refs++;
 1238: 	    pi->list = pl;
 1239: 	    return (1);
 1240: 	}
 1241: 	
 1242: 	pl = Malloc(MB_PHYS, sizeof(*pl));
 1243: 	strlcpy(pl->session, pi->session, sizeof(pl->session));
 1244: 	pl->refs = 1;
 1245: 	pi->list = pl;
 1246: 	SLIST_INSERT_HEAD(&pi->PIf->list, pl, next);
 1247: 
 1248: 	snprintf(path, sizeof(path), "[%x]:", PIf->node_id);
 1249: 	
 1250: 	/* Connect our socket node link hook to the ng_pppoe(4) node. */
 1251: 	memset(&cn, 0, sizeof(cn));
 1252: 	strcpy(cn.path, path);
 1253: 	snprintf(cn.ourhook, sizeof(cn.peerhook), "listen-%s", pi->session);
 1254: 	strcpy(cn.peerhook, cn.ourhook);
 1255: 
 1256: 	if (NgSendMsg(PIf->csock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
 1257: 	    sizeof(cn)) < 0) {
 1258: 		Log(LG_ERR, ("PPPoE: Can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\": %s",
 1259: 		    ".:", cn.ourhook, cn.path, cn.peerhook,
 1260: 		    strerror(errno)));
 1261: 		return(0);
 1262: 	}
 1263: 
 1264: 	/* Tell the PPPoE node to be a server. */
 1265: 	memset(idata, 0, sizeof(*idata));
 1266: 	snprintf(idata->hook, sizeof(idata->hook), "listen-%s", pi->session);
 1267: 	idata->data_len = strlen(pi->session);
 1268: 	strncpy(idata->data, pi->session, MAX_SESSION);
 1269: 
 1270: 	if (NgSendMsg(PIf->csock, path, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN,
 1271: 	    idata, sizeof(*idata) + idata->data_len) < 0) {
 1272: 		Perror("PPPoE: Can't send NGM_PPPOE_LISTEN to %s hook %s",
 1273: 		     path, idata->hook);
 1274: 		return (0);
 1275: 	}
 1276: 
 1277: 	Log(LG_PHYS, ("PPPoE: waiting for connection on %s, service \"%s\"",
 1278: 		PIf->ifnodepath, idata->data));
 1279: 	    
 1280: 	return (1);
 1281: }
 1282: 
 1283: static int 
 1284: PppoeUnListen(Link l)
 1285: {
 1286: 	PppoeInfo pi = (PppoeInfo)l->info;
 1287: 	struct PppoeIf *PIf = pi->PIf;
 1288: 	char path[NG_PATHSIZ];
 1289: 	char session_hook[NG_HOOKSIZ];
 1290: 
 1291: 	if (!pi->list)
 1292: 	    return(1);	/* Do this only once */
 1293: 
 1294: 	pi->list->refs--;
 1295: 	
 1296: 	if (pi->list->refs == 0) {
 1297: 	
 1298: 	    snprintf(path, sizeof(path), "[%x]:", pi->PIf->node_id);
 1299: 	    snprintf(session_hook, sizeof(session_hook), "listen-%s", pi->list->session);
 1300: 	    NgFuncDisconnect(pi->PIf->csock, l->name, path, session_hook);
 1301: 
 1302: 	    Log(LG_PHYS, ("PPPoE: stop waiting for connection on %s, service \"%s\"",
 1303: 		PIf->ifnodepath, pi->list->session));
 1304: 		
 1305: 	    SLIST_REMOVE(&PIf->list, pi->list, PppoeList, next);
 1306: 	    Freee(pi->list);
 1307: 	}
 1308: 	    
 1309: 	pi->list = NULL;
 1310: 	return (1);
 1311: }
 1312: 
 1313: /*
 1314:  * PppoeNodeUpdate()
 1315:  */
 1316: 
 1317: static void
 1318: PppoeNodeUpdate(Link l)
 1319: {
 1320:     PppoeInfo pi = (PppoeInfo)l->info;
 1321:     if (!pi->list) {
 1322: 	if (Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
 1323: 	    PppoeGetNode(l);
 1324: 	    PppoeListen(l);
 1325: 	}
 1326:     } else {
 1327: 	if (!Enabled(&l->conf.options, LINK_CONF_INCOMING)) {
 1328: 	    PppoeUnListen(l);
 1329: 	    if (l->state == PHYS_STATE_DOWN)
 1330: 		PppoeReleaseNode(l);
 1331: 	}
 1332:     }
 1333: }
 1334: 
 1335: /*
 1336:  * PppoeSetCommand()
 1337:  */
 1338:  
 1339: static int
 1340: PppoeSetCommand(Context ctx, int ac, char *av[], void *arg)
 1341: {
 1342: 	const PppoeInfo pi = (PppoeInfo) ctx->lnk->info;
 1343: 	const char *hookname = ETHER_DEFAULT_HOOK;
 1344: 	const char *colon;
 1345: 
 1346: 	switch ((intptr_t)arg) {
 1347: 	case SET_IFACE:
 1348: 		switch (ac) {
 1349: 		case 2:
 1350: 			hookname = av[1];
 1351: 			/* fall through */
 1352: 		case 1:
 1353: 			colon = (av[0][strlen(av[0]) - 1] == ':') ? "" : ":";
 1354: 			snprintf(pi->path, sizeof(pi->path),
 1355: 			    "%s%s", av[0], colon);
 1356: 			strlcpy(pi->hook, hookname, sizeof(pi->hook));
 1357: 			break;
 1358: 		default:
 1359: 			return(-1);
 1360: 		}
 1361: 		if (pi->list) {
 1362: 		    PppoeUnListen(ctx->lnk);
 1363: 		    PppoeReleaseNode(ctx->lnk);
 1364: 		    PppoeGetNode(ctx->lnk);
 1365: 		    PppoeListen(ctx->lnk);
 1366: 		}
 1367: 		break;
 1368: 	case SET_SESSION:
 1369: 		if (ac != 1)
 1370: 			return(-1);
 1371: 		strlcpy(pi->session, av[0], sizeof(pi->session));
 1372: 		if (pi->list) {
 1373: 		    PppoeUnListen(ctx->lnk);
 1374: 		    PppoeListen(ctx->lnk);
 1375: 		}
 1376: 		break;
 1377: 	case SET_ACNAME:
 1378: 		if (ac != 1)
 1379: 			return(-1);
 1380: 		strlcpy(pi->acname, av[0], sizeof(pi->acname));
 1381: 		break;
 1382: 	default:
 1383: 		assert(0);
 1384: 	}
 1385: 	return(0);
 1386: }

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