1 /* $NetBSD: ddp_output.c,v 1.13 2008/01/14 04:12:40 dyoung Exp $ */
4 * Copyright (c) 1990,1991 Regents of The University of Michigan.
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.
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
20 * Research Systems Unix Group
21 * The University of Michigan
23 * 535 W. William Street
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: ddp_output.c,v 1.13 2008/01/14 04:12:40 dyoung Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
35 #include <sys/socket.h>
36 #include <sys/errno.h>
37 #include <sys/syslog.h>
40 #include <net/route.h>
41 #include <net/if_ether.h>
43 #include <netinet/in.h>
46 #include <netatalk/at.h>
47 #include <netatalk/at_var.h>
48 #include <netatalk/ddp.h>
49 #include <netatalk/ddp_var.h>
50 #include <netatalk/at_extern.h>
52 #include <machine/stdarg.h>
57 ddp_output(struct mbuf
*m
,...)
64 ddp
= va_arg(ap
, struct ddpcb
*);
67 M_PREPEND(m
, sizeof(struct ddpehdr
), M_DONTWAIT
);
71 deh
= mtod(m
, struct ddpehdr
*);
75 deh
->deh_len
= m
->m_pkthdr
.len
;
77 deh
->deh_dnet
= ddp
->ddp_fsat
.sat_addr
.s_net
;
78 deh
->deh_dnode
= ddp
->ddp_fsat
.sat_addr
.s_node
;
79 deh
->deh_dport
= ddp
->ddp_fsat
.sat_port
;
80 deh
->deh_snet
= ddp
->ddp_lsat
.sat_addr
.s_net
;
81 deh
->deh_snode
= ddp
->ddp_lsat
.sat_addr
.s_node
;
82 deh
->deh_sport
= ddp
->ddp_lsat
.sat_port
;
85 * The checksum calculation is done after all of the other bytes have
89 deh
->deh_sum
= at_cksum(m
, sizeof(int));
92 deh
->deh_bytes
= htonl(deh
->deh_bytes
);
94 return ddp_route(m
, &ddp
->ddp_route
);
98 at_cksum(struct mbuf
*m
, int skip
)
103 for (; m
; m
= m
->m_next
) {
104 for (data
= mtod(m
, u_char
*), end
= data
+ m
->m_len
;
105 data
< end
; data
++) {
110 cksum
= (cksum
+ *data
) << 1;
111 if (cksum
& 0x00010000)
120 return (u_short
)cksum
;
124 ddp_route(struct mbuf
*m
, struct route
*ro
)
127 struct sockaddr_at gate
;
129 struct at_ifaddr
*aa
= NULL
;
130 struct ifnet
*ifp
= NULL
;
133 if ((rt
= rtcache_validate(ro
)) != NULL
&& (ifp
= rt
->rt_ifp
) != NULL
) {
134 net
= satosat(rt
->rt_gateway
)->sat_addr
.s_net
;
135 TAILQ_FOREACH(aa
, &at_ifaddr
, aa_list
) {
136 if (aa
->aa_ifp
== ifp
&&
137 ntohs(net
) >= ntohs(aa
->aa_firstnet
) &&
138 ntohs(net
) <= ntohs(aa
->aa_lastnet
)) {
144 printf("%s: no address found\n", __func__
);
149 * There are several places in the kernel where data is added to
150 * an mbuf without ensuring that the mbuf pointer is aligned.
151 * This is bad for transition routing, since phase 1 and phase 2
152 * packets end up poorly aligned due to the three byte elap header.
154 if (!(aa
->aa_flags
& AFA_PHASE2
)) {
155 M_PREPEND(m
, SZ_ELAPHDR
, M_DONTWAIT
);
159 elh
= mtod(m
, struct elaphdr
*);
160 elh
->el_snode
= satosat(&aa
->aa_addr
)->sat_addr
.s_node
;
161 elh
->el_type
= ELAP_DDPEXTEND
;
162 if (ntohs(satocsat(rtcache_getdst(ro
))->sat_addr
.s_net
) >=
163 ntohs(aa
->aa_firstnet
) &&
164 ntohs(satocsat(rtcache_getdst(ro
))->sat_addr
.s_net
) <=
165 ntohs(aa
->aa_lastnet
)) {
166 elh
->el_dnode
= satocsat(rtcache_getdst(ro
))->sat_addr
.s_node
;
169 satosat(rt
->rt_gateway
)->sat_addr
.s_node
;
172 if (ntohs(satocsat(rtcache_getdst(ro
))->sat_addr
.s_net
) >=
173 ntohs(aa
->aa_firstnet
) &&
174 ntohs(satocsat(rtcache_getdst(ro
))->sat_addr
.s_net
) <=
175 ntohs(aa
->aa_lastnet
)) {
176 gate
= *satocsat(rtcache_getdst(ro
));
178 gate
= *satosat(rt
->rt_gateway
);
183 aa
->aa_ifa
.ifa_data
.ifad_outbytes
+= m
->m_pkthdr
.len
;
187 return (*ifp
->if_output
)(ifp
, m
, (struct sockaddr
*)&gate
, NULL
);