ddp_output.c revision 23396
1/* 2 * Copyright (c) 1990,1991 Regents of The University of Michigan. 3 * All Rights Reserved. 4 * 5 * Permission to use, copy, modify, and distribute this software and 6 * its documentation for any purpose and without fee is hereby granted, 7 * provided that the above copyright notice appears in all copies and 8 * that both that copyright notice and this permission notice appear 9 * in supporting documentation, and that the name of The University 10 * of Michigan not be used in advertising or publicity pertaining to 11 * distribution of the software without specific, written prior 12 * permission. This software is supplied as is without expressed or 13 * implied warranties of any kind. 14 * 15 * Research Systems Unix Group 16 * The University of Michigan 17 * c/o Mike Clark 18 * 535 W. William Street 19 * Ann Arbor, Michigan 20 * +1-313-763-0525 21 * netatalk@itd.umich.edu 22 */ 23 24#include <sys/types.h> 25#include <sys/param.h> 26#include <sys/systm.h> 27#include <sys/mbuf.h> 28#include <sys/socket.h> 29#include <sys/socketvar.h> 30#include <sys/errno.h> 31#include <sys/syslog.h> 32 33#include <net/if.h> 34#include <net/route.h> 35 36#include <netinet/in.h> 37#undef s_net 38#include <netinet/if_ether.h> 39 40#include <netatalk/at.h> 41#include <netatalk/at_var.h> 42#include <netatalk/endian.h> 43#include <netatalk/ddp.h> 44#include <netatalk/ddp_var.h> 45#include <netatalk/at_extern.h> 46 47int ddp_cksum = 1; 48 49int 50/*ddp_output( struct ddpcb *ddp, struct mbuf *m)*/ 51ddp_output( struct mbuf *m, struct socket *so) 52{ 53 struct ddpehdr *deh; 54 struct ddpcb *ddp = sotoddpcb( so ); 55 56 M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT ); 57 58 deh = mtod( m, struct ddpehdr *); 59 deh->deh_pad = 0; 60 deh->deh_hops = 0; 61 62 deh->deh_len = m->m_pkthdr.len; 63 64 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; 65 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; 66 deh->deh_dport = ddp->ddp_fsat.sat_port; 67 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; 68 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; 69 deh->deh_sport = ddp->ddp_lsat.sat_port; 70 71 /* 72 * The checksum calculation is done after all of the other bytes have 73 * been filled in. 74 */ 75 if ( ddp_cksum ) { 76 deh->deh_sum = at_cksum( m, sizeof( int )); 77 } else { 78 deh->deh_sum = 0; 79 } 80 deh->deh_bytes = htonl( deh->deh_bytes ); 81 82 return( ddp_route( m, &ddp->ddp_route )); 83} 84 85u_short 86at_cksum( struct mbuf *m, int skip) 87{ 88 u_char *data, *end; 89 u_long cksum = 0; 90 91 for (; m; m = m->m_next ) { 92 for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end; 93 data++ ) { 94 if ( skip ) { 95 skip--; 96 continue; 97 } 98 cksum = ( cksum + *data ) << 1; 99 if ( cksum & 0x00010000 ) { 100 cksum++; 101 } 102 cksum &= 0x0000ffff; 103 } 104 } 105 106 if ( cksum == 0 ) { 107 cksum = 0x0000ffff; 108 } 109 return( (u_short)cksum ); 110} 111 112int 113ddp_route( struct mbuf *m, struct route *ro) 114{ 115 struct sockaddr_at gate; 116 struct elaphdr *elh; 117 struct mbuf *m0; 118 struct at_ifaddr *aa = NULL; 119 struct ifnet *ifp = NULL; 120 u_short net; 121 122 if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { 123 net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net; 124 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 125 if ( aa->aa_ifp == ifp && 126 ntohs( net ) >= ntohs( aa->aa_firstnet ) && 127 ntohs( net ) <= ntohs( aa->aa_lastnet )) { 128 break; 129 } 130 } 131 } 132 if ( aa == NULL ) { 133printf( "ddp_route: oops\n" ); 134 m_freem( m ); 135 return( EINVAL ); 136 } 137 138 /* 139 * There are several places in the kernel where data is added to 140 * an mbuf without ensuring that the mbuf pointer is aligned. 141 * This is bad for transition routing, since phase 1 and phase 2 142 * packets end up poorly aligned due to the three byte elap header. 143 */ 144 if ( !(aa->aa_flags & AFA_PHASE2) ) { 145 MGET( m0, M_WAIT, MT_HEADER ); 146 if ( m0 == 0 ) { 147 m_freem( m ); 148 printf("ddp_route: no buffers\n"); 149 return( ENOBUFS ); 150 } 151 m0->m_next = m; 152 /* XXX perhaps we ought to align the header? */ 153 m0->m_len = SZ_ELAPHDR; 154 m = m0; 155 156 elh = mtod( m, struct elaphdr *); 157 elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node; 158 elh->el_type = ELAP_DDPEXTEND; 159 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= 160 ntohs( aa->aa_firstnet ) && 161 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= 162 ntohs( aa->aa_lastnet )) { 163 elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node; 164 } else { 165 elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node; 166 } 167 } 168 169 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= 170 ntohs( aa->aa_firstnet ) && 171 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= 172 ntohs( aa->aa_lastnet )) { 173 gate = *satosat( &ro->ro_dst ); 174 } else { 175 gate = *satosat( ro->ro_rt->rt_gateway ); 176 } 177 ro->ro_rt->rt_use++; 178 179 return((*ifp->if_output)( ifp, 180 m, (struct sockaddr *)&gate, NULL)); /* XXX */ 181} 182