]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ether_inet_pr_module.c
xnu-1504.3.12.tar.gz
[apple/xnu.git] / bsd / net / ether_inet_pr_module.c
1 /*
2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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 */
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 */
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>
77 #include <kern/lock.h>
78
79 #include <net/if.h>
80 #include <net/route.h>
81 #include <net/if_llc.h>
82 #include <net/if_dl.h>
83 #include <net/if_types.h>
84 #include <net/kpi_protocol.h>
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>
91 #include <netinet/in_arp.h>
92
93 #include <sys/socketvar.h>
94
95 #include <net/dlil.h>
96
97 /* #include "vlan.h" */
98 #if NVLAN > 0
99 #include <net/if_vlan_var.h>
100 #endif /* NVLAN > 0 */
101 #include <net/ether_if_module.h>
102 #if CONFIG_MACF
103 #include <security/mac_framework.h>
104 #endif
105
106 /* Local function declerations */
107 extern void *kdp_get_interface(void);
108 extern void kdp_set_ip_and_mac_addresses(struct in_addr *ipaddr,
109 struct ether_addr *macaddr);
110
111 static __inline__ void
112 _ip_copy(struct in_addr * dst, const struct in_addr * src)
113 {
114 *dst = *src;
115 return;
116 }
117
118 static void
119 ether_inet_arp_input(
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
142 /* Verify the sender is not broadcast */
143 if (bcmp(ea->arp_sha, etherbroadcastaddr, ETHER_ADDR_LEN) == 0) {
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;
151 _ip_copy(&sender_ip.sin_addr, (const struct in_addr *)ea->arp_spa);
152 target_ip = sender_ip;
153 _ip_copy(&target_ip.sin_addr, (const struct in_addr *)ea->arp_tpa);
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 }
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 */
171 static errno_t
172 ether_inet_input(
173 __unused ifnet_t ifp,
174 __unused protocol_family_t protocol_family,
175 mbuf_t m_list)
176 {
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;
186
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 }
209
210 return 0;
211 }
212
213 static errno_t
214 ether_inet_pre_output(
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)
222 {
223 register struct mbuf *m = *m0;
224 const struct ether_header *eh;
225 errno_t result = 0;
226
227
228 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
229 return ENETDOWN;
230
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) {
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;
252 eh = (const struct ether_header *)dst_netaddr->sa_data;
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 }
263
264 return result;
265 }
266
267 static errno_t
268 ether_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;
282
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;
297 }
298
299 static errno_t
300 ether_inet_prmod_ioctl(
301 ifnet_t ifp,
302 __unused protocol_family_t protocol_family,
303 u_long command,
304 void *data)
305 {
306 ifaddr_t ifa = data;
307 struct ifreq *ifr = data;
308 int error = 0;
309
310
311 switch (command) {
312 case SIOCSIFADDR:
313 case SIOCAIFADDR:
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 }
318
319 switch (ifaddr_address_family(ifa)) {
320
321 case AF_INET:
322
323 inet_arp_init_ifaddr(ifp, ifa);
324 /*
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.
331 */
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));
338
339 break;
340
341 default:
342 break;
343 }
344
345 break;
346
347 case SIOCGIFADDR:
348 ifnet_lladdr_copy_bytes(ifp, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN);
349 break;
350
351 default:
352 error = EOPNOTSUPP;
353 break;
354 }
355
356 return (error);
357 }
358
359 static void
360 ether_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 }
384
385 static errno_t
386 ether_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) ||
406 target_ip->sin_family != AF_INET)
407 return EAFNOSUPPORT;
408
409 result = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_DATA, &m);
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);
419 datap -= (((uintptr_t)datap) & 0x3);
420 mbuf_setdata(m, datap, sizeof(*ea));
421 ea = mbuf_data(m);
422
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
431 eh = mbuf_data(m);
432 eh->ether_type = htons(ETHERTYPE_ARP);
433
434 #if CONFIG_MACF_NET
435 mac_mbuf_label_associate_linklayer(ifp, m);
436 #endif
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 }
496
497 errno_t
498 ether_attach_inet(
499 struct ifnet *ifp,
500 __unused protocol_family_t proto_family)
501 {
502 struct ifnet_attach_proto_param_v2 proto;
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]);
519 proto.input = ether_inet_input;
520 proto.pre_output = ether_inet_pre_output;
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
526 error = ifnet_attach_protocol_v2(ifp, proto_family, &proto);
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;
532 }
533
534 void
535 ether_detach_inet(
536 struct ifnet *ifp,
537 protocol_family_t proto_family)
538 {
539 (void)ifnet_detach_protocol(ifp, proto_family);
540 }
541