1 | /* $NetBSD: ddp_input.c,v 1.28 2016/10/03 11:06:06 ozaki-r Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1990,1994 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 | * This product includes software developed by the University of |
18 | * California, Berkeley and its contributors. |
19 | * |
20 | * Research Systems Unix Group |
21 | * The University of Michigan |
22 | * c/o Wesley Craig |
23 | * 535 W. William Street |
24 | * Ann Arbor, Michigan |
25 | * +1-313-764-2278 |
26 | * netatalk@umich.edu |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: ddp_input.c,v 1.28 2016/10/03 11:06:06 ozaki-r Exp $" ); |
31 | |
32 | #include <sys/param.h> |
33 | #include <sys/systm.h> |
34 | #include <sys/kernel.h> |
35 | #include <net/netisr.h> |
36 | #include <sys/mbuf.h> |
37 | #include <sys/socket.h> |
38 | #include <sys/socketvar.h> |
39 | #include <sys/syslog.h> |
40 | #include <net/if.h> |
41 | #include <net/route.h> |
42 | #include <net/if_ether.h> |
43 | #include <netinet/in.h> |
44 | |
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> |
51 | |
52 | int ddp_forward = 1; |
53 | int ddp_firewall = 0; |
54 | extern int ddp_cksum; |
55 | void ddp_input(struct mbuf *, struct ifnet *, |
56 | struct elaphdr *, int); |
57 | |
58 | /* |
59 | * Could probably merge these two code segments a little better... |
60 | */ |
61 | void |
62 | atintr(void) |
63 | { |
64 | struct elaphdr *elhp, elh; |
65 | struct ifnet *ifp; |
66 | struct mbuf *m; |
67 | struct at_ifaddr *aa; |
68 | |
69 | mutex_enter(softnet_lock); |
70 | for (;;) { |
71 | IFQ_LOCK(&atintrq2); |
72 | IF_DEQUEUE(&atintrq2, m); |
73 | IFQ_UNLOCK(&atintrq2); |
74 | |
75 | if (m == 0) /* no more queued packets */ |
76 | break; |
77 | |
78 | m_claimm(m, &atalk_rx_mowner); |
79 | ifp = m_get_rcvif_NOMPSAFE(m); |
80 | for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { |
81 | if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2)) |
82 | break; |
83 | } |
84 | if (aa == NULL) { /* ifp not an appletalk interface */ |
85 | m_freem(m); |
86 | continue; |
87 | } |
88 | ddp_input(m, ifp, NULL, 2); |
89 | } |
90 | |
91 | for (;;) { |
92 | IFQ_LOCK(&atintrq1); |
93 | IF_DEQUEUE(&atintrq1, m); |
94 | IFQ_UNLOCK(&atintrq1); |
95 | |
96 | if (m == 0) /* no more queued packets */ |
97 | |
98 | break; |
99 | |
100 | m_claimm(m, &atalk_rx_mowner); |
101 | ifp = m_get_rcvif_NOMPSAFE(m); |
102 | for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { |
103 | if (aa->aa_ifp == ifp && |
104 | (aa->aa_flags & AFA_PHASE2) == 0) |
105 | break; |
106 | } |
107 | if (aa == NULL) { /* ifp not an appletalk interface */ |
108 | m_freem(m); |
109 | continue; |
110 | } |
111 | if (m->m_len < SZ_ELAPHDR && |
112 | ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) { |
113 | DDP_STATINC(DDP_STAT_TOOSHORT); |
114 | continue; |
115 | } |
116 | elhp = mtod(m, struct elaphdr *); |
117 | m_adj(m, SZ_ELAPHDR); |
118 | |
119 | if (elhp->el_type == ELAP_DDPEXTEND) { |
120 | ddp_input(m, ifp, NULL, 1); |
121 | } else { |
122 | memcpy((void *) & elh, (void *) elhp, SZ_ELAPHDR); |
123 | ddp_input(m, ifp, &elh, 1); |
124 | } |
125 | } |
126 | mutex_exit(softnet_lock); |
127 | } |
128 | |
129 | struct route forwro; |
130 | |
131 | void |
132 | ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase) |
133 | { |
134 | struct rtentry *rt; |
135 | struct sockaddr_at from, to; |
136 | struct ddpshdr *dsh, ddps; |
137 | struct at_ifaddr *aa; |
138 | struct ddpehdr *deh = NULL, ddpe; |
139 | struct ddpcb *ddp; |
140 | int dlen, mlen; |
141 | u_short cksum = 0; |
142 | union { |
143 | struct sockaddr dst; |
144 | struct sockaddr_at dsta; |
145 | } u; |
146 | |
147 | memset((void *) & from, 0, sizeof(struct sockaddr_at)); |
148 | if (elh) { |
149 | DDP_STATINC(DDP_STAT_SHORT); |
150 | |
151 | if (m->m_len < sizeof(struct ddpshdr) && |
152 | ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { |
153 | DDP_STATINC(DDP_STAT_TOOSHORT); |
154 | return; |
155 | } |
156 | dsh = mtod(m, struct ddpshdr *); |
157 | memcpy((void *) & ddps, (void *) dsh, sizeof(struct ddpshdr)); |
158 | ddps.dsh_bytes = ntohl(ddps.dsh_bytes); |
159 | dlen = ddps.dsh_len; |
160 | |
161 | to.sat_addr.s_net = ATADDR_ANYNET; |
162 | to.sat_addr.s_node = elh->el_dnode; |
163 | to.sat_port = ddps.dsh_dport; |
164 | from.sat_addr.s_net = ATADDR_ANYNET; |
165 | from.sat_addr.s_node = elh->el_snode; |
166 | from.sat_port = ddps.dsh_sport; |
167 | |
168 | for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { |
169 | if (aa->aa_ifp == ifp && |
170 | (aa->aa_flags & AFA_PHASE2) == 0 && |
171 | (AA_SAT(aa)->sat_addr.s_node == |
172 | to.sat_addr.s_node || |
173 | to.sat_addr.s_node == ATADDR_BCAST)) |
174 | break; |
175 | } |
176 | if (aa == NULL) { |
177 | m_freem(m); |
178 | return; |
179 | } |
180 | } else { |
181 | DDP_STATINC(DDP_STAT_LONG); |
182 | |
183 | if (m->m_len < sizeof(struct ddpehdr) && |
184 | ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { |
185 | DDP_STATINC(DDP_STAT_TOOSHORT); |
186 | return; |
187 | } |
188 | deh = mtod(m, struct ddpehdr *); |
189 | memcpy((void *) & ddpe, (void *) deh, sizeof(struct ddpehdr)); |
190 | ddpe.deh_bytes = ntohl(ddpe.deh_bytes); |
191 | dlen = ddpe.deh_len; |
192 | |
193 | if ((cksum = ddpe.deh_sum) == 0) { |
194 | DDP_STATINC(DDP_STAT_NOSUM); |
195 | } |
196 | from.sat_addr.s_net = ddpe.deh_snet; |
197 | from.sat_addr.s_node = ddpe.deh_snode; |
198 | from.sat_port = ddpe.deh_sport; |
199 | to.sat_addr.s_net = ddpe.deh_dnet; |
200 | to.sat_addr.s_node = ddpe.deh_dnode; |
201 | to.sat_port = ddpe.deh_dport; |
202 | |
203 | if (to.sat_addr.s_net == ATADDR_ANYNET) { |
204 | for (aa = at_ifaddr.tqh_first; aa; |
205 | aa = aa->aa_list.tqe_next) { |
206 | if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) |
207 | continue; |
208 | |
209 | if (phase == 2 && |
210 | (aa->aa_flags & AFA_PHASE2) == 0) |
211 | continue; |
212 | |
213 | if (aa->aa_ifp == ifp && |
214 | (AA_SAT(aa)->sat_addr.s_node == |
215 | to.sat_addr.s_node || |
216 | to.sat_addr.s_node == ATADDR_BCAST || |
217 | (ifp->if_flags & IFF_LOOPBACK))) |
218 | break; |
219 | } |
220 | } else { |
221 | for (aa = at_ifaddr.tqh_first; aa; |
222 | aa = aa->aa_list.tqe_next) { |
223 | if (to.sat_addr.s_net == aa->aa_firstnet && |
224 | to.sat_addr.s_node == 0) |
225 | break; |
226 | |
227 | if ((ntohs(to.sat_addr.s_net) < |
228 | ntohs(aa->aa_firstnet) || |
229 | ntohs(to.sat_addr.s_net) > |
230 | ntohs(aa->aa_lastnet)) && |
231 | (ntohs(to.sat_addr.s_net) < 0xff00 || |
232 | ntohs(to.sat_addr.s_net) > 0xfffe)) |
233 | continue; |
234 | |
235 | if (to.sat_addr.s_node != |
236 | AA_SAT(aa)->sat_addr.s_node && |
237 | to.sat_addr.s_node != ATADDR_BCAST) |
238 | continue; |
239 | |
240 | break; |
241 | } |
242 | } |
243 | } |
244 | |
245 | /* |
246 | * Adjust the length, removing any padding that may have been added |
247 | * at a link layer. We do this before we attempt to forward a packet, |
248 | * possibly on a different media. |
249 | */ |
250 | mlen = m->m_pkthdr.len; |
251 | if (mlen < dlen) { |
252 | DDP_STATINC(DDP_STAT_TOOSMALL); |
253 | m_freem(m); |
254 | return; |
255 | } |
256 | if (mlen > dlen) { |
257 | m_adj(m, dlen - mlen); |
258 | } |
259 | /* |
260 | * XXX Should we deliver broadcasts locally, also, or rely on the |
261 | * link layer to give us a copy? For the moment, the latter. |
262 | */ |
263 | if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && |
264 | aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { |
265 | if (ddp_forward == 0) { |
266 | m_freem(m); |
267 | return; |
268 | } |
269 | sockaddr_at_init(&u.dsta, &to.sat_addr, 0); |
270 | rt = rtcache_lookup(&forwro, &u.dst); |
271 | #if 0 /* XXX The if-condition is always false. What was this |
272 | * actually trying to test? |
273 | */ |
274 | if (to.sat_addr.s_net != |
275 | satocsat(rtcache_getdst(&forwro))->sat_addr.s_net && |
276 | ddpe.deh_hops == DDP_MAXHOPS) { |
277 | m_freem(m); |
278 | return; |
279 | } |
280 | #endif |
281 | if (ddp_firewall && (rt == NULL || rt->rt_ifp != ifp)) { |
282 | m_freem(m); |
283 | return; |
284 | } |
285 | ddpe.deh_hops++; |
286 | ddpe.deh_bytes = htonl(ddpe.deh_bytes); |
287 | memcpy((void *) deh, (void *) & ddpe, sizeof(u_short));/*XXX*/ |
288 | if (ddp_route(m, &forwro)) { |
289 | DDP_STATINC(DDP_STAT_CANTFORWARD); |
290 | } else { |
291 | DDP_STATINC(DDP_STAT_FORWARD); |
292 | } |
293 | return; |
294 | } |
295 | from.sat_len = sizeof(struct sockaddr_at); |
296 | from.sat_family = AF_APPLETALK; |
297 | |
298 | if (elh) { |
299 | m_adj(m, sizeof(struct ddpshdr)); |
300 | } else { |
301 | if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { |
302 | DDP_STATINC(DDP_STAT_BADSUM); |
303 | m_freem(m); |
304 | return; |
305 | } |
306 | m_adj(m, sizeof(struct ddpehdr)); |
307 | } |
308 | |
309 | if ((ddp = ddp_search(&from, &to, aa)) == NULL) { |
310 | m_freem(m); |
311 | return; |
312 | } |
313 | if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, |
314 | m, (struct mbuf *) 0) == 0) { |
315 | DDP_STATINC(DDP_STAT_NOSOCKSPACE); |
316 | m_freem(m); |
317 | return; |
318 | } |
319 | #if IFA_STATS |
320 | if (aa) |
321 | aa->aa_ifa.ifa_data.ifad_inbytes += dlen; |
322 | #endif |
323 | sorwakeup(ddp->ddp_socket); |
324 | } |
325 | |
326 | #if 0 |
327 | |
328 | #define BPXLEN 48 |
329 | #define BPALEN 16 |
330 | #include <ctype.h> |
331 | |
332 | static void |
333 | bprint(char *data, int len) |
334 | { |
335 | char xout[BPXLEN], aout[BPALEN]; |
336 | int i = 0; |
337 | |
338 | memset(xout, 0, BPXLEN); |
339 | memset(aout, 0, BPALEN); |
340 | |
341 | for (;;) { |
342 | if (len < 1) { |
343 | if (i != 0) { |
344 | printf("%s\t%s\n" , xout, aout); |
345 | } |
346 | printf("%s\n" , "(end)" ); |
347 | break; |
348 | } |
349 | xout[(i * 3)] = hexdigits[(*data & 0xf0) >> 4]; |
350 | xout[(i * 3) + 1] = hexdigits[*data & 0x0f]; |
351 | |
352 | if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { |
353 | aout[i] = *data; |
354 | } else { |
355 | aout[i] = '.'; |
356 | } |
357 | |
358 | xout[(i * 3) + 2] = ' '; |
359 | |
360 | i++; |
361 | len--; |
362 | data++; |
363 | |
364 | if (i > BPALEN - 2) { |
365 | printf("%s\t%s\n" , xout, aout); |
366 | memset(xout, 0, BPXLEN); |
367 | memset(aout, 0, BPALEN); |
368 | i = 0; |
369 | continue; |
370 | } |
371 | } |
372 | } |
373 | |
374 | static void |
375 | m_printm(struct mbuf *m) |
376 | { |
377 | for (; m; m = m->m_next) |
378 | bprint(mtod(m, char *), m->m_len); |
379 | } |
380 | #endif |
381 | |