xref: /xnu-10002.1.13/bsd/net/if_llatbl.c (revision 1031c584a5e37aff177559b9f69dbd3c8c3fd30a)
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