1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/atomic.h> 28 #include <sys/kmem.h> 29 #include <sys/rwlock.h> 30 #include <sys/errno.h> 31 #include <sys/queue.h> 32 #include <inet/common.h> 33 #include <inet/led.h> 34 #include <inet/ip.h> 35 #include <sys/neti.h> 36 #include <sys/zone.h> 37 38 static net_handle_t net_find(const char *protocol, neti_stack_t *ns); 39 40 static net_handle_t 41 net_find(const char *protocol, neti_stack_t *nts) 42 { 43 struct net_data *n; 44 45 ASSERT(protocol != NULL); 46 ASSERT(nts != NULL); 47 48 LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { 49 ASSERT(n->netd_info.netp_name != NULL); 50 /* 51 * If they're trying to find a protocol that is being 52 * shutdown, just ignore it.. 53 */ 54 if (n->netd_condemned != 0) 55 continue; 56 if (strcmp(n->netd_info.netp_name, protocol) == 0) { 57 break; 58 } 59 } 60 61 return (n); 62 } 63 64 net_handle_t 65 net_protocol_register(netid_t id, const net_protocol_t *info) 66 { 67 struct net_data *n, *new; 68 neti_stack_t *nts; 69 70 ASSERT(info != NULL); 71 72 nts = net_getnetistackbyid(id); 73 if (nts == NULL) 74 return (NULL); 75 76 new = kmem_alloc(sizeof (*new), KM_SLEEP); 77 new->netd_refcnt = 1; 78 new->netd_hooks = NULL; 79 new->netd_info = *info; 80 new->netd_stack = nts; 81 new->netd_condemned = 0; 82 83 mutex_enter(&nts->nts_lock); 84 n = net_find(info->netp_name, nts); 85 if (n != NULL) { 86 mutex_exit(&nts->nts_lock); 87 kmem_free(new, sizeof (*new)); 88 return (NULL); 89 } 90 91 if (LIST_EMPTY(&nts->nts_netd_head)) { 92 LIST_INSERT_HEAD(&nts->nts_netd_head, new, netd_list); 93 } else { 94 LIST_INSERT_AFTER(LIST_FIRST(&nts->nts_netd_head), 95 new, netd_list); 96 } 97 mutex_exit(&nts->nts_lock); 98 99 return (new); 100 } 101 102 int 103 net_protocol_unregister(net_handle_t info) 104 { 105 neti_stack_t *nts; 106 107 ASSERT(info != NULL); 108 109 nts = info->netd_stack; 110 ASSERT(nts != NULL); 111 112 mutex_enter(&nts->nts_lock); 113 LIST_REMOVE(info, netd_list); 114 info->netd_stack = NULL; 115 mutex_exit(&nts->nts_lock); 116 117 (void) net_protocol_release(info); 118 119 return (0); 120 } 121 122 net_handle_t 123 net_protocol_lookup(netid_t netid, const char *protocol) 124 { 125 neti_stack_t *nts; 126 net_handle_t nd; 127 128 ASSERT(protocol != NULL); 129 130 nts = net_getnetistackbyid(netid); 131 if (nts == NULL) 132 return (NULL); 133 134 mutex_enter(&nts->nts_lock); 135 nd = net_find(protocol, nts); 136 if (nd != NULL) 137 atomic_add_32((uint_t *)&nd->netd_refcnt, 1); 138 mutex_exit(&nts->nts_lock); 139 return (nd); 140 } 141 142 /* 143 * Note: the man page specifies "returns -1 if the value passed in is unknown 144 * to this framework". We are not doing a lookup in this function, just a 145 * simply add to the netd_refcnt of the net_handle_t passed in, so -1 is never a 146 * return value. 147 */ 148 int 149 net_protocol_release(net_handle_t info) 150 { 151 152 ASSERT(info->netd_refcnt > 0); 153 /* 154 * Is this safe? No hold on nts_lock? Consider that if the caller 155 * of net_protocol_release() is going to free this structure then 156 * it is now the only owner (refcnt==1) and it will have been 157 * removed from the nts_netd_head list on the neti_stack_t from a 158 * call to net_protocol_unregister already, so it is thus an orphan. 159 */ 160 if (atomic_add_32_nv((uint_t *)&info->netd_refcnt, -1) == 0) { 161 ASSERT(info->netd_hooks == NULL); 162 ASSERT(info->netd_stack == NULL); 163 kmem_free(info, sizeof (struct net_data)); 164 } 165 166 return (0); 167 } 168 169 net_handle_t 170 net_protocol_walk(netid_t netid, net_handle_t info) 171 { 172 struct net_data *n = NULL; 173 boolean_t found = B_FALSE; 174 neti_stack_t *nts; 175 176 nts = net_getnetistackbyid(netid); 177 ASSERT(nts != NULL); 178 179 if (info == NULL) 180 found = B_TRUE; 181 182 mutex_enter(&nts->nts_lock); 183 LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { 184 if (found) { 185 /* 186 * We are only interested in finding protocols that 187 * are not in some sort of shutdown state. There is 188 * no need to check for netd_stack==NULL because 189 * that implies it is no longer on this list. 190 */ 191 if (n->netd_condemned == 0) 192 continue; 193 break; 194 } 195 196 if (n == info) 197 found = B_TRUE; 198 } 199 200 if (info != NULL) 201 (void) net_protocol_release(info); 202 203 if (n != NULL) 204 atomic_add_32((uint_t *)&n->netd_refcnt, 1); 205 206 mutex_exit(&nts->nts_lock); 207 208 return (n); 209 } 210 211 /* 212 * Public accessor functions 213 */ 214 int 215 net_getifname(net_handle_t info, phy_if_t nic, char *buffer, 216 const size_t buflen) 217 { 218 219 ASSERT(info != NULL); 220 221 if (info->netd_condemned != 0 || info->netd_stack == NULL) 222 return (-1); 223 224 return (info->netd_info.netp_getifname(info, nic, buffer, buflen)); 225 } 226 227 int 228 net_getmtu(net_handle_t info, phy_if_t nic, lif_if_t ifdata) 229 { 230 231 ASSERT(info != NULL); 232 233 if (info->netd_condemned != 0 || info->netd_stack == NULL) 234 return (-1); 235 236 return (info->netd_info.netp_getmtu(info, nic, ifdata)); 237 } 238 239 int 240 net_getpmtuenabled(net_handle_t info) 241 { 242 243 ASSERT(info != NULL); 244 245 if (info->netd_condemned != 0 || info->netd_stack == NULL) 246 return (-1); 247 248 return (info->netd_info.netp_getpmtuenabled(info)); 249 } 250 251 int 252 net_getlifaddr(net_handle_t info, phy_if_t nic, lif_if_t ifdata, 253 int nelem, net_ifaddr_t type[], void *storage) 254 { 255 256 ASSERT(info != NULL); 257 258 if (info->netd_condemned != 0 || info->netd_stack == NULL) 259 return (-1); 260 261 return (info->netd_info.netp_getlifaddr(info, nic, ifdata, 262 nelem, type, storage)); 263 } 264 265 int 266 net_getlifzone(net_handle_t info, phy_if_t phy_ifdata, lif_if_t ifdata, 267 zoneid_t *zoneid) 268 { 269 ASSERT(info != NULL); 270 271 if (info->netd_condemned != 0 || info->netd_stack == NULL) 272 return (-1); 273 274 return (info->netd_info.neti_getlifzone(info, phy_ifdata, ifdata, 275 zoneid)); 276 } 277 278 int 279 net_getlifflags(net_handle_t info, phy_if_t phy_ifdata, lif_if_t ifdata, 280 uint64_t *flags) 281 { 282 ASSERT(info != NULL); 283 284 if (info->netd_condemned != 0 || info->netd_stack == NULL) 285 return (-1); 286 287 return (info->netd_info.neti_getlifflags(info, phy_ifdata, ifdata, 288 flags)); 289 } 290 291 phy_if_t 292 net_phygetnext(net_handle_t info, phy_if_t nic) 293 { 294 295 ASSERT(info != NULL); 296 297 if (info->netd_condemned != 0 || info->netd_stack == NULL) 298 return ((phy_if_t)-1); 299 300 return (info->netd_info.netp_phygetnext(info, nic)); 301 } 302 303 phy_if_t 304 net_phylookup(net_handle_t info, const char *name) 305 { 306 307 ASSERT(info != NULL); 308 309 if (info->netd_condemned != 0 || info->netd_stack == NULL) 310 return ((phy_if_t)-1); 311 312 return (info->netd_info.netp_phylookup(info, name)); 313 } 314 315 lif_if_t 316 net_lifgetnext(net_handle_t info, phy_if_t ifidx, lif_if_t ifdata) 317 { 318 319 ASSERT(info != NULL); 320 321 if (info->netd_condemned != 0 || info->netd_stack == NULL) 322 return ((lif_if_t)-1); 323 324 return (info->netd_info.netp_lifgetnext(info, ifidx, ifdata)); 325 } 326 327 int 328 net_inject(net_handle_t info, inject_t style, net_inject_t *packet) 329 { 330 331 ASSERT(info != NULL); 332 333 if (info->netd_condemned != 0 || info->netd_stack == NULL) 334 return (-1); 335 336 return (info->netd_info.netp_inject(info, style, packet)); 337 } 338 339 phy_if_t 340 net_routeto(net_handle_t info, struct sockaddr *address, struct sockaddr *next) 341 { 342 343 ASSERT(info != NULL); 344 345 if (info->netd_condemned != 0 || info->netd_stack == NULL) 346 return ((phy_if_t)-1); 347 348 return (info->netd_info.netp_routeto(info, address, next)); 349 } 350 351 int 352 net_ispartialchecksum(net_handle_t info, mblk_t *mp) 353 { 354 355 ASSERT(info != NULL); 356 ASSERT(mp != NULL); 357 358 if (info->netd_condemned != 0 || info->netd_stack == NULL) 359 return (-1); 360 361 return (info->netd_info.netp_ispartialchecksum(info, mp)); 362 } 363 364 int 365 net_isvalidchecksum(net_handle_t info, mblk_t *mp) 366 { 367 368 ASSERT(info != NULL); 369 ASSERT(mp != NULL); 370 371 if (info->netd_condemned != 0 || info->netd_stack == NULL) 372 return (-1); 373 374 return (info->netd_info.netp_isvalidchecksum(info, mp)); 375 } 376 377 /* 378 * Hooks related functions 379 */ 380 381 /* 382 * Function: net_family_register 383 * Returns: int - 0 = Succ, Else = Fail 384 * Parameters: info(I) - protocol 385 * hf(I) - family pointer 386 * 387 * Call hook_family_add to register family 388 * 389 * There is no need to bump netd_refcnt in the two functions 390 * net_family_register and net_family_unregister because the caller of these 391 * two functions is assumed to "own" a reference on 'info' via an earlier 392 * call to net_protocol_register(). Thus the owner is expected to do a 393 * call to net_protocol_unregister() after having done a 394 * net_family_unregister() to make sure things are properly cleaned up. 395 * Passing a pointer to info->netd_hooks into hook_family_add is required 396 * so that this can be set before the notify functions are called. If this 397 * does not happen, the notify function may do something that seems fine, 398 * like add a notify function to the family but cause a panic because 399 * netd_hooks is NULL when we get to hook_family_notify_register. 400 */ 401 int 402 net_family_register(net_handle_t info, hook_family_t *hf) 403 { 404 netstack_t *ns; 405 406 ASSERT(info != NULL); 407 ASSERT(hf != NULL); 408 409 if (info->netd_condemned != 0 || info->netd_stack == NULL) 410 return (ESHUTDOWN); 411 412 if (info->netd_hooks != NULL) 413 return (EEXIST); 414 415 ns = info->netd_stack->nts_netstack; 416 ASSERT(ns != NULL); 417 if (hook_family_add(hf, ns->netstack_hook, 418 (void **)&info->netd_hooks) == NULL) 419 return (EEXIST); 420 421 return (0); 422 } 423 424 /* 425 * Function: net_family_unregister 426 * Returns: int - transparent value, explained by caller 427 * Parameters: info(I) - protocol 428 * hf(I) - family pointer 429 * 430 * Call hook_family_remove to unregister family 431 */ 432 int 433 net_family_unregister(net_handle_t info, hook_family_t *hf) 434 { 435 int ret; 436 437 ASSERT(info != NULL); 438 ASSERT(hf != NULL); 439 440 if (info->netd_hooks == NULL) 441 return (ENXIO); 442 443 if (strcmp(info->netd_hooks->hfi_family.hf_name, 444 hf->hf_name) != 0) 445 return (EINVAL); 446 447 ret = hook_family_remove(info->netd_hooks); 448 if (ret == 0) 449 info->netd_hooks = NULL; 450 451 return (ret); 452 } 453 454 int 455 net_family_shutdown(net_handle_t info, hook_family_t *hf) 456 { 457 458 ASSERT(info != NULL); 459 ASSERT(hf != NULL); 460 461 if (info->netd_hooks == NULL) 462 return (ENXIO); 463 464 if (strcmp(info->netd_hooks->hfi_family.hf_name, 465 hf->hf_name) != 0) 466 return (EINVAL); 467 468 return (hook_family_shutdown(info->netd_hooks)); 469 } 470 471 /* 472 * Function: net_event_register 473 * Returns: internal event pointer - NULL = Fail 474 * Parameters: info(I) - protocol 475 * he(I) - event pointer 476 * 477 * Call hook_event_add to register event on specific family 478 * Internal event pointer is returned so caller can get 479 * handle to run hooks 480 */ 481 hook_event_token_t 482 net_event_register(net_handle_t info, hook_event_t *he) 483 { 484 hook_event_int_t *hei; 485 486 ASSERT(info != NULL); 487 ASSERT(he != NULL); 488 489 if (info->netd_hooks == NULL || info->netd_condemned != 0 || 490 info->netd_stack == NULL) 491 return (NULL); 492 493 hei = hook_event_add(info->netd_hooks, he); 494 return ((hook_event_token_t)hei); 495 } 496 497 /* 498 * Function: net_event_unregister 499 * Returns: int - transparent value, explained by caller 500 * Parameters: info(I) - protocol 501 * he(I) - event pointer 502 * 503 * Call hook_event_remove to unregister event on specific family 504 */ 505 int 506 net_event_unregister(net_handle_t info, hook_event_t *he) 507 { 508 509 ASSERT(info != NULL); 510 ASSERT(he != NULL); 511 512 if (info->netd_hooks == NULL) 513 return (ENXIO); 514 515 return (hook_event_remove(info->netd_hooks, he)); 516 } 517 518 int 519 net_event_shutdown(net_handle_t info, hook_event_t *he) 520 { 521 522 ASSERT(info != NULL); 523 ASSERT(he != NULL); 524 525 if (info->netd_hooks == NULL) 526 return (ENXIO); 527 528 return (hook_event_shutdown(info->netd_hooks, he)); 529 } 530 531 /* 532 * Function: net_hook_register 533 * Returns: int - transparent value, explained by caller 534 * Parameters: info(I) - protocol 535 * event(I) - event name 536 * h(I) - hook pointer 537 * 538 * Call hook_register to add hook on specific family/event 539 */ 540 int 541 net_hook_register(net_handle_t info, char *event, hook_t *h) 542 { 543 544 ASSERT(info != NULL); 545 ASSERT(event != NULL); 546 ASSERT(h != NULL); 547 548 if (info->netd_condemned != 0 || info->netd_stack == NULL) 549 return (ESHUTDOWN); 550 551 if (info->netd_hooks == NULL) 552 return (ENXIO); 553 554 return (hook_register(info->netd_hooks, event, h)); 555 } 556 557 /* 558 * Function: net_hook_unregister 559 * Returns: int - transparent value, explained by caller 560 * Parameters: info(I) - protocol 561 * event(I) - event name 562 * h(I) - hook pointer 563 * 564 * Call hook_unregister to remove hook on specific family/event 565 */ 566 int 567 net_hook_unregister(net_handle_t info, char *event, hook_t *h) 568 { 569 570 ASSERT(info != NULL); 571 ASSERT(event != NULL); 572 ASSERT(h != NULL); 573 574 if (info->netd_hooks == NULL) 575 return (ENXIO); 576 577 return (hook_unregister(info->netd_hooks, event, h)); 578 } 579 580 netid_t 581 net_getnetid(net_handle_t netd) 582 { 583 584 if (netd->netd_stack == NULL) 585 return (-1); 586 return (netd->netd_stack->nts_id); 587 } 588 589 net_inject_t * 590 net_inject_alloc(const int version) 591 { 592 net_inject_t *ni; 593 594 ni = kmem_zalloc(sizeof (*ni), KM_NOSLEEP); 595 if (ni == NULL) 596 return (NULL); 597 598 ni->ni_version = version; 599 return (ni); 600 } 601 602 void 603 net_inject_free(net_inject_t *ni) 604 { 605 kmem_free(ni, sizeof (*ni)); 606 } 607 608 kstat_t * 609 net_kstat_create(netid_t netid, char *module, int instance, char *name, 610 char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag) 611 { 612 netstackid_t stackid = net_getnetstackidbynetid(netid); 613 614 if (stackid == -1) 615 return (NULL); 616 617 return (kstat_create_netstack(module, instance, name, class, type, 618 ndata, ks_flag, stackid)); 619 } 620 621 void 622 net_kstat_delete(netid_t netid, kstat_t *ks) 623 { 624 netstackid_t stackid = net_getnetstackidbynetid(netid); 625 626 if (stackid != -1) 627 kstat_delete_netstack(ks, stackid); 628 } 629 630 int 631 net_event_notify_register(net_handle_t family, char *event, 632 hook_notify_fn_t callback, void *arg) 633 { 634 int error; 635 636 if (family->netd_condemned != 0 || family->netd_stack == NULL) 637 return (ESHUTDOWN); 638 639 error = hook_event_notify_register(family->netd_hooks, event, 640 callback, arg); 641 642 return (error); 643 } 644 645 int 646 net_event_notify_unregister(net_handle_t family, char *event, 647 hook_notify_fn_t callback) 648 { 649 int error; 650 651 error = hook_event_notify_unregister(family->netd_hooks, event, 652 callback); 653 654 return (error); 655 } 656 657 int 658 net_protocol_notify_register(net_handle_t family, hook_notify_fn_t callback, 659 void *arg) 660 { 661 int error; 662 663 if (family->netd_condemned != 0 || family->netd_stack == NULL) 664 return (ESHUTDOWN); 665 666 error = hook_family_notify_register(family->netd_hooks, callback, 667 arg); 668 669 return (error); 670 } 671 672 int 673 net_protocol_notify_unregister(net_handle_t family, hook_notify_fn_t callback) 674 { 675 int error; 676 677 error = hook_family_notify_unregister(family->netd_hooks, callback); 678 679 return (error); 680 } 681