• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/sys/netatalk/
1/*
2 * $Id: ddp_output.c,v 1.4 2002-01-04 04:45:49 sibaz Exp $
3 *
4 * Copyright (c) 1990,1991 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif /* HAVE_CONFIG_H */
11
12#include <sys/types.h>
13#include <sys/param.h>
14#include <sys/mbuf.h>
15#include <sys/socket.h>
16#include <sys/errno.h>
17#include <atalk/logger.h>
18
19#include <net/if.h>
20#include <net/route.h>
21
22#include <netinet/in.h>
23#undef s_net
24#include <netinet/if_ether.h>
25
26#include "at.h"
27#include "at_var.h"
28#include "endian.h"
29#include "ddp.h"
30#include "ddp_var.h"
31
32u_short	at_cksum();
33int	ddp_cksum = 1;
34
35ddp_output( ddp, m )
36    struct ddpcb	*ddp;
37    struct mbuf		*m;
38{
39#ifndef BSD4_4
40    struct mbuf		*m0;
41    int			len;
42#endif /* ! BSD4_4 */
43    struct ifnet	*ifp;
44    struct at_ifaddr	*aa = NULL;
45    struct ddpehdr	*deh;
46    u_short		net;
47
48#ifdef BSD4_4
49    M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
50#else /* BSD4_4 */
51    for ( len = 0, m0 = m; m; m = m->m_next ) {
52	len += m->m_len;
53    }
54    MGET( m, M_WAIT, MT_HEADER );
55    if ( m == 0 ) {
56	m_freem( m0 );
57	return( ENOBUFS );
58    }
59    m->m_next = m0;
60#endif /* BSD4_4 */
61
62#ifndef BSD4_4
63# define align(a)	(((a)+3)&0xfc)
64    m->m_off = MMINOFF + align( SZ_ELAPHDR );
65    m->m_len = sizeof( struct ddpehdr );
66#endif /* ! BSD4_4 */
67
68    deh = mtod( m, struct ddpehdr *);
69    deh->deh_pad = 0;
70    deh->deh_hops = 0;
71
72#ifdef BSD4_4
73    deh->deh_len = m->m_pkthdr.len;
74#else /* BSD4_4 */
75    deh->deh_len = len + sizeof( struct ddpehdr );
76#endif /* BSD4_4 */
77
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;
84
85    /*
86     * The checksum calculation is done after all of the other bytes have
87     * been filled in.
88     */
89    if ( ddp_cksum ) {
90	deh->deh_sum = at_cksum( m, sizeof( int ));
91    } else {
92	deh->deh_sum = 0;
93    }
94    deh->deh_bytes = htonl( deh->deh_bytes );
95
96    return( ddp_route( m, &ddp->ddp_route ));
97}
98
99    u_short
100at_cksum( m, skip )
101    struct mbuf	*m;
102    int		skip;
103{
104    u_char	*data, *end;
105    u_int32_t	cksum = 0;
106
107    for (; m; m = m->m_next ) {
108	for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end;
109		data++ ) {
110	    if ( skip ) {
111		skip--;
112		continue;
113	    }
114	    cksum = ( cksum + *data ) << 1;
115	    if ( cksum & 0x00010000 ) {
116		cksum++;
117	    }
118	    cksum &= 0x0000ffff;
119	}
120    }
121
122    if ( cksum == 0 ) {
123	cksum = 0x0000ffff;
124    }
125    return( (u_short)cksum );
126}
127
128ddp_route( m, ro )
129    struct mbuf		*m;
130    struct route	*ro;
131{
132    struct sockaddr_at	gate;
133    struct elaphdr	*elh;
134    struct mbuf		*m0;
135    struct at_ifaddr	*aa = NULL;
136    struct ifnet	*ifp;
137    int			mlen;
138    u_short		net;
139
140    if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
141#ifdef BSD4_4
142	net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
143#else /* BSD4_4 */
144	net = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_net;
145#endif /* BSD4_4 */
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 )) {
150		break;
151	    }
152	}
153    }
154    if ( aa == NULL ) {
155	m_freem( m );
156	return( EINVAL );
157    }
158
159    /*
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.
164     */
165    if ( aa->aa_flags & AFA_PHASE2 ) {
166	for ( mlen = 0, m0 = m; m0; m0 = m0->m_next ) {
167	    mlen += m0->m_len;
168	}
169	if (( m = m_pullup( m, MIN( MLEN, mlen ))) == 0 ) {
170	    return( ENOBUFS );
171	}
172    } else {
173# ifdef notdef
174#ifdef BSD4_4
175	M_PREPEND( m, SZ_ELAPHDR, M_DONTWAIT );
176	if ( m == NULL ) {
177	    return( ENOBUFS );
178	}
179#else /* BSD4_4 */
180	m->m_off -= SZ_ELAPHDR;
181	m->m_len += SZ_ELAPHDR;
182#endif /* BSD4_4 */
183# endif /* notdef */
184
185	MGET( m0, M_WAIT, MT_HEADER );
186	if ( m0 == 0 ) {
187	    m_freem( m );
188	    return( ENOBUFS );
189	}
190	m0->m_next = m;
191	m0->m_off = MMINOFF + align( sizeof( struct ether_header ));
192	m0->m_len = SZ_ELAPHDR;
193	m = m0;
194
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;
203	} else {
204#ifdef BSD4_4
205	    elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
206#else /* BSD4_4 */
207	    elh->el_dnode = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_node;
208#endif /* BSD4_4 */
209	}
210    }
211
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 );
217    } else {
218#ifdef BSD4_4
219	gate = *satosat( ro->ro_rt->rt_gateway );
220#else /* BSD4_4 */
221	gate = *satosat( &ro->ro_rt->rt_gateway );
222#endif /* BSD4_4 */
223    }
224    ro->ro_rt->rt_use++;
225
226#ifdef ultrix
227    /*
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?
231     *
232     * Note: Passing NULL for the elaphdr is cool, since we'll only ever
233     * try to send long form ddp throught the loopback.
234     */
235    if ( ifp->if_flags & IFF_LOOPBACK ) {
236#ifdef notdef
237	m->m_off += SZ_ELAPHDR;
238	m->m_len -= SZ_ELAPHDR;
239#endif /* notdef */
240	ddp_input( m, ifp, (struct elaphdr *)NULL, 2 );
241	return( 0 );
242    }
243#endif /* ultrix */
244
245#ifdef _IBMR2
246    /*
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.
252     */
253    if ( ! ( ifp->if_flags & IFF_LOOPBACK )) {
254	struct ether_header	eh;
255
256	if ( !aarpresolve(( struct arpcom *)ifp, m,
257		&gate, eh.ether_dhost )) {
258	    return( 0 );
259	}
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 ));
264    }
265#endif /* _IBMR2 */
266    return((*ifp->if_output)( ifp, m, &gate ));
267}
268