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; }
/* * 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); }
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; }
/* * 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(); }
/* * 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; }
/* * 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); } }
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 ); }
/* * 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 ); }
/* * 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; } }