File:  [DragonFly] / src / sys / netproto / atalk / ddp_input.c
Revision 1.9: download - view: text, annotated - select for diffs
Wed Apr 21 18:13:59 2004 UTC (10 years, 5 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Stable, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_RELEASE_1_4_Slip, DragonFly_RELEASE_1_4, DragonFly_RELEASE_1_2_Slip, DragonFly_RELEASE_1_2, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Fix a netmsg memory leak in the ARP code.  Adjust all ms_cmd function
dispatches to return a proper error code.

Reported-by: multiple people

    1: /*
    2:  * Copyright (c) 1990,1994 Regents of The University of Michigan.
    3:  * All Rights Reserved.  See COPYRIGHT.
    4:  *
    5:  * $FreeBSD: src/sys/netatalk/ddp_input.c,v 1.12 2000/02/13 03:31:58 peter Exp $
    6:  * $DragonFly: src/sys/netproto/atalk/ddp_input.c,v 1.9 2004/04/21 18:13:59 dillon Exp $
    7:  */
    8: 
    9: #include <sys/param.h>
   10: #include <sys/systm.h>
   11: #include <sys/kernel.h>
   12: #include <sys/mbuf.h>
   13: #include <sys/socket.h>
   14: #include <sys/socketvar.h>
   15: 
   16: #include <sys/thread2.h>
   17: #include <sys/msgport2.h>
   18: 
   19: #include <net/if.h>
   20: #include <net/netisr.h>
   21: #include <net/route.h>
   22: #include <net/intrq.h>
   23: 
   24: #include "at.h"
   25: #include "at_var.h"
   26: #include "ddp.h"
   27: #include "ddp_var.h"
   28: #include "at_extern.h"
   29: 
   30: static volatile int	ddp_forward = 1;
   31: static volatile int	ddp_firewall = 0;
   32: static struct ddpstat	ddpstat;
   33: static struct route	forwro;
   34: 
   35: const int atintrq1_present = 1, atintrq2_present = 1;
   36: 
   37: static void     ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int);
   38: 
   39: /*
   40:  * Could probably merge these two code segments a little better...
   41:  */
   42: int
   43: at2intr(struct netmsg *msg)
   44: {
   45: 	struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
   46: 
   47: 	/*
   48: 	 * Phase 2 packet handling 
   49: 	 */
   50: 	ddp_input(m, m->m_pkthdr.rcvif, NULL, 2);
   51: 	lwkt_replymsg(&msg->nm_lmsg, 0);
   52: 	return(EASYNC);
   53: }
   54: 
   55: int
   56: at1intr(struct netmsg *msg)
   57: {
   58: 	struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
   59: 	struct elaphdr *elhp, elh;
   60: 
   61: 	/*
   62: 	 * Phase 1 packet handling 
   63: 	 */
   64: 	if (m->m_len < SZ_ELAPHDR && ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) {
   65: 		ddpstat.ddps_tooshort++;
   66: 		goto out;
   67: 	}
   68: 
   69: 	/*
   70: 	 * This seems a little dubious, but I don't know phase 1 so leave it.
   71: 	 */
   72: 	elhp = mtod(m, struct elaphdr *);
   73: 	m_adj(m, SZ_ELAPHDR);
   74: 
   75: 	if (elhp->el_type == ELAP_DDPEXTEND) {
   76: 		ddp_input(m, m->m_pkthdr.rcvif, NULL, 1);
   77: 	} else {
   78: 		bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR);
   79: 		ddp_input(m, m->m_pkthdr.rcvif, &elh, 1);
   80: 	}
   81: out:
   82: 	lwkt_replymsg(&msg->nm_lmsg, 0);
   83: 	return(EASYNC);
   84: }
   85: 
   86: static void
   87: ddp_input( m, ifp, elh, phase )
   88:     struct mbuf		*m;
   89:     struct ifnet	*ifp;
   90:     struct elaphdr	*elh;
   91:     int			phase;
   92: {
   93:     struct sockaddr_at	from, to;
   94:     struct ddpshdr	*dsh, ddps;
   95:     struct at_ifaddr	*aa;
   96:     struct ddpehdr	*deh = NULL, ddpe;
   97:     struct ddpcb	*ddp;
   98:     int			dlen, mlen;
   99:     u_short		cksum = 0;
  100: 
  101:     bzero( (caddr_t)&from, sizeof( struct sockaddr_at ));
  102:     bzero( (caddr_t)&to, sizeof( struct sockaddr_at ));
  103:     if ( elh ) {
  104: 	/*
  105: 	 * Extract the information in the short header.
  106: 	 * netowrk information is defaulted to ATADDR_ANYNET
  107: 	 * and node information comes from the elh info.
  108: 	 * We must be phase 1.
  109: 	 */
  110: 	ddpstat.ddps_short++;
  111: 
  112: 	if ( m->m_len < sizeof( struct ddpshdr ) &&
  113: 		(( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) {
  114: 	    ddpstat.ddps_tooshort++;
  115: 	    return;
  116: 	}
  117: 
  118: 	dsh = mtod( m, struct ddpshdr *);
  119: 	bcopy( (caddr_t)dsh, (caddr_t)&ddps, sizeof( struct ddpshdr ));
  120: 	ddps.dsh_bytes = ntohl( ddps.dsh_bytes );
  121: 	dlen = ddps.dsh_len;
  122: 
  123: 	to.sat_addr.s_net = ATADDR_ANYNET;
  124: 	to.sat_addr.s_node = elh->el_dnode;
  125: 	to.sat_port = ddps.dsh_dport;
  126: 	from.sat_addr.s_net = ATADDR_ANYNET;
  127: 	from.sat_addr.s_node = elh->el_snode;
  128: 	from.sat_port = ddps.dsh_sport;
  129: 
  130: 	/* 
  131: 	 * Make sure that we point to the phase1 ifaddr info 
  132: 	 * and that it's valid for this packet.
  133: 	 */
  134: 	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
  135: 	    if ( (aa->aa_ifp == ifp)
  136: 	    && ( (aa->aa_flags & AFA_PHASE2) == 0)
  137: 	    && ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node)
  138: 	      || (to.sat_addr.s_node == ATADDR_BCAST))) {
  139: 		break;
  140: 	    }
  141: 	}
  142: 	/* 
  143: 	 * maybe we got a broadcast not meant for us.. ditch it.
  144: 	 */
  145: 	if ( aa == NULL ) {
  146: 	    m_freem( m );
  147: 	    return;
  148: 	}
  149:     } else {
  150: 	/*
  151: 	 * There was no 'elh' passed on. This could still be
  152: 	 * either phase1 or phase2.
  153: 	 * We have a long header, but we may be running on a phase 1 net.
  154: 	 * Extract out all the info regarding this packet's src & dst.
  155: 	 */
  156: 	ddpstat.ddps_long++;
  157: 
  158: 	if ( m->m_len < sizeof( struct ddpehdr ) &&
  159: 		(( m = m_pullup( m, sizeof( struct ddpehdr ))) == 0 )) {
  160: 	    ddpstat.ddps_tooshort++;
  161: 	    return;
  162: 	}
  163: 
  164: 	deh = mtod( m, struct ddpehdr *);
  165: 	bcopy( (caddr_t)deh, (caddr_t)&ddpe, sizeof( struct ddpehdr ));
  166: 	ddpe.deh_bytes = ntohl( ddpe.deh_bytes );
  167: 	dlen = ddpe.deh_len;
  168: 
  169: 	if (( cksum = ddpe.deh_sum ) == 0 ) {
  170: 	    ddpstat.ddps_nosum++;
  171: 	}
  172: 
  173: 	from.sat_addr.s_net = ddpe.deh_snet;
  174: 	from.sat_addr.s_node = ddpe.deh_snode;
  175: 	from.sat_port = ddpe.deh_sport;
  176: 	to.sat_addr.s_net = ddpe.deh_dnet;
  177: 	to.sat_addr.s_node = ddpe.deh_dnode;
  178: 	to.sat_port = ddpe.deh_dport;
  179: 
  180: 	if ( to.sat_addr.s_net == ATADDR_ANYNET ) {
  181: 	    /*
  182: 	     * The TO address doesn't specify a net,
  183: 	     * So by definition it's for this net.
  184: 	     * Try find ifaddr info with the right phase, 
  185: 	     * the right interface, and either to our node, a broadcast,
  186: 	     * or looped back (though that SHOULD be covered in the other
  187: 	     * cases).
  188: 	     *
  189: 	     * XXX If we have multiple interfaces, then the first with
  190: 	     * this node number will match (which may NOT be what we want,
  191: 	     * but it's probably safe in 99.999% of cases.
  192: 	     */
  193: 	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
  194: 		if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) {
  195: 		    continue;
  196: 		}
  197: 		if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) {
  198: 		    continue;
  199: 		}
  200: 		if ( (aa->aa_ifp == ifp)
  201: 		&& ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node)
  202: 		  || (to.sat_addr.s_node == ATADDR_BCAST)
  203: 		  || (ifp->if_flags & IFF_LOOPBACK))) {
  204: 		    break;
  205: 		}
  206: 	    }
  207: 	} else {
  208: 	    /* 
  209: 	     * A destination network was given. We just try to find 
  210: 	     * which ifaddr info matches it.
  211: 	     */
  212: 	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
  213: 		/*
  214: 		 * This is a kludge. Accept packets that are
  215: 		 * for any router on a local netrange.
  216: 		 */
  217: 		if ( to.sat_addr.s_net == aa->aa_firstnet &&
  218: 			to.sat_addr.s_node == 0 ) {
  219: 		    break;
  220: 		}
  221: 		/*
  222: 		 * Don't use ifaddr info for which we are totally outside the
  223: 		 * netrange, and it's not a startup packet.
  224: 		 * Startup packets are always implicitly allowed on to
  225: 		 * the next test.
  226: 		 */
  227: 		if ((( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet ))
  228: 		    || (ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet )))
  229: 		 && (( ntohs( to.sat_addr.s_net ) < 0xff00)
  230: 		    || (ntohs( to.sat_addr.s_net ) > 0xfffe ))) {
  231: 		    continue;
  232: 		}
  233: 
  234: 		/*
  235: 		 * Don't record a match either if we just don't have a match
  236: 		 * in the node address. This can have if the interface
  237: 		 * is in promiscuous mode for example.
  238: 		 */
  239: 		if (( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node)
  240: 		&& (to.sat_addr.s_node != ATADDR_BCAST) ) {
  241: 		    continue;
  242: 		}
  243: 		break;
  244: 	    }
  245: 	}
  246:     }
  247: 
  248:     /*
  249:      * Adjust the length, removing any padding that may have been added
  250:      * at a link layer.  We do this before we attempt to forward a packet,
  251:      * possibly on a different media.
  252:      */
  253:     mlen = m->m_pkthdr.len;
  254:     if ( mlen < dlen ) {
  255: 	ddpstat.ddps_toosmall++;
  256: 	m_freem( m );
  257: 	return;
  258:     }
  259:     if ( mlen > dlen ) {
  260: 	m_adj( m, dlen - mlen );
  261:     }
  262: 
  263:     /*
  264:      * If it aint for a net on any of our interfaces,
  265:      * or it IS for a net on a different interface than it came in on,
  266:      * (and it is not looped back) then consider if we should forward it.
  267:      * As we are not really a router this is a bit cheeky, but it may be
  268:      * useful some day.
  269:      */
  270:     if ( (aa == NULL)
  271:     || ( (to.sat_addr.s_node == ATADDR_BCAST)
  272:       && (aa->aa_ifp != ifp)
  273:       && (( ifp->if_flags & IFF_LOOPBACK ) == 0 ))) {
  274: 	/* 
  275: 	 * If we've explicitly disabled it, don't route anything
  276: 	 */
  277: 	if ( ddp_forward == 0 ) {
  278: 	    m_freem( m );
  279: 	    return;
  280: 	}
  281: 	/* 
  282: 	 * If the cached forwarding route is still valid, use it.
  283: 	 */
  284: 	if ( forwro.ro_rt
  285: 	&& ( satosat(&forwro.ro_dst)->sat_addr.s_net != to.sat_addr.s_net
  286: 	  || satosat(&forwro.ro_dst)->sat_addr.s_node != to.sat_addr.s_node )) {
  287: 	    RTFREE( forwro.ro_rt );
  288: 	    forwro.ro_rt = (struct rtentry *)0;
  289: 	}
  290: 
  291: 	/*
  292: 	 * If we don't have a cached one (any more) or it's useless,
  293: 	 * Then get a new route.
  294: 	 * XXX this could cause a 'route leak'. check this!
  295: 	 */
  296: 	if ( forwro.ro_rt == (struct rtentry *)0
  297: 	|| forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) {
  298: 	    forwro.ro_dst.sa_len = sizeof( struct sockaddr_at );
  299: 	    forwro.ro_dst.sa_family = AF_APPLETALK;
  300: 	    satosat(&forwro.ro_dst)->sat_addr.s_net = to.sat_addr.s_net;
  301: 	    satosat(&forwro.ro_dst)->sat_addr.s_node = to.sat_addr.s_node;
  302: 	    rtalloc(&forwro);
  303: 	}
  304: 
  305: 	/* 
  306: 	 * If it's not going to get there on this hop, and it's
  307: 	 * already done too many hops, then throw it away.
  308: 	 */
  309: 	if ( (to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net)
  310: 	&& (ddpe.deh_hops == DDP_MAXHOPS) ) {
  311: 	    m_freem( m );
  312: 	    return;
  313: 	}
  314: 
  315: 	/*
  316: 	 * A ddp router might use the same interface
  317: 	 * to forward the packet, which this would not effect.
  318: 	 * Don't allow packets to cross from one interface to another however.
  319: 	 */
  320: 	if ( ddp_firewall
  321: 	&& ( (forwro.ro_rt == NULL)
  322: 	  || (forwro.ro_rt->rt_ifp != ifp))) {
  323: 	    m_freem( m );
  324: 	    return;
  325: 	}
  326: 
  327: 	/*
  328: 	 * Adjust the header.
  329: 	 * If it was a short header then it would have not gotten here,
  330: 	 * so we can assume there is room to drop the header in.
  331: 	 * XXX what about promiscuous mode, etc...
  332: 	 */
  333: 	ddpe.deh_hops++;
  334: 	ddpe.deh_bytes = htonl( ddpe.deh_bytes );
  335: 	bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_short )); /* XXX deh? */
  336: 	if ( ddp_route( m, &forwro )) {
  337: 	    ddpstat.ddps_cantforward++;
  338: 	} else {
  339: 	    ddpstat.ddps_forward++;
  340: 	}
  341: 	return;
  342:     }
  343: 
  344:     /*
  345:      * It was for us, and we have an ifaddr to use with it.
  346:      */
  347:     from.sat_len = sizeof( struct sockaddr_at );
  348:     from.sat_family = AF_APPLETALK;
  349: 
  350:     /* 
  351:      * We are no longer interested in the link layer.
  352:      * so cut it off.
  353:      */
  354:     if ( elh ) {
  355: 	m_adj( m, sizeof( struct ddpshdr ));
  356:     } else {
  357: 	if ( ddp_cksum && cksum && cksum != at_cksum( m, sizeof( int ))) {
  358: 	    ddpstat.ddps_badsum++;
  359: 	    m_freem( m );
  360: 	    return;
  361: 	}
  362: 	m_adj( m, sizeof( struct ddpehdr ));
  363:     }
  364: 
  365:     /* 
  366:      * Search for ddp protocol control blocks that match these
  367:      * addresses. 
  368:      */
  369:     if (( ddp = ddp_search( &from, &to, aa )) == NULL ) {
  370: 	m_freem( m );
  371: 	return;
  372:     }
  373: 
  374:     /* 
  375:      * If we found one, deliver th epacket to the socket
  376:      */
  377:     if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from,
  378: 	    m, (struct mbuf *)0 ) == 0 ) {
  379: 	/* 
  380: 	 * If the socket is full (or similar error) dump the packet.
  381: 	 */
  382: 	ddpstat.ddps_nosockspace++;
  383: 	m_freem( m );
  384: 	return;
  385:     }
  386:     /*
  387:      * And wake up whatever might be waiting for it
  388:      */
  389:     sorwakeup( ddp->ddp_socket );
  390: }
  391: 
  392: #if 0
  393: /* As if we haven't got enough of this sort of think floating
  394: around the kernel :) */
  395: 
  396: #define BPXLEN	48
  397: #define BPALEN	16
  398: #include <ctype.h>
  399: char	hexdig[] = "0123456789ABCDEF";
  400: 
  401: static void
  402: bprint( char *data, int len )
  403: {
  404:     char	xout[ BPXLEN ], aout[ BPALEN ];
  405:     int		i = 0;
  406: 
  407:     bzero( xout, BPXLEN );
  408:     bzero( aout, BPALEN );
  409: 
  410:     for ( ;; ) {
  411: 	if ( len < 1 ) {
  412: 	    if ( i != 0 ) {
  413: 		printf( "%s\t%s\n", xout, aout );
  414: 	    }
  415: 	    printf( "%s\n", "(end)" );
  416: 	    break;
  417: 	}
  418: 
  419: 	xout[ (i*3) ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
  420: 	xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ];
  421: 
  422: 	if ( (u_char)*data < 0x7f && (u_char)*data > 0x20 ) {
  423: 	    aout[ i ] = *data;
  424: 	} else {
  425: 	    aout[ i ] = '.';
  426: 	}
  427: 
  428: 	xout[ (i*3) + 2 ] = ' ';
  429: 
  430: 	i++;
  431: 	len--;
  432: 	data++;
  433: 
  434: 	if ( i > BPALEN - 2 ) {
  435: 	    printf( "%s\t%s\n", xout, aout );
  436: 	    bzero( xout, BPXLEN );
  437: 	    bzero( aout, BPALEN );
  438: 	    i = 0;
  439: 	    continue;
  440: 	}
  441:     }
  442: }
  443: 
  444: static void
  445: m_printm( struct mbuf *m )
  446: {
  447:     for (; m; m = m->m_next ) {
  448: 	bprint( mtod( m, char * ), m->m_len );
  449:     }
  450: }
  451: #endif