1 /* $NetBSD: ddp_input.c,v 1.24 2009/03/18 17:06:52 cegger Exp $ */
4 * Copyright (c) 1990,1994 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_input.c,v 1.24 2009/03/18 17:06:52 cegger Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <net/netisr.h>
37 #include <sys/socket.h>
38 #include <sys/socketvar.h>
39 #include <sys/syslog.h>
41 #include <net/route.h>
42 #include <net/if_ether.h>
43 #include <netinet/in.h>
45 #include <netatalk/at.h>
46 #include <netatalk/at_var.h>
47 #include <netatalk/ddp.h>
48 #include <netatalk/ddp_var.h>
49 #include <netatalk/ddp_private.h>
50 #include <netatalk/at_extern.h>
55 void ddp_input(struct mbuf
*, struct ifnet
*,
56 struct elaphdr
*, int);
59 * Could probably merge these two code segments a little better...
64 struct elaphdr
*elhp
, elh
;
70 mutex_enter(softnet_lock
);
74 IF_DEQUEUE(&atintrq2
, m
);
78 if (m
== 0) /* no more queued packets */
81 m_claimm(m
, &atalk_rx_mowner
);
82 ifp
= m
->m_pkthdr
.rcvif
;
83 for (aa
= at_ifaddr
.tqh_first
; aa
; aa
= aa
->aa_list
.tqe_next
) {
84 if (aa
->aa_ifp
== ifp
&& (aa
->aa_flags
& AFA_PHASE2
))
87 if (aa
== NULL
) { /* ifp not an appletalk interface */
91 ddp_input(m
, ifp
, (struct elaphdr
*) NULL
, 2);
97 IF_DEQUEUE(&atintrq1
, m
);
101 if (m
== 0) /* no more queued packets */
105 m_claimm(m
, &atalk_rx_mowner
);
106 ifp
= m
->m_pkthdr
.rcvif
;
107 for (aa
= at_ifaddr
.tqh_first
; aa
; aa
= aa
->aa_list
.tqe_next
) {
108 if (aa
->aa_ifp
== ifp
&&
109 (aa
->aa_flags
& AFA_PHASE2
) == 0)
112 if (aa
== NULL
) { /* ifp not an appletalk interface */
116 if (m
->m_len
< SZ_ELAPHDR
&&
117 ((m
= m_pullup(m
, SZ_ELAPHDR
)) == 0)) {
118 DDP_STATINC(DDP_STAT_TOOSHORT
);
121 elhp
= mtod(m
, struct elaphdr
*);
122 m_adj(m
, SZ_ELAPHDR
);
124 if (elhp
->el_type
== ELAP_DDPEXTEND
) {
125 ddp_input(m
, ifp
, (struct elaphdr
*) NULL
, 1);
127 memcpy((void *) & elh
, (void *) elhp
, SZ_ELAPHDR
);
128 ddp_input(m
, ifp
, &elh
, 1);
131 mutex_exit(softnet_lock
);
137 ddp_input(struct mbuf
*m
, struct ifnet
*ifp
, struct elaphdr
*elh
, int phase
)
140 struct sockaddr_at from
, to
;
141 struct ddpshdr
*dsh
, ddps
;
142 struct at_ifaddr
*aa
;
143 struct ddpehdr
*deh
= NULL
, ddpe
;
149 struct sockaddr_at dsta
;
152 memset((void *) & from
, 0, sizeof(struct sockaddr_at
));
154 DDP_STATINC(DDP_STAT_SHORT
);
156 if (m
->m_len
< sizeof(struct ddpshdr
) &&
157 ((m
= m_pullup(m
, sizeof(struct ddpshdr
))) == 0)) {
158 DDP_STATINC(DDP_STAT_TOOSHORT
);
161 dsh
= mtod(m
, struct ddpshdr
*);
162 memcpy((void *) & ddps
, (void *) dsh
, sizeof(struct ddpshdr
));
163 ddps
.dsh_bytes
= ntohl(ddps
.dsh_bytes
);
166 to
.sat_addr
.s_net
= ATADDR_ANYNET
;
167 to
.sat_addr
.s_node
= elh
->el_dnode
;
168 to
.sat_port
= ddps
.dsh_dport
;
169 from
.sat_addr
.s_net
= ATADDR_ANYNET
;
170 from
.sat_addr
.s_node
= elh
->el_snode
;
171 from
.sat_port
= ddps
.dsh_sport
;
173 for (aa
= at_ifaddr
.tqh_first
; aa
; aa
= aa
->aa_list
.tqe_next
) {
174 if (aa
->aa_ifp
== ifp
&&
175 (aa
->aa_flags
& AFA_PHASE2
) == 0 &&
176 (AA_SAT(aa
)->sat_addr
.s_node
==
177 to
.sat_addr
.s_node
||
178 to
.sat_addr
.s_node
== ATADDR_BCAST
))
186 DDP_STATINC(DDP_STAT_LONG
);
188 if (m
->m_len
< sizeof(struct ddpehdr
) &&
189 ((m
= m_pullup(m
, sizeof(struct ddpehdr
))) == 0)) {
190 DDP_STATINC(DDP_STAT_TOOSHORT
);
193 deh
= mtod(m
, struct ddpehdr
*);
194 memcpy((void *) & ddpe
, (void *) deh
, sizeof(struct ddpehdr
));
195 ddpe
.deh_bytes
= ntohl(ddpe
.deh_bytes
);
198 if ((cksum
= ddpe
.deh_sum
) == 0) {
199 DDP_STATINC(DDP_STAT_NOSUM
);
201 from
.sat_addr
.s_net
= ddpe
.deh_snet
;
202 from
.sat_addr
.s_node
= ddpe
.deh_snode
;
203 from
.sat_port
= ddpe
.deh_sport
;
204 to
.sat_addr
.s_net
= ddpe
.deh_dnet
;
205 to
.sat_addr
.s_node
= ddpe
.deh_dnode
;
206 to
.sat_port
= ddpe
.deh_dport
;
208 if (to
.sat_addr
.s_net
== ATADDR_ANYNET
) {
209 for (aa
= at_ifaddr
.tqh_first
; aa
;
210 aa
= aa
->aa_list
.tqe_next
) {
211 if (phase
== 1 && (aa
->aa_flags
& AFA_PHASE2
))
215 (aa
->aa_flags
& AFA_PHASE2
) == 0)
218 if (aa
->aa_ifp
== ifp
&&
219 (AA_SAT(aa
)->sat_addr
.s_node
==
220 to
.sat_addr
.s_node
||
221 to
.sat_addr
.s_node
== ATADDR_BCAST
||
222 (ifp
->if_flags
& IFF_LOOPBACK
)))
226 for (aa
= at_ifaddr
.tqh_first
; aa
;
227 aa
= aa
->aa_list
.tqe_next
) {
228 if (to
.sat_addr
.s_net
== aa
->aa_firstnet
&&
229 to
.sat_addr
.s_node
== 0)
232 if ((ntohs(to
.sat_addr
.s_net
) <
233 ntohs(aa
->aa_firstnet
) ||
234 ntohs(to
.sat_addr
.s_net
) >
235 ntohs(aa
->aa_lastnet
)) &&
236 (ntohs(to
.sat_addr
.s_net
) < 0xff00 ||
237 ntohs(to
.sat_addr
.s_net
) > 0xfffe))
240 if (to
.sat_addr
.s_node
!=
241 AA_SAT(aa
)->sat_addr
.s_node
&&
242 to
.sat_addr
.s_node
!= ATADDR_BCAST
)
251 * Adjust the length, removing any padding that may have been added
252 * at a link layer. We do this before we attempt to forward a packet,
253 * possibly on a different media.
255 mlen
= m
->m_pkthdr
.len
;
257 DDP_STATINC(DDP_STAT_TOOSMALL
);
262 m_adj(m
, dlen
- mlen
);
265 * XXX Should we deliver broadcasts locally, also, or rely on the
266 * link layer to give us a copy? For the moment, the latter.
268 if (aa
== NULL
|| (to
.sat_addr
.s_node
== ATADDR_BCAST
&&
269 aa
->aa_ifp
!= ifp
&& (ifp
->if_flags
& IFF_LOOPBACK
) == 0)) {
270 if (ddp_forward
== 0) {
274 sockaddr_at_init(&u
.dsta
, &to
.sat_addr
, 0);
275 rt
= rtcache_lookup(&forwro
, &u
.dst
);
276 #if 0 /* XXX The if-condition is always false. What was this
277 * actually trying to test?
279 if (to
.sat_addr
.s_net
!=
280 satocsat(rtcache_getdst(&forwro
))->sat_addr
.s_net
&&
281 ddpe
.deh_hops
== DDP_MAXHOPS
) {
286 if (ddp_firewall
&& (rt
== NULL
|| rt
->rt_ifp
!= ifp
)) {
291 ddpe
.deh_bytes
= htonl(ddpe
.deh_bytes
);
292 memcpy((void *) deh
, (void *) & ddpe
, sizeof(u_short
));/*XXX*/
293 if (ddp_route(m
, &forwro
)) {
294 DDP_STATINC(DDP_STAT_CANTFORWARD
);
296 DDP_STATINC(DDP_STAT_FORWARD
);
300 from
.sat_len
= sizeof(struct sockaddr_at
);
301 from
.sat_family
= AF_APPLETALK
;
304 m_adj(m
, sizeof(struct ddpshdr
));
306 if (ddp_cksum
&& cksum
&& cksum
!= at_cksum(m
, sizeof(int))) {
307 DDP_STATINC(DDP_STAT_BADSUM
);
311 m_adj(m
, sizeof(struct ddpehdr
));
314 if ((ddp
= ddp_search(&from
, &to
, aa
)) == NULL
) {
318 if (sbappendaddr(&ddp
->ddp_socket
->so_rcv
, (struct sockaddr
*) & from
,
319 m
, (struct mbuf
*) 0) == 0) {
320 DDP_STATINC(DDP_STAT_NOSOCKSPACE
);
326 aa
->aa_ifa
.ifa_data
.ifad_inbytes
+= dlen
;
328 sorwakeup(ddp
->ddp_socket
);
338 bprint(char *data
, int len
)
340 char xout
[BPXLEN
], aout
[BPALEN
];
343 memset(xout
, 0, BPXLEN
);
344 memset(aout
, 0, BPALEN
);
349 printf("%s\t%s\n", xout
, aout
);
351 printf("%s\n", "(end)");
354 xout
[(i
* 3)] = hexdigits
[(*data
& 0xf0) >> 4];
355 xout
[(i
* 3) + 1] = hexdigits
[*data
& 0x0f];
357 if ((u_char
) * data
< 0x7f && (u_char
) * data
> 0x20) {
363 xout
[(i
* 3) + 2] = ' ';
369 if (i
> BPALEN
- 2) {
370 printf("%s\t%s\n", xout
, aout
);
371 memset(xout
, 0, BPXLEN
);
372 memset(aout
, 0, BPALEN
);
380 m_printm(struct mbuf
*m
)
382 for (; m
; m
= m
->m_next
)
383 bprint(mtod(m
, char *), m
->m_len
);