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 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <sys/types.h>
29#include <sys/conf.h>
30#include <sys/modctl.h>
31#include <sys/stream.h>
32#include <sys/strsubr.h>
33#include <sys/strsun.h>
34#include <sys/zone.h>
35#include <inet/common.h>
36#include <inet/led.h>
37#include <inet/nd.h>
38#include <netinet/in.h>
39
40#include "ncaconf.h"
41
42char			_depends_on[] = "fs/sockfs drv/ip";
43
44extern caddr_t	nca_g_nd;	/* Head of 'named dispatch' variable list */
45
46#define	INET_NAME	"nca"
47#define	INET_MODSTRTAB	ncainfo
48#define	INET_DEVSTRTAB	ncainfo
49#define	INET_MODDESC	"NCA STREAMS module 1.6"
50#define	INET_DEVDESC	"NCA STREAMS driver 1.6"
51#define	INET_DEVMINOR	0
52#define	INET_DEVMTFLAGS	D_MP
53#define	INET_MODMTFLAGS	D_MP
54
55#include "../inetddi.c"
56
57/*ARGSUSED*/
58static int
59nca_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
60{
61	/* Reopen supported */
62	if (q->q_ptr != NULL)
63		return (0);
64
65	/*
66	 * NCA is not supported in non-global zones; we enforce this restriction
67	 * here.
68	 */
69	if (credp != NULL && crgetzoneid(credp) != GLOBAL_ZONEID) {
70		return (ENOTSUP);
71	}
72
73	if (! (sflag & MODOPEN)) {
74		/* Device instance */
75		RD(q)->q_ptr = (void *)B_TRUE;
76		WR(q)->q_ptr = (void *)B_TRUE;
77	} else {
78		/* Modopen just pass through */
79		RD(q)->q_ptr = (void *)B_FALSE;
80		WR(q)->q_ptr = (void *)B_FALSE;
81	}
82	qprocson(q);
83	return (0);
84}
85
86static int
87nca_close(queue_t *q)
88{
89	qprocsoff(q);
90	RD(q)->q_ptr = NULL;
91	WR(q)->q_ptr = NULL;
92	return (0);
93}
94
95static void
96nca_rput(queue_t *q, mblk_t *mp)
97{
98	/* Passthrough */
99	putnext(q, mp);
100}
101
102static void
103nca_wput(queue_t *q, mblk_t *mp)
104{
105	struct iocblk	*iocp;
106
107	if (! (boolean_t)q->q_ptr) {
108		iocp = (struct iocblk *)mp->b_rptr;
109		if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_cmd == NCA_SET_IF) {
110			miocnak(q, mp, 0, ENOTSUP);
111			return;
112		}
113		/* Module, passthrough */
114		putnext(q, mp);
115		return;
116	}
117
118	switch (DB_TYPE(mp)) {
119	case M_IOCTL:
120		iocp = (struct iocblk *)mp->b_rptr;
121		switch (iocp->ioc_cmd) {
122		case ND_SET:
123		case ND_GET:
124			if (! nd_getset(q, nca_g_nd, mp)) {
125				miocnak(q, mp, 0, ENOENT);
126				return;
127			}
128			qreply(q, mp);
129			break;
130		default:
131			miocnak(q, mp, 0, ENOTSUP);
132			break;
133		}
134		break;
135	default:
136		freemsg(mp);
137		break;
138	}
139}
140
141static struct module_info info = {
142	0, "nca", 1, INFPSZ, 65536, 1024
143};
144
145static struct qinit rinit = {
146	(pfi_t)nca_rput, NULL, nca_open, nca_close, NULL, &info
147};
148
149static struct qinit winit = {
150	(pfi_t)nca_wput, NULL, nca_open, nca_close, NULL, &info
151};
152
153struct streamtab ncainfo = {
154	&rinit, &winit
155};
156
157int
158_init(void)
159{
160	return (mod_install(&modlinkage));
161}
162
163int
164_fini(void)
165{
166	return (EBUSY);
167}
168
169int
170_info(struct modinfo *modinfop)
171{
172	return (mod_info(&modlinkage, modinfop));
173}
174