]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/ether_inet_pr_module.c
xnu-1504.3.12.tar.gz
[apple/xnu.git] / bsd / net / ether_inet_pr_module.c
CommitLineData
1c79356b 1/*
b7266188 2 * Copyright (c) 2000-2009 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/* #include "vlan.h" */
98#if NVLAN > 0
99#include <net/if_vlan_var.h>
100#endif /* NVLAN > 0 */
2d21ac55
A
101#include <net/ether_if_module.h>
102#if CONFIG_MACF
103#include <security/mac_framework.h>
104#endif
1c79356b 105
91447636 106/* Local function declerations */
2d21ac55
A
107extern void *kdp_get_interface(void);
108extern void kdp_set_ip_and_mac_addresses(struct in_addr *ipaddr,
109 struct ether_addr *macaddr);
1c79356b 110
2d21ac55
A
111static __inline__ void
112_ip_copy(struct in_addr * dst, const struct in_addr * src)
113{
114 *dst = *src;
115 return;
116}
1c79356b 117
91447636 118static void
2d21ac55 119ether_inet_arp_input(
91447636
A
120 struct mbuf *m)
121{
122 struct ether_arp *ea;
123 struct sockaddr_dl sender_hw;
124 struct sockaddr_in sender_ip;
125 struct sockaddr_in target_ip;
126
127 if (mbuf_len(m) < sizeof(*ea) &&
128 mbuf_pullup(&m, sizeof(*ea)) != 0)
129 return;
130
131 ea = mbuf_data(m);
132
133 /* Verify this is an ethernet/ip arp and address lengths are correct */
134 if (ntohs(ea->arp_hrd) != ARPHRD_ETHER ||
135 ntohs(ea->arp_pro) != ETHERTYPE_IP ||
136 ea->arp_pln != sizeof(struct in_addr) ||
137 ea->arp_hln != ETHER_ADDR_LEN) {
138 mbuf_free(m);
139 return;
140 }
141
13fec989
A
142 /* Verify the sender is not broadcast */
143 if (bcmp(ea->arp_sha, etherbroadcastaddr, ETHER_ADDR_LEN) == 0) {
91447636
A
144 mbuf_free(m);
145 return;
146 }
147
148 bzero(&sender_ip, sizeof(sender_ip));
149 sender_ip.sin_len = sizeof(sender_ip);
150 sender_ip.sin_family = AF_INET;
2d21ac55 151 _ip_copy(&sender_ip.sin_addr, (const struct in_addr *)ea->arp_spa);
91447636 152 target_ip = sender_ip;
2d21ac55 153 _ip_copy(&target_ip.sin_addr, (const struct in_addr *)ea->arp_tpa);
91447636
A
154
155 bzero(&sender_hw, sizeof(sender_hw));
156 sender_hw.sdl_len = sizeof(sender_hw);
157 sender_hw.sdl_family = AF_LINK;
158 sender_hw.sdl_type = IFT_ETHER;
159 sender_hw.sdl_alen = ETHER_ADDR_LEN;
160 bcopy(ea->arp_sha, LLADDR(&sender_hw), ETHER_ADDR_LEN);
161
162 arp_ip_handle_input(mbuf_pkthdr_rcvif(m), ntohs(ea->arp_op), &sender_hw, &sender_ip, &target_ip);
163 mbuf_free(m);
164}
1c79356b
A
165
166/*
167 * Process a received Ethernet packet;
168 * the packet is in the mbuf chain m without
169 * the ether header, which is provided separately.
170 */
91447636 171static errno_t
2d21ac55 172ether_inet_input(
91447636
A
173 __unused ifnet_t ifp,
174 __unused protocol_family_t protocol_family,
2d21ac55 175 mbuf_t m_list)
1c79356b 176{
2d21ac55
A
177 mbuf_t m;
178 mbuf_t *tailptr = &m_list;
179 mbuf_t nextpkt;
180
181 /* Strip ARP and non-IP packets out of the list */
182 for (m = m_list; m; m = nextpkt) {
183 struct ether_header *eh = mbuf_pkthdr_header(m);
184
185 nextpkt = m->m_nextpkt;
91447636 186
2d21ac55
A
187 if (eh->ether_type == htons(ETHERTYPE_IP)) {
188 /* put this packet in the list */
189 *tailptr = m;
190 tailptr = &m->m_nextpkt;
191 }
192 else {
193 /* Pass ARP packets to arp input */
194 m->m_nextpkt = NULL;
195 if (eh->ether_type == htons(ETHERTYPE_ARP))
196 ether_inet_arp_input(m);
197 else
198 mbuf_freem(m);
199 }
200 }
201
202 *tailptr = NULL;
203
204 /* Pass IP list to ip input */
205 if (m_list != NULL && proto_input(PF_INET, m_list) != 0)
206 {
207 mbuf_freem_list(m_list);
208 }
91447636 209
1c79356b
A
210 return 0;
211}
212
91447636 213static errno_t
2d21ac55 214ether_inet_pre_output(
91447636
A
215 ifnet_t ifp,
216 __unused protocol_family_t protocol_family,
217 mbuf_t *m0,
218 const struct sockaddr *dst_netaddr,
219 void* route,
220 char *type,
221 char *edst)
1c79356b 222{
1c79356b 223 register struct mbuf *m = *m0;
2d21ac55 224 const struct ether_header *eh;
91447636 225 errno_t result = 0;
1c79356b
A
226
227
228 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
91447636 229 return ENETDOWN;
1c79356b 230
1c79356b
A
231 /*
232 * Tell ether_frameout it's ok to loop packet unless negated below.
233 */
234 m->m_flags |= M_LOOP;
235
236 switch (dst_netaddr->sa_family) {
91447636
A
237
238 case AF_INET: {
239 struct sockaddr_dl ll_dest;
240 result = arp_lookup_ip(ifp, (const struct sockaddr_in*)dst_netaddr,
241 &ll_dest, sizeof(ll_dest), (route_t)route, *m0);
242 if (result == 0) {
243 bcopy(LLADDR(&ll_dest), edst, ETHER_ADDR_LEN);
244 *(u_int16_t*)type = htons(ETHERTYPE_IP);
245 }
246 }
247 break;
248
249 case pseudo_AF_HDRCMPLT:
250 case AF_UNSPEC:
251 m->m_flags &= ~M_LOOP;
2d21ac55 252 eh = (const struct ether_header *)dst_netaddr->sa_data;
91447636
A
253 (void)memcpy(edst, eh->ether_dhost, 6);
254 *(u_short *)type = eh->ether_type;
255 break;
256
257 default:
258 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
259 dst_netaddr->sa_family);
260
261 result = EAFNOSUPPORT;
262 }
1c79356b 263
91447636
A
264 return result;
265}
1c79356b 266
91447636
A
267static errno_t
268ether_inet_resolve_multi(
269 ifnet_t ifp,
270 const struct sockaddr *proto_addr,
271 struct sockaddr_dl *out_ll,
272 size_t ll_len)
273{
274 static const size_t minsize = offsetof(struct sockaddr_dl, sdl_data[0]) + ETHER_ADDR_LEN;
275 const struct sockaddr_in *sin = (const struct sockaddr_in*)proto_addr;
276
277 if (proto_addr->sa_family != AF_INET)
278 return EAFNOSUPPORT;
279
280 if (proto_addr->sa_len < sizeof(struct sockaddr_in))
281 return EINVAL;
1c79356b 282
91447636
A
283 if (ll_len < minsize)
284 return EMSGSIZE;
285
286 bzero(out_ll, minsize);
287 out_ll->sdl_len = minsize;
288 out_ll->sdl_family = AF_LINK;
289 out_ll->sdl_index = ifp->if_index;
290 out_ll->sdl_type = IFT_ETHER;
291 out_ll->sdl_nlen = 0;
292 out_ll->sdl_alen = ETHER_ADDR_LEN;
293 out_ll->sdl_slen = 0;
294 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, LLADDR(out_ll));
295
296 return 0;
1c79356b
A
297}
298
91447636
A
299static errno_t
300ether_inet_prmod_ioctl(
b0d623f7 301 ifnet_t ifp,
91447636 302 __unused protocol_family_t protocol_family,
b0d623f7
A
303 u_long command,
304 void *data)
1c79356b 305{
91447636
A
306 ifaddr_t ifa = data;
307 struct ifreq *ifr = data;
1c79356b 308 int error = 0;
1c79356b
A
309
310
1c79356b 311 switch (command) {
1c79356b 312 case SIOCSIFADDR:
2d21ac55 313 case SIOCAIFADDR:
91447636
A
314 if ((ifnet_flags(ifp) & IFF_RUNNING) == 0) {
315 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
316 ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL);
317 }
1c79356b 318
91447636 319 switch (ifaddr_address_family(ifa)) {
1c79356b
A
320
321 case AF_INET:
322
91447636 323 inet_arp_init_ifaddr(ifp, ifa);
9bccf70c 324 /*
2d21ac55
A
325 * Register new IP and MAC addresses with the kernel
326 * debugger if the interface is the same as was registered
327 * by IOKernelDebugger. If no interface was registered,
328 * fall back and just match against en0 interface.
329 * Do this only for the first address of the interface
330 * and not for aliases.
9bccf70c 331 */
2d21ac55
A
332 if (command == SIOCSIFADDR &&
333 ((kdp_get_interface() != 0 &&
334 kdp_get_interface() == ifp->if_softc) ||
335 (kdp_get_interface() == 0 && ifp->if_unit == 0)))
336 kdp_set_ip_and_mac_addresses(&(IA_SIN(ifa)->sin_addr),
337 ifnet_lladdr(ifp));
9bccf70c 338
1c79356b
A
339 break;
340
341 default:
342 break;
343 }
344
345 break;
346
347 case SIOCGIFADDR:
2d21ac55
A
348 ifnet_lladdr_copy_bytes(ifp, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN);
349 break;
1c79356b
A
350
351 default:
2d21ac55
A
352 error = EOPNOTSUPP;
353 break;
1c79356b
A
354 }
355
1c79356b
A
356 return (error);
357}
358
91447636
A
359static void
360ether_inet_event(
361 ifnet_t ifp,
362 __unused protocol_family_t protocol,
363 const struct kev_msg *event)
364{
365 ifaddr_t *addresses;
366
367 if (event->vendor_code != KEV_VENDOR_APPLE ||
368 event->kev_class != KEV_NETWORK_CLASS ||
369 event->kev_subclass != KEV_DL_SUBCLASS ||
370 event->event_code != KEV_DL_LINK_ADDRESS_CHANGED) {
371 return;
372 }
373
374 if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0) {
375 int i;
376
377 for (i = 0; addresses[i] != NULL; i++) {
378 inet_arp_init_ifaddr(ifp, addresses[i]);
379 }
380
381 ifnet_free_address_list(addresses);
382 }
383}
1c79356b 384
91447636
A
385static errno_t
386ether_inet_arp(
387 ifnet_t ifp,
388 u_short arpop,
389 const struct sockaddr_dl* sender_hw,
390 const struct sockaddr* sender_proto,
391 const struct sockaddr_dl* target_hw,
392 const struct sockaddr* target_proto)
393{
394 mbuf_t m;
395 errno_t result;
396 struct ether_header *eh;
397 struct ether_arp *ea;
398 const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto;
399 const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto;
400 char *datap;
401
402 if (target_ip == NULL)
403 return EINVAL;
404
405 if ((sender_ip && sender_ip->sin_family != AF_INET) ||
2d21ac55 406 target_ip->sin_family != AF_INET)
91447636
A
407 return EAFNOSUPPORT;
408
2d21ac55 409 result = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_DATA, &m);
91447636
A
410 if (result != 0)
411 return result;
412
413 mbuf_setlen(m, sizeof(*ea));
414 mbuf_pkthdr_setlen(m, sizeof(*ea));
415
416 /* Move the data pointer in the mbuf to the end, aligned to 4 bytes */
417 datap = mbuf_datastart(m);
418 datap += mbuf_trailingspace(m);
b0d623f7 419 datap -= (((uintptr_t)datap) & 0x3);
91447636
A
420 mbuf_setdata(m, datap, sizeof(*ea));
421 ea = mbuf_data(m);
422
2d21ac55
A
423 /*
424 * Prepend the ethernet header, we will send the raw frame;
425 * callee frees the original mbuf when allocation fails.
426 */
427 result = mbuf_prepend(&m, sizeof(*eh), MBUF_DONTWAIT);
428 if (result != 0)
429 return result;
430
91447636
A
431 eh = mbuf_data(m);
432 eh->ether_type = htons(ETHERTYPE_ARP);
2d21ac55
A
433
434#if CONFIG_MACF_NET
435 mac_mbuf_label_associate_linklayer(ifp, m);
436#endif
91447636
A
437
438 /* Fill out the arp header */
439 ea->arp_pro = htons(ETHERTYPE_IP);
440 ea->arp_hln = sizeof(ea->arp_sha);
441 ea->arp_pln = sizeof(ea->arp_spa);
442 ea->arp_hrd = htons(ARPHRD_ETHER);
443 ea->arp_op = htons(arpop);
444
445 /* Sender Hardware */
446 if (sender_hw != NULL) {
447 bcopy(CONST_LLADDR(sender_hw), ea->arp_sha, sizeof(ea->arp_sha));
448 }
449 else {
450 ifnet_lladdr_copy_bytes(ifp, ea->arp_sha, ETHER_ADDR_LEN);
451 }
452 ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, sizeof(eh->ether_shost));
453
454 /* Sender IP */
455 if (sender_ip != NULL) {
456 bcopy(&sender_ip->sin_addr, ea->arp_spa, sizeof(ea->arp_spa));
457 }
458 else {
459 struct ifaddr *ifa;
460
461 /* Look for an IP address to use as our source */
462 ifnet_lock_shared(ifp);
463 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
464 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
465 break;
466 }
467 if (ifa) {
468 bcopy(&((struct sockaddr_in*)ifa->ifa_addr)->sin_addr, ea->arp_spa,
469 sizeof(ea->arp_spa));
470 }
471 ifnet_lock_done(ifp);
472
473 if (ifa == NULL) {
474 mbuf_free(m);
475 return ENXIO;
476 }
477 }
478
479 /* Target Hardware */
480 if (target_hw == 0) {
481 bzero(ea->arp_tha, sizeof(ea->arp_tha));
482 bcopy(etherbroadcastaddr, eh->ether_dhost, sizeof(eh->ether_dhost));
483 }
484 else {
485 bcopy(CONST_LLADDR(target_hw), ea->arp_tha, sizeof(ea->arp_tha));
486 bcopy(CONST_LLADDR(target_hw), eh->ether_dhost, sizeof(eh->ether_dhost));
487 }
488
489 /* Target IP */
490 bcopy(&target_ip->sin_addr, ea->arp_tpa, sizeof(ea->arp_tpa));
491
492 ifnet_output_raw(ifp, PF_INET, m);
493
494 return 0;
495}
1c79356b 496
2d21ac55 497errno_t
91447636
A
498ether_attach_inet(
499 struct ifnet *ifp,
2d21ac55 500 __unused protocol_family_t proto_family)
1c79356b 501{
2d21ac55 502 struct ifnet_attach_proto_param_v2 proto;
91447636
A
503 struct ifnet_demux_desc demux[2];
504 u_short en_native=htons(ETHERTYPE_IP);
505 u_short arp_native=htons(ETHERTYPE_ARP);
506 errno_t error;
507
508 bzero(&demux[0], sizeof(demux));
509 demux[0].type = DLIL_DESC_ETYPE2;
510 demux[0].data = &en_native;
511 demux[0].datalen = sizeof(en_native);
512 demux[1].type = DLIL_DESC_ETYPE2;
513 demux[1].data = &arp_native;
514 demux[1].datalen = sizeof(arp_native);
515
516 bzero(&proto, sizeof(proto));
517 proto.demux_list = demux;
518 proto.demux_count = sizeof(demux) / sizeof(demux[0]);
2d21ac55
A
519 proto.input = ether_inet_input;
520 proto.pre_output = ether_inet_pre_output;
91447636
A
521 proto.ioctl = ether_inet_prmod_ioctl;
522 proto.event = ether_inet_event;
523 proto.resolve = ether_inet_resolve_multi;
524 proto.send_arp = ether_inet_arp;
525
2d21ac55 526 error = ifnet_attach_protocol_v2(ifp, proto_family, &proto);
91447636
A
527 if (error && error != EEXIST) {
528 printf("WARNING: ether_attach_inet can't attach ip to %s%d\n",
529 ifp->if_name, ifp->if_unit);
530 }
531 return error;
1c79356b 532}
0b4e3aa0 533
2d21ac55 534void
91447636
A
535ether_detach_inet(
536 struct ifnet *ifp,
2d21ac55 537 protocol_family_t proto_family)
0b4e3aa0 538{
2d21ac55 539 (void)ifnet_detach_protocol(ifp, proto_family);
0b4e3aa0
A
540}
541