2 * $Id: ddp_output.c,v 1.4 2002-01-04 04:45:49 sibaz Exp $
4 * Copyright (c) 1990,1991 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
12 #include <sys/types.h>
13 #include <sys/param.h>
15 #include <sys/socket.h>
16 #include <sys/errno.h>
17 #include <atalk/logger.h>
20 #include <net/route.h>
22 #include <netinet/in.h>
24 #include <netinet/if_ether.h>
44 struct at_ifaddr *aa = NULL;
49 M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
51 for ( len = 0, m0 = m; m; m = m->m_next ) {
54 MGET( m, M_WAIT, MT_HEADER );
63 # define align(a) (((a)+3)&0xfc)
64 m->m_off = MMINOFF + align( SZ_ELAPHDR );
65 m->m_len = sizeof( struct ddpehdr );
68 deh = mtod( m, struct ddpehdr *);
73 deh->deh_len = m->m_pkthdr.len;
75 deh->deh_len = len + sizeof( struct ddpehdr );
78 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
79 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
80 deh->deh_dport = ddp->ddp_fsat.sat_port;
81 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
82 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
83 deh->deh_sport = ddp->ddp_lsat.sat_port;
86 * The checksum calculation is done after all of the other bytes have
90 deh->deh_sum = at_cksum( m, sizeof( int ));
94 deh->deh_bytes = htonl( deh->deh_bytes );
96 return( ddp_route( m, &ddp->ddp_route ));
107 for (; m; m = m->m_next ) {
108 for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end;
114 cksum = ( cksum + *data ) << 1;
115 if ( cksum & 0x00010000 ) {
125 return( (u_short)cksum );
132 struct sockaddr_at gate;
135 struct at_ifaddr *aa = NULL;
140 if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
142 net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
144 net = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_net;
146 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
147 if ( aa->aa_ifp == ifp &&
148 ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
149 ntohs( net ) <= ntohs( aa->aa_lastnet )) {
160 * There are several places in the kernel where data is added to
161 * an mbuf without ensuring that the mbuf pointer is aligned.
162 * This is bad for transition routing, since phase 1 and phase 2
163 * packets end up poorly aligned due to the three byte elap header.
165 if ( aa->aa_flags & AFA_PHASE2 ) {
166 for ( mlen = 0, m0 = m; m0; m0 = m0->m_next ) {
169 if (( m = m_pullup( m, MIN( MLEN, mlen ))) == 0 ) {
175 M_PREPEND( m, SZ_ELAPHDR, M_DONTWAIT );
180 m->m_off -= SZ_ELAPHDR;
181 m->m_len += SZ_ELAPHDR;
185 MGET( m0, M_WAIT, MT_HEADER );
191 m0->m_off = MMINOFF + align( sizeof( struct ether_header ));
192 m0->m_len = SZ_ELAPHDR;
195 elh = mtod( m, struct elaphdr *);
196 elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
197 elh->el_type = ELAP_DDPEXTEND;
198 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
199 ntohs( aa->aa_firstnet ) &&
200 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
201 ntohs( aa->aa_lastnet )) {
202 elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node;
205 elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
207 elh->el_dnode = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_node;
212 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
213 ntohs( aa->aa_firstnet ) &&
214 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
215 ntohs( aa->aa_lastnet )) {
216 gate = *satosat( &ro->ro_dst );
219 gate = *satosat( ro->ro_rt->rt_gateway );
221 gate = *satosat( &ro->ro_rt->rt_gateway );
228 * SAIEW: We can't make changes to net/if_loop.c, so we don't route
229 * further than this: if it's going to go through the lookback,
230 * short-circuit to ddp_input(). Who needs queuing?
232 * Note: Passing NULL for the elaphdr is cool, since we'll only ever
233 * try to send long form ddp throught the loopback.
235 if ( ifp->if_flags & IFF_LOOPBACK ) {
237 m->m_off += SZ_ELAPHDR;
238 m->m_len -= SZ_ELAPHDR;
240 ddp_input( m, ifp, (struct elaphdr *)NULL, 2 );
247 * We can't make changes to the interface routines on RS6ks, and
248 * they don't provide hooks for if_output, so we just resolve
249 * our address here, and pass the packet as a raw ethernet packet.
250 * This doesn't work particularly well, if we aren't *on* ethernet,
251 * but it's ok for the moment.
253 if ( ! ( ifp->if_flags & IFF_LOOPBACK )) {
254 struct ether_header eh;
256 if ( !aarpresolve(( struct arpcom *)ifp, m,
257 &gate, eh.ether_dhost )) {
260 eh.ether_type = htons( ETHERTYPE_AT );
261 gate.sat_family = AF_UNSPEC;
262 bcopy( &eh, (*(struct sockaddr *)&gate).sa_data,
263 sizeof( (*(struct sockaddr *)&gate).sa_data ));
266 return((*ifp->if_output)( ifp, m, &gate ));