xref: /minix3/minix/servers/vfs/smap.c (revision e3b8d4bb58a799dc7fd563ac39bf3015762af03b)
1*e3b8d4bbSDavid van Moolenbroek /*
2*e3b8d4bbSDavid van Moolenbroek  * This file contains the table with socket driver mappings.  One socket driver
3*e3b8d4bbSDavid van Moolenbroek  * may implement multiple domains (e.g., PF_INET and PF_INET6).  For this
4*e3b8d4bbSDavid van Moolenbroek  * reason, we assign a unique number to each socket driver, and use a "socket
5*e3b8d4bbSDavid van Moolenbroek  * device map" table (smap) that maps from those numbers to information about
6*e3b8d4bbSDavid van Moolenbroek  * socket drivers.  This number is combined with a per-driver socket identifier
7*e3b8d4bbSDavid van Moolenbroek  * to form a globally unique socket ID (64-bit, stored as dev_t).  In addition,
8*e3b8d4bbSDavid van Moolenbroek  * we use a table that maps from PF_xxx domains to socket drivers (pfmap).
9*e3b8d4bbSDavid van Moolenbroek  */
10*e3b8d4bbSDavid van Moolenbroek 
11*e3b8d4bbSDavid van Moolenbroek #include "fs.h"
12*e3b8d4bbSDavid van Moolenbroek #include <sys/socket.h>
13*e3b8d4bbSDavid van Moolenbroek #include <assert.h>
14*e3b8d4bbSDavid van Moolenbroek 
15*e3b8d4bbSDavid van Moolenbroek static struct smap smap[NR_SOCKDEVS];
16*e3b8d4bbSDavid van Moolenbroek static struct smap *pfmap[PF_MAX];
17*e3b8d4bbSDavid van Moolenbroek 
18*e3b8d4bbSDavid van Moolenbroek /*
19*e3b8d4bbSDavid van Moolenbroek  * Initialize the socket device map table.
20*e3b8d4bbSDavid van Moolenbroek  */
21*e3b8d4bbSDavid van Moolenbroek void
init_smap(void)22*e3b8d4bbSDavid van Moolenbroek init_smap(void)
23*e3b8d4bbSDavid van Moolenbroek {
24*e3b8d4bbSDavid van Moolenbroek 	unsigned int i;
25*e3b8d4bbSDavid van Moolenbroek 
26*e3b8d4bbSDavid van Moolenbroek 	for (i = 0; i < __arraycount(smap); i++) {
27*e3b8d4bbSDavid van Moolenbroek 		/*
28*e3b8d4bbSDavid van Moolenbroek 		 * The smap numbers are one-based so as to ensure that no
29*e3b8d4bbSDavid van Moolenbroek 		 * socket will have the device number NO_DEV, which would
30*e3b8d4bbSDavid van Moolenbroek 		 * create problems with eg the select code.
31*e3b8d4bbSDavid van Moolenbroek 		 */
32*e3b8d4bbSDavid van Moolenbroek 		smap[i].smap_num = i + 1;
33*e3b8d4bbSDavid van Moolenbroek 		smap[i].smap_endpt = NONE;
34*e3b8d4bbSDavid van Moolenbroek 	}
35*e3b8d4bbSDavid van Moolenbroek 
36*e3b8d4bbSDavid van Moolenbroek 	memset(pfmap, 0, sizeof(pfmap));
37*e3b8d4bbSDavid van Moolenbroek }
38*e3b8d4bbSDavid van Moolenbroek 
39*e3b8d4bbSDavid van Moolenbroek /*
40*e3b8d4bbSDavid van Moolenbroek  * Register a socket driver.  This action can only be requested by RS.  The
41*e3b8d4bbSDavid van Moolenbroek  * process identified by the given DS label 'label' and endpoint 'endpt' is to
42*e3b8d4bbSDavid van Moolenbroek  * be responsible for sockets created in the domains as given in the 'domains'
43*e3b8d4bbSDavid van Moolenbroek  * array, which contains 'ndomains' elements.  Return OK upon successful
44*e3b8d4bbSDavid van Moolenbroek  * registration, or an error code otherwise.
45*e3b8d4bbSDavid van Moolenbroek  */
46*e3b8d4bbSDavid van Moolenbroek int
smap_map(const char * label,endpoint_t endpt,const int * domains,unsigned int ndomains)47*e3b8d4bbSDavid van Moolenbroek smap_map(const char * label, endpoint_t endpt, const int * domains,
48*e3b8d4bbSDavid van Moolenbroek 	unsigned int ndomains)
49*e3b8d4bbSDavid van Moolenbroek {
50*e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
51*e3b8d4bbSDavid van Moolenbroek 	unsigned int i, num = 0;
52*e3b8d4bbSDavid van Moolenbroek 	int domain;
53*e3b8d4bbSDavid van Moolenbroek 
54*e3b8d4bbSDavid van Moolenbroek 	if (ndomains <= 0 || ndomains > NR_DOMAIN)
55*e3b8d4bbSDavid van Moolenbroek 		return EINVAL;
56*e3b8d4bbSDavid van Moolenbroek 
57*e3b8d4bbSDavid van Moolenbroek 	/*
58*e3b8d4bbSDavid van Moolenbroek 	 * See if there is already a socket device map entry for this label.
59*e3b8d4bbSDavid van Moolenbroek 	 * If so, the socket driver is probably being restarted, and we should
60*e3b8d4bbSDavid van Moolenbroek 	 * overwrite its previous entry.
61*e3b8d4bbSDavid van Moolenbroek 	 */
62*e3b8d4bbSDavid van Moolenbroek 	sp = NULL;
63*e3b8d4bbSDavid van Moolenbroek 	for (i = 0; i < __arraycount(smap); i++) {
64*e3b8d4bbSDavid van Moolenbroek 		if (smap[i].smap_endpt != NONE &&
65*e3b8d4bbSDavid van Moolenbroek 		    !strcmp(smap[i].smap_label, label)) {
66*e3b8d4bbSDavid van Moolenbroek 			sp = &smap[i];
67*e3b8d4bbSDavid van Moolenbroek 			break;
68*e3b8d4bbSDavid van Moolenbroek 		}
69*e3b8d4bbSDavid van Moolenbroek 	}
70*e3b8d4bbSDavid van Moolenbroek 
71*e3b8d4bbSDavid van Moolenbroek 	/*
72*e3b8d4bbSDavid van Moolenbroek 	 * See if all given domains are valid and not already reserved by a
73*e3b8d4bbSDavid van Moolenbroek 	 * socket driver other than (if applicable) this driver's old instance.
74*e3b8d4bbSDavid van Moolenbroek 	 */
75*e3b8d4bbSDavid van Moolenbroek 	for (i = 0; i < ndomains; i++) {
76*e3b8d4bbSDavid van Moolenbroek 		domain = domains[i];
77*e3b8d4bbSDavid van Moolenbroek 		if (domain < 0 || domain >= __arraycount(pfmap))
78*e3b8d4bbSDavid van Moolenbroek 			return EINVAL;
79*e3b8d4bbSDavid van Moolenbroek 		if (domain == PF_UNSPEC)
80*e3b8d4bbSDavid van Moolenbroek 			return EINVAL;
81*e3b8d4bbSDavid van Moolenbroek 		if (pfmap[domain] != NULL && pfmap[domain] != sp)
82*e3b8d4bbSDavid van Moolenbroek 			return EBUSY;
83*e3b8d4bbSDavid van Moolenbroek 	}
84*e3b8d4bbSDavid van Moolenbroek 
85*e3b8d4bbSDavid van Moolenbroek 	/*
86*e3b8d4bbSDavid van Moolenbroek 	 * If we are not about to replace an existing socket device map entry,
87*e3b8d4bbSDavid van Moolenbroek 	 * find a free entry, returning an error if all entries are in use.
88*e3b8d4bbSDavid van Moolenbroek 	 */
89*e3b8d4bbSDavid van Moolenbroek 	if (sp == NULL) {
90*e3b8d4bbSDavid van Moolenbroek 		for (num = 0; num < __arraycount(smap); num++)
91*e3b8d4bbSDavid van Moolenbroek 			if (smap[num].smap_endpt == NONE)
92*e3b8d4bbSDavid van Moolenbroek 				break;
93*e3b8d4bbSDavid van Moolenbroek 
94*e3b8d4bbSDavid van Moolenbroek 		if (num == __arraycount(smap))
95*e3b8d4bbSDavid van Moolenbroek 			return ENOMEM;
96*e3b8d4bbSDavid van Moolenbroek 	} else
97*e3b8d4bbSDavid van Moolenbroek 		num = (unsigned int)(sp - smap);
98*e3b8d4bbSDavid van Moolenbroek 
99*e3b8d4bbSDavid van Moolenbroek 	/*
100*e3b8d4bbSDavid van Moolenbroek 	 * At this point, the registration will succeed, and we can start
101*e3b8d4bbSDavid van Moolenbroek 	 * modifying tables.  Just to be sure, unmap the domain mappings for
102*e3b8d4bbSDavid van Moolenbroek 	 * the old instance, in case it is somehow registered with a different
103*e3b8d4bbSDavid van Moolenbroek 	 * set of domains.  Also, if the endpoint of the service has changed,
104*e3b8d4bbSDavid van Moolenbroek 	 * cancel any operations involving the previous endpoint and invalidate
105*e3b8d4bbSDavid van Moolenbroek 	 * any preexisting sockets.  However, for stateful restarts where the
106*e3b8d4bbSDavid van Moolenbroek 	 * service endpoint does not change, leave things as is.
107*e3b8d4bbSDavid van Moolenbroek 	 */
108*e3b8d4bbSDavid van Moolenbroek 	if (sp != NULL) {
109*e3b8d4bbSDavid van Moolenbroek 		if (sp->smap_endpt != endpt) {
110*e3b8d4bbSDavid van Moolenbroek 			/*
111*e3b8d4bbSDavid van Moolenbroek 			 * For stateless restarts, it is common that the new
112*e3b8d4bbSDavid van Moolenbroek 			 * endpoint is made ready before the old endpoint is
113*e3b8d4bbSDavid van Moolenbroek 			 * exited, so we cannot wait for the exit handling code
114*e3b8d4bbSDavid van Moolenbroek 			 * to do these steps, as they rely on the old socket
115*e3b8d4bbSDavid van Moolenbroek 			 * mapping still being around.
116*e3b8d4bbSDavid van Moolenbroek 			 */
117*e3b8d4bbSDavid van Moolenbroek 			unsuspend_by_endpt(sp->smap_endpt);
118*e3b8d4bbSDavid van Moolenbroek 
119*e3b8d4bbSDavid van Moolenbroek 			invalidate_filp_by_sock_drv(sp->smap_num);
120*e3b8d4bbSDavid van Moolenbroek 		}
121*e3b8d4bbSDavid van Moolenbroek 
122*e3b8d4bbSDavid van Moolenbroek 		for (i = 0; i < __arraycount(pfmap); i++)
123*e3b8d4bbSDavid van Moolenbroek 			if (pfmap[i] == sp)
124*e3b8d4bbSDavid van Moolenbroek 				pfmap[i] = NULL;
125*e3b8d4bbSDavid van Moolenbroek 	}
126*e3b8d4bbSDavid van Moolenbroek 
127*e3b8d4bbSDavid van Moolenbroek 	/*
128*e3b8d4bbSDavid van Moolenbroek 	 * Initialize the socket driver map entry, and set up the domain map
129*e3b8d4bbSDavid van Moolenbroek 	 * entries.
130*e3b8d4bbSDavid van Moolenbroek 	 */
131*e3b8d4bbSDavid van Moolenbroek 	sp = &smap[num];
132*e3b8d4bbSDavid van Moolenbroek 	sp->smap_endpt = endpt;
133*e3b8d4bbSDavid van Moolenbroek 	strlcpy(sp->smap_label, label, sizeof(sp->smap_label));
134*e3b8d4bbSDavid van Moolenbroek 	sp->smap_sel_busy = FALSE;
135*e3b8d4bbSDavid van Moolenbroek 	sp->smap_sel_filp = NULL;
136*e3b8d4bbSDavid van Moolenbroek 
137*e3b8d4bbSDavid van Moolenbroek 	for (i = 0; i < ndomains; i++)
138*e3b8d4bbSDavid van Moolenbroek 		pfmap[domains[i]] = sp;
139*e3b8d4bbSDavid van Moolenbroek 
140*e3b8d4bbSDavid van Moolenbroek 	return OK;
141*e3b8d4bbSDavid van Moolenbroek }
142*e3b8d4bbSDavid van Moolenbroek 
143*e3b8d4bbSDavid van Moolenbroek /*
144*e3b8d4bbSDavid van Moolenbroek  * The process with the given endpoint has exited.  If the endpoint identifies
145*e3b8d4bbSDavid van Moolenbroek  * a socket driver, deregister the driver and invalidate any sockets it owned.
146*e3b8d4bbSDavid van Moolenbroek  */
147*e3b8d4bbSDavid van Moolenbroek void
smap_unmap_by_endpt(endpoint_t endpt)148*e3b8d4bbSDavid van Moolenbroek smap_unmap_by_endpt(endpoint_t endpt)
149*e3b8d4bbSDavid van Moolenbroek {
150*e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
151*e3b8d4bbSDavid van Moolenbroek 	unsigned int i;
152*e3b8d4bbSDavid van Moolenbroek 
153*e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_endpt(endpt)) == NULL)
154*e3b8d4bbSDavid van Moolenbroek 		return;
155*e3b8d4bbSDavid van Moolenbroek 
156*e3b8d4bbSDavid van Moolenbroek 	/*
157*e3b8d4bbSDavid van Moolenbroek 	 * Invalidation requires that the smap entry still be around, so do
158*e3b8d4bbSDavid van Moolenbroek 	 * this before clearing the endpoint.
159*e3b8d4bbSDavid van Moolenbroek 	 */
160*e3b8d4bbSDavid van Moolenbroek 	invalidate_filp_by_sock_drv(sp->smap_num);
161*e3b8d4bbSDavid van Moolenbroek 
162*e3b8d4bbSDavid van Moolenbroek 	sp->smap_endpt = NONE;
163*e3b8d4bbSDavid van Moolenbroek 
164*e3b8d4bbSDavid van Moolenbroek 	for (i = 0; i < __arraycount(pfmap); i++)
165*e3b8d4bbSDavid van Moolenbroek 		if (pfmap[i] == sp)
166*e3b8d4bbSDavid van Moolenbroek 			pfmap[i] = NULL;
167*e3b8d4bbSDavid van Moolenbroek }
168*e3b8d4bbSDavid van Moolenbroek 
169*e3b8d4bbSDavid van Moolenbroek /*
170*e3b8d4bbSDavid van Moolenbroek  * The given endpoint has announced itself as a socket driver.
171*e3b8d4bbSDavid van Moolenbroek  */
172*e3b8d4bbSDavid van Moolenbroek void
smap_endpt_up(endpoint_t endpt)173*e3b8d4bbSDavid van Moolenbroek smap_endpt_up(endpoint_t endpt)
174*e3b8d4bbSDavid van Moolenbroek {
175*e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
176*e3b8d4bbSDavid van Moolenbroek 
177*e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_endpt(endpt)) == NULL)
178*e3b8d4bbSDavid van Moolenbroek 		return;
179*e3b8d4bbSDavid van Moolenbroek 
180*e3b8d4bbSDavid van Moolenbroek 	/*
181*e3b8d4bbSDavid van Moolenbroek 	 * The announcement indicates that the socket driver has either started
182*e3b8d4bbSDavid van Moolenbroek 	 * anew or restarted statelessly.  In the second case, none of its
183*e3b8d4bbSDavid van Moolenbroek 	 * previously existing sockets will have survived, so mark them as
184*e3b8d4bbSDavid van Moolenbroek 	 * invalid.
185*e3b8d4bbSDavid van Moolenbroek 	 */
186*e3b8d4bbSDavid van Moolenbroek 	invalidate_filp_by_sock_drv(sp->smap_num);
187*e3b8d4bbSDavid van Moolenbroek }
188*e3b8d4bbSDavid van Moolenbroek 
189*e3b8d4bbSDavid van Moolenbroek /*
190*e3b8d4bbSDavid van Moolenbroek  * Construct a device number that combines the entry number of the given socket
191*e3b8d4bbSDavid van Moolenbroek  * map and the given per-driver socket identifier, thus constructing a unique
192*e3b8d4bbSDavid van Moolenbroek  * identifier for the socket.  Generally speaking, we use the dev_t type
193*e3b8d4bbSDavid van Moolenbroek  * because the value is stored as special device number (sdev) on a socket node
194*e3b8d4bbSDavid van Moolenbroek  * on PFS.  We use our own bit division rather than the standard major/minor
195*e3b8d4bbSDavid van Moolenbroek  * division because this simplifies using each half as a 32-bit value.  The
196*e3b8d4bbSDavid van Moolenbroek  * block/character device numbers and socket device numbers are in different
197*e3b8d4bbSDavid van Moolenbroek  * namespaces, and numbers may overlap (even though this is currently
198*e3b8d4bbSDavid van Moolenbroek  * practically impossible), so one must always test the file type first.
199*e3b8d4bbSDavid van Moolenbroek  */
200*e3b8d4bbSDavid van Moolenbroek dev_t
make_smap_dev(struct smap * sp,sockid_t sockid)201*e3b8d4bbSDavid van Moolenbroek make_smap_dev(struct smap * sp, sockid_t sockid)
202*e3b8d4bbSDavid van Moolenbroek {
203*e3b8d4bbSDavid van Moolenbroek 
204*e3b8d4bbSDavid van Moolenbroek 	assert(sp->smap_endpt != NONE);
205*e3b8d4bbSDavid van Moolenbroek 	assert(sockid >= 0);
206*e3b8d4bbSDavid van Moolenbroek 
207*e3b8d4bbSDavid van Moolenbroek 	return (dev_t)(((uint64_t)sp->smap_num << 32) | (uint32_t)sockid);
208*e3b8d4bbSDavid van Moolenbroek }
209*e3b8d4bbSDavid van Moolenbroek 
210*e3b8d4bbSDavid van Moolenbroek /*
211*e3b8d4bbSDavid van Moolenbroek  * Return a pointer to the smap structure for the socket driver associated with
212*e3b8d4bbSDavid van Moolenbroek  * the socket device number.  In addition, if the given socket ID pointer is
213*e3b8d4bbSDavid van Moolenbroek  * not NULL, store the per-driver socket identifier in it.  Return NULL if the
214*e3b8d4bbSDavid van Moolenbroek  * given socket device number is not a socket for a valid socket driver.
215*e3b8d4bbSDavid van Moolenbroek  */
216*e3b8d4bbSDavid van Moolenbroek struct smap *
get_smap_by_dev(dev_t dev,sockid_t * sockidp)217*e3b8d4bbSDavid van Moolenbroek get_smap_by_dev(dev_t dev, sockid_t * sockidp)
218*e3b8d4bbSDavid van Moolenbroek {
219*e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
220*e3b8d4bbSDavid van Moolenbroek 	unsigned int num;
221*e3b8d4bbSDavid van Moolenbroek 	sockid_t id;
222*e3b8d4bbSDavid van Moolenbroek 
223*e3b8d4bbSDavid van Moolenbroek 	num = (unsigned int)(dev >> 32);
224*e3b8d4bbSDavid van Moolenbroek 	id = (sockid_t)(dev & ((1ULL << 32) - 1));
225*e3b8d4bbSDavid van Moolenbroek 	if (num == 0 || num > __arraycount(smap) || id < 0)
226*e3b8d4bbSDavid van Moolenbroek 		return NULL;
227*e3b8d4bbSDavid van Moolenbroek 
228*e3b8d4bbSDavid van Moolenbroek 	sp = &smap[num - 1];
229*e3b8d4bbSDavid van Moolenbroek 	assert(sp->smap_num == num);
230*e3b8d4bbSDavid van Moolenbroek 
231*e3b8d4bbSDavid van Moolenbroek 	if (sp->smap_endpt == NONE)
232*e3b8d4bbSDavid van Moolenbroek 		return NULL;
233*e3b8d4bbSDavid van Moolenbroek 
234*e3b8d4bbSDavid van Moolenbroek 	if (sockidp != NULL)
235*e3b8d4bbSDavid van Moolenbroek 		*sockidp = id;
236*e3b8d4bbSDavid van Moolenbroek 	return sp;
237*e3b8d4bbSDavid van Moolenbroek }
238*e3b8d4bbSDavid van Moolenbroek 
239*e3b8d4bbSDavid van Moolenbroek /*
240*e3b8d4bbSDavid van Moolenbroek  * Return a pointer to the smap structure for the socket driver with the given
241*e3b8d4bbSDavid van Moolenbroek  * endpoint.  Return NULL if the endpoint does not identify a socket driver.
242*e3b8d4bbSDavid van Moolenbroek  */
243*e3b8d4bbSDavid van Moolenbroek struct smap *
get_smap_by_endpt(endpoint_t endpt)244*e3b8d4bbSDavid van Moolenbroek get_smap_by_endpt(endpoint_t endpt)
245*e3b8d4bbSDavid van Moolenbroek {
246*e3b8d4bbSDavid van Moolenbroek 	unsigned int i;
247*e3b8d4bbSDavid van Moolenbroek 
248*e3b8d4bbSDavid van Moolenbroek 	/*
249*e3b8d4bbSDavid van Moolenbroek 	 * TODO: this function is used rather frequently, so it would be nice
250*e3b8d4bbSDavid van Moolenbroek 	 * to get rid of the O(n) loop here.  The get_dmap_by_endpt() function
251*e3b8d4bbSDavid van Moolenbroek 	 * suffers from the same problem.  It might be worth adding an extra
252*e3b8d4bbSDavid van Moolenbroek 	 * field to the fproc structure for this.
253*e3b8d4bbSDavid van Moolenbroek 	 */
254*e3b8d4bbSDavid van Moolenbroek 	for (i = 0; i < __arraycount(smap); i++)
255*e3b8d4bbSDavid van Moolenbroek 		if (smap[i].smap_endpt == endpt)
256*e3b8d4bbSDavid van Moolenbroek 			return &smap[i];
257*e3b8d4bbSDavid van Moolenbroek 
258*e3b8d4bbSDavid van Moolenbroek 	return NULL;
259*e3b8d4bbSDavid van Moolenbroek }
260*e3b8d4bbSDavid van Moolenbroek 
261*e3b8d4bbSDavid van Moolenbroek /*
262*e3b8d4bbSDavid van Moolenbroek  * Return a pointer to the smap structure for the socket driver handling the
263*e3b8d4bbSDavid van Moolenbroek  * given domain (protocol family).  Return NULL if there is no match.
264*e3b8d4bbSDavid van Moolenbroek  */
265*e3b8d4bbSDavid van Moolenbroek struct smap *
get_smap_by_domain(int domain)266*e3b8d4bbSDavid van Moolenbroek get_smap_by_domain(int domain)
267*e3b8d4bbSDavid van Moolenbroek {
268*e3b8d4bbSDavid van Moolenbroek 
269*e3b8d4bbSDavid van Moolenbroek 	if (domain < 0 || domain >= __arraycount(pfmap))
270*e3b8d4bbSDavid van Moolenbroek 		return NULL;
271*e3b8d4bbSDavid van Moolenbroek 
272*e3b8d4bbSDavid van Moolenbroek 	return pfmap[domain]; /* may be NULL */
273*e3b8d4bbSDavid van Moolenbroek }
274