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 phy_if_t 266 net_phygetnext(net_handle_t info, phy_if_t nic) 267 { 268 269 ASSERT(info != NULL); 270 271 if (info->netd_condemned != 0 || info->netd_stack == NULL) 272 return ((phy_if_t)-1); 273 274 return (info->netd_info.netp_phygetnext(info, nic)); 275 } 276 277 phy_if_t 278 net_phylookup(net_handle_t info, const char *name) 279 { 280 281 ASSERT(info != NULL); 282 283 if (info->netd_condemned != 0 || info->netd_stack == NULL) 284 return ((phy_if_t)-1); 285 286 return (info->netd_info.netp_phylookup(info, name)); 287 } 288 289 lif_if_t 290 net_lifgetnext(net_handle_t info, phy_if_t ifidx, lif_if_t ifdata) 291 { 292 293 ASSERT(info != NULL); 294 295 if (info->netd_condemned != 0 || info->netd_stack == NULL) 296 return ((lif_if_t)-1); 297 298 return (info->netd_info.netp_lifgetnext(info, ifidx, ifdata)); 299 } 300 301 int 302 net_inject(net_handle_t info, inject_t style, net_inject_t *packet) 303 { 304 305 ASSERT(info != NULL); 306 307 if (info->netd_condemned != 0 || info->netd_stack == NULL) 308 return (-1); 309 310 return (info->netd_info.netp_inject(info, style, packet)); 311 } 312 313 phy_if_t 314 net_routeto(net_handle_t info, struct sockaddr *address, struct sockaddr *next) 315 { 316 317 ASSERT(info != NULL); 318 319 if (info->netd_condemned != 0 || info->netd_stack == NULL) 320 return ((phy_if_t)-1); 321 322 return (info->netd_info.netp_routeto(info, address, next)); 323 } 324 325 int 326 net_ispartialchecksum(net_handle_t info, mblk_t *mp) 327 { 328 329 ASSERT(info != NULL); 330 ASSERT(mp != NULL); 331 332 if (info->netd_condemned != 0 || info->netd_stack == NULL) 333 return (-1); 334 335 return (info->netd_info.netp_ispartialchecksum(info, mp)); 336 } 337 338 int 339 net_isvalidchecksum(net_handle_t info, mblk_t *mp) 340 { 341 342 ASSERT(info != NULL); 343 ASSERT(mp != NULL); 344 345 if (info->netd_condemned != 0 || info->netd_stack == NULL) 346 return (-1); 347 348 return (info->netd_info.netp_isvalidchecksum(info, mp)); 349 } 350 351 /* 352 * Hooks related functions 353 */ 354 355 /* 356 * Function: net_family_register 357 * Returns: int - 0 = Succ, Else = Fail 358 * Parameters: info(I) - protocol 359 * hf(I) - family pointer 360 * 361 * Call hook_family_add to register family 362 * 363 * There is no need to bump netd_refcnt in the two functions 364 * net_family_register and net_family_unregister because the caller of these 365 * two functions is assumed to "own" a reference on 'info' via an earlier 366 * call to net_protocol_register(). Thus the owner is expected to do a 367 * call to net_protocol_unregister() after having done a 368 * net_family_unregister() to make sure things are properly cleaned up. 369 */ 370 int 371 net_family_register(net_handle_t info, hook_family_t *hf) 372 { 373 hook_family_int_t *hfi; 374 netstack_t *ns; 375 376 ASSERT(info != NULL); 377 ASSERT(hf != NULL); 378 379 if (info->netd_condemned != 0 || info->netd_stack == NULL) 380 return (ESHUTDOWN); 381 382 if (info->netd_hooks != NULL) 383 return (EEXIST); 384 385 ns = info->netd_stack->nts_netstack; 386 ASSERT(ns != NULL); 387 hfi = hook_family_add(hf, ns->netstack_hook); 388 if (hfi == NULL) 389 return (EEXIST); 390 391 info->netd_hooks = hfi; 392 return (0); 393 } 394 395 /* 396 * Function: net_family_unregister 397 * Returns: int - transparent value, explained by caller 398 * Parameters: info(I) - protocol 399 * hf(I) - family pointer 400 * 401 * Call hook_family_remove to unregister family 402 */ 403 int 404 net_family_unregister(net_handle_t info, hook_family_t *hf) 405 { 406 int ret; 407 408 ASSERT(info != NULL); 409 ASSERT(hf != NULL); 410 411 if (info->netd_hooks == NULL) 412 return (ENXIO); 413 414 if (strcmp(info->netd_hooks->hfi_family.hf_name, 415 hf->hf_name) != 0) 416 return (EINVAL); 417 418 ret = hook_family_remove(info->netd_hooks); 419 if (ret == 0) 420 info->netd_hooks = NULL; 421 422 return (ret); 423 } 424 425 int 426 net_family_shutdown(net_handle_t info, hook_family_t *hf) 427 { 428 429 ASSERT(info != NULL); 430 ASSERT(hf != NULL); 431 432 if (info->netd_hooks == NULL) 433 return (ENXIO); 434 435 if (strcmp(info->netd_hooks->hfi_family.hf_name, 436 hf->hf_name) != 0) 437 return (EINVAL); 438 439 return (hook_family_shutdown(info->netd_hooks)); 440 } 441 442 /* 443 * Function: net_event_register 444 * Returns: internal event pointer - NULL = Fail 445 * Parameters: info(I) - protocol 446 * he(I) - event pointer 447 * 448 * Call hook_event_add to register event on specific family 449 * Internal event pointer is returned so caller can get 450 * handle to run hooks 451 */ 452 hook_event_token_t 453 net_event_register(net_handle_t info, hook_event_t *he) 454 { 455 hook_event_int_t *hei; 456 457 ASSERT(info != NULL); 458 ASSERT(he != NULL); 459 460 if (info->netd_hooks == NULL || info->netd_condemned != 0 || 461 info->netd_stack == NULL) 462 return (NULL); 463 464 hei = hook_event_add(info->netd_hooks, he); 465 return ((hook_event_token_t)hei); 466 } 467 468 /* 469 * Function: net_event_unregister 470 * Returns: int - transparent value, explained by caller 471 * Parameters: info(I) - protocol 472 * he(I) - event pointer 473 * 474 * Call hook_event_remove to unregister event on specific family 475 */ 476 int 477 net_event_unregister(net_handle_t info, hook_event_t *he) 478 { 479 480 ASSERT(info != NULL); 481 ASSERT(he != NULL); 482 483 if (info->netd_hooks == NULL) 484 return (ENXIO); 485 486 return (hook_event_remove(info->netd_hooks, he)); 487 } 488 489 int 490 net_event_shutdown(net_handle_t info, hook_event_t *he) 491 { 492 493 ASSERT(info != NULL); 494 ASSERT(he != NULL); 495 496 if (info->netd_hooks == NULL) 497 return (ENXIO); 498 499 return (hook_event_shutdown(info->netd_hooks, he)); 500 } 501 502 /* 503 * Function: net_hook_register 504 * Returns: int - transparent value, explained by caller 505 * Parameters: info(I) - protocol 506 * event(I) - event name 507 * h(I) - hook pointer 508 * 509 * Call hook_register to add hook on specific family/event 510 */ 511 int 512 net_hook_register(net_handle_t info, char *event, hook_t *h) 513 { 514 515 ASSERT(info != NULL); 516 ASSERT(event != NULL); 517 ASSERT(h != NULL); 518 519 if (info->netd_condemned != 0 || info->netd_stack == NULL) 520 return (ESHUTDOWN); 521 522 if (info->netd_hooks == NULL) 523 return (ENXIO); 524 525 return (hook_register(info->netd_hooks, event, h)); 526 } 527 528 /* 529 * Function: net_hook_unregister 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_unregister to remove hook on specific family/event 536 */ 537 int 538 net_hook_unregister(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_hooks == NULL) 546 return (ENXIO); 547 548 return (hook_unregister(info->netd_hooks, event, h)); 549 } 550 551 netid_t 552 net_getnetid(net_handle_t netd) 553 { 554 555 if (netd->netd_stack == NULL) 556 return (-1); 557 return (netd->netd_stack->nts_id); 558 } 559 560 net_inject_t * 561 net_inject_alloc(const int version) 562 { 563 net_inject_t *ni; 564 565 ni = kmem_zalloc(sizeof (*ni), KM_NOSLEEP); 566 if (ni == NULL) 567 return (NULL); 568 569 ni->ni_version = version; 570 return (ni); 571 } 572 573 void 574 net_inject_free(net_inject_t *ni) 575 { 576 kmem_free(ni, sizeof (*ni)); 577 } 578 579 kstat_t * 580 net_kstat_create(netid_t netid, char *module, int instance, char *name, 581 char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag) 582 { 583 netstackid_t stackid = net_getnetstackidbynetid(netid); 584 585 if (stackid == -1) 586 return (NULL); 587 588 return (kstat_create_netstack(module, instance, name, class, type, 589 ndata, ks_flag, stackid)); 590 } 591 592 void 593 net_kstat_delete(netid_t netid, kstat_t *ks) 594 { 595 netstackid_t stackid = net_getnetstackidbynetid(netid); 596 597 if (stackid != -1) 598 kstat_delete_netstack(ks, stackid); 599 } 600 601 int 602 net_event_notify_register(net_handle_t family, char *event, 603 hook_notify_fn_t callback, void *arg) 604 { 605 int error; 606 607 if (family->netd_condemned != 0 || family->netd_stack == NULL) 608 return (ESHUTDOWN); 609 610 error = hook_event_notify_register(family->netd_hooks, event, 611 callback, arg); 612 613 return (error); 614 } 615 616 int 617 net_event_notify_unregister(net_handle_t family, char *event, 618 hook_notify_fn_t callback) 619 { 620 int error; 621 622 error = hook_event_notify_unregister(family->netd_hooks, event, 623 callback); 624 625 return (error); 626 } 627 628 int 629 net_protocol_notify_register(net_handle_t family, hook_notify_fn_t callback, 630 void *arg) 631 { 632 int error; 633 634 if (family->netd_condemned != 0 || family->netd_stack == NULL) 635 return (ESHUTDOWN); 636 637 error = hook_family_notify_register(family->netd_hooks, callback, 638 arg); 639 640 return (error); 641 } 642 643 int 644 net_protocol_notify_unregister(net_handle_t family, hook_notify_fn_t callback) 645 { 646 int error; 647 648 error = hook_family_notify_unregister(family->netd_hooks, callback); 649 650 return (error); 651 } 652