1 1.35 yamt /* $NetBSD: if_llatbl.c,v 1.35 2022/11/19 08:00:51 yamt Exp $ */ 2 1.1 ozaki /* 3 1.1 ozaki * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. 4 1.1 ozaki * Copyright (c) 2004-2008 Qing Li. All rights reserved. 5 1.1 ozaki * Copyright (c) 2008 Kip Macy. All rights reserved. 6 1.1 ozaki * Copyright (c) 2015 The NetBSD Foundation, Inc. 7 1.1 ozaki * All rights reserved. 8 1.1 ozaki * 9 1.1 ozaki * Redistribution and use in source and binary forms, with or without 10 1.1 ozaki * modification, are permitted provided that the following conditions 11 1.1 ozaki * are met: 12 1.1 ozaki * 1. Redistributions of source code must retain the above copyright 13 1.1 ozaki * notice, this list of conditions and the following disclaimer. 14 1.1 ozaki * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 ozaki * notice, this list of conditions and the following disclaimer in the 16 1.1 ozaki * documentation and/or other materials provided with the distribution. 17 1.1 ozaki * 18 1.1 ozaki * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 1.1 ozaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 1.1 ozaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 1.1 ozaki * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 1.1 ozaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 ozaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 1.1 ozaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 ozaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 ozaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 ozaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 ozaki * SUCH DAMAGE. 29 1.1 ozaki */ 30 1.1 ozaki #include <sys/cdefs.h> 31 1.1 ozaki 32 1.1 ozaki #ifdef _KERNEL_OPT 33 1.1 ozaki #include "opt_ddb.h" 34 1.1 ozaki #include "opt_inet.h" 35 1.1 ozaki #include "opt_inet6.h" 36 1.18 msaitoh #include "opt_net_mpsafe.h" 37 1.1 ozaki #endif 38 1.1 ozaki 39 1.9 ozaki #include "arp.h" 40 1.9 ozaki 41 1.1 ozaki #include <sys/param.h> 42 1.1 ozaki #include <sys/systm.h> 43 1.1 ozaki #include <sys/malloc.h> 44 1.1 ozaki #include <sys/mbuf.h> 45 1.1 ozaki #include <sys/syslog.h> 46 1.1 ozaki #include <sys/sysctl.h> 47 1.1 ozaki #include <sys/socket.h> 48 1.4 ozaki #include <sys/socketvar.h> 49 1.1 ozaki #include <sys/kernel.h> 50 1.1 ozaki #include <sys/lock.h> 51 1.1 ozaki #include <sys/mutex.h> 52 1.1 ozaki #include <sys/rwlock.h> 53 1.1 ozaki 54 1.1 ozaki #ifdef DDB 55 1.1 ozaki #include <ddb/ddb.h> 56 1.1 ozaki #endif 57 1.1 ozaki 58 1.1 ozaki #include <netinet/in.h> 59 1.1 ozaki #include <net/if_llatbl.h> 60 1.1 ozaki #include <net/if.h> 61 1.1 ozaki #include <net/if_dl.h> 62 1.32 roy #include <net/nd.h> 63 1.1 ozaki #include <net/route.h> 64 1.1 ozaki #include <netinet/if_inarp.h> 65 1.15 roy #include <netinet/in_var.h> 66 1.1 ozaki #include <netinet6/in6_var.h> 67 1.1 ozaki 68 1.1 ozaki static SLIST_HEAD(, lltable) lltables; 69 1.1 ozaki krwlock_t lltable_rwlock; 70 1.26 ozaki static struct pool llentry_pool; 71 1.1 ozaki 72 1.1 ozaki static void lltable_unlink(struct lltable *llt); 73 1.1 ozaki static void llentries_unlink(struct lltable *llt, struct llentries *head); 74 1.1 ozaki 75 1.1 ozaki static void htable_unlink_entry(struct llentry *lle); 76 1.1 ozaki static void htable_link_entry(struct lltable *llt, struct llentry *lle); 77 1.1 ozaki static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, 78 1.1 ozaki void *farg); 79 1.1 ozaki 80 1.11 ozaki int 81 1.11 ozaki lltable_dump_entry(struct lltable *llt, struct llentry *lle, 82 1.11 ozaki struct rt_walkarg *w, struct sockaddr *sa) 83 1.11 ozaki { 84 1.21 ozaki #define RTF_LLINFO 0x400 85 1.21 ozaki #define RTF_CLONED 0x2000 86 1.11 ozaki struct ifnet *ifp = llt->llt_ifp; 87 1.12 ozaki int error; 88 1.12 ozaki void *a; 89 1.11 ozaki struct sockaddr_dl sdl; 90 1.11 ozaki int size; 91 1.11 ozaki struct rt_addrinfo info; 92 1.11 ozaki 93 1.11 ozaki memset(&info, 0, sizeof(info)); 94 1.11 ozaki info.rti_info[RTAX_DST] = sa; 95 1.12 ozaki 96 1.12 ozaki a = (lle->la_flags & LLE_VALID) == LLE_VALID ? &lle->ll_addr : NULL; 97 1.12 ozaki if (sockaddr_dl_init(&sdl, sizeof(sdl), ifp->if_index, ifp->if_type, 98 1.12 ozaki NULL, 0, a, ifp->if_addrlen) == NULL) 99 1.12 ozaki return EINVAL; 100 1.12 ozaki 101 1.11 ozaki info.rti_info[RTAX_GATEWAY] = sstocsa(&sdl); 102 1.11 ozaki if (sa->sa_family == AF_INET && lle->la_flags & LLE_PUB) { 103 1.11 ozaki struct sockaddr_inarp *sin; 104 1.11 ozaki sin = (struct sockaddr_inarp *)sa; 105 1.11 ozaki sin->sin_other = SIN_PROXY; 106 1.11 ozaki } 107 1.11 ozaki if ((error = rt_msg3(RTM_GET, &info, 0, w, &size))) 108 1.11 ozaki return error; 109 1.11 ozaki if (w->w_where && w->w_tmem && w->w_needed <= 0) { 110 1.11 ozaki struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; 111 1.11 ozaki 112 1.11 ozaki /* Need to copy by myself */ 113 1.21 ozaki rtm->rtm_index = ifp->if_index; 114 1.21 ozaki rtm->rtm_rmx.rmx_mtu = 0; 115 1.27 nonaka rtm->rtm_rmx.rmx_expire = (lle->la_flags & LLE_STATIC) ? 0 : 116 1.27 nonaka time_mono_to_wall(lle->la_expire); 117 1.21 ozaki rtm->rtm_flags = RTF_UP; 118 1.11 ozaki rtm->rtm_flags |= RTF_HOST; /* For ndp */ 119 1.21 ozaki /* For backward compatibility */ 120 1.21 ozaki rtm->rtm_flags |= RTF_LLINFO | RTF_CLONED; 121 1.11 ozaki rtm->rtm_flags |= (lle->la_flags & LLE_STATIC) ? RTF_STATIC : 0; 122 1.11 ozaki if (lle->la_flags & LLE_PUB) 123 1.11 ozaki rtm->rtm_flags |= RTF_ANNOUNCE; 124 1.13 ozaki rtm->rtm_addrs = info.rti_addrs; 125 1.11 ozaki if ((error = copyout(rtm, w->w_where, size)) != 0) 126 1.11 ozaki w->w_where = NULL; 127 1.11 ozaki else 128 1.11 ozaki w->w_where = (char *)w->w_where + size; 129 1.11 ozaki } 130 1.11 ozaki 131 1.11 ozaki return error; 132 1.21 ozaki #undef RTF_LLINFO 133 1.21 ozaki #undef RTF_CLONED 134 1.11 ozaki } 135 1.11 ozaki 136 1.1 ozaki /* 137 1.1 ozaki * Dump lle state for a specific address family. 138 1.1 ozaki */ 139 1.1 ozaki static int 140 1.11 ozaki lltable_dump_af(struct lltable *llt, struct rt_walkarg *w) 141 1.1 ozaki { 142 1.1 ozaki int error; 143 1.1 ozaki 144 1.1 ozaki LLTABLE_LOCK_ASSERT(); 145 1.1 ozaki 146 1.1 ozaki if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 147 1.1 ozaki return (0); 148 1.1 ozaki error = 0; 149 1.1 ozaki 150 1.1 ozaki IF_AFDATA_RLOCK(llt->llt_ifp); 151 1.1 ozaki error = lltable_foreach_lle(llt, 152 1.11 ozaki (llt_foreach_cb_t *)llt->llt_dump_entry, w); 153 1.1 ozaki IF_AFDATA_RUNLOCK(llt->llt_ifp); 154 1.1 ozaki 155 1.1 ozaki return (error); 156 1.1 ozaki } 157 1.1 ozaki 158 1.1 ozaki /* 159 1.1 ozaki * Dump arp state for a specific address family. 160 1.1 ozaki */ 161 1.1 ozaki int 162 1.20 ozaki lltable_sysctl_dump(int af, struct rt_walkarg *w) 163 1.1 ozaki { 164 1.1 ozaki struct lltable *llt; 165 1.1 ozaki int error = 0; 166 1.1 ozaki 167 1.1 ozaki LLTABLE_RLOCK(); 168 1.1 ozaki SLIST_FOREACH(llt, &lltables, llt_link) { 169 1.1 ozaki if (llt->llt_af == af) { 170 1.11 ozaki error = lltable_dump_af(llt, w); 171 1.1 ozaki if (error != 0) 172 1.1 ozaki goto done; 173 1.1 ozaki } 174 1.1 ozaki } 175 1.1 ozaki done: 176 1.1 ozaki LLTABLE_RUNLOCK(); 177 1.1 ozaki return (error); 178 1.1 ozaki } 179 1.1 ozaki 180 1.1 ozaki /* 181 1.1 ozaki * Common function helpers for chained hash table. 182 1.1 ozaki */ 183 1.1 ozaki 184 1.1 ozaki /* 185 1.1 ozaki * Runs specified callback for each entry in @llt. 186 1.1 ozaki * Caller does the locking. 187 1.1 ozaki * 188 1.1 ozaki */ 189 1.1 ozaki static int 190 1.1 ozaki htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 191 1.1 ozaki { 192 1.1 ozaki struct llentry *lle, *next; 193 1.1 ozaki int i, error; 194 1.1 ozaki 195 1.1 ozaki error = 0; 196 1.1 ozaki 197 1.1 ozaki for (i = 0; i < llt->llt_hsize; i++) { 198 1.1 ozaki LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 199 1.1 ozaki error = f(llt, lle, farg); 200 1.1 ozaki if (error != 0) 201 1.1 ozaki break; 202 1.1 ozaki } 203 1.1 ozaki } 204 1.1 ozaki 205 1.1 ozaki return (error); 206 1.1 ozaki } 207 1.1 ozaki 208 1.1 ozaki static void 209 1.1 ozaki htable_link_entry(struct lltable *llt, struct llentry *lle) 210 1.1 ozaki { 211 1.1 ozaki struct llentries *lleh; 212 1.1 ozaki uint32_t hashidx; 213 1.1 ozaki 214 1.1 ozaki if ((lle->la_flags & LLE_LINKED) != 0) 215 1.1 ozaki return; 216 1.1 ozaki 217 1.1 ozaki IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 218 1.1 ozaki 219 1.1 ozaki hashidx = llt->llt_hash(lle, llt->llt_hsize); 220 1.1 ozaki lleh = &llt->lle_head[hashidx]; 221 1.1 ozaki 222 1.1 ozaki lle->lle_tbl = llt; 223 1.1 ozaki lle->lle_head = lleh; 224 1.1 ozaki lle->la_flags |= LLE_LINKED; 225 1.1 ozaki LIST_INSERT_HEAD(lleh, lle, lle_next); 226 1.8 ozaki 227 1.8 ozaki llt->llt_lle_count++; 228 1.1 ozaki } 229 1.1 ozaki 230 1.1 ozaki static void 231 1.1 ozaki htable_unlink_entry(struct llentry *lle) 232 1.1 ozaki { 233 1.1 ozaki 234 1.1 ozaki if ((lle->la_flags & LLE_LINKED) != 0) { 235 1.1 ozaki IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp); 236 1.1 ozaki LIST_REMOVE(lle, lle_next); 237 1.1 ozaki lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 238 1.1 ozaki #if 0 239 1.1 ozaki lle->lle_tbl = NULL; 240 1.1 ozaki lle->lle_head = NULL; 241 1.1 ozaki #endif 242 1.31 ozaki KASSERTMSG(lle->lle_tbl->llt_lle_count != 0, 243 1.31 ozaki "llt_lle_count=%u", lle->lle_tbl->llt_lle_count); 244 1.8 ozaki lle->lle_tbl->llt_lle_count--; 245 1.1 ozaki } 246 1.1 ozaki } 247 1.1 ozaki 248 1.1 ozaki struct prefix_match_data { 249 1.1 ozaki const struct sockaddr *prefix; 250 1.1 ozaki const struct sockaddr *mask; 251 1.1 ozaki struct llentries dchain; 252 1.1 ozaki u_int flags; 253 1.1 ozaki }; 254 1.1 ozaki 255 1.1 ozaki static int 256 1.1 ozaki htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 257 1.1 ozaki { 258 1.1 ozaki struct prefix_match_data *pmd; 259 1.1 ozaki 260 1.1 ozaki pmd = (struct prefix_match_data *)farg; 261 1.1 ozaki 262 1.1 ozaki if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) { 263 1.1 ozaki LLE_WLOCK(lle); 264 1.1 ozaki LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 265 1.1 ozaki } 266 1.1 ozaki 267 1.1 ozaki return (0); 268 1.1 ozaki } 269 1.1 ozaki 270 1.1 ozaki static void 271 1.1 ozaki htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix, 272 1.1 ozaki const struct sockaddr *mask, u_int flags) 273 1.1 ozaki { 274 1.1 ozaki struct llentry *lle, *next; 275 1.1 ozaki struct prefix_match_data pmd; 276 1.1 ozaki 277 1.1 ozaki memset(&pmd, 0, sizeof(pmd)); 278 1.1 ozaki pmd.prefix = prefix; 279 1.1 ozaki pmd.mask = mask; 280 1.1 ozaki pmd.flags = flags; 281 1.1 ozaki LIST_INIT(&pmd.dchain); 282 1.1 ozaki 283 1.1 ozaki IF_AFDATA_WLOCK(llt->llt_ifp); 284 1.1 ozaki /* Push matching lles to chain */ 285 1.1 ozaki lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 286 1.1 ozaki 287 1.1 ozaki llentries_unlink(llt, &pmd.dchain); 288 1.1 ozaki IF_AFDATA_WUNLOCK(llt->llt_ifp); 289 1.1 ozaki 290 1.1 ozaki LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 291 1.1 ozaki llt->llt_free_entry(llt, lle); 292 1.1 ozaki } 293 1.1 ozaki 294 1.1 ozaki static void 295 1.1 ozaki htable_free_tbl(struct lltable *llt) 296 1.1 ozaki { 297 1.1 ozaki 298 1.1 ozaki free(llt->lle_head, M_LLTABLE); 299 1.1 ozaki free(llt, M_LLTABLE); 300 1.1 ozaki } 301 1.1 ozaki 302 1.1 ozaki static void 303 1.1 ozaki llentries_unlink(struct lltable *llt, struct llentries *head) 304 1.1 ozaki { 305 1.1 ozaki struct llentry *lle, *next; 306 1.1 ozaki 307 1.1 ozaki LIST_FOREACH_SAFE(lle, head, lle_chain, next) 308 1.1 ozaki llt->llt_unlink_entry(lle); 309 1.1 ozaki } 310 1.1 ozaki 311 1.1 ozaki /* 312 1.1 ozaki * Helper function used to drop all mbufs in hold queue. 313 1.1 ozaki * 314 1.1 ozaki * Returns the number of held packets, if any, that were dropped. 315 1.1 ozaki */ 316 1.1 ozaki size_t 317 1.1 ozaki lltable_drop_entry_queue(struct llentry *lle) 318 1.1 ozaki { 319 1.1 ozaki size_t pkts_dropped; 320 1.1 ozaki struct mbuf *next; 321 1.1 ozaki 322 1.1 ozaki LLE_WLOCK_ASSERT(lle); 323 1.1 ozaki 324 1.1 ozaki pkts_dropped = 0; 325 1.1 ozaki while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 326 1.1 ozaki next = lle->la_hold->m_nextpkt; 327 1.1 ozaki m_freem(lle->la_hold); 328 1.1 ozaki lle->la_hold = next; 329 1.1 ozaki lle->la_numheld--; 330 1.1 ozaki pkts_dropped++; 331 1.1 ozaki } 332 1.1 ozaki 333 1.1 ozaki KASSERTMSG(lle->la_numheld == 0, 334 1.34 andvar "la_numheld %d > 0, pkts_dropped %zd", 335 1.1 ozaki lle->la_numheld, pkts_dropped); 336 1.1 ozaki 337 1.1 ozaki return (pkts_dropped); 338 1.1 ozaki } 339 1.1 ozaki 340 1.26 ozaki struct llentry * 341 1.26 ozaki llentry_pool_get(int flags) 342 1.26 ozaki { 343 1.26 ozaki struct llentry *lle; 344 1.26 ozaki 345 1.26 ozaki lle = pool_get(&llentry_pool, flags); 346 1.26 ozaki if (lle != NULL) 347 1.26 ozaki memset(lle, 0, sizeof(*lle)); 348 1.26 ozaki return lle; 349 1.26 ozaki } 350 1.26 ozaki 351 1.26 ozaki void 352 1.26 ozaki llentry_pool_put(struct llentry *lle) 353 1.26 ozaki { 354 1.26 ozaki 355 1.26 ozaki pool_put(&llentry_pool, lle); 356 1.26 ozaki } 357 1.26 ozaki 358 1.1 ozaki /* 359 1.1 ozaki * Deletes an address from the address table. 360 1.1 ozaki * This function is called by the timer functions 361 1.1 ozaki * such as arptimer() and nd6_llinfo_timer(), and 362 1.1 ozaki * the caller does the locking. 363 1.1 ozaki * 364 1.1 ozaki * Returns the number of held packets, if any, that were dropped. 365 1.1 ozaki */ 366 1.1 ozaki size_t 367 1.1 ozaki llentry_free(struct llentry *lle) 368 1.1 ozaki { 369 1.1 ozaki struct lltable *llt; 370 1.1 ozaki size_t pkts_dropped; 371 1.1 ozaki 372 1.1 ozaki LLE_WLOCK_ASSERT(lle); 373 1.1 ozaki 374 1.25 ozaki lle->la_flags |= LLE_DELETED; 375 1.25 ozaki 376 1.1 ozaki if ((lle->la_flags & LLE_LINKED) != 0) { 377 1.1 ozaki llt = lle->lle_tbl; 378 1.1 ozaki 379 1.1 ozaki IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 380 1.1 ozaki llt->llt_unlink_entry(lle); 381 1.1 ozaki } 382 1.1 ozaki 383 1.24 ozaki /* 384 1.24 ozaki * Stop a pending callout if one exists. If we cancel one, we have to 385 1.24 ozaki * remove a reference to avoid a leak. callout_pending is required to 386 1.24 ozaki * to exclude the case that the callout has never been scheduled. 387 1.24 ozaki */ 388 1.24 ozaki /* XXX once softnet_lock goes away, we should use callout_halt */ 389 1.24 ozaki if (callout_pending(&lle->la_timer)) { 390 1.24 ozaki bool expired = callout_stop(&lle->la_timer); 391 1.24 ozaki if (!expired) 392 1.24 ozaki LLE_REMREF(lle); 393 1.24 ozaki } 394 1.24 ozaki 395 1.1 ozaki pkts_dropped = lltable_drop_entry_queue(lle); 396 1.1 ozaki 397 1.1 ozaki LLE_FREE_LOCKED(lle); 398 1.1 ozaki 399 1.1 ozaki return (pkts_dropped); 400 1.1 ozaki } 401 1.1 ozaki 402 1.1 ozaki /* 403 1.1 ozaki * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp). 404 1.1 ozaki * 405 1.1 ozaki * If found the llentry * is returned referenced and unlocked. 406 1.1 ozaki */ 407 1.1 ozaki struct llentry * 408 1.1 ozaki llentry_alloc(struct ifnet *ifp, struct lltable *lt, 409 1.1 ozaki struct sockaddr_storage *dst) 410 1.1 ozaki { 411 1.1 ozaki struct llentry *la; 412 1.1 ozaki 413 1.1 ozaki IF_AFDATA_RLOCK(ifp); 414 1.1 ozaki la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 415 1.1 ozaki IF_AFDATA_RUNLOCK(ifp); 416 1.23 maxv if ((la == NULL) && (ifp->if_flags & IFF_NOARP) == 0) { 417 1.1 ozaki IF_AFDATA_WLOCK(ifp); 418 1.22 ozaki la = lla_create(lt, 0, (struct sockaddr *)dst, NULL /* XXX */); 419 1.1 ozaki IF_AFDATA_WUNLOCK(ifp); 420 1.1 ozaki } 421 1.1 ozaki 422 1.1 ozaki if (la != NULL) { 423 1.1 ozaki LLE_ADDREF(la); 424 1.1 ozaki LLE_WUNLOCK(la); 425 1.1 ozaki } 426 1.1 ozaki 427 1.1 ozaki return (la); 428 1.1 ozaki } 429 1.1 ozaki 430 1.1 ozaki /* 431 1.1 ozaki * Free all entries from given table and free itself. 432 1.1 ozaki */ 433 1.1 ozaki 434 1.1 ozaki static int 435 1.1 ozaki lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 436 1.1 ozaki { 437 1.1 ozaki struct llentries *dchain; 438 1.1 ozaki 439 1.1 ozaki dchain = (struct llentries *)farg; 440 1.1 ozaki 441 1.1 ozaki LLE_WLOCK(lle); 442 1.1 ozaki LIST_INSERT_HEAD(dchain, lle, lle_chain); 443 1.1 ozaki 444 1.1 ozaki return (0); 445 1.1 ozaki } 446 1.1 ozaki 447 1.1 ozaki /* 448 1.8 ozaki * Free all entries from given table. 449 1.1 ozaki */ 450 1.1 ozaki void 451 1.8 ozaki lltable_purge_entries(struct lltable *llt) 452 1.1 ozaki { 453 1.1 ozaki struct llentry *lle, *next; 454 1.1 ozaki struct llentries dchain; 455 1.1 ozaki 456 1.1 ozaki KASSERTMSG(llt != NULL, "llt is NULL"); 457 1.1 ozaki 458 1.1 ozaki LIST_INIT(&dchain); 459 1.1 ozaki IF_AFDATA_WLOCK(llt->llt_ifp); 460 1.1 ozaki /* Push all lles to @dchain */ 461 1.1 ozaki lltable_foreach_lle(llt, lltable_free_cb, &dchain); 462 1.1 ozaki llentries_unlink(llt, &dchain); 463 1.1 ozaki IF_AFDATA_WUNLOCK(llt->llt_ifp); 464 1.1 ozaki 465 1.24 ozaki LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) 466 1.24 ozaki (void)llentry_free(lle); 467 1.8 ozaki } 468 1.8 ozaki 469 1.8 ozaki /* 470 1.8 ozaki * Free all entries from given table and free itself. 471 1.8 ozaki */ 472 1.8 ozaki void 473 1.8 ozaki lltable_free(struct lltable *llt) 474 1.8 ozaki { 475 1.8 ozaki 476 1.8 ozaki KASSERTMSG(llt != NULL, "llt is NULL"); 477 1.8 ozaki 478 1.8 ozaki lltable_unlink(llt); 479 1.8 ozaki lltable_purge_entries(llt); 480 1.1 ozaki llt->llt_free_tbl(llt); 481 1.1 ozaki } 482 1.1 ozaki 483 1.1 ozaki void 484 1.1 ozaki lltable_drain(int af) 485 1.1 ozaki { 486 1.1 ozaki struct lltable *llt; 487 1.1 ozaki struct llentry *lle; 488 1.1 ozaki register int i; 489 1.1 ozaki 490 1.1 ozaki LLTABLE_RLOCK(); 491 1.1 ozaki SLIST_FOREACH(llt, &lltables, llt_link) { 492 1.1 ozaki if (llt->llt_af != af) 493 1.1 ozaki continue; 494 1.1 ozaki 495 1.1 ozaki for (i=0; i < llt->llt_hsize; i++) { 496 1.1 ozaki LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 497 1.1 ozaki LLE_WLOCK(lle); 498 1.1 ozaki lltable_drop_entry_queue(lle); 499 1.1 ozaki LLE_WUNLOCK(lle); 500 1.1 ozaki } 501 1.1 ozaki } 502 1.1 ozaki } 503 1.1 ozaki LLTABLE_RUNLOCK(); 504 1.1 ozaki } 505 1.1 ozaki 506 1.1 ozaki void 507 1.19 ozaki lltable_prefix_free(const int af, const struct sockaddr *prefix, 508 1.19 ozaki const struct sockaddr *mask, const u_int flags) 509 1.1 ozaki { 510 1.1 ozaki struct lltable *llt; 511 1.1 ozaki 512 1.1 ozaki LLTABLE_RLOCK(); 513 1.1 ozaki SLIST_FOREACH(llt, &lltables, llt_link) { 514 1.1 ozaki if (llt->llt_af != af) 515 1.1 ozaki continue; 516 1.1 ozaki 517 1.1 ozaki llt->llt_prefix_free(llt, prefix, mask, flags); 518 1.1 ozaki } 519 1.1 ozaki LLTABLE_RUNLOCK(); 520 1.1 ozaki } 521 1.1 ozaki 522 1.1 ozaki struct lltable * 523 1.1 ozaki lltable_allocate_htbl(uint32_t hsize) 524 1.1 ozaki { 525 1.1 ozaki struct lltable *llt; 526 1.1 ozaki int i; 527 1.1 ozaki 528 1.1 ozaki llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 529 1.1 ozaki llt->llt_hsize = hsize; 530 1.1 ozaki llt->lle_head = malloc(sizeof(struct llentries) * hsize, 531 1.1 ozaki M_LLTABLE, M_WAITOK | M_ZERO); 532 1.1 ozaki 533 1.1 ozaki for (i = 0; i < llt->llt_hsize; i++) 534 1.1 ozaki LIST_INIT(&llt->lle_head[i]); 535 1.1 ozaki 536 1.1 ozaki /* Set some default callbacks */ 537 1.1 ozaki llt->llt_link_entry = htable_link_entry; 538 1.1 ozaki llt->llt_unlink_entry = htable_unlink_entry; 539 1.1 ozaki llt->llt_prefix_free = htable_prefix_free; 540 1.1 ozaki llt->llt_foreach_entry = htable_foreach_lle; 541 1.1 ozaki 542 1.1 ozaki llt->llt_free_tbl = htable_free_tbl; 543 1.35 yamt #ifdef MBUFTRACE 544 1.35 yamt llt->llt_mowner = NULL; 545 1.35 yamt #endif 546 1.1 ozaki 547 1.1 ozaki return (llt); 548 1.1 ozaki } 549 1.1 ozaki 550 1.1 ozaki /* 551 1.1 ozaki * Links lltable to global llt list. 552 1.1 ozaki */ 553 1.1 ozaki void 554 1.1 ozaki lltable_link(struct lltable *llt) 555 1.1 ozaki { 556 1.1 ozaki 557 1.1 ozaki LLTABLE_WLOCK(); 558 1.1 ozaki SLIST_INSERT_HEAD(&lltables, llt, llt_link); 559 1.1 ozaki LLTABLE_WUNLOCK(); 560 1.1 ozaki } 561 1.1 ozaki 562 1.1 ozaki static void 563 1.1 ozaki lltable_unlink(struct lltable *llt) 564 1.1 ozaki { 565 1.1 ozaki 566 1.1 ozaki LLTABLE_WLOCK(); 567 1.1 ozaki SLIST_REMOVE(&lltables, llt, lltable, llt_link); 568 1.1 ozaki LLTABLE_WUNLOCK(); 569 1.1 ozaki 570 1.1 ozaki } 571 1.1 ozaki 572 1.1 ozaki /* 573 1.1 ozaki * External methods used by lltable consumers 574 1.1 ozaki */ 575 1.1 ozaki 576 1.1 ozaki int 577 1.1 ozaki lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 578 1.1 ozaki { 579 1.1 ozaki 580 1.1 ozaki return (llt->llt_foreach_entry(llt, f, farg)); 581 1.1 ozaki } 582 1.1 ozaki 583 1.1 ozaki void 584 1.1 ozaki lltable_link_entry(struct lltable *llt, struct llentry *lle) 585 1.1 ozaki { 586 1.1 ozaki 587 1.1 ozaki llt->llt_link_entry(llt, lle); 588 1.1 ozaki } 589 1.1 ozaki 590 1.1 ozaki void 591 1.1 ozaki lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 592 1.1 ozaki { 593 1.1 ozaki 594 1.1 ozaki llt->llt_unlink_entry(lle); 595 1.1 ozaki } 596 1.1 ozaki 597 1.1 ozaki void 598 1.16 ozaki lltable_free_entry(struct lltable *llt, struct llentry *lle) 599 1.16 ozaki { 600 1.16 ozaki 601 1.16 ozaki llt->llt_free_entry(llt, lle); 602 1.16 ozaki } 603 1.16 ozaki 604 1.16 ozaki void 605 1.1 ozaki lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 606 1.1 ozaki { 607 1.1 ozaki struct lltable *llt; 608 1.1 ozaki 609 1.1 ozaki llt = lle->lle_tbl; 610 1.1 ozaki llt->llt_fill_sa_entry(lle, sa); 611 1.1 ozaki } 612 1.1 ozaki 613 1.1 ozaki struct ifnet * 614 1.1 ozaki lltable_get_ifp(const struct lltable *llt) 615 1.1 ozaki { 616 1.1 ozaki 617 1.1 ozaki return (llt->llt_ifp); 618 1.1 ozaki } 619 1.1 ozaki 620 1.1 ozaki int 621 1.1 ozaki lltable_get_af(const struct lltable *llt) 622 1.1 ozaki { 623 1.1 ozaki 624 1.1 ozaki return (llt->llt_af); 625 1.1 ozaki } 626 1.1 ozaki 627 1.1 ozaki /* 628 1.1 ozaki * Called in route_output when rtm_flags contains RTF_LLDATA. 629 1.1 ozaki */ 630 1.1 ozaki int 631 1.11 ozaki lla_rt_output(const u_char rtm_type, const int rtm_flags, const time_t rtm_expire, 632 1.11 ozaki struct rt_addrinfo *info, int sdl_index) 633 1.1 ozaki { 634 1.1 ozaki const struct sockaddr_dl *dl = satocsdl(info->rti_info[RTAX_GATEWAY]); 635 1.1 ozaki const struct sockaddr *dst = info->rti_info[RTAX_DST]; 636 1.1 ozaki struct ifnet *ifp; 637 1.1 ozaki struct lltable *llt; 638 1.1 ozaki struct llentry *lle; 639 1.1 ozaki u_int laflags; 640 1.1 ozaki int error; 641 1.14 ozaki struct psref psref; 642 1.14 ozaki int bound; 643 1.1 ozaki 644 1.1 ozaki KASSERTMSG(dl != NULL && dl->sdl_family == AF_LINK, "invalid dl"); 645 1.1 ozaki 646 1.14 ozaki bound = curlwp_bind(); 647 1.11 ozaki if (sdl_index != 0) 648 1.14 ozaki ifp = if_get_byindex(sdl_index, &psref); 649 1.11 ozaki else 650 1.14 ozaki ifp = if_get_byindex(dl->sdl_index, &psref); 651 1.1 ozaki if (ifp == NULL) { 652 1.14 ozaki curlwp_bindx(bound); 653 1.1 ozaki log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 654 1.11 ozaki __func__, sdl_index != 0 ? sdl_index : dl->sdl_index); 655 1.1 ozaki return EINVAL; 656 1.1 ozaki } 657 1.1 ozaki 658 1.1 ozaki /* XXX linked list may be too expensive */ 659 1.1 ozaki LLTABLE_RLOCK(); 660 1.1 ozaki SLIST_FOREACH(llt, &lltables, llt_link) { 661 1.1 ozaki if (llt->llt_af == dst->sa_family && 662 1.1 ozaki llt->llt_ifp == ifp) 663 1.1 ozaki break; 664 1.1 ozaki } 665 1.1 ozaki LLTABLE_RUNLOCK(); 666 1.1 ozaki KASSERTMSG(llt != NULL, "Yep, ugly hacks are bad"); 667 1.1 ozaki 668 1.1 ozaki error = 0; 669 1.1 ozaki 670 1.11 ozaki switch (rtm_type) { 671 1.22 ozaki case RTM_ADD: { 672 1.22 ozaki struct rtentry *rt; 673 1.22 ozaki 674 1.22 ozaki /* Never call rtalloc1 with IF_AFDATA_WLOCK */ 675 1.22 ozaki rt = rtalloc1(dst, 0); 676 1.22 ozaki 677 1.1 ozaki /* Add static LLE */ 678 1.1 ozaki IF_AFDATA_WLOCK(ifp); 679 1.28 ozaki lle = lla_lookup(llt, LLE_EXCLUSIVE, dst); 680 1.11 ozaki 681 1.11 ozaki /* Cannot overwrite an existing static entry */ 682 1.11 ozaki if (lle != NULL && 683 1.11 ozaki (lle->la_flags & LLE_STATIC || lle->la_expire == 0)) { 684 1.11 ozaki LLE_RUNLOCK(lle); 685 1.11 ozaki IF_AFDATA_WUNLOCK(ifp); 686 1.22 ozaki if (rt != NULL) 687 1.22 ozaki rt_unref(rt); 688 1.14 ozaki error = EEXIST; 689 1.14 ozaki goto out; 690 1.11 ozaki } 691 1.28 ozaki 692 1.28 ozaki /* 693 1.28 ozaki * We can't overwrite an existing entry to avoid race 694 1.28 ozaki * conditions so remove it first. 695 1.28 ozaki */ 696 1.28 ozaki if (lle != NULL) { 697 1.30 kre #if defined(INET) && NARP > 0 698 1.28 ozaki size_t pkts_dropped = llentry_free(lle); 699 1.28 ozaki if (dst->sa_family == AF_INET) { 700 1.28 ozaki arp_stat_add(ARP_STAT_DFRDROPPED, 701 1.28 ozaki (uint64_t)pkts_dropped); 702 1.28 ozaki } 703 1.30 kre #else 704 1.30 kre (void) llentry_free(lle); 705 1.29 kre #endif 706 1.28 ozaki } 707 1.11 ozaki 708 1.22 ozaki lle = lla_create(llt, 0, dst, rt); 709 1.1 ozaki if (lle == NULL) { 710 1.1 ozaki IF_AFDATA_WUNLOCK(ifp); 711 1.22 ozaki if (rt != NULL) 712 1.22 ozaki rt_unref(rt); 713 1.14 ozaki error = ENOMEM; 714 1.14 ozaki goto out; 715 1.1 ozaki } 716 1.1 ozaki 717 1.12 ozaki KASSERT(ifp->if_addrlen <= sizeof(lle->ll_addr)); 718 1.1 ozaki memcpy(&lle->ll_addr, CLLADDR(dl), ifp->if_addrlen); 719 1.11 ozaki if ((rtm_flags & RTF_ANNOUNCE)) 720 1.1 ozaki lle->la_flags |= LLE_PUB; 721 1.1 ozaki lle->la_flags |= LLE_VALID; 722 1.32 roy switch (dst->sa_family) { 723 1.33 roy #ifdef INET 724 1.33 roy case AF_INET: 725 1.33 roy lle->ln_state = ND_LLINFO_REACHABLE; 726 1.33 roy break; 727 1.33 roy #endif 728 1.1 ozaki #ifdef INET6 729 1.32 roy case AF_INET6: 730 1.32 roy lle->ln_state = ND_LLINFO_REACHABLE; 731 1.32 roy break; 732 1.1 ozaki #endif 733 1.32 roy } 734 1.32 roy 735 1.1 ozaki /* 736 1.1 ozaki * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) 737 1.1 ozaki */ 738 1.1 ozaki 739 1.11 ozaki if (rtm_expire == 0) { 740 1.1 ozaki lle->la_flags |= LLE_STATIC; 741 1.1 ozaki lle->la_expire = 0; 742 1.1 ozaki } else 743 1.11 ozaki lle->la_expire = rtm_expire; 744 1.1 ozaki laflags = lle->la_flags; 745 1.1 ozaki LLE_WUNLOCK(lle); 746 1.1 ozaki IF_AFDATA_WUNLOCK(ifp); 747 1.22 ozaki if (rt != NULL) 748 1.22 ozaki rt_unref(rt); 749 1.9 ozaki #if defined(INET) && NARP > 0 750 1.1 ozaki /* gratuitous ARP */ 751 1.15 roy if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) { 752 1.15 roy const struct sockaddr_in *sin; 753 1.15 roy struct in_ifaddr *ia; 754 1.15 roy struct psref _psref; 755 1.15 roy 756 1.15 roy sin = satocsin(dst); 757 1.15 roy ia = in_get_ia_on_iface_psref(sin->sin_addr, 758 1.15 roy ifp, &_psref); 759 1.15 roy if (ia != NULL) { 760 1.15 roy arpannounce(ifp, &ia->ia_ifa, CLLADDR(dl)); 761 1.15 roy ia4_release(ia, &_psref); 762 1.15 roy } 763 1.15 roy } 764 1.9 ozaki #else 765 1.9 ozaki (void)laflags; 766 1.1 ozaki #endif 767 1.1 ozaki break; 768 1.22 ozaki } 769 1.1 ozaki 770 1.1 ozaki case RTM_DELETE: 771 1.1 ozaki IF_AFDATA_WLOCK(ifp); 772 1.1 ozaki error = lla_delete(llt, 0, dst); 773 1.1 ozaki IF_AFDATA_WUNLOCK(ifp); 774 1.14 ozaki error = (error == 0 ? 0 : ENOENT); 775 1.14 ozaki break; 776 1.1 ozaki 777 1.1 ozaki default: 778 1.1 ozaki error = EINVAL; 779 1.1 ozaki } 780 1.1 ozaki 781 1.14 ozaki out: 782 1.14 ozaki if_put(ifp, &psref); 783 1.14 ozaki curlwp_bindx(bound); 784 1.1 ozaki return (error); 785 1.1 ozaki } 786 1.1 ozaki 787 1.1 ozaki void 788 1.1 ozaki lltableinit(void) 789 1.1 ozaki { 790 1.1 ozaki 791 1.1 ozaki SLIST_INIT(&lltables); 792 1.1 ozaki rw_init(&lltable_rwlock); 793 1.26 ozaki 794 1.26 ozaki pool_init(&llentry_pool, sizeof(struct llentry), 0, 0, 0, "llentrypl", 795 1.26 ozaki NULL, IPL_SOFTNET); 796 1.1 ozaki } 797 1.1 ozaki 798 1.1 ozaki #ifdef __FreeBSD__ 799 1.1 ozaki #ifdef DDB 800 1.1 ozaki struct llentry_sa { 801 1.1 ozaki struct llentry base; 802 1.1 ozaki struct sockaddr l3_addr; 803 1.1 ozaki }; 804 1.1 ozaki 805 1.1 ozaki static void 806 1.1 ozaki llatbl_lle_show(struct llentry_sa *la) 807 1.1 ozaki { 808 1.1 ozaki struct llentry *lle; 809 1.1 ozaki uint8_t octet[6]; 810 1.1 ozaki 811 1.1 ozaki lle = &la->base; 812 1.1 ozaki db_printf("lle=%p\n", lle); 813 1.1 ozaki db_printf(" lle_next=%p\n", lle->lle_next.le_next); 814 1.1 ozaki db_printf(" lle_lock=%p\n", &lle->lle_lock); 815 1.1 ozaki db_printf(" lle_tbl=%p\n", lle->lle_tbl); 816 1.1 ozaki db_printf(" lle_head=%p\n", lle->lle_head); 817 1.1 ozaki db_printf(" la_hold=%p\n", lle->la_hold); 818 1.1 ozaki db_printf(" la_numheld=%d\n", lle->la_numheld); 819 1.1 ozaki db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 820 1.1 ozaki db_printf(" la_flags=0x%04x\n", lle->la_flags); 821 1.1 ozaki db_printf(" la_asked=%u\n", lle->la_asked); 822 1.1 ozaki db_printf(" la_preempt=%u\n", lle->la_preempt); 823 1.1 ozaki db_printf(" ln_byhint=%u\n", lle->ln_byhint); 824 1.1 ozaki db_printf(" ln_state=%d\n", lle->ln_state); 825 1.1 ozaki db_printf(" ln_router=%u\n", lle->ln_router); 826 1.1 ozaki db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 827 1.1 ozaki db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 828 1.1 ozaki memcopy(octet, &lle->ll_addr.mac16, sizeof(octet)); 829 1.1 ozaki db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 830 1.1 ozaki octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 831 1.1 ozaki db_printf(" lle_timer=%p\n", &lle->lle_timer); 832 1.1 ozaki 833 1.1 ozaki switch (la->l3_addr.sa_family) { 834 1.1 ozaki #ifdef INET 835 1.1 ozaki case AF_INET: 836 1.1 ozaki { 837 1.1 ozaki struct sockaddr_in *sin; 838 1.1 ozaki char l3s[INET_ADDRSTRLEN]; 839 1.1 ozaki 840 1.1 ozaki sin = (struct sockaddr_in *)&la->l3_addr; 841 1.1 ozaki inet_ntoa_r(sin->sin_addr, l3s); 842 1.1 ozaki db_printf(" l3_addr=%s\n", l3s); 843 1.1 ozaki break; 844 1.1 ozaki } 845 1.1 ozaki #endif 846 1.1 ozaki #ifdef INET6 847 1.1 ozaki case AF_INET6: 848 1.1 ozaki { 849 1.1 ozaki struct sockaddr_in6 *sin6; 850 1.1 ozaki char l3s[INET6_ADDRSTRLEN]; 851 1.1 ozaki 852 1.1 ozaki sin6 = (struct sockaddr_in6 *)&la->l3_addr; 853 1.17 christos IN6_PRINT(l3s, &sin6->sin6_addr); 854 1.1 ozaki db_printf(" l3_addr=%s\n", l3s); 855 1.1 ozaki break; 856 1.1 ozaki } 857 1.1 ozaki #endif 858 1.1 ozaki default: 859 1.1 ozaki db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 860 1.1 ozaki break; 861 1.1 ozaki } 862 1.1 ozaki } 863 1.1 ozaki 864 1.1 ozaki DB_SHOW_COMMAND(llentry, db_show_llentry) 865 1.1 ozaki { 866 1.1 ozaki 867 1.1 ozaki if (!have_addr) { 868 1.1 ozaki db_printf("usage: show llentry <struct llentry *>\n"); 869 1.1 ozaki return; 870 1.1 ozaki } 871 1.1 ozaki 872 1.1 ozaki llatbl_lle_show((struct llentry_sa *)addr); 873 1.1 ozaki } 874 1.1 ozaki 875 1.1 ozaki static void 876 1.1 ozaki llatbl_llt_show(struct lltable *llt) 877 1.1 ozaki { 878 1.1 ozaki int i; 879 1.1 ozaki struct llentry *lle; 880 1.1 ozaki 881 1.1 ozaki db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 882 1.1 ozaki llt, llt->llt_af, llt->llt_ifp); 883 1.1 ozaki 884 1.1 ozaki for (i = 0; i < llt->llt_hsize; i++) { 885 1.1 ozaki LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 886 1.1 ozaki 887 1.1 ozaki llatbl_lle_show((struct llentry_sa *)lle); 888 1.1 ozaki if (db_pager_quit) 889 1.1 ozaki return; 890 1.1 ozaki } 891 1.1 ozaki } 892 1.1 ozaki } 893 1.1 ozaki 894 1.1 ozaki DB_SHOW_COMMAND(lltable, db_show_lltable) 895 1.1 ozaki { 896 1.1 ozaki 897 1.1 ozaki if (!have_addr) { 898 1.1 ozaki db_printf("usage: show lltable <struct lltable *>\n"); 899 1.1 ozaki return; 900 1.1 ozaki } 901 1.1 ozaki 902 1.1 ozaki llatbl_llt_show((struct lltable *)addr); 903 1.1 ozaki } 904 1.1 ozaki 905 1.1 ozaki DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 906 1.1 ozaki { 907 1.1 ozaki VNET_ITERATOR_DECL(vnet_iter); 908 1.1 ozaki struct lltable *llt; 909 1.1 ozaki 910 1.1 ozaki VNET_FOREACH(vnet_iter) { 911 1.1 ozaki CURVNET_SET_QUIET(vnet_iter); 912 1.1 ozaki #ifdef VIMAGE 913 1.1 ozaki db_printf("vnet=%p\n", curvnet); 914 1.1 ozaki #endif 915 1.1 ozaki SLIST_FOREACH(llt, &lltables, llt_link) { 916 1.1 ozaki db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 917 1.1 ozaki llt, llt->llt_af, llt->llt_ifp, 918 1.1 ozaki (llt->llt_ifp != NULL) ? 919 1.1 ozaki llt->llt_ifp->if_xname : "?"); 920 1.1 ozaki if (have_addr && addr != 0) /* verbose */ 921 1.1 ozaki llatbl_llt_show(llt); 922 1.1 ozaki if (db_pager_quit) { 923 1.1 ozaki CURVNET_RESTORE(); 924 1.1 ozaki return; 925 1.1 ozaki } 926 1.1 ozaki } 927 1.1 ozaki CURVNET_RESTORE(); 928 1.1 ozaki } 929 1.1 ozaki } 930 1.1 ozaki #endif /* DDB */ 931 1.1 ozaki #endif /* __FreeBSD__ */ 932