]> arthur.barton.de Git - netatalk.git/blob - sys/netatalk/ddp_output.c
Initial revision
[netatalk.git] / sys / netatalk / ddp_output.c
1 /*
2  * Copyright (c) 1990,1991 Regents of The University of Michigan.
3  * All Rights Reserved. See COPYRIGHT.
4  */
5
6 #include <sys/types.h>
7 #include <sys/param.h>
8 #include <sys/mbuf.h>
9 #include <sys/socket.h>
10 #include <sys/errno.h>
11 #include <sys/syslog.h>
12
13 #include <net/if.h>
14 #include <net/route.h>
15
16 #include <netinet/in.h>
17 #undef s_net
18 #include <netinet/if_ether.h>
19
20 #include "at.h"
21 #include "at_var.h"
22 #include "endian.h"
23 #include "ddp.h"
24 #include "ddp_var.h"
25
26 u_short at_cksum();
27 int     ddp_cksum = 1;
28
29 ddp_output( ddp, m )
30     struct ddpcb        *ddp;
31     struct mbuf         *m;
32 {
33 #ifndef BSD4_4
34     struct mbuf         *m0;
35     int                 len;
36 #endif BSD4_4
37     struct ifnet        *ifp;
38     struct at_ifaddr    *aa = NULL;
39     struct ddpehdr      *deh;
40     u_short             net;
41
42 #ifdef BSD4_4
43     M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
44 #else BSD4_4
45     for ( len = 0, m0 = m; m; m = m->m_next ) {
46         len += m->m_len;
47     }
48     MGET( m, M_WAIT, MT_HEADER );
49     if ( m == 0 ) {
50         m_freem( m0 );
51         return( ENOBUFS );
52     }
53     m->m_next = m0;
54 #endif BSD4_4
55
56 #ifndef BSD4_4
57 # define align(a)       (((a)+3)&0xfc)
58     m->m_off = MMINOFF + align( SZ_ELAPHDR );
59     m->m_len = sizeof( struct ddpehdr );
60 #endif BSD4_4
61
62     deh = mtod( m, struct ddpehdr *);
63     deh->deh_pad = 0;
64     deh->deh_hops = 0;
65
66 #ifdef BSD4_4
67     deh->deh_len = m->m_pkthdr.len;
68 #else BSD4_4
69     deh->deh_len = len + sizeof( struct ddpehdr );
70 #endif BSD4_4
71
72     deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
73     deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
74     deh->deh_dport = ddp->ddp_fsat.sat_port;
75     deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
76     deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
77     deh->deh_sport = ddp->ddp_lsat.sat_port;
78
79     /*
80      * The checksum calculation is done after all of the other bytes have
81      * been filled in.
82      */
83     if ( ddp_cksum ) {
84         deh->deh_sum = at_cksum( m, sizeof( int ));
85     } else {
86         deh->deh_sum = 0;
87     }
88     deh->deh_bytes = htonl( deh->deh_bytes );
89
90     return( ddp_route( m, &ddp->ddp_route ));
91 }
92
93     u_short
94 at_cksum( m, skip )
95     struct mbuf *m;
96     int         skip;
97 {
98     u_char      *data, *end;
99     u_int32_t   cksum = 0;
100
101     for (; m; m = m->m_next ) {
102         for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end;
103                 data++ ) {
104             if ( skip ) {
105                 skip--;
106                 continue;
107             }
108             cksum = ( cksum + *data ) << 1;
109             if ( cksum & 0x00010000 ) {
110                 cksum++;
111             }
112             cksum &= 0x0000ffff;
113         }
114     }
115
116     if ( cksum == 0 ) {
117         cksum = 0x0000ffff;
118     }
119     return( (u_short)cksum );
120 }
121
122 ddp_route( m, ro )
123     struct mbuf         *m;
124     struct route        *ro;
125 {
126     struct sockaddr_at  gate;
127     struct elaphdr      *elh;
128     struct mbuf         *m0;
129     struct at_ifaddr    *aa = NULL;
130     struct ifnet        *ifp;
131     int                 mlen;
132     u_short             net;
133
134     if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
135 #ifdef BSD4_4
136         net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
137 #else BSD4_4
138         net = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_net;
139 #endif BSD4_4
140         for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
141             if ( aa->aa_ifp == ifp &&
142                     ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
143                     ntohs( net ) <= ntohs( aa->aa_lastnet )) {
144                 break;
145             }
146         }
147     }
148     if ( aa == NULL ) {
149         m_freem( m );
150         return( EINVAL );
151     }
152
153     /*
154      * There are several places in the kernel where data is added to
155      * an mbuf without ensuring that the mbuf pointer is aligned.
156      * This is bad for transition routing, since phase 1 and phase 2
157      * packets end up poorly aligned due to the three byte elap header.
158      */
159     if ( aa->aa_flags & AFA_PHASE2 ) {
160         for ( mlen = 0, m0 = m; m0; m0 = m0->m_next ) {
161             mlen += m0->m_len;
162         }
163         if (( m = m_pullup( m, MIN( MLEN, mlen ))) == 0 ) {
164             return( ENOBUFS );
165         }
166     } else {
167 # ifdef notdef
168 #ifdef BSD4_4
169         M_PREPEND( m, SZ_ELAPHDR, M_DONTWAIT );
170         if ( m == NULL ) {
171             return( ENOBUFS );
172         }
173 #else BSD4_4
174         m->m_off -= SZ_ELAPHDR;
175         m->m_len += SZ_ELAPHDR;
176 #endif BSD4_4
177 # endif notdef
178
179         MGET( m0, M_WAIT, MT_HEADER );
180         if ( m0 == 0 ) {
181             m_freem( m );
182             return( ENOBUFS );
183         }
184         m0->m_next = m;
185         m0->m_off = MMINOFF + align( sizeof( struct ether_header ));
186         m0->m_len = SZ_ELAPHDR;
187         m = m0;
188
189         elh = mtod( m, struct elaphdr *);
190         elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
191         elh->el_type = ELAP_DDPEXTEND;
192         if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
193                 ntohs( aa->aa_firstnet ) &&
194                 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
195                 ntohs( aa->aa_lastnet )) {
196             elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node;
197         } else {
198 #ifdef BSD4_4
199             elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
200 #else BSD4_4
201             elh->el_dnode = satosat( &ro->ro_rt->rt_gateway )->sat_addr.s_node;
202 #endif BSD4_4
203         }
204     }
205
206     if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
207             ntohs( aa->aa_firstnet ) &&
208             ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
209             ntohs( aa->aa_lastnet )) {
210         gate = *satosat( &ro->ro_dst );
211     } else {
212 #ifdef BSD4_4
213         gate = *satosat( ro->ro_rt->rt_gateway );
214 #else BSD4_4
215         gate = *satosat( &ro->ro_rt->rt_gateway );
216 #endif BSD4_4
217     }
218     ro->ro_rt->rt_use++;
219
220 #ifdef ultrix
221     /*
222      * SAIEW: We can't make changes to net/if_loop.c, so we don't route
223      * further than this: if it's going to go through the lookback,
224      * short-circuit to ddp_input(). Who needs queuing?
225      *
226      * Note: Passing NULL for the elaphdr is cool, since we'll only ever
227      * try to send long form ddp throught the loopback.
228      */
229     if ( ifp->if_flags & IFF_LOOPBACK ) {
230 #ifdef notdef
231         m->m_off += SZ_ELAPHDR;
232         m->m_len -= SZ_ELAPHDR;
233 #endif notdef
234         ddp_input( m, ifp, (struct elaphdr *)NULL, 2 );
235         return( 0 );
236     }
237 #endif ultrix
238
239 #ifdef _IBMR2
240     /*
241      * We can't make changes to the interface routines on RS6ks, and
242      * they don't provide hooks for if_output, so we just resolve
243      * our address here, and pass the packet as a raw ethernet packet.
244      * This doesn't work particularly well, if we aren't *on* ethernet,
245      * but it's ok for the moment.
246      */
247     if ( ! ( ifp->if_flags & IFF_LOOPBACK )) {
248         struct ether_header     eh;
249
250         if ( !aarpresolve(( struct arpcom *)ifp, m,
251                 &gate, eh.ether_dhost )) {
252             return( 0 );
253         }
254         eh.ether_type = htons( ETHERTYPE_AT );
255         gate.sat_family = AF_UNSPEC;
256         bcopy( &eh, (*(struct sockaddr *)&gate).sa_data,
257                 sizeof( (*(struct sockaddr *)&gate).sa_data ));
258     }
259 #endif _IBMR2
260     return((*ifp->if_output)( ifp, m, &gate ));
261 }