示例#1
0
int
ifpoll_deregister(struct ifnet *ifp)
{
	struct netmsg_base nmsg;
	int error;

	if (ifp->if_npoll == NULL)
		return EOPNOTSUPP;

	ifnet_serialize_all(ifp);

	if ((ifp->if_flags & IFF_NPOLLING) == 0) {
		ifnet_deserialize_all(ifp);
		return EINVAL;
	}
	ifp->if_flags &= ~IFF_NPOLLING;

	ifnet_deserialize_all(ifp);

	netmsg_init(&nmsg, NULL, &curthread->td_msgport,
		    0, ifpoll_deregister_handler);
	nmsg.lmsg.u.ms_resultp = ifp;

	error = lwkt_domsg(netisr_portfn(0), &nmsg.lmsg, 0);
	if (!error) {
		ifnet_serialize_all(ifp);
		ifp->if_npoll(ifp, NULL);
		KASSERT(ifp->if_npoll_cpuid < 0, ("invalid npoll cpuid"));
		ifnet_deserialize_all(ifp);
	}
	return error;
}
示例#2
0
/*
 * Initialize an interface's internet address
 * and routing table entry.
 */
static int
ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
	   struct sockaddr_ipx *sipx, int scrub)
{
	struct sockaddr_ipx oldaddr;
	int error;

	/*
	 * Set up new addresses.
	 */
	oldaddr = ia->ia_addr;
	ia->ia_addr = *sipx;

	/*
	 * The convention we shall adopt for naming is that
	 * a supplied address of zero means that "we don't care".
	 * Use the MAC address of the interface. If it is an
	 * interface without a MAC address, like a serial line, the
	 * address must be supplied.
	 *
	 * Give the interface a chance to initialize
	 * if this is its first address,
	 * and to validate the address if necessary.
	 */
	ifnet_serialize_all(ifp);
	if (ifp->if_ioctl != NULL &&
	    (error = ifp->if_ioctl(ifp, SIOCSIFADDR, (void *)ia, NULL))) {
		ia->ia_addr = oldaddr;
		ifnet_deserialize_all(ifp);
		return (error);
	}
	ifnet_deserialize_all(ifp);
	ia->ia_ifa.ifa_metric = ifp->if_metric;
	/*
	 * Add route for the network.
	 */
	if (scrub) {
		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
		ipx_ifscrub(ifp, ia);
		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
	}
	if (ifp->if_flags & IFF_POINTOPOINT)
		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
	else {
		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
	}
	ia->ia_flags |= IFA_ROUTE;
	return (0);
}
示例#3
0
int
ifpoll_register(struct ifnet *ifp)
{
	struct ifpoll_info *info;
	struct netmsg_base nmsg;
	int error;

	if (ifp->if_npoll == NULL) {
		/* Device does not support polling */
		return EOPNOTSUPP;
	}

	info = kmalloc(sizeof(*info), M_TEMP, M_WAITOK | M_ZERO);

	/*
	 * Attempt to register.  Interlock with IFF_NPOLLING.
	 */

	ifnet_serialize_all(ifp);

	if (ifp->if_flags & IFF_NPOLLING) {
		/* Already polling */
		ifnet_deserialize_all(ifp);
		kfree(info, M_TEMP);
		return EBUSY;
	}

	info->ifpi_ifp = ifp;

	ifp->if_flags |= IFF_NPOLLING;
	ifp->if_npoll(ifp, info);
	KASSERT(ifp->if_npoll_cpuid >= 0, ("invalid npoll cpuid"));

	ifnet_deserialize_all(ifp);

	netmsg_init(&nmsg, NULL, &curthread->td_msgport,
		    0, ifpoll_register_handler);
	nmsg.lmsg.u.ms_resultp = info;

	error = lwkt_domsg(netisr_portfn(0), &nmsg.lmsg, 0);
	if (error) {
		if (!ifpoll_deregister(ifp)) {
			if_printf(ifp, "ifpoll_register: "
				  "ifpoll_deregister failed!\n");
		}
	}

	kfree(info, M_TEMP);
	return error;
}
示例#4
0
/*
 * Software interrupt routine, called at spl[soft]net.
 */
static void
pppintr(netmsg_t msg)
{
    struct mbuf *m;
    struct ppp_softc *sc;
    int i;

    /*
     * Packets are never sent to this netisr so the message must always
     * be replied.  Interlock processing and notification by replying
     * the message first.
     */
    lwkt_replymsg(&msg->lmsg, 0);

    get_mplock();

    sc = ppp_softc;
    for (i = 0; i < NPPP; ++i, ++sc) {
	ifnet_serialize_all(&sc->sc_if);
	if (!(sc->sc_flags & SC_TBUSY)
	    && (!ifq_is_empty(&sc->sc_if.if_snd) || !IF_QEMPTY(&sc->sc_fastq))) {
	    sc->sc_flags |= SC_TBUSY;
	    (*sc->sc_start)(sc);
	} 
	for (;;) {
	    IF_DEQUEUE(&sc->sc_rawq, m);
	    if (m == NULL)
		break;
	    ppp_inproc(sc, m);
	}
	ifnet_deserialize_all(&sc->sc_if);
    }
    rel_mplock();
}
示例#5
0
/*
 * Disable multicast routing
 */
int
ip6_mrouter_done(void)
{
	mifi_t mifi;
	int i;
	struct ifnet *ifp;
	struct in6_ifreq ifr;
	struct mf6c *rt;
	struct rtdetq *rte;
	struct lwkt_msg *lmsg = &expire_upcalls_nmsg.lmsg;

	ASSERT_NETISR0;

	if (ip6_mrouter == NULL)
		return EINVAL;

	/*
	 * For each phyint in use, disable promiscuous reception of all IPv6
	 * multicasts.
	 */
#ifdef INET
#ifdef MROUTING
	/*
	 * If there is still IPv4 multicast routing daemon,
	 * we remain interfaces to receive all muliticasted packets.
	 * XXX: there may be an interface in which the IPv4 multicast
	 * daemon is not interested...
	 */
	if (!ip_mrouter)
#endif
#endif
	{
		for (mifi = 0; mifi < nummifs; mifi++) {
			if (mif6table[mifi].m6_ifp &&
			    !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
				ifr.ifr_addr.sin6_family = AF_INET6;
				ifr.ifr_addr.sin6_addr = kin6addr_any;
				ifp = mif6table[mifi].m6_ifp;
				ifnet_serialize_all(ifp);
				ifp->if_ioctl(ifp, SIOCDELMULTI,
					      (caddr_t)&ifr, NULL);
				ifnet_deserialize_all(ifp);
			}
		}
	}
#ifdef notyet
	bzero((caddr_t)qtable, sizeof(qtable));
	bzero((caddr_t)tbftable, sizeof(tbftable));
#endif
	bzero((caddr_t)mif6table, sizeof(mif6table));
	nummifs = 0;

	pim6 = 0; /* used to stub out/in pim specific code */

	callout_stop(&expire_upcalls_ch);
	crit_enter();
	if ((lmsg->ms_flags & MSGF_DONE) == 0)
		lwkt_dropmsg(lmsg);
	crit_exit();

	/*
	 * Free all multicast forwarding cache entries.
	 */
	for (i = 0; i < MF6CTBLSIZ; i++) {
		rt = mf6ctable[i];
		while (rt) {
			struct mf6c *frt;

			for (rte = rt->mf6c_stall; rte != NULL; ) {
				struct rtdetq *n = rte->next;

				m_freem(rte->m);
				kfree(rte, M_MRTABLE);
				rte = n;
			}
			frt = rt;
			rt = rt->mf6c_next;
			kfree(frt, M_MRTABLE);
		}
	}

	bzero((caddr_t)mf6ctable, sizeof(mf6ctable));

	/*
	 * Reset de-encapsulation cache
	 */
	reg_mif_num = -1;

	ip6_mrouter = NULL;
	ip6_mrouter_ver = 0;

#ifdef MRT6DEBUG
	if (mrt6debug)
		log(LOG_DEBUG, "ip6_mrouter_done\n");
#endif

	return 0;
}
示例#6
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);
	}
}
示例#7
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 );
}
示例#8
0
/*
 * given an at_ifaddr,a sockaddr_at and an ifp,
 * bang them all together at high speed and see what happens
 */
static int
at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, struct sockaddr_at *sat)
{
    struct netrange	nr, onr;
    struct sockaddr_at	oldaddr;
    int			error = 0, i, j;
    int			netinc, nodeinc, nnets;
    u_short		net;

    crit_enter();

    /*
     * save the old addresses in the at_ifaddr just in case we need them.
     */
    oldaddr = aa->aa_addr;
    onr.nr_firstnet = aa->aa_firstnet;
    onr.nr_lastnet = aa->aa_lastnet;

    /*
     * take the address supplied as an argument, and add it to the
     * at_ifnet (also given). Remember ing to update
     * those parts of the at_ifaddr that need special processing
     */
    bzero( AA_SAT( aa ), sizeof( struct sockaddr_at ));
    bcopy( sat->sat_zero, &nr, sizeof( struct netrange ));
    bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange ));
    nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1;
    aa->aa_firstnet = nr.nr_firstnet;
    aa->aa_lastnet = nr.nr_lastnet;

    /* XXX ALC */
#if 0
    kprintf("at_ifinit: %s: %u.%u range %u-%u phase %d\n",
            ifp->if_name,
            ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
            ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet),
            (aa->aa_flags & AFA_PHASE2) ? 2 : 1);
#endif

    /*
     * We could eliminate the need for a second phase 1 probe (post
     * autoconf) if we check whether we're resetting the node. Note
     * that phase 1 probes use only nodes, not net.node pairs.  Under
     * phase 2, both the net and node must be the same.
     */
    if ( ifp->if_flags & IFF_LOOPBACK ) {
        AA_SAT( aa )->sat_len = sat->sat_len;
        AA_SAT( aa )->sat_family = AF_APPLETALK;
        AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net;
        AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
#if 0
    } else if ( fp->if_flags & IFF_POINTOPOINT) {
        /* unimplemented */
        /*
         * we'd have to copy the dstaddr field over from the sat
         * but it's not clear that it would contain the right info..
         */
#endif
    } else {
        /*
         * We are a normal (probably ethernet) interface.
         * apply the new address to the interface structures etc.
         * We will probe this address on the net first, before
         * applying it to ensure that it is free.. If it is not, then
         * we will try a number of other randomly generated addresses
         * in this net and then increment the net.  etc.etc. until
         * we find an unused address.
         */
        aa->aa_flags |= AFA_PROBING; /* if not loopback we Must probe? */
        AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at);
        AA_SAT( aa )->sat_family = AF_APPLETALK;
        if ( aa->aa_flags & AFA_PHASE2 ) {
            if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
                /*
                 * If we are phase 2, and the net was not specified
                 * then we select a random net within the supplied netrange.
                 * XXX use /dev/random?
                 */
                if ( nnets != 1 ) {
                    net = ntohs( nr.nr_firstnet ) + time_second % ( nnets - 1 );
                } else {
                    net = ntohs( nr.nr_firstnet );
                }
            } else {
                /*
                 * if a net was supplied, then check that it is within
                 * the netrange. If it is not then replace the old values
                 * and return an error
                 */
                if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) ||
                        ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) {
                    aa->aa_addr = oldaddr;
                    aa->aa_firstnet = onr.nr_firstnet;
                    aa->aa_lastnet = onr.nr_lastnet;
                    crit_exit();
                    return( EINVAL );
                }
                /*
                 * otherwise just use the new net number..
                 */
                net = ntohs( sat->sat_addr.s_net );
            }
        } else {
            /*
             * we must be phase one, so just use whatever we were given.
             * I guess it really isn't going to be used... RIGHT?
             */
            net = ntohs( sat->sat_addr.s_net );
        }

        /*
         * set the node part of the address into the ifaddr.
         * If it's not specified, be random about it...
         * XXX use /dev/random?
         */
        if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) {
            AA_SAT( aa )->sat_addr.s_node = time_second;
        } else {
            AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node;
        }

        /*
         * Copy the phase.
         */
        AA_SAT( aa )->sat_range.r_netrange.nr_phase
            = ((aa->aa_flags & AFA_PHASE2) ? 2:1);

        /*
         * step through the nets in the range
         * starting at the (possibly random) start point.
         */
        for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) +
                (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) {
            AA_SAT( aa )->sat_addr.s_net = htons( net );

            /*
             * using a rather strange stepping method,
             * stagger through the possible node addresses
             * Once again, starting at the (possibly random)
             * initial node address.
             */
            for ( j = 0, nodeinc = time_second | 1; j < 256;
                    j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) {
                if ( AA_SAT( aa )->sat_addr.s_node > 253 ||
                        AA_SAT( aa )->sat_addr.s_node < 1 ) {
                    continue;
                }
                aa->aa_probcnt = 10;

                /*
                 * start off the probes as an asynchronous activity.
                 * though why wait 200mSec?
                 */
                callout_reset(&aa->aa_ch, hz / 5, aarpprobe, ifp);
                if ( tsleep( aa, PCATCH, "at_ifinit", 0 )) {
                    /*
                     * theoretically we shouldn't time out here
                     * so if we returned with an error..
                     */
                    kprintf( "at_ifinit: why did this happen?!\n" );
                    aa->aa_addr = oldaddr;
                    aa->aa_firstnet = onr.nr_firstnet;
                    aa->aa_lastnet = onr.nr_lastnet;
                    crit_exit();
                    return( EINTR );
                }

                /*
                 * The async activity should have woken us up.
                 * We need to see if it was successful in finding
                 * a free spot, or if we need to iterate to the next
                 * address to try.
                 */
                if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
                    break;
                }
            }

            /*
             * of course we need to break out through two loops...
             */
            if (( aa->aa_flags & AFA_PROBING ) == 0 ) {
                break;
            }
            /* reset node for next network */
            AA_SAT( aa )->sat_addr.s_node = time_second;
        }

        /*
         * if we are still trying to probe, then we have finished all
         * the possible addresses, so we need to give up
         */

        if ( aa->aa_flags & AFA_PROBING ) {
            aa->aa_addr = oldaddr;
            aa->aa_firstnet = onr.nr_firstnet;
            aa->aa_lastnet = onr.nr_lastnet;
            crit_exit();
            return( EADDRINUSE );
        }
    }

    /*
     * Now that we have selected an address, we need to tell the interface
     * about it, just in case it needs to adjust something.
     */
    ifnet_serialize_all(ifp);
    if (ifp->if_ioctl &&
            (error = ifp->if_ioctl(ifp, SIOCSIFADDR, (caddr_t)aa, NULL))
       ) {
        /*
         * of course this could mean that it objects violently
         * so if it does, we back out again..
         */
        aa->aa_addr = oldaddr;
        aa->aa_firstnet = onr.nr_firstnet;
        aa->aa_lastnet = onr.nr_lastnet;
        ifnet_deserialize_all(ifp);
        crit_exit();
        return( error );
    }
    ifnet_deserialize_all(ifp);

    /*
     * set up the netmask part of the at_ifaddr
     * and point the appropriate pointer in the ifaddr to it.
     * probably pointless, but what the heck.. XXX
     */
    bzero(&aa->aa_netmask, sizeof(aa->aa_netmask));
    aa->aa_netmask.sat_len = sizeof(struct sockaddr_at);
    aa->aa_netmask.sat_family = AF_APPLETALK;
    aa->aa_netmask.sat_addr.s_net = 0xffff;
    aa->aa_netmask.sat_addr.s_node = 0;
    aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */

    /*
     * Initialize broadcast (or remote p2p) address
     */
    bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr));
    aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at);
    aa->aa_broadaddr.sat_family = AF_APPLETALK;

    aa->aa_ifa.ifa_metric = ifp->if_metric;
    if (ifp->if_flags & IFF_BROADCAST) {
        aa->aa_broadaddr.sat_addr.s_net = htons(0);
        aa->aa_broadaddr.sat_addr.s_node = 0xff;
        aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr;
        /* add the range of routes needed */
        error = aa_dorangeroute(&aa->aa_ifa,
                                ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD );
    }
    else if (ifp->if_flags & IFF_POINTOPOINT) {
        struct at_addr	rtaddr, rtmask;

        bzero(&rtaddr, sizeof(rtaddr));
        bzero(&rtmask, sizeof(rtmask));
        /* fill in the far end if we know it here XXX */
        aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr;
        error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
    }
    else if ( ifp->if_flags & IFF_LOOPBACK ) {
        struct at_addr	rtaddr, rtmask;

        bzero(&rtaddr, sizeof(rtaddr));
        bzero(&rtmask, sizeof(rtmask));
        rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net;
        rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node;
        rtmask.s_net = 0xffff;
        rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */
        error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask);
    }


    /*
     * set the address of our "check if this addr is ours" routine.
     */
    aa->aa_ifa.ifa_claim_addr = aa_claim_addr;

    /*
     * of course if we can't add these routes we back out, but it's getting
     * risky by now XXX
     */
    if ( error ) {
        at_scrub( ifp, aa );
        aa->aa_addr = oldaddr;
        aa->aa_firstnet = onr.nr_firstnet;
        aa->aa_lastnet = onr.nr_lastnet;
        crit_exit();
        return( error );
    }

    /*
     * note that the address has a route associated with it....
     */
    aa->aa_ifa.ifa_flags |= IFA_ROUTE;
    aa->aa_flags |= AFA_ROUTE;
    crit_exit();
    return( 0 );
}
示例#9
0
/*
 * atm_rtrequest: handle ATM rt request (in support of generic code)
 *   inputs: "req" = request code
 *	     "rt" = route entry
 *	     "info" = rt_addrinfo
 */
void
atm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
{
	struct sockaddr *gate = rt->rt_gateway;
	struct atm_pseudoioctl api;
#ifdef NATM
	struct sockaddr_in *sin;
	struct natmpcb *npcb = NULL;
	struct atm_pseudohdr *aph;
#endif
	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
	int error;

	if (rt->rt_flags & RTF_GATEWAY)   /* link level requests only */
		return;

	switch (req) {

	case RTM_RESOLVE: /* resolve: only happens when cloning */
		kprintf("atm_rtrequest: RTM_RESOLVE request detected?\n");
		break;

	case RTM_ADD:

		/*
		 * route added by a command (e.g. ifconfig, route, arp...).
		 *
		 * first check to see if this is not a host route, in which
		 * case we are being called via "ifconfig" to set the address.
		 */

		if ((rt->rt_flags & RTF_HOST) == 0) {
			rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl,
				   RTL_DONTREPORT);
			gate = rt->rt_gateway;
			SDL(gate)->sdl_type = rt->rt_ifp->if_type;
			SDL(gate)->sdl_index = rt->rt_ifp->if_index;
			break;
		}

		if ((rt->rt_flags & RTF_CLONING) != 0) {
			kprintf("atm_rtrequest: cloning route detected?\n");
			break;
		}
		if (gate->sa_family != AF_LINK ||
		    gate->sa_len < sizeof(null_sdl)) {
			log(LOG_DEBUG, "atm_rtrequest: bad gateway value");
			break;
		}

#ifdef DIAGNOSTIC
		if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl");
#endif

#ifdef NATM
		/*
		 * let native ATM know we are using this VCI/VPI
		 * (i.e. reserve it)
		 */
		sin = (struct sockaddr_in *) rt_key(rt);
		if (sin->sin_family != AF_INET)
			goto failed;
		aph = (struct atm_pseudohdr *) LLADDR(SDL(gate));
		npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph),
						ATM_PH_VPI(aph));
		if (npcb == NULL)
			goto failed;
		npcb->npcb_flags |= NPCB_IP;
		npcb->ipaddr.s_addr = sin->sin_addr.s_addr;
		/* XXX: move npcb to llinfo when ATM ARP is ready */
		rt->rt_llinfo =  npcb;
		rt->rt_flags |= RTF_LLINFO;
#endif
		/*
		 * let the lower level know this circuit is active
		 */
		bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph));
		api.rxhand = NULL;
		ifnet_serialize_all(rt->rt_ifp);
		error = rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA,
					     (caddr_t)&api, NULL);
		ifnet_deserialize_all(rt->rt_ifp);
		if (error) {
			kprintf("atm: couldn't add VC\n");
			goto failed;
		}

		SDL(gate)->sdl_type = rt->rt_ifp->if_type;
		SDL(gate)->sdl_index = rt->rt_ifp->if_index;

		break;

failed:
#ifdef NATM
		if (npcb) {
			npcb_free(npcb, NPCB_DESTROY);
			rt->rt_llinfo = NULL;
			rt->rt_flags &= ~RTF_LLINFO;
		}
#endif
		rtrequest(RTM_DELETE, rt_key(rt), NULL,
		    rt_mask(rt), 0, NULL);
		break;

	case RTM_DELETE:

#ifdef NATM
		/*
		 * tell native ATM we are done with this VC
		 */

		if (rt->rt_flags & RTF_LLINFO) {
			npcb_free(rt->rt_llinfo, NPCB_DESTROY);
			rt->rt_llinfo = NULL;
			rt->rt_flags &= ~RTF_LLINFO;
		}
#endif
		/*
		 * tell the lower layer to disable this circuit
		 */

		bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph));
		api.rxhand = NULL;
		ifnet_serialize_all(rt->rt_ifp);
		rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, (caddr_t)&api,
				     NULL);
		ifnet_deserialize_all(rt->rt_ifp);
		break;
	}
}