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 /* 426 * Function: net_event_register 427 * Returns: internal event pointer - NULL = Fail 428 * Parameters: info(I) - protocol 429 * he(I) - event pointer 430 * 431 * Call hook_event_add to register event on specific family 432 * Internal event pointer is returned so caller can get 433 * handle to run hooks 434 */ 435 hook_event_token_t 436 net_event_register(net_handle_t info, hook_event_t *he) 437 { 438 hook_event_int_t *hei; 439 440 ASSERT(info != NULL); 441 ASSERT(he != NULL); 442 443 if (info->netd_hooks == NULL || info->netd_condemned != 0 || 444 info->netd_stack == NULL) 445 return (NULL); 446 447 hei = hook_event_add(info->netd_hooks, he); 448 return ((hook_event_token_t)hei); 449 } 450 451 /* 452 * Function: net_event_unregister 453 * Returns: int - transparent value, explained by caller 454 * Parameters: info(I) - protocol 455 * he(I) - event pointer 456 * 457 * Call hook_event_remove to unregister event on specific family 458 */ 459 int 460 net_event_unregister(net_handle_t info, hook_event_t *he) 461 { 462 463 ASSERT(info != NULL); 464 ASSERT(he != NULL); 465 466 if (info->netd_hooks == NULL) 467 return (ENXIO); 468 469 return (hook_event_remove(info->netd_hooks, he)); 470 } 471 472 /* 473 * Function: net_hook_register 474 * Returns: int - transparent value, explained by caller 475 * Parameters: info(I) - protocol 476 * event(I) - event name 477 * h(I) - hook pointer 478 * 479 * Call hook_register to add hook on specific family/event 480 */ 481 int 482 net_hook_register(net_handle_t info, char *event, hook_t *h) 483 { 484 485 ASSERT(info != NULL); 486 ASSERT(event != NULL); 487 ASSERT(h != NULL); 488 489 if (info->netd_condemned != 0 || info->netd_stack == NULL) 490 return (ESHUTDOWN); 491 492 if (info->netd_hooks == NULL) 493 return (ENXIO); 494 495 return (hook_register(info->netd_hooks, event, h)); 496 } 497 498 /* 499 * Function: net_hook_unregister 500 * Returns: int - transparent value, explained by caller 501 * Parameters: info(I) - protocol 502 * event(I) - event name 503 * h(I) - hook pointer 504 * 505 * Call hook_unregister to remove hook on specific family/event 506 */ 507 int 508 net_hook_unregister(net_handle_t info, char *event, hook_t *h) 509 { 510 511 ASSERT(info != NULL); 512 ASSERT(event != NULL); 513 ASSERT(h != NULL); 514 515 if (info->netd_hooks == NULL) 516 return (ENXIO); 517 518 return (hook_unregister(info->netd_hooks, event, h)); 519 } 520 521 netid_t 522 net_getnetid(net_handle_t netd) 523 { 524 525 if (netd->netd_stack == NULL) 526 return (-1); 527 return (netd->netd_stack->nts_id); 528 } 529 530 net_inject_t * 531 net_inject_alloc(const int version) 532 { 533 net_inject_t *ni; 534 535 ni = kmem_zalloc(sizeof (*ni), KM_NOSLEEP); 536 if (ni == NULL) 537 return (NULL); 538 539 ni->ni_version = version; 540 return (ni); 541 } 542 543 void 544 net_inject_free(net_inject_t *ni) 545 { 546 kmem_free(ni, sizeof (*ni)); 547 } 548 549 kstat_t * 550 net_kstat_create(netid_t netid, char *module, int instance, char *name, 551 char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag) 552 { 553 netstackid_t stackid = net_getnetstackidbynetid(netid); 554 555 if (stackid == -1) 556 return (NULL); 557 558 return (kstat_create_netstack(module, instance, name, class, type, 559 ndata, ks_flag, stackid)); 560 } 561 562 void 563 net_kstat_delete(netid_t netid, kstat_t *ks) 564 { 565 netstackid_t stackid = net_getnetstackidbynetid(netid); 566 567 if (stackid != -1) 568 kstat_delete_netstack(ks, stackid); 569 } 570 571 int 572 net_event_notify_register(net_handle_t family, char *event, 573 hook_notify_fn_t callback, void *arg) 574 { 575 int error; 576 577 if (family->netd_condemned != 0 || family->netd_stack == NULL) 578 return (ESHUTDOWN); 579 580 error = hook_event_notify_register(family->netd_hooks, event, 581 callback, arg); 582 583 return (error); 584 } 585 586 int 587 net_event_notify_unregister(net_handle_t family, char *event, 588 hook_notify_fn_t callback) 589 { 590 int error; 591 592 error = hook_event_notify_unregister(family->netd_hooks, event, 593 callback); 594 595 return (error); 596 } 597 598 int 599 net_protocol_notify_register(net_handle_t family, hook_notify_fn_t callback, 600 void *arg) 601 { 602 int error; 603 604 if (family->netd_condemned != 0 || family->netd_stack == NULL) 605 return (ESHUTDOWN); 606 607 error = hook_family_notify_register(family->netd_hooks, callback, 608 arg); 609 610 return (error); 611 } 612 613 int 614 net_protocol_notify_unregister(net_handle_t family, hook_notify_fn_t callback) 615 { 616 int error; 617 618 error = hook_family_notify_unregister(family->netd_hooks, callback); 619 620 return (error); 621 } 622