]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/ether_inet_pr_module.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / net / ether_inet_pr_module.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1982, 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 */
2d21ac55
A
61/*
62 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
63 * support for mandatory and extensible security protections. This notice
64 * is included in support of clause 2.2 (b) of the Apple Public License,
65 * Version 2.0.
66 */
1c79356b
A
67
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/kernel.h>
72#include <sys/malloc.h>
73#include <sys/mbuf.h>
74#include <sys/socket.h>
75#include <sys/sockio.h>
76#include <sys/sysctl.h>
91447636 77#include <kern/lock.h>
1c79356b
A
78
79#include <net/if.h>
1c79356b
A
80#include <net/route.h>
81#include <net/if_llc.h>
82#include <net/if_dl.h>
83#include <net/if_types.h>
91447636 84#include <net/kpi_protocol.h>
1c79356b
A
85
86#include <netinet/in.h>
87#include <netinet/in_var.h>
88#include <netinet/if_ether.h>
89#include <netinet/in_systm.h>
90#include <netinet/ip.h>
91447636 91#include <netinet/in_arp.h>
1c79356b
A
92
93#include <sys/socketvar.h>
94
95#include <net/dlil.h>
96
1c79356b
A
97#if BRIDGE
98#include <net/bridge.h>
99#endif
100
101/* #include "vlan.h" */
102#if NVLAN > 0
103#include <net/if_vlan_var.h>
104#endif /* NVLAN > 0 */
2d21ac55
A
105#include <net/ether_if_module.h>
106#if CONFIG_MACF
107#include <security/mac_framework.h>
108#endif
1c79356b 109
91447636 110/* Local function declerations */
2d21ac55
A
111extern void *kdp_get_interface(void);
112extern void kdp_set_ip_and_mac_addresses(struct in_addr *ipaddr,
113 struct ether_addr *macaddr);
1c79356b 114
2d21ac55
A
115static __inline__ void
116_ip_copy(struct in_addr * dst, const struct in_addr * src)
117{
118 *dst = *src;
119 return;
120}
1c79356b 121
91447636 122static void
2d21ac55 123ether_inet_arp_input(
91447636
A
124 struct mbuf *m)
125{
126 struct ether_arp *ea;
127 struct sockaddr_dl sender_hw;
128 struct sockaddr_in sender_ip;
129 struct sockaddr_in target_ip;
130
131 if (mbuf_len(m) < sizeof(*ea) &&
132 mbuf_pullup(&m, sizeof(*ea)) != 0)
133 return;
134
135 ea = mbuf_data(m);
136
137 /* Verify this is an ethernet/ip arp and address lengths are correct */
138 if (ntohs(ea->arp_hrd) != ARPHRD_ETHER ||
139 ntohs(ea->arp_pro) != ETHERTYPE_IP ||
140 ea->arp_pln != sizeof(struct in_addr) ||
141 ea->arp_hln != ETHER_ADDR_LEN) {
142 mbuf_free(m);
143 return;
144 }
145
13fec989
A
146 /* Verify the sender is not broadcast */
147 if (bcmp(ea->arp_sha, etherbroadcastaddr, ETHER_ADDR_LEN) == 0) {
91447636
A
148 mbuf_free(m);
149 return;
150 }
151
152 bzero(&sender_ip, sizeof(sender_ip));
153 sender_ip.sin_len = sizeof(sender_ip);
154 sender_ip.sin_family = AF_INET;
2d21ac55 155 _ip_copy(&sender_ip.sin_addr, (const struct in_addr *)ea->arp_spa);
91447636 156 target_ip = sender_ip;
2d21ac55 157 _ip_copy(&target_ip.sin_addr, (const struct in_addr *)ea->arp_tpa);
91447636
A
158
159 bzero(&sender_hw, sizeof(sender_hw));
160 sender_hw.sdl_len = sizeof(sender_hw);
161 sender_hw.sdl_family = AF_LINK;
162 sender_hw.sdl_type = IFT_ETHER;
163 sender_hw.sdl_alen = ETHER_ADDR_LEN;
164 bcopy(ea->arp_sha, LLADDR(&sender_hw), ETHER_ADDR_LEN);
165
166 arp_ip_handle_input(mbuf_pkthdr_rcvif(m), ntohs(ea->arp_op), &sender_hw, &sender_ip, &target_ip);
167 mbuf_free(m);
168}
1c79356b
A
169
170/*
171 * Process a received Ethernet packet;
172 * the packet is in the mbuf chain m without
173 * the ether header, which is provided separately.
174 */
91447636 175static errno_t
2d21ac55 176ether_inet_input(
91447636
A
177 __unused ifnet_t ifp,
178 __unused protocol_family_t protocol_family,
2d21ac55 179 mbuf_t m_list)
1c79356b 180{
2d21ac55
A
181 mbuf_t m;
182 mbuf_t *tailptr = &m_list;
183 mbuf_t nextpkt;
184
185 /* Strip ARP and non-IP packets out of the list */
186 for (m = m_list; m; m = nextpkt) {
187 struct ether_header *eh = mbuf_pkthdr_header(m);
188
189 nextpkt = m->m_nextpkt;
91447636 190
2d21ac55
A
191 if (eh->ether_type == htons(ETHERTYPE_IP)) {
192 /* put this packet in the list */
193 *tailptr = m;
194 tailptr = &m->m_nextpkt;
195 }
196 else {
197 /* Pass ARP packets to arp input */
198 m->m_nextpkt = NULL;
199 if (eh->ether_type == htons(ETHERTYPE_ARP))
200 ether_inet_arp_input(m);
201 else
202 mbuf_freem(m);
203 }
204 }
205
206 *tailptr = NULL;
207
208 /* Pass IP list to ip input */
209 if (m_list != NULL && proto_input(PF_INET, m_list) != 0)
210 {
211 mbuf_freem_list(m_list);
212 }
91447636 213
1c79356b
A
214 return 0;
215}
216
91447636 217static errno_t
2d21ac55 218ether_inet_pre_output(
91447636
A
219 ifnet_t ifp,
220 __unused protocol_family_t protocol_family,
221 mbuf_t *m0,
222 const struct sockaddr *dst_netaddr,
223 void* route,
224 char *type,
225 char *edst)
1c79356b 226{
1c79356b 227 register struct mbuf *m = *m0;
2d21ac55 228 const struct ether_header *eh;
91447636 229 errno_t result = 0;
1c79356b
A
230
231
232 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
91447636 233 return ENETDOWN;
1c79356b 234
1c79356b
A
235 /*
236 * Tell ether_frameout it's ok to loop packet unless negated below.
237 */
238 m->m_flags |= M_LOOP;
239
240 switch (dst_netaddr->sa_family) {
91447636
A
241
242 case AF_INET: {
243 struct sockaddr_dl ll_dest;
244 result = arp_lookup_ip(ifp, (const struct sockaddr_in*)dst_netaddr,
245 &ll_dest, sizeof(ll_dest), (route_t)route, *m0);
246 if (result == 0) {
247 bcopy(LLADDR(&ll_dest), edst, ETHER_ADDR_LEN);
248 *(u_int16_t*)type = htons(ETHERTYPE_IP);
249 }
250 }
251 break;
252
253 case pseudo_AF_HDRCMPLT:
254 case AF_UNSPEC:
255 m->m_flags &= ~M_LOOP;
2d21ac55 256 eh = (const struct ether_header *)dst_netaddr->sa_data;
91447636
A
257 (void)memcpy(edst, eh->ether_dhost, 6);
258 *(u_short *)type = eh->ether_type;
259 break;
260
261 default:
262 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
263 dst_netaddr->sa_family);
264
265 result = EAFNOSUPPORT;
266 }
1c79356b 267
91447636
A
268 return result;
269}
1c79356b 270
91447636
A
271static errno_t
272ether_inet_resolve_multi(
273 ifnet_t ifp,
274 const struct sockaddr *proto_addr,
275 struct sockaddr_dl *out_ll,
276 size_t ll_len)
277{
278 static const size_t minsize = offsetof(struct sockaddr_dl, sdl_data[0]) + ETHER_ADDR_LEN;
279 const struct sockaddr_in *sin = (const struct sockaddr_in*)proto_addr;
280
281 if (proto_addr->sa_family != AF_INET)
282 return EAFNOSUPPORT;
283
284 if (proto_addr->sa_len < sizeof(struct sockaddr_in))
285 return EINVAL;
1c79356b 286
91447636
A
287 if (ll_len < minsize)
288 return EMSGSIZE;
289
290 bzero(out_ll, minsize);
291 out_ll->sdl_len = minsize;
292 out_ll->sdl_family = AF_LINK;
293 out_ll->sdl_index = ifp->if_index;
294 out_ll->sdl_type = IFT_ETHER;
295 out_ll->sdl_nlen = 0;
296 out_ll->sdl_alen = ETHER_ADDR_LEN;
297 out_ll->sdl_slen = 0;
298 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, LLADDR(out_ll));
299
300 return 0;
1c79356b
A
301}
302
91447636
A
303static errno_t
304ether_inet_prmod_ioctl(
305 ifnet_t ifp,
306 __unused protocol_family_t protocol_family,
307 u_int32_t command,
308 void* data)
1c79356b 309{
91447636
A
310 ifaddr_t ifa = data;
311 struct ifreq *ifr = data;
1c79356b 312 int error = 0;
1c79356b
A
313
314
1c79356b 315 switch (command) {
1c79356b 316 case SIOCSIFADDR:
2d21ac55 317 case SIOCAIFADDR:
91447636
A
318 if ((ifnet_flags(ifp) & IFF_RUNNING) == 0) {
319 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
320 ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL);
321 }
1c79356b 322
91447636 323 switch (ifaddr_address_family(ifa)) {
1c79356b
A
324
325 case AF_INET:
326
91447636 327 inet_arp_init_ifaddr(ifp, ifa);
9bccf70c 328 /*
2d21ac55
A
329 * Register new IP and MAC addresses with the kernel
330 * debugger if the interface is the same as was registered
331 * by IOKernelDebugger. If no interface was registered,
332 * fall back and just match against en0 interface.
333 * Do this only for the first address of the interface
334 * and not for aliases.
9bccf70c 335 */
2d21ac55
A
336 if (command == SIOCSIFADDR &&
337 ((kdp_get_interface() != 0 &&
338 kdp_get_interface() == ifp->if_softc) ||
339 (kdp_get_interface() == 0 && ifp->if_unit == 0)))
340 kdp_set_ip_and_mac_addresses(&(IA_SIN(ifa)->sin_addr),
341 ifnet_lladdr(ifp));
9bccf70c 342
1c79356b
A
343 break;
344
345 default:
346 break;
347 }
348
349 break;
350
351 case SIOCGIFADDR:
2d21ac55
A
352 ifnet_lladdr_copy_bytes(ifp, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN);
353 break;
1c79356b
A
354
355 default:
2d21ac55
A
356 error = EOPNOTSUPP;
357 break;
1c79356b
A
358 }
359
1c79356b
A
360 return (error);
361}
362
91447636
A
363static void
364ether_inet_event(
365 ifnet_t ifp,
366 __unused protocol_family_t protocol,
367 const struct kev_msg *event)
368{
369 ifaddr_t *addresses;
370
371 if (event->vendor_code != KEV_VENDOR_APPLE ||
372 event->kev_class != KEV_NETWORK_CLASS ||
373 event->kev_subclass != KEV_DL_SUBCLASS ||
374 event->event_code != KEV_DL_LINK_ADDRESS_CHANGED) {
375 return;
376 }
377
378 if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0) {
379 int i;
380
381 for (i = 0; addresses[i] != NULL; i++) {
382 inet_arp_init_ifaddr(ifp, addresses[i]);
383 }
384
385 ifnet_free_address_list(addresses);
386 }
387}
1c79356b 388
91447636
A
389static errno_t
390ether_inet_arp(
391 ifnet_t ifp,
392 u_short arpop,
393 const struct sockaddr_dl* sender_hw,
394 const struct sockaddr* sender_proto,
395 const struct sockaddr_dl* target_hw,
396 const struct sockaddr* target_proto)
397{
398 mbuf_t m;
399 errno_t result;
400 struct ether_header *eh;
401 struct ether_arp *ea;
402 const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto;
403 const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto;
404 char *datap;
405
406 if (target_ip == NULL)
407 return EINVAL;
408
409 if ((sender_ip && sender_ip->sin_family != AF_INET) ||
2d21ac55 410 target_ip->sin_family != AF_INET)
91447636
A
411 return EAFNOSUPPORT;
412
2d21ac55 413 result = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_DATA, &m);
91447636
A
414 if (result != 0)
415 return result;
416
417 mbuf_setlen(m, sizeof(*ea));
418 mbuf_pkthdr_setlen(m, sizeof(*ea));
419
420 /* Move the data pointer in the mbuf to the end, aligned to 4 bytes */
421 datap = mbuf_datastart(m);
422 datap += mbuf_trailingspace(m);
423 datap -= (((u_long)datap) & 0x3);
424 mbuf_setdata(m, datap, sizeof(*ea));
425 ea = mbuf_data(m);
426
2d21ac55
A
427 /*
428 * Prepend the ethernet header, we will send the raw frame;
429 * callee frees the original mbuf when allocation fails.
430 */
431 result = mbuf_prepend(&m, sizeof(*eh), MBUF_DONTWAIT);
432 if (result != 0)
433 return result;
434
91447636
A
435 eh = mbuf_data(m);
436 eh->ether_type = htons(ETHERTYPE_ARP);
2d21ac55
A
437
438#if CONFIG_MACF_NET
439 mac_mbuf_label_associate_linklayer(ifp, m);
440#endif
91447636
A
441
442 /* Fill out the arp header */
443 ea->arp_pro = htons(ETHERTYPE_IP);
444 ea->arp_hln = sizeof(ea->arp_sha);
445 ea->arp_pln = sizeof(ea->arp_spa);
446 ea->arp_hrd = htons(ARPHRD_ETHER);
447 ea->arp_op = htons(arpop);
448
449 /* Sender Hardware */
450 if (sender_hw != NULL) {
451 bcopy(CONST_LLADDR(sender_hw), ea->arp_sha, sizeof(ea->arp_sha));
452 }
453 else {
454 ifnet_lladdr_copy_bytes(ifp, ea->arp_sha, ETHER_ADDR_LEN);
455 }
456 ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, sizeof(eh->ether_shost));
457
458 /* Sender IP */
459 if (sender_ip != NULL) {
460 bcopy(&sender_ip->sin_addr, ea->arp_spa, sizeof(ea->arp_spa));
461 }
462 else {
463 struct ifaddr *ifa;
464
465 /* Look for an IP address to use as our source */
466 ifnet_lock_shared(ifp);
467 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
468 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
469 break;
470 }
471 if (ifa) {
472 bcopy(&((struct sockaddr_in*)ifa->ifa_addr)->sin_addr, ea->arp_spa,
473 sizeof(ea->arp_spa));
474 }
475 ifnet_lock_done(ifp);
476
477 if (ifa == NULL) {
478 mbuf_free(m);
479 return ENXIO;
480 }
481 }
482
483 /* Target Hardware */
484 if (target_hw == 0) {
485 bzero(ea->arp_tha, sizeof(ea->arp_tha));
486 bcopy(etherbroadcastaddr, eh->ether_dhost, sizeof(eh->ether_dhost));
487 }
488 else {
489 bcopy(CONST_LLADDR(target_hw), ea->arp_tha, sizeof(ea->arp_tha));
490 bcopy(CONST_LLADDR(target_hw), eh->ether_dhost, sizeof(eh->ether_dhost));
491 }
492
493 /* Target IP */
494 bcopy(&target_ip->sin_addr, ea->arp_tpa, sizeof(ea->arp_tpa));
495
496 ifnet_output_raw(ifp, PF_INET, m);
497
498 return 0;
499}
1c79356b 500
2d21ac55 501errno_t
91447636
A
502ether_attach_inet(
503 struct ifnet *ifp,
2d21ac55 504 __unused protocol_family_t proto_family)
1c79356b 505{
2d21ac55 506 struct ifnet_attach_proto_param_v2 proto;
91447636
A
507 struct ifnet_demux_desc demux[2];
508 u_short en_native=htons(ETHERTYPE_IP);
509 u_short arp_native=htons(ETHERTYPE_ARP);
510 errno_t error;
511
512 bzero(&demux[0], sizeof(demux));
513 demux[0].type = DLIL_DESC_ETYPE2;
514 demux[0].data = &en_native;
515 demux[0].datalen = sizeof(en_native);
516 demux[1].type = DLIL_DESC_ETYPE2;
517 demux[1].data = &arp_native;
518 demux[1].datalen = sizeof(arp_native);
519
520 bzero(&proto, sizeof(proto));
521 proto.demux_list = demux;
522 proto.demux_count = sizeof(demux) / sizeof(demux[0]);
2d21ac55
A
523 proto.input = ether_inet_input;
524 proto.pre_output = ether_inet_pre_output;
91447636
A
525 proto.ioctl = ether_inet_prmod_ioctl;
526 proto.event = ether_inet_event;
527 proto.resolve = ether_inet_resolve_multi;
528 proto.send_arp = ether_inet_arp;
529
2d21ac55 530 error = ifnet_attach_protocol_v2(ifp, proto_family, &proto);
91447636
A
531 if (error && error != EEXIST) {
532 printf("WARNING: ether_attach_inet can't attach ip to %s%d\n",
533 ifp->if_name, ifp->if_unit);
534 }
535 return error;
1c79356b 536}
0b4e3aa0 537
2d21ac55 538void
91447636
A
539ether_detach_inet(
540 struct ifnet *ifp,
2d21ac55 541 protocol_family_t proto_family)
0b4e3aa0 542{
2d21ac55 543 (void)ifnet_detach_protocol(ifp, proto_family);
0b4e3aa0
A
544}
545