FreeBSD/sys/netinet/in.c
/*
 * Generic internet control operations (ioctl's).
 */
Generic internet control operations (ioctl's).
Generic internet control operations ( ioctl ' s ) .
int
in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
    struct thread *td)
{
	struct ifreq *ifr = (struct ifreq *)data;
	struct sockaddr_in *addr = (struct sockaddr_in *)&ifr->ifr_addr;
	struct ifaddr *ifa;
	struct in_ifaddr *ia;
	int error;
	if (ifp == NULL)
		return (EADDRNOTAVAIL);
	switch (cmd) {
	case SIOCGIFADDR:
	case SIOCGIFBRDADDR:
	case SIOCGIFDSTADDR:
	case SIOCGIFNETMASK:
		break;
	case SIOCDIFADDR:
		sx_xlock(&in_control_sx);
		error = in_difaddr_ioctl(data, ifp, td);
		sx_xunlock(&in_control_sx);
		return (error);
	case OSIOCAIFADDR:	
	case SIOCAIFADDR:
		sx_xlock(&in_control_sx);
		error = in_aifaddr_ioctl(cmd, data, ifp, td);
		sx_xunlock(&in_control_sx);
		return (error);
	case SIOCSIFADDR:
	case SIOCSIFBRDADDR:
	case SIOCSIFDSTADDR:
	case SIOCSIFNETMASK:
		return (EINVAL);
	default:
		if (ifp->if_ioctl == NULL)
			return (EOPNOTSUPP);
		return ((*ifp->if_ioctl)(ifp, cmd, data));
	}
	if (addr->sin_addr.s_addr != INADDR_ANY &&
	    prison_check_ip4(td->td_ucred, &addr->sin_addr) != 0)
		return (EADDRNOTAVAIL);
	IF_ADDR_RLOCK(ifp);
	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
		if (ifa->ifa_addr->sa_family != AF_INET)
			continue;
		ia = (struct in_ifaddr *)ifa;
		if (ia->ia_addr.sin_addr.s_addr == addr->sin_addr.s_addr)
			break;
	}
	if (ifa == NULL)
		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
			if (ifa->ifa_addr->sa_family == AF_INET) {
				ia = (struct in_ifaddr *)ifa;
				if (prison_check_ip4(td->td_ucred,
				    &ia->ia_addr.sin_addr) == 0)
					break;
			}
	if (ifa == NULL) {
		IF_ADDR_RUNLOCK(ifp);
		return (EADDRNOTAVAIL);
	}
	error = 0;
	switch (cmd) {
	case SIOCGIFADDR:
		*addr = ia->ia_addr;
		break;
	case SIOCGIFBRDADDR:
		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
			error = EINVAL;
			break;
		}
		*addr = ia->ia_broadaddr;
		break;
	case SIOCGIFDSTADDR:
		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
			error = EINVAL;
			break;
		}
		*addr = ia->ia_dstaddr;
		break;
	case SIOCGIFNETMASK:
		*addr = ia->ia_sockmask;
		break;
	}
	IF_ADDR_RUNLOCK(ifp);
	return (error);
}
int in_control ( struct socket * so , u_long cmd , caddr_t data , struct ifnet * ifp , struct thread * td ) { struct ifreq * ifr = ( struct ifreq * ) data ; struct sockaddr_in * addr = ( struct sockaddr_in * ) & ifr -> ifr_addr ; struct ifaddr * ifa ; struct in_ifaddr * ia ; int error ; if ( ifp == NULL ) return ( EADDRNOTAVAIL ) ; switch ( cmd ) { case SIOCGIFADDR : case SIOCGIFBRDADDR : case SIOCGIFDSTADDR : case SIOCGIFNETMASK : break ; case SIOCDIFADDR : sx_xlock ( & in_control_sx ) ; error = in_difaddr_ioctl ( data , ifp , td ) ; sx_xunlock ( & in_control_sx ) ; return ( error ) ; case OSIOCAIFADDR : case SIOCAIFADDR : sx_xlock ( & in_control_sx ) ; error = in_aifaddr_ioctl ( cmd , data , ifp , td ) ; sx_xunlock ( & in_control_sx ) ; return ( error ) ; case SIOCSIFADDR : case SIOCSIFBRDADDR : case SIOCSIFDSTADDR : case SIOCSIFNETMASK : return ( EINVAL ) ; default : if ( ifp -> if_ioctl == NULL ) return ( EOPNOTSUPP ) ; return ( ( * ifp -> if_ioctl ) ( ifp , cmd , data ) ) ; } if ( addr -> sin_addr . s_addr != INADDR_ANY && prison_check_ip4 ( td -> td_ucred , & addr -> sin_addr ) != 0 ) return ( EADDRNOTAVAIL ) ; IF_ADDR_RLOCK ( ifp ) ; TAILQ_FOREACH ( ifa , & ifp -> if_addrhead , ifa_link ) { if ( ifa -> ifa_addr -> sa_family != AF_INET ) continue ; ia = ( struct in_ifaddr * ) ifa ; if ( ia -> ia_addr . sin_addr . s_addr == addr -> sin_addr . s_addr ) break ; } if ( ifa == NULL ) TAILQ_FOREACH ( ifa , & ifp -> if_addrhead , ifa_link ) if ( ifa -> ifa_addr -> sa_family == AF_INET ) { ia = ( struct in_ifaddr * ) ifa ; if ( prison_check_ip4 ( td -> td_ucred , & ia -> ia_addr . sin_addr ) == 0 ) break ; } if ( ifa == NULL ) { IF_ADDR_RUNLOCK ( ifp ) ; return ( EADDRNOTAVAIL ) ; } error = 0 ; switch ( cmd ) { case SIOCGIFADDR : * addr = ia -> ia_addr ; break ; case SIOCGIFBRDADDR : if ( ( ifp -> if_flags & IFF_BROADCAST ) == 0 ) { error = EINVAL ; break ; } * addr = ia -> ia_broadaddr ; break ; case SIOCGIFDSTADDR : if ( ( ifp -> if_flags & IFF_POINTOPOINT ) == 0 ) { error = EINVAL ; break ; } * addr = ia -> ia_dstaddr ; break ; case SIOCGIFNETMASK : * addr = ia -> ia_sockmask ; break ; } IF_ADDR_RUNLOCK ( ifp ) ; return ( error ) ; }
Generic internet control operations (ioctl's).
Generic internet control operations ( ioctl ' s ) .
/*
	 * Filter out 4 ioctls we implement directly.  Forward the rest
	 * to specific functions and ifp->if_ioctl().
	 */ /* 9.x compat */ /* We no longer support that old commands. */ /*
	 * Find address for this interface, if it exists.  If an
	 * address was specified, find that one instead of the
	 * first one on the interface, if possible.
	 */