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 hook_family_int_t *hfi; 405 netstack_t *ns; 406 407 ASSERT(info != NULL); 408 ASSERT(hf != NULL); 409 410 if (info->netd_condemned != 0 || info->netd_stack == NULL) 411 return (ESHUTDOWN); 412 413 if (info->netd_hooks != NULL) 414 return (EEXIST); 415 416 ns = info->netd_stack->nts_netstack; 417 ASSERT(ns != NULL); 418 if (hook_family_add(hf, ns->netstack_hook, 419 (void **)&info->netd_hooks) == NULL) 420 return (EEXIST); 421 422 return (0); 423 } 424 425 /* 426 * Function: net_family_unregister 427 * Returns: int - transparent value, explained by caller 428 * Parameters: info(I) - protocol 429 * hf(I) - family pointer 430 * 431 * Call hook_family_remove to unregister family 432 */ 433 int 434 net_family_unregister(net_handle_t info, hook_family_t *hf) 435 { 436 int ret; 437 438 ASSERT(info != NULL); 439 ASSERT(hf != NULL); 440 441 if (info->netd_hooks == NULL) 442 return (ENXIO); 443 444 if (strcmp(info->netd_hooks->hfi_family.hf_name, 445 hf->hf_name) != 0) 446 return (EINVAL); 447 448 ret = hook_family_remove(info->netd_hooks); 449 if (ret == 0) 450 info->netd_hooks = NULL; 451 452 return (ret); 453 } 454 455 int 456 net_family_shutdown(net_handle_t info, hook_family_t *hf) 457 { 458 459 ASSERT(info != NULL); 460 ASSERT(hf != NULL); 461 462 if (info->netd_hooks == NULL) 463 return (ENXIO); 464 465 if (strcmp(info->netd_hooks->hfi_family.hf_name, 466 hf->hf_name) != 0) 467 return (EINVAL); 468 469 return (hook_family_shutdown(info->netd_hooks)); 470 } 471 472 /* 473 * Function: net_event_register 474 * Returns: internal event pointer - NULL = Fail 475 * Parameters: info(I) - protocol 476 * he(I) - event pointer 477 * 478 * Call hook_event_add to register event on specific family 479 * Internal event pointer is returned so caller can get 480 * handle to run hooks 481 */ 482 hook_event_token_t 483 net_event_register(net_handle_t info, hook_event_t *he) 484 { 485 hook_event_int_t *hei; 486 487 ASSERT(info != NULL); 488 ASSERT(he != NULL); 489 490 if (info->netd_hooks == NULL || info->netd_condemned != 0 || 491 info->netd_stack == NULL) 492 return (NULL); 493 494 hei = hook_event_add(info->netd_hooks, he); 495 return ((hook_event_token_t)hei); 496 } 497 498 /* 499 * Function: net_event_unregister 500 * Returns: int - transparent value, explained by caller 501 * Parameters: info(I) - protocol 502 * he(I) - event pointer 503 * 504 * Call hook_event_remove to unregister event on specific family 505 */ 506 int 507 net_event_unregister(net_handle_t info, hook_event_t *he) 508 { 509 510 ASSERT(info != NULL); 511 ASSERT(he != NULL); 512 513 if (info->netd_hooks == NULL) 514 return (ENXIO); 515 516 return (hook_event_remove(info->netd_hooks, he)); 517 } 518 519 int 520 net_event_shutdown(net_handle_t info, hook_event_t *he) 521 { 522 523 ASSERT(info != NULL); 524 ASSERT(he != NULL); 525 526 if (info->netd_hooks == NULL) 527 return (ENXIO); 528 529 return (hook_event_shutdown(info->netd_hooks, he)); 530 } 531 532 /* 533 * Function: net_hook_register 534 * Returns: int - transparent value, explained by caller 535 * Parameters: info(I) - protocol 536 * event(I) - event name 537 * h(I) - hook pointer 538 * 539 * Call hook_register to add hook on specific family/event 540 */ 541 int 542 net_hook_register(net_handle_t info, char *event, hook_t *h) 543 { 544 545 ASSERT(info != NULL); 546 ASSERT(event != NULL); 547 ASSERT(h != NULL); 548 549 if (info->netd_condemned != 0 || info->netd_stack == NULL) 550 return (ESHUTDOWN); 551 552 if (info->netd_hooks == NULL) 553 return (ENXIO); 554 555 return (hook_register(info->netd_hooks, event, h)); 556 } 557 558 /* 559 * Function: net_hook_unregister 560 * Returns: int - transparent value, explained by caller 561 * Parameters: info(I) - protocol 562 * event(I) - event name 563 * h(I) - hook pointer 564 * 565 * Call hook_unregister to remove hook on specific family/event 566 */ 567 int 568 net_hook_unregister(net_handle_t info, char *event, hook_t *h) 569 { 570 571 ASSERT(info != NULL); 572 ASSERT(event != NULL); 573 ASSERT(h != NULL); 574 575 if (info->netd_hooks == NULL) 576 return (ENXIO); 577 578 return (hook_unregister(info->netd_hooks, event, h)); 579 } 580 581 netid_t 582 net_getnetid(net_handle_t netd) 583 { 584 585 if (netd->netd_stack == NULL) 586 return (-1); 587 return (netd->netd_stack->nts_id); 588 } 589 590 net_inject_t * 591 net_inject_alloc(const int version) 592 { 593 net_inject_t *ni; 594 595 ni = kmem_zalloc(sizeof (*ni), KM_NOSLEEP); 596 if (ni == NULL) 597 return (NULL); 598 599 ni->ni_version = version; 600 return (ni); 601 } 602 603 void 604 net_inject_free(net_inject_t *ni) 605 { 606 kmem_free(ni, sizeof (*ni)); 607 } 608 609 kstat_t * 610 net_kstat_create(netid_t netid, char *module, int instance, char *name, 611 char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag) 612 { 613 netstackid_t stackid = net_getnetstackidbynetid(netid); 614 615 if (stackid == -1) 616 return (NULL); 617 618 return (kstat_create_netstack(module, instance, name, class, type, 619 ndata, ks_flag, stackid)); 620 } 621 622 void 623 net_kstat_delete(netid_t netid, kstat_t *ks) 624 { 625 netstackid_t stackid = net_getnetstackidbynetid(netid); 626 627 if (stackid != -1) 628 kstat_delete_netstack(ks, stackid); 629 } 630 631 int 632 net_event_notify_register(net_handle_t family, char *event, 633 hook_notify_fn_t callback, void *arg) 634 { 635 int error; 636 637 if (family->netd_condemned != 0 || family->netd_stack == NULL) 638 return (ESHUTDOWN); 639 640 error = hook_event_notify_register(family->netd_hooks, event, 641 callback, arg); 642 643 return (error); 644 } 645 646 int 647 net_event_notify_unregister(net_handle_t family, char *event, 648 hook_notify_fn_t callback) 649 { 650 int error; 651 652 error = hook_event_notify_unregister(family->netd_hooks, event, 653 callback); 654 655 return (error); 656 } 657 658 int 659 net_protocol_notify_register(net_handle_t family, hook_notify_fn_t callback, 660 void *arg) 661 { 662 int error; 663 664 if (family->netd_condemned != 0 || family->netd_stack == NULL) 665 return (ESHUTDOWN); 666 667 error = hook_family_notify_register(family->netd_hooks, callback, 668 arg); 669 670 return (error); 671 } 672 673 int 674 net_protocol_notify_unregister(net_handle_t family, hook_notify_fn_t callback) 675 { 676 int error; 677 678 error = hook_family_notify_unregister(family->netd_hooks, callback); 679 680 return (error); 681 } 682