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