diff options
author | julian <julian@FreeBSD.org> | 1996-08-29 23:16:34 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1996-08-29 23:16:34 +0000 |
commit | d6528e09bf2fc871352eefbf24f1b16ddf66d4dc (patch) | |
tree | 65b5b5c549f41604eb4e02921b682acae58daf1e | |
parent | 60f630a42e2406bcb512c9f1b5b2a2571304d5b7 (diff) | |
download | FreeBSD-src-d6528e09bf2fc871352eefbf24f1b16ddf66d4dc.zip FreeBSD-src-d6528e09bf2fc871352eefbf24f1b16ddf66d4dc.tar.gz |
Massively COMMENT at_control.c
and fix some bugs..
also fix a bug in aarp.c that didn't take netranges into account.
default routes now work with appletalk, which is a poor-man's
way of being able to access netranges if you only have one network :)
Hopefully the full netranges fix will happen soon.
-rw-r--r-- | sys/netatalk/aarp.c | 17 | ||||
-rw-r--r-- | sys/netatalk/at_control.c | 304 |
2 files changed, 278 insertions, 43 deletions
diff --git a/sys/netatalk/aarp.c b/sys/netatalk/aarp.c index 68c243f..1d7e029 100644 --- a/sys/netatalk/aarp.c +++ b/sys/netatalk/aarp.c @@ -89,20 +89,33 @@ aarptimer(void *ignored) } } +/* + * search through the network addresses to find one that includes + * the given network.. remember to take netranges into + * consideration. + */ struct ifaddr * at_ifawithnet( sat, ifa ) struct sockaddr_at *sat; struct ifaddr *ifa; { + struct sockaddr_at *sat2; + struct netrange *nr; for (; ifa; ifa = ifa->ifa_next ) { if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) { continue; } - if ( satosat( ifa->ifa_addr )->sat_addr.s_net == - sat->sat_addr.s_net ) { + sat2 = satosat( ifa->ifa_addr ); + if ( sat2->sat_addr.s_net == sat->sat_addr.s_net ) { break; } + nr = (struct netrange *)(sat2->sat_zero); + if( (nr->nr_phase == 2 ) + && (nr->nr_firstnet <= sat->sat_addr.s_net) + && (nr->nr_lastnet >= sat->sat_addr.s_net)) { + break; + } } return( ifa ); } diff --git a/sys/netatalk/at_control.c b/sys/netatalk/at_control.c index a2d3a4e..955f751 100644 --- a/sys/netatalk/at_control.c +++ b/sys/netatalk/at_control.c @@ -53,15 +53,31 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) struct mbuf *m; struct ifaddr *ifa; + /* + * 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 && @@ -70,12 +86,19 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) } } } + /* + * 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 ( suser(p->p_ucred, &p->p_acflag) ) { return( EPERM ); } @@ -83,6 +106,11 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) 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 ) { @@ -90,6 +118,11 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) } } } 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; @@ -100,6 +133,11 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) if ( ifp == 0 ) panic( "at_control" ); + /* + * If we failed to find an existing at_ifaddr entry, then we + * allocate a fresh one. + * XXX change this to use malloc + */ if ( aa == (struct at_ifaddr *) 0 ) { m = m_getclr( M_WAIT, MT_IFADDR ); if ( m == (struct mbuf *)NULL ) { @@ -111,6 +149,8 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) * 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 = mtod( m, struct at_ifaddr *); @@ -127,6 +167,10 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) aa = mtod( m, struct at_ifaddr *); + /* + * Find the end of the interface's addresses + * and link our new one on the end + */ if (( ifa = ifp->if_addrlist ) != NULL ) { for ( ; ifa->ifa_next; ifa = ifa->ifa_next ) ; @@ -135,6 +179,10 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) ifp->if_addrlist = (struct ifaddr *)aa; } + /* + * As the at_ifaddr contains the actual sockaddrs, + * and the ifaddr itself, link them al together correctly. + */ aa->aa_ifa.ifa_addr = (struct sockaddr *)&aa->aa_addr; aa->aa_ifa.ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; aa->aa_ifa.ifa_netmask = (struct sockaddr *)&aa->aa_netmask; @@ -147,8 +195,15 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) } 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; @@ -157,13 +212,20 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) 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 */ + } else { + /* + * default to phase 2 + */ for ( ; aa; aa = aa->aa_next ) { if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { break; @@ -176,10 +238,22 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) 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; @@ -196,13 +270,24 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) 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 + */ if (( ifa = ifp->if_addrlist ) == (struct ifaddr *)aa ) { ifp->if_addrlist = ifa->ifa_next; } else { while ( ifa->ifa_next && ( ifa->ifa_next != (struct ifaddr *)aa )) { ifa = ifa->ifa_next; } + + /* + * if we found it, remove it, otherwise we screwed up. + */ if ( ifa->ifa_next ) { ifa->ifa_next = ((struct ifaddr *)aa)->ifa_next; } else { @@ -210,6 +295,10 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) } } + /* + * 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; @@ -217,12 +306,20 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) 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 + */ m_free( dtom( aa0 )); break; @@ -234,6 +331,12 @@ at_control( int cmd, caddr_t data, struct ifnet *ifp, struct proc *p ) return( 0 ); } +/* + * Given an interface and an at_ifaddr (supposedly on that interface) + * remove any routes that depend on this. + * Why ifp is needed I'm not sure, + * as aa->at_ifaddr.ifa_ifp should be the same. + */ static int at_scrub( ifp, aa ) struct ifnet *ifp; @@ -252,6 +355,10 @@ at_scrub( ifp, aa ) 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( ifp, aa, sat ) struct ifnet *ifp; @@ -264,14 +371,22 @@ at_ifinit( ifp, aa, sat ) int flags = RTF_UP, netinc, nodeinc, nnets; u_short net; + /* + * 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; - - onr.nr_firstnet = aa->aa_firstnet; - onr.nr_lastnet = aa->aa_lastnet; aa->aa_firstnet = nr.nr_firstnet; aa->aa_lastnet = nr.nr_lastnet; @@ -296,19 +411,42 @@ at_ifinit( ifp, aa, sat ) #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 { - aa->aa_flags |= AFA_PROBING; + /* + * 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.tv_sec % ( 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; @@ -316,22 +454,44 @@ at_ifinit( ifp, aa, sat ) aa->aa_lastnet = onr.nr_lastnet; 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.tv_sec; } else { AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; } + /* + * 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.tv_sec | 1; j < 256; j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) { if ( AA_SAT( aa )->sat_addr.s_node > 253 || @@ -339,20 +499,40 @@ at_ifinit( ifp, aa, sat ) continue; } aa->aa_probcnt = 10; + + /* + * start off the probes as an asynchronous activity. + * though why wait 200mSec? + */ timeout( (timeout_func_t)aarpprobe, (caddr_t)ifp, hz / 5 ); splx( s ); if ( tsleep( aa, PPAUSE|PCATCH, "at_ifinit", 0 )) { + /* + * theoretically we shouldn't time out here + * so if we returned with an error.. + */ printf( "at_ifinit: why did this happen?!\n" ); aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; 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. + */ s = splimp(); 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; } @@ -360,6 +540,11 @@ at_ifinit( ifp, aa, sat ) AA_SAT( aa )->sat_addr.s_node = time.tv_sec; } + /* + * 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; @@ -369,8 +554,16 @@ at_ifinit( ifp, aa, sat ) } } + /* + * Now that we have selected an address, we need to tell the interface + * about it, just in case it needs to adjust something. + */ if ( ifp->if_ioctl && ( error = (*ifp->if_ioctl)( ifp, SIOCSIFADDR, (caddr_t)aa ))) { + /* + * 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; @@ -378,54 +571,57 @@ at_ifinit( ifp, aa, sat ) return( error ); } -#if 1 -/* this works */ - aa->aa_netmask.sat_len = 6/*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 */ - -#else -/* this doesn't */ - /* Initialize netmask and broadcast address */ - + /* + * set up the netmask part of the at_ifaddr + * and point the appropriate pointer in the ifaddr to it. + */ 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; + 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_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr; aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); aa->aa_broadaddr.sat_family = AF_APPLETALK; - /* "Add a route to the network" */ - 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_netmask.sat_addr.s_net = htons(0xffff); /* XXX */ aa->aa_netmask.sat_addr.s_node = 0; /* XXX */ - } else if (ifp->if_flags & IFF_LOOPBACK) { + aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr; + } +#if 0 + else if (ifp->if_flags & IFF_LOOPBACK) { aa->aa_ifa.ifa_dstaddr = aa->aa_ifa.ifa_addr; aa->aa_netmask.sat_addr.s_net = htons(0xffff); /* XXX */ aa->aa_netmask.sat_addr.s_node = 0xff; /* XXX */ flags |= RTF_HOST; - } else if (ifp->if_flags & IFF_POINTOPOINT) { - aa->aa_ifa.ifa_dstaddr = aa->aa_ifa.ifa_addr; + } +#endif + else if (ifp->if_flags & IFF_POINTOPOINT) { + aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr; aa->aa_netmask.sat_addr.s_net = htons(0xffff); aa->aa_netmask.sat_addr.s_node = 0xff; flags |= RTF_HOST; } -#endif - error = rtinit(&aa->aa_ifa, RTM_ADD, flags); -#if 0 + /* + * Now that we have selected an address, it becomes + * important that we start setting up the routing table so that + * we can actually USE that address. + */ + if ( ifp->if_flags & IFF_LOOPBACK ) { +#if 1 + error = rtinit(&aa->aa_ifa, RTM_ADD, flags); +#else struct at_addr rtaddr, rtmask; bzero(&rtaddr, sizeof(rtaddr)); @@ -433,12 +629,15 @@ at_ifinit( ifp, aa, sat ) 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 = 0xff; + rtmask.s_node = 0x0; + flags |= RTF_HOST; error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); - +#endif } else { - +#if 1 + error = rtinit(&aa->aa_ifa, RTM_ADD, flags); +#else /* Install routes for our own network, and then also for all networks above and below it in the network range */ @@ -454,10 +653,14 @@ at_ifinit( ifp, aa, sat ) error = aa_addrangeroute(&aa->aa_ifa, ntohs(aa->aa_addr.sat_addr.s_net) + 1, ntohs(aa->aa_lastnet) + 1); - } #endif + } + /* + * of course if we can't add these routes we back out, but it's getting + * risky by now XXX + */ if ( error ) { aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; @@ -466,30 +669,46 @@ at_ifinit( ifp, aa, sat ) return( error ); } + /* + * note that the address has a route associated with it.... + */ aa->aa_ifa.ifa_flags |= IFA_ROUTE; aa->aa_flags |= AFA_ROUTE; splx( s ); return( 0 ); } +/* + * check whether a given address is a broadcast address for us.. + */ int at_broadcast( sat ) struct sockaddr_at *sat; { struct at_ifaddr *aa; + /* + * If the node is not right, it can't be a broadcast + */ if ( sat->sat_addr.s_node != ATADDR_BCAST ) { return( 0 ); } + + /* + * If the node was right then if the net is right, it's a broadcast + */ if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { return( 1 ); - } else { - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if (( aa->aa_ifp->if_flags & IFF_BROADCAST ) && - ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) && - ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) { - return( 1 ); - } + } + + /* + * failing that, if the net is one we have, it's a broadcast as well. + */ + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + if (( aa->aa_ifp->if_flags & IFF_BROADCAST ) + && ( ntohs( sat->sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) + && ntohs( sat->sat_addr.s_net ) <= ntohs( aa->aa_lastnet ))) { + return( 1 ); } } return( 0 ); @@ -609,7 +828,7 @@ aa_delsingleroute(struct ifaddr *ifa, error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0); if (error) - printf("aa_delsingleroute: error %d\n", error); + printf("aa_delsingleroute: error %d\n", error); return(error); } @@ -625,12 +844,15 @@ aa_dosingleroute(struct ifaddr *ifa, addr.sat_len = sizeof(struct sockaddr_at); addr.sat_addr.s_net = at_addr->s_net; addr.sat_addr.s_node = at_addr->s_node; + mask.sat_family = AF_APPLETALK; + mask.sat_len = sizeof(struct sockaddr_at); mask.sat_addr.s_net = at_mask->s_net; mask.sat_addr.s_node = at_mask->s_node; if (at_mask->s_node) flags |= RTF_HOST; - return(rtrequest(cmd, (struct sockaddr *) &addr, ifa->ifa_addr, - (struct sockaddr *) &mask, flags, NULL)); + return(rtrequest(cmd, (struct sockaddr *) &addr, + (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), + (struct sockaddr *) &mask, flags, NULL)); } #if 0 |