Home | History | Annotate | Download | only in io
      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