ddp_output.c revision 18207
115885Sjulian/*
215885Sjulian * Copyright (c) 1990,1991 Regents of The University of Michigan.
315885Sjulian * All Rights Reserved.
415885Sjulian *
515885Sjulian * Permission to use, copy, modify, and distribute this software and
615885Sjulian * its documentation for any purpose and without fee is hereby granted,
715885Sjulian * provided that the above copyright notice appears in all copies and
815885Sjulian * that both that copyright notice and this permission notice appear
915885Sjulian * in supporting documentation, and that the name of The University
1015885Sjulian * of Michigan not be used in advertising or publicity pertaining to
1115885Sjulian * distribution of the software without specific, written prior
1215885Sjulian * permission. This software is supplied as is without expressed or
1315885Sjulian * implied warranties of any kind.
1415885Sjulian *
1515885Sjulian *	Research Systems Unix Group
1615885Sjulian *	The University of Michigan
1715885Sjulian *	c/o Mike Clark
1815885Sjulian *	535 W. William Street
1915885Sjulian *	Ann Arbor, Michigan
2015885Sjulian *	+1-313-763-0525
2115885Sjulian *	netatalk@itd.umich.edu
2215885Sjulian */
2315885Sjulian
2415885Sjulian#include <sys/types.h>
2515885Sjulian#include <sys/param.h>
2615885Sjulian#include <sys/systm.h>
2715885Sjulian#include <sys/mbuf.h>
2815885Sjulian#include <sys/socket.h>
2915885Sjulian#include <sys/errno.h>
3015885Sjulian#include <sys/syslog.h>
3115885Sjulian
3215885Sjulian#include <net/if.h>
3315885Sjulian#include <net/route.h>
3415885Sjulian
3515885Sjulian#include <netinet/in.h>
3615885Sjulian#undef s_net
3715885Sjulian#include <netinet/if_ether.h>
3815885Sjulian
3918207Sbde#include <netatalk/at.h>
4018207Sbde#include <netatalk/at_var.h>
4118207Sbde#include <netatalk/endian.h>
4218207Sbde#include <netatalk/ddp.h>
4318207Sbde#include <netatalk/ddp_var.h>
4415885Sjulian#include <netatalk/at_extern.h>
4515885Sjulian
4615885Sjulianint	ddp_cksum = 1;
4715885Sjulian
4815885Sjulianint
4915885Sjulianddp_output( struct ddpcb *ddp, struct mbuf *m)
5015885Sjulian{
5115885Sjulian    struct ddpehdr	*deh;
5215885Sjulian
5315885Sjulian    M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
5415885Sjulian
5515885Sjulian    deh = mtod( m, struct ddpehdr *);
5615885Sjulian    deh->deh_pad = 0;
5715885Sjulian    deh->deh_hops = 0;
5815885Sjulian
5915885Sjulian    deh->deh_len = m->m_pkthdr.len;
6015885Sjulian
6115885Sjulian    deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
6215885Sjulian    deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
6315885Sjulian    deh->deh_dport = ddp->ddp_fsat.sat_port;
6415885Sjulian    deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
6515885Sjulian    deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
6615885Sjulian    deh->deh_sport = ddp->ddp_lsat.sat_port;
6715885Sjulian
6815885Sjulian    /*
6915885Sjulian     * The checksum calculation is done after all of the other bytes have
7015885Sjulian     * been filled in.
7115885Sjulian     */
7215885Sjulian    if ( ddp_cksum ) {
7315885Sjulian	deh->deh_sum = at_cksum( m, sizeof( int ));
7415885Sjulian    } else {
7515885Sjulian	deh->deh_sum = 0;
7615885Sjulian    }
7715885Sjulian    deh->deh_bytes = htonl( deh->deh_bytes );
7815885Sjulian
7915885Sjulian    return( ddp_route( m, &ddp->ddp_route ));
8015885Sjulian}
8115885Sjulian
8215885Sjulianu_short
8315885Sjulianat_cksum( struct mbuf *m, int skip)
8415885Sjulian{
8515885Sjulian    u_char	*data, *end;
8615885Sjulian    u_long	cksum = 0;
8715885Sjulian
8815885Sjulian    for (; m; m = m->m_next ) {
8915885Sjulian	for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end;
9015885Sjulian		data++ ) {
9115885Sjulian	    if ( skip ) {
9215885Sjulian		skip--;
9315885Sjulian		continue;
9415885Sjulian	    }
9515885Sjulian	    cksum = ( cksum + *data ) << 1;
9615885Sjulian	    if ( cksum & 0x00010000 ) {
9715885Sjulian		cksum++;
9815885Sjulian	    }
9915885Sjulian	    cksum &= 0x0000ffff;
10015885Sjulian	}
10115885Sjulian    }
10215885Sjulian
10315885Sjulian    if ( cksum == 0 ) {
10415885Sjulian	cksum = 0x0000ffff;
10515885Sjulian    }
10615885Sjulian    return( (u_short)cksum );
10715885Sjulian}
10815885Sjulian
10915885Sjulianint
11015885Sjulianddp_route( struct mbuf *m, struct route *ro)
11115885Sjulian{
11215885Sjulian    struct sockaddr_at	gate;
11315885Sjulian    struct elaphdr	*elh;
11415885Sjulian    struct mbuf		*m0;
11515885Sjulian    struct at_ifaddr	*aa = NULL;
11615885Sjulian    struct ifnet	*ifp = NULL;
11715885Sjulian    u_short		net;
11815885Sjulian
11915885Sjulian    if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
12015885Sjulian	net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
12115885Sjulian	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
12215885Sjulian	    if ( aa->aa_ifp == ifp &&
12315885Sjulian		    ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
12415885Sjulian		    ntohs( net ) <= ntohs( aa->aa_lastnet )) {
12515885Sjulian		break;
12615885Sjulian	    }
12715885Sjulian	}
12815885Sjulian    }
12915885Sjulian    if ( aa == NULL ) {
13015885Sjulianprintf( "ddp_route: oops\n" );
13115885Sjulian	m_freem( m );
13215885Sjulian	return( EINVAL );
13315885Sjulian    }
13415885Sjulian
13515885Sjulian    /*
13615885Sjulian     * There are several places in the kernel where data is added to
13715885Sjulian     * an mbuf without ensuring that the mbuf pointer is aligned.
13815885Sjulian     * This is bad for transition routing, since phase 1 and phase 2
13915885Sjulian     * packets end up poorly aligned due to the three byte elap header.
14015885Sjulian     */
14117254Sjulian    if ( !(aa->aa_flags & AFA_PHASE2) ) {
14215885Sjulian	MGET( m0, M_WAIT, MT_HEADER );
14315885Sjulian	if ( m0 == 0 ) {
14415885Sjulian	    m_freem( m );
14515885Sjulian	    printf("ddp_route: no buffers\n");
14615885Sjulian	    return( ENOBUFS );
14715885Sjulian	}
14815885Sjulian	m0->m_next = m;
14915885Sjulian	/* XXX perhaps we ought to align the header? */
15015885Sjulian	m0->m_len = SZ_ELAPHDR;
15115885Sjulian	m = m0;
15215885Sjulian
15315885Sjulian	elh = mtod( m, struct elaphdr *);
15415885Sjulian	elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
15515885Sjulian	elh->el_type = ELAP_DDPEXTEND;
15615885Sjulian	if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
15715885Sjulian		ntohs( aa->aa_firstnet ) &&
15815885Sjulian		ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
15915885Sjulian		ntohs( aa->aa_lastnet )) {
16015885Sjulian	    elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node;
16115885Sjulian	} else {
16215885Sjulian	    elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
16315885Sjulian	}
16415885Sjulian    }
16515885Sjulian
16615885Sjulian    if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
16715885Sjulian	    ntohs( aa->aa_firstnet ) &&
16815885Sjulian	    ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
16915885Sjulian	    ntohs( aa->aa_lastnet )) {
17015885Sjulian	gate = *satosat( &ro->ro_dst );
17115885Sjulian    } else {
17215885Sjulian	gate = *satosat( ro->ro_rt->rt_gateway );
17315885Sjulian    }
17415885Sjulian    ro->ro_rt->rt_use++;
17515885Sjulian
17617254Sjulian    return((*ifp->if_output)( ifp,
17717254Sjulian	m, (struct sockaddr *)&gate, NULL)); /* XXX */
17815885Sjulian}
179