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