1 /* $OpenBSD: ddp_output.c,v 1.6 2003/06/06 09:45:08 itojun Exp $ */
2
3 /*
4 * Copyright (c) 1990,1991 Regents of The University of Michigan.
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify, and distribute this software and
8 * its documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appears in all copies and
10 * that both that copyright notice and this permission notice appear
11 * in supporting documentation, and that the name of The University
12 * of Michigan not be used in advertising or publicity pertaining to
13 * distribution of the software without specific, written prior
14 * permission. This software is supplied as is without expressed or
15 * implied warranties of any kind.
16 *
17 * Research Systems Unix Group
18 * The University of Michigan
19 * c/o Mike Clark
20 * 535 W. William Street
21 * Ann Arbor, Michigan
22 * +1-313-763-0525
23 * netatalk@itd.umich.edu
24 */
25
26 /*
27 * The following is the contents of the COPYRIGHT file from the
28 * netatalk-1.4a2 distribution, from which this file is derived.
29 */
30 /*
31 * Copyright (c) 1990,1996 Regents of The University of Michigan.
32 *
33 * All Rights Reserved.
34 *
35 * Permission to use, copy, modify, and distribute this software and
36 * its documentation for any purpose and without fee is hereby granted,
37 * provided that the above copyright notice appears in all copies and
38 * that both that copyright notice and this permission notice appear
39 * in supporting documentation, and that the name of The University
40 * of Michigan not be used in advertising or publicity pertaining to
41 * distribution of the software without specific, written prior
42 * permission. This software is supplied as is without expressed or
43 * implied warranties of any kind.
44 *
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 *
48 * Solaris code is encumbered by the following:
49 *
50 * Copyright (C) 1996 by Sun Microsystems Computer Co.
51 *
52 * Permission to use, copy, modify, and distribute this software and
53 * its documentation for any purpose and without fee is hereby
54 * granted, provided that the above copyright notice appear in all
55 * copies and that both that copyright notice and this permission
56 * notice appear in supporting documentation. This software is
57 * provided "as is" without express or implied warranty.
58 *
59 * Research Systems Unix Group
60 * The University of Michigan
61 * c/o Wesley Craig
62 * 535 W. William Street
63 * Ann Arbor, Michigan
64 * +1-313-764-2278
65 * netatalk@umich.edu
66 */
67 /*
68 * None of the Solaris code mentioned is included in OpenBSD.
69 * This code also relies heavily on previous effort in FreeBSD and NetBSD.
70 */
71
72 #include <sys/types.h>
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/mbuf.h>
76 #include <sys/socket.h>
77 #include <sys/errno.h>
78 #include <sys/syslog.h>
79
80 #include <net/if.h>
81 #include <net/route.h>
82
83 #include <netinet/in.h>
84 #undef s_net
85 #include <netinet/if_ether.h>
86
87 #include <machine/endian.h>
88
89 #include <netatalk/at.h>
90 #include <netatalk/at_var.h>
91 #include <netatalk/ddp.h>
92 #include <netatalk/ddp_var.h>
93 #include <netatalk/at_extern.h>
94
95 int ddp_output( struct mbuf *, ... );
96 u_int16_t at_cksum( struct mbuf *, int );
97 int ddp_route(struct mbuf *, struct route * );
98
99 int ddp_cksum = 1;
100
101 int
102 ddp_output(struct mbuf *m, ...)
103 {
104 struct ddpcb *ddp;
105 struct ddpehdr *deh;
106 va_list ap;
107
108 va_start(ap, m);
109 ddp = va_arg(ap, struct ddpcb *);
110 va_end(ap);
111
112 M_PREPEND( m, sizeof( struct ddpehdr ), M_DONTWAIT );
113 if (!m)
114 return (ENOBUFS);
115
116 deh = mtod( m, struct ddpehdr *);
117 deh->deh_pad = 0;
118 deh->deh_hops = 0;
119
120 deh->deh_len = m->m_pkthdr.len;
121
122 deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net;
123 deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node;
124 deh->deh_dport = ddp->ddp_fsat.sat_port;
125 deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net;
126 deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node;
127 deh->deh_sport = ddp->ddp_lsat.sat_port;
128
129 /*
130 * The checksum calculation is done after all of the other bytes have
131 * been filled in.
132 */
133 if ( ddp_cksum ) {
134 deh->deh_sum = at_cksum( m, sizeof( int ));
135 } else {
136 deh->deh_sum = 0;
137 }
138 deh->deh_bytes = htonl( deh->deh_bytes );
139
140 return( ddp_route( m, &ddp->ddp_route ));
141 }
142
143 u_int16_t
144 at_cksum( m, skip )
145 struct mbuf *m;
146 int skip;
147 {
148 u_int8_t *data, *end;
149 u_long cksum = 0;
150
151 for (; m; m = m->m_next ) {
152 for ( data = mtod( m, u_int8_t * ), end = data + m->m_len; data < end;
153 data++ ) {
154 if ( skip ) {
155 skip--;
156 continue;
157 }
158 cksum = ( cksum + *data ) << 1;
159 if ( cksum & 0x00010000 ) {
160 cksum++;
161 }
162 cksum &= 0x0000ffff;
163 }
164 }
165
166 if ( cksum == 0 ) {
167 cksum = 0x0000ffff;
168 }
169 return( (u_int16_t)cksum );
170 }
171
172 int
173 ddp_route( m, ro )
174 struct mbuf *m;
175 struct route *ro;
176 {
177 struct sockaddr_at gate;
178 struct elaphdr *elh;
179 struct at_ifaddr *aa = NULL;
180 struct ifnet *ifp;
181 u_int16_t net;
182
183 if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
184 net = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_net;
185 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
186 if ( aa->aa_ifp == ifp &&
187 ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
188 ntohs( net ) <= ntohs( aa->aa_lastnet )) {
189 break;
190 }
191 }
192 }
193 if ( aa == NULL ) {
194 m_freem( m );
195 return( EINVAL );
196 }
197
198 /*
199 * There are several places in the kernel where data is added to
200 * an mbuf without ensuring that the mbuf pointer is aligned.
201 * This is bad for transition routing, since phase 1 and phase 2
202 * packets end up poorly aligned due to the three byte elap header.
203 */
204 if ( aa->aa_flags & AFA_PHASE2 ) {
205 if (( m = m_pullup( m, MIN( MHLEN, m->m_pkthdr.len ))) == 0 ) {
206 return( ENOBUFS );
207 }
208 } else {
209 M_PREPEND(m, SZ_ELAPHDR, M_DONTWAIT);
210 if (!m)
211 return (ENOBUFS);
212
213 elh = mtod( m, struct elaphdr *);
214 elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
215 elh->el_type = ELAP_DDPEXTEND;
216 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
217 ntohs( aa->aa_firstnet ) &&
218 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
219 ntohs( aa->aa_lastnet )) {
220 elh->el_dnode = satosat( &ro->ro_dst )->sat_addr.s_node;
221 } else {
222 elh->el_dnode = satosat( ro->ro_rt->rt_gateway )->sat_addr.s_node;
223 }
224 }
225
226 if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
227 ntohs( aa->aa_firstnet ) &&
228 ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
229 ntohs( aa->aa_lastnet )) {
230 gate = *satosat( &ro->ro_dst );
231 } else {
232 gate = *satosat( ro->ro_rt->rt_gateway );
233 }
234 ro->ro_rt->rt_use++;
235
236 /* XXX The NULL should be a struct rtentry */
237 return((*ifp->if_output)( ifp, m, (struct sockaddr *) &gate, NULL ));
238 }