]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_stf.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / net / if_stf.c
CommitLineData
9bccf70c
A
1/* $FreeBSD: src/sys/net/if_stf.c,v 1.1.2.6 2001/07/24 19:10:18 brooks Exp $ */
2/* $KAME: if_stf.c,v 1.62 2001/06/07 22:32:16 itojun Exp $ */
3
4/*
5 * Copyright (C) 2000 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
2d21ac55
A
32/*
33 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
34 * support for mandatory and extensible security protections. This notice
35 * is included in support of clause 2.2 (b) of the Apple Public License,
36 * Version 2.0.
37 */
9bccf70c
A
38
39/*
40 * 6to4 interface, based on RFC3056.
41 *
42 * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting.
43 * There is no address mapping defined from IPv6 multicast address to IPv4
44 * address. Therefore, we do not have IFF_MULTICAST on the interface.
45 *
46 * Due to the lack of address mapping for link-local addresses, we cannot
47 * throw packets toward link-local addresses (fe80::x). Also, we cannot throw
48 * packets to link-local multicast addresses (ff02::x).
49 *
50 * Here are interesting symptoms due to the lack of link-local address:
51 *
52 * Unicast routing exchange:
53 * - RIPng: Impossible. Uses link-local multicast packet toward ff02::9,
54 * and link-local addresses as nexthop.
55 * - OSPFv6: Impossible. OSPFv6 assumes that there's link-local address
56 * assigned to the link, and makes use of them. Also, HELLO packets use
57 * link-local multicast addresses (ff02::5 and ff02::6).
58 * - BGP4+: Maybe. You can only use global address as nexthop, and global
59 * address as TCP endpoint address.
60 *
61 * Multicast routing protocols:
62 * - PIM: Hello packet cannot be used to discover adjacent PIM routers.
63 * Adjacent PIM routers must be configured manually (is it really spec-wise
64 * correct thing to do?).
65 *
66 * ICMPv6:
67 * - Redirects cannot be used due to the lack of link-local address.
68 *
69 * stf interface does not have, and will not need, a link-local address.
70 * It seems to have no real benefit and does not help the above symptoms much.
71 * Even if we assign link-locals to interface, we cannot really
72 * use link-local unicast/multicast on top of 6to4 cloud (since there's no
73 * encapsulation defined for link-local address), and the above analysis does
74 * not change. RFC3056 does not mandate the assignment of link-local address
75 * either.
76 *
77 * 6to4 interface has security issues. Refer to
78 * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt
79 * for details. The code tries to filter out some of malicious packets.
80 * Note that there is no way to be 100% secure.
81 */
82
83#include <sys/param.h>
84#include <sys/systm.h>
85#include <sys/socket.h>
86#include <sys/sockio.h>
87#include <sys/mbuf.h>
88#include <sys/errno.h>
89#include <sys/protosw.h>
90#include <sys/kernel.h>
91#include <sys/syslog.h>
9bccf70c
A
92
93#include <sys/malloc.h>
94
95#include <net/if.h>
96#include <net/route.h>
9bccf70c 97#include <net/if_types.h>
9bccf70c
A
98
99#include <netinet/in.h>
100#include <netinet/in_systm.h>
101#include <netinet/ip.h>
102#include <netinet/ip_var.h>
103#include <netinet/in_var.h>
104
105#include <netinet/ip6.h>
106#include <netinet6/ip6_var.h>
107#include <netinet6/in6_var.h>
108#include <netinet/ip_ecn.h>
109
110#include <netinet/ip_encap.h>
2d21ac55
A
111#include <net/kpi_interface.h>
112#include <net/kpi_protocol.h>
9bccf70c
A
113
114
115#include <net/net_osdep.h>
116
117#include <net/bpf.h>
118
2d21ac55
A
119#if CONFIG_MACF_NET
120#include <security/mac_framework.h>
121#endif
122
9bccf70c 123#define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002)
2d21ac55 124#define GET_V4(x) ((const struct in_addr *)(&(x)->s6_addr16[1]))
9bccf70c
A
125
126struct stf_softc {
2d21ac55
A
127 ifnet_t sc_if; /* common area */
128 u_long sc_protocol_family; /* dlil protocol attached */
9bccf70c
A
129 union {
130 struct route __sc_ro4;
131 struct route_in6 __sc_ro6; /* just for safety */
132 } __sc_ro46;
133#define sc_ro __sc_ro46.__sc_ro4
134 const struct encaptab *encap_cookie;
2d21ac55
A
135 bpf_tap_mode tap_mode;
136 bpf_packet_func tap_callback;
9bccf70c
A
137};
138
91447636 139void stfattach (void);
9bccf70c 140
9bccf70c
A
141static int ip_stf_ttl = 40;
142
91447636 143static void in_stf_input(struct mbuf *, int);
9bccf70c
A
144extern struct domain inetdomain;
145struct protosw in_stf_protosw =
146{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR,
2d21ac55
A
147 in_stf_input, NULL, NULL, rip_ctloutput,
148 NULL,
149 NULL, NULL, NULL, NULL,
150 NULL,
91447636 151 &rip_usrreqs,
2d21ac55 152 NULL, rip_unlock, NULL, {NULL, NULL}, NULL, {0}
9bccf70c
A
153};
154
91447636
A
155static int stf_encapcheck(const struct mbuf *, int, int, void *);
156static struct in6_ifaddr *stf_getsrcifa6(struct ifnet *);
2d21ac55
A
157int stf_pre_output(struct ifnet *, protocol_family_t, struct mbuf **,
158 const struct sockaddr *, void *, char *, char *);
159static int stf_checkaddr4(struct stf_softc *, const struct in_addr *,
91447636
A
160 struct ifnet *);
161static int stf_checkaddr6(struct stf_softc *, struct in6_addr *,
162 struct ifnet *);
163static void stf_rtrequest(int, struct rtentry *, struct sockaddr *);
2d21ac55
A
164static errno_t stf_ioctl(ifnet_t ifp, u_int32_t cmd, void *data);
165static errno_t stf_output(ifnet_t ifp, mbuf_t m);
166
167/*
168 * gif_input is the input handler for IP and IPv6 attached to gif
169 */
170static errno_t
171stf_media_input(
172 __unused ifnet_t ifp,
173 protocol_family_t protocol_family,
174 mbuf_t m,
175 __unused char *frame_header)
176{
177 proto_input(protocol_family, m);
178
179 return (0);
180}
181
182
183
184static errno_t
185stf_add_proto(
186 ifnet_t ifp,
187 protocol_family_t protocol_family,
188 __unused const struct ifnet_demux_desc *demux_array,
189 __unused u_int32_t demux_count)
190{
9bccf70c 191 /* Only one protocol may be attached at a time */
2d21ac55 192 struct stf_softc* stf = ifnet_softc(ifp);
91447636
A
193 if (stf->sc_protocol_family == 0)
194 stf->sc_protocol_family = protocol_family;
9bccf70c
A
195 else {
196 printf("stf_add_proto: stf already has a proto\n");
91447636 197 return EBUSY;
9bccf70c 198 }
91447636
A
199
200 return 0;
9bccf70c
A
201}
202
2d21ac55
A
203static errno_t
204stf_del_proto(
205 ifnet_t ifp,
206 protocol_family_t protocol_family)
207{
208 if (((struct stf_softc*)ifnet_softc(ifp))->sc_protocol_family == protocol_family)
209 ((struct stf_softc*)ifnet_softc(ifp))->sc_protocol_family = 0;
210
9bccf70c
A
211 return 0;
212}
213
2d21ac55
A
214static errno_t
215stf_attach_inet6(
216 ifnet_t ifp,
217 protocol_family_t protocol_family)
218{
219 struct ifnet_attach_proto_param reg;
220 errno_t stat;
221
222 if (protocol_family != PF_INET6)
223 return EPROTONOSUPPORT;
9bccf70c 224
91447636 225 bzero(&reg, sizeof(reg));
2d21ac55
A
226 reg.input = stf_media_input;
227 reg.pre_output = stf_pre_output;
9bccf70c 228
2d21ac55
A
229 stat = ifnet_attach_protocol(ifp, protocol_family, &reg);
230 if (stat && stat != EEXIST) {
231 printf("stf_attach_proto_family can't attach interface fam=%d\n",
232 protocol_family);
233 }
9bccf70c 234
55e303ae 235 return stat;
9bccf70c
A
236}
237
2d21ac55 238static errno_t
91447636 239stf_demux(
2d21ac55
A
240 ifnet_t ifp,
241 __unused mbuf_t m,
242 __unused char *frame_ptr,
243 protocol_family_t *protocol_family)
9bccf70c 244{
2d21ac55
A
245 struct stf_softc* stf = ifnet_softc(ifp);
246 *protocol_family = stf->sc_protocol_family;
91447636 247 return 0;
9bccf70c
A
248}
249
2d21ac55
A
250static errno_t
251stf_set_bpf_tap(
252 ifnet_t ifp,
253 bpf_tap_mode mode,
254 bpf_packet_func callback)
255{
256 struct stf_softc *sc = ifnet_softc(ifp);
257
258 sc->tap_mode = mode;
259 sc->tap_callback = callback;
260
261 return 0;
55e303ae 262}
9bccf70c
A
263
264void
265stfattach(void)
266{
9bccf70c 267 struct stf_softc *sc;
2d21ac55 268 int error;
9bccf70c 269 const struct encaptab *p;
2d21ac55 270 struct ifnet_init_params stf_init;
9bccf70c 271
2d21ac55
A
272 error = proto_register_plumber(PF_INET6, APPLE_IF_FAM_STF,
273 stf_attach_inet6, NULL);
274 if (error != 0)
275 printf("proto_register_plumber failed for AF_INET6 error=%d\n", error);
9bccf70c
A
276
277 sc = _MALLOC(sizeof(struct stf_softc), M_DEVBUF, M_WAITOK);
278 if (sc == 0) {
279 printf("stf softc attach failed\n" );
280 return;
281 }
2d21ac55 282
9bccf70c 283 bzero(sc, sizeof(*sc));
2d21ac55 284
9bccf70c
A
285 p = encap_attach_func(AF_INET, IPPROTO_IPV6, stf_encapcheck,
286 &in_stf_protosw, sc);
287 if (p == NULL) {
2d21ac55 288 printf("sftattach encap_attach_func failed\n");
9bccf70c
A
289 FREE(sc, M_DEVBUF);
290 return;
291 }
292 sc->encap_cookie = p;
2d21ac55
A
293
294 bzero(&stf_init, sizeof(stf_init));
295 stf_init.name = "stf";
296 stf_init.unit = 0;
297 stf_init.type = IFT_STF;
298 stf_init.family = IFNET_FAMILY_STF;
299 stf_init.output = stf_output;
300 stf_init.demux = stf_demux;
301 stf_init.add_proto = stf_add_proto;
302 stf_init.del_proto = stf_del_proto;
303 stf_init.softc = sc;
304 stf_init.ioctl = stf_ioctl;
305 stf_init.set_bpf_tap = stf_set_bpf_tap;
306
307 error = ifnet_allocate(&stf_init, &sc->sc_if);
308 if (error != 0) {
309 printf("stfattach, ifnet_allocate failed - %d\n", error);
310 encap_detach(sc->encap_cookie);
311 FREE(sc, M_DEVBUF);
312 return;
313 }
314 ifnet_set_mtu(sc->sc_if, IPV6_MMTU);
315 ifnet_set_flags(sc->sc_if, 0, 0xffff); /* clear all flags */
9bccf70c
A
316#if 0
317 /* turn off ingress filter */
2d21ac55 318 ifnet_set_flags(sc->sc_if, IFF_LINK2, IFF_LINK2);
9bccf70c 319#endif
9bccf70c 320
2d21ac55
A
321#if CONFIG_MACF_NET
322 mac_ifnet_label_init(&sc->sc_if);
323#endif
324
325 error = ifnet_attach(sc->sc_if, NULL);
326 if (error != 0) {
327 printf("stfattach: ifnet_attach returned error=%d\n", error);
328 encap_detach(sc->encap_cookie);
329 ifnet_release(sc->sc_if);
330 FREE(sc, M_DEVBUF);
331 return;
332 }
9bccf70c 333
2d21ac55
A
334 bpfattach(sc->sc_if, DLT_NULL, sizeof(u_int));
335
336 return;
9bccf70c
A
337}
338
339static int
2d21ac55
A
340stf_encapcheck(
341 const struct mbuf *m,
342 __unused int off,
343 int proto,
344 void *arg)
9bccf70c
A
345{
346 struct ip ip;
347 struct in6_ifaddr *ia6;
348 struct stf_softc *sc;
349 struct in_addr a, b;
350
351 sc = (struct stf_softc *)arg;
352 if (sc == NULL)
353 return 0;
354
2d21ac55 355 if ((ifnet_flags(sc->sc_if) & IFF_UP) == 0)
9bccf70c
A
356 return 0;
357
358 /* IFF_LINK0 means "no decapsulation" */
2d21ac55 359 if ((ifnet_flags(sc->sc_if) & IFF_LINK0) != 0)
9bccf70c
A
360 return 0;
361
362 if (proto != IPPROTO_IPV6)
363 return 0;
364
365 /* LINTED const cast */
2d21ac55 366 mbuf_copydata(m, 0, sizeof(ip), &ip);
9bccf70c
A
367
368 if (ip.ip_v != 4)
369 return 0;
370
2d21ac55 371 ia6 = stf_getsrcifa6(sc->sc_if);
9bccf70c
A
372 if (ia6 == NULL)
373 return 0;
374
375 /*
376 * check if IPv4 dst matches the IPv4 address derived from the
377 * local 6to4 address.
378 * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:...
379 */
380 if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst,
381 sizeof(ip.ip_dst)) != 0)
382 return 0;
383
384 /*
385 * check if IPv4 src matches the IPv4 address derived from the
386 * local 6to4 address masked by prefixmask.
387 * success on: src = 10.1.1.1, ia6->ia_addr = 2002:0a00:.../24
388 * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24
389 */
390 bzero(&a, sizeof(a));
391 a.s_addr = GET_V4(&ia6->ia_addr.sin6_addr)->s_addr;
392 a.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr;
393 b = ip.ip_src;
394 b.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr;
395 if (a.s_addr != b.s_addr)
396 return 0;
397
398 /* stf interface makes single side match only */
399 return 32;
400}
401
402static struct in6_ifaddr *
2d21ac55 403stf_getsrcifa6(struct ifnet *ifp)
9bccf70c
A
404{
405 struct ifaddr *ia;
406 struct in_ifaddr *ia4;
407 struct sockaddr_in6 *sin6;
408 struct in_addr in;
409
91447636 410 ifnet_lock_shared(ifp);
9bccf70c
A
411 for (ia = ifp->if_addrlist.tqh_first;
412 ia;
413 ia = ia->ifa_list.tqe_next)
414 {
415 if (ia->ifa_addr == NULL)
416 continue;
417 if (ia->ifa_addr->sa_family != AF_INET6)
418 continue;
419 sin6 = (struct sockaddr_in6 *)ia->ifa_addr;
420 if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr))
421 continue;
422
423 bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in));
91447636 424 lck_mtx_lock(rt_mtx);
9bccf70c
A
425 for (ia4 = TAILQ_FIRST(&in_ifaddrhead);
426 ia4;
427 ia4 = TAILQ_NEXT(ia4, ia_link))
428 {
429 if (ia4->ia_addr.sin_addr.s_addr == in.s_addr)
430 break;
431 }
91447636 432 lck_mtx_unlock(rt_mtx);
9bccf70c
A
433 if (ia4 == NULL)
434 continue;
435
91447636 436 ifnet_lock_done(ifp);
9bccf70c
A
437 return (struct in6_ifaddr *)ia;
438 }
91447636 439 ifnet_lock_done(ifp);
9bccf70c
A
440
441 return NULL;
442}
443
444int
91447636 445stf_pre_output(
2d21ac55
A
446 struct ifnet *ifp,
447 __unused protocol_family_t protocol_family,
448 struct mbuf **m0,
449 const struct sockaddr *dst,
450 __unused void *route,
451 __unused char *desk_linkaddr,
452 __unused char *frame_type)
9bccf70c 453{
2d21ac55 454 struct mbuf *m = *m0;
9bccf70c 455 struct stf_softc *sc;
2d21ac55
A
456 const struct sockaddr_in6 *dst6;
457 const struct in_addr *in4;
9bccf70c
A
458 u_int8_t tos;
459 struct ip *ip;
460 struct ip6_hdr *ip6;
461 struct in6_ifaddr *ia6;
2d21ac55
A
462 struct sockaddr_in *dst4;
463 errno_t result = 0;
9bccf70c 464
2d21ac55
A
465 sc = ifnet_softc(ifp);
466 dst6 = (const struct sockaddr_in6 *)dst;
9bccf70c
A
467
468 /* just in case */
2d21ac55 469 if ((ifnet_flags(ifp) & IFF_UP) == 0) {
9bccf70c
A
470 printf("stf: IFF_DOWN\n");
471 return ENETDOWN;
472 }
473
474 /*
475 * If we don't have an ip4 address that match my inner ip6 address,
476 * we shouldn't generate output. Without this check, we'll end up
477 * using wrong IPv4 source.
478 */
479 ia6 = stf_getsrcifa6(ifp);
480 if (ia6 == NULL) {
481 return ENETDOWN;
482 }
483
2d21ac55 484 if (mbuf_len(m) < sizeof(*ip6)) {
9bccf70c 485 m = m_pullup(m, sizeof(*ip6));
cc9f6e38
A
486 if (!m) {
487 *m0 = NULL; /* makes sure this won't be double freed */
9bccf70c 488 return ENOBUFS;
cc9f6e38 489 }
9bccf70c
A
490 }
491 ip6 = mtod(m, struct ip6_hdr *);
492 tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
493
494 /*
495 * Pickup the right outer dst addr from the list of candidates.
496 * ip6_dst has priority as it may be able to give us shorter IPv4 hops.
497 */
498 if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst))
499 in4 = GET_V4(&ip6->ip6_dst);
500 else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr))
501 in4 = GET_V4(&dst6->sin6_addr);
502 else {
503 return ENETUNREACH;
504 }
505
506 if (ifp->if_bpf) {
2d21ac55 507 /* We need to prepend the address family as a four byte field. */
9bccf70c
A
508 u_int32_t af = AF_INET6;
509
2d21ac55 510 bpf_tap_out(ifp, 0, m, &af, sizeof(af));
9bccf70c
A
511 }
512
513 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
2d21ac55 514 if (m && mbuf_len(m) < sizeof(struct ip))
9bccf70c 515 m = m_pullup(m, sizeof(struct ip));
cc9f6e38
A
516 if (m == NULL) {
517 *m0 = NULL;
9bccf70c 518 return ENOBUFS;
cc9f6e38 519 }
9bccf70c
A
520 ip = mtod(m, struct ip *);
521
522 bzero(ip, sizeof(*ip));
523
524 bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr),
525 &ip->ip_src, sizeof(ip->ip_src));
526 bcopy(in4, &ip->ip_dst, sizeof(ip->ip_dst));
527 ip->ip_p = IPPROTO_IPV6;
528 ip->ip_ttl = ip_stf_ttl;
529 ip->ip_len = m->m_pkthdr.len; /*host order*/
530 if (ifp->if_flags & IFF_LINK1)
531 ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos);
532 else
533 ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos);
534
535 dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst;
536 if (dst4->sin_family != AF_INET ||
537 bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) {
538 /* cache route doesn't match */
2d21ac55 539 printf("stf_output: cached route doesn't match \n");
9bccf70c
A
540 dst4->sin_family = AF_INET;
541 dst4->sin_len = sizeof(struct sockaddr_in);
542 bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr));
543 if (sc->sc_ro.ro_rt) {
91447636 544 rtfree(sc->sc_ro.ro_rt);
9bccf70c
A
545 sc->sc_ro.ro_rt = NULL;
546 }
547 }
548
549 if (sc->sc_ro.ro_rt == NULL) {
550 rtalloc(&sc->sc_ro);
551 if (sc->sc_ro.ro_rt == NULL) {
552 return ENETUNREACH;
553 }
554 }
555
2d21ac55
A
556 result = ip_output_list(m, 0, NULL, &sc->sc_ro, 0, NULL, NULL);
557 /* Assumption: ip_output will free mbuf on errors */
558 /* All the output processing is done here, don't let stf_output be called */
559 if (result == 0)
560 result = EJUSTRETURN;
561 *m0 = NULL;
562 return result;
9bccf70c 563}
2d21ac55
A
564static errno_t
565stf_output(
566 __unused ifnet_t ifp,
567 __unused mbuf_t m)
568{
569 /* All processing is done in stf_pre_output
570 * this shouldn't be called as the pre_output returns "EJUSTRETURN"
571 */
572 return 0;
573}
9bccf70c
A
574
575static int
2d21ac55
A
576stf_checkaddr4(
577 struct stf_softc *sc,
578 const struct in_addr *in,
579 struct ifnet *inifp) /* incoming interface */
9bccf70c
A
580{
581 struct in_ifaddr *ia4;
582
583 /*
584 * reject packets with the following address:
585 * 224.0.0.0/4 0.0.0.0/8 127.0.0.0/8 255.0.0.0/8
586 */
587 if (IN_MULTICAST(ntohl(in->s_addr)))
588 return -1;
589 switch ((ntohl(in->s_addr) & 0xff000000) >> 24) {
590 case 0: case 127: case 255:
591 return -1;
592 }
593
594 /*
595 * reject packets with broadcast
596 */
91447636 597 lck_mtx_lock(rt_mtx);
9bccf70c
A
598 for (ia4 = TAILQ_FIRST(&in_ifaddrhead);
599 ia4;
600 ia4 = TAILQ_NEXT(ia4, ia_link))
601 {
602 if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
603 continue;
91447636
A
604 if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) {
605 lck_mtx_unlock(rt_mtx);
9bccf70c 606 return -1;
91447636 607 }
9bccf70c 608 }
91447636 609 lck_mtx_unlock(rt_mtx);
9bccf70c
A
610
611 /*
612 * perform ingress filter
613 */
2d21ac55 614 if (sc && (ifnet_flags(sc->sc_if) & IFF_LINK2) == 0 && inifp) {
9bccf70c
A
615 struct sockaddr_in sin;
616 struct rtentry *rt;
617
618 bzero(&sin, sizeof(sin));
619 sin.sin_family = AF_INET;
620 sin.sin_len = sizeof(struct sockaddr_in);
621 sin.sin_addr = *in;
622 rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
623 if (!rt || rt->rt_ifp != inifp) {
624#if 1
625 log(LOG_WARNING, "%s: packet from 0x%x dropped "
2d21ac55 626 "due to ingress filter\n", if_name(sc->sc_if),
9bccf70c
A
627 (u_int32_t)ntohl(sin.sin_addr.s_addr));
628#endif
629 if (rt)
630 rtfree(rt);
631 return -1;
632 }
633 rtfree(rt);
634 }
635
636 return 0;
637}
638
639static int
2d21ac55
A
640stf_checkaddr6(
641 struct stf_softc *sc,
642 struct in6_addr *in6,
643 struct ifnet *inifp) /* incoming interface */
9bccf70c
A
644{
645 /*
646 * check 6to4 addresses
647 */
648 if (IN6_IS_ADDR_6TO4(in6))
649 return stf_checkaddr4(sc, GET_V4(in6), inifp);
650
651 /*
652 * reject anything that look suspicious. the test is implemented
653 * in ip6_input too, but we check here as well to
654 * (1) reject bad packets earlier, and
655 * (2) to be safe against future ip6_input change.
656 */
657 if (IN6_IS_ADDR_V4COMPAT(in6) || IN6_IS_ADDR_V4MAPPED(in6))
658 return -1;
659
660 return 0;
661}
662
91447636 663static void
2d21ac55
A
664in_stf_input(
665 struct mbuf *m,
666 int off)
9bccf70c
A
667{
668 struct stf_softc *sc;
669 struct ip *ip;
2d21ac55 670 struct ip6_hdr ip6;
9bccf70c 671 u_int8_t otos, itos;
91447636 672 int proto;
9bccf70c 673 struct ifnet *ifp;
2d21ac55 674 struct ifnet_stat_increment_param stats;
9bccf70c
A
675
676 ip = mtod(m, struct ip *);
677 proto = ip->ip_p;
678
9bccf70c
A
679 if (proto != IPPROTO_IPV6) {
680 m_freem(m);
681 return;
682 }
683
684 ip = mtod(m, struct ip *);
685
686 sc = (struct stf_softc *)encap_getarg(m);
687
2d21ac55 688 if (sc == NULL || (ifnet_flags(sc->sc_if) & IFF_UP) == 0) {
9bccf70c
A
689 m_freem(m);
690 return;
691 }
692
2d21ac55
A
693 ifp = sc->sc_if;
694
695#if MAC_LABEL
696 mac_mbuf_label_associate_ifnet(ifp, m);
697#endif
9bccf70c
A
698
699 /*
700 * perform sanity check against outer src/dst.
701 * for source, perform ingress filter as well.
702 */
703 if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 ||
704 stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) {
705 m_freem(m);
706 return;
707 }
708
709 otos = ip->ip_tos;
2d21ac55 710 mbuf_copydata(m, off, sizeof(ip6), &ip6);
9bccf70c
A
711
712 /*
713 * perform sanity check against inner src/dst.
714 * for source, perform ingress filter as well.
715 */
2d21ac55
A
716 if (stf_checkaddr6(sc, &ip6.ip6_dst, NULL) < 0 ||
717 stf_checkaddr6(sc, &ip6.ip6_src, m->m_pkthdr.rcvif) < 0) {
9bccf70c
A
718 m_freem(m);
719 return;
720 }
721
2d21ac55
A
722 itos = (ntohl(ip6.ip6_flow) >> 20) & 0xff;
723 if ((ifnet_flags(ifp) & IFF_LINK1) != 0)
9bccf70c
A
724 ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
725 else
726 ip_ecn_egress(ECN_NOCARE, &otos, &itos);
2d21ac55
A
727 ip6.ip6_flow &= ~htonl(0xff << 20);
728 ip6.ip6_flow |= htonl((u_int32_t)itos << 20);
9bccf70c
A
729
730 m->m_pkthdr.rcvif = ifp;
2d21ac55
A
731 mbuf_pkthdr_setheader(m, mbuf_data(m));
732 mbuf_adj(m, off);
9bccf70c
A
733
734 if (ifp->if_bpf) {
2d21ac55 735 /* We need to prepend the address family as a four byte field. */
9bccf70c 736 u_int32_t af = AF_INET6;
2d21ac55 737 bpf_tap_in(ifp, 0, m, &af, sizeof(af));
9bccf70c
A
738 }
739
740 /*
741 * Put the packet to the network layer input queue according to the
742 * specified address family.
743 * See net/if_gif.c for possible issues with packet processing
744 * reorder due to extra queueing.
745 */
2d21ac55
A
746 bzero(&stats, sizeof(stats));
747 stats.packets_in = 1;
748 stats.bytes_in = mbuf_pkthdr_len(m);
749 mbuf_pkthdr_setrcvif(m, ifp);
750 ifnet_input(ifp, m, &stats);
751
55e303ae 752 return;
9bccf70c
A
753}
754
9bccf70c 755static void
2d21ac55
A
756stf_rtrequest(
757 __unused int cmd,
758 struct rtentry *rt,
759 __unused struct sockaddr *sa)
9bccf70c
A
760{
761
762 if (rt)
763 rt->rt_rmx.rmx_mtu = IPV6_MMTU;
764}
765
2d21ac55
A
766static errno_t
767stf_ioctl(
768 ifnet_t ifp,
769 u_int32_t cmd,
770 void *data)
9bccf70c
A
771{
772 struct ifaddr *ifa;
773 struct ifreq *ifr;
774 struct sockaddr_in6 *sin6;
775 int error;
776
777 error = 0;
778 switch (cmd) {
779 case SIOCSIFADDR:
780 ifa = (struct ifaddr *)data;
781 if (ifa == NULL || ifa->ifa_addr->sa_family != AF_INET6) {
782 error = EAFNOSUPPORT;
783 break;
784 }
785 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
786 if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) {
91447636
A
787 if ( !(ifnet_flags( ifp ) & IFF_UP) ) {
788 /* do this only if the interface is not already up */
789 ifa->ifa_rtrequest = stf_rtrequest;
790 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
791 }
9bccf70c
A
792 } else
793 error = EINVAL;
794 break;
795
796 case SIOCADDMULTI:
797 case SIOCDELMULTI:
798 ifr = (struct ifreq *)data;
799 if (ifr && ifr->ifr_addr.sa_family == AF_INET6)
800 ;
801 else
802 error = EAFNOSUPPORT;
803 break;
804
805 default:
806 error = EINVAL;
807 break;
808 }
809
810 return error;
811}