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

    1: 
    2: /*
    3:  * iface.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:  * TCP MSSFIX code copyright (c) 2000 Ruslan Ermilov
   10:  * TCP MSSFIX contributed by Sergey Korolew <dsATbittu.org.ru>
   11:  *
   12:  */
   13: 
   14: #include "ppp.h"
   15: #include "iface.h"
   16: #include "ipcp.h"
   17: #include "auth.h"
   18: #include "ngfunc.h"
   19: #include "netgraph.h"
   20: #include "util.h"
   21: 
   22: #include <sys/types.h>
   23: #include <sys/sockio.h>
   24: #include <sys/sysctl.h>
   25: #include <sys/param.h>
   26: #include <net/if.h>
   27: #include <net/if_types.h>
   28: #include <net/if_dl.h>
   29: #include <net/if_var.h>
   30: #include <net/route.h>
   31: #include <netinet/in_systm.h>
   32: #include <netinet/in.h>
   33: #include <netinet/in_var.h>
   34: #include <netinet/if_ether.h>
   35: #include <netinet6/nd6.h>
   36: #include <netgraph/ng_message.h>
   37: #include <netgraph/ng_iface.h>
   38: #ifdef USE_NG_BPF
   39: #include <netgraph/ng_bpf.h>
   40: #endif
   41: #include <netgraph/ng_tee.h>
   42: #include <netgraph/ng_ksocket.h>
   43: #include <netinet/ip_icmp.h>
   44: #include <netinet/tcp.h>
   45: #include <netinet/udp.h>
   46: #ifdef USE_NG_TCPMSS
   47: #include <netgraph/ng_tcpmss.h>
   48: #endif
   49: #ifdef USE_NG_IPACCT
   50: #include <netgraph/ng_ipacct.h>
   51: #undef r_ip_p	/* XXX:DIRTY CONFLICT! */
   52: #endif
   53: #ifdef USE_NG_NETFLOW
   54: #include <netgraph/netflow/ng_netflow.h>
   55: #endif
   56: #ifdef USE_NG_CAR
   57: #include <netgraph/ng_car.h>
   58: #endif
   59: 
   60: #ifdef USE_NG_BPF
   61: #include <pcap.h>
   62: #endif
   63: 
   64: #include <string.h>
   65: 
   66: /*
   67:  * DEFINITIONS
   68:  */
   69: 
   70: /* Set menu options */
   71: 
   72:   enum {
   73:     SET_IDLE,
   74:     SET_SESSION,
   75:     SET_ADDRS,
   76:     SET_ROUTE,
   77:     SET_MTU,
   78:     SET_NAME,
   79: #ifdef SIOCSIFDESCR
   80:     SET_DESCR,
   81: #endif
   82: #ifdef SIOCAIFGROUP
   83:     SET_GROUP,
   84: #endif
   85:     SET_UP_SCRIPT,
   86:     SET_DOWN_SCRIPT,
   87:     SET_ENABLE,
   88:     SET_DISABLE
   89:   };
   90: 
   91: /*
   92:  * INTERNAL FUNCTIONS
   93:  */
   94: 
   95:   static int	IfaceNgIpInit(Bund b, int ready);
   96:   static void	IfaceNgIpShutdown(Bund b);
   97:   static int	IfaceNgIpv6Init(Bund b, int ready);
   98:   static void	IfaceNgIpv6Shutdown(Bund b);
   99: 
  100: #ifdef USE_NG_NETFLOW
  101:   static int	IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out, int v6);
  102:   static int	IfaceSetupNetflow(Bund b, char in, char out, int v6);
  103:   static void	IfaceShutdownNetflow(Bund b, char in, char out, int v6);
  104: #endif
  105: 
  106: #ifdef USE_NG_IPACCT
  107:   static int	IfaceInitIpacct(Bund b, char *path, char *hook);
  108:   static void	IfaceShutdownIpacct(Bund b);
  109: #endif
  110: 
  111: #ifdef USE_NG_NAT
  112:   static int	IfaceInitNAT(Bund b, char *path, char *hook);
  113:   static int	IfaceSetupNAT(Bund b);
  114:   static void	IfaceShutdownNAT(Bund b);
  115: #endif
  116: 
  117:   static int	IfaceInitTee(Bund b, char *path, char *hook, int v6);
  118:   static void	IfaceShutdownTee(Bund b, int v6);
  119: 
  120: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
  121:   static int    IfaceInitMSS(Bund b, char *path, char *hook);
  122:   static void	IfaceSetupMSS(Bund b, uint16_t maxMSS);
  123:   static void	IfaceShutdownMSS(Bund b);
  124: #endif
  125: 
  126: #ifdef USE_NG_BPF
  127:   static int    IfaceInitLimits(Bund b, char *path, char *hook);
  128:   static void	IfaceSetupLimits(Bund b);
  129:   static void	IfaceShutdownLimits(Bund b);
  130: #endif
  131: 
  132:   static int	IfaceSetCommand(Context ctx, int ac, char *av[], void *arg);
  133:   static void	IfaceSessionTimeout(void *arg);
  134:   static void	IfaceIdleTimeout(void *arg);
  135: 
  136:   static void	IfaceCacheSend(Bund b);
  137:   static void	IfaceCachePkt(Bund b, int proto, Mbuf pkt);
  138:   static int	IfaceIsDemand(int proto, Mbuf pkt);
  139: 
  140: #ifdef USE_IPFW
  141:   static int	IfaceAllocACL (struct acl_pool ***ap, int start, char * ifname, int number);
  142:   static int	IfaceFindACL (struct acl_pool *ap, char * ifname, int number);
  143:   static char *	IfaceParseACL (char * src, IfaceState iface);
  144: #endif
  145: 
  146:   static int	IfaceSetName(Bund b, const char * ifname);
  147: #ifdef SIOCSIFDESCR
  148:   static int	IfaceSetDescr(Bund b, const char * ifdescr);
  149:   static void	IfaceFreeDescr(IfaceState iface);
  150: #endif
  151: #ifdef SIOCAIFGROUP
  152:   static int	IfaceAddGroup(Bund b, const char * ifgroup);
  153:   static int	IfaceDelGroup(Bund b, const char * ifgroup);
  154: #endif
  155: /*
  156:  * GLOBAL VARIABLES
  157:  */
  158: 
  159:   const struct cmdtab IfaceSetCmds[] = {
  160:     { "addrs {self} {peer}",		"Set interface addresses",
  161: 	IfaceSetCommand, NULL, 2, (void *) SET_ADDRS },
  162:     { "route {dest}[/{width}]",		"Add IP route",
  163: 	IfaceSetCommand, NULL, 2, (void *) SET_ROUTE },
  164:     { "mtu {size}",			"Set max allowed interface MTU",
  165: 	IfaceSetCommand, NULL, 2, (void *) SET_MTU },
  166:     { "name [{name}]",			"Set interface name",
  167: 	IfaceSetCommand, NULL, 2, (void *) SET_NAME },
  168: #ifdef SIOCSIFDESCR
  169:     { "description [{descr}]",		"Set interface description",
  170: 	IfaceSetCommand, NULL, 2, (void *) SET_DESCR },
  171: #endif
  172: #ifdef SIOCAIFGROUP
  173:     { "group [{group}]",		"Set interface group",
  174: 	IfaceSetCommand, NULL, 2, (void *) SET_GROUP },
  175: #endif
  176:     { "up-script [{progname}]",		"Interface up script",
  177: 	IfaceSetCommand, NULL, 2, (void *) SET_UP_SCRIPT },
  178:     { "down-script [{progname}]",	"Interface down script",
  179: 	IfaceSetCommand, NULL, 2, (void *) SET_DOWN_SCRIPT },
  180: #ifdef USE_NG_BPF
  181:     { "idle {seconds}",			"Idle timeout",
  182: 	IfaceSetCommand, NULL, 2, (void *) SET_IDLE },
  183: #endif
  184:     { "session {seconds}",		"Session timeout",
  185: 	IfaceSetCommand, NULL, 2, (void *) SET_SESSION },
  186:     { "enable [opt ...]",		"Enable option",
  187: 	IfaceSetCommand, NULL, 2, (void *) SET_ENABLE },
  188:     { "disable [opt ...]",		"Disable option",
  189: 	IfaceSetCommand, NULL, 2, (void *) SET_DISABLE },
  190:     { NULL },
  191:   };
  192: 
  193: /*
  194:  * INTERNAL VARIABLES
  195:  */
  196: 
  197:   static const struct confinfo	gConfList[] = {
  198:     { 0,	IFACE_CONF_ONDEMAND,		"on-demand"	},
  199:     { 0,	IFACE_CONF_PROXY,		"proxy-arp"	},
  200:     { 0,	IFACE_CONF_KEEP_TIMEOUT,	"keep-timeout"	},
  201: #ifdef USE_NG_TCPMSS
  202:     { 0,	IFACE_CONF_TCPMSSFIX,           "tcpmssfix"	},
  203: #endif
  204:     { 0,	IFACE_CONF_TEE,			"tee"		},
  205: #ifdef USE_NG_NAT
  206:     { 0,	IFACE_CONF_NAT,			"nat"		},
  207: #endif
  208: #ifdef USE_NG_NETFLOW
  209:     { 0,	IFACE_CONF_NETFLOW_IN,		"netflow-in"	},
  210:     { 0,	IFACE_CONF_NETFLOW_OUT,		"netflow-out"	},
  211: #ifdef NG_NETFLOW_CONF_ONCE
  212:     { 0,	IFACE_CONF_NETFLOW_ONCE,	"netflow-once"	},
  213: #endif
  214: #endif
  215: #ifdef USE_NG_IPACCT
  216:     { 0,	IFACE_CONF_IPACCT,		"ipacct"	},
  217: #endif
  218:     { 0,	0,				NULL		},
  219:   };
  220: 
  221: #ifdef USE_IPFW
  222:   struct acl_pool * rule_pool = NULL; /* Pointer to the first element in the list of rules */
  223:   struct acl_pool * pipe_pool = NULL; /* Pointer to the first element in the list of pipes */
  224:   struct acl_pool * queue_pool = NULL; /* Pointer to the first element in the list of queues */
  225:   struct acl_pool * table_pool = NULL; /* Pointer to the first element in the list of tables */
  226:   int rule_pool_start = 10000; /* Initial number of ipfw rules pool */
  227:   int pipe_pool_start = 10000; /* Initial number of ipfw dummynet pipe pool */
  228:   int queue_pool_start = 10000; /* Initial number of ipfw dummynet queue pool */
  229:   int table_pool_start = 32; /* Initial number of ipfw tables pool */
  230: #endif
  231: 
  232: #ifdef USE_NG_BPF
  233:   /* A BPF filter that matches TCP SYN packets */
  234:   static const struct bpf_insn gTCPSYNProg[] __attribute__((used)) = {
  235: /*00*/	BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 9),		/* A <- IP protocol */
  236: /*01*/	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 6), /* !TCP => 8 */
  237: /*02*/	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 6),	/* A <- fragmentation offset */
  238: /*03*/	BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 4, 0),	/* fragment => 8 */
  239: /*04*/	BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 0),		/* X <- header len */
  240: /*05*/	BPF_STMT(BPF_LD+BPF_B+BPF_IND, 13),		/* A <- TCP flags */
  241: /*06*/	BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, TH_SYN, 0, 1),	/* !TH_SYN => 8 */
  242: /*07*/	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),		/* accept packet */
  243: /*08*/	BPF_STMT(BPF_RET+BPF_K, 0),			/* reject packet */
  244:   };
  245: 
  246:   #define TCPSYN_PROG_LEN	(sizeof(gTCPSYNProg) / sizeof(*gTCPSYNProg))
  247: 
  248:   /* A BPF filter that matches nothing */
  249:   static const struct bpf_insn gNoMatchProg[] = {
  250: 	BPF_STMT(BPF_RET+BPF_K, 0)
  251:   };
  252: 
  253:   #define NOMATCH_PROG_LEN	(sizeof(gNoMatchProg) / sizeof(*gNoMatchProg))
  254: 
  255:   /* A BPF filter that matches everything */
  256:   static const struct bpf_insn gMatchProg[] = {
  257: 	BPF_STMT(BPF_RET+BPF_K, (u_int)-1)
  258:   };
  259: 
  260:   #define MATCH_PROG_LEN	(sizeof(gMatchProg) / sizeof(*gMatchProg))
  261: #endif /* USE_NG_BPF */
  262: 
  263: #define IN6MASK128	{{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
  264: 			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
  265: static const struct in6_addr in6mask128 = IN6MASK128;
  266: 
  267: #ifdef SIOCSIFDESCR
  268: void
  269: IfaceFreeDescr(IfaceState iface)
  270: {
  271:   if (iface->ifdescr != NULL)
  272: 	Freee(iface->ifdescr);
  273:   if (iface->conf.ifdescr != NULL)
  274: 	Freee(iface->conf.ifdescr);
  275:   iface->ifdescr = iface->conf.ifdescr = NULL;
  276: }
  277: #endif
  278: 
  279: /*
  280:  * IfaceInit()
  281:  */
  282: 
  283: void
  284: IfaceInit(Bund b)
  285: {
  286:   IfaceState	const iface = &b->iface;
  287: 
  288:   /* Default configuration */
  289:   iface->mtu = NG_IFACE_MTU_DEFAULT;
  290:   iface->max_mtu = NG_IFACE_MTU_DEFAULT;
  291: #ifdef SIOCSIFDESCR
  292:   iface->ifdescr = NULL;
  293:   iface->conf.ifdescr = NULL;
  294: #endif
  295:   Disable(&iface->options, IFACE_CONF_ONDEMAND);
  296:   Disable(&iface->options, IFACE_CONF_PROXY);
  297:   Disable(&iface->options, IFACE_CONF_KEEP_TIMEOUT);
  298:   Disable(&iface->options, IFACE_CONF_TCPMSSFIX);
  299: #ifdef	USE_NG_NAT
  300:   NatInit(b);
  301: #endif
  302: #ifdef USE_NG_BPF
  303:   SLIST_INIT(&iface->ss[0]);
  304:   SLIST_INIT(&iface->ss[1]);
  305: #endif
  306: }
  307: 
  308: /*
  309:  * IfaceInst()
  310:  */
  311: 
  312: void
  313: IfaceInst(Bund b, Bund bt)
  314: {
  315:     IfaceState	const iface = &b->iface;
  316: 
  317:     memcpy(iface, &bt->iface, sizeof(*iface));
  318: 
  319: #ifdef SIOCSIFDESCR
  320:     /* Copy interface description from template config to current */
  321:     if (bt->iface.conf.ifdescr)
  322: 	iface->conf.ifdescr = Mstrdup(MB_IFACE, bt->iface.conf.ifdescr);
  323:     if (bt->iface.ifdescr)
  324: 	iface->ifdescr = Mstrdup(MB_IFACE, bt->iface.ifdescr);
  325: #endif
  326:     /* Copy interface name from template config to current */
  327:     if (bt->iface.conf.ifname[0] != 0 && b->tmpl == 0) {
  328:         snprintf(iface->conf.ifname, sizeof(iface->conf.ifname), "%s%d",
  329:              bt->iface.conf.ifname, b->id);
  330:         Log(LG_IFACE2, ("[%s] IFACE: Set conf.ifname to ", iface->conf.ifname));
  331:     }
  332: }
  333: 
  334: /*
  335:  * IfaceDestroy()
  336:  */
  337: 
  338: void
  339: IfaceDestroy(Bund b)
  340: {
  341: #ifdef SIOCSIFDESCR
  342:     IfaceState	const iface = &b->iface;
  343: 
  344:     IfaceFreeDescr(iface);
  345: #endif
  346: }
  347: 
  348: /*
  349:  * IfaceOpen()
  350:  *
  351:  * Open the interface layer
  352:  */
  353: 
  354: void
  355: IfaceOpen(Bund b)
  356: {
  357:     IfaceState	const iface = &b->iface;
  358: 
  359:     Log(LG_IFACE, ("[%s] IFACE: Open event", b->name));
  360: 
  361:     /* Open is useless without on-demand. */
  362:     if (!Enabled(&iface->options, IFACE_CONF_ONDEMAND)) {
  363: 	Log(LG_ERR, ("[%s] 'open iface' is useless without on-demand enabled", b->name));
  364: 	return;
  365:     }
  366: 
  367:     /* If interface is already open do nothing */
  368:     if (iface->open)
  369: 	return;
  370:     iface->open = TRUE;
  371: 
  372:     /* If on-demand, bring up system interface immediately and start
  373:      listening for outgoing packets. The next outgoing packet will
  374:      cause us to open the lower layer(s) */
  375:     BundNcpsJoin(b, NCP_NONE);
  376: }
  377: 
  378: /*
  379:  * IfaceClose()
  380:  *
  381:  * Close the interface layer
  382:  */
  383: 
  384: void
  385: IfaceClose(Bund b)
  386: {
  387:     IfaceState	const iface = &b->iface;
  388: 
  389:     Log(LG_IFACE, ("[%s] IFACE: Close event", b->name));
  390: 
  391:     /* If interface is already closed do nothing */
  392:     if (!iface->open)
  393: 	return;
  394:     iface->open = FALSE;
  395: 
  396:     /* If there was on-demand, tell that it is not needed anymore */
  397:     BundNcpsLeave(b, NCP_NONE);
  398: }
  399: 
  400: /*
  401:  * IfaceOpenCmd()
  402:  *
  403:  * Open the interface layer
  404:  */
  405: 
  406: int
  407: IfaceOpenCmd(Context ctx)
  408: {
  409:     if (ctx->bund->tmpl)
  410: 	Error("impossible to open template");
  411:     IfaceOpen(ctx->bund);
  412:     return (0);
  413: }
  414: 
  415: /*
  416:  * IfaceCloseCmd()
  417:  *
  418:  * Close the interface layer
  419:  */
  420: 
  421: int
  422: IfaceCloseCmd(Context ctx)
  423: {
  424:     if (ctx->bund->tmpl)
  425: 	Error("impossible to close template");
  426:     IfaceClose(ctx->bund);
  427:     return (0);
  428: }
  429: 
  430: /*
  431:  * IfaceUp()
  432:  *
  433:  * Our underlying PPP bundle is ready for traffic.
  434:  * We may signal that the interface is in DoD with the IFF_LINK0 flag.
  435:  */
  436: 
  437: void
  438: IfaceUp(Bund b, int ready)
  439: {
  440:   IfaceState	const iface = &b->iface;
  441:   int		session_timeout = 0, idle_timeout = 0;
  442: #ifdef USE_IPFW
  443:   struct acl	*acls, *acl;
  444:   char			*buf;
  445:   struct acl_pool 	**poollast;
  446:   int 			poollaststart;
  447:   int		prev_number;
  448:   int		prev_real_number;
  449: #endif
  450: 
  451:   Log(LG_IFACE, ("[%s] IFACE: Up event", b->name));
  452:   iface->last_up = time(NULL);
  453: 
  454:   if (ready) {
  455: 
  456:     /* Start Session timer */
  457:     if (b->params.session_timeout > 0) {
  458: 	if (Enabled(&iface->options, IFACE_CONF_KEEP_TIMEOUT)) {
  459: 	    session_timeout = b->params.session_timeout - \
  460: 		(iface->last_up - b->last_up);
  461: 	    Log(LG_IFACE2, ("[%s] IFACE: keep session-timeout at: %d seconds",
  462: 		b->name, session_timeout));
  463: 	} else {
  464: 	    session_timeout = b->params.session_timeout;
  465: 	}
  466:     } else if (iface->session_timeout > 0) {
  467: 	session_timeout = iface->session_timeout;
  468:     }
  469: 
  470:     if (session_timeout > 0) {
  471: 	Log(LG_IFACE2, ("[%s] IFACE: session-timeout: %d seconds", 
  472:     	    b->name, session_timeout));
  473: 	if (session_timeout > INT_MAX / 1100) {
  474: 	    session_timeout = INT_MAX / 1100;
  475: 	    Log(LG_ERR, ("[%s] IFACE: session-timeout limited to %d seconds", 
  476: 		b->name, session_timeout));
  477: 	}
  478: 	TimerInit(&iface->sessionTimer, "IfaceSession",
  479:     	    session_timeout * SECONDS, IfaceSessionTimeout, b);
  480: 	TimerStart(&iface->sessionTimer);
  481:     }
  482: 
  483:     /* Start idle timer */
  484:     if (b->params.idle_timeout > 0) {
  485: 	idle_timeout = b->params.idle_timeout;
  486:     } else if (iface->idle_timeout > 0) {
  487: 	idle_timeout = iface->idle_timeout;
  488:     }
  489:     
  490:     if (idle_timeout > 0) {
  491: 	Log(LG_IFACE2, ("[%s] IFACE: idle-timeout: %d seconds", 
  492:     	    b->name, idle_timeout));
  493: 	if (idle_timeout > INT_MAX / 1100 * IFACE_IDLE_SPLIT) {
  494: 	    idle_timeout = INT_MAX / 1100 * IFACE_IDLE_SPLIT;
  495: 	    Log(LG_ERR, ("[%s] IFACE: idle-timeout limited to %d seconds", 
  496:     		b->name, idle_timeout));
  497: 	}
  498: 	TimerInit(&iface->idleTimer, "IfaceIdle",
  499:     	    idle_timeout * SECONDS / IFACE_IDLE_SPLIT, IfaceIdleTimeout, b);
  500: 	TimerStart(&iface->idleTimer);
  501: 	iface->traffic[1] = TRUE;
  502: 	iface->traffic[0] = FALSE;
  503: 
  504: 	/* Reset statistics */
  505: 	memset(&iface->idleStats, 0, sizeof(iface->idleStats));
  506:     }
  507: 
  508:     /* Update interface name and description */
  509:     if (b->params.ifname[0] != 0) {
  510:        if (IfaceSetName(b, b->params.ifname) != -1)
  511: 	    Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
  512: 		b->name, iface->ngname, b->params.ifname));
  513:     } else if (iface->conf.ifname[0] != 0) {
  514:        if (IfaceSetName(b, iface->conf.ifname) != -1)
  515: 	    Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
  516: 		b->name, iface->ngname, iface->conf.ifname));
  517:     }
  518: #ifdef SIOCSIFDESCR
  519:     if (b->params.ifdescr != NULL) {
  520:        if (IfaceSetDescr(b, b->params.ifdescr) != -1) {
  521: 	    Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add description \"%s\"",
  522: 		b->name, iface->ifdescr));
  523: 	}
  524:     } else if (iface->conf.ifdescr != NULL) {
  525:        if (IfaceSetDescr(b, iface->conf.ifdescr) != -1) {
  526: 	    Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add description \"%s\"",
  527: 		b->name, iface->ifdescr));
  528: 	}
  529:     }
  530: #endif
  531: #ifdef SIOCAIFGROUP
  532:     if (iface->conf.ifgroup[0] != 0) {
  533:        if (IfaceAddGroup(b, iface->conf.ifgroup) != -1)
  534: 	    Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add group %s to %s",
  535: 		b->name, iface->conf.ifgroup, iface->ngname));
  536:     }
  537:     if (b->params.ifgroup[0] != 0) {
  538:        if (IfaceAddGroup(b, b->params.ifgroup) != -1)
  539: 	    Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add group %s to %s",
  540: 		b->name, b->params.ifgroup, iface->ngname));
  541:     }
  542: #endif
  543: #ifdef USE_IPFW
  544:   /* Allocate ACLs */
  545:   acls = b->params.acl_pipe;
  546:   poollast = &pipe_pool;
  547:   poollaststart = pipe_pool_start;
  548:   while (acls != NULL) {
  549:     acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
  550:     poollaststart = acls->real_number;
  551:     acls = acls->next;
  552:   };
  553:   acls = b->params.acl_queue;
  554:   poollast = &queue_pool;
  555:   poollaststart = queue_pool_start;
  556:   while (acls != NULL) {
  557:     acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
  558:     poollaststart = acls->real_number;
  559:     acls = acls->next;
  560:   };
  561:   prev_number = -1;
  562:   prev_real_number = -1;
  563:   acls = b->params.acl_table;
  564:   poollast = &table_pool;
  565:   poollaststart = table_pool_start;
  566:   while (acls != NULL) {
  567:     if (acls->real_number == 0) {
  568: 	if (acls->number == prev_number) { /* ACL list is presorted so we need not allocate if equal */
  569: 	    acls->real_number = prev_real_number;
  570: 	} else {
  571: 	    acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
  572: 	    poollaststart = acls->real_number;
  573: 	    prev_number = acls->number;
  574: 	    prev_real_number = acls->real_number;
  575: 	}
  576:     }
  577:     acls = acls->next;
  578:   };
  579:   acls = b->params.acl_rule;
  580:   poollast = &rule_pool;
  581:   poollaststart = rule_pool_start;
  582:   while (acls != NULL) {
  583:     acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
  584:     poollaststart = acls->real_number;
  585:     acls = acls->next;
  586:   };
  587: 
  588:   /* Set ACLs */
  589:   acls = b->params.acl_pipe;
  590:   while (acls != NULL) {
  591:     ExecCmd(LG_IFACE2, b->name, "%s pipe %d config %s", PATH_IPFW, acls->real_number, acls->rule);
  592:     acls = acls->next;
  593:   }
  594:   acls = b->params.acl_queue;
  595:   while (acls != NULL) {
  596:     buf = IfaceParseACL(acls->rule, iface);
  597:     ExecCmd(LG_IFACE2, b->name, "%s queue %d config %s", PATH_IPFW, acls->real_number, buf);
  598:     Freee(buf);
  599:     acls = acls->next;
  600:   }
  601:   acls = b->params.acl_table;
  602:   while (acls != NULL) {
  603:     /* allow both %aX and `peer_addr` macros */
  604:     buf = IfaceParseACL(acls->rule, iface);
  605:     strcpy(acls->rule, buf);
  606:     Freee(buf);
  607:     acl = Mdup(MB_IPFW, acls, sizeof(struct acl) + strlen(acls->rule));
  608:     acl->next = iface->tables;
  609:     iface->tables = acl;
  610:     if (strncmp(acls->rule, "peer_addr", 9) == 0) {
  611: 	char hisaddr[20];
  612: 	ExecCmd(LG_IFACE2, b->name, "%s table %d add %s",
  613: 	    PATH_IPFW, acls->real_number,
  614: 	    u_addrtoa(&iface->peer_addr, hisaddr, sizeof(hisaddr)));
  615:     } else {
  616: 	ExecCmd(LG_IFACE2, b->name, "%s table %d add %s", PATH_IPFW, acls->real_number, acls->rule);
  617:     }
  618:     acls = acls->next;
  619:   };
  620:   acls = b->params.acl_rule;
  621:   while (acls != NULL) {
  622:     buf = IfaceParseACL(acls->rule, iface);
  623:     ExecCmd(LG_IFACE2, b->name, "%s add %d %s via %s", PATH_IPFW, acls->real_number, buf, iface->ifname);
  624:     Freee(buf);
  625:     acls = acls->next;
  626:   };
  627: #endif /* USE_IPFW */
  628: 
  629:   };
  630: 
  631:   /* Bring up system interface */
  632:   IfaceChangeFlags(b, 0, IFF_UP | (ready?0:IFF_LINK0));
  633: 
  634:   /* Send any cached packets */
  635:   IfaceCacheSend(b);
  636: 
  637: }
  638: 
  639: /*
  640:  * IfaceDown()
  641:  *
  642:  * Our packet transport mechanism is no longer ready for traffic.
  643:  */
  644: 
  645: void
  646: IfaceDown(Bund b)
  647: {
  648:   IfaceState	const iface = &b->iface;
  649: #ifdef USE_IPFW
  650:   struct acl_pool	**rp, *rp1;
  651:   char		cb[32768];
  652:   struct acl    *acl, *aclnext;
  653: #endif
  654: 
  655:   Log(LG_IFACE, ("[%s] IFACE: Down event", b->name));
  656: 
  657:   /* Bring down system interface */
  658:   IfaceChangeFlags(b, IFF_UP | IFF_LINK0, 0);
  659: 
  660:   TimerStop(&iface->idleTimer);
  661:   TimerStop(&iface->sessionTimer);
  662: 
  663: #ifdef USE_IPFW
  664:   /* Remove rule ACLs */
  665:   rp = &rule_pool;
  666:   cb[0]=0;
  667:   while (*rp != NULL) {
  668:     if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
  669:       sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
  670:       rp1 = *rp;
  671:       *rp = (*rp)->next;
  672:       Freee(rp1);
  673:     } else {
  674:       rp = &((*rp)->next);
  675:     };
  676:   };
  677:   if (cb[0]!=0)
  678:     ExecCmdNosh(LG_IFACE2, b->name, "%s delete%s",
  679:       PATH_IPFW, cb);
  680: 
  681:   /* Remove table ACLs */
  682:   rp = &table_pool;
  683:   while (*rp != NULL) {
  684:     if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
  685:       rp1 = *rp;
  686:       *rp = (*rp)->next;
  687:       Freee(rp1);
  688:     } else {
  689:       rp = &((*rp)->next);
  690:     };
  691:   };
  692:   acl = iface->tables;
  693:   while (acl != NULL) {
  694:     if (strncmp(acl->rule, "peer_addr", 9) == 0) {
  695:       char hisaddr[20];
  696:       ExecCmd(LG_IFACE2, b->name, "%s table %d delete %s",
  697:         PATH_IPFW, acl->real_number,
  698:         u_addrtoa(&iface->peer_addr, hisaddr, sizeof(hisaddr)));
  699:     } else {
  700:       ExecCmd(LG_IFACE2, b->name, "%s table %d delete %s",
  701:         PATH_IPFW, acl->real_number, acl->rule);
  702:     }
  703:     aclnext = acl->next;
  704:     Freee(acl);
  705:     acl = aclnext;
  706:   };
  707:   iface->tables = NULL;
  708: 
  709:   /* Remove queue ACLs */
  710:   rp = &queue_pool;
  711:   cb[0]=0;
  712:   while (*rp != NULL) {
  713:     if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
  714:       sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
  715:       rp1 = *rp;
  716:       *rp = (*rp)->next;
  717:       Freee(rp1);
  718:     } else {
  719:       rp = &((*rp)->next);
  720:     };
  721:   };
  722:   if (cb[0]!=0)
  723:     ExecCmdNosh(LG_IFACE2, b->name, "%s queue delete%s",
  724:       PATH_IPFW, cb);
  725: 
  726:   /* Remove pipe ACLs */
  727:   rp = &pipe_pool;
  728:   cb[0]=0;
  729:   while (*rp != NULL) {
  730:     if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
  731:       sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
  732:       rp1 = *rp;
  733:       *rp = (*rp)->next;
  734:       Freee(rp1);
  735:     } else {
  736:       rp = &((*rp)->next);
  737:     };
  738:   };
  739:   if (cb[0]!=0)
  740:     ExecCmdNosh(LG_IFACE2, b->name, "%s pipe delete%s",
  741:       PATH_IPFW, cb);
  742: #endif /* USE_IPFW */
  743: 
  744:     /* Clearing self and peer addresses */
  745:     u_rangeclear(&iface->self_addr);
  746:     u_addrclear(&iface->peer_addr);
  747:     u_addrclear(&iface->self_ipv6_addr);
  748:     u_addrclear(&iface->peer_ipv6_addr);
  749: 
  750:     /* Revert interface name and description */
  751: 
  752:     if (strcmp(iface->ngname, iface->ifname) != 0) {
  753: 	if (iface->conf.ifname[0] != 0) {
  754: 	    /* Restore to config defined */
  755: 	    if (IfaceSetName(b, iface->conf.ifname) != -1)
  756: 		Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
  757: 		    b->name, iface->ifname, iface->conf.ifname));
  758: 	} else {
  759: 	    /* Restore to original interface name */
  760: 	    if (IfaceSetName(b, iface->ngname) != -1)
  761: 		Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
  762: 		    b->name, iface->ifname, iface->ngname));
  763: 	}
  764:     }
  765: #ifdef SIOCSIFDESCR
  766:     if ((iface->ifdescr != NULL)
  767:     && (IfaceSetDescr(b, iface->conf.ifdescr) != -1)) {
  768: 	if (iface->conf.ifdescr != NULL) {
  769: 		Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Set description \"%s\"",
  770: 		    b->name, iface->ifdescr));
  771: 	} else {
  772: 		Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Clear description",
  773: 		    b->name));
  774: 	}
  775:     }
  776: #endif
  777: #ifdef SIOCAIFGROUP
  778:     if (b->params.ifgroup[0] != 0) {
  779:        if (IfaceDelGroup(b, b->params.ifgroup) != -1)
  780: 	    Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Remove group %s from %s",
  781: 		b->name, b->params.ifgroup, iface->ngname));
  782:     }
  783: #endif
  784: }
  785: 
  786: /*
  787:  * IfaceListenInput()
  788:  *
  789:  * A packet was received on our demand snooping hook. Stimulate a connection.
  790:  */
  791: 
  792: void
  793: IfaceListenInput(Bund b, int proto, Mbuf pkt)
  794: {
  795:     IfaceState	const iface = &b->iface;
  796:     int		const isDemand = IfaceIsDemand(proto, pkt);
  797: 
  798:     /* Does this count as demand traffic? */
  799:     if (iface->open && isDemand) {
  800: 	iface->traffic[0] = TRUE;
  801:         Log(LG_IFACE, ("[%s] IFACE: Outgoing %s packet demands connection", b->name,
  802: 	    (proto==PROTO_IP)?"IP":"IPv6"));
  803: 	RecordLinkUpDownReason(b, NULL, 1, STR_DEMAND, NULL);
  804:         BundOpen(b);
  805:         IfaceCachePkt(b, proto, pkt);
  806:     } else {
  807: 	mbfree(pkt);
  808:     }
  809: }
  810: 
  811: #ifdef USE_IPFW
  812: /*
  813:  * IfaceAllocACL ()
  814:  *
  815:  * Allocates unique real number for new ACL and adds it to the list of used ones.
  816:  */
  817: 
  818: static int
  819: IfaceAllocACL(struct acl_pool ***ap, int start, char *ifname, int number)
  820: {
  821:     int	i;
  822:     struct acl_pool **rp,*rp1;
  823: 
  824:     rp1 = Malloc(MB_IPFW, sizeof(struct acl_pool));
  825:     strlcpy(rp1->ifname, ifname, sizeof(rp1->ifname));
  826:     rp1->acl_number = number;
  827: 
  828:     rp = *ap;
  829:     i = start;
  830:     while (*rp != NULL && (*rp)->real_number <= i) {
  831:         i = (*rp)->real_number+1;
  832:         rp = &((*rp)->next);
  833:     };
  834:     if (*rp == NULL) {
  835:         rp1->next = NULL;
  836:     } else {
  837:         rp1->next = *rp;
  838:     };
  839:     rp1->real_number = i;
  840:     *rp = rp1;
  841:     *ap = rp;
  842:     return(i);
  843: }
  844: 
  845: /*
  846:  * IfaceFindACL ()
  847:  *
  848:  * Finds ACL in the list and gets its real number.
  849:  */
  850: 
  851: static int
  852: IfaceFindACL (struct acl_pool *ap, char * ifname, int number)
  853: {
  854:     int	i;
  855:     struct acl_pool *rp;
  856: 
  857:     rp=ap;
  858:     i=-1;
  859:     while (rp != NULL) {
  860: 	if ((rp->acl_number == number) && (strncmp(rp->ifname,ifname,IFNAMSIZ) == 0)) {
  861:     	    i = rp->real_number;
  862: 	    break;
  863: 	};
  864:         rp = rp->next;
  865:     };
  866:     return(i);
  867: }
  868: 
  869: /*
  870:  * IfaceParseACL ()
  871:  *
  872:  * Parses ACL and replaces %r, %p and %q macroses 
  873:  * by the real numbers of rules, queues and pipes.
  874:  *
  875:  * Also replaces %a1 and a2 with the remote(peer)
  876:  * or local(self) IP address respectively.
  877:  */
  878: 
  879: static char *
  880: IfaceParseACL (char * src, IfaceState iface)
  881: {
  882:     char *buf,*buf1;
  883:     char *begin,*param,*end;
  884:     char t;
  885:     int num,real_number;
  886:     struct acl_pool *ap;
  887:     char hisaddr[20];
  888:     int ipmode = 0; /* 0 - normal macro, 1 - IP address macro */
  889:     
  890:     buf = Malloc(MB_IPFW, ACL_LEN);
  891:     buf1 = Malloc(MB_IPFW, ACL_LEN);
  892: 
  893:     strlcpy(buf, src, ACL_LEN);
  894:     do {
  895:         end = buf;
  896: 	begin = strsep(&end, "%");
  897: 	param = strsep(&end, " ");
  898: 	if (param != NULL) {
  899: 	    if (sscanf(param,"%c%d", &t, &num) == 2) {
  900: 		switch (t) {
  901: 		    case 'r':
  902: 			ap = rule_pool;
  903: 			break;
  904: 		    case 'p':
  905: 			ap = pipe_pool;
  906: 			break;
  907: 		    case 'q':
  908: 			ap = queue_pool;
  909: 			break;
  910: 		    case 't':
  911: 			ap = table_pool;
  912: 			break;
  913: 		    case 'a':
  914: 			ipmode = 1;
  915: 			if (num == 1)
  916: 			   u_addrtoa(&iface->peer_addr, hisaddr, sizeof(hisaddr));
  917: 			else if (num == 2)
  918: 			   u_rangetoa(&iface->self_addr, hisaddr, sizeof(hisaddr));
  919: 			else
  920: 			   ipmode = 0;
  921: 			ap = NULL;
  922:                         break;
  923: 		    default:
  924: 			ap = NULL;
  925: 		};
  926: 		if (ipmode)
  927: 		{
  928: 		    if (end != NULL)
  929: 			snprintf(buf1, ACL_LEN, "%s%s %s", begin, hisaddr, end);
  930: 		    else
  931: 			snprintf(buf1, ACL_LEN, "%s%s", begin, hisaddr);
  932: 		    ipmode = 0;
  933: 		}
  934: 		else
  935: 		{
  936: 		    real_number = IfaceFindACL(ap, iface->ifname, num);
  937: 		    if (end != NULL)
  938: 			snprintf(buf1, ACL_LEN, "%s%d %s", begin, real_number, end);
  939: 		    else
  940: 		 	snprintf(buf1, ACL_LEN, "%s%d", begin, real_number);
  941: 		}
  942: 		strlcpy(buf, buf1, ACL_LEN);
  943: 	    };
  944: 	};
  945:     } while (end != NULL);
  946:     Freee(buf1);
  947:     return(buf);
  948: }
  949: #endif /* USE_IPFW */
  950: 
  951: /*
  952:  * IfaceIpIfaceUp()
  953:  *
  954:  * Bring up the IP interface. The "ready" flag means that
  955:  * IPCP is also up and we can deliver packets immediately.
  956:  */
  957: 
  958: int
  959: IfaceIpIfaceUp(Bund b, int ready)
  960: {
  961:     IfaceState		const iface = &b->iface;
  962:     struct sockaddr_dl	hwa;
  963:     char		hisaddr[20];
  964:     IfaceRoute		r;
  965:     u_char		*ether;
  966: 
  967:     if (ready && !iface->conf.self_addr_force) {
  968: 	in_addrtou_range(&b->ipcp.want_addr, 32, &iface->self_addr);
  969:     } else {
  970: 	u_rangecopy(&iface->conf.self_addr, &iface->self_addr);
  971:     }
  972:     if (ready && !iface->conf.peer_addr_force) {
  973: 	in_addrtou_addr(&b->ipcp.peer_addr, &iface->peer_addr);
  974:     } else {
  975: 	u_addrcopy(&iface->conf.peer_addr, &iface->peer_addr);
  976:     }
  977: 
  978:     if (IfaceNgIpInit(b, ready)) {
  979: 	Log(LG_ERR, ("[%s] IFACE: IfaceNgIpInit() error, closing IPCP", b->name));
  980: 	FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
  981: 	return (-1);
  982:     };
  983: 
  984:     /* Set addresses */
  985:     if (!u_rangeempty(&iface->self_addr) &&
  986: 	    IfaceChangeAddr(b, 1, &iface->self_addr, &iface->peer_addr)) {
  987: 	Log(LG_ERR, ("[%s] IFACE: IfaceChangeAddr() error, closing IPCP", b->name));
  988: 	FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
  989: 	return (-1);
  990:     };
  991: 
  992:     /* Proxy ARP for peer if desired and peer's address is known */
  993:     u_addrclear(&iface->proxy_addr);
  994:     if (Enabled(&iface->options, IFACE_CONF_PROXY)) {
  995: 	u_addrtoa(&iface->peer_addr,hisaddr,sizeof(hisaddr));
  996: 	if (u_addrempty(&iface->peer_addr)) {
  997:     	    Log(LG_IFACE, ("[%s] IFACE: Can't proxy arp for %s",
  998: 		b->name, hisaddr));
  999: 	} else if (GetEther(&iface->peer_addr, &hwa) < 0) {
 1000:     	    Log(LG_IFACE, ("[%s] IFACE: No interface to proxy arp on for %s",
 1001: 		b->name, hisaddr));
 1002: 	} else {
 1003:     	    ether = (u_char *) LLADDR(&hwa);
 1004:     	    if (ExecCmdNosh(LG_IFACE2, b->name, 
 1005: 		"%s -S %s %x:%x:%x:%x:%x:%x pub",
 1006: 		PATH_ARP, hisaddr,
 1007: 		ether[0], ether[1], ether[2],
 1008: 		ether[3], ether[4], ether[5]) == 0)
 1009: 		iface->proxy_addr = iface->peer_addr;
 1010: 	}
 1011:     }
 1012:   
 1013:     /* Add static routes */
 1014:     SLIST_FOREACH(r, &iface->routes, next) {
 1015: 	if (u_rangefamily(&r->dest)==AF_INET) {
 1016: 	    r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_addr) == 0);
 1017: 	}
 1018:     }
 1019:     /* Add dynamic routes */
 1020:     SLIST_FOREACH(r, &b->params.routes, next) {
 1021: 	if (u_rangefamily(&r->dest)==AF_INET) {
 1022: 	    r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_addr) == 0);
 1023: 	}
 1024:     }
 1025: 
 1026: #ifdef USE_NG_NAT
 1027:     /* Set NAT IP */
 1028:     if (iface->nat_up)
 1029: 	IfaceSetupNAT(b);
 1030: #endif
 1031: 
 1032:     /* Call "up" script */
 1033:     if (*iface->up_script) {
 1034: 	char	selfbuf[40],peerbuf[40];
 1035: 	char	ns1buf[21], ns2buf[21];
 1036: 	int	res;
 1037: 
 1038: 	if(b->ipcp.want_dns[0].s_addr != 0)
 1039:     	    snprintf(ns1buf, sizeof(ns1buf), "dns1 %s", inet_ntoa(b->ipcp.want_dns[0]));
 1040: 	else
 1041:     	    ns1buf[0] = '\0';
 1042: 	if(b->ipcp.want_dns[1].s_addr != 0)
 1043:     	    snprintf(ns2buf, sizeof(ns2buf), "dns2 %s", inet_ntoa(b->ipcp.want_dns[1]));
 1044: 	else
 1045:     	    ns2buf[0] = '\0';
 1046: 
 1047: 	res = ExecCmd(LG_IFACE2, b->name, "%s %s inet %s %s '%s' '%s' '%s' '%s' '%s'",
 1048: 	    iface->up_script, iface->ifname,
 1049: 	    u_rangetoa(&iface->self_addr,selfbuf, sizeof(selfbuf)),
 1050:     	    u_addrtoa(&iface->peer_addr, peerbuf, sizeof(peerbuf)), 
 1051:     	    *b->params.authname ? b->params.authname : "-", 
 1052:     	    ns1buf, ns2buf, *b->params.peeraddr ? b->params.peeraddr : "-",
 1053:     	    b->params.filter_id ? b->params.filter_id : "-");
 1054: 	if (res != 0) {
 1055: 	    FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
 1056: 	    return (-1);
 1057: 	}
 1058:     }
 1059:     return (0);
 1060: }
 1061: 
 1062: /*
 1063:  * IfaceIpIfaceDown()
 1064:  *
 1065:  * Bring down the IP interface. This implies we're no longer ready.
 1066:  */
 1067: 
 1068: void
 1069: IfaceIpIfaceDown(Bund b)
 1070: {
 1071:     IfaceState	const iface = &b->iface;
 1072:     IfaceRoute	r;
 1073:     char	buf[48];
 1074: 
 1075:     /* Call "down" script */
 1076:     if (*iface->down_script) {
 1077: 	char	selfbuf[40],peerbuf[40];
 1078: 
 1079: 	ExecCmd(LG_IFACE2, b->name, "%s %s inet %s %s '%s' '%s' '%s'",
 1080:     	    iface->down_script, iface->ifname,
 1081:     	    u_rangetoa(&iface->self_addr,selfbuf, sizeof(selfbuf)),
 1082:     	    u_addrtoa(&iface->peer_addr, peerbuf, sizeof(peerbuf)), 
 1083:     	    *b->params.authname ? b->params.authname : "-",
 1084:     	    *b->params.peeraddr ? b->params.peeraddr : "-",
 1085:     	    b->params.filter_id ? b->params.filter_id : "-");
 1086:     }
 1087: 
 1088:     /* Delete dynamic routes */
 1089:     SLIST_FOREACH(r, &b->params.routes, next) {
 1090: 	if (u_rangefamily(&r->dest)==AF_INET) {
 1091: 	    if (!r->ok)
 1092: 		continue;
 1093: 	    IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_addr);
 1094: 	    r->ok = 0;
 1095: 	}
 1096:     }
 1097:     /* Delete static routes */
 1098:     SLIST_FOREACH(r, &iface->routes, next) {
 1099: 	if (u_rangefamily(&r->dest)==AF_INET) {
 1100: 	    if (!r->ok)
 1101: 		continue;
 1102: 	    IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_addr);
 1103: 	    r->ok = 0;
 1104: 	}
 1105:     }
 1106: 
 1107:     /* Delete any proxy arp entry */
 1108:     if (!u_addrempty(&iface->proxy_addr))
 1109: 	ExecCmdNosh(LG_IFACE2, b->name, "%s -d %s", PATH_ARP, u_addrtoa(&iface->proxy_addr, buf, sizeof(buf)));
 1110:     u_addrclear(&iface->proxy_addr);
 1111: 
 1112:     /* Remove address from interface */
 1113:     if (!u_rangeempty(&iface->self_addr))
 1114: 	IfaceChangeAddr(b, 0, &iface->self_addr, &iface->peer_addr);
 1115:     
 1116:     IfaceNgIpShutdown(b);
 1117: }
 1118: 
 1119: /*
 1120:  * IfaceIpv6IfaceUp()
 1121:  *
 1122:  * Bring up the IPv6 interface. The "ready" flag means that
 1123:  * IPv6CP is also up and we can deliver packets immediately.
 1124:  */
 1125: 
 1126: int
 1127: IfaceIpv6IfaceUp(Bund b, int ready)
 1128: {
 1129:     IfaceState		const iface = &b->iface;
 1130:     IfaceRoute		r;
 1131: 
 1132:     if (ready && !iface->conf.self_ipv6_addr_force) {
 1133:         iface->self_ipv6_addr.family = AF_INET6;
 1134:         iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[0] = 0x80fe;  /* Network byte order */
 1135:         iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[1] = 0x0000;
 1136:         iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[2] = 0x0000;
 1137:         iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[3] = 0x0000;
 1138:         bcopy(b->ipv6cp.myintid, &iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[4], sizeof(b->ipv6cp.myintid));
 1139:         bcopy(&iface->self_ipv6_addr.u.ip6, &b->ipv6cp.want_addr, sizeof(struct in6_addr));
 1140:     } else {
 1141: 	u_addrcopy(&iface->conf.self_ipv6_addr, &iface->self_ipv6_addr);
 1142:     }
 1143:     if (ready && !iface->conf.peer_ipv6_addr_force) {
 1144:         iface->peer_ipv6_addr.family = AF_INET6;
 1145:         iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[0] = 0x80fe;  /* Network byte order */
 1146:         iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[1] = 0x0000;
 1147:         iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[2] = 0x0000;
 1148:         iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[3] = 0x0000;
 1149:         bcopy(b->ipv6cp.hisintid, &iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[4], sizeof(b->ipv6cp.hisintid));
 1150:         bcopy(&iface->peer_ipv6_addr.u.ip6, &b->ipv6cp.peer_addr, sizeof(struct in6_addr));
 1151:     } else {
 1152: 	u_addrcopy(&iface->conf.peer_ipv6_addr, &iface->peer_ipv6_addr);
 1153:     }
 1154: 
 1155:     if (IfaceNgIpv6Init(b, ready)) {
 1156:         Log(LG_ERR, ("[%s] IFACE: IfaceNgIpv6Init() failed, closing IPv6CP", b->name));
 1157:         FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
 1158:         return (-1);
 1159:     };
 1160:   
 1161:     /* Set addresses */
 1162:     if (!u_addrempty(&iface->self_ipv6_addr)) {
 1163: 	struct u_range	rng;
 1164: 	rng.addr = iface->self_ipv6_addr;
 1165: 	rng.width = 64;
 1166: 	if (IfaceChangeAddr(b, 1, &rng, &iface->peer_ipv6_addr)) {
 1167: 	    Log(LG_ERR, ("[%s] IFACE: IfaceChangeAddr() failed, closing IPv6CP", b->name));
 1168: 	    FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
 1169:     	    return (-1);
 1170: 	}
 1171:     };
 1172:   
 1173:     /* Add static routes */
 1174:     SLIST_FOREACH(r, &iface->routes, next) {
 1175: 	if (u_rangefamily(&r->dest)==AF_INET6) {
 1176: 	    r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_ipv6_addr) == 0);
 1177: 	}
 1178:     }
 1179:     /* Add dynamic routes */
 1180:     SLIST_FOREACH(r, &b->params.routes, next) {
 1181: 	if (u_rangefamily(&r->dest)==AF_INET6) {
 1182: 	    r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_ipv6_addr) == 0);
 1183: 	}
 1184:     }
 1185: 
 1186:     /* Call "up" script */
 1187:     if (*iface->up_script) {
 1188: 	char	selfbuf[48],peerbuf[48];
 1189: 	int	res;
 1190: 
 1191: 	res = ExecCmd(LG_IFACE2, b->name, "%s %s inet6 %s%%%s %s%%%s '%s' '%s' '%s'",
 1192:     	    iface->up_script, iface->ifname, 
 1193:     	    u_addrtoa(&iface->self_ipv6_addr, selfbuf, sizeof(selfbuf)), iface->ifname,
 1194:     	    u_addrtoa(&iface->peer_ipv6_addr, peerbuf, sizeof(peerbuf)), iface->ifname, 
 1195:     	    *b->params.authname ? b->params.authname : "-",
 1196:     	    *b->params.peeraddr ? b->params.peeraddr : "-",
 1197:     	    b->params.filter_id ? b->params.filter_id : "-");
 1198: 	if (res != 0) {
 1199: 	    FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
 1200: 	    return (-1);
 1201: 	}
 1202:     }
 1203:     return (0);
 1204: 
 1205: }
 1206: 
 1207: /*
 1208:  * IfaceIpv6IfaceDown()
 1209:  *
 1210:  * Bring down the IPv6 interface. This implies we're no longer ready.
 1211:  */
 1212: 
 1213: void
 1214: IfaceIpv6IfaceDown(Bund b)
 1215: {
 1216:     IfaceState		const iface = &b->iface;
 1217:     IfaceRoute		r;
 1218:     struct u_range	rng;
 1219: 
 1220:     /* Call "down" script */
 1221:     if (*iface->down_script) {
 1222: 	char	selfbuf[48],peerbuf[48];
 1223: 
 1224: 	ExecCmd(LG_IFACE2, b->name, "%s %s inet6 %s%%%s %s%%%s '%s' '%s' '%s'",
 1225:     	    iface->down_script, iface->ifname, 
 1226:     	    u_addrtoa(&iface->self_ipv6_addr, selfbuf, sizeof(selfbuf)), iface->ifname,
 1227:     	    u_addrtoa(&iface->peer_ipv6_addr, peerbuf, sizeof(peerbuf)), iface->ifname, 
 1228:     	    *b->params.authname ? b->params.authname : "-",
 1229:     	    *b->params.peeraddr ? b->params.peeraddr : "-",
 1230:     	    b->params.filter_id ? b->params.filter_id : "-");
 1231:     }
 1232: 
 1233:     /* Delete dynamic routes */
 1234:     SLIST_FOREACH(r, &b->params.routes, next) {
 1235: 	if (u_rangefamily(&r->dest)==AF_INET6) {
 1236: 	    if (!r->ok)
 1237: 		continue;
 1238: 	    IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_ipv6_addr);
 1239: 	    r->ok = 0;
 1240: 	}
 1241:     }
 1242:     /* Delete static routes */
 1243:     SLIST_FOREACH(r, &iface->routes, next) {
 1244: 	if (u_rangefamily(&r->dest)==AF_INET6) {
 1245: 	    if (!r->ok)
 1246: 		continue;
 1247: 	    IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_ipv6_addr);
 1248: 	    r->ok = 0;
 1249: 	}
 1250:     }
 1251: 
 1252:     if (!u_addrempty(&iface->self_ipv6_addr)) {
 1253: 	/* Remove address from interface */
 1254: 	rng.addr = iface->self_ipv6_addr;
 1255: 	rng.width = 64;
 1256: 	IfaceChangeAddr(b, 0, &rng, &iface->peer_ipv6_addr);
 1257:     }
 1258: 
 1259:     IfaceNgIpv6Shutdown(b);
 1260: }
 1261: 
 1262: /*
 1263:  * IfaceIdleTimeout()
 1264:  */
 1265: 
 1266: static void
 1267: IfaceIdleTimeout(void *arg)
 1268: {
 1269:     Bund b = (Bund)arg;
 1270: 
 1271:   IfaceState			const iface = &b->iface;
 1272:   int				k;
 1273: 
 1274:   /* Get updated bpf node traffic statistics */
 1275:   BundUpdateStats(b);
 1276: 
 1277:   /* Mark current traffic period if there was traffic */
 1278:   if (iface->idleStats.recvFrames + iface->idleStats.xmitFrames < 
 1279: 	b->stats.recvFrames + b->stats.xmitFrames) {
 1280:     iface->traffic[0] = TRUE;
 1281:   } else {		/* no demand traffic for a whole idle timeout period? */
 1282:     for (k = 0; k < IFACE_IDLE_SPLIT && !iface->traffic[k]; k++);
 1283:     if (k == IFACE_IDLE_SPLIT) {
 1284:       Log(LG_BUND, ("[%s] IFACE: Idle timeout", b->name));
 1285:       RecordLinkUpDownReason(b, NULL, 0, STR_IDLE_TIMEOUT, NULL);
 1286:       BundClose(b);
 1287:       return;
 1288:     }
 1289:   }
 1290: 
 1291:   iface->idleStats = b->stats;
 1292: 
 1293:   /* Shift traffic history */
 1294:   memmove(iface->traffic + 1,
 1295:     iface->traffic, (IFACE_IDLE_SPLIT - 1) * sizeof(*iface->traffic));
 1296:   iface->traffic[0] = FALSE;
 1297: 
 1298:   /* Restart timer */
 1299:   TimerStart(&iface->idleTimer);
 1300: }
 1301: 
 1302: /*
 1303:  * IfaceSessionTimeout()
 1304:  */
 1305: 
 1306: static void
 1307: IfaceSessionTimeout(void *arg)
 1308: {
 1309:     Bund b = (Bund)arg;
 1310: 
 1311:   Log(LG_BUND, ("[%s] IFACE: Session timeout", b->name));
 1312: 
 1313:   RecordLinkUpDownReason(b, NULL, 0, STR_SESSION_TIMEOUT, NULL);
 1314: 
 1315:   BundClose(b);
 1316: 
 1317: }
 1318: 
 1319: /*
 1320:  * IfaceCachePkt()
 1321:  *
 1322:  * A packet caused dial-on-demand; save it for later if possible.
 1323:  * Consumes the mbuf in any case.
 1324:  */
 1325: 
 1326: static void
 1327: IfaceCachePkt(Bund b, int proto, Mbuf pkt)
 1328: {
 1329:     IfaceState	const iface = &b->iface;
 1330: 
 1331:     /* Only cache network layer data */
 1332:     if (!PROT_NETWORK_DATA(proto)) {
 1333: 	mbfree(pkt);
 1334: 	return;
 1335:     }
 1336: 
 1337:     /* Release previously cached packet, if any, and save this one */
 1338:     if (iface->dodCache.pkt)
 1339: 	mbfree(iface->dodCache.pkt);
 1340: 
 1341:     iface->dodCache.pkt = pkt;
 1342:     iface->dodCache.proto = proto;
 1343:     iface->dodCache.ts = time(NULL);
 1344: }
 1345: 
 1346: /*
 1347:  * IfaceCacheSend()
 1348:  *
 1349:  * Send cached packet
 1350:  */
 1351: 
 1352: static void
 1353: IfaceCacheSend(Bund b)
 1354: {
 1355:     IfaceState	const iface = &b->iface;
 1356: 
 1357:     if (iface->dodCache.pkt) {
 1358: 	if (iface->dodCache.ts + MAX_DOD_CACHE_DELAY < time(NULL))
 1359:     	    mbfree(iface->dodCache.pkt);
 1360: 	else {
 1361:     	    if (NgFuncWritePppFrame(b, NG_PPP_BUNDLE_LINKNUM,
 1362: 		    iface->dodCache.proto, iface->dodCache.pkt) < 0) {
 1363: 		Perror("[%s] can't write cached pkt", b->name);
 1364:     	    }
 1365: 	}
 1366: 	iface->dodCache.pkt = NULL;
 1367:     }
 1368: }
 1369: 
 1370: /*
 1371:  * IfaceIsDemand()
 1372:  *
 1373:  * Determine if this outgoing packet qualifies for dial-on-demand
 1374:  */
 1375: 
 1376: static int
 1377: IfaceIsDemand(int proto, Mbuf pkt)
 1378: {
 1379:   switch (proto) {
 1380:     case PROTO_IP:
 1381:       {
 1382:         struct ip	*ip;
 1383: 
 1384:         if (MBLEN(pkt) < sizeof(struct ip))
 1385: 	    return (0);
 1386: 
 1387: 	ip = (struct ip *)MBDATA(pkt);
 1388: 	switch (ip->ip_p) {
 1389: 	  case IPPROTO_IGMP:		/* No multicast stuff */
 1390: 	    return(0);
 1391: #if (!defined(__FreeBSD__) || __FreeBSD_version >= 600025)
 1392: 	  case IPPROTO_ICMP:
 1393: 	    {
 1394: 	      struct icmphdr	*icmp;
 1395: 	      
 1396:     	      if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct icmphdr)))
 1397: 		return (0);
 1398: 
 1399: 	      icmp = (struct icmphdr *) ((u_int32_t *) ip + ip->ip_hl);
 1400: 
 1401: 	      switch (icmp->icmp_type)	/* No ICMP replies */
 1402: 	      {
 1403: 		case ICMP_ECHOREPLY:
 1404: 		case ICMP_UNREACH:
 1405: 		case ICMP_REDIRECT:
 1406: 		  return(0);
 1407: 		default:
 1408: 		  break;
 1409: 	      }
 1410: 	    }
 1411: 	    break;
 1412: #endif
 1413: 	  case IPPROTO_UDP:
 1414: 	    {
 1415: 	      struct udphdr	*udp;
 1416: 
 1417:     	      if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct udphdr)))
 1418: 		return (0);
 1419: 
 1420: 	      udp = (struct udphdr *) ((u_int32_t *) ip + ip->ip_hl);
 1421: 
 1422: #define NTP_PORT	123
 1423: 	      if (ntohs(udp->uh_dport) == NTP_PORT)	/* No NTP packets */
 1424: 		return(0);
 1425: 	    }
 1426: 	    break;
 1427: 	  case IPPROTO_TCP:
 1428: 	    {
 1429: 	      struct tcphdr	*tcp;
 1430: 
 1431:     	      if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct tcphdr)))
 1432: 		return (0);
 1433: 
 1434: 	      tcp = (struct tcphdr *) ((u_int32_t *) ip + ip->ip_hl);
 1435: 
 1436: 	      if (tcp->th_flags & TH_RST)	/* No TCP reset packets */
 1437: 		return(0);
 1438: 	    }
 1439: 	    break;
 1440: 	  default:
 1441: 	    break;
 1442: 	}
 1443: 	break;
 1444:       }
 1445:     default:
 1446:       break;
 1447:   }
 1448:   return(1);
 1449: }
 1450: 
 1451: /*
 1452:  * IfaceSetCommand()
 1453:  */
 1454: 
 1455: static int
 1456: IfaceSetCommand(Context ctx, int ac, char *av[], void *arg)
 1457: {
 1458:   IfaceState	const iface = &ctx->bund->iface;
 1459:   int		empty_arg;
 1460: 
 1461:   switch ((intptr_t)arg) {
 1462:     case SET_NAME:
 1463: #ifdef SIOCSIFDESCR
 1464:     case SET_DESCR:
 1465: #endif
 1466:     case SET_UP_SCRIPT:
 1467:     case SET_DOWN_SCRIPT:
 1468:       empty_arg = TRUE;
 1469:       break;
 1470:     default:
 1471:       empty_arg = FALSE;
 1472:       break;
 1473:   }
 1474: 
 1475:   if ((ac == 0) && (empty_arg == FALSE))
 1476:     return(-1);
 1477:   switch ((intptr_t)arg) {
 1478:     case SET_IDLE:
 1479:       iface->idle_timeout = atoi(*av);
 1480:       break;
 1481:     case SET_SESSION:
 1482:       iface->session_timeout = atoi(*av);
 1483:       break;
 1484:     case SET_ADDRS:
 1485:       {
 1486: 	struct u_range	self_addr;
 1487: 	struct u_addr	peer_addr;
 1488: 	int	self_addr_force = 0, peer_addr_force = 0;
 1489: 	char	*arg;
 1490: 
 1491: 	/* Parse */
 1492: 	if (ac != 2)
 1493: 	  return(-1);
 1494: 	arg = av[0];
 1495: 	if (arg[0] == '!') {
 1496: 	    self_addr_force = 1;
 1497: 	    arg++;
 1498: 	}
 1499: 	if (!ParseRange(arg, &self_addr, ALLOW_IPV4|ALLOW_IPV6))
 1500: 	  Error("Bad IP address \"%s\"", av[0]);
 1501: 	arg = av[1];
 1502: 	if (arg[0] == '!') {
 1503: 	    peer_addr_force = 1;
 1504: 	    arg++;
 1505: 	}
 1506: 	if (!ParseAddr(arg, &peer_addr, ALLOW_IPV4|ALLOW_IPV6))
 1507: 	  Error("Bad IP address \"%s\"", av[1]);
 1508: 	if (self_addr.addr.family != peer_addr.family)
 1509: 	  Error("Addresses must be from the same protocol family");
 1510: 
 1511: 	/* OK */
 1512: 	if (peer_addr.family == AF_INET) {
 1513: 	    iface->conf.self_addr = self_addr;
 1514: 	    iface->conf.peer_addr = peer_addr;
 1515: 	    iface->conf.self_addr_force = self_addr_force;
 1516: 	    iface->conf.peer_addr_force = peer_addr_force;
 1517: 	} else {
 1518: 	    iface->conf.self_ipv6_addr = self_addr.addr;
 1519: 	    iface->conf.peer_ipv6_addr = peer_addr;
 1520: 	    iface->conf.self_ipv6_addr_force = self_addr_force;
 1521: 	    iface->conf.peer_ipv6_addr_force = peer_addr_force;
 1522: 	}
 1523:       }
 1524:       break;
 1525: 
 1526:     case SET_ROUTE:
 1527:       {
 1528: 	struct u_range		range;
 1529: 	IfaceRoute		r;
 1530: 
 1531: 	/* Check */
 1532: 	if (ac != 1)
 1533: 	  return(-1);
 1534: 
 1535: 	/* Get dest address */
 1536: 	if (!strcasecmp(av[0], "default")) {
 1537: 	  u_rangeclear(&range);
 1538: 	  range.addr.family=AF_INET;
 1539: 	}
 1540: 	else if (!ParseRange(av[0], &range, ALLOW_IPV4|ALLOW_IPV6))
 1541: 	  Error("Bad route dest address \"%s\"", av[0]);
 1542: 	r = Malloc(MB_IFACE, sizeof(struct ifaceroute));
 1543: 	r->dest = range;
 1544: 	r->ok = 0;
 1545: 	SLIST_INSERT_HEAD(&iface->routes, r, next);
 1546:       }
 1547:       break;
 1548: 
 1549:     case SET_MTU:
 1550:       {
 1551: 	int	max_mtu;
 1552: 
 1553: 	/* Check */
 1554: 	if (ac != 1)
 1555: 	  return(-1);
 1556: 
 1557: 	max_mtu = atoi(av[0]);
 1558: 	if (max_mtu < IFACE_MIN_MTU || max_mtu > IFACE_MAX_MTU)
 1559: 	  Error("Invalid interface mtu %d", max_mtu);
 1560: 	iface->max_mtu = max_mtu;
 1561:       }
 1562:       break;
 1563: 
 1564:     case SET_NAME:
 1565: 	switch (ac) {
 1566: 	  case 0:
 1567: 	    /* Restore original interface name */
 1568: 	    if (strcmp(iface->ifname, iface->ngname) != 0) {
 1569: 		iface->conf.ifname[0] = '\0';
 1570: 		return IfaceSetName(ctx->bund, iface->ngname);
 1571: 	    }
 1572: 	    break;
 1573: 	  case 1:
 1574: 	    if (strcmp(iface->ifname, av[0]) != 0) {
 1575: 		int ifmaxlen = IF_NAMESIZE - ctx->bund->tmpl * IFNUMLEN;
 1576: 		if (strlen(av[0]) >= ifmaxlen)
 1577: 		    Error("Interface name too long, >%d characters", ifmaxlen-1);
 1578: 		if ((strncmp(av[0], "ng", 2) == 0) &&
 1579: 		  ((ctx->bund->tmpl && av[0][2] == 0) ||
 1580: 		  (av[0][2] >= '0' && av[0][2] <= '9')))
 1581: 		    Error("This interface name is reserved");
 1582: 		strlcpy(iface->conf.ifname, av[0], sizeof(iface->conf.ifname));
 1583: 		return IfaceSetName(ctx->bund, av[0]);
 1584: 	    }
 1585: 	    break;
 1586: 	  default:
 1587: 	    return(-1);
 1588: 	}
 1589: 	break;
 1590: #ifdef SIOCSIFDESCR
 1591:     case SET_DESCR:
 1592: 	IfaceFreeDescr(iface);
 1593: 	switch (ac) {
 1594: 	  case 0:
 1595: 	    return IfaceSetDescr(ctx->bund, "");
 1596: 	    break;
 1597: 	  case 1:
 1598: 	    iface->conf.ifdescr = Mstrdup(MB_IFACE, av[0]);
 1599: 	    return IfaceSetDescr(ctx->bund, av[0]);
 1600: 	    break;
 1601: 	  default:
 1602: 	    return(-1);
 1603: 	}
 1604: 	break;
 1605: #endif
 1606: #ifdef SIOCAIFGROUP
 1607:     case SET_GROUP:
 1608: 	if (ac != 1)
 1609: 	  return(-1);
 1610: 
 1611: 	if (av[0][0] && isdigit(av[0][strlen(av[0]) - 1]))
 1612: 	    Error("Groupnames may not end in a digit");
 1613: 	if (strlen(av[0]) >= IFNAMSIZ)
 1614: 	    Error("Group name %s too long", av[0]);
 1615: 	if (iface->conf.ifgroup[0] != 0)
 1616: 	    IfaceDelGroup(ctx->bund, iface->conf.ifgroup);
 1617: 	strlcpy(iface->conf.ifgroup, av[0], IFNAMSIZ);
 1618: 	return IfaceAddGroup(ctx->bund, av[0]);
 1619:       break;
 1620: #endif
 1621:     case SET_UP_SCRIPT:
 1622:       switch (ac) {
 1623: 	case 0:
 1624: 	  *iface->up_script = 0;
 1625: 	  break;
 1626: 	case 1:
 1627: 	  strlcpy(iface->up_script, av[0], sizeof(iface->up_script));
 1628: 	  break;
 1629: 	default:
 1630: 	  return(-1);
 1631:       }
 1632:       break;
 1633: 
 1634:     case SET_DOWN_SCRIPT:
 1635:       switch (ac) {
 1636: 	case 0:
 1637: 	  *iface->down_script = 0;
 1638: 	  break;
 1639: 	case 1:
 1640: 	  strlcpy(iface->down_script, av[0], sizeof(iface->down_script));
 1641: 	  break;
 1642: 	default:
 1643: 	  return(-1);
 1644:       }
 1645:       break;
 1646: 
 1647:     case SET_ENABLE:
 1648:       EnableCommand(ac, av, &iface->options, gConfList);
 1649:       break;
 1650: 
 1651:     case SET_DISABLE:
 1652:       DisableCommand(ac, av, &iface->options, gConfList);
 1653:       break;
 1654: 
 1655:     default:
 1656:       assert(0);
 1657:   }
 1658:   return(0);
 1659: }
 1660: 
 1661: /*
 1662:  * IfaceStat()
 1663:  */
 1664: 
 1665: int
 1666: IfaceStat(Context ctx, int ac, char *av[], void *arg)
 1667: {
 1668:     Bund	const b = ctx->bund;
 1669:     IfaceState	const iface = &b->iface;
 1670:     IfaceRoute	r;
 1671: #ifdef USE_NG_BPF
 1672:     int		k;
 1673: #endif
 1674:     char	buf[48];
 1675: #if defined(USE_NG_BPF) || defined(USE_IPFW)
 1676:     struct acl	*a;
 1677: #endif
 1678: 
 1679:     Printf("Interface configuration:\r\n");
 1680:     Printf("\tName            : %s\r\n", iface->conf.ifname);
 1681: #ifdef SIOCSIFDESCR
 1682:     Printf("\tDescription     : \"%s\"\r\n",
 1683: 	(iface->ifdescr != NULL) ? iface->ifdescr : "<none>");
 1684: #endif
 1685: #ifdef SIOCAIFGROUP
 1686:     Printf("\tGroup           : %s\r\n", iface->conf.ifgroup);
 1687: #endif
 1688:     Printf("\tMaximum MTU     : %d bytes\r\n", iface->max_mtu);
 1689:     Printf("\tIdle timeout    : %d seconds\r\n", iface->idle_timeout);
 1690:     Printf("\tSession timeout : %d seconds\r\n", iface->session_timeout);
 1691:     if (!u_rangeempty(&iface->conf.self_addr)) {
 1692: 	Printf("\tIP Addresses    : %s%s -> ", iface->conf.self_addr_force?"!":"",
 1693: 	    u_rangetoa(&iface->conf.self_addr,buf,sizeof(buf)));
 1694: 	Printf("%s%s\r\n",  iface->conf.peer_addr_force?"!":"",
 1695: 	    u_addrtoa(&iface->conf.peer_addr,buf,sizeof(buf)));
 1696:     }
 1697:     if (!u_addrempty(&iface->conf.self_ipv6_addr)) {
 1698: 	Printf("\tIPv6 Addresses  : %s%s%%%s -> ",  iface->conf.self_ipv6_addr_force?"!":"",
 1699: 	    u_addrtoa(&iface->conf.self_ipv6_addr,buf,sizeof(buf)), iface->ifname);
 1700: 	Printf("%s%s%%%s\r\n",  iface->conf.peer_ipv6_addr_force?"!":"",
 1701: 	    u_addrtoa(&iface->conf.peer_ipv6_addr,buf,sizeof(buf)), iface->ifname);
 1702:     }
 1703:     Printf("\tEvent scripts\r\n");
 1704:     Printf("\t  up-script     : \"%s\"\r\n",
 1705: 	*iface->up_script ? iface->up_script : "<none>");
 1706:     Printf("\t  down-script   : \"%s\"\r\n",
 1707: 	*iface->down_script ? iface->down_script : "<none>");
 1708:     Printf("Interface options:\r\n");
 1709:     OptStat(ctx, &iface->options, gConfList);
 1710:     if (!SLIST_EMPTY(&iface->routes)) {
 1711: 	Printf("Static routes via peer:\r\n");
 1712: 	SLIST_FOREACH(r, &iface->routes, next) {
 1713: 	    Printf("\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));
 1714: 	}
 1715:     }
 1716:     Printf("Interface status:\r\n");
 1717:     Printf("\tAdmin status    : %s\r\n", iface->open ? "OPEN" : "CLOSED");
 1718:     Printf("\tStatus          : %s\r\n", iface->up ? (iface->dod?"DoD":"UP") : "DOWN");
 1719:     Printf("\tName            : %s\r\n", iface->ifname);
 1720: #ifdef SIOCSIFDESCR
 1721:     Printf("\tDescription     : \"%s\"\r\n",
 1722: 	(iface->ifdescr != NULL) ? iface->ifdescr : "<none>");
 1723: #endif
 1724:     if (iface->up) {
 1725: 	Printf("\tSession time    : %ld seconds\r\n", (long int)(time(NULL) - iface->last_up));
 1726: 	if (b->params.idle_timeout || iface->idle_timeout)
 1727: 	    Printf("\tIdle timeout    : %d seconds\r\n", b->params.idle_timeout?b->params.idle_timeout:iface->idle_timeout);
 1728: 	if (b->params.session_timeout || iface->session_timeout)
 1729: 	    Printf("\tSession timeout : %d seconds\r\n", b->params.session_timeout?b->params.session_timeout:iface->session_timeout);
 1730: 	Printf("\tMTU             : %d bytes\r\n", iface->mtu);
 1731:     }
 1732:     if (iface->ip_up && !u_rangeempty(&iface->self_addr)) {
 1733: 	Printf("\tIP Addresses    : %s -> ", u_rangetoa(&iface->self_addr,buf,sizeof(buf)));
 1734: 	Printf("%s\r\n", u_addrtoa(&iface->peer_addr,buf,sizeof(buf)));
 1735:     }
 1736:     if (iface->ipv6_up && !u_addrempty(&iface->self_ipv6_addr)) {
 1737: 	Printf("\tIPv6 Addresses  : %s%%%s -> ", 
 1738: 	    u_addrtoa(&iface->self_ipv6_addr,buf,sizeof(buf)), iface->ifname);
 1739: 	Printf("%s%%%s\r\n", u_addrtoa(&iface->peer_ipv6_addr,buf,sizeof(buf)), iface->ifname);
 1740:     }
 1741:     if (iface->up) {
 1742:         Printf("Dynamic routes via peer:\r\n");
 1743: 	SLIST_FOREACH(r, &ctx->bund->params.routes, next) {
 1744: 	    Printf("\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));
 1745: 	}
 1746: #ifdef USE_IPFW
 1747: 	Printf("IPFW pipes:\r\n");
 1748: 	a = ctx->bund->params.acl_pipe;
 1749: 	while (a) {
 1750: 	    Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
 1751: 	    a = a->next;
 1752: 	}
 1753: 	Printf("IPFW queues:\r\n");
 1754: 	a = ctx->bund->params.acl_queue;
 1755: 	while (a) {
 1756: 	    Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
 1757: 	    a = a->next;
 1758: 	}
 1759: 	Printf("IPFW tables:\r\n");
 1760: 	a = ctx->bund->params.acl_table;
 1761: 	while (a) {
 1762: 	    if (a->number != 0)
 1763: 		Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
 1764: 	    else
 1765: 		Printf("\t(%d)\t: '%s'\r\n", a->real_number, a->rule);
 1766: 	    a = a->next;
 1767: 	}
 1768: 	Printf("IPFW rules:\r\n");
 1769: 	a = ctx->bund->params.acl_rule;
 1770: 	while (a) {
 1771: 	    Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
 1772: 	    a = a->next;
 1773: 	}
 1774: #endif /* USE_IPFW */
 1775: #ifdef USE_NG_BPF
 1776: 	Printf("Traffic filters:\r\n");
 1777: 	for (k = 0; k < ACL_FILTERS; k++) {
 1778: 	    a = ctx->bund->params.acl_filters[k];
 1779: 	    if (a == NULL)
 1780: 		a = acl_filters[k];
 1781: 	    while (a) {
 1782: 		Printf("\t%d#%d\t: '%s'\r\n", (k + 1), a->number, a->rule);
 1783: 		a = a->next;
 1784: 	    }
 1785: 	}
 1786: 	Printf("Traffic limits:\r\n");
 1787: 	for (k = 0; k < 2; k++) {
 1788: 	    a = ctx->bund->params.acl_limits[k];
 1789: 	    while (a) {
 1790: 		Printf("\t%s#%d%s%s\t: '%s'\r\n", (k?"out":"in"), a->number,
 1791: 		    ((a->name[0])?"#":""), a->name, a->rule);
 1792: 		a = a->next;
 1793: 	    }
 1794: 	}
 1795: #endif /* USE_NG_BPF */
 1796:     }
 1797:     return(0);
 1798: }
 1799: 
 1800: /*
 1801:  * IfaceSetMTU()
 1802:  *
 1803:  * Set MTU and bandwidth on bundle's interface
 1804:  */
 1805: 
 1806: void
 1807: IfaceSetMTU(Bund b, int mtu)
 1808: {
 1809:     IfaceState		const iface = &b->iface;
 1810:     struct ifreq	ifr;
 1811:     int			s;
 1812: 
 1813:     /* Get socket */
 1814:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 1815: 	Perror("[%s] IFACE: Can't get socket to set MTU", b->name);
 1816: 	return;
 1817:     }
 1818: 
 1819:     if ((b->params.mtu > 0) && (mtu > b->params.mtu)) {
 1820: 	mtu = b->params.mtu;
 1821: 	Log(LG_IFACE2, ("[%s] IFACE: forcing MTU of auth backend: %d bytes",
 1822: 	    b->name, mtu));
 1823:     }
 1824: 
 1825:     /* Limit MTU to configured maximum */
 1826:     if (mtu > iface->max_mtu)
 1827:         mtu = iface->max_mtu;
 1828: 
 1829:     /* Set MTU on interface */
 1830:     memset(&ifr, 0, sizeof(ifr));
 1831:     strlcpy(ifr.ifr_name, b->iface.ifname, sizeof(ifr.ifr_name));
 1832:     ifr.ifr_mtu = mtu;
 1833:     Log(LG_IFACE2, ("[%s] IFACE: setting %s MTU to %d bytes",
 1834: 	b->name, b->iface.ifname, mtu));
 1835:     if (ioctl(s, SIOCSIFMTU, (char *)&ifr) < 0)
 1836: 	Perror("[%s] IFACE: ioctl(%s, %s)", b->name, b->iface.ifname, "SIOCSIFMTU");
 1837:     close(s);
 1838: 
 1839:     /* Save MTU */
 1840:     iface->mtu = mtu;
 1841: 
 1842: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
 1843:     /* Update tcpmssfix config */
 1844:     if (iface->mss_up)
 1845:         IfaceSetupMSS(b, MAXMSS(mtu));
 1846: #endif
 1847: 
 1848: }
 1849: 
 1850: void
 1851: IfaceChangeFlags(Bund b, int clear, int set)
 1852: {
 1853:     struct ifreq ifrq;
 1854:     int s, new_flags;
 1855: 
 1856:     Log(LG_IFACE2, ("[%s] IFACE: Change interface %s flags: -%d +%d",
 1857: 	b->name, b->iface.ifname, clear, set));
 1858: 
 1859:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 1860: 	Perror("[%s] IFACE: Can't get socket to change interface flags", b->name);
 1861: 	return;
 1862:     }
 1863: 
 1864:     memset(&ifrq, '\0', sizeof(ifrq));
 1865:     strlcpy(ifrq.ifr_name, b->iface.ifname, sizeof(ifrq.ifr_name));
 1866:     if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
 1867: 	Perror("[%s] IFACE: ioctl(SIOCGIFFLAGS, %s)", b->name, b->iface.ifname);
 1868: 	close(s);
 1869: 	return;
 1870:     }
 1871:     new_flags = (ifrq.ifr_flags & 0xffff) | (ifrq.ifr_flagshigh << 16);
 1872: 
 1873:     new_flags &= ~clear;
 1874:     new_flags |= set;
 1875: 
 1876:     ifrq.ifr_flags = new_flags & 0xffff;
 1877:     ifrq.ifr_flagshigh = new_flags >> 16;
 1878: 
 1879:     if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
 1880: 	Perror("[%s] IFACE: ioctl(SIOCSIFFLAGS, %s)", b->name, b->iface.ifname);
 1881: 	close(s);
 1882: 	return;
 1883:     }
 1884:     close(s);
 1885: }
 1886: 
 1887: #if defined(__KAME__) && !defined(NOINET6)
 1888: static void
 1889: add_scope(struct sockaddr *sa, int ifindex)
 1890: {
 1891:   struct sockaddr_in6 *sa6;
 1892: 
 1893:   if (sa->sa_family != AF_INET6)
 1894:     return;
 1895:   sa6 = (struct sockaddr_in6 *)sa;
 1896:   if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) &&
 1897:       !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr))
 1898:     return;
 1899:   if (sa6->sin6_addr.__u6_addr.__u6_addr16[1] != 0)
 1900:     return;
 1901:   sa6->sin6_addr.__u6_addr.__u6_addr16[1] = htons(ifindex);
 1902: }
 1903: #endif
 1904: 
 1905: int
 1906: IfaceChangeAddr(Bund b, int add, struct u_range *self, struct u_addr *peer)
 1907: {
 1908:     struct ifaliasreq ifra;
 1909:     struct in6_aliasreq ifra6;
 1910:     struct sockaddr_in *me4, *msk4, *peer4;
 1911:     struct sockaddr_storage ssself, sspeer, ssmsk;
 1912:     int res = 0;
 1913:     int s;
 1914:     char buf[48], buf1[48];
 1915: 
 1916:     Log(LG_IFACE2, ("[%s] IFACE: %s address %s->%s %s %s",
 1917: 	b->name, add?"Add":"Remove", u_rangetoa(self, buf, sizeof(buf)), 
 1918: 	((peer != NULL)?u_addrtoa(peer, buf1, sizeof(buf1)):""),
 1919: 	add?"to":"from", b->iface.ifname));
 1920: 
 1921:     u_rangetosockaddrs(self, &ssself, &ssmsk);
 1922:     if (peer)
 1923: 	u_addrtosockaddr(peer, 0, &sspeer);
 1924: 
 1925:     if ((s = socket(self->addr.family, SOCK_DGRAM, 0)) < 0) {
 1926: 	Perror("[%s] IFACE: Can't get socket to change interface address", b->name);
 1927: 	return (s);
 1928:     }
 1929: 
 1930:     switch (self->addr.family) {
 1931:       case AF_INET:
 1932: 	memset(&ifra, '\0', sizeof(ifra));
 1933: 	strlcpy(ifra.ifra_name, b->iface.ifname, sizeof(ifra.ifra_name));
 1934: 
 1935: 	me4 = (struct sockaddr_in *)&ifra.ifra_addr;
 1936: 	memcpy(me4, &ssself, sizeof(*me4));
 1937: 
 1938: 	msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
 1939: 	memcpy(msk4, &ssmsk, sizeof(*msk4));
 1940: 
 1941: 	peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
 1942: 	if (peer == NULL || peer->family == AF_UNSPEC) {
 1943:     	    peer4->sin_family = AF_INET;
 1944:     	    peer4->sin_len = sizeof(*peer4);
 1945:     	    peer4->sin_addr.s_addr = INADDR_NONE;
 1946: 	} else
 1947:     	    memcpy(peer4, &sspeer, sizeof(*peer4));
 1948: 
 1949: 	res = ioctl(s, add?SIOCAIFADDR:SIOCDIFADDR, &ifra);
 1950: 	if (res == -1) {
 1951: 	    Perror("[%s] IFACE: %s IPv4 address %s %s failed", 
 1952: 		b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname);
 1953: 	}
 1954: 	break;
 1955: 
 1956:       case AF_INET6:
 1957: 	memset(&ifra6, '\0', sizeof(ifra6));
 1958: 	strlcpy(ifra6.ifra_name, b->iface.ifname, sizeof(ifra6.ifra_name));
 1959: 
 1960: 	memcpy(&ifra6.ifra_addr, &ssself, sizeof(ifra6.ifra_addr));
 1961: 	memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof(ifra6.ifra_prefixmask));
 1962: 	if (peer == NULL || peer->family == AF_UNSPEC)
 1963:     	    ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
 1964: 	else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128,
 1965: 		    sizeof(in6mask128)) == 0)
 1966:     	    memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof(ifra6.ifra_dstaddr));
 1967: 	ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
 1968: 	ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
 1969: 
 1970: 	res = ioctl(s, add?SIOCAIFADDR_IN6:SIOCDIFADDR_IN6, &ifra6);
 1971: 	if (res == -1) {
 1972: 		if (add && errno == EEXIST) {
 1973: 			/* this can happen if the kernel has already automatically added
 1974: 			   the same link-local address - ignore the error */
 1975: 			res = 0;
 1976: 		} else {
 1977: 			Perror("[%s] IFACE: %s IPv6 address %s %s failed", 
 1978: 				b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname);
 1979: 		}
 1980: 	}
 1981: 	break;
 1982: 
 1983:       default:
 1984:         res = -1;
 1985: 	break;
 1986:     }
 1987:     close(s);
 1988:     return (res);
 1989: }
 1990: 
 1991: struct rtmsg {
 1992:   struct rt_msghdr m_rtm;
 1993:   char m_space[256];
 1994: };
 1995: 
 1996: static size_t
 1997: memcpy_roundup(char *cp, const void *data, size_t len)
 1998: {
 1999:   size_t padlen;
 2000: 
 2001: #define ROUNDUP(x) ((x) ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long))
 2002:   padlen = ROUNDUP(len);
 2003:   memcpy(cp, data, len);
 2004:   if (padlen > len)
 2005:     memset(cp + len, '\0', padlen - len);
 2006: 
 2007:   return padlen;
 2008: }
 2009: 
 2010: int
 2011: IfaceSetRoute(Bund b, int cmd, struct u_range *dst,
 2012:        struct u_addr *gw)
 2013: {
 2014:     struct rtmsg rtmes;
 2015:     int s, nb, wb;
 2016:     char *cp;
 2017:     const char *cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
 2018:     struct sockaddr_storage sadst, samask, sagw;
 2019:     char buf[48], buf1[48];
 2020: 
 2021:     s = socket(PF_ROUTE, SOCK_RAW, 0);
 2022:     if (s < 0) {
 2023: 	Perror("[%s] IFACE: Can't get route socket", b->name);
 2024: 	return (-1);
 2025:     }
 2026:     memset(&rtmes, '\0', sizeof(rtmes));
 2027:     rtmes.m_rtm.rtm_version = RTM_VERSION;
 2028:     rtmes.m_rtm.rtm_type = cmd;
 2029:     rtmes.m_rtm.rtm_addrs = RTA_DST;
 2030:     rtmes.m_rtm.rtm_seq = ++gRouteSeq;
 2031:     rtmes.m_rtm.rtm_pid = gPid;
 2032:     rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
 2033: 
 2034:     u_rangetosockaddrs(dst, &sadst, &samask);
 2035: #if defined(__KAME__) && !defined(NOINET6)
 2036:     add_scope((struct sockaddr *)&sadst, b->iface.ifindex);
 2037: #endif
 2038: 
 2039:     cp = rtmes.m_space;
 2040:     cp += memcpy_roundup(cp, &sadst, sadst.ss_len);
 2041:     if (gw != NULL) {
 2042: 	u_addrtosockaddr(gw, 0, &sagw);
 2043: #if defined(__KAME__) && !defined(NOINET6)
 2044: 	add_scope((struct sockaddr *)&sagw, b->iface.ifindex);
 2045: #endif
 2046:     	cp += memcpy_roundup(cp, &sagw, sagw.ss_len);
 2047:     	rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
 2048:     } else if (cmd == RTM_ADD) {
 2049:     	Log(LG_ERR, ("[%s] IfaceSetRoute: gw is not set\n", b->name));
 2050:     	close(s);
 2051:     	return (-1);
 2052:     }
 2053: 
 2054:     if (u_rangehost(dst)) {
 2055: 	rtmes.m_rtm.rtm_flags |= RTF_HOST;
 2056:     } else {
 2057: 	cp += memcpy_roundup(cp, &samask, samask.ss_len);
 2058: 	rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
 2059:     }
 2060: 
 2061:     nb = cp - (char *)&rtmes;
 2062:     rtmes.m_rtm.rtm_msglen = nb;
 2063:     wb = write(s, &rtmes, nb);
 2064:     if (wb < 0) {
 2065:     	Log(LG_ERR, ("[%s] IFACE: %s route %s %s failed: %s",
 2066: 	    b->name, cmdstr, u_rangetoa(dst, buf, sizeof(buf)), 
 2067: 	    ((gw != NULL)?u_addrtoa(gw, buf1, sizeof(buf1)):""),
 2068: 	    (rtmes.m_rtm.rtm_errno != 0)?strerror(rtmes.m_rtm.rtm_errno):strerror(errno)));
 2069: 	close(s);
 2070: 	return (-1);
 2071:     }
 2072:     close(s);
 2073:     Log(LG_IFACE2, ("[%s] IFACE: %s route %s %s",
 2074: 	    b->name, cmdstr, u_rangetoa(dst, buf, sizeof(buf)), 
 2075: 	    ((gw != NULL)?u_addrtoa(gw, buf1, sizeof(buf1)):"")));
 2076:     return (0);
 2077: }
 2078: 
 2079: #ifndef USE_NG_TCPMSS
 2080: void
 2081: IfaceCorrectMSS(Mbuf pkt, uint16_t maxmss)
 2082: {
 2083:   struct ip	*iphdr;
 2084:   struct tcphdr	*tc;
 2085:   int		pktlen, hlen, olen, optlen, accumulate;
 2086:   uint16_t	*mss;
 2087:   u_char	*opt;
 2088: 
 2089:   if (pkt == NULL)
 2090:     return;
 2091: 
 2092:   iphdr = (struct ip *)MBDATAU(pkt);
 2093:   hlen = iphdr->ip_hl << 2;
 2094:   pktlen = MBLEN(pkt) - hlen;
 2095:   tc = (struct tcphdr *)(MBDATAU(pkt) + hlen);
 2096:   hlen = tc->th_off << 2;
 2097: 
 2098:   /* Invalid header length or header without options. */
 2099:   if (hlen <= sizeof(struct tcphdr) || hlen > pktlen)
 2100:     return;
 2101: 
 2102:   /* MSS option only allowed within SYN packets. */  
 2103:   if (!(tc->th_flags & TH_SYN))
 2104:     return;
 2105: 
 2106:   for (olen = hlen - sizeof(struct tcphdr), opt = (u_char *)(tc + 1);
 2107: 	olen > 0; olen -= optlen, opt += optlen) {
 2108:     if (*opt == TCPOPT_EOL)
 2109:       break;
 2110:     else if (*opt == TCPOPT_NOP)
 2111:       optlen = 1;
 2112:     else {
 2113:       optlen = *(opt + 1);
 2114:       if (optlen <= 0 || optlen > olen)
 2115: 	break;
 2116:       if (*opt == TCPOPT_MAXSEG) {
 2117: 	if (optlen != TCPOLEN_MAXSEG)
 2118: 	  continue;
 2119: 	mss = (u_int16_t *)(opt + 2);
 2120: 	if (ntohs(*mss) > maxmss) {
 2121: 	  accumulate = *mss;
 2122: 	  *mss = htons(maxmss);
 2123: 	  accumulate -= *mss;
 2124: 	  ADJUST_CHECKSUM(accumulate, tc->th_sum);
 2125: 	}
 2126:       }
 2127:     }
 2128:   }
 2129: }
 2130: #endif
 2131: 
 2132: static int
 2133: IfaceNgIpInit(Bund b, int ready)
 2134: {
 2135:     struct ngm_connect	cn;
 2136:     char		path[NG_PATHSIZ];
 2137:     char		hook[NG_HOOKSIZ];
 2138: 
 2139:     if (!ready) {
 2140: 	/* Dial-on-Demand mode */
 2141: 	/* Use demand hook of the socket node */
 2142: 	snprintf(path, sizeof(path), ".:");
 2143: 	snprintf(hook, sizeof(hook), "4%d", b->id);
 2144: 
 2145:     } else {
 2146: 	snprintf(path, sizeof(path), "[%x]:", b->nodeID);
 2147: 	strcpy(hook, NG_PPP_HOOK_INET);
 2148: 
 2149: #ifdef USE_NG_NAT
 2150: 	/* Add a nat node if configured */
 2151: 	if (Enabled(&b->iface.options, IFACE_CONF_NAT)) {
 2152: 	    if (IfaceInitNAT(b, path, hook))
 2153: 		goto fail;
 2154: 	    b->iface.nat_up = 1;
 2155: 	}
 2156: #endif
 2157: 
 2158: 	/* Add a tee node if configured */
 2159: 	if (Enabled(&b->iface.options, IFACE_CONF_TEE)) {
 2160: 	    if (IfaceInitTee(b, path, hook, 0))
 2161: 		goto fail;
 2162: 	    b->iface.tee_up = 1;
 2163: 	}
 2164:   
 2165: #ifdef USE_NG_IPACCT
 2166: 	/* Connect a ipacct node if configured */
 2167: 	if (Enabled(&b->iface.options, IFACE_CONF_IPACCT)) {
 2168: 	    if (IfaceInitIpacct(b, path, hook))
 2169: 		goto fail;
 2170: 	    b->iface.ipacct_up = 1;
 2171: 	}
 2172: #endif	/* USE_NG_IPACCT */
 2173: 
 2174: #ifdef USE_NG_NETFLOW
 2175: #ifdef NG_NETFLOW_CONF_INGRESS
 2176: 	/* Connect a netflow node if configured */
 2177: 	if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN) ||
 2178: 	    Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
 2179: 	    if (IfaceInitNetflow(b, path, hook, 
 2180: 		Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)?1:0,
 2181: 		Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0, 0))
 2182: 		goto fail;
 2183: 	    if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN))
 2184: 		b->iface.nfin_up = 1;
 2185: 	    if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT))
 2186: 		b->iface.nfout_up = 1;
 2187: 	}
 2188: #else	/* NG_NETFLOW_CONF_INGRESS */
 2189: 	/* Connect a netflow node if configured */
 2190: 	if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) {
 2191: 	    if (IfaceInitNetflow(b, path, hook, 1, 0, 0))
 2192: 		goto fail;
 2193: 	    b->iface.nfin_up = 1;
 2194: 	}
 2195: 
 2196: 	if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
 2197: 	    if (IfaceInitNetflow(b, path, hook, 0, 1, 0))
 2198: 		goto fail;
 2199: 	    b->iface.nfout_up = 1;
 2200: 	}
 2201: #endif	/* NG_NETFLOW_CONF_INGRESS */
 2202: #endif	/* USE_NG_NETFLOW */
 2203: 
 2204:     }
 2205: 
 2206: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
 2207:     if (Enabled(&b->iface.options, IFACE_CONF_TCPMSSFIX)) {
 2208: 	if (IfaceInitMSS(b, path, hook))
 2209:     	    goto fail;
 2210: 	b->iface.mss_up = 1;
 2211:     }
 2212: #endif
 2213: 
 2214: #ifdef USE_NG_BPF
 2215:     if (IfaceInitLimits(b, path, hook))
 2216: 	goto fail;
 2217: #endif
 2218: 
 2219:     /* Connect graph to the iface node. */
 2220:     memset(&cn, 0, sizeof(cn));
 2221:     strcpy(cn.ourhook, hook);
 2222:     snprintf(cn.path, sizeof(cn.path), "%s:", b->iface.ngname);
 2223:     strcpy(cn.peerhook, NG_IFACE_HOOK_INET);
 2224:     if (NgSendMsg(gLinksCsock, path,
 2225:     	    NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
 2226: 	Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 2227: 	    b->name, path, cn.ourhook, cn.path, cn.peerhook);
 2228: 	goto fail;
 2229:     }
 2230: 
 2231:     if (ready) {
 2232: #ifdef USE_NG_NETFLOW
 2233: #ifdef NG_NETFLOW_CONF_INGRESS
 2234: 	if (b->iface.nfin_up || b->iface.nfout_up)
 2235: 	    IfaceSetupNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 0);
 2236: #else /* NG_NETFLOW_CONF_INGRESS */
 2237: 	if (b->iface.nfin_up)
 2238: 	    IfaceSetupNetflow(b, 1, 0, 0);
 2239: 
 2240: 	if (b->iface.nfout_up)
 2241: 	    IfaceSetupNetflow(b, 0, 1, 0);
 2242: #endif /* NG_NETFLOW_CONF_INGRESS */
 2243: #endif /* USE_NG_NETFLOW */
 2244:     }
 2245: 
 2246: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
 2247:     if (b->iface.mss_up)
 2248:         IfaceSetupMSS(b, MAXMSS(b->iface.mtu));
 2249: #endif
 2250:     
 2251: #ifdef USE_NG_BPF
 2252:     IfaceSetupLimits(b);
 2253: #endif
 2254: 
 2255:     /* OK */
 2256:     return(0);
 2257: 
 2258: fail:
 2259:     return(-1);
 2260: }
 2261: 
 2262: /*
 2263:  * IfaceNgIpShutdown()
 2264:  */
 2265: 
 2266: static void
 2267: IfaceNgIpShutdown(Bund b)
 2268: {
 2269:     char		path[NG_PATHSIZ];
 2270: 
 2271: #ifdef USE_NG_BPF
 2272:     IfaceShutdownLimits(b); /* Limits must shutdown first to save final stats. */
 2273: #endif
 2274: #ifdef USE_NG_NAT
 2275:     if (b->iface.nat_up)
 2276: 	IfaceShutdownNAT(b);
 2277:     b->iface.nat_up = 0;
 2278: #endif
 2279:     if (b->iface.tee_up)
 2280: 	IfaceShutdownTee(b, 0);
 2281:     b->iface.tee_up = 0;
 2282: #ifdef USE_NG_NETFLOW
 2283: #ifdef NG_NETFLOW_CONF_INGRESS
 2284:     if (b->iface.nfin_up || b->iface.nfout_up)
 2285: 	IfaceShutdownNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 0);
 2286:     b->iface.nfin_up = 0;
 2287:     b->iface.nfout_up = 0;
 2288: #else /* NG_NETFLOW_CONF_INGRESS */
 2289:     if (b->iface.nfin_up)
 2290: 	IfaceShutdownNetflow(b, 1, 0, 0);
 2291:     b->iface.nfin_up = 0;
 2292:     if (b->iface.nfout_up)
 2293: 	IfaceShutdownNetflow(b, 0, 1, 0);
 2294:     b->iface.nfout_up = 0;
 2295: #endif /* NG_NETFLOW_CONF_INGRESS */
 2296: #endif
 2297: #ifdef USE_NG_IPACCT
 2298:     if (b->iface.ipacct_up)
 2299: 	IfaceShutdownIpacct(b);
 2300:     b->iface.ipacct_up = 0;
 2301: #endif
 2302: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
 2303:     if (b->iface.mss_up)
 2304: 	IfaceShutdownMSS(b);
 2305: #endif
 2306:     b->iface.mss_up = 0;
 2307: 
 2308:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
 2309:     NgFuncDisconnect(gLinksCsock, b->name, path, NG_PPP_HOOK_INET);
 2310: 
 2311:     snprintf(path, sizeof(path), "%s:", b->iface.ngname);
 2312:     NgFuncDisconnect(gLinksCsock, b->name, path, NG_IFACE_HOOK_INET);
 2313: }
 2314: 
 2315: static int
 2316: IfaceNgIpv6Init(Bund b, int ready)
 2317: {
 2318:     struct ngm_connect	cn;
 2319:     char		path[NG_PATHSIZ];
 2320:     char		hook[NG_HOOKSIZ];
 2321: 
 2322:     if (!ready) {
 2323: 	/* Dial-on-Demand mode */
 2324: 	/* Use demand hook of the socket node */
 2325: 	snprintf(path, sizeof(path), ".:");
 2326: 	snprintf(hook, sizeof(hook), "6%d", b->id);
 2327:     } else {
 2328: 	snprintf(path, sizeof(path), "[%x]:", b->nodeID);
 2329: 	strcpy(hook, NG_PPP_HOOK_IPV6);
 2330: 
 2331: 	/* Add a tee node if configured */
 2332: 	if (Enabled(&b->iface.options, IFACE_CONF_TEE)) {
 2333: 	    if (IfaceInitTee(b, path, hook, 1))
 2334: 		goto fail;
 2335: 	    b->iface.tee6_up = 1;
 2336: 	}
 2337:   
 2338: #ifdef USE_NG_NETFLOW
 2339: #ifdef NG_NETFLOW_CONF_INGRESS
 2340: 	/* Connect a netflow node if configured */
 2341: 	if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN) ||
 2342: 	    Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
 2343: 	    if (IfaceInitNetflow(b, path, hook, 
 2344: 		Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)?1:0,
 2345: 		Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0, 1))
 2346: 		goto fail;
 2347: 	    if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN))
 2348: 		b->iface.nfin_up = 1;
 2349: 	    if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT))
 2350: 		b->iface.nfout_up = 1;
 2351: 	}
 2352: #else	/* NG_NETFLOW_CONF_INGRESS */
 2353: 	/* Connect a netflow node if configured */
 2354: 	if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) {
 2355: 	    if (IfaceInitNetflow(b, path, hook, 1, 0, 1))
 2356: 		goto fail;
 2357: 	    b->iface.nfin_up = 1;
 2358: 	}
 2359: 
 2360: 	if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
 2361: 	    if (IfaceInitNetflow(b, path, hook, 0, 1, 1))
 2362: 		goto fail;
 2363: 	    b->iface.nfout_up = 1;
 2364: 	}
 2365: #endif	/* NG_NETFLOW_CONF_INGRESS */
 2366: #endif	/* USE_NG_NETFLOW */
 2367:     }
 2368: 
 2369: #ifdef USE_NG_BPF
 2370:     if (IfaceInitLimits(b, path, hook))
 2371: 	goto fail;
 2372: #endif
 2373: 
 2374:     /* Connect graph to the iface node. */
 2375:     strcpy(cn.ourhook, hook);
 2376:     snprintf(cn.path, sizeof(cn.path), "%s:", b->iface.ngname);
 2377:     strcpy(cn.peerhook, NG_IFACE_HOOK_INET6);
 2378:     if (NgSendMsg(gLinksCsock, path,
 2379:     	    NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
 2380: 	Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 2381: 	    b->name, path, cn.ourhook, cn.path, cn.peerhook);
 2382: 	goto fail;
 2383:     }
 2384: 
 2385:     if (ready) {
 2386: #ifdef USE_NG_NETFLOW
 2387: #ifdef NG_NETFLOW_CONF_INGRESS
 2388: 	if (b->iface.nfin_up || b->iface.nfout_up)
 2389: 	    IfaceSetupNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 1);
 2390: #else /* NG_NETFLOW_CONF_INGRESS */
 2391: 	if (b->iface.nfin_up)
 2392: 	    IfaceSetupNetflow(b, 1, 0, 1);
 2393: 
 2394: 	if (b->iface.nfout_up)
 2395: 	    IfaceSetupNetflow(b, 0, 1, 1);
 2396: #endif /* NG_NETFLOW_CONF_INGRESS */
 2397: #endif /* USE_NG_NETFLOW */
 2398:     }
 2399: 
 2400: #ifdef USE_NG_BPF
 2401:     IfaceSetupLimits(b);
 2402: #endif
 2403: 
 2404:     /* OK */
 2405:     return(0);
 2406: 
 2407: fail:
 2408:     return(-1);
 2409: }
 2410: 
 2411: /*
 2412:  * IfaceNgIpv6Shutdown()
 2413:  */
 2414: 
 2415: static void
 2416: IfaceNgIpv6Shutdown(Bund b)
 2417: {
 2418:     char		path[NG_PATHSIZ];
 2419: 
 2420: #ifdef USE_NG_BPF
 2421:     IfaceShutdownLimits(b); /* Limits must shutdown first to save final stats. */
 2422: #endif
 2423:     if (b->iface.tee6_up)
 2424: 	IfaceShutdownTee(b, 1);
 2425:     b->iface.tee6_up = 0;
 2426: #ifdef USE_NG_NETFLOW
 2427: #ifdef NG_NETFLOW_CONF_INGRESS
 2428:     if (b->iface.nfin_up || b->iface.nfout_up)
 2429: 	IfaceShutdownNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 1);
 2430:     b->iface.nfin_up = 0;
 2431:     b->iface.nfout_up = 0;
 2432: #else /* NG_NETFLOW_CONF_INGRESS */
 2433:     if (b->iface.nfin_up)
 2434: 	IfaceShutdownNetflow(b, 1, 0, 1);
 2435:     b->iface.nfin_up = 0;
 2436:     if (b->iface.nfout_up)
 2437: 	IfaceShutdownNetflow(b, 0, 1, 1);
 2438:     b->iface.nfout_up = 0;
 2439: #endif /* NG_NETFLOW_CONF_INGRESS */
 2440: #endif
 2441: 
 2442:     snprintf(path, sizeof(path), "[%x]:", b->nodeID);
 2443:     NgFuncDisconnect(gLinksCsock, b->name, path, NG_PPP_HOOK_IPV6);
 2444: 
 2445:     snprintf(path, sizeof(path), "%s:", b->iface.ngname);
 2446:     NgFuncDisconnect(gLinksCsock, b->name, path, NG_IFACE_HOOK_INET6);
 2447: }
 2448: 
 2449: #ifdef USE_NG_NAT
 2450: static int
 2451: IfaceInitNAT(Bund b, char *path, char *hook)
 2452: {
 2453:     NatState      const nat = &b->iface.nat;
 2454:     struct ngm_mkpeer	mp;
 2455:     struct ngm_name	nm;
 2456:     struct in_addr	ip;
 2457: #ifdef NG_NAT_LOG
 2458:     struct ng_nat_mode	mode;
 2459: #endif  
 2460:     Log(LG_IFACE2, ("[%s] IFACE: Connecting NAT", b->name));
 2461:   
 2462:     strcpy(mp.type, NG_NAT_NODE_TYPE);
 2463:     strcpy(mp.ourhook, hook);
 2464:     strcpy(mp.peerhook, NG_NAT_HOOK_IN);
 2465:     if (NgSendMsg(gLinksCsock, path,
 2466: 	NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 2467:       Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
 2468: 	b->name, NG_NAT_NODE_TYPE, path, mp.ourhook);
 2469:       return(-1);
 2470:     }
 2471:     strlcat(path, ".", NG_PATHSIZ);
 2472:     strlcat(path, hook, NG_PATHSIZ);
 2473:     snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-nat", gPid, b->name);
 2474:     if (NgSendMsg(gLinksCsock, path,
 2475: 	NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 2476:       Perror("[%s] can't name %s node", b->name, NG_NAT_NODE_TYPE);
 2477:       return(-1);
 2478:     }
 2479:     strcpy(hook, NG_NAT_HOOK_OUT);
 2480: 
 2481:     /* Set NAT IP */
 2482:     if (u_addrempty(&nat->alias_addr)) {
 2483: 	ip.s_addr = 1; // Set something just to make it ready
 2484:     } else {
 2485: 	ip = nat->alias_addr.u.ip4;
 2486:     }
 2487:     if (NgSendMsg(gLinksCsock, path,
 2488: 	    NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR, &ip, sizeof(ip)) < 0)
 2489: 	Perror("[%s] can't set NAT ip", b->name);
 2490: 
 2491: #ifdef NG_NAT_LOG
 2492:     /* Set NAT mode */
 2493:     mode.flags = 0;
 2494:     if (Enabled(&nat->options, NAT_CONF_LOG))
 2495: 	mode.flags |= NG_NAT_LOG;
 2496:     if (!Enabled(&nat->options, NAT_CONF_INCOMING))
 2497: 	mode.flags |= NG_NAT_DENY_INCOMING;
 2498:     if (Enabled(&nat->options, NAT_CONF_SAME_PORTS))
 2499: 	mode.flags |= NG_NAT_SAME_PORTS;
 2500:     if (Enabled(&nat->options, NAT_CONF_UNREG_ONLY))
 2501: 	mode.flags |= NG_NAT_UNREGISTERED_ONLY;
 2502:     
 2503:     mode.mask = NG_NAT_LOG | NG_NAT_DENY_INCOMING | 
 2504: 	NG_NAT_SAME_PORTS | NG_NAT_UNREGISTERED_ONLY;
 2505:     if (NgSendMsg(gLinksCsock, path,
 2506: 	    NGM_NAT_COOKIE, NGM_NAT_SET_MODE, &mode, sizeof(mode)) < 0)
 2507: 	Perror("[%s] can't set NAT mode", b->name);
 2508: 
 2509:     /* Set NAT target IP */
 2510:     if (!u_addrempty(&nat->target_addr)) {
 2511: 	ip = nat->target_addr.u.ip4;
 2512: 	if (NgSendMsg(gLinksCsock, path,
 2513: 		NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR, &ip, sizeof(ip)) < 0) {
 2514: 	    Perror("[%s] can't set NAT target IP", b->name);
 2515: 	}
 2516:     }
 2517: #endif
 2518: 
 2519:     return(0);
 2520: }
 2521: 
 2522: static int
 2523: IfaceSetupNAT(Bund b)
 2524: {
 2525:     NatState	const nat = &b->iface.nat;
 2526:     char	path[NG_PATHSIZ];
 2527: #ifdef NG_NAT_DESC_LENGTH
 2528:     int k;
 2529:     union {
 2530:         u_char buf[sizeof(struct ng_mesg) + sizeof(uint32_t)];
 2531:         struct ng_mesg reply;
 2532:     } u;
 2533:     uint32_t *const nat_id = (uint32_t *)(void *)u.reply.data;
 2534: #endif
 2535: 
 2536:     snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name);
 2537:     if (u_addrempty(&nat->alias_addr)) {
 2538: 	if (NgSendMsg(gLinksCsock, path,
 2539:     		NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR,
 2540: 		&b->iface.self_addr.addr.u.ip4,
 2541: 		sizeof(b->iface.self_addr.addr.u.ip4)) < 0) {
 2542: 	    Perror("[%s] can't set NAT ip", b->name);
 2543: 	    return (-1);
 2544: 	}
 2545:     }
 2546: #ifdef NG_NAT_DESC_LENGTH
 2547:     /* redirect-port */
 2548:     for(k = 0; k < NM_PORT; k++) {
 2549:       if(nat->nrpt_id[k] == -1) {
 2550: 	if (NgSendMsg(gLinksCsock, path,
 2551: 		NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PORT, &nat->nrpt[k],
 2552: 		sizeof(struct ng_nat_redirect_port)) < 0) {
 2553: 	    Perror("[%s] can't set NAT redirect-port", b->name);
 2554: 	} else {
 2555: 	    if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
 2556: 		Perror("[%s] can't recv NAT redirect-port message", b->name);
 2557: 	    } else
 2558: 		nat->nrpt_id[k] = *nat_id;
 2559: 	}
 2560:       }
 2561:     }
 2562:     /* redirect-addr */
 2563:     for(k = 0; k < NM_ADDR; k++) {
 2564:       if(nat->nrad_id[k] == -1) {
 2565: 	if (NgSendMsg(gLinksCsock, path,
 2566: 		NGM_NAT_COOKIE, NGM_NAT_REDIRECT_ADDR, &nat->nrad[k],
 2567: 		sizeof(struct ng_nat_redirect_addr)) < 0) {
 2568: 	    Perror("[%s] can't set NAT redirect-addr", b->name);
 2569: 	} else {
 2570: 	    if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
 2571: 		Perror("[%s] can't recv NAT redirect-addr message", b->name);
 2572: 	    } else
 2573: 		nat->nrad_id[k] = *nat_id;
 2574: 	}
 2575:       }
 2576:     }
 2577:     /* redirect-proto */
 2578:     for(k = 0; k < NM_PROTO; k++) {
 2579:       if(nat->nrpr_id[k] == -1) {
 2580: 	if (NgSendMsg(gLinksCsock, path,
 2581: 		NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PROTO, &nat->nrpr[k],
 2582: 		sizeof(struct ng_nat_redirect_proto)) < 0) {
 2583: 	    Perror("[%s] can't set NAT redirect-proto", b->name);
 2584: 	} else {
 2585: 	    if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
 2586: 		Perror("[%s] can't recv NAT redirect-proto message", b->name);
 2587: 	    } else
 2588: 		nat->nrpr_id[k] = *nat_id;
 2589: 	}
 2590:       }
 2591:     }
 2592: #endif
 2593:     return (0);
 2594: }
 2595: 
 2596: static void
 2597: IfaceShutdownNAT(Bund b)
 2598: {
 2599:     char	path[NG_PATHSIZ];
 2600: #ifdef NG_NAT_DESC_LENGTH
 2601:     NatState	const nat = &b->iface.nat;
 2602:     int		k;
 2603: #endif
 2604: 
 2605:     snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name);
 2606:     NgFuncShutdownNode(gLinksCsock, b->name, path);
 2607: #ifdef NG_NAT_DESC_LENGTH
 2608:     /* redirect-port */
 2609:     for(k = 0; k < NM_PORT; k++)
 2610:       if(nat->nrpt_id[k] > 0)
 2611:         nat->nrpt_id[k] = -1;
 2612:     /* redirect-addr */
 2613:     for(k = 0; k < NM_ADDR; k++)
 2614:       if(nat->nrad_id[k] > 0)
 2615:         nat->nrad_id[k] = -1;
 2616:     /* redirect-proto */
 2617:     for(k = 0; k < NM_PROTO; k++)
 2618:       if(nat->nrpr_id[k] > 0)
 2619:         nat->nrpr_id[k] = -1;
 2620: #endif
 2621: }
 2622: #endif /* USE_NG_NAT */
 2623: 
 2624: static int
 2625: IfaceInitTee(Bund b, char *path, char *hook, int v6)
 2626: {
 2627:     struct ngm_mkpeer	mp;
 2628:     struct ngm_name	nm;
 2629: 
 2630:     Log(LG_IFACE2, ("[%s] IFACE: Connecting tee%s", b->name, v6?"6":""));
 2631:   
 2632:     strcpy(mp.type, NG_TEE_NODE_TYPE);
 2633:     strcpy(mp.ourhook, hook);
 2634:     strcpy(mp.peerhook, NG_TEE_HOOK_RIGHT);
 2635:     if (NgSendMsg(gLinksCsock, path,
 2636: 	NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 2637:       Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
 2638: 	b->name, NG_TEE_NODE_TYPE, path, mp.ourhook);
 2639:       return(-1);
 2640:     }
 2641:     strlcat(path, ".", NG_PATHSIZ);
 2642:     strlcat(path, hook, NG_PATHSIZ);
 2643:     snprintf(nm.name, sizeof(nm.name), "%s-tee%s", b->iface.ifname, v6?"6":"");
 2644:     if (NgSendMsg(gLinksCsock, path,
 2645: 	NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 2646:       Perror("[%s] can't name %s node", b->name, NG_TEE_NODE_TYPE);
 2647:       return(-1);
 2648:     }
 2649:     strcpy(hook, NG_TEE_HOOK_LEFT);
 2650: 
 2651:     return(0);
 2652: }
 2653: 
 2654: static void
 2655: IfaceShutdownTee(Bund b, int v6)
 2656: {
 2657:     char	path[NG_PATHSIZ];
 2658: 
 2659:     snprintf(path, sizeof(path), "%s-tee%s:", b->iface.ifname, v6?"6":"");
 2660:     NgFuncShutdownNode(gLinksCsock, b->name, path);
 2661: }
 2662: 
 2663: #ifdef USE_NG_IPACCT
 2664: static int
 2665: IfaceInitIpacct(Bund b, char *path, char *hook)
 2666: {
 2667:     struct ngm_mkpeer	mp;
 2668:     struct ngm_name	nm;
 2669:     struct ngm_connect  cn;
 2670:     char		path1[NG_PATHSIZ];
 2671:     struct {
 2672: 	struct ng_ipacct_mesg m;
 2673: 	int		data;
 2674:     } ipam;
 2675: 
 2676:     Log(LG_IFACE2, ("[%s] IFACE: Connecting ipacct", b->name));
 2677:   
 2678:     strcpy(mp.type, NG_TEE_NODE_TYPE);
 2679:     strcpy(mp.ourhook, hook);
 2680:     strcpy(mp.peerhook, NG_TEE_HOOK_RIGHT);
 2681:     if (NgSendMsg(gLinksCsock, path,
 2682: 	NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 2683:       Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
 2684: 	b->name, NG_TEE_NODE_TYPE, path, mp.ourhook);
 2685:       return(-1);
 2686:     }
 2687:     strlcat(path, ".", NG_PATHSIZ);
 2688:     strlcat(path, hook, NG_PATHSIZ);
 2689:     snprintf(nm.name, sizeof(nm.name), "%s_acct_tee", b->iface.ifname);
 2690:     if (NgSendMsg(gLinksCsock, path,
 2691: 	NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 2692:       Perror("[%s] can't name %s node", b->name, NG_TEE_NODE_TYPE);
 2693:       return(-1);
 2694:     }
 2695:     strcpy(hook, NG_TEE_HOOK_LEFT);
 2696: 
 2697:     strcpy(mp.type, NG_IPACCT_NODE_TYPE);
 2698:     strcpy(mp.ourhook, NG_TEE_HOOK_RIGHT2LEFT);
 2699:     snprintf(mp.peerhook, sizeof(mp.peerhook), "%s_in", b->iface.ifname);
 2700:     if (NgSendMsg(gLinksCsock, path,
 2701: 	NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 2702:       Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
 2703: 	b->name, NG_IPACCT_NODE_TYPE, path, mp.ourhook);
 2704:       return(-1);
 2705:     }
 2706:     snprintf(path1, sizeof(path1), "%s.%s", path, NG_TEE_HOOK_RIGHT2LEFT);
 2707:     snprintf(nm.name, sizeof(nm.name), "%s_ip_acct", b->iface.ifname);
 2708:     if (NgSendMsg(gLinksCsock, path1,
 2709: 	NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 2710:       Perror("[%s] can't name %s node", b->name, NG_IPACCT_NODE_TYPE);
 2711:       return(-1);
 2712:     }
 2713:     strcpy(cn.ourhook, NG_TEE_HOOK_LEFT2RIGHT);
 2714:     strcpy(cn.path, NG_TEE_HOOK_RIGHT2LEFT);
 2715:     snprintf(cn.peerhook, sizeof(cn.peerhook), "%s_out", b->iface.ifname);
 2716:     if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
 2717: 	sizeof(cn)) < 0) {
 2718:       Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 2719:         b->name, path, cn.ourhook, cn.path, cn.peerhook);
 2720:       return (-1);
 2721:     }
 2722:     
 2723:     snprintf(ipam.m.hname, sizeof(ipam.m.hname), "%s_in", b->iface.ifname);
 2724:     ipam.data = DLT_RAW;
 2725:     if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_SETDLT, 
 2726: 	&ipam, sizeof(ipam)) < 0) {
 2727:       Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
 2728:       return (-1);
 2729:     }
 2730:     ipam.data = 10000;
 2731:     if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_STHRS, 
 2732: 	&ipam, sizeof(ipam)) < 0) {
 2733:       Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
 2734:       return (-1);
 2735:     }
 2736:     
 2737:     snprintf(ipam.m.hname, sizeof(ipam.m.hname), "%s_out", b->iface.ifname);
 2738:     ipam.data = DLT_RAW;
 2739:     if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_SETDLT, 
 2740: 	&ipam, sizeof(ipam)) < 0) {
 2741:       Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
 2742:       return (-1);
 2743:     }
 2744:     ipam.data = 10000;
 2745:     if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_STHRS, 
 2746: 	&ipam, sizeof(ipam)) < 0) {
 2747:       Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
 2748:       return (-1);
 2749:     }
 2750: 
 2751:     return(0);
 2752: }
 2753: 
 2754: static void
 2755: IfaceShutdownIpacct(Bund b)
 2756: {
 2757:     char	path[NG_PATHSIZ];
 2758: 
 2759:     snprintf(path, sizeof(path), "%s_acct_tee:", b->iface.ifname);
 2760:     NgFuncShutdownNode(gLinksCsock, b->name, path);
 2761: }
 2762: #endif
 2763: 
 2764: #ifdef USE_NG_NETFLOW
 2765: static int
 2766: IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out, int v6)
 2767: {
 2768:     struct ngm_connect	cn;
 2769:     int nif;
 2770: 
 2771: #ifdef NG_NETFLOW_CONF_INGRESS
 2772:     nif = gNetflowIface + b->id*2;
 2773: #else
 2774:     nif = gNetflowIface + b->id*4 + out*2;
 2775: #endif
 2776:     nif += v6 ? 1 : 0;
 2777: 
 2778:     Log(LG_IFACE2, ("[%s] IFACE: Connecting netflow%s (%s)",
 2779: 	b->name, v6?"6":"",  out?"out":"in"));
 2780:   
 2781:     /* Create global ng_netflow(4) node if not yet. */
 2782:     if (gNetflowNodeID == 0) {
 2783: 	if (NgFuncInitGlobalNetflow())
 2784: 	    return(-1);
 2785:     }
 2786: 
 2787:     /* Connect ng_netflow(4) node to the ng_bpf(4)/ng_tee(4) node. */
 2788:     strcpy(cn.ourhook, hook);
 2789:     snprintf(cn.path, sizeof(cn.path), "[%x]:", gNetflowNodeID);
 2790: #ifndef NG_NETFLOW_CONF_INGRESS
 2791:     if (out) {
 2792: 	snprintf(cn.peerhook, sizeof(cn.peerhook), "%s%d", NG_NETFLOW_HOOK_OUT,
 2793: 	    nif);
 2794:     } else {
 2795: #endif
 2796: 	snprintf(cn.peerhook, sizeof(cn.peerhook), "%s%d", NG_NETFLOW_HOOK_DATA,
 2797: 	    nif);
 2798: #ifndef NG_NETFLOW_CONF_INGRESS
 2799:     }
 2800: #endif
 2801:     if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
 2802: 	sizeof(cn)) < 0) {
 2803:       Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 2804:         b->name, path, cn.ourhook, cn.path, cn.peerhook);
 2805:       return (-1);
 2806:     }
 2807:     strlcat(path, ".", NG_PATHSIZ);
 2808:     strlcat(path, hook, NG_PATHSIZ);
 2809: #ifndef NG_NETFLOW_CONF_INGRESS
 2810:     if (out) {
 2811: 	snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_DATA, nif);
 2812:     } else {
 2813: #endif
 2814: 	snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_OUT, nif);
 2815: #ifndef NG_NETFLOW_CONF_INGRESS
 2816:     }
 2817: #endif
 2818:     return (0);
 2819: }
 2820: 
 2821: static int
 2822: IfaceSetupNetflow(Bund b, char in, char out, int v6)
 2823: {
 2824:     char path[NG_PATHSIZ];
 2825:     struct ng_netflow_setdlt	 nf_setdlt;
 2826:     struct ng_netflow_setifindex nf_setidx;
 2827: #ifdef NG_NETFLOW_CONF_INGRESS
 2828:     struct ng_netflow_setconfig  nf_setconf;
 2829: #endif
 2830:     int nif;
 2831: 
 2832: #ifdef NG_NETFLOW_CONF_INGRESS
 2833:     nif = gNetflowIface + b->id*2;
 2834: #else
 2835:     nif = gNetflowIface + b->id*4 + out*2;
 2836: #endif
 2837:     nif += v6 ? 1 : 0;
 2838: 
 2839:     /* Configure data link type and interface index. */
 2840:     snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
 2841:     nf_setdlt.iface = nif;
 2842:     nf_setdlt.dlt = DLT_RAW;
 2843:     if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETDLT,
 2844: 	&nf_setdlt, sizeof(nf_setdlt)) < 0) {
 2845:       Perror("[%s] can't configure data link type on %s", b->name, path);
 2846:       goto fail;
 2847:     }
 2848: #ifdef NG_NETFLOW_CONF_INGRESS
 2849:     nf_setconf.iface = nif;
 2850:     nf_setconf.conf = 
 2851: 	(in?NG_NETFLOW_CONF_INGRESS:0) |
 2852: 	(out?NG_NETFLOW_CONF_EGRESS:0) |
 2853: 	(Enabled(&b->iface.options, IFACE_CONF_NETFLOW_ONCE)?NG_NETFLOW_CONF_ONCE:0);
 2854:     if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETCONFIG,
 2855: 	&nf_setconf, sizeof(nf_setconf)) < 0) {
 2856:       Perror("[%s] can't set config on %s", b->name, path);
 2857:       goto fail;
 2858:     }
 2859: #endif
 2860: #ifndef NG_NETFLOW_CONF_INGRESS
 2861:     if (!out) {
 2862: #endif
 2863: 	nf_setidx.iface = nif;
 2864: 	nf_setidx.index = if_nametoindex(b->iface.ifname);
 2865: 	if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETIFINDEX,
 2866: 	    &nf_setidx, sizeof(nf_setidx)) < 0) {
 2867:     	  Perror("[%s] can't configure interface index on %s", b->name, path);
 2868:     	  goto fail;
 2869: 	}
 2870: #ifndef NG_NETFLOW_CONF_INGRESS
 2871:     }
 2872: #endif
 2873: 
 2874:     return 0;
 2875: fail:
 2876:     return -1;
 2877: }
 2878: 
 2879: static void
 2880: IfaceShutdownNetflow(Bund b, char in, char out, int v6)
 2881: {
 2882:     char	path[NG_PATHSIZ];
 2883:     char	hook[NG_HOOKSIZ];
 2884:     int nif;
 2885: 
 2886: #ifdef NG_NETFLOW_CONF_INGRESS
 2887:     nif = gNetflowIface + b->id*2;
 2888: #else
 2889:     nif = gNetflowIface + b->id*4 + out*2;
 2890: #endif
 2891:     nif += v6 ? 1 : 0;
 2892: 
 2893:     snprintf(path, NG_PATHSIZ, "[%x]:", gNetflowNodeID);
 2894:     snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_DATA, nif);
 2895:     NgFuncDisconnect(gLinksCsock, b->name, path, hook);
 2896:     snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_OUT, nif);
 2897:     NgFuncDisconnect(gLinksCsock, b->name, path, hook);
 2898: }
 2899: #endif
 2900: 
 2901: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
 2902: static int
 2903: IfaceInitMSS(Bund b, char *path, char *hook)
 2904: {
 2905: 	struct ngm_mkpeer	mp;
 2906: 	struct ngm_name		nm;
 2907: #ifndef USE_NG_TCPMSS
 2908: 	struct ngm_connect	cn;
 2909: #endif
 2910: 
 2911: 	Log(LG_IFACE2, ("[%s] IFACE: Connecting tcpmssfix", b->name));
 2912:   
 2913: #ifdef USE_NG_TCPMSS
 2914: 	/* Create ng_tcpmss(4) node. */
 2915: 	strcpy(mp.type, NG_TCPMSS_NODE_TYPE);
 2916: 	strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
 2917: 	strcpy(mp.peerhook, "in");
 2918: 	if (NgSendMsg(gLinksCsock, path,
 2919:     		NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 2920:     	    Perror("can't create %s node at \"%s\"->\"%s\"",
 2921:     		NG_TCPMSS_NODE_TYPE, path, mp.ourhook);
 2922: 	    goto fail;
 2923: 	}
 2924: 
 2925: 	strlcat(path, ".", NG_PATHSIZ);
 2926: 	strlcat(path, hook, NG_PATHSIZ);
 2927: 	snprintf(hook, NG_HOOKSIZ, "out");
 2928: 
 2929: 	/* Set the new node's name. */
 2930: 	snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-mss", gPid, b->name);
 2931: 	if (NgSendMsg(gLinksCsock, path,
 2932:     		NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 2933:     	    Perror("can't name %s node", NG_TCPMSS_NODE_TYPE);
 2934: 	    goto fail;
 2935: 	}
 2936: 
 2937: #else
 2938:     /* Create a bpf node for SYN detection. */
 2939:     strcpy(mp.type, NG_BPF_NODE_TYPE);
 2940:     strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
 2941:     strcpy(mp.peerhook, "ppp");
 2942:     if (NgSendMsg(gLinksCsock, path,
 2943: 	    NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 2944: 	Perror("can't create %s node at \"%s\"->\"%s\"",
 2945: 	    NG_BPF_NODE_TYPE, path, mp.ourhook);
 2946: 	goto fail;
 2947:     }
 2948: 
 2949:     strlcat(path, ".", NG_PATHSIZ);
 2950:     strlcat(path, hook, NG_PATHSIZ);
 2951:     strcpy(hook, "iface");
 2952: 
 2953:     /* Set the new node's name. */
 2954:     snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-mss", gPid, b->name);
 2955:     if (NgSendMsg(gLinksCsock, path,
 2956: 	    NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 2957: 	Perror("can't name tcpmssfix %s node", NG_BPF_NODE_TYPE);
 2958: 	goto fail;
 2959:     }
 2960: 
 2961:     /* Connect to the bundle socket node. */
 2962:     strlcpy(cn.path, path, sizeof(cn.path));
 2963:     snprintf(cn.ourhook, sizeof(cn.ourhook), "i%d", b->id);
 2964:     strcpy(cn.peerhook, MPD_HOOK_TCPMSS_IN);
 2965:     if (NgSendMsg(gLinksCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
 2966:     	    sizeof(cn)) < 0) {
 2967:     	Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 2968:     	    b->name, path, cn.ourhook, cn.path, cn.peerhook);
 2969:     	goto fail;
 2970:     }
 2971: 
 2972:     strlcpy(cn.path, path, sizeof(cn.path));
 2973:     snprintf(cn.ourhook, sizeof(cn.ourhook), "o%d", b->id);
 2974:     strcpy(cn.peerhook, MPD_HOOK_TCPMSS_OUT);
 2975:     if (NgSendMsg(gLinksCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
 2976:     	    sizeof(cn)) < 0) {
 2977:     	Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 2978:     	    b->name, path, cn.ourhook, cn.path, cn.peerhook);
 2979:     	goto fail;
 2980:     }
 2981: #endif /* USE_NG_TCPMSS */
 2982: 
 2983:     return (0);
 2984: fail:
 2985:     return (-1);
 2986: }
 2987: 
 2988: /*
 2989:  * BundConfigMSS()
 2990:  *
 2991:  * Configure the tcpmss node to reduce MSS to given value.
 2992:  */
 2993: 
 2994: static void
 2995: IfaceSetupMSS(Bund b, uint16_t maxMSS)
 2996: {
 2997: #ifdef USE_NG_TCPMSS
 2998:   struct	ng_tcpmss_config tcpmsscfg;
 2999:   char		path[NG_PATHSIZ];
 3000: 
 3001:   snprintf(path, sizeof(path), "mpd%d-%s-mss:", gPid, b->name);
 3002: 
 3003:   /* Send configure message. */
 3004:   memset(&tcpmsscfg, 0, sizeof(tcpmsscfg));
 3005:   tcpmsscfg.maxMSS = maxMSS;
 3006: 
 3007:   snprintf(tcpmsscfg.inHook, sizeof(tcpmsscfg.inHook), "in");
 3008:   snprintf(tcpmsscfg.outHook, sizeof(tcpmsscfg.outHook), "out");
 3009:   if (NgSendMsg(gLinksCsock, path, NGM_TCPMSS_COOKIE, NGM_TCPMSS_CONFIG,
 3010:       &tcpmsscfg, sizeof(tcpmsscfg)) < 0) {
 3011:     Perror("[%s] can't configure %s node program", b->name, NG_TCPMSS_NODE_TYPE);
 3012:   }
 3013:   snprintf(tcpmsscfg.inHook, sizeof(tcpmsscfg.inHook), "out");
 3014:   snprintf(tcpmsscfg.outHook, sizeof(tcpmsscfg.outHook), "in");
 3015:   if (NgSendMsg(gLinksCsock, path, NGM_TCPMSS_COOKIE, NGM_TCPMSS_CONFIG,
 3016:       &tcpmsscfg, sizeof(tcpmsscfg)) < 0) {
 3017:     Perror("[%s] can't configure %s node program", b->name, NG_TCPMSS_NODE_TYPE);
 3018:   }
 3019: #else
 3020:     union {
 3021: 	u_char			buf[NG_BPF_HOOKPROG_SIZE(TCPSYN_PROG_LEN)];
 3022: 	struct ng_bpf_hookprog	hprog;
 3023:     }				u;
 3024:     struct ng_bpf_hookprog	*const hp = &u.hprog;
 3025:     char			hook[NG_HOOKSIZ];
 3026: 
 3027:     /* Setup programs for ng_bpf hooks */
 3028:     snprintf(hook, sizeof(hook), "i%d", b->id);
 3029: 
 3030:     memset(&u, 0, sizeof(u));
 3031:     strcpy(hp->thisHook, "ppp");
 3032:     hp->bpf_prog_len = TCPSYN_PROG_LEN;
 3033:     memcpy(&hp->bpf_prog, &gTCPSYNProg,
 3034:         TCPSYN_PROG_LEN * sizeof(*gTCPSYNProg));
 3035:     strcpy(hp->ifMatch, MPD_HOOK_TCPMSS_IN);
 3036:     strcpy(hp->ifNotMatch, "iface");
 3037: 
 3038:     if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
 3039: 	    NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
 3040: 	Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
 3041: 
 3042:     memset(&u, 0, sizeof(u));
 3043:     strcpy(hp->thisHook, MPD_HOOK_TCPMSS_IN);
 3044:     hp->bpf_prog_len = NOMATCH_PROG_LEN;
 3045:     memcpy(&hp->bpf_prog, &gNoMatchProg,
 3046:         NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
 3047:     strcpy(hp->ifMatch, "ppp");
 3048:     strcpy(hp->ifNotMatch, "ppp");
 3049: 
 3050:     if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
 3051: 	    NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
 3052: 	Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
 3053: 
 3054:     snprintf(hook, sizeof(hook), "o%d", b->id);
 3055:     memset(&u, 0, sizeof(u));
 3056:     strcpy(hp->thisHook, "iface");
 3057:     hp->bpf_prog_len = TCPSYN_PROG_LEN;
 3058:     memcpy(&hp->bpf_prog, &gTCPSYNProg,
 3059:         TCPSYN_PROG_LEN * sizeof(*gTCPSYNProg));
 3060:     strcpy(hp->ifMatch, MPD_HOOK_TCPMSS_OUT);
 3061:     strcpy(hp->ifNotMatch, "ppp");
 3062: 
 3063:     if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
 3064: 	    NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
 3065: 	Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
 3066: 
 3067:     memset(&u, 0, sizeof(u));
 3068:     strcpy(hp->thisHook, MPD_HOOK_TCPMSS_OUT);
 3069:     hp->bpf_prog_len = NOMATCH_PROG_LEN;
 3070:     memcpy(&hp->bpf_prog, &gNoMatchProg,
 3071:         NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
 3072:     strcpy(hp->ifMatch, "iface");
 3073:     strcpy(hp->ifNotMatch, "iface");
 3074: 
 3075:     if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
 3076: 	    NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
 3077: 	Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
 3078: 
 3079: #endif /* USE_NG_TCPMSS */
 3080: }
 3081: 
 3082: static void
 3083: IfaceShutdownMSS(Bund b)
 3084: {
 3085: 	char	path[NG_PATHSIZ];
 3086: 
 3087: #ifdef USE_NG_TCPMSS
 3088: 	snprintf(path, sizeof(path), "mpd%d-%s-mss:", gPid, b->name);
 3089: 	NgFuncShutdownNode(gLinksCsock, b->name, path);
 3090: #else
 3091: 	snprintf(path, sizeof(path), "i%d", b->id);
 3092: 	NgFuncShutdownNode(gLinksCsock, b->name, path);
 3093: #endif
 3094: }
 3095: #endif /* defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF)) */
 3096: 
 3097: #ifdef USE_NG_BPF
 3098: static int
 3099: IfaceInitLimits(Bund b, char *path, char *hook)
 3100: {
 3101:     struct ngm_mkpeer	mp;
 3102:     struct ngm_name	nm;
 3103: 
 3104:     if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
 3105: 
 3106: 	Log(LG_IFACE2, ("[%s] IFACE: Connecting limits", b->name));
 3107:   
 3108: 	/* Create a bpf node for traffic filtering. */
 3109: 	strcpy(mp.type, NG_BPF_NODE_TYPE);
 3110: 	strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
 3111: 	strcpy(mp.peerhook, "ppp");
 3112: 	if (NgSendMsg(gLinksCsock, path,
 3113: 		NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 3114: 	    Perror("can't create %s node at \"%s\"->\"%s\"",
 3115: 		NG_BPF_NODE_TYPE, path, mp.ourhook);
 3116: 	    goto fail;
 3117: 	}
 3118: 
 3119: 	strlcat(path, ".", NG_PATHSIZ);
 3120: 	strlcat(path, hook, NG_PATHSIZ);
 3121: 	strcpy(hook, "iface");
 3122: 
 3123: 	b->iface.limitID = NgGetNodeID(gLinksCsock, path);
 3124: 	if (b->iface.limitID == 0)
 3125: 	    Perror("can't get limits %s node ID", NG_BPF_NODE_TYPE);
 3126: 
 3127: 	/* Set the new node's name. */
 3128: 	snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-lim", gPid, b->name);
 3129: 	if (NgSendMsg(gLinksCsock, path,
 3130: 		NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
 3131: 	    Perror("can't name limits %s node", NG_BPF_NODE_TYPE);
 3132: 	    goto fail;
 3133: 	}
 3134: 
 3135:     }
 3136: 
 3137:     return (0);
 3138: fail:
 3139:     return (-1);
 3140: }
 3141: 
 3142: /*
 3143:  * BundConfigLimits()
 3144:  *
 3145:  * Configure the bpf & car nodes.
 3146:  */
 3147: 
 3148: static void
 3149: IfaceSetupLimits(Bund b)
 3150: {
 3151: #define	ACL_MAX_PROGLEN	65536
 3152:     union {
 3153: 	u_char			buf[NG_BPF_HOOKPROG_SIZE(ACL_MAX_PROGLEN)];
 3154: 	struct ng_bpf_hookprog	hprog;
 3155:     }				*hpu;
 3156:     struct ng_bpf_hookprog	*hp;
 3157:     struct ngm_connect  cn;
 3158:     int			i;
 3159:     
 3160:     hpu = Malloc(MB_ACL, sizeof(*hpu));
 3161:     hp = &hpu->hprog;
 3162: 
 3163:     if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
 3164: 	char		path[NG_PATHSIZ];
 3165: 	int		num, dir;
 3166: 
 3167: 	snprintf(path, sizeof(path), "mpd%d-%s-lim:", gPid, b->name);
 3168: 	
 3169: 	for (dir = 0; dir < 2; dir++) {
 3170: 	    char	inhook[2][NG_HOOKSIZ];
 3171: 	    char	inhookn[2][NG_HOOKSIZ];
 3172: 	    char	outhook[NG_HOOKSIZ];
 3173: 	    struct acl	*l;
 3174: 
 3175: 	    if (dir == 0) {
 3176: 		strcpy(inhook[0], "ppp");
 3177: 		strcpy(outhook, "iface");
 3178: 	    } else {
 3179: 		strcpy(inhook[0], "iface");
 3180: 		strcpy(outhook, "ppp");
 3181: 	    }
 3182: 	    strcpy(inhook[1], "");
 3183: 	    num = 0;
 3184: 	    for (l = b->params.acl_limits[dir]; l; l = l->next) {
 3185: 	        char		str[ACL_LEN];
 3186: #define	ACL_MAX_PARAMS	7	/* one more then max number of arguments */
 3187: 	        int		ac;
 3188: 	        char		*av[ACL_MAX_PARAMS];
 3189: 		int		p;
 3190: 		char		stathook[NG_HOOKSIZ];
 3191: 		struct svcs	*ss = NULL;
 3192: 		struct svcssrc	*sss = NULL;
 3193: 
 3194: 		Log(LG_IFACE2, ("[%s] IFACE: limit %s#%d%s%s: '%s'",
 3195:         	    b->name, (dir?"out":"in"), l->number,
 3196: 		    ((l->name[0])?"#":""), l->name, l->rule));
 3197: 		strlcpy(str, l->rule, sizeof(str));
 3198:     		ac = ParseLine(str, av, ACL_MAX_PARAMS, 0);
 3199: 	        if (ac < 1 || ac >= ACL_MAX_PARAMS) {
 3200: 		    Log(LG_ERR, ("[%s] IFACE: incorrect limit: '%s'",
 3201:     			b->name, l->rule));
 3202: 		    continue;
 3203: 		}
 3204: 		
 3205: 		stathook[0] = 0;
 3206: 	    	memset(hpu, 0, sizeof(*hpu));
 3207: 		/* Prepare filter */
 3208: 		if (strcasecmp(av[0], "all") == 0) {
 3209: 		    hp->bpf_prog_len = MATCH_PROG_LEN;
 3210: 		    memcpy(&hp->bpf_prog, &gMatchProg,
 3211:     		        MATCH_PROG_LEN * sizeof(*gMatchProg));
 3212: 		} else if (strncasecmp(av[0], "flt", 3) == 0) {
 3213: 		    struct acl  *f;
 3214: 		    int		flt;
 3215: 		    
 3216: 		    flt = atoi(av[0] + 3);
 3217: 		    if (flt <= 0 || flt > ACL_FILTERS) {
 3218: 			Log(LG_ERR, ("[%s] IFACE: incorrect filter number: '%s'",
 3219:     			    b->name, av[0]));
 3220: 		    } else if ((f = b->params.acl_filters[flt - 1]) == NULL &&
 3221: 			(f = acl_filters[flt - 1]) == NULL) {
 3222: 			Log(LG_ERR, ("[%s] IFACE: Undefined filter: '%s'",
 3223:     			    b->name, av[0]));
 3224: 		    } else {
 3225: 			struct bpf_program pr;
 3226: 		    	char		*buf;
 3227: 		    	int		bufbraces;
 3228: 
 3229: #define ACL_BUF_SIZE	256*1024
 3230: 			buf = Malloc(MB_ACL, ACL_BUF_SIZE);
 3231: 			buf[0] = 0;
 3232: 			bufbraces = 0;
 3233: 			while (f) {
 3234: 			    char	*b1, *b2, *sbuf;
 3235: 			    sbuf = Mstrdup(MB_ACL, f->rule);
 3236: 			    b2 = sbuf;
 3237: 			    b1 = strsep(&b2, " ");
 3238: 			    if (b2 != NULL) {
 3239: 			        if (strcasecmp(b1, "match") == 0) {
 3240: 			    	    strlcat(buf, "( ", ACL_BUF_SIZE);
 3241: 				    strlcat(buf, b2, ACL_BUF_SIZE);
 3242: 				    strlcat(buf, " ) ", ACL_BUF_SIZE);
 3243: 				    if (f->next) {
 3244: 				        strlcat(buf, "|| ( ", ACL_BUF_SIZE);
 3245: 				        bufbraces++;
 3246: 				    }
 3247: 				} else if (strcasecmp(b1, "nomatch") == 0) {
 3248: 				    strlcat(buf, "( not ( ", ACL_BUF_SIZE);
 3249: 				    strlcat(buf, b2, ACL_BUF_SIZE);
 3250: 				    strlcat(buf, " ) ) ", ACL_BUF_SIZE);
 3251: 				    if (f->next) {
 3252: 				        strlcat(buf, "&& ( ", ACL_BUF_SIZE);
 3253: 				        bufbraces++;
 3254: 				    }
 3255: 				} else {
 3256: 			    	    Log(LG_ERR, ("[%s] IFACE: filter action '%s' is unknown",
 3257:         		    		b->name, b1));
 3258: 				}
 3259: 			    };
 3260: 			    Freee(sbuf);
 3261: 			    f = f->next;
 3262: 			}
 3263: 			for (i = 0; i < bufbraces; i++)
 3264: 			    strlcat(buf, ") ", ACL_BUF_SIZE);
 3265: 			Log(LG_IFACE2, ("[%s] IFACE: flt%d: '%s'",
 3266:         		    b->name, flt, buf));
 3267: 			
 3268: 			if (pcap_compile_nopcap((u_int)-1, DLT_RAW, &pr, buf, 1, 0xffffff00)) {
 3269: 			    Log(LG_ERR, ("[%s] IFACE: filter '%s' compilation error",
 3270:     			        b->name, av[0]));
 3271: 			    /* Incorrect matches nothing. */
 3272: 			    hp->bpf_prog_len = NOMATCH_PROG_LEN;
 3273: 			    memcpy(&hp->bpf_prog, &gNoMatchProg,
 3274:     		    		NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
 3275: 			} else if (pr.bf_len > ACL_MAX_PROGLEN) {
 3276: 			    Log(LG_ERR, ("[%s] IFACE: filter '%s' is too long",
 3277:         		        b->name, av[0]));
 3278: 			    pcap_freecode(&pr);
 3279: 			    /* Incorrect matches nothing. */
 3280: 			    hp->bpf_prog_len = NOMATCH_PROG_LEN;
 3281: 			    memcpy(&hp->bpf_prog, &gNoMatchProg,
 3282:     		    		NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
 3283: 			} else {
 3284: 			    hp->bpf_prog_len = pr.bf_len;
 3285: 			    memcpy(&hp->bpf_prog, pr.bf_insns,
 3286:     			        pr.bf_len * sizeof(struct bpf_insn));
 3287: 			    pcap_freecode(&pr);
 3288: 			}
 3289: 			Freee(buf);
 3290: 		    }
 3291: 		} else {
 3292: 		    Log(LG_ERR, ("[%s] IFACE: incorrect filter: '%s'",
 3293:     		        b->name, av[0]));
 3294: 		    /* Incorrect matches nothing. */
 3295: 		    hp->bpf_prog_len = NOMATCH_PROG_LEN;
 3296: 		    memcpy(&hp->bpf_prog, &gNoMatchProg,
 3297:     		        NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
 3298: 		}
 3299: 		
 3300: 		/* Prepare action */
 3301: 		p = 1;
 3302: 		if (ac == 1) {
 3303: 		    if (!l->next) {
 3304: 			strcpy(hp->ifMatch, outhook);
 3305: 			strcpy(inhookn[0], "");
 3306: 		    } else {
 3307: 			sprintf(hp->ifMatch, "%d-%d-m", dir, num);
 3308: 			sprintf(inhookn[0], "%d-%d-mi", dir, num);
 3309: 
 3310: 			/* Connect nomatch hook to bpf itself. */
 3311: 			strcpy(cn.ourhook, hp->ifMatch);
 3312: 			strcpy(cn.path, path);
 3313: 			strcpy(cn.peerhook, inhookn[0]);
 3314: 			if (NgSendMsg(gLinksCsock, path,
 3315: 		        	NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
 3316: 			    Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 3317: 			        b->name, path, cn.ourhook, cn.path, cn.peerhook);
 3318: 			}
 3319: 			strcpy(stathook, inhookn[0]);
 3320: 		    }
 3321: 		} else if (strcasecmp(av[p], "pass") == 0) {
 3322: 		    strcpy(hp->ifMatch, outhook);
 3323: 		    strcpy(inhookn[0], "");
 3324: 		} else if (strcasecmp(av[p], "deny") == 0) {
 3325: 		    strcpy(hp->ifMatch, "deny");
 3326: 		    strcpy(inhookn[0], "");
 3327: #ifdef USE_NG_CAR
 3328: 		} else if ((strcasecmp(av[p], "shape") == 0) ||
 3329: 			   (strcasecmp(av[p], "rate-limit") == 0)) {
 3330: 		    struct ngm_mkpeer 	mp;
 3331: 		    struct ng_car_bulkconf car;
 3332: 		    char		tmppath[NG_PATHSIZ];
 3333: 
 3334: 		    sprintf(hp->ifMatch, "%d-%d-m", dir, num);
 3335: 
 3336: 		    /* Create a car node for traffic shaping. */
 3337: 		    strcpy(mp.type, NG_CAR_NODE_TYPE);
 3338: 		    snprintf(mp.ourhook, sizeof(mp.ourhook), "%d-%d-m", dir, num);
 3339: 		    strcpy(mp.peerhook, ((dir == 0)?NG_CAR_HOOK_LOWER:NG_CAR_HOOK_UPPER));
 3340: 		    if (NgSendMsg(gLinksCsock, path,
 3341: 			    NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
 3342: 			Perror("[%s] IFACE: can't create %s node at \"%s\"->\"%s\"", 
 3343: 			    b->name, NG_CAR_NODE_TYPE, path, mp.ourhook);
 3344: 		    }
 3345: 
 3346: 		    snprintf(tmppath, sizeof(tmppath), "%s%d-%d-m", path, dir, num);
 3347: 
 3348: 		    /* Connect car to bpf. */
 3349: 		    snprintf(cn.ourhook, sizeof(cn.ourhook), "%d-%d-mi", dir, num);
 3350: 		    strlcpy(cn.path, tmppath, sizeof(cn.path));
 3351: 		    strcpy(cn.peerhook, ((dir == 0)?NG_CAR_HOOK_UPPER:NG_CAR_HOOK_LOWER));
 3352: 		    if (NgSendMsg(gLinksCsock, path,
 3353: 		            NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
 3354: 			Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 3355: 			    b->name, path, cn.ourhook, cn.path, cn.peerhook);
 3356: 		    }
 3357: 			
 3358: 		    bzero(&car, sizeof(car));
 3359: 			
 3360: 		    if (strcasecmp(av[p], "shape") == 0) {
 3361: 		        car.upstream.mode = NG_CAR_SHAPE;
 3362: 		    } else {
 3363: 		        car.upstream.mode = NG_CAR_RED;
 3364: 		    }
 3365: 		    p++;
 3366: 
 3367: 		    if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
 3368: 		        car.upstream.cir = atol(av[p]);
 3369: 		        p++;
 3370: 		        if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
 3371: 		    	    car.upstream.cbs = atol(av[p]);
 3372: 			    p++;
 3373: 			    if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
 3374: 			        car.upstream.ebs = atol(av[p]);
 3375: 			        p++;
 3376: 			    } else {
 3377: 			        car.upstream.ebs = car.upstream.cbs * 2;
 3378: 			    }
 3379: 			} else {
 3380: 			    car.upstream.cbs = car.upstream.cir / 8;
 3381: 			    car.upstream.ebs = car.upstream.cbs * 2;
 3382: 			}
 3383: 		    } else {
 3384: 		        car.upstream.cir = 8000;
 3385: 		        car.upstream.cbs = car.upstream.cir / 8;
 3386: 		        car.upstream.ebs = car.upstream.cbs * 2;
 3387: 		    }
 3388: 		    car.upstream.green_action = NG_CAR_ACTION_FORWARD;
 3389: 		    car.upstream.yellow_action = NG_CAR_ACTION_FORWARD;
 3390: 		    car.upstream.red_action = NG_CAR_ACTION_DROP;
 3391: 			
 3392: 		    car.downstream = car.upstream;
 3393: 						
 3394: 		    if (NgSendMsg(gLinksCsock, tmppath,
 3395: 		            NGM_CAR_COOKIE, NGM_CAR_SET_CONF, &car, sizeof(car)) < 0) {
 3396: 		        Perror("[%s] IFACE: can't set %s configuration",
 3397: 			    b->name, NG_CAR_NODE_TYPE);
 3398: 		    }
 3399: 			
 3400: 		    if (ac > p) {
 3401: 			if (strcasecmp(av[p], "pass") == 0) {
 3402: 			    union {
 3403: 		    		u_char	buf[NG_BPF_HOOKPROG_SIZE(MATCH_PROG_LEN)];
 3404: 		    		struct ng_bpf_hookprog	hprog;
 3405: 			    } hpu1;
 3406: 			    struct ng_bpf_hookprog	*const hp1 = &hpu1.hprog;
 3407: 
 3408: 			    memset(&hpu1, 0, sizeof(hpu1));
 3409: 			    strcpy(hp1->ifMatch, outhook);
 3410: 			    strcpy(hp1->ifNotMatch, outhook);
 3411: 			    hp1->bpf_prog_len = MATCH_PROG_LEN;
 3412: 			    memcpy(&hp1->bpf_prog, &gMatchProg,
 3413:     			        MATCH_PROG_LEN * sizeof(*gMatchProg));
 3414: 		    	    sprintf(hp1->thisHook, "%d-%d-mi", dir, num);
 3415: 			    if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
 3416: 			    	    hp1, NG_BPF_HOOKPROG_SIZE(hp1->bpf_prog_len)) < 0) {
 3417: 				Perror("[%s] IFACE: can't set %s node program",
 3418: 	    			    b->name, NG_BPF_NODE_TYPE);
 3419: 			    }
 3420: 			    			    
 3421: 			    strcpy(stathook, hp1->thisHook);
 3422: 			    strcpy(inhookn[0], "");
 3423: 			} else {
 3424: 			    Log(LG_ERR, ("[%s] IFACE: unknown action: '%s'",
 3425:     			        b->name, av[p]));
 3426: 			    strcpy(inhookn[0], "");
 3427: 			}
 3428: 		    } else {
 3429: 			sprintf(inhookn[0], "%d-%d-mi", dir, num);
 3430: 			strcpy(stathook, inhookn[0]);
 3431: 		    }
 3432: #endif /* USE_NG_CAR */
 3433: 	        } else {
 3434: 		    Log(LG_ERR, ("[%s] IFACE: unknown action: '%s'",
 3435:     		        b->name, av[1]));
 3436: 		    strcpy(inhookn[0], "");
 3437: 		}
 3438: 		
 3439: 		/* Prepare nomatch */
 3440: 		if (l->next && strcasecmp(av[0], "all")) {
 3441: 		    /* If there is next limit and there is possible nomatch,
 3442: 		     * then pass nomatch there. */
 3443: 		    sprintf(hp->ifNotMatch, "%d-%d-n", dir, num);
 3444: 		    sprintf(inhookn[1], "%d-%d-ni", dir, num);
 3445: 
 3446: 		    /* Connect nomatch hook to bpf itself. */
 3447: 		    strcpy(cn.ourhook, hp->ifNotMatch);
 3448: 		    strcpy(cn.path, path);
 3449: 		    strcpy(cn.peerhook, inhookn[1]);
 3450: 		    if (NgSendMsg(gLinksCsock, path,
 3451: 		            NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
 3452: 			Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
 3453: 			    b->name, path, cn.ourhook, cn.path, cn.peerhook);
 3454: 		    }
 3455: 		} else {
 3456: 		    /* There is no next limit, pass nomatch. */
 3457: 		    strcpy(hp->ifNotMatch, outhook);
 3458: 		    strcpy(inhookn[1], "");
 3459: 		}
 3460: 		
 3461: 		/* Remember how to collect stats for this limit */
 3462: 		if (l->name[0]) {
 3463: 		    SLIST_FOREACH(ss, &b->iface.ss[dir], next) {
 3464: 			if (strcmp(ss->name, l->name) == 0)
 3465: 			    break;
 3466: 		    }
 3467: 		    if (ss == NULL) {
 3468: 			ss = Malloc(MB_ACL, sizeof(*ss));
 3469: 			strlcpy(ss->name, l->name, sizeof(ss->name));
 3470: 			SLIST_INIT(&ss->src);
 3471: 			SLIST_INSERT_HEAD(&b->iface.ss[dir], ss, next);
 3472: 		    }
 3473: 		    if (stathook[0]) {
 3474: 			sss = Malloc(MB_ACL, sizeof(*sss));
 3475: 			strlcpy(sss->hook, stathook, sizeof(sss->hook));
 3476: 			sss->type = SSSS_IN;
 3477: 			SLIST_INSERT_HEAD(&ss->src, sss, next);
 3478: 		    }
 3479: 		}
 3480: 		
 3481: 		for (i = 0; i < 2; i++) {
 3482: 		    if (inhook[i][0] != 0) {
 3483: 			if (l->name[0] && !stathook[0]) {
 3484: 			    sss = Malloc(MB_ACL, sizeof(*sss));
 3485: 			    strlcpy(sss->hook, inhook[i], sizeof(sss->hook));
 3486: 			    sss->type = SSSS_MATCH;
 3487: 			    SLIST_INSERT_HEAD(&ss->src, sss, next);
 3488: 			}
 3489: 		
 3490: 		        strcpy(hp->thisHook, inhook[i]);
 3491: 		        if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
 3492: 		    		hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
 3493: 			    Perror("[%s] IFACE: can't set %s node program",
 3494: 	    		        b->name, NG_BPF_NODE_TYPE);
 3495: 			}
 3496: 		    }
 3497: 		    strcpy(inhook[i], inhookn[i]);
 3498: 		}
 3499: 
 3500: 		num++;
 3501: 	    }
 3502: 	
 3503: 	    /* Connect left hooks to output */
 3504: 	    for (i = 0; i < 2; i++) {
 3505: 		if (inhook[i][0] != 0) {
 3506: 		    memset(hpu, 0, sizeof(*hpu));
 3507: 		    strcpy(hp->thisHook, inhook[i]);
 3508: 		    hp->bpf_prog_len = MATCH_PROG_LEN;
 3509: 		    memcpy(&hp->bpf_prog, &gMatchProg,
 3510:     			MATCH_PROG_LEN * sizeof(*gMatchProg));
 3511: 		    strcpy(hp->ifMatch, outhook);
 3512: 		    strcpy(hp->ifNotMatch, outhook);
 3513: 		    if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM, 
 3514: 			    hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
 3515: 			Perror("[%s] IFACE: can't set %s node %s %s program (2)",
 3516: 			    b->name, NG_BPF_NODE_TYPE, path, hp->thisHook);
 3517: 		    }
 3518: 		}
 3519: 	    }
 3520: 	}
 3521:     }
 3522:     Freee(hpu);
 3523: }
 3524: 
 3525: static void
 3526: IfaceShutdownLimits(Bund b)
 3527: {
 3528:     char path[NG_PATHSIZ];
 3529:     struct svcs *ss;
 3530:     struct svcssrc *sss;
 3531:     struct svcstat curstats;
 3532:     int		i;
 3533: 
 3534:     if (b->n_up > 0) {
 3535: 	bzero(&curstats, sizeof(curstats));
 3536:     	IfaceGetStats(b, &curstats);
 3537:     	IfaceAddStats(&b->iface.prevstats, &curstats);
 3538: 	IfaceFreeStats(&curstats);
 3539:     }
 3540: 
 3541:     if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
 3542: 	snprintf(path, sizeof(path), "[%x]:", b->iface.limitID);
 3543: 	NgFuncShutdownNode(gLinksCsock, b->name, path);
 3544:     }
 3545: 
 3546:     for (i = 0; i < ACL_DIRS; i++) {
 3547: 	while ((ss = SLIST_FIRST(&b->iface.ss[i])) != NULL) {
 3548: 	    while ((sss = SLIST_FIRST(&ss->src)) != NULL) {
 3549:     		SLIST_REMOVE_HEAD(&ss->src, next);
 3550: 		Freee(sss);
 3551: 	    }
 3552: 	    SLIST_REMOVE_HEAD(&b->iface.ss[i], next);
 3553: 	    Freee(ss);
 3554: 	}
 3555:     }
 3556: }
 3557: 
 3558: void
 3559: IfaceGetStats(Bund b, struct svcstat *stat)
 3560: {
 3561:     char path[NG_PATHSIZ];
 3562:     struct svcs 	*ss;
 3563:     struct svcssrc	*sss;
 3564:     int	dir;
 3565: 
 3566:     union {
 3567:         u_char          buf[sizeof(struct ng_mesg) + sizeof(struct ng_bpf_hookstat)];
 3568: 	struct ng_mesg  reply;
 3569:     }                   u;
 3570:     struct ng_bpf_hookstat     *const hs = (struct ng_bpf_hookstat *)(void *)u.reply.data;
 3571: 
 3572:     snprintf(path, sizeof(path), "[%x]:", b->iface.limitID);
 3573:     for (dir = 0; dir < ACL_DIRS; dir++) {
 3574: 	SLIST_FOREACH(ss, &b->iface.ss[dir], next) {
 3575: 	    struct svcstatrec *ssr;
 3576: 	
 3577: 	    SLIST_FOREACH(ssr, &stat->stat[dir], next) {
 3578: 		if (strcmp(ssr->name, ss->name) == 0)
 3579: 		    break;
 3580: 	    }
 3581: 	    if (!ssr) {
 3582: 		ssr = Malloc(MB_ACL, sizeof(*ssr));
 3583: 		strlcpy(ssr->name, ss->name, sizeof(ssr->name));
 3584: 		SLIST_INSERT_HEAD(&stat->stat[dir], ssr, next);
 3585: 	    }
 3586:     
 3587: 	    SLIST_FOREACH(sss, &ss->src, next) {
 3588: 		if (NgSendMsg(gLinksCsock, path,
 3589:     		    NGM_BPF_COOKIE, NGM_BPF_GET_STATS, sss->hook, strlen(sss->hook)+1) < 0)
 3590:     		    continue;
 3591: 		if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0)
 3592:     		    continue;
 3593: 		
 3594: 		switch(sss->type) {
 3595: 		case SSSS_IN:
 3596: 		    ssr->Packets += hs->recvFrames;
 3597: 		    ssr->Octets += hs->recvOctets;
 3598: 		    break;
 3599: 		case SSSS_MATCH:
 3600: 		    ssr->Packets += hs->recvMatchFrames;
 3601: 		    ssr->Octets += hs->recvMatchOctets;
 3602: 		    break;
 3603: 		case SSSS_NOMATCH:
 3604: 		    ssr->Packets += hs->recvFrames - hs->recvMatchFrames;
 3605: 		    ssr->Octets += hs->recvOctets - hs->recvMatchOctets;
 3606: 		    break;
 3607: 		case SSSS_OUT:
 3608: 		    ssr->Packets += hs->xmitFrames;
 3609: 		    ssr->Octets += hs->xmitOctets;
 3610: 		    break;
 3611: 		}
 3612: 	    }
 3613: 	}
 3614:     }
 3615: }
 3616: 
 3617: void
 3618: IfaceAddStats(struct svcstat *stat1, struct svcstat *stat2)
 3619: {
 3620:     struct svcstatrec   *ssr1, *ssr2;
 3621:     int                 dir;
 3622: 
 3623:     for (dir = 0; dir < ACL_DIRS; dir++) {
 3624: 	SLIST_FOREACH(ssr2, &stat2->stat[dir], next) {
 3625: 	    SLIST_FOREACH(ssr1, &stat1->stat[dir], next)
 3626: 		if (strcmp(ssr1->name, ssr2->name) == 0) {
 3627: 		    break;
 3628: 	    }
 3629: 	    if (!ssr1) {
 3630: 		ssr1 = Malloc(MB_ACL, sizeof(*ssr1));
 3631: 		strlcpy(ssr1->name, ssr2->name, sizeof(ssr1->name));
 3632: 		SLIST_INSERT_HEAD(&stat1->stat[dir], ssr1, next);
 3633: 	    }
 3634: 	    ssr1->Packets += ssr2->Packets;
 3635: 	    ssr1->Octets += ssr2->Octets;
 3636: 	}
 3637:     }
 3638: }
 3639: 
 3640: void
 3641: IfaceFreeStats(struct svcstat *stat)
 3642: {
 3643:     struct svcstatrec   *ssr;
 3644:     int                 i;
 3645: 
 3646:     for (i = 0; i < ACL_DIRS; i++) {
 3647: 	while ((ssr = SLIST_FIRST(&stat->stat[i])) != NULL) {
 3648:     	    SLIST_REMOVE_HEAD(&stat->stat[i], next);
 3649: 	    Freee(ssr);
 3650: 	}
 3651:     }
 3652: }
 3653: #endif /* USE_NG_BPF */
 3654: 
 3655: /*
 3656:  * IfaceSetName()
 3657:  */
 3658: 
 3659: int
 3660: IfaceSetName(Bund b, const char * ifname)
 3661: {
 3662:     IfaceState	const iface = &b->iface;
 3663:     struct ifreq ifr;
 3664:     int s;
 3665: 
 3666:     /* Do not rename interface on template */
 3667:     if (b->tmpl)
 3668: 	return(0);
 3669: 
 3670:     /* Do not wait ioctl error "file already exist" */
 3671:     if (strncmp(iface->ifname, ifname, sizeof(iface->ifname)) == 0)
 3672: 	return(0);
 3673: 
 3674:     /* Get socket */
 3675:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 3676: 	Perror("[%s] IFACE: Can't get socket to set name", b->name);
 3677: 	return(-1);
 3678:     }
 3679: 
 3680:     /* Set name of interface */
 3681:     memset(&ifr, 0, sizeof(ifr));
 3682:     strlcpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
 3683:     ifr.ifr_data = (caddr_t)ifname;
 3684:     Log(LG_IFACE2, ("[%s] IFACE: setting \"%s\" name to \"%s\"",
 3685: 	b->name, iface->ifname, ifname));
 3686: 
 3687:     if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
 3688: 	if (errno != EEXIST) {
 3689: 	    Perror("[%s] IFACE: ioctl(%s, SIOCSIFNAME)", b->name, iface->ifname);
 3690: 	    close(s);
 3691: 	    return(-1);
 3692: 	}
 3693:     }
 3694: 
 3695:     close(s);
 3696:     /* Save name */
 3697:     strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
 3698:     return(0);
 3699: }
 3700: 
 3701: #ifdef SIOCSIFDESCR
 3702: /*
 3703:  * IfaceSetDescr()
 3704:  *
 3705:  * Set/clear our own interface description accessible in console/web interface
 3706:  * and kernel level interface description if it is available.
 3707:  *
 3708:  * Template may contain conversion specifications:
 3709:  *
 3710:  * %% expands to single % sign;
 3711:  * %a for interface local address;
 3712:  * %A for peer address;
 3713:  * %i for system interface index;
 3714:  * %I for interface name;
 3715:  * %l for name of bundle's first link
 3716:  * %M for peer MAC address of bundle's first link
 3717:  * %o for local outer ("physical") address of bundle's first link
 3718:  * %O for peer outer ("physical") address of bundle's first link
 3719:  * %P for peer outer ("physical") port of bundle's first link
 3720:  * %S for interface status (DoD/UP/DOWN)
 3721:  * %t for type of bundle's first link (pppoe, pptp, l2tp etc.)
 3722:  * %u for self auth name (or dash if self auth name not used)
 3723:  * %U for peer auth name (or dash if peer has not authenticated)
 3724:  */
 3725: int
 3726: IfaceSetDescr(Bund b, const char * template)
 3727: {
 3728:     IfaceState	const iface = &b->iface;
 3729:     struct	ifreq ifr;
 3730:     int		s;
 3731:     unsigned	int ifdescr_maxlen = 1024;	/* used as limit for old kernels */
 3732:     char	*newdescr;
 3733:     size_t	sz = sizeof(ifdescr_maxlen);
 3734:     char	*limit, *ifname;
 3735:     const char	*src;
 3736:     int		proceed;
 3737:     char	buf[64];
 3738: 
 3739:     static	int mib[2] = { -1, 0 };	/* MIB for net.ifdescr_maxlen */
 3740:     size_t	miblen = sizeof(mib) / sizeof(mib[0]);
 3741: 
 3742:     /*
 3743:      * Check whether running kernel supports interface description.
 3744:      * Perform the check only once.
 3745:      */
 3746:     if (mib[0] < 0 && sysctlnametomib("net.ifdescr_maxlen", mib, &miblen) < 0) {
 3747:       mib[0] = 0;
 3748:       Perror("[%s] IFACE: sysctl net.ifdescr_maxlen  failed", b->name);
 3749:     }
 3750: 
 3751:     /*
 3752:      * Fetch net.ifdescr_maxlen value every time to catch up with changes
 3753:      */
 3754:     if (mib[0] && sysctl(mib, 2, &ifdescr_maxlen, &sz, NULL, 0) < 0) {
 3755:       /* unexpected error from the kernel, use default value */
 3756:       Perror("[%s] IFACE: sysctl net.ifdescr_maxlen  failed", b->name);
 3757:       ifdescr_maxlen = 1024;
 3758:     }
 3759: 
 3760:     newdescr = NULL;
 3761:     ifname = iface->ifname;
 3762:     if (iface->ifdescr != NULL) {
 3763: 	Freee(iface->ifdescr);
 3764: 	iface->ifdescr = NULL;
 3765:     }
 3766:     if ((src = template) != NULL) {
 3767: 
 3768:       /* Will use Mstrdup() later for iface->ifdescr to free extra memory */
 3769:       if ((iface->ifdescr = newdescr = Malloc(MB_IFACE, ifdescr_maxlen)) == NULL) {
 3770: 	Log(LG_IFACE2, ("[%s] IFACE: no memory for interface %s description",
 3771:     	    b->name, ifname ? ifname : ""));
 3772:         return(-1);
 3773:       }
 3774: 
 3775:       /* ifdescr_maxlen includes terminating zero */
 3776:       limit = newdescr + ifdescr_maxlen - 1;
 3777: 
 3778:       /*
 3779:        * Perform template expansion
 3780:        */
 3781:       proceed = 1;
 3782:       while (proceed && *src && newdescr < limit) {
 3783: 	if (*src != '%') {	/* ordinary symbol, just copy it and proceed */
 3784: 	  *newdescr++ = *src++;
 3785: 	  continue;
 3786: 	}
 3787: 	if (!*(src+1)) {	/* '%' at the end of template, just copy */
 3788: 	  *newdescr++ = *src++;
 3789: 	  continue;
 3790: 	}
 3791: 	switch(*++src) {	/* expand */
 3792: 	  case '%':		/* %% got replaced with single % */
 3793: 	    *newdescr++ = *src;
 3794: 	    break;
 3795: 
 3796: #define DST_COPY(a)				\
 3797:   do { const char *temp = a;			\
 3798:     if (temp && *temp) {			\
 3799:       if ((newdescr + strlen (temp)) <= limit) {\
 3800: 	newdescr = stpcpy (newdescr, temp);	\
 3801:       } else {					\
 3802: 	proceed = 0;				\
 3803:       }						\
 3804:     } else {					\
 3805:       *newdescr++ = '-';			\
 3806:     }						\
 3807:   } while(0)
 3808: 
 3809: 	  /* self address */
 3810: 	  case 'a':
 3811: 	    {
 3812: 	      char *sep;
 3813: 	      u_rangetoa(&iface->self_addr, buf, sizeof(buf));
 3814: 	      /* cut netmask */
 3815: 	      if ((sep = strchr(buf, '/')))
 3816: 	        *sep = '\0';
 3817: 	      DST_COPY(buf);
 3818: 	    }
 3819: 	    break;
 3820: 	  /* peer address */
 3821: 	  case 'A':
 3822: 	    {
 3823: 	      u_addrtoa(&iface->peer_addr, buf, sizeof(buf));
 3824: 	      DST_COPY(buf);
 3825: 	    }
 3826: 	    break;
 3827: 	  /* interface index */
 3828: 	  case 'i':
 3829: 	    {
 3830: 	      snprintf(buf, sizeof(buf), "%u", iface->ifindex);
 3831: 	      DST_COPY(buf);
 3832: 	    }
 3833: 	    break;
 3834: 	  /* interface name */
 3835: 	  case 'I':
 3836: 	    DST_COPY(iface->ifname);
 3837: 	    break;
 3838: 	  /* first link name */
 3839: 	  case 'l':
 3840: 	    DST_COPY(b->links[0] ? b->links[0]->name : NULL);
 3841: 	    break;
 3842: 	  /* peer MAC address */
 3843: 	  case 'M':
 3844: 	    if (b->links[0]) {
 3845: 	      PhysType const pt = b->links[0]->type;
 3846: 	      if (pt && pt->peermacaddr) {
 3847: 		(*pt->peermacaddr)(b->links[0], buf, sizeof(buf));
 3848: 		DST_COPY(buf);
 3849: 	      } else {
 3850: 		  DST_COPY("-");
 3851: 	      }
 3852: 	    } else {
 3853: 		DST_COPY("-");
 3854: 	    }
 3855: 	    break;
 3856: 	  /* local "physycal" address */
 3857: 	  case 'o':
 3858: 	    if (b->links[0] && PhysGetSelfAddr(b->links[0], buf, sizeof(buf)) == 0) {
 3859: 		DST_COPY(buf);
 3860: 	    } else {
 3861: 		DST_COPY("-");
 3862: 	    }
 3863: 	    break;
 3864: 	  /* peer "physycal" address */
 3865: 	  case 'O':
 3866: 	    if (b->links[0] && PhysGetPeerAddr(b->links[0], buf, sizeof(buf)) == 0) {
 3867: 		DST_COPY(buf);
 3868: 	    } else {
 3869: 		DST_COPY("-");
 3870: 	    }
 3871: 	    break;
 3872: 	  /* peer port */
 3873: 	  case 'P':
 3874: 	    if (b->links[0] && PhysGetPeerPort(b->links[0], buf, sizeof(buf)) == 0) {
 3875: 		DST_COPY(buf);
 3876: 	    } else {
 3877: 		DST_COPY("-");
 3878: 	    }
 3879: 	    break;
 3880: 	  /* interface status */
 3881: 	  case 'S':
 3882: 	    DST_COPY(iface->up ? (iface->dod ? "DoD" : "UP") : "DOWN");
 3883: 	    break;
 3884: 	  /* first link type */
 3885: 	  case 't':
 3886: 	    DST_COPY(b->links[0] ? b->links[0]->type->name : NULL);
 3887: 	    break;
 3888: 	  /* self auth name */
 3889: 	  case 'u':
 3890: 	    DST_COPY(b->links[0] ? b->links[0]->lcp.auth.conf.authname : NULL);
 3891: 	    break;
 3892: 	  /* peer auth name */
 3893: 	  case 'U':
 3894: 	    DST_COPY(b->params.authname);
 3895: 	    break;
 3896: #undef DST_COPY
 3897: 	  default: /* unrecognized specification, just copy */
 3898: 	    *newdescr++ = '%';
 3899: 	    if (newdescr < limit)
 3900: 		*newdescr++ = *src;
 3901: 	} /* switch(*++src) */
 3902: 	++src;
 3903:       } /* while */
 3904:       *newdescr = '\0';
 3905: 
 3906:       /* includes terminating zero */
 3907:       sz = newdescr - iface->ifdescr + 1;
 3908:       if ((newdescr = Mstrdup(MB_IFACE, iface->ifdescr)) == NULL) {
 3909:         Log(LG_IFACE2, ("[%s] IFACE: no memory for interface %s description",
 3910: 			b->name, ifname ? ifname : ""));
 3911:         Freee(iface->ifdescr);
 3912: 	iface->ifdescr = NULL;
 3913:         return(-1);
 3914:       }
 3915:       Freee(iface->ifdescr);
 3916:       iface->ifdescr = newdescr;
 3917:     } /* template != NULL */
 3918: 
 3919:     /* Set description of interface */
 3920:     if (mib[0] == 0)
 3921: 	return(0);		/* do not bother kernel if it is too old */
 3922: 
 3923:     if (ifname == NULL || *ifname == '\0')
 3924: 	return(0);		/* we have not set system interface name yet */
 3925: 
 3926:     /* Get socket */
 3927:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 3928: 	Perror("[%s] IFACE: Can't get socket to set description for %s",
 3929: 	        b->name, ifname);
 3930: 	return(-1);
 3931:     }
 3932: 
 3933:     memset(&ifr, 0, sizeof(ifr));
 3934:     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
 3935: 
 3936:     if (!newdescr || !*newdescr) {	/* empty description or clearing request */
 3937: 	ifr.ifr_buffer.buffer = NULL;
 3938: 	ifr.ifr_buffer.length = 0;
 3939: 	Log(LG_IFACE2, ("[%s] IFACE: clearing \"%s\" description",
 3940: 	    b->name, ifname));
 3941:     } else {
 3942: 	ifr.ifr_buffer.length = (unsigned)sz;
 3943: 	ifr.ifr_buffer.buffer = newdescr;
 3944: 	Log(LG_IFACE2, ("[%s] IFACE: setting \"%s\" description to \"%s\"",
 3945: 	    b->name, ifname, newdescr));
 3946:     }
 3947: 
 3948:     if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) {
 3949: 	Perror("[%s] IFACE: ioctl(%s, SIOCSIFDESCR, \"%s\")",
 3950: 	        b->name, ifname, newdescr ? newdescr : "" );
 3951: 	close(s);
 3952: 	return(-1);
 3953:     }
 3954:     close(s);
 3955:     return(0);
 3956: }
 3957: #endif /* SIOCSIFDESCR */
 3958: #ifdef SIOCAIFGROUP
 3959: /*
 3960:  * IfaceAddGroup()
 3961:  */
 3962: 
 3963: int
 3964: IfaceAddGroup(Bund b, const char * ifgroup)
 3965: {
 3966:     IfaceState	const iface = &b->iface;
 3967:     struct ifgroupreq	ifgr;
 3968:     int	s, i;
 3969: 
 3970:     /* Do not add group on template */
 3971:     if (b->tmpl)
 3972: 	return(0);
 3973: 
 3974:     if (ifgroup[0] && isdigit(ifgroup[strlen(ifgroup) - 1])) {
 3975: 	Perror("[%s] IFACE: groupnames may not end in a digit", b->name);
 3976: 	return(-1);
 3977:     }
 3978: 
 3979:     /* Get socket */
 3980:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 3981: 	Perror("[%s] IFACE: Can't get socket to add group", b->name);
 3982: 	return(-1);
 3983:     }
 3984: 
 3985:     /* Add interface group */
 3986:     memset(&ifgr, 0, sizeof(ifgr));
 3987:     strlcpy(ifgr.ifgr_name, iface->ifname, sizeof(ifgr.ifgr_name));
 3988:     strlcpy(ifgr.ifgr_group, ifgroup, sizeof(ifgr.ifgr_group));
 3989: 
 3990:     Log(LG_IFACE2, ("[%s] IFACE: adding interface %s to group %s",
 3991: 	b->name, iface->ifname, ifgroup));
 3992: 
 3993:     i = ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr);
 3994:     if (i < 0 && i != EEXIST) {
 3995: 	Perror("[%s] IFACE: ioctl(%s, SIOCAIFGROUP)", b->name, iface->ifname);
 3996:         close(s);
 3997:         return(-1);
 3998:     }
 3999: 
 4000:     close(s);
 4001:     return(0);
 4002: }
 4003: 
 4004: /*
 4005:  * IfaceDelGroup()
 4006:  */
 4007: int
 4008: IfaceDelGroup(Bund b, const char * ifgroup)
 4009: {
 4010:     IfaceState	const iface = &b->iface;
 4011:     struct ifgroupreq	ifgr;
 4012:     int	s;
 4013: 
 4014:     /* Get socket */
 4015:     if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
 4016: 	Perror("[%s] IFACE: Can't get socket to delete from group", b->name);
 4017: 	return(-1);
 4018:     }
 4019: 
 4020:     if (ifgroup[0] && isdigit(ifgroup[strlen(ifgroup) - 1])) {
 4021: 	Perror("[%s] IFACE: groupnames may not end in a digit", b->name);
 4022: 	return(-1);
 4023:     }
 4024: 
 4025:     /* Set interface group */
 4026:     memset(&ifgr, 0, sizeof(ifgr));
 4027:     strlcpy(ifgr.ifgr_name, iface->ifname, sizeof(ifgr.ifgr_name));
 4028:     strlcpy(ifgr.ifgr_group, ifgroup, sizeof(ifgr.ifgr_group));
 4029: 
 4030:     Log(LG_IFACE2, ("[%s] IFACE: remove interface %s from group %s",
 4031: 	b->name, iface->ifname, ifgroup));
 4032: 
 4033:     if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1) {
 4034: 	Perror("[%s] IFACE: ioctl(%s, SIOCDIFGROUP)", b->name, iface->ifname);
 4035: 	close(s);
 4036: 	return(-1);
 4037:     }
 4038:     close(s);
 4039:     return(0);
 4040: }
 4041: #endif

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