From 1d0eab59d381985c99cfa2ce981a3551367b27e6 Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Wed, 29 Oct 1997 00:30:52 +0000 Subject: [PATCH] Fix various problems with netatalk kernel support. Some of these changes are a bit rough and will become more polished later. the changes to if_ethersubr should largely be moved to within the appletalk code, but that will happen later. A few of these were related to network-byteorder problems, and more were related to loopback failures. --- sys/net/if_ethersubr.c | 53 ++++++++--- sys/netatalk/aarp.c | 45 ++++----- sys/netatalk/at_control.c | 8 +- sys/netatalk/at_extern.h | 3 +- sys/netatalk/ddp_input.c | 195 ++++++++++++++++++++++++++++---------- sys/netatalk/ddp_output.c | 6 +- 6 files changed, 211 insertions(+), 99 deletions(-) diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index dd056861dd1..190fd473f28 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 - * $Id: if_ethersubr.c,v 1.36 1997/07/15 23:25:32 julian Exp $ + * $Id: if_ethersubr.c,v 1.37 1997/10/28 15:58:31 bde Exp $ */ #include @@ -196,21 +196,46 @@ ether_output(ifp, m0, dst, rt0) #endif #ifdef NETATALK case AF_APPLETALK: - if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) { + { + struct sockaddr_at *sat = (struct sockaddr_at *)dst; + + /* + * super hack.. + * Most of this loopback code should move into the appletalk + * code, but it's here for now.. remember to move it! [JRE] + * This may not get the same interface we started with, + * fix asap. XXX + */ + aa = at_ifawithnet( sat ); + if (aa == NULL) { + goto bad; + } + if( aa->aa_ifa.ifa_ifp != ifp ) { + (*aa->aa_ifa.ifa_ifp->if_output)(aa->aa_ifa.ifa_ifp, + m,dst,rt); + } + if (((sat->sat_addr.s_net == ATADDR_ANYNET) + && (sat->sat_addr.s_node == ATADDR_ANYNODE)) + || ((sat->sat_addr.s_net == aa->aa_addr.sat_addr.s_net ) + && (sat->sat_addr.s_node == aa->aa_addr.sat_addr.s_node))) { + (void) looutput(ifp, m, dst, rt); + return(0); + } + + if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) { #ifdef NETATALKDEBUG - extern char *prsockaddr(struct sockaddr *); - printf("aarpresolv: failed for %s\n", prsockaddr(dst)); + extern char *prsockaddr(struct sockaddr *); + printf("aarpresolv: failed for %s\n", prsockaddr(dst)); #endif NETATALKDEBUG - return (0); - } - /* - * ifaddr is the first thing in at_ifaddr - */ - if ((aa = (struct at_ifaddr *)at_ifawithnet( - (struct sockaddr_at *)dst, &ifp->if_addrhead)) - == 0) - goto bad; - + return (0); + } + + /* + * If broadcasting on a simplex interface, loopback a copy + */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) + mcopy = m_copy(m, 0, (int)M_COPYALL); + } /* * In the phase 2 case, we need to prepend an mbuf for the llc header. * Since we must preserve the value of m, which is passed to us by diff --git a/sys/netatalk/aarp.c b/sys/netatalk/aarp.c index 56c8924291f..ea853683d20 100644 --- a/sys/netatalk/aarp.c +++ b/sys/netatalk/aarp.c @@ -92,31 +92,24 @@ aarptimer(void *ignored) * the given network.. remember to take netranges into * consideration. */ -struct ifaddr * -at_ifawithnet( sat, ifah ) - struct sockaddr_at *sat; - struct ifaddrhead *ifah; +struct at_ifaddr * +at_ifawithnet(struct sockaddr_at *sat ) { + struct at_ifaddr *aa; struct sockaddr_at *sat2; - struct netrange *nr; - struct ifaddr *ifa; - for (ifa = ifah->tqh_first; ifa; ifa = ifa->ifa_link.tqe_next ) { - if ( ifa->ifa_addr->sa_family != AF_APPLETALK ) { - continue; + for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + sat2 = &(aa->aa_addr); + if ( sat2->sat_addr.s_net == sat->sat_addr.s_net ) { + break; + } + if( (aa->aa_flags & AFA_PHASE2 ) + && (ntohs(aa->aa_firstnet) <= ntohs(sat->sat_addr.s_net)) + && (ntohs(aa->aa_lastnet) >= ntohs(sat->sat_addr.s_net))) { + break; + } } - 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 ); + return( aa ); } static void @@ -154,8 +147,7 @@ aarpwhohas( struct arpcom *ac, struct sockaddr_at *sat ) * interface with the same address as we're looking for. If the * net is phase 2, generate an 802.2 and SNAP header. */ - if ((aa = (struct at_ifaddr *)at_ifawithnet(sat, &ac->ac_if.if_addrhead)) - == NULL) { + if ((aa = at_ifawithnet( sat )) == NULL) { m_freem( m ); return; } @@ -212,8 +204,8 @@ aarpresolve( ac, m, destsat, desten ) int s; if ( at_broadcast( destsat )) { - if ((aa = (struct at_ifaddr *)at_ifawithnet(destsat, - &((struct ifnet *)ac)->if_addrhead)) == NULL) { + m->m_flags |= M_BCAST; + if ((aa = at_ifawithnet( destsat )) == NULL) { m_freem( m ); return( 0 ); } @@ -324,8 +316,7 @@ at_aarpinput( struct arpcom *ac, struct mbuf *m) sat.sat_len = sizeof(struct sockaddr_at); sat.sat_family = AF_APPLETALK; sat.sat_addr.s_net = net; - if ((aa = (struct at_ifaddr *)at_ifawithnet(&sat, - &ac->ac_if.if_addrhead)) == NULL) { + if ((aa = at_ifawithnet( &sat )) == NULL) { m_freem( m ); return; } diff --git a/sys/netatalk/at_control.c b/sys/netatalk/at_control.c index 3777a23b2c9..60f65ed4dcd 100644 --- a/sys/netatalk/at_control.c +++ b/sys/netatalk/at_control.c @@ -861,10 +861,10 @@ aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw0) */ if ((addr->sat_addr.s_net == gw->sat_addr.s_net) || ((addr->sat_range.r_netrange.nr_lastnet) - && (gw->sat_addr.s_net - >= addr->sat_range.r_netrange.nr_firstnet ) - && (gw->sat_addr.s_net - <= addr->sat_range.r_netrange.nr_lastnet ))) { + && (ntohs(gw->sat_addr.s_net) + >= ntohs(addr->sat_range.r_netrange.nr_firstnet )) + && (ntohs(gw->sat_addr.s_net) + <= ntohs(addr->sat_range.r_netrange.nr_lastnet )))) { return 1; } break; diff --git a/sys/netatalk/at_extern.h b/sys/netatalk/at_extern.h index 661684c666b..07454253e96 100644 --- a/sys/netatalk/at_extern.h +++ b/sys/netatalk/at_extern.h @@ -21,8 +21,7 @@ extern int at_control __P(( struct socket *so, struct proc *p )); extern u_short at_cksum __P(( struct mbuf *m, int skip)); extern void ddp_init __P((void )); -extern struct ifaddr *at_ifawithnet __P((struct sockaddr_at *, - struct ifaddrhead *)); +extern struct at_ifaddr *at_ifawithnet __P((struct sockaddr_at *)); #ifdef _NETATALK_DDP_VAR_H_ extern int ddp_output __P((struct mbuf *m, struct socket *so)); diff --git a/sys/netatalk/ddp_input.c b/sys/netatalk/ddp_input.c index 411dfde421f..8717682fbd0 100644 --- a/sys/netatalk/ddp_input.c +++ b/sys/netatalk/ddp_input.c @@ -40,6 +40,9 @@ atintr( void ) struct at_ifaddr *aa; int s; + /* + * First pull off all the phase 2 packets. + */ for (;;) { s = splimp(); @@ -52,19 +55,12 @@ atintr( void ) } ifp = m->m_pkthdr.rcvif; - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { - break; - } - } - if ( aa == NULL ) { /* ifp not an appletalk interface */ - m_freem( m ); - continue; - } - ddp_input( m, ifp, (struct elaphdr *)NULL, 2 ); } + /* + * Then pull off all the phase 1 packets. + */ for (;;) { s = splimp(); @@ -77,15 +73,6 @@ atintr( void ) } ifp = m->m_pkthdr.rcvif; - for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { - break; - } - } - if ( aa == NULL ) { /* ifp not an appletalk interface */ - m_freem( m ); - continue; - } if ( m->m_len < SZ_ELAPHDR && (( m = m_pullup( m, SZ_ELAPHDR )) == 0 )) { @@ -93,6 +80,9 @@ atintr( void ) continue; } + /* + * this seems a little dubios, but I don't know phase 1 so leave it. + */ elhp = mtod( m, struct elaphdr *); m_adj( m, SZ_ELAPHDR ); @@ -124,7 +114,14 @@ ddp_input( m, ifp, elh, phase ) u_short cksum = 0; bzero( (caddr_t)&from, sizeof( struct sockaddr_at )); + bzero( (caddr_t)&to, sizeof( struct sockaddr_at )); if ( elh ) { + /* + * Extract the information in the short header. + * netowrk information is defaulted to ATADDR_ANYNET + * and node information comes from the elh info. + * We must be phase 1. + */ ddpstat.ddps_short++; if ( m->m_len < sizeof( struct ddpshdr ) && @@ -145,18 +142,32 @@ ddp_input( m, ifp, elh, phase ) from.sat_addr.s_node = elh->el_snode; from.sat_port = ddps.dsh_sport; + /* + * Make sure that we point to the phase1 ifaddr info + * and that it's valid for this packet. + */ for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { - if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 && - ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || - to.sat_addr.s_node == ATADDR_BCAST )) { + if ( (aa->aa_ifp == ifp) + && ( (aa->aa_flags & AFA_PHASE2) == 0) + && ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node) + || (to.sat_addr.s_node == ATADDR_BCAST))) { break; } } + /* + * maybe we got a broadcast not meant for us.. ditch it. + */ if ( aa == NULL ) { m_freem( m ); return; } } else { + /* + * There was no 'elh' passed on. This could still be + * either phase1 or phase2. + * We have a long header, but we may be running on a pahse 1 net. + * Extract out all the info regarding this packet's src & dst. + */ ddpstat.ddps_long++; if ( m->m_len < sizeof( struct ddpehdr ) && @@ -182,6 +193,18 @@ ddp_input( m, ifp, elh, phase ) to.sat_port = ddpe.deh_dport; if ( to.sat_addr.s_net == ATADDR_ANYNET ) { + /* + * The TO address doesn't specify a net, + * So by definition it's for this net. + * Try find ifaddr info with the right phase, + * the right interface, and either to our node, a bradcast, + * or looped back (though that SHOULD be covered in the other + * cases). + * + * XXX If we have multiple interfaces, then the first with + * this node number will match (which may NOT be what we want, + * but it's probably safe in 99.999% of cases. + */ for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) { continue; @@ -189,27 +212,47 @@ ddp_input( m, ifp, elh, phase ) if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { continue; } - if ( aa->aa_ifp == ifp && - ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || - to.sat_addr.s_node == ATADDR_BCAST || - ( ifp->if_flags & IFF_LOOPBACK ))) { + if ( (aa->aa_ifp == ifp) + && ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node) + || (to.sat_addr.s_node == ATADDR_BCAST) + || (ifp->if_flags & IFF_LOOPBACK))) { break; } } } else { + /* + * A destination network was given. We just try to find + * which ifaddr info matches it. + */ for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { + /* + * This is a kludge. Accept packets that are + * for any router on a local netrange. + */ if ( to.sat_addr.s_net == aa->aa_firstnet && to.sat_addr.s_node == 0 ) { break; } - if (( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet ) || - ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet )) && - ( ntohs( to.sat_addr.s_net ) < ntohs( 0xff00 ) || - ntohs( to.sat_addr.s_net ) > ntohs( 0xfffe ))) { + /* + * Don't use ifaddr info for which we are totally outside the + * netrange, and it's not a startup packet. + * Startup packets are always implicitly allowed on to + * the next test. + */ + if ((( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet )) + || (ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet ))) + && (( ntohs( to.sat_addr.s_net ) < ntohs( 0xff00 )) + || (ntohs( to.sat_addr.s_net ) > ntohs( 0xfffe )))) { continue; } - if ( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node && - to.sat_addr.s_node != ATADDR_BCAST ) { + + /* + * Don't record a match either if we just don't have a match + * in the node address. This can have if the interface + * is in promiscuous mode for example. + */ + if (( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node) + && (to.sat_addr.s_node != ATADDR_BCAST) ) { continue; } break; @@ -233,43 +276,75 @@ ddp_input( m, ifp, elh, phase ) } /* - * XXX Should we deliver broadcasts locally, also, or rely on the - * link layer to give us a copy? For the moment, the latter. + * If it aint for a net on any of our interfaces, + * or it IS for a net on a different interface than it came in on, + * (and it is not looped back) then consider if we shoulf forward it. + * As we a re not really a router this is a bit cheaky, but it may be + * useful some day. */ - if ( aa == NULL || ( to.sat_addr.s_node == ATADDR_BCAST && - aa->aa_ifp != ifp && ( ifp->if_flags & IFF_LOOPBACK ) == 0 )) { + if ( (aa == NULL) + || ( (to.sat_addr.s_node == ATADDR_BCAST) + && (aa->aa_ifp != ifp) + && (( ifp->if_flags & IFF_LOOPBACK ) == 0 ))) { + /* + * If we've explicitly disabled it, don't route anything + */ if ( ddp_forward == 0 ) { m_freem( m ); return; } - if ( forwro.ro_rt && ( satosat( &forwro.ro_dst )->sat_addr.s_net != - to.sat_addr.s_net || - satosat( &forwro.ro_dst )->sat_addr.s_node != - to.sat_addr.s_node )) { + /* + * If the cached forwarding route is still valid, use it. + */ + if ( forwro.ro_rt + && ( satosat(&forwro.ro_dst)->sat_addr.s_net != to.sat_addr.s_net + || satosat(&forwro.ro_dst)->sat_addr.s_node != to.sat_addr.s_node )) { RTFREE( forwro.ro_rt ); forwro.ro_rt = (struct rtentry *)0; } - if ( forwro.ro_rt == (struct rtentry *)0 || - forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) { + + /* + * If we don't have a cached one (any more) or it's useless, + * Then get a new route. + * XXX this could cause a 'route leak'. check this! + */ + if ( forwro.ro_rt == (struct rtentry *)0 + || forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) { forwro.ro_dst.sa_len = sizeof( struct sockaddr_at ); forwro.ro_dst.sa_family = AF_APPLETALK; - satosat( &forwro.ro_dst )->sat_addr.s_net = to.sat_addr.s_net; - satosat( &forwro.ro_dst )->sat_addr.s_node = to.sat_addr.s_node; - rtalloc( &forwro ); + satosat(&forwro.ro_dst)->sat_addr.s_net = to.sat_addr.s_net; + satosat(&forwro.ro_dst)->sat_addr.s_node = to.sat_addr.s_node; + rtalloc(&forwro); } - if ( to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net && - ddpe.deh_hops == DDP_MAXHOPS ) { + /* + * If it's not going to get there on this hop, and it's + * already done too many hops, then throw it away. + */ + if ( (to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net) + && (ddpe.deh_hops == DDP_MAXHOPS) ) { m_freem( m ); return; } - if ( ddp_firewall && - ( forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp != ifp )) { + /* + * A ddp router might use the same interface + * to forward the packet, which this would not effect. + * Don't allow packets to cross from one interface to another however. + */ + if ( ddp_firewall + && ( (forwro.ro_rt == NULL) + || (forwro.ro_rt->rt_ifp != ifp))) { m_freem( m ); return; } + /* + * Adjust the header. + * If it was a short header then it would have not gotten here, + * so we can assume there is room to drop the header in. + * XXX what about promiscuous mode, etc... + */ ddpe.deh_hops++; ddpe.deh_bytes = htonl( ddpe.deh_bytes ); bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_short )); /* XXX deh? */ @@ -281,9 +356,16 @@ ddp_input( m, ifp, elh, phase ) return; } + /* + * It was for us, and we have an ifaddr to use with it. + */ from.sat_len = sizeof( struct sockaddr_at ); from.sat_family = AF_APPLETALK; + /* + * We are no longer interested in the link layer. + * so cut it off. + */ if ( elh ) { m_adj( m, sizeof( struct ddpshdr )); } else { @@ -295,21 +377,36 @@ ddp_input( m, ifp, elh, phase ) m_adj( m, sizeof( struct ddpehdr )); } + /* + * Search for ddp protocol control blocks that match these + * addresses. + */ if (( ddp = ddp_search( &from, &to, aa )) == NULL ) { m_freem( m ); return; } + /* + * If we found one, deliver th epacket to the socket + */ if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from, m, (struct mbuf *)0 ) == 0 ) { + /* + * If the socket is full (or similar error) dump the packet. + */ ddpstat.ddps_nosockspace++; m_freem( m ); return; } + /* + * And wake up whatever might be waiting for it + */ sorwakeup( ddp->ddp_socket ); } #if 0 +/* As if we haven't got enough of this sort of think floating +around the kernel :) */ #define BPXLEN 48 #define BPALEN 16 diff --git a/sys/netatalk/ddp_output.c b/sys/netatalk/ddp_output.c index 96de7cab8f3..acaf47ea2d9 100644 --- a/sys/netatalk/ddp_output.c +++ b/sys/netatalk/ddp_output.c @@ -124,11 +124,11 @@ ddp_route( struct mbuf *m, struct route *ro) if ( (ro->ro_rt != NULL) && ( ro->ro_rt->rt_ifa ) && ( ifp = ro->ro_rt->rt_ifa->ifa_ifp )) { - net = satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net; + net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net); for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { if (((net == 0) || (aa->aa_ifp == ifp)) && - ntohs( net ) >= ntohs( aa->aa_firstnet ) && - ntohs( net ) <= ntohs( aa->aa_lastnet )) { + net >= ntohs( aa->aa_firstnet ) && + net <= ntohs( aa->aa_lastnet )) { break; } }