ddp_output.c revision 17254
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/errno.h> 30#include <sys/syslog.h> 31 32#include <net/if.h> 33#include <net/route.h> 34 35#include <netinet/in.h> 36#undef s_net 37#include <netinet/if_ether.h> 38 39#include "at.h" 40#include "at_var.h" 41#include "endian.h" 42#include "ddp.h" 43#include "ddp_var.h" 44#include <netatalk/at_extern.h> 45 46int ddp_cksum = 1; 47 48int 49ddp_output( struct ddpcb *ddp, struct mbuf *m) 50{ 51 struct ddpehdr *deh; 52 53 M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT ); 54 55 deh = mtod( m, struct ddpehdr *); 56 deh->deh_pad = 0; 57 deh->deh_hops = 0; 58 59 deh->deh_len = m->m_pkthdr.len; 60 61 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; 62 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; 63 deh->deh_dport = ddp->ddp_fsat.sat_port; 64 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; 65 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; 66 deh->deh_sport = ddp->ddp_lsat.sat_port; 67 68 /* 69 * The checksum calculation is done after all of the other bytes have 70 * been filled in. 71 */ 72 if ( ddp_cksum ) { 73 deh->deh_sum = at_cksum( m, sizeof( int )); 74 } else { 75 deh->deh_sum = 0; 76 } 77 deh->deh_bytes = htonl( deh->deh_bytes ); 78 79 return( ddp_route( m, &ddp->ddp_route )); 80} 81 82u_short 83at_cksum( struct mbuf *m, int skip) 84{ 85 u_char *data, *end; 86 u_long cksum = 0; 87 88 for (; m; m = m->m_next ) { 89 for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end; 90 data++ ) { 91 if ( skip ) { 92 skip--; 93 continue; 94 } 95 cksum = ( cksum + *data ) << 1; 96 if ( cksum & 0x00010000 ) { 97 cksum++; 98 } 99 cksum &= 0x0000ffff; 100 } 101 } 102 103 if ( cksum == 0 ) { 104 cksum = 0x0000ffff; 105 } 106 return( (u_short)cksum ); 107} 108 109int 110ddp_route( struct mbuf *m, struct route *ro) 111{ 112 struct sockaddr_at gate; 113 struct elaphdr *elh; 114 struct mbuf *m0; 115 struct at_ifaddr *aa = NULL; 116 struct ifnet *ifp = NULL; 117 u_short net; 118 119 if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { 120 net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net; 121 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 122 if ( aa->aa_ifp == ifp && 123 ntohs( net ) >= ntohs( aa->aa_firstnet ) && 124 ntohs( net ) <= ntohs( aa->aa_lastnet )) { 125 break; 126 } 127 } 128 } 129 if ( aa == NULL ) { 130printf( "ddp_route: oops\n" ); 131 m_freem( m ); 132 return( EINVAL ); 133 } 134 135 /* 136 * There are several places in the kernel where data is added to 137 * an mbuf without ensuring that the mbuf pointer is aligned. 138 * This is bad for transition routing, since phase 1 and phase 2 139 * packets end up poorly aligned due to the three byte elap header. 140 */ 141 if ( !(aa->aa_flags & AFA_PHASE2) ) { 142 MGET( m0, M_WAIT, MT_HEADER ); 143 if ( m0 == 0 ) { 144 m_freem( m ); 145 printf("ddp_route: no buffers\n"); 146 return( ENOBUFS ); 147 } 148 m0->m_next = m; 149 /* XXX perhaps we ought to align the header? */ 150 m0->m_len = SZ_ELAPHDR; 151 m = m0; 152 153 elh = mtod( m, struct elaphdr *); 154 elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node; 155 elh->el_type = ELAP_DDPEXTEND; 156 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= 157 ntohs( aa->aa_firstnet ) && 158 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= 159 ntohs( aa->aa_lastnet )) { 160 elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node; 161 } else { 162 elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node; 163 } 164 } 165 166 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >= 167 ntohs( aa->aa_firstnet ) && 168 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <= 169 ntohs( aa->aa_lastnet )) { 170 gate = *satosat( &ro->ro_dst ); 171 } else { 172 gate = *satosat( ro->ro_rt->rt_gateway ); 173 } 174 ro->ro_rt->rt_use++; 175 176 return((*ifp->if_output)( ifp, 177 m, (struct sockaddr *)&gate, NULL)); /* XXX */ 178} 179