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
ddp_output(struct mbuf * m,...)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
at_cksum(m,skip)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
ddp_route(m,ro)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 }
239