File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / udp.c
Revision 1.1.1.2 (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_8p7, v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    1: 
    2: /*
    3:  * udp.c
    4:  *
    5:  * Written by  Alexander Motin <mav@FreeBSD.org>
    6:  */
    7: 
    8: #include "ppp.h"
    9: #include "phys.h"
   10: #include "mbuf.h"
   11: #include "udp.h"
   12: #include "ngfunc.h"
   13: #include "util.h"
   14: #include "log.h"
   15: 
   16: #include <netgraph/ng_message.h>
   17: #include <netgraph/ng_socket.h>
   18: #include <netgraph/ng_ksocket.h>
   19: #include <netgraph.h>
   20: 
   21: /*
   22:  * XXX this device type not completely correct, 
   23:  * as it can deliver out-of-order frames. This can make problems 
   24:  * for different compression and encryption protocols.
   25:  */
   26: 
   27: /*
   28:  * DEFINITIONS
   29:  */
   30: 
   31:   #define UDP_MTU		2048
   32:   #define UDP_MRU		2048
   33: 
   34: #ifndef SMALL_SYSTEM
   35: #define UDP_MAXPARENTIFS	256
   36: #else
   37: #define UDP_MAXPARENTIFS	64
   38: #endif
   39: 
   40:   struct udpinfo {
   41:     struct {
   42: 	struct optinfo	options;
   43: 	struct u_addr	self_addr;	/* Configured local IP address */
   44: 	struct u_range	peer_addr;	/* Configured peer IP address */
   45: 	in_port_t	self_port;	/* Configured local port */
   46: 	in_port_t	peer_port;	/* Configured peer port */
   47: 	char		*fqdn_peer_addr; /* FQDN Peer address */
   48:     } conf;
   49: 
   50:     /* State */
   51:     u_char		incoming;		/* incoming vs. outgoing */
   52:     struct UdpIf 	*If;
   53:     struct u_addr	peer_addr;
   54:     in_port_t		peer_port;
   55:     ng_ID_t		node_id;
   56:   };
   57:   typedef struct udpinfo	*UdpInfo;
   58: 
   59: /* Set menu options */
   60: 
   61:   enum {
   62:     SET_PEERADDR,
   63:     SET_SELFADDR,
   64:     SET_ENABLE,
   65:     SET_DISABLE
   66:   };
   67: 
   68:   /* Binary options */
   69:   enum {
   70:     UDP_CONF_RESOLVE_ONCE	/* Only once resolve peer_addr */
   71:   };
   72: 
   73: /*
   74:  * INTERNAL FUNCTIONS
   75:  */
   76: 
   77:   static int	UdpInit(Link l);
   78:   static int	UdpInst(Link l, Link lt);
   79:   static void	UdpOpen(Link l);
   80:   static void	UdpClose(Link l);
   81:   static void	UdpStat(Context ctx);
   82:   static int	UdpOrigination(Link l);
   83:   static int	UdpIsSync(Link l);
   84:   static int	UdpSelfAddr(Link l, void *buf, size_t buf_len);
   85:   static int	UdpPeerAddr(Link l, void *buf, size_t buf_len);
   86:   static int	UdpPeerPort(Link l, void *buf, size_t buf_len);
   87:   static int	UdpCallingNum(Link l, void *buf, size_t buf_len);
   88:   static int	UdpCalledNum(Link l, void *buf, size_t buf_len);
   89: 
   90:   static void	UdpDoClose(Link l);
   91:   static void	UdpShutdown(Link l);
   92:   static int	UdpSetCommand(Context ctx, int ac, char *av[], void *arg);
   93:   static void	UdpNodeUpdate(Link l);
   94:   static int	UdpListen(Link l);
   95:   static int	UdpUnListen(Link l);
   96: 
   97: /*
   98:  * GLOBAL VARIABLES
   99:  */
  100: 
  101:   const struct phystype gUdpPhysType = {
  102:     .name		= "udp",
  103:     .descr		= "PPP over UDP",
  104:     .mtu		= UDP_MTU,
  105:     .mru		= UDP_MRU,
  106:     .tmpl		= 1,
  107:     .init		= UdpInit,
  108:     .inst		= UdpInst,
  109:     .open		= UdpOpen,
  110:     .close		= UdpClose,
  111:     .update		= UdpNodeUpdate,
  112:     .shutdown		= UdpShutdown,
  113:     .showstat		= UdpStat,
  114:     .originate		= UdpOrigination,
  115:     .issync		= UdpIsSync,
  116:     .selfaddr		= UdpSelfAddr,
  117:     .peeraddr		= UdpPeerAddr,
  118:     .peerport		= UdpPeerPort,
  119:     .callingnum		= UdpCallingNum,
  120:     .callednum		= UdpCalledNum,
  121:   };
  122: 
  123:   const struct cmdtab UdpSetCmds[] = {
  124:     { "self {ip} [{port}]",		"Set local IP address",
  125: 	UdpSetCommand, NULL, 2, (void *) SET_SELFADDR },
  126:     { "peer {ip} [{port}]",		"Set remote IP address",
  127: 	UdpSetCommand, NULL, 2, (void *) SET_PEERADDR },
  128:     { "enable [opt ...]",		"Enable option",
  129: 	UdpSetCommand, NULL, 2, (void *) SET_ENABLE },
  130:     { "disable [opt ...]",		"Disable option",
  131: 	UdpSetCommand, NULL, 2, (void *) SET_DISABLE },
  132:     { NULL },
  133:   };
  134: 
  135: struct UdpIf {
  136:     struct u_addr	self_addr;
  137:     in_port_t	self_port;
  138:     int		refs;
  139:     int		csock;                  /* netgraph Control socket */
  140:     EventRef	ctrlEvent;		/* listen for ctrl messages */
  141: };
  142: struct UdpIf UdpIfs[UDP_MAXPARENTIFS];
  143: 
  144: int UdpListenUpdateSheduled=0;
  145: struct pppTimer UdpListenUpdateTimer;
  146: 
  147:  /*
  148:  * INTERNAL VARIABLES
  149:  */
  150: 
  151:   static struct confinfo	gConfList[] = {
  152:     { 0,	UDP_CONF_RESOLVE_ONCE,	"resolve-once"	},
  153:     { 0,	0,			NULL		},
  154:   };
  155: 
  156: 
  157: /*
  158:  * UdpInit()
  159:  */
  160: 
  161: static int
  162: UdpInit(Link l)
  163: {
  164:     UdpInfo	pi;
  165: 
  166:     pi = (UdpInfo) (l->info = Malloc(MB_PHYS, sizeof(*pi)));
  167: 
  168:     u_addrclear(&pi->conf.self_addr);
  169:     u_rangeclear(&pi->conf.peer_addr);
  170:     pi->conf.self_port=0;
  171:     pi->conf.peer_port=0;
  172: 
  173:     pi->incoming = 0;
  174:     pi->If = NULL;
  175: 
  176:     u_addrclear(&pi->peer_addr);
  177:     pi->peer_port=0;
  178:     pi->conf.fqdn_peer_addr = NULL;
  179:     Enable(&pi->conf.options, UDP_CONF_RESOLVE_ONCE);
  180: 
  181:     return(0);
  182: }
  183: 
  184: /*
  185:  * UdpInst()
  186:  */
  187: 
  188: static int
  189: UdpInst(Link l, Link lt)
  190: {
  191:     UdpInfo	pi;
  192:     UdpInfo const pit = (UdpInfo) lt->info;
  193: 
  194:     /* Initialize this link */
  195:     pi = (UdpInfo) (l->info = Mdup(MB_PHYS, lt->info, sizeof(*pi)));
  196:     if (pit->conf.fqdn_peer_addr != NULL)
  197:         pi->conf.fqdn_peer_addr =
  198:             Mstrdup(MB_PHYS, pit->conf.fqdn_peer_addr);
  199:     
  200:     if (pi->If)
  201: 	pi->If->refs++;
  202: 
  203:     return(0);
  204: }
  205: 
  206: /*
  207:  * UdpOpen()
  208:  */
  209: 
  210: static void
  211: UdpOpen(Link l)
  212: {
  213: 	UdpInfo			const pi = (UdpInfo) l->info;
  214: 	char        		path[NG_PATHSIZ];
  215: 	char        		hook[NG_HOOKSIZ];
  216: 	struct ngm_mkpeer	mkp;
  217: 	struct ngm_name         nm;
  218: 	struct sockaddr_storage	addr;
  219:         union {
  220:             u_char buf[sizeof(struct ng_ksocket_sockopt) + sizeof(int)];
  221:             struct ng_ksocket_sockopt ksso;
  222:         } u;
  223:         struct ng_ksocket_sockopt *const ksso = &u.ksso;
  224: 	int			csock;
  225: 
  226: 	/* Create a new netgraph node to control TCP ksocket node. */
  227: 	if (NgMkSockNode(NULL, &csock, NULL) < 0) {
  228: 		Perror("[%s] TCP can't create control socket", l->name);
  229: 		goto fail;
  230: 	}
  231: 	(void)fcntl(csock, F_SETFD, 1);
  232: 
  233:         if (!PhysGetUpperHook(l, path, hook)) {
  234: 		Log(LG_PHYS, ("[%s] UDP: can't get upper hook", l->name));
  235:     		goto fail;
  236:         }
  237: 
  238: 	/* Attach ksocket node to PPP node */
  239: 	memset(&mkp, 0, sizeof(mkp));
  240: 	strcpy(mkp.type, NG_KSOCKET_NODE_TYPE);
  241: 	strlcpy(mkp.ourhook, hook, sizeof(mkp.ourhook));
  242: 	if ((pi->conf.self_addr.family==AF_INET6) || 
  243: 	    (pi->conf.self_addr.family==AF_UNSPEC && pi->conf.peer_addr.addr.family==AF_INET6)) {
  244: 	        snprintf(mkp.peerhook, sizeof(mkp.peerhook), "%d/%d/%d", PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  245: 	} else {
  246: 	    snprintf(mkp.peerhook, sizeof(mkp.peerhook), "inet/dgram/udp");
  247: 	}
  248: 	if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
  249: 	    NGM_MKPEER, &mkp, sizeof(mkp)) < 0) {
  250: 	        Perror("[%s] can't attach %s node",
  251: 	    	    l->name, NG_KSOCKET_NODE_TYPE);
  252: 		goto fail;
  253: 	}
  254: 
  255: 	strlcat(path, ".", sizeof(path));
  256: 	strlcat(path, hook, sizeof(path));
  257: 
  258: 	/* Give it a name */
  259: 	memset(&nm, 0, sizeof(nm));
  260: 	snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-kso", gPid, l->name);
  261: 	if (NgSendMsg(csock, path,
  262: 	    NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
  263: 		Perror("[%s] can't name %s node", l->name, NG_KSOCKET_NODE_TYPE);
  264: 	}
  265: 
  266: 	if ((pi->node_id = NgGetNodeID(csock, path)) == 0) {
  267: 	    Perror("[%s] Cannot get %s node id", l->name, NG_KSOCKET_NODE_TYPE);
  268: 	    goto fail;
  269: 	};
  270: 
  271:     if ((pi->incoming) || (pi->conf.self_port != 0)) {
  272: 	/* Setsockopt socket. */
  273: 	ksso->level=SOL_SOCKET;
  274: 	ksso->name=SO_REUSEPORT;
  275: 	((int *)(ksso->value))[0]=1;
  276: 	if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
  277:     	    NGM_KSOCKET_SETOPT, &u, sizeof(u)) < 0) {
  278:     	    Perror("[%s] can't setsockopt() %s node",
  279:     		l->name, NG_KSOCKET_NODE_TYPE);
  280: 	    goto fail;
  281: 	}
  282: 
  283: 	if ((!Enabled(&pi->conf.options, UDP_CONF_RESOLVE_ONCE)) &&
  284: 	    (pi->conf.fqdn_peer_addr != NULL)) {
  285: 	    struct u_range	rng;
  286: 	    if (ParseRange(pi->conf.fqdn_peer_addr, &rng, ALLOW_IPV4|ALLOW_IPV6))
  287: 		pi->conf.peer_addr = rng;
  288: 	}
  289: 
  290: 	/* Bind socket */
  291: 	u_addrtosockaddr(&pi->conf.self_addr, pi->conf.self_port, &addr);
  292: 	if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
  293: 	  NGM_KSOCKET_BIND, &addr, addr.ss_len) < 0) {
  294: 	    Perror("[%s] can't bind() %s node", l->name, NG_KSOCKET_NODE_TYPE);
  295: 	    goto fail;
  296: 	}
  297:     }
  298: 
  299:     if (!pi->incoming) {
  300: 	if ((!u_rangeempty(&pi->conf.peer_addr)) && (pi->conf.peer_port != 0)) {
  301: 	    u_addrcopy(&pi->conf.peer_addr.addr,&pi->peer_addr);
  302: 	    pi->peer_port = pi->conf.peer_port;
  303: 	} else {
  304: 	    Log(LG_ERR, ("[%s] Can't connect without peer specified", l->name));
  305: 	    goto fail;
  306: 	}
  307:     }
  308:     u_addrtosockaddr(&pi->peer_addr, pi->peer_port, &addr);
  309: 
  310:     /* Connect socket if peer address and port is specified */
  311:     if (NgSendMsg(csock, path, NGM_KSOCKET_COOKIE,
  312:       NGM_KSOCKET_CONNECT, &addr, addr.ss_len) < 0) {
  313: 	Perror("[%s] can't connect() %s node", l->name, NG_KSOCKET_NODE_TYPE);
  314: 	goto fail;
  315:     }
  316:   
  317:     close(csock);
  318: 
  319:     /* OK */
  320:     l->state = PHYS_STATE_UP;
  321:     PhysUp(l);
  322:     return;
  323: 
  324: fail:
  325:     UdpDoClose(l);
  326:     pi->incoming=0;
  327:     l->state = PHYS_STATE_DOWN;
  328:     u_addrclear(&pi->peer_addr);
  329:     pi->peer_port=0;
  330:     if (csock>0)
  331: 	close(csock);
  332: 
  333:     PhysDown(l, STR_ERROR, NULL);
  334: }
  335: 
  336: /*
  337:  * UdpClose()
  338:  */
  339: 
  340: static void
  341: UdpClose(Link l)
  342: {
  343:     UdpInfo const pi = (UdpInfo) l->info;
  344:     if (l->state != PHYS_STATE_DOWN) {
  345: 	UdpDoClose(l);
  346: 	pi->incoming=0;
  347: 	l->state = PHYS_STATE_DOWN;
  348: 	u_addrclear(&pi->peer_addr);
  349: 	pi->peer_port=0;
  350: 	PhysDown(l, STR_MANUALLY, NULL);
  351:     }
  352: }
  353: 
  354: /*
  355:  * UdpShutdown()
  356:  */
  357: 
  358: static void
  359: UdpShutdown(Link l)
  360: {
  361:     UdpInfo const pi = (UdpInfo) l->info;
  362: 
  363:     if (pi->conf.fqdn_peer_addr)
  364:         Freee(pi->conf.fqdn_peer_addr);
  365: 
  366: 	UdpDoClose(l);
  367: 	UdpUnListen(l);
  368: 	Freee(l->info);
  369: }
  370: 
  371: /*
  372:  * UdpDoClose()
  373:  */
  374: 
  375: static void
  376: UdpDoClose(Link l)
  377: {
  378: 	UdpInfo	const pi = (UdpInfo) l->info;
  379: 	char	path[NG_PATHSIZ];
  380: 	int	csock;
  381: 
  382: 	if (pi->node_id == 0)
  383: 		return;
  384: 
  385: 	/* Get a temporary netgraph socket node */
  386: 	if (NgMkSockNode(NULL, &csock, NULL) == -1) {
  387: 		Perror("UDP: NgMkSockNode");
  388: 		return;
  389: 	}
  390: 	
  391: 	/* Disconnect session hook. */
  392: 	snprintf(path, sizeof(path), "[%lx]:", (u_long)pi->node_id);
  393: 	NgFuncShutdownNode(csock, l->name, path);
  394: 	
  395: 	close(csock);
  396: 	
  397: 	pi->node_id = 0;
  398: }
  399: 
  400: /*
  401:  * UdpOrigination()
  402:  */
  403: 
  404: static int
  405: UdpOrigination(Link l)
  406: {
  407:     UdpInfo	const pi = (UdpInfo) l->info;
  408: 
  409:     return (pi->incoming ? LINK_ORIGINATE_REMOTE : LINK_ORIGINATE_LOCAL);
  410: }
  411: 
  412: /*
  413:  * UdpIsSync()
  414:  */
  415: 
  416: static int
  417: UdpIsSync(Link l)
  418: {
  419:     return (1);
  420: }
  421: 
  422: static int
  423: UdpSelfAddr(Link l, void *buf, size_t buf_len)
  424: {
  425:     UdpInfo	const pi = (UdpInfo) l->info;
  426: 
  427:     if (!u_addrempty(&pi->conf.self_addr)) {
  428: 	if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
  429: 	    return (0);
  430:   	else {
  431: 	    ((char*)buf)[0]=0;
  432: 	    return (-1);
  433: 	}
  434:     }
  435:     ((char*)buf)[0]=0;
  436:     return (0);
  437: }
  438: 
  439: static int
  440: UdpPeerAddr(Link l, void *buf, size_t buf_len)
  441: {
  442:     UdpInfo	const pi = (UdpInfo) l->info;
  443: 
  444:     if (u_addrtoa(&pi->peer_addr, buf, buf_len))
  445: 	return(0);
  446:     else
  447: 	return(-1);
  448: }
  449: 
  450: static int
  451: UdpPeerPort(Link l, void *buf, size_t buf_len)
  452: {
  453:     UdpInfo	const pi = (UdpInfo) l->info;
  454: 
  455:     if (snprintf(buf, buf_len, "%d", pi->peer_port))
  456: 	return(0);
  457:     else
  458: 	return(-1);
  459: }
  460: 
  461: static int
  462: UdpCallingNum(Link l, void *buf, size_t buf_len)
  463: {
  464: 	UdpInfo const pi = (UdpInfo) l->info;
  465: 
  466: 	if (pi->incoming) {
  467: 	    if (u_addrtoa(&pi->peer_addr, buf, buf_len))
  468: 	    	return (0);
  469:   	    else
  470: 		return (-1);
  471: 	} else {
  472: 	    if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
  473: 	    	return (0);
  474:   	    else
  475: 		return (-1);
  476: 	}
  477: }
  478: 
  479: static int
  480: UdpCalledNum(Link l, void *buf, size_t buf_len)
  481: {
  482: 	UdpInfo const pi = (UdpInfo) l->info;
  483: 
  484: 	if (!pi->incoming) {
  485: 	    if (u_addrtoa(&pi->peer_addr, buf, buf_len))
  486: 	    	return (0);
  487:   	    else
  488: 		return (-1);
  489: 	} else {
  490: 	    if (u_addrtoa(&pi->conf.self_addr, buf, buf_len))
  491: 	    	return (0);
  492:   	    else
  493: 		return (-1);
  494: 	}
  495: }
  496: 
  497: /*
  498:  * UdpStat()
  499:  */
  500: 
  501: void
  502: UdpStat(Context ctx)
  503: {
  504: 	UdpInfo const pi = (UdpInfo) ctx->lnk->info;
  505: 	char	buf[48];
  506: 
  507: 	Printf("UDP configuration:\r\n");
  508: 	Printf("\tPeer FQDN    : %s\r\n", pi->conf.fqdn_peer_addr);
  509: 	Printf("\tSelf address : %s, port %u\r\n",
  510: 	    u_addrtoa(&pi->conf.self_addr, buf, sizeof(buf)), pi->conf.self_port);
  511: 	Printf("\tPeer address : %s, port %u\r\n",
  512: 	    u_rangetoa(&pi->conf.peer_addr, buf, sizeof(buf)), pi->conf.peer_port);
  513: 	Printf("UDP state:\r\n");
  514: 	if (ctx->lnk->state != PHYS_STATE_DOWN) {
  515: 	    Printf("\tIncoming     : %s\r\n", (pi->incoming?"YES":"NO"));
  516: 	    Printf("\tCurrent peer : %s, port %u\r\n",
  517: 		u_addrtoa(&pi->peer_addr, buf, sizeof(buf)), pi->peer_port);
  518: 	}
  519: }
  520: 
  521: /*
  522:  * UdpAcceptEvent() triggers when we accept incoming connection.
  523:  */
  524: 
  525: static void
  526: UdpAcceptEvent(int type, void *cookie)
  527: {
  528: 	struct sockaddr_storage saddr;
  529: 	socklen_t	saddrlen;
  530: 	struct u_addr	addr;
  531: 	in_port_t	port;
  532: 	char		buf[48];
  533: 	char		buf1[48];
  534: 	int 		k;
  535: 	struct UdpIf 	*If=(struct UdpIf *)(cookie);
  536: 	Link		l = NULL;
  537: 	UdpInfo		pi = NULL;
  538: 
  539: 	char		pktbuf[UDP_MRU+100];
  540: 	ssize_t		pktlen;
  541: 
  542: 	assert(type == EVENT_READ);
  543: 
  544: 	saddrlen = sizeof(saddr);
  545: 	if ((pktlen = recvfrom(If->csock, pktbuf, sizeof(pktbuf), MSG_DONTWAIT, (struct sockaddr *)(&saddr), &saddrlen)) < 0) {
  546: 	    Log(LG_PHYS, ("recvfrom() error: %s", strerror(errno)));
  547: 	}
  548: 
  549: 	sockaddrtou_addr(&saddr, &addr, &port);
  550: 
  551: 	Log(LG_PHYS, ("Incoming UDP connection from %s %u to %s %u",
  552: 	    u_addrtoa(&addr, buf, sizeof(buf)), port,
  553: 	    u_addrtoa(&If->self_addr, buf1, sizeof(buf1)), If->self_port));
  554: 
  555: 	if (gShutdownInProgress) {
  556: 		Log(LG_PHYS, ("Shutdown sequence in progress, ignoring request."));
  557: 		goto failed;
  558: 	}
  559: 
  560: 	if (OVERLOAD()) {
  561: 		Log(LG_PHYS, ("Daemon overloaded, ignoring request."));
  562: 		goto failed;
  563: 	}
  564: 
  565: 	/* Examine all UDP links. */
  566: 	for (k = 0; k < gNumLinks; k++) {
  567: 		Link l2;
  568: 	        UdpInfo pi2;
  569: 
  570: 		if (!gLinks[k] || gLinks[k]->type != &gUdpPhysType)
  571: 			continue;
  572: 
  573: 		l2 = gLinks[k];
  574: 		pi2 = (UdpInfo)l2->info;
  575: 
  576: 		if ((!PhysIsBusy(l2)) &&
  577: 		    Enabled(&l2->conf.options, LINK_CONF_INCOMING) &&
  578: 		    (pi2->If == If) &&
  579: 		    IpAddrInRange(&pi2->conf.peer_addr, &addr) &&
  580: 		    (pi2->conf.peer_port == 0 || pi2->conf.peer_port == port)) {
  581: 
  582: 			if (pi == NULL || pi2->conf.peer_addr.width > pi->conf.peer_addr.width) {
  583: 				l = l2;
  584: 				pi = pi2;
  585: 				if (u_rangehost(&pi->conf.peer_addr)) {
  586: 					break;	/* Nothing could be better */
  587: 				}
  588: 			}
  589: 		}
  590: 	}
  591: 	if (l != NULL && l->tmpl)
  592:     		l = LinkInst(l, NULL, 0, 0);
  593: 
  594: 	if (l != NULL) {
  595:     		pi = (UdpInfo)l->info;
  596: 		Log(LG_PHYS, ("[%s] Accepting UDP connection from %s %u to %s %u",
  597: 		    l->name, u_addrtoa(&addr, buf, sizeof(buf)), port,
  598: 		    u_addrtoa(&If->self_addr, buf1, sizeof(buf1)), If->self_port));
  599: 
  600: 		sockaddrtou_addr(&saddr, &pi->peer_addr, &pi->peer_port);
  601: 
  602: 		pi->incoming=1;
  603: 		l->state = PHYS_STATE_READY;
  604: 
  605: 		PhysIncoming(l);
  606: 	} else {
  607: 		Log(LG_PHYS, ("No free UDP link with requested parameters "
  608: 	    	    "was found"));
  609: 	}
  610: 
  611: failed:
  612: 	EventRegister(&If->ctrlEvent, EVENT_READ, If->csock,
  613: 	    0, UdpAcceptEvent, If);
  614: }
  615: 
  616: static int 
  617: UdpListen(Link l)
  618: {
  619: 	UdpInfo const pi = (UdpInfo) l->info;
  620: 	struct sockaddr_storage addr;
  621: 	char buf[48];
  622: 	int opt, i, j = -1, free = -1;
  623: 	
  624: 	if (pi->If)
  625: 	    return(1);
  626: 
  627: 	for (i = 0; i < UDP_MAXPARENTIFS; i++) {
  628: 	    if (UdpIfs[i].self_port == 0)
  629: 	        free = i;
  630: 	    else if ((u_addrcompare(&UdpIfs[i].self_addr, &pi->conf.self_addr) == 0) &&
  631: 	        (UdpIfs[i].self_port == pi->conf.self_port)) {
  632: 	            j = i;
  633: 	    	    break;
  634: 	    }
  635: 	}
  636: 
  637: 	if (j >= 0) {
  638: 	    UdpIfs[j].refs++;
  639: 	    pi->If=&UdpIfs[j];
  640: 	    return(1);
  641: 	}
  642: 
  643: 	if (free < 0) {
  644: 	    Log(LG_ERR, ("[%s] UDP: Too many different listening ports! ", 
  645: 		l->name));
  646: 	    return (0);
  647: 	}
  648: 
  649: 	UdpIfs[free].refs = 1;
  650: 	pi->If=&UdpIfs[free];
  651: 	
  652: 	u_addrcopy(&pi->conf.self_addr,&pi->If->self_addr);
  653: 	pi->If->self_port=pi->conf.self_port;
  654: 	
  655: 	/* Make listening UDP socket. */
  656: 	if (pi->If->self_addr.family==AF_INET6) {
  657: 	    pi->If->csock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  658: 	} else {
  659: 	    pi->If->csock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  660: 	}
  661: 	(void)fcntl(pi->If->csock, F_SETFD, 1);
  662: 
  663: 	/* Setsockopt socket. */
  664: 	opt = 1;
  665: 	if (setsockopt(pi->If->csock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) {
  666: 		Perror("UDP: can't setsockopt socket");
  667: 		goto fail2;
  668: 	};
  669: 
  670: 	/* Bind socket. */
  671: 	u_addrtosockaddr(&pi->If->self_addr, pi->If->self_port, &addr);
  672: 	if (bind(pi->If->csock, (struct sockaddr *)(&addr), addr.ss_len)) {
  673: 		Perror("UDP: can't bind socket");
  674: 		goto fail2;
  675: 	}
  676: 
  677: 	Log(LG_PHYS, ("UDP: waiting for connection on %s %u",
  678: 	    u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
  679: 	EventRegister(&pi->If->ctrlEvent, EVENT_READ, pi->If->csock,
  680: 	    0, UdpAcceptEvent, pi->If);
  681: 
  682: 	return (1);
  683: fail2:
  684: 	close(pi->If->csock);
  685: 	pi->If->csock = -1;
  686: 	pi->If->self_port = 0;
  687: 	pi->If = NULL;
  688: 	return (0);
  689: }
  690: 
  691: 
  692: static int 
  693: UdpUnListen(Link l)
  694: {
  695: 	UdpInfo const pi = (UdpInfo) l->info;
  696: 	char buf[48];
  697: 	
  698: 	if (!pi->If)
  699: 	    return(1);
  700: 
  701: 	pi->If->refs--;
  702: 	if (pi->If->refs == 0) {
  703: 	    Log(LG_PHYS, ("UDP: stop waiting for connection on %s %u",
  704: 		u_addrtoa(&pi->If->self_addr, buf, sizeof(buf)), pi->If->self_port));
  705: 	    EventUnRegister(&pi->If->ctrlEvent);
  706: 	    close(pi->If->csock);
  707: 	    pi->If->csock = -1;
  708: 	    pi->If->self_port = 0;
  709: 	    pi->If = NULL;
  710: 	}
  711: 
  712: 	return (1);
  713: }
  714: 
  715: /*
  716:  * UdpNodeUpdate()
  717:  */
  718: 
  719: static void
  720: UdpNodeUpdate(Link l)
  721: {
  722:     UdpInfo const pi = (UdpInfo) l->info;
  723:     if (!pi->If) {
  724: 	if (Enabled(&l->conf.options, LINK_CONF_INCOMING))
  725: 	    UdpListen(l);
  726:     } else {
  727: 	if (!Enabled(&l->conf.options, LINK_CONF_INCOMING))
  728: 	    UdpUnListen(l);
  729:     }
  730: }
  731: 
  732: /*
  733:  * UdpSetCommand()
  734:  */
  735: 
  736: static int
  737: UdpSetCommand(Context ctx, int ac, char *av[], void *arg)
  738: {
  739:     UdpInfo		const pi = (UdpInfo) ctx->lnk->info;
  740:     char		**fqdn_peer_addr = &pi->conf.fqdn_peer_addr;
  741:     struct u_range	rng;
  742:     int			port;
  743: 	
  744:     switch ((intptr_t)arg) {
  745: 	case SET_PEERADDR:
  746: 	case SET_SELFADDR:
  747: 	    if ((ac == 1 || ac == 2) && (intptr_t)arg == SET_PEERADDR) {
  748: 		if (*fqdn_peer_addr)
  749: 		    Freee(*fqdn_peer_addr);
  750: 		*fqdn_peer_addr = Mstrdup(MB_PHYS, av[0]);
  751: 	    }
  752:     	    if (ac < 1 || ac > 2 || !ParseRange(av[0], &rng, ALLOW_IPV4|ALLOW_IPV6))
  753: 		return(-1);
  754:     	    if (ac > 1) {
  755: 		if ((port = atoi(av[1])) < 0 || port > 0xffff)
  756: 		    return(-1);
  757:     	    } else {
  758: 		port = 0;
  759:     	    }
  760:     	    if ((intptr_t)arg == SET_SELFADDR) {
  761: 		pi->conf.self_addr = rng.addr;
  762: 		pi->conf.self_port = port;
  763:     	    } else {
  764: 		pi->conf.peer_addr = rng;
  765: 		pi->conf.peer_port = port;
  766:     	    }
  767: 	    if (pi->If) {
  768: 		UdpUnListen(ctx->lnk);
  769: 		UdpListen(ctx->lnk);
  770: 	    }
  771:     	    break;
  772: 	case SET_ENABLE:
  773: 	    EnableCommand(ac, av, &pi->conf.options, gConfList);
  774: 	    UdpNodeUpdate(ctx->lnk);
  775: 	    break;
  776: 	case SET_DISABLE:
  777: 	    DisableCommand(ac, av, &pi->conf.options, gConfList);
  778: 	    UdpNodeUpdate(ctx->lnk);
  779: 	    break;
  780: 	default:
  781:     	    assert(0);
  782:     }
  783:     return(0);
  784: }
  785: 

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