xref: /xnu-8019.80.24/bsd/net/if_llatbl.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
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 MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
78 
79 static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables);
80 
81 static LCK_GRP_DECLARE(lltable_rwlock_grp, "lltable_rwlock");
82 LCK_RW_DECLARE(lltable_rwlock, &lltable_rwlock_grp);
83 
84 LCK_GRP_DECLARE(lle_lock_grp, "lle locks");
85 LCK_ATTR_DECLARE(lle_lock_attr, 0, 0);
86 
87 #if 0
88 static void lltable_unlink(struct lltable *llt);
89 #endif
90 static void llentries_unlink(struct lltable *llt, struct llentries *head);
91 
92 static void htable_unlink_entry(struct llentry *lle);
93 static void htable_link_entry(struct lltable *llt, struct llentry *lle);
94 static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
95     void *farg);
96 
97 /*
98  * Dump lle state for a specific address family.
99  */
100 static int
lltable_dump_af(struct lltable * llt,struct sysctl_req * wr)101 lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
102 {
103 	int error;
104 
105 	LLTABLE_LOCK_ASSERT();
106 
107 	if (llt->llt_ifp->if_flags & IFF_LOOPBACK) {
108 		return 0;
109 	}
110 	error = 0;
111 
112 	IF_AFDATA_RLOCK(llt->llt_ifp, llt->llt_af);
113 	error = lltable_foreach_lle(llt,
114 	    (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
115 	IF_AFDATA_RUNLOCK(llt->llt_ifp, llt->llt_af);
116 
117 	return error;
118 }
119 
120 /*
121  * Dump arp state for a specific address family.
122  */
123 int
lltable_sysctl_dumparp(int af,struct sysctl_req * wr)124 lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
125 {
126 	struct lltable *llt = NULL;
127 	int error = 0;
128 
129 	LLTABLE_RLOCK();
130 	SLIST_FOREACH(llt, &lltables, llt_link) {
131 		if (llt->llt_af == af) {
132 			error = lltable_dump_af(llt, wr);
133 			if (error != 0) {
134 				goto done;
135 			}
136 		}
137 	}
138 done:
139 	LLTABLE_RUNLOCK();
140 	return error;
141 }
142 
143 /*
144  * Common function helpers for chained hash table.
145  */
146 
147 /*
148  * Runs specified callback for each entry in @llt.
149  * Caller does the locking.
150  *
151  */
152 static int
htable_foreach_lle(struct lltable * llt,llt_foreach_cb_t * f,void * farg)153 htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
154 {
155 	struct llentry *lle, *next;
156 	int i, error;
157 
158 	error = 0;
159 
160 	for (i = 0; i < llt->llt_hsize; i++) {
161 		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
162 			error = f(llt, lle, farg);
163 			if (error != 0) {
164 				break;
165 			}
166 		}
167 	}
168 
169 	return error;
170 }
171 
172 static void
htable_link_entry(struct lltable * llt,struct llentry * lle)173 htable_link_entry(struct lltable *llt, struct llentry *lle)
174 {
175 	struct llentries *lleh;
176 	uint32_t hashidx;
177 
178 	if ((lle->la_flags & LLE_LINKED) != 0) {
179 		return;
180 	}
181 
182 	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp, llt->llt_af);
183 
184 	hashidx = llt->llt_hash(lle, llt->llt_hsize);
185 	lleh = &llt->lle_head[hashidx];
186 
187 	lle->lle_tbl  = llt;
188 	lle->lle_head = lleh;
189 	lle->la_flags |= LLE_LINKED;
190 	LIST_INSERT_HEAD(lleh, lle, lle_next);
191 }
192 
193 static void
htable_unlink_entry(struct llentry * lle)194 htable_unlink_entry(struct llentry *lle)
195 {
196 	if ((lle->la_flags & LLE_LINKED) != 0) {
197 		IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp, lle->lle_tbl->llt_af);
198 		LIST_REMOVE(lle, lle_next);
199 		lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
200 #if 0
201 		lle->lle_tbl = NULL;
202 		lle->lle_head = NULL;
203 #endif
204 	}
205 }
206 
207 struct prefix_match_data {
208 	const struct sockaddr *addr;
209 	const struct sockaddr *mask;
210 	struct llentries dchain;
211 	uint16_t flags;
212 };
213 
214 static int
htable_prefix_free_cb(struct lltable * llt,struct llentry * lle,void * farg)215 htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
216 {
217 	struct prefix_match_data *pmd;
218 
219 	pmd = (struct prefix_match_data *)farg;
220 
221 	if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
222 		LLE_WLOCK(lle);
223 		LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
224 	}
225 
226 	return 0;
227 }
228 
229 static void
htable_prefix_free(struct lltable * llt,const struct sockaddr * addr,const struct sockaddr * mask,uint16_t flags)230 htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
231     const struct sockaddr *mask, uint16_t flags)
232 {
233 	struct llentry *lle, *next;
234 	struct prefix_match_data pmd;
235 
236 	bzero(&pmd, sizeof(pmd));
237 	pmd.addr = addr;
238 	pmd.mask = mask;
239 	pmd.flags = flags;
240 	LIST_INIT(&pmd.dchain);
241 
242 	IF_AFDATA_WLOCK(llt->llt_ifp, llt->llt_af);
243 	/* Push matching lles to chain */
244 	lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
245 
246 	llentries_unlink(llt, &pmd.dchain);
247 	IF_AFDATA_WUNLOCK(llt->llt_ifp, llt->llt_af);
248 
249 	LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
250 	lltable_free_entry(llt, lle);
251 }
252 
253 static void
htable_free_tbl(struct lltable * llt)254 htable_free_tbl(struct lltable *llt)
255 {
256 	FREE(llt->lle_head, M_LLTABLE);
257 	kfree_type(struct lltable, llt);
258 }
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 	/* llt->llt_free_tbl(llt); */
555 }
556 
557 #if 0
558 void
559 lltable_drain(int af)
560 {
561 	struct lltable  *llt;
562 	struct llentry  *lle;
563 	register int i;
564 
565 	LLTABLE_RLOCK();
566 	SLIST_FOREACH(llt, &lltables, llt_link) {
567 		if (llt->llt_af != af) {
568 			continue;
569 		}
570 
571 		for (i = 0; i < llt->llt_hsize; i++) {
572 			LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
573 				LLE_WLOCK(lle);
574 				if (lle->la_hold) {
575 					m_freem(lle->la_hold);
576 					lle->la_hold = NULL;
577 				}
578 				LLE_WUNLOCK(lle);
579 			}
580 		}
581 	}
582 	LLTABLE_RUNLOCK();
583 }
584 #endif
585 
586 /*
587  * Deletes an address from given lltable.
588  * Used for userland interaction to remove
589  * individual entries. Skips entries added by OS.
590  */
591 int
lltable_delete_addr(struct lltable * llt,u_int flags,const struct sockaddr * l3addr)592 lltable_delete_addr(struct lltable *llt, u_int flags,
593     const struct sockaddr *l3addr)
594 {
595 	struct llentry *lle;
596 	struct ifnet *ifp;
597 
598 	ifp = llt->llt_ifp;
599 	IF_AFDATA_WLOCK(ifp, llt->llt_af);
600 	lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr);
601 
602 	if (lle == NULL) {
603 		IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
604 		return ENOENT;
605 	}
606 	if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
607 		IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
608 		LLE_WUNLOCK(lle);
609 		return EPERM;
610 	}
611 
612 	lltable_unlink_entry(llt, lle);
613 	IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
614 
615 	llt->llt_delete_entry(llt, lle);
616 
617 	return 0;
618 }
619 
620 void
lltable_prefix_free(int af,struct sockaddr * addr,struct sockaddr * mask,uint16_t flags)621 lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
622     uint16_t flags)
623 {
624 	struct lltable *llt;
625 
626 	LLTABLE_RLOCK();
627 	SLIST_FOREACH(llt, &lltables, llt_link) {
628 		if (llt->llt_af != af) {
629 			continue;
630 		}
631 
632 		llt->llt_prefix_free(llt, addr, mask, flags);
633 	}
634 	LLTABLE_RUNLOCK();
635 }
636 
637 struct lltable *
lltable_allocate_htbl(uint32_t hsize)638 lltable_allocate_htbl(uint32_t hsize)
639 {
640 	struct lltable *llt;
641 	int i;
642 
643 	llt = kalloc_type(struct lltable, Z_WAITOK | Z_ZERO);
644 	llt->llt_hsize = hsize;
645 	MALLOC(llt->lle_head, struct llentries *, sizeof(struct llentries) * hsize,
646 	    M_LLTABLE, M_WAITOK | M_ZERO);
647 
648 	for (i = 0; i < llt->llt_hsize; i++) {
649 		LIST_INIT(&llt->lle_head[i]);
650 	}
651 
652 	/* Set some default callbacks */
653 	llt->llt_link_entry = htable_link_entry;
654 	llt->llt_unlink_entry = htable_unlink_entry;
655 	llt->llt_prefix_free = htable_prefix_free;
656 	llt->llt_foreach_entry = htable_foreach_lle;
657 	llt->llt_free_tbl = htable_free_tbl;
658 
659 	return llt;
660 }
661 
662 /*
663  * Links lltable to global llt list.
664  */
665 void
lltable_link(struct lltable * llt)666 lltable_link(struct lltable *llt)
667 {
668 	LLTABLE_WLOCK();
669 	SLIST_INSERT_HEAD(&lltables, llt, llt_link);
670 	LLTABLE_WUNLOCK();
671 }
672 
673 #if 0
674 static void
675 lltable_unlink(struct lltable *llt)
676 {
677 	LLTABLE_WLOCK();
678 	SLIST_REMOVE(&lltables, llt, lltable, llt_link);
679 	LLTABLE_WUNLOCK();
680 }
681 #endif
682 
683 /*
684  * External methods used by lltable consumers
685  */
686 
687 int
lltable_foreach_lle(struct lltable * llt,llt_foreach_cb_t * f,void * farg)688 lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
689 {
690 	return llt->llt_foreach_entry(llt, f, farg);
691 }
692 
693 struct llentry *
lltable_alloc_entry(struct lltable * llt,uint16_t flags,const struct sockaddr * l3addr)694 lltable_alloc_entry(struct lltable *llt, uint16_t flags,
695     const struct sockaddr *l3addr)
696 {
697 	return llt->llt_alloc_entry(llt, flags, l3addr);
698 }
699 
700 void
lltable_free_entry(struct lltable * llt,struct llentry * lle)701 lltable_free_entry(struct lltable *llt, struct llentry *lle)
702 {
703 	llt->llt_free_entry(llt, lle);
704 }
705 
706 void
lltable_link_entry(struct lltable * llt,struct llentry * lle)707 lltable_link_entry(struct lltable *llt, struct llentry *lle)
708 {
709 	llt->llt_link_entry(llt, lle);
710 }
711 
712 void
lltable_unlink_entry(struct lltable * llt,struct llentry * lle)713 lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
714 {
715 	llt->llt_unlink_entry(lle);
716 }
717 
718 void
lltable_fill_sa_entry(const struct llentry * lle,struct sockaddr * sa)719 lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
720 {
721 	struct lltable *llt;
722 
723 	llt = lle->lle_tbl;
724 	llt->llt_fill_sa_entry(lle, sa);
725 }
726 
727 struct ifnet *
lltable_get_ifp(const struct lltable * llt)728 lltable_get_ifp(const struct lltable *llt)
729 {
730 	return llt->llt_ifp;
731 }
732 
733 int
lltable_get_af(const struct lltable * llt)734 lltable_get_af(const struct lltable *llt)
735 {
736 	return llt->llt_af;
737 }
738 
739 #define ifnet_byindex(index)    ifindex2ifnet[(index)]
740 
741 /*
742  * Called in route_output when rtm_flags contains RTF_LLDATA.
743  */
744 int
lla_rt_output(struct rt_msghdr * rtm,struct rt_addrinfo * info)745 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
746 {
747 	struct sockaddr_dl *dl =
748 	    (struct sockaddr_dl *)(void *)info->rti_info[RTAX_GATEWAY];
749 	struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
750 	struct ifnet *ifp;
751 	struct lltable *llt;
752 	struct llentry *lle, *lle_tmp;
753 	uint16_t laflags = 0;
754 	int error;
755 
756 	KASSERT(dl != NULL && dl->sdl_family == AF_LINK,
757 	    ("%s: invalid dl\n", __func__));
758 
759 	ifp = ifnet_byindex(dl->sdl_index);
760 	if (ifp == NULL) {
761 		log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
762 		    __func__, dl->sdl_index);
763 		return EINVAL;
764 	}
765 
766 	/* XXX linked list may be too expensive */
767 	LLTABLE_RLOCK();
768 	SLIST_FOREACH(llt, &lltables, llt_link) {
769 		if (llt->llt_af == dst->sa_family &&
770 		    llt->llt_ifp == ifp) {
771 			break;
772 		}
773 	}
774 	LLTABLE_RUNLOCK();
775 	KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
776 
777 	error = 0;
778 
779 	switch (rtm->rtm_type) {
780 	case RTM_ADD:
781 		/* Add static LLE */
782 		laflags = 0;
783 		if (rtm->rtm_rmx.rmx_expire == 0) {
784 			laflags = LLE_STATIC;
785 		}
786 		lle = lltable_alloc_entry(llt, laflags, dst);
787 		if (lle == NULL) {
788 			return ENOMEM;
789 		}
790 #if 0
791 		linkhdrsize = sizeof(linkhdr);
792 		if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl),
793 		    (void *)linkhdr, &linkhdrsize, &lladdr_off) != 0) {
794 			return EINVAL;
795 		}
796 #endif
797 		lltable_set_entry_addr(ifp, lle, LLADDR(dl));
798 
799 		if (rtm->rtm_flags & RTF_ANNOUNCE) {
800 			lle->la_flags |= LLE_PUB;
801 		}
802 		lle->la_expire = rtm->rtm_rmx.rmx_expire;
803 
804 		laflags = lle->la_flags;
805 
806 		/* Try to link new entry */
807 		lle_tmp = NULL;
808 		IF_AFDATA_WLOCK(ifp, llt->llt_af);
809 		LLE_WLOCK(lle);
810 		lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst);
811 		if (lle_tmp != NULL) {
812 			/* Check if we are trying to replace immutable entry */
813 			if ((lle_tmp->la_flags & LLE_IFADDR) != 0) {
814 				IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
815 				LLE_WUNLOCK(lle_tmp);
816 				lltable_free_entry(llt, lle);
817 				return EPERM;
818 			}
819 			/* Unlink existing entry from table */
820 			lltable_unlink_entry(llt, lle_tmp);
821 		}
822 		lltable_link_entry(llt, lle);
823 		IF_AFDATA_WUNLOCK(ifp, llt->llt_af);
824 
825 		if (lle_tmp != NULL) {
826 			EVENTHANDLER_INVOKE(NULL, lle_event, lle_tmp, LLENTRY_EXPIRED);
827 			lltable_free_entry(llt, lle_tmp);
828 		}
829 
830 		/*
831 		 * By invoking LLE handler here we might get
832 		 * two events on static LLE entry insertion
833 		 * in routing socket. However, since we might have
834 		 * other subscribers we need to generate this event.
835 		 */
836 		EVENTHANDLER_INVOKE(NULL, lle_event, lle, LLENTRY_RESOLVED);
837 		LLE_WUNLOCK(lle);
838 #ifdef INET
839 		/* gratuitous ARP */
840 		if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) {
841 			dlil_send_arp(ifp, ARPOP_REQUEST, NULL, dst, NULL, dst, 0);
842 		}
843 #endif
844 
845 		break;
846 
847 	case RTM_DELETE:
848 		return lltable_delete_addr(llt, 0, dst);
849 
850 	default:
851 		error = EINVAL;
852 	}
853 
854 	return error;
855 }
856