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