FreeBSD/usr.sbin/rwhod/rwhod.c
/*
 * Figure out device configuration and select
 * networks which deserve status information.
 */
Figure out device configuration and select
networks which deserve status information.
Figure out device configuration and select networks which deserve status information .
int
configure(int so)
{
	struct neighbor *np;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr_dl *sdl;
	size_t needed;
	int mib[6], flags, lflags, len;
	char *buf, *lim, *next;
	struct rt_addrinfo info;
	flags = 0;
	if (multicast_mode != NO_MULTICAST) {
		multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP);
		multicast_addr.sin_port = sp->s_port;
	}
	if (multicast_mode == SCOPED_MULTICAST) {
		struct ip_mreq mreq;
		unsigned char ttl;
		mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP);
		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
		if (setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP,
		    &mreq, sizeof(mreq)) < 0) {
			syslog(LOG_ERR,
			    "setsockopt IP_ADD_MEMBERSHIP: %m");
			return (0);
		}
		ttl = multicast_scope;
		if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
		    sizeof(ttl)) < 0) {
			syslog(LOG_ERR,
			    "setsockopt IP_MULTICAST_TTL: %m");
			return (0);
		}
		return (1);
	}
	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;
	mib[3] = AF_INET;
	mib[4] = NET_RT_IFLIST;
	mib[5] = 0;
	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
		quit("route-sysctl-estimate");
	if ((buf = malloc(needed)) == NULL)
		quit("malloc");
	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
		quit("actual retrieval of interface table");
	lim = buf + needed;
	sdl = NULL;		
	for (next = buf; next < lim; next += ifm->ifm_msglen) {
		ifm = (struct if_msghdr *)next;
		if (ifm->ifm_type == RTM_IFINFO) {
			sdl = (struct sockaddr_dl *)(ifm + 1);
			flags = ifm->ifm_flags;
			continue;
		}
		if ((flags & IFF_UP) == 0)
			continue;
		lflags = IFF_BROADCAST | iff_flag;
		if (multicast_mode == PER_INTERFACE_MULTICAST)
			lflags |= IFF_MULTICAST;
		if ((flags & lflags) == 0)
			continue;
		if (ifm->ifm_type != RTM_NEWADDR)
			quit("out of sync parsing NET_RT_IFLIST");
		ifam = (struct ifa_msghdr *)ifm;
		info.rti_addrs = ifam->ifam_addrs;
		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
		    &info);
#define	dstaddr		info.rti_info[RTAX_BRD]
#define	ifaddr		info.rti_info[RTAX_IFA]
#define	IPADDR_SA(x)	((struct sockaddr_in *)(x))->sin_addr.s_addr
#define	PORT_SA(x)	((struct sockaddr_in *)(x))->sin_port
		if (dstaddr == 0 || dstaddr->sa_family != AF_INET)
			continue;
		PORT_SA(dstaddr) = sp->s_port;
		for (np = neighbors; np != NULL; np = np->n_next) {
			if (memcmp(sdl->sdl_data, np->n_name,
			    sdl->sdl_nlen) == 0 &&
			    IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) {
				break;
			}
		}
		if (np != NULL)
			continue;
		len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1;
		np = malloc(len);
		if (np == NULL)
			quit("malloc of neighbor structure");
		memset(np, 0, len);
		np->n_flags = flags;
		np->n_addr = (struct sockaddr *)(np + 1);
		np->n_addrlen = dstaddr->sa_len;
		np->n_name = np->n_addrlen + (char *)np->n_addr;
		memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen);
		memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen);
		if (multicast_mode == PER_INTERFACE_MULTICAST &&
		    (flags & IFF_MULTICAST) != 0 &&
		    (flags & IFF_LOOPBACK) == 0) {
			struct ip_mreq mreq;
			memcpy((char *)np->n_addr, (char *)ifaddr,
			    np->n_addrlen);
			mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP);
			mreq.imr_interface.s_addr =
			    ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr;
			if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
			    &mreq, sizeof(mreq)) < 0) {
				syslog(LOG_ERR,
				    "setsockopt IP_ADD_MEMBERSHIP: %m");
#if 0
				np->n_flags &= ~IFF_MULTICAST;
#else
				free(np);
				continue;
#endif
			}
		}
		np->n_next = neighbors;
		neighbors = np;
	}
	free(buf);
	return (1);
}
int configure ( int so ) { struct neighbor * np ; struct if_msghdr * ifm ; struct ifa_msghdr * ifam ; struct sockaddr_dl * sdl ; size_t needed ; int mib [ 6 ] , flags , lflags , len ; char * buf , * lim , * next ; struct rt_addrinfo info ; flags = 0 ; if ( multicast_mode != NO_MULTICAST ) { multicast_addr . sin_addr . s_addr = htonl ( INADDR_WHOD_GROUP ) ; multicast_addr . sin_port = sp -> s_port ; } if ( multicast_mode == SCOPED_MULTICAST ) { struct ip_mreq mreq ; unsigned char ttl ; mreq . imr_multiaddr . s_addr = htonl ( INADDR_WHOD_GROUP ) ; mreq . imr_interface . s_addr = htonl ( INADDR_ANY ) ; if ( setsockopt ( so , IPPROTO_IP , IP_ADD_MEMBERSHIP , & mreq , sizeof ( mreq ) ) < 0 ) { syslog ( LOG_ERR , " " ) ; return ( 0 ) ; } ttl = multicast_scope ; if ( setsockopt ( so , IPPROTO_IP , IP_MULTICAST_TTL , & ttl , sizeof ( ttl ) ) < 0 ) { syslog ( LOG_ERR , " " ) ; return ( 0 ) ; } return ( 1 ) ; } mib [ 0 ] = CTL_NET ; mib [ 1 ] = PF_ROUTE ; mib [ 2 ] = 0 ; mib [ 3 ] = AF_INET ; mib [ 4 ] = NET_RT_IFLIST ; mib [ 5 ] = 0 ; if ( sysctl ( mib , 6 , NULL , & needed , NULL , 0 ) < 0 ) quit ( " " ) ; if ( ( buf = malloc ( needed ) ) == NULL ) quit ( " " ) ; if ( sysctl ( mib , 6 , buf , & needed , NULL , 0 ) < 0 ) quit ( " " ) ; lim = buf + needed ; sdl = NULL ; for ( next = buf ; next < lim ; next += ifm -> ifm_msglen ) { ifm = ( struct if_msghdr * ) next ; if ( ifm -> ifm_type == RTM_IFINFO ) { sdl = ( struct sockaddr_dl * ) ( ifm + 1 ) ; flags = ifm -> ifm_flags ; continue ; } if ( ( flags & IFF_UP ) == 0 ) continue ; lflags = IFF_BROADCAST | iff_flag ; if ( multicast_mode == PER_INTERFACE_MULTICAST ) lflags |= IFF_MULTICAST ; if ( ( flags & lflags ) == 0 ) continue ; if ( ifm -> ifm_type != RTM_NEWADDR ) quit ( " " ) ; ifam = ( struct ifa_msghdr * ) ifm ; info . rti_addrs = ifam -> ifam_addrs ; rt_xaddrs ( ( char * ) ( ifam + 1 ) , ifam -> ifam_msglen + ( char * ) ifam , & info ) ; #define dstaddr 		info.rti_info[RTAX_BRD] #define ifaddr 		info.rti_info[RTAX_IFA] #define IPADDR_SA ( x ) 	((struct sockaddr_in *)(x))->sin_addr.s_addr #define PORT_SA ( x ) 	((struct sockaddr_in *)(x))->sin_port if ( dstaddr == 0 || dstaddr -> sa_family != AF_INET ) continue ; PORT_SA ( dstaddr ) = sp -> s_port ; for ( np = neighbors ; np != NULL ; np = np -> n_next ) { if ( memcmp ( sdl -> sdl_data , np -> n_name , sdl -> sdl_nlen ) == 0 && IPADDR_SA ( np -> n_addr ) == IPADDR_SA ( dstaddr ) ) { break ; } } if ( np != NULL ) continue ; len = sizeof ( * np ) + dstaddr -> sa_len + sdl -> sdl_nlen + 1 ; np = malloc ( len ) ; if ( np == NULL ) quit ( " " ) ; memset ( np , 0 , len ) ; np -> n_flags = flags ; np -> n_addr = ( struct sockaddr * ) ( np + 1 ) ; np -> n_addrlen = dstaddr -> sa_len ; np -> n_name = np -> n_addrlen + ( char * ) np -> n_addr ; memcpy ( ( char * ) np -> n_addr , ( char * ) dstaddr , np -> n_addrlen ) ; memcpy ( np -> n_name , sdl -> sdl_data , sdl -> sdl_nlen ) ; if ( multicast_mode == PER_INTERFACE_MULTICAST && ( flags & IFF_MULTICAST ) != 0 && ( flags & IFF_LOOPBACK ) == 0 ) { struct ip_mreq mreq ; memcpy ( ( char * ) np -> n_addr , ( char * ) ifaddr , np -> n_addrlen ) ; mreq . imr_multiaddr . s_addr = htonl ( INADDR_WHOD_GROUP ) ; mreq . imr_interface . s_addr = ( ( struct sockaddr_in * ) np -> n_addr ) -> sin_addr . s_addr ; if ( setsockopt ( s , IPPROTO_IP , IP_ADD_MEMBERSHIP , & mreq , sizeof ( mreq ) ) < 0 ) { syslog ( LOG_ERR , " " ) ; #if 0 np -> n_flags &= ~ IFF_MULTICAST ; #else free ( np ) ; continue ; #endif } } np -> n_next = neighbors ; neighbors = np ; } free ( buf ) ; return ( 1 ) ; }
Figure out device configuration and select
 networks which deserve status information.
Figure out device configuration and select networks which deserve status information .
/* XXX just to keep gcc -Wall happy */ /* gag, wish we could get rid of Internet dependencies */ /* Fall back to broadcast on this if. */