thread stage 10: (note stage 9 was the kern/lwkt_rwlock commit). Cleanup
[dragonfly.git] / sys / netproto / atalk / ddp_output.c
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 /* $FreeBSD: src/sys/netatalk/ddp_output.c,v 1.13.6.1 2000/06/02 22:39:07 archie Exp $ */
25 /* $DragonFly: src/sys/netproto/atalk/ddp_output.c,v 1.2 2003/06/17 04:28:48 dillon Exp $ */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/mbuf.h>
30 #include <sys/socket.h>
31 #include <sys/socketvar.h>
32
33 #include <net/if.h>
34 #include <net/route.h>
35
36 #undef s_net
37
38 #include <netatalk/at.h>
39 #include <netatalk/at_var.h>
40 #include <netatalk/ddp.h>
41 #include <netatalk/ddp_var.h>
42 #include <netatalk/at_extern.h>
43
44 int     ddp_cksum = 1;
45
46 int
47 ddp_output( struct mbuf *m, struct socket *so)
48 {
49     struct ddpehdr      *deh;
50     struct ddpcb *ddp = sotoddpcb( so );
51
52     M_PREPEND( m, sizeof( struct ddpehdr ), M_WAIT );
53
54     deh = mtod( m, struct ddpehdr *);
55     deh->deh_pad = 0;
56     deh->deh_hops = 0;
57
58     deh->deh_len = m->m_pkthdr.len;
59
60     deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
61     deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
62     deh->deh_dport = ddp->ddp_fsat.sat_port;
63     deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
64     deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
65     deh->deh_sport = ddp->ddp_lsat.sat_port;
66
67     /*
68      * The checksum calculation is done after all of the other bytes have
69      * been filled in.
70      */
71     if ( ddp_cksum ) {
72         deh->deh_sum = at_cksum( m, sizeof( int ));
73     } else {
74         deh->deh_sum = 0;
75     }
76     deh->deh_bytes = htonl( deh->deh_bytes );
77
78 #ifdef NETATALK_DEBUG
79     printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n",
80         ntohs(deh->deh_snet), deh->deh_snode, deh->deh_sport,
81         ntohs(deh->deh_dnet), deh->deh_dnode, deh->deh_dport);
82 #endif
83     return( ddp_route( m, &ddp->ddp_route ));
84 }
85
86 u_short
87 at_cksum( struct mbuf *m, int skip)
88 {
89     u_char      *data, *end;
90     u_long      cksum = 0;
91
92     for (; m; m = m->m_next ) {
93         for ( data = mtod( m, u_char * ), end = data + m->m_len; data < end;
94                 data++ ) {
95             if ( skip ) {
96                 skip--;
97                 continue;
98             }
99             cksum = ( cksum + *data ) << 1;
100             if ( cksum & 0x00010000 ) {
101                 cksum++;
102             }
103             cksum &= 0x0000ffff;
104         }
105     }
106
107     if ( cksum == 0 ) {
108         cksum = 0x0000ffff;
109     }
110     return( (u_short)cksum );
111 }
112
113 int
114 ddp_route( struct mbuf *m, struct route *ro)
115 {
116     struct sockaddr_at  gate;
117     struct elaphdr      *elh;
118     struct mbuf         *m0;
119     struct at_ifaddr    *aa = NULL;
120     struct ifnet        *ifp = NULL;
121     u_short             net;
122
123 #if 0
124     /* Check for net zero, node zero ("myself") */
125     if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET
126         && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) {
127             /* Find the loopback interface */
128     }
129 #endif
130
131     /*
132      * if we have a route, find the ifa that refers to this route.
133      * I.e The ifa used to get to the gateway.
134      */
135     if ( (ro->ro_rt == NULL)
136     || ( ro->ro_rt->rt_ifa == NULL )
137     || ( (ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL )) {
138         rtalloc(ro);
139     }
140     if ( (ro->ro_rt != NULL)
141     && ( ro->ro_rt->rt_ifa )
142     && ( ifp = ro->ro_rt->rt_ifa->ifa_ifp )) {
143         net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net);
144         for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
145             if (((net == 0) || (aa->aa_ifp == ifp)) &&
146                     net >= ntohs( aa->aa_firstnet ) &&
147                     net <= ntohs( aa->aa_lastnet )) {
148                 break;
149             }
150         }
151     } else {
152         m_freem( m );
153 #ifdef NETATALK_DEBUG
154         if (ro->ro_rt == NULL)
155             printf ("ddp_route: no ro_rt.\n");
156         else if (ro->ro_rt->rt_ifa == NULL)
157             printf ("ddp_route: no ro_rt->rt_ifa\n");
158         else
159             printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n");
160 #endif
161         return( ENETUNREACH );
162     }
163
164     if ( aa == NULL ) {
165 #ifdef NETATALK_DEBUG
166         printf( "ddp_route: no atalk address found for %s%d\n", 
167             ifp->if_name, ifp->if_unit);
168 #endif
169         m_freem( m );
170         return( ENETUNREACH );
171     }
172
173     /*
174      * if the destination address is on a directly attached node use that,
175      * else use the official gateway.
176      */
177     if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
178             ntohs( aa->aa_firstnet ) &&
179             ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
180             ntohs( aa->aa_lastnet )) {
181         gate = *satosat( &ro->ro_dst );
182     } else {
183         gate = *satosat( ro->ro_rt->rt_gateway );
184     }
185
186     /*
187      * There are several places in the kernel where data is added to
188      * an mbuf without ensuring that the mbuf pointer is aligned.
189      * This is bad for transition routing, since phase 1 and phase 2
190      * packets end up poorly aligned due to the three byte elap header.
191      */
192     if ( !(aa->aa_flags & AFA_PHASE2) ) {
193         MGET( m0, M_WAIT, MT_HEADER );
194         if ( m0 == 0 ) {
195             m_freem( m );
196             printf("ddp_route: no buffers\n");
197             return( ENOBUFS );
198         }
199         m0->m_next = m;
200         /* XXX perhaps we ought to align the header? */
201         m0->m_len = SZ_ELAPHDR;
202         m = m0;
203
204         elh = mtod( m, struct elaphdr *);
205         elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
206         elh->el_type = ELAP_DDPEXTEND;
207         elh->el_dnode = gate.sat_addr.s_node;
208     }
209     ro->ro_rt->rt_use++;
210
211 #ifdef NETATALK_DEBUG
212     printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s%d)\n",
213         ntohs(satosat(&aa->aa_addr)->sat_addr.s_net),
214         satosat(&aa->aa_addr)->sat_addr.s_node,
215         ntohs(satosat(&ro->ro_dst)->sat_addr.s_net),
216         satosat(&ro->ro_dst)->sat_addr.s_node,
217         ntohs(gate.sat_addr.s_net),
218         gate.sat_addr.s_node,
219         ifp->if_name, ifp->if_unit);
220 #endif
221
222     /* short-circuit the output if we're sending this to ourself */
223     if ((satosat(&aa->aa_addr)->sat_addr.s_net  == satosat(&ro->ro_dst)->sat_addr.s_net) &&
224         (satosat(&aa->aa_addr)->sat_addr.s_node == satosat(&ro->ro_dst)->sat_addr.s_node))
225     {
226         return (if_simloop(ifp, m, gate.sat_family, 0));
227     }
228
229     return((*ifp->if_output)( ifp,
230         m, (struct sockaddr *)&gate, NULL)); /* XXX */
231 }