summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/inet/inetddi.c
blob: a64bf7e978e3b915940c08887359a9e8d745b99b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stream.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/priv_names.h>

/*
 * This file contains generic goo needed to hook the STREAMS modules and
 * drivers that live under uts/common/inet into the DDI.  In order to use it,
 * each module/driver should #define the symbols below (as appropriate) and
 * then #include this source file; see the other uts/common/inet/<star>ddi.c
 * files for examples of this in action.
 *
 * The symbols that all modules and drivers must define are:
 *
 *	INET_NAME	 The name of the module/driver.
 *
 * The symbols that all modules must define are:
 *
 *	INET_MODSTRTAB	 The name of the `streamtab' structure for this module.
 *	INET_MODDESC	 The one-line description for this module.
 *	INET_MODMTFLAGS  The mt-streams(9F) flags for the module.
 *
 * The symbols that all drivers must define are:
 *
 *	INET_DEVSTRTAB	 The name of the `streamtab' structure for this driver.
 *	INET_DEVDESC	 The one-line description for this driver.
 *	INET_DEVMTFLAGS  The mt-streams(9F) flags for the driver.
 *	INET_DEVMINOR	 The minor number of the driver (usually 0).
 *
 * Drivers that need to masquerade as IP should set INET_DEVMTFLAGS to
 * IP_DEVMTFLAGS and set INET_DEVSTRTAB to ipinfo.
 *
 * The symbols that all socket modules must define are:
 *
 *	INET_SOCKDESC	The one-line description for this socket module
 *	INET_SOCK_PROTO_CREATE_FUNC The function used to create PCBs
 *
 * In addition, socket modules that can be converted to TPI must define:
 *
 *	INET_SOCK_PROTO_FB_FUNC The function used to fallback to TPI
 */

#if	!defined(INET_NAME)
#error inetddi.c: INET_NAME is not defined!
#elif	!defined(INET_DEVDESC) && !defined(INET_MODDESC) && \
	!defined(INET_SOCKDESC)
#error inetddi.c: at least one of INET_DEVDESC or INET_MODDESC or \
INET_SOCKDESC must be defined!
#elif	defined(INET_DEVDESC) && !defined(INET_DEVSTRTAB)
#error inetddi.c: INET_DEVDESC is defined but INET_DEVSTRTAB is not!
#elif	defined(INET_DEVDESC) && !defined(INET_DEVMTFLAGS)
#error inetddi.c: INET_DEVDESC is defined but INET_DEVMTFLAGS is not!
#elif	defined(INET_DEVDESC) && !defined(INET_DEVMINOR)
#error inetddi.c: INET_DEVDESC is defined but INET_DEVMINOR is not!
#elif	defined(INET_MODDESC) && !defined(INET_MODSTRTAB)
#error inetddi.c: INET_MODDESC is defined but INET_MODSTRTAB is not!
#elif	defined(INET_MODDESC) && !defined(INET_MODMTFLAGS)
#error inetddi.c: INET_MODDESC is defined but INET_MODMTFLAGS is not!
#elif	defined(INET_SOCKDESC) && !defined(SOCKMOD_VERSION)
#error  inetddi.c: INET_SOCKDESC is defined but SOCKMOD_VERSION is not!
#elif	defined(INET_SOCKDESC) && !defined(INET_SOCK_PROTO_CREATE_FUNC)
#error  inetddi.c: INET_SOCKDESC is defined but INET_SOCK_PROTO_CREATE_FUNC \
is not!
#elif	defined(INET_SOCK_PROTO_FB_FUNC) && !defined(INET_SOCK_FALLBACK_DEV_V4)
#error	inetddi.c: INET_SOCK_PROTO_FB_FUNC is defined but \
INET_SOCK_FALLBACK_DEV_V4 is not!
#elif	defined(INET_SOCK_PROTO_FB_FUNC) && !defined(INET_SOCK_FALLBACK_DEV_V6)
#error	inetddi.c: INET_SOCK_PROTO_FB_FUNC is defined but \
INET_SOCK_FALLBACK_DEV_V6 is not!
#endif

#ifdef	INET_DEVDESC

extern struct streamtab INET_DEVSTRTAB;

/*
 * Drivers that actually want to be IP would set INET_DEVSTRTAB to ipinfo.
 */

static dev_info_t *inet_dev_info;

#define	INET_DEFAULT_PRIV_MODE	0666

static struct dev_priv {
	char *driver;
	int privonly;
	const char *read_priv;
	const char *write_priv;
} netdev_privs[] = {
	{"icmp", PRIVONLY_DEV,	PRIV_NET_ICMPACCESS,	PRIV_NET_ICMPACCESS},
	{"icmp6", PRIVONLY_DEV,	PRIV_NET_ICMPACCESS,	PRIV_NET_ICMPACCESS},
	{"ip", PRIVONLY_DEV,	PRIV_NET_RAWACCESS,	PRIV_NET_RAWACCESS},
	{"ip6", PRIVONLY_DEV,	PRIV_NET_RAWACCESS,	PRIV_NET_RAWACCESS},
	{"keysock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
	{"ipsecah", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
	{"ipsecesp", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
	{"spdsock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
	{NULL,	0,		NULL,			NULL}
};

static int
inet_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	int i, ndevs;

	if (cmd != DDI_ATTACH)
		return (DDI_FAILURE);

	inet_dev_info = devi;

	ndevs = sizeof (netdev_privs) / sizeof (struct dev_priv);
	for (i = 0; i < ndevs; i++) {
		char *drv = netdev_privs[i].driver;
		if (drv == NULL || strcmp(drv, ddi_driver_name(devi)) == 0)
			break;
	}

	return (ddi_create_priv_minor_node(devi, INET_NAME, S_IFCHR,
	    INET_DEVMINOR, DDI_PSEUDO, netdev_privs[i].privonly,
	    netdev_privs[i].read_priv, netdev_privs[i].write_priv,
	    INET_DEFAULT_PRIV_MODE));
}

static int
inet_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
{
	if (cmd != DDI_DETACH)
		return (DDI_FAILURE);

	ASSERT(devi == inet_dev_info);

	ddi_remove_minor_node(devi, NULL);
	return (DDI_SUCCESS);
}


/* ARGSUSED */
static int
inet_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
{
	int error = DDI_FAILURE;

	switch (cmd) {
	case DDI_INFO_DEVT2DEVINFO:
		if (inet_dev_info != NULL) {
			*result = (void *)inet_dev_info;
			error = DDI_SUCCESS;
		}
		break;

	case DDI_INFO_DEVT2INSTANCE:
		*result = NULL;
		error = DDI_SUCCESS;
		break;

	default:
		break;
	}

	return (error);
}

DDI_DEFINE_STREAM_OPS(inet_devops, nulldev, nulldev, inet_attach, inet_detach,
    nulldev, inet_info, INET_DEVMTFLAGS, &INET_DEVSTRTAB,
    ddi_quiesce_not_supported);

static struct modldrv modldrv = {
	&mod_driverops,
	INET_DEVDESC,
	&inet_devops
};

#endif /* INET_DEVDESC */

#ifdef	INET_MODDESC
extern struct streamtab INET_MODSTRTAB;

static struct fmodsw fsw = {
	INET_NAME,
	&INET_MODSTRTAB,
	INET_MODMTFLAGS
};

static struct modlstrmod modlstrmod = {
	&mod_strmodops,
	INET_MODDESC,
	&fsw
};

#endif /* INET_MODDESC */

#ifdef  INET_SOCKDESC

#ifdef	INET_SOCK_PROTO_FB_FUNC
static __smod_priv_t smodpriv = {
	NULL,
	NULL,
	INET_SOCK_PROTO_FB_FUNC,
	INET_SOCK_FALLBACK_DEV_V4,
	INET_SOCK_FALLBACK_DEV_V6
};
#endif	/* INET_SOCK_PROTO_FB_FUNC */

static struct smod_reg_s smodreg = {
	SOCKMOD_VERSION,
	INET_NAME,
	SOCK_UC_VERSION,
	SOCK_DC_VERSION,
	INET_SOCK_PROTO_CREATE_FUNC,
#ifdef	INET_SOCK_PROTO_FB_FUNC
	&smodpriv
#else
	NULL
#endif	/* INET_SOCK_PROTO_FB_FUNC */
};

static struct modlsockmod modlsockmod = {
	&mod_sockmodops,
	INET_SOCKDESC,
	&smodreg
};
#endif	/* INET_SOCKDESC */

static struct modlinkage modlinkage = {
	MODREV_1,
#ifdef	INET_DEVDESC
	&modldrv,
#endif
#ifdef	INET_MODDESC
	&modlstrmod,
#endif
#ifdef	INET_SOCKDESC
	&modlsockmod,
#endif
	NULL
};