1 /*
2 * Copyright (c) 2016-2021 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) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
30 * Copyright (c) 2004-2008 Qing Li. All rights reserved.
31 * Copyright (c) 2008 Kip Macy. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 */
54 #include <sys/cdefs.h>
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/malloc.h>
58 #include <sys/mbuf.h>
59 #include <sys/syslog.h>
60 #include <sys/sysctl.h>
61 #include <sys/socket.h>
62 #include <sys/kernel.h>
63 #include <kern/queue.h>
64 #include <kern/locks.h>
65
66 #include <netinet/in.h>
67 #include <net/if_llatbl.h>
68 #include <net/if.h>
69 #include <net/if_dl.h>
70 #include <net/if_var.h>
71 #include <net/dlil.h>
72 #include <net/route.h>
73 #include <netinet/if_ether.h>
74 #include <netinet6/in6_var.h>
75 #include <netinet6/nd6.h>
76
77 static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables);
78
79 static LCK_GRP_DECLARE(lltable_rwlock_grp, "lltable_rwlock");
80 LCK_RW_DECLARE(lltable_rwlock, &lltable_rwlock_grp);
81
82 LCK_GRP_DECLARE(lle_lock_grp, "lle locks");
83 LCK_ATTR_DECLARE(lle_lock_attr, 0, 0);
84
85 #if 0
86 static void lltable_unlink(struct lltable *llt);
87 #endif
88 static void llentries_unlink(struct lltable *llt, struct llentries *head);
89
90 static void htable_unlink_entry(struct llentry *lle);
91 static void htable_link_entry(struct lltable *llt, struct llentry *lle);
92 static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
93 void *farg);
94
95 /*
96 * Dump lle state for a specific address family.
97 */
98 static int
lltable_dump_af(struct lltable * llt,struct sysctl_req * wr)99 lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
100 {
101 int error;
102
103 LLTABLE_LOCK_ASSERT();
104
105 if (llt->llt_ifp->if_flags & IFF_LOOPBACK) {
106 return 0;
107 }
108 error = 0;
109
110 IF_AFDATA_RLOCK(llt->llt_ifp, llt->llt_af);
111 error = lltable_foreach_lle(llt,
112 (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
113 IF_AFDATA_RUNLOCK(llt->llt_ifp, llt->llt_af);
114
115 return error;
116 }
117
118 /*
119 * Dump arp state for a specific address family.
120 */
121 int
lltable_sysctl_dumparp(int af,struct sysctl_req * wr)122 lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
123 {
124 struct lltable *llt = NULL;
125 int error = 0;
126
127 LLTABLE_RLOCK();
128 SLIST_FOREACH(llt, &lltables, llt_link) {
129 if (llt->llt_af == af) {
130 error = lltable_dump_af(llt, wr);
131 if (error != 0) {
132 goto done;
133 }
134 }
135 }
136 done:
137 LLTABLE_RUNLOCK();
138 return error;
139 }
140
141 /*
142 * Common function helpers for chained hash table.
143 */
144
145 /*
146 * Runs specified callback for each entry in @llt.
147 * Caller does the locking.
148 *
149 */
150 static int
htable_foreach_lle(struct lltable * llt,llt_foreach_cb_t * f,void * farg)151 htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
152 {
153 struct llentry *lle, *next;
154 int i, error;
155
156 error = 0;
157
158 for (i = 0; i < llt->llt_hsize; i++) {
159 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
160 error = f(llt, lle, farg);
161 if (error != 0) {
162 break;
163 }
164 }
165 }
166
167 return error;
168 }
169
170 static void
htable_link_entry(struct lltable * llt,struct llentry * lle)171 htable_link_entry(struct lltable *llt, struct llentry *lle)
172 {
173 struct llentries *lleh;
174 uint32_t hashidx;
175
176 if ((lle->la_flags & LLE_LINKED) != 0) {
177 return;
178 }
179
180 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp, llt->llt_af);
181
182 hashidx = llt->llt_hash(lle, llt->llt_hsize);
183 lleh = &llt->lle_head[hashidx];
184
185 lle->lle_tbl = llt;
186 lle->lle_head = lleh;
187 lle->la_flags |= LLE_LINKED;
188 LIST_INSERT_HEAD(lleh, lle, lle_next);
189 }
190
191 static void
htable_unlink_entry(struct llentry * lle)192 htable_unlink_entry(struct llentry *lle)
193 {
194 if ((lle->la_flags & LLE_LINKED) != 0) {
195 IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp, lle->lle_tbl->llt_af);
196 LIST_REMOVE(lle, lle_next);
197 lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
198 #if 0
199 lle->lle_tbl = NULL;
200 lle->lle_head = NULL;
201 #endif
202 }
203 }
204
205 struct prefix_match_data {
206 const struct sockaddr *addr;
207 const struct sockaddr *mask;
208 struct llentries dchain;
209 uint16_t flags;
210 };
211
212 static int
htable_prefix_free_cb(struct lltable * llt,struct llentry * lle,void * farg)213 htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
214 {
215 struct prefix_match_data *pmd;
216
217 pmd = (struct prefix_match_data *)farg;
218
219 if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
220 LLE_WLOCK(lle);
221 LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
222 }
223
224 return 0;
225 }
226
227 static void
htable_prefix_free(struct lltable * llt,const struct sockaddr * addr,const struct sockaddr * mask,uint16_t flags)228 htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
229 const struct sockaddr *mask, uint16_t flags)
230 {
231 struct llentry *lle, *next;
232 struct prefix_match_data pmd;
233
234 bzero(&pmd, sizeof(pmd));
235 pmd.addr = addr;
236 pmd.mask = mask;
237 pmd.flags = flags;
238 LIST_INIT(&pmd.dchain);
239
240 IF_AFDATA_WLOCK(llt->llt_ifp, llt->llt_af);
241 /* Push matching lles to chain */
242 lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
243
244 llentries_unlink(llt, &pmd.dchain);
245 IF_AFDATA_WUNLOCK(llt->llt_ifp, llt->llt_af);
246
247 LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
248 lltable_free_entry(llt, lle);
249 }
250
251 #if 0
252 static void
253 htable_free_tbl(struct lltable *llt)
254 {
255 kfree_type(struct llentries, llt->llt_hsize, llt->lle_head);
256 kfree_type(struct lltable, llt);
257 }
258 #endif
259
260 static void
llentries_unlink(struct lltable * llt,struct llentries * head)261 llentries_unlink(struct lltable *llt, struct llentries *head)
262 {
263 struct llentry *lle, *next;
264
265 LIST_FOREACH_SAFE(lle, head, lle_chain, next)
266 llt->llt_unlink_entry(lle);
267 }
268
269 /*
270 * Helper function used to drop all mbufs in hold queue.
271 *
272 * Returns the number of held packets, if any, that were dropped.
273 */
274 size_t
lltable_drop_entry_queue(struct llentry * lle)275 lltable_drop_entry_queue(struct llentry *lle)
276 {
277 size_t pkts_dropped;
278 struct mbuf *next;
279
280 LLE_WLOCK_ASSERT(lle);
281
282 pkts_dropped = 0;
283 while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
284 next = lle->la_hold->m_nextpkt;
285 m_freem(lle->la_hold);
286 lle->la_hold = next;
287 lle->la_numheld--;
288 pkts_dropped++;
289 }
290
291 KASSERT(lle->la_numheld == 0,
292 ("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
293 lle->la_numheld, pkts_dropped));
294
295 return pkts_dropped;
296 }
297
298 void
lltable_set_entry_addr(struct ifnet * ifp,struct llentry * lle,const char * ll_addr)299 lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
300 const char *ll_addr)
301 {
302 bcopy(ll_addr, &lle->ll_addr, ifp->if_addrlen);
303 lle->la_flags |= LLE_VALID;
304 lle->r_flags |= RLLE_VALID;
305 }
306
307 #if 0
308 /*
309 * XXX The following is related to a change to cache destination layer 2
310 * header cached in the entry instead of just the destination mac address
311 * Right now leaving this code out and just storing the destination's mac
312 * information.
313 */
314 /*
315 * Tries to update @lle link-level address.
316 * Since update requires AFDATA WLOCK, function
317 * drops @lle lock, acquires AFDATA lock and then acquires
318 * @lle lock to maintain lock order.
319 *
320 * Returns 1 on success.
321 */
322 int
323 lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
324 const char *linkhdr, size_t linkhdrsize, int lladdr_off)
325 {
326 /* Perform real LLE update */
327 /* use afdata WLOCK to update fields */
328 LLE_WLOCK_ASSERT(lle);
329 LLE_ADDREF(lle);
330 LLE_WUNLOCK(lle);
331 IF_AFDATA_WLOCK(ifp, lle->lle_tbl->llt_af);
332 LLE_WLOCK(lle);
333
334 /*
335 * Since we droppped LLE lock, other thread might have deleted
336 * this lle. Check and return
337 */
338 if ((lle->la_flags & LLE_DELETED) != 0) {
339 IF_AFDATA_WUNLOCK(ifp, lle->lle_tbl->llt_af);
340 LLE_FREE_LOCKED(lle);
341 return 0;
342 }
343
344 /* Update data */
345 lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off);
346
347 IF_AFDATA_WUNLOCK(ifp, lle->lle_tbl->llt_af);
348
349 LLE_REMREF(lle);
350
351 return 1;
352 }
353
354 /*
355 * Helper function used to pre-compute full/partial link-layer
356 * header data suitable for feeding into if_output().
357 */
358 int
359 lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr,
360 char *buf, size_t *bufsize, int *lladdr_off)
361 {
362 struct if_encap_req ereq;
363 int error;
364
365 bzero(buf, *bufsize);
366 bzero(&ereq, sizeof(ereq));
367 ereq.buf = buf;
368 ereq.bufsize = *bufsize;
369 ereq.rtype = IFENCAP_LL;
370 ereq.family = family;
371 ereq.lladdr = lladdr;
372 ereq.lladdr_len = ifp->if_addrlen;
373 error = ifp->if_requestencap(ifp, &ereq);
374 if (error == 0) {
375 *bufsize = ereq.bufsize;
376 *lladdr_off = ereq.lladdr_off;
377 }
378
379 return error;
380 }
381
382 /*
383 * Update link-layer header for given @lle after
384 * interface lladdr was changed.
385 */
386 static int
387 llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg)
388 {
389 struct ifnet *ifp;
390 u_char linkhdr[LLE_MAX_LINKHDR];
391 size_t linkhdrsize;
392 u_char *lladdr;
393 int lladdr_off;
394
395 ifp = (struct ifnet *)farg;
396
397 lladdr = (void *)lle->ll_addr;
398
399 LLE_WLOCK(lle);
400 if ((lle->la_flags & LLE_VALID) == 0) {
401 LLE_WUNLOCK(lle);
402 return 0;
403 }
404
405 if ((lle->la_flags & LLE_IFADDR) != 0) {
406 lladdr = (void *)IF_LLADDR(ifp);
407 }
408
409 linkhdrsize = sizeof(linkhdr);
410 lltable_calc_llheader(ifp, llt->llt_af, (void *)lladdr, (void *)linkhdr, &linkhdrsize,
411 &lladdr_off);
412 memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
413 LLE_WUNLOCK(lle);
414
415 return 0;
416 }
417
418 /*
419 * Update all calculated headers for given @llt
420 */
421 void
422 lltable_update_ifaddr(struct lltable *llt)
423 {
424 if (llt->llt_ifp->if_flags & IFF_LOOPBACK) {
425 return;
426 }
427
428 IF_AFDATA_WLOCK(llt->llt_ifp, llt->llt_af);
429 lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp);
430 IF_AFDATA_WUNLOCK(llt->llt_ifp, llt->llt_af);
431 }
432 #endif
433
434 /*
435 *
436 * Performs generic cleanup routines and frees lle.
437 *
438 * Called for non-linked entries, with callouts and
439 * other AF-specific cleanups performed.
440 *
441 * @lle must be passed WLOCK'ed
442 *
443 * Returns the number of held packets, if any, that were dropped.
444 */
445 size_t
llentry_free(struct llentry * lle)446 llentry_free(struct llentry *lle)
447 {
448 size_t pkts_dropped;
449
450 LLE_WLOCK_ASSERT(lle);
451
452 KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle"));
453
454 pkts_dropped = lltable_drop_entry_queue(lle);
455
456 LLE_FREE_LOCKED(lle);
457
458 return pkts_dropped;
459 }
460
461 /*
462 * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
463 *
464 * If found the llentry * is returned referenced and unlocked.
465 */
466 struct llentry *
llentry_alloc(struct ifnet * ifp,struct lltable * lt,struct sockaddr_storage * dst)467 llentry_alloc(struct ifnet *ifp, struct lltable *lt,
468 struct sockaddr_storage *dst)
469 {
470 struct llentry *la, *la_tmp;
471
472 IF_AFDATA_RLOCK(ifp, lt->llt_af);
473 la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
474 IF_AFDATA_RUNLOCK(ifp, lt->llt_af);
475
476 if (la != NULL) {
477 LLE_ADDREF(la);
478 LLE_WUNLOCK(la);
479 return la;
480 }
481
482 if ((ifp->if_flags & IFF_NOARP) == 0) {
483 la = lltable_alloc_entry(lt, 0, (struct sockaddr *)dst);
484 if (la == NULL) {
485 return NULL;
486 }
487 IF_AFDATA_WLOCK(ifp, lt->llt_af);
488 LLE_WLOCK(la);
489 /* Prefer any existing LLE over newly-created one */
490 la_tmp = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
491 if (la_tmp == NULL) {
492 lltable_link_entry(lt, la);
493 }
494 IF_AFDATA_WUNLOCK(ifp, lt->llt_af);
495 if (la_tmp != NULL) {
496 lltable_free_entry(lt, la);
497 la = la_tmp;
498 }
499 LLE_ADDREF(la);
500 LLE_WUNLOCK(la);
501 }
502
503 return la;
504 }
505
506 /*
507 * Free all entries from given table and free itself.
508 */
509
510 static int
lltable_free_cb(struct lltable * llt,struct llentry * lle,void * farg)511 lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
512 {
513 #pragma unused(llt)
514 struct llentries *dchain;
515
516 dchain = (struct llentries *)farg;
517
518 LLE_WLOCK(lle);
519 LIST_INSERT_HEAD(dchain, lle, lle_chain);
520
521 return 0;
522 }
523
524 /*
525 * Free all entries from given table and free itself.
526 */
527 void
lltable_free(struct lltable * llt)528 lltable_free(struct lltable *llt)
529 {
530 struct llentry *lle, *next;
531 struct llentries dchain;
532
533 KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
534
535 //lltable_unlink(llt);
536
537 LIST_INIT(&dchain);
538 IF_AFDATA_WLOCK(llt->llt_ifp, llt->llt_af);
539 /* Push all lles to @dchain */
540 lltable_foreach_lle(llt, lltable_free_cb, &dchain);
541 llentries_unlink(llt, &dchain);
542 IF_AFDATA_WUNLOCK(llt->llt_ifp, llt->llt_af);
543
544 LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
545 #if 0
546 if (thread_call_cancel(lle->lle_timer) == TRUE) {
547 LLE_REMREF(lle);
548 }
549 #endif
550 llentry_free(lle);
551 }
552
553 /* XXX We recycle network interfaces so we only purge */
554 /* htable_freee_tbl(llt); */
555 }
556
557 /* Purge all entries from a given table */
558 void
lltable_purge(struct lltable * llt)559 lltable_purge(struct lltable *llt)
560 {
561 struct llentry *lle = NULL;
562 struct llentry *next = NULL;
563 struct llentries dchain = {};
564
565 KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
566
567 LIST_INIT(&dchain);
568 IF_AFDATA_WLOCK(llt->llt_ifp, llt->llt_af);
569 /* Push all lles to @dchain */
570 lltable_foreach_lle(llt, lltable_free_cb, &dchain);
571 llentries_unlink(llt, &dchain);
572 IF_AFDATA_WUNLOCK(llt->llt_ifp, llt->llt_af);
573
574 LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
575 llentry_free(lle);
576 }
577 }
578
579 #if 0
580 void
581 lltable_drain(int af)
582 {
583 struct lltable *llt;
584 struct llentry *lle;
585 register int i;
586
587 LLTABLE_RLOCK();
588 SLIST_FOREACH(llt, &lltables, llt_link) {
589 if (llt->llt_af != af) {
590 continue;
591 }
592
593 for (i = 0; i < llt->llt_hsize; i++) {
594 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
595 LLE_WLOCK(lle);
596 if (lle->la_hold) {
597 m_freem(lle->la_hold);
598 lle->la_hold = NULL;
599 }
600 LLE_WUNLOCK(lle);
601 }
602 }
603 }
604 LLTABLE_RUNLOCK();
605 }
606 #endif
607
608 /*
609 * Deletes an address from given lltable.
610 * Used for userland interaction to remove
611 * individual entries. Skips entries added by OS.
612 */
613 int
lltable_delete_addr(struct lltable * llt,u_int flags,const struct sockaddr * l3addr)614 lltable_delete_addr(struct lltable *llt, u_int flags,
615 const struct sockaddr *l3addr)
616 {
617 struct llentry *lle;
618 struct ifnet *ifp;
619
620 ifp = llt->llt_ifp;
621 IF_AFDATA_WLOCK(ifp, llt->llt_af);
622 lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr);
623
624 if (lle == NULL) {
625 IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
626 return ENOENT;
627 }
628 if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
629 IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
630 LLE_WUNLOCK(lle);
631 return EPERM;
632 }
633
634 lltable_unlink_entry(llt, lle);
635 IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
636
637 llt->llt_delete_entry(llt, lle);
638
639 return 0;
640 }
641
642 void
lltable_prefix_free(int af,struct sockaddr * addr,struct sockaddr * mask,uint16_t flags)643 lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
644 uint16_t flags)
645 {
646 struct lltable *llt;
647
648 LLTABLE_RLOCK();
649 SLIST_FOREACH(llt, &lltables, llt_link) {
650 if (llt->llt_af != af) {
651 continue;
652 }
653
654 llt->llt_prefix_free(llt, addr, mask, flags);
655 }
656 LLTABLE_RUNLOCK();
657 }
658
659 struct lltable *
lltable_allocate_htbl(uint32_t hsize)660 lltable_allocate_htbl(uint32_t hsize)
661 {
662 struct lltable *llt;
663
664 llt = kalloc_type(struct lltable, Z_WAITOK | Z_ZERO);
665 llt->llt_hsize = hsize;
666 llt->lle_head = kalloc_type(struct llentries, hsize,
667 Z_WAITOK | Z_ZERO | Z_NOFAIL);
668
669 for (int i = 0; i < llt->llt_hsize; i++) {
670 LIST_INIT(&llt->lle_head[i]);
671 }
672
673 /* Set some default callbacks */
674 llt->llt_link_entry = htable_link_entry;
675 llt->llt_unlink_entry = htable_unlink_entry;
676 llt->llt_prefix_free = htable_prefix_free;
677 llt->llt_foreach_entry = htable_foreach_lle;
678
679 return llt;
680 }
681
682 /*
683 * Links lltable to global llt list.
684 */
685 void
lltable_link(struct lltable * llt)686 lltable_link(struct lltable *llt)
687 {
688 LLTABLE_WLOCK();
689 SLIST_INSERT_HEAD(&lltables, llt, llt_link);
690 LLTABLE_WUNLOCK();
691 }
692
693 #if 0
694 static void
695 lltable_unlink(struct lltable *llt)
696 {
697 LLTABLE_WLOCK();
698 SLIST_REMOVE(&lltables, llt, lltable, llt_link);
699 LLTABLE_WUNLOCK();
700 }
701 #endif
702
703 /*
704 * External methods used by lltable consumers
705 */
706
707 int
lltable_foreach_lle(struct lltable * llt,llt_foreach_cb_t * f,void * farg)708 lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
709 {
710 return llt->llt_foreach_entry(llt, f, farg);
711 }
712
713 struct llentry *
lltable_alloc_entry(struct lltable * llt,uint16_t flags,const struct sockaddr * l3addr)714 lltable_alloc_entry(struct lltable *llt, uint16_t flags,
715 const struct sockaddr *l3addr)
716 {
717 return llt->llt_alloc_entry(llt, flags, l3addr);
718 }
719
720 void
lltable_free_entry(struct lltable * llt,struct llentry * lle)721 lltable_free_entry(struct lltable *llt, struct llentry *lle)
722 {
723 llt->llt_free_entry(llt, lle);
724 }
725
726 void
lltable_link_entry(struct lltable * llt,struct llentry * lle)727 lltable_link_entry(struct lltable *llt, struct llentry *lle)
728 {
729 llt->llt_link_entry(llt, lle);
730 }
731
732 void
lltable_unlink_entry(struct lltable * llt,struct llentry * lle)733 lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
734 {
735 llt->llt_unlink_entry(lle);
736 }
737
738 void
lltable_fill_sa_entry(const struct llentry * lle,struct sockaddr * sa)739 lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
740 {
741 struct lltable *llt;
742
743 llt = lle->lle_tbl;
744 llt->llt_fill_sa_entry(lle, sa);
745 }
746
747 struct ifnet *
lltable_get_ifp(const struct lltable * llt)748 lltable_get_ifp(const struct lltable *llt)
749 {
750 return llt->llt_ifp;
751 }
752
753 int
lltable_get_af(const struct lltable * llt)754 lltable_get_af(const struct lltable *llt)
755 {
756 return llt->llt_af;
757 }
758
759 #define ifnet_byindex(index) ifindex2ifnet[(index)]
760
761 /*
762 * Called in route_output when rtm_flags contains RTF_LLDATA.
763 */
764 int
lla_rt_output(struct rt_msghdr * rtm,struct rt_addrinfo * info)765 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
766 {
767 struct sockaddr_dl *dl =
768 (struct sockaddr_dl *)(void *)info->rti_info[RTAX_GATEWAY];
769 struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
770 struct ifnet *ifp;
771 struct lltable *llt;
772 struct llentry *lle, *lle_tmp;
773 uint16_t laflags = 0;
774 int error;
775
776 KASSERT(dl != NULL && dl->sdl_family == AF_LINK,
777 ("%s: invalid dl\n", __func__));
778
779 ifp = ifnet_byindex(dl->sdl_index);
780 if (ifp == NULL) {
781 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
782 __func__, dl->sdl_index);
783 return EINVAL;
784 }
785
786 /* XXX linked list may be too expensive */
787 LLTABLE_RLOCK();
788 SLIST_FOREACH(llt, &lltables, llt_link) {
789 if (llt->llt_af == dst->sa_family &&
790 llt->llt_ifp == ifp) {
791 break;
792 }
793 }
794 LLTABLE_RUNLOCK();
795 KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
796
797 error = 0;
798
799 switch (rtm->rtm_type) {
800 case RTM_ADD:
801 /* Add static LLE */
802 laflags = 0;
803 if (rtm->rtm_rmx.rmx_expire == 0) {
804 laflags = LLE_STATIC;
805 }
806 lle = lltable_alloc_entry(llt, laflags, dst);
807 if (lle == NULL) {
808 return ENOMEM;
809 }
810 #if 0
811 linkhdrsize = sizeof(linkhdr);
812 if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl),
813 (void *)linkhdr, &linkhdrsize, &lladdr_off) != 0) {
814 return EINVAL;
815 }
816 #endif
817 lltable_set_entry_addr(ifp, lle, LLADDR(dl));
818
819 if (rtm->rtm_flags & RTF_ANNOUNCE) {
820 lle->la_flags |= LLE_PUB;
821 }
822 lle->la_expire = rtm->rtm_rmx.rmx_expire;
823
824 laflags = lle->la_flags;
825
826 /* Try to link new entry */
827 lle_tmp = NULL;
828 IF_AFDATA_WLOCK(ifp, llt->llt_af);
829 LLE_WLOCK(lle);
830 lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst);
831 if (lle_tmp != NULL) {
832 /* Check if we are trying to replace immutable entry */
833 if ((lle_tmp->la_flags & LLE_IFADDR) != 0) {
834 IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
835 LLE_WUNLOCK(lle_tmp);
836 lltable_free_entry(llt, lle);
837 return EPERM;
838 }
839 /* Unlink existing entry from table */
840 lltable_unlink_entry(llt, lle_tmp);
841 }
842 lltable_link_entry(llt, lle);
843 IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
844
845 if (lle_tmp != NULL) {
846 EVENTHANDLER_INVOKE(NULL, lle_event, lle_tmp, LLENTRY_EXPIRED);
847 lltable_free_entry(llt, lle_tmp);
848 }
849
850 /*
851 * By invoking LLE handler here we might get
852 * two events on static LLE entry insertion
853 * in routing socket. However, since we might have
854 * other subscribers we need to generate this event.
855 */
856 EVENTHANDLER_INVOKE(NULL, lle_event, lle, LLENTRY_RESOLVED);
857 LLE_WUNLOCK(lle);
858 #ifdef INET
859 /* gratuitous ARP */
860 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) {
861 dlil_send_arp(ifp, ARPOP_REQUEST, NULL, dst, NULL, dst, 0);
862 }
863 #endif
864
865 break;
866
867 case RTM_DELETE:
868 return lltable_delete_addr(llt, 0, dst);
869
870 default:
871 error = EINVAL;
872 }
873
874 return error;
875 }
876