summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/inet/inetddi.c
blob: e6a0395ba0a5d0fa2443dde0e7431b8f68c5a6ef (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
/*
 * 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 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#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.
 *	INET_STRTAB	 The name of the `streamtab' structure.
 *
 * The symbols that all modules must define are:
 *
 *	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_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 then call INET_BECOME_IP() in their _init(9E) routine.
 */

#if	!defined(INET_STRTAB)
#error inetddi.c: INET_STRTAB is not defined!
#elif	!defined(INET_NAME)
#error inetddi.c: INET_NAME is not defined!
#elif	!defined(INET_DEVDESC) && !defined(INET_MODDESC)
#error inetddi.c: at least one of INET_DEVDESC or INET_MODDESC must be defined!
#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_MODMTFLAGS)
#error inetddi.c: INET_MODDESC is defined but INET_MODMTFLAGS is not!
#endif

extern struct streamtab INET_STRTAB, ipinfo;

#ifdef	INET_DEVDESC

/*
 * This macro is intended to be called from the _init() routine of drivers
 * that actually want to be IP.  Yes, this is a disgusting, vile hack.
 */
#define	INET_BECOME_IP()	(cb_inet_devops.cb_str = &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_STRTAB);

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

#endif /* INET_DEVDESC */

#ifdef	INET_MODDESC
static struct fmodsw fsw = {
	INET_NAME,
	&INET_STRTAB,
	INET_MODMTFLAGS
};

static struct modlstrmod modlstrmod = {
	&mod_strmodops,
	INET_MODDESC,
	&fsw
};
#endif /* INET_MODDESC */

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