Ejemplo n.º 1
0
/*
 * Generic internet control operations (ioctl's).
 */
int
ipx_control_oncpu(struct socket *so, u_long cmd, caddr_t data,
	struct ifnet *ifp, struct thread *td)
{
	struct ifreq *ifr = (struct ifreq *)data;
	struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
	struct ipx_ifaddr *ia;
	struct ifaddr *ifa;
	struct ipx_ifaddr *oia;
	int dstIsNew, hostIsNew;
	int error = 0;

	/*
	 * Find address for this interface, if it exists.
	 */
	if (ifp == NULL)
		return (EADDRNOTAVAIL);
	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
		if (ia->ia_ifp == ifp)
			break;

	switch (cmd) {

	case SIOCGIFADDR:
		if (ia == NULL)
			return (EADDRNOTAVAIL);
		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
		return (0);

	case SIOCGIFBRDADDR:
		if (ia == NULL)
			return (EADDRNOTAVAIL);
		if ((ifp->if_flags & IFF_BROADCAST) == 0)
			return (EINVAL);
		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
		return (0);

	case SIOCGIFDSTADDR:
		if (ia == NULL)
			return (EADDRNOTAVAIL);
		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
			return (EINVAL);
		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
		return (0);
	}

	if ((error = priv_check(td, PRIV_ROOT)) != 0)
		return (error);

	switch (cmd) {
	case SIOCAIFADDR:
	case SIOCDIFADDR:
		if (ifra->ifra_addr.sipx_family == AF_IPX)
		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
			if (ia->ia_ifp == ifp  &&
			    ipx_neteq(ia->ia_addr.sipx_addr,
				  ifra->ifra_addr.sipx_addr))
			    break;
		    }
		if (cmd == SIOCDIFADDR && ia == NULL)
			return (EADDRNOTAVAIL);
		/* FALLTHROUGH */

	case SIOCSIFADDR:
	case SIOCSIFDSTADDR:
		if (ia == NULL) {
			oia = ifa_create(sizeof(*ia), M_WAITOK);
			if ((ia = ipx_ifaddr) != NULL) {
				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
					;
				ia->ia_next = oia;
			} else
				ipx_ifaddr = oia;
			ia = oia;
			ifa = (struct ifaddr *)ia;
			ifa_iflink(ifa, ifp, 1);
			ia->ia_ifp = ifp;
			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;

			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;

			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
			if (ifp->if_flags & IFF_BROADCAST) {
				ia->ia_broadaddr.sipx_family = AF_IPX;
				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
			}
		}
	}

	switch (cmd) {

	case SIOCSIFDSTADDR:
		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
			return (EINVAL);
		if (ia->ia_flags & IFA_ROUTE) {
			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
			ia->ia_flags &= ~IFA_ROUTE;
		}
		if (ifp->if_ioctl) {
			ifnet_serialize_all(ifp);
			error = ifp->if_ioctl(ifp, SIOCSIFDSTADDR,
					      (void *)ia, td->td_proc->p_ucred);
			ifnet_deserialize_all(ifp);
			if (error)
				return (error);
		}
		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
		return (0);

	case SIOCSIFADDR:
		return (ipx_ifinit(ifp, ia,
				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));

	case SIOCDIFADDR:
		ipx_ifscrub(ifp, ia);
		ifa = (struct ifaddr *)ia;
		ifa_ifunlink(ifa, ifp);
		oia = ia;
		if (oia == (ia = ipx_ifaddr)) {
			ipx_ifaddr = ia->ia_next;
		} else {
			while (ia->ia_next && (ia->ia_next != oia)) {
				ia = ia->ia_next;
			}
			if (ia->ia_next)
			    ia->ia_next = oia->ia_next;
			else
				kprintf("Didn't unlink ipxifadr from list\n");
		}
		ifa_destroy(&oia->ia_ifa);
		return (0);
	
	case SIOCAIFADDR:
		dstIsNew = 0;
		hostIsNew = 1;
		if (ia->ia_addr.sipx_family == AF_IPX) {
			if (ifra->ifra_addr.sipx_len == 0) {
				ifra->ifra_addr = ia->ia_addr;
				hostIsNew = 0;
			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
					 ia->ia_addr.sipx_addr))
				hostIsNew = 0;
		}
		if ((ifp->if_flags & IFF_POINTOPOINT) &&
		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
			if (hostIsNew == 0)
				ipx_ifscrub(ifp, ia);
			ia->ia_dstaddr = ifra->ifra_dstaddr;
			dstIsNew  = 1;
		}
		if (ifra->ifra_addr.sipx_family == AF_IPX &&
					    (hostIsNew || dstIsNew))
			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
		return (error);

	default:
		if (ifp->if_ioctl == NULL)
			return (EOPNOTSUPP);
		ifnet_serialize_all(ifp);
		error = ifp->if_ioctl(ifp, cmd, data, td->td_proc->p_ucred);
		ifnet_deserialize_all(ifp);
		return (error);
	}
}
Ejemplo n.º 2
0
int
at_control(struct socket *so, u_long cmd, caddr_t data,
           struct ifnet *ifp, struct thread *td )
{
    struct ifreq	*ifr = (struct ifreq *)data;
    struct sockaddr_at	*sat;
    struct netrange	*nr;
    struct at_aliasreq	*ifra = (struct at_aliasreq *)data;
    struct at_ifaddr	*aa0;
    struct at_ifaddr	*aa = 0;
    struct ifaddr	*ifa, *ifa0;
    int error;

    /*
     * If we have an ifp, then find the matching at_ifaddr if it exists
     */
    if ( ifp ) {
        for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
            if ( aa->aa_ifp == ifp ) break;
        }
    }

    /*
     * In this first switch table we are basically getting ready for
     * the second one, by getting the atalk-specific things set up
     * so that they start to look more similar to other protocols etc.
     */

    switch ( cmd ) {
    case SIOCAIFADDR:
    case SIOCDIFADDR:
        /*
         * If we have an appletalk sockaddr, scan forward of where
         * we are now on the at_ifaddr list to find one with a matching
         * address on this interface.
         * This may leave aa pointing to the first address on the
         * NEXT interface!
         */
        if ( ifra->ifra_addr.sat_family == AF_APPLETALK ) {
            for ( ; aa; aa = aa->aa_next ) {
                if ( aa->aa_ifp == ifp &&
                        sateqaddr( &aa->aa_addr, &ifra->ifra_addr )) {
                    break;
                }
            }
        }
        /*
         * If we a retrying to delete an addres but didn't find such,
         * then rewurn with an error
         */
        if ( cmd == SIOCDIFADDR && aa == 0 ) {
            return( EADDRNOTAVAIL );
        }
    /*FALLTHROUGH*/

    case SIOCSIFADDR:
        /*
         * If we are not superuser, then we don't get to do these ops.
         */
        if (priv_check(td, PRIV_ROOT))
            return(EPERM);

        sat = satosat( &ifr->ifr_addr );
        nr = (struct netrange *)sat->sat_zero;
        if ( nr->nr_phase == 1 ) {
            /*
             * Look for a phase 1 address on this interface.
             * This may leave aa pointing to the first address on the
             * NEXT interface!
             */
            for ( ; aa; aa = aa->aa_next ) {
                if ( aa->aa_ifp == ifp &&
                        ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
                    break;
                }
            }
        } else {		/* default to phase 2 */
            /*
             * Look for a phase 2 address on this interface.
             * This may leave aa pointing to the first address on the
             * NEXT interface!
             */
            for ( ; aa; aa = aa->aa_next ) {
                if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
                    break;
                }
            }
        }

        if ( ifp == 0 )
            panic( "at_control" );

        /*
         * If we failed to find an existing at_ifaddr entry, then we
         * allocate a fresh one.
         */
        if ( aa == NULL ) {
            aa0 = ifa_create(sizeof(struct at_ifaddr), M_WAITOK);
            callout_init(&aa0->aa_ch);
            if (( aa = at_ifaddr ) != NULL ) {
                /*
                 * Don't let the loopback be first, since the first
                 * address is the machine's default address for
                 * binding.
                 * If it is, stick ourself in front, otherwise
                 * go to the back of the list.
                 */
                if ( at_ifaddr->aa_ifp->if_flags & IFF_LOOPBACK ) {
                    aa = aa0;
                    aa->aa_next = at_ifaddr;
                    at_ifaddr = aa;
                } else {
                    for ( ; aa->aa_next; aa = aa->aa_next )
                        ;
                    aa->aa_next = aa0;
                }
            } else {
                at_ifaddr = aa0;
            }
            aa = aa0;

            /*
             * Find the end of the interface's addresses
             * and link our new one on the end
             */
            ifa = (struct ifaddr *)aa;
            ifa_iflink(ifa, ifp, 1);

            /*
             * As the at_ifaddr contains the actual sockaddrs,
             * and the ifaddr itself, link them al together correctly.
             */
            ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr;
            ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr;
            ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask;

            /*
             * Set/clear the phase 2 bit.
             */
            if ( nr->nr_phase == 1 ) {
                aa->aa_flags &= ~AFA_PHASE2;
            } else {
                aa->aa_flags |= AFA_PHASE2;
            }

            /*
             * and link it all together
             */
            aa->aa_ifp = ifp;
        } else {
            /*
             * If we DID find one then we clobber any routes dependent on it..
             */
            at_scrub( ifp, aa );
        }
        break;

    case SIOCGIFADDR :
        sat = satosat( &ifr->ifr_addr );
        nr = (struct netrange *)sat->sat_zero;
        if ( nr->nr_phase == 1 ) {
            /*
             * If the request is specifying phase 1, then
             * only look at a phase one address
             */
            for ( ; aa; aa = aa->aa_next ) {
                if ( aa->aa_ifp == ifp &&
                        ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
                    break;
                }
            }
        } else {
            /*
             * default to phase 2
             */
            for ( ; aa; aa = aa->aa_next ) {
                if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) {
                    break;
                }
            }
        }

        if ( aa == NULL )
            return( EADDRNOTAVAIL );
        break;
    }

    /*
     * By the time this switch is run we should be able to assume that
     * the "aa" pointer is valid when needed.
     */
    switch ( cmd ) {
    case SIOCGIFADDR:

        /*
         * copy the contents of the sockaddr blindly.
         */
        sat = (struct sockaddr_at *)&ifr->ifr_addr;
        *sat = aa->aa_addr;

        /*
         * and do some cleanups
         */
        ((struct netrange *)&sat->sat_zero)->nr_phase
            = (aa->aa_flags & AFA_PHASE2) ? 2 : 1;
        ((struct netrange *)&sat->sat_zero)->nr_firstnet = aa->aa_firstnet;
        ((struct netrange *)&sat->sat_zero)->nr_lastnet = aa->aa_lastnet;
        break;

    case SIOCSIFADDR:
        return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));

    case SIOCAIFADDR:
        if ( sateqaddr( &ifra->ifra_addr, &aa->aa_addr )) {
            return( 0 );
        }
        return( at_ifinit( ifp, aa, (struct sockaddr_at *)&ifr->ifr_addr ));

    case SIOCDIFADDR:
        /*
         * scrub all routes.. didn't we just DO this? XXX yes, del it
         */
        at_scrub( ifp, aa );

        /*
         * remove the ifaddr from the interface
         */
        ifa0 = (struct ifaddr *)aa;
        ifa_ifunlink(ifa0, ifp);

        /*
         * Now remove the at_ifaddr from the parallel structure
         * as well, or we'd be in deep trouble
         */
        aa0 = aa;
        if ( aa0 == ( aa = at_ifaddr )) {
            at_ifaddr = aa->aa_next;
        } else {
            while ( aa->aa_next && ( aa->aa_next != aa0 )) {
                aa = aa->aa_next;
            }

            /*
             * if we found it, remove it, otherwise we screwed up.
             */
            if ( aa->aa_next ) {
                aa->aa_next = aa0->aa_next;
            } else {
                panic( "at_control" );
            }
        }

        /*
         * Now dump the memory we were using.
         * Decrement the reference count.
         * This should probably be the last reference
         * as the count will go from 1 to 0.
         * (unless there is still a route referencing this)
         */
        ifa_destroy(ifa0);
        break;

    default:
        if ( ifp == 0 || ifp->if_ioctl == 0 )
            return( EOPNOTSUPP );
        ifnet_serialize_all(ifp);
        error = ifp->if_ioctl(ifp, cmd, data, td->td_proc->p_ucred);
        ifnet_deserialize_all(ifp);
        return (error);
    }
    return( 0 );
}