xref: /minix3/minix/net/lwip/ndev.c (revision ef8d499e2d2af900e9b2ab297171d7b088652482)
1 /* LWIP service - ndev.c - network driver communication module */
2 /*
3  * There is almost a one-to-one mapping between network device driver (ndev)
4  * objects and ethernet interface (ethif) objects, with as major difference
5  * that there may be an ndev object but not an ethif object for a driver that
6  * is known to exist but has not yet replied to our initialization request:
7  * without the information from the initialization request, there is no point
8  * creating an ethif object just yet, while we do need to track the driver
9  * process.  TODO: it would be nice if unanswered init requests timed out and
10  * caused the removal of the ndev object after a while.
11  *
12  * Beyond that, this module aims to abstract away the low-level details of
13  * communication, memory grants, and driver restarts.  Driver restarts are not
14  * fully transparent to the ethif module because it needs to reinitialize
15  * driver state only it knows about after a restart.  Drivers that are in the
16  * process of restarting and therefore not operational are said to be disabled.
17  *
18  * From this module's point of view, a network driver is one of two states:
19  * initializing, where it has yet to respond to our initialization request, and
20  * active, where it is expected to accept and respond to all other requests.
21  * This module does not keep track of higher-level states and rules however;
22  * that is left to the ethif layer on one side, and the network driver itself
23  * on the other side.  One important example is the interface being up or down:
24  * the ndev layer will happily forward send and receive requests when the
25  * interface is down, but these requests will be (resp.) dropped and rejected
26  * by the network driver in that state, and will not be generated by the ethif
27  * layer when the layer is down.  Imposing barriers between configure and send
28  * requests is also left to the other parties.
29  *
30  * In this module, each active network driver has a send queue and a receive
31  * queue.  The send queue is shared for packet send requests and configuration
32  * change requests.  The receive queue is used for packet receive requests
33  * only.  Each queue has a maximum depth, which is the minimum of a value
34  * provided by the network driver during initialization and local restrictions.
35  * These local restrictions are different for the two queue types: the receive
36  * queue is always bounded to a hardcoded value, while the send queue has a
37  * guaranteed minimum depth but may use up to the driver's maximum using spare
38  * entries.  For both, a minimum depth is always available, since it is not
39  * possible to cancel individual send or receive requests after they have been
40  * sent to a particular driver.  This does mean that we necessarily waste a
41  * large number of request structures in the common case.
42  *
43  * The general API model does not support the notion of blocking calls.  While
44  * it would make sense to retrieve e.g. error statistics from the driver only
45  * when requested by userland, implementing this without threads would be
46  * seriously complicated, because such requests can have many origins (ioctl,
47  * PF_ROUTE message, sysctl).  Instead, we rely on drivers updating us with the
48  * latest information on everything at all times, so that we can hand over a
49  * cached copy of (e.g.) those error statistics right away.  We provide a means
50  * for drivers to perform rate limiting of such status updates (to prevent
51  * overflowing asynsend queues), by replying to these status messages.  That
52  * means that there is a request-response combo going in the opposite direction
53  * of the regular messages.
54  *
55  * TODO: in the future we will want to obtain the list of supported media modes
56  * (IFM_) from drivers, so that userland can view the list.  Given the above
57  * model, the easiest way would be to obtain a copy of the full list, limited
58  * to a configured number of entries, at driver initialization time.  This
59  * would require that the initialization request also involve a memory grant.
60  *
61  * If necessary, it would not be too much work to split off this module into
62  * its own libndev library.  For now, there is no point in doing this and the
63  * tighter coupling allows us to optimize just a little but (see pbuf usage).
64  */
65 
66 #include "lwip.h"
67 #include "ndev.h"
68 #include "ethif.h"
69 
70 #define LABEL_MAX	16	/* FIXME: this should be in a system header */
71 
72 #define NDEV_SENDQ	2	/* minimum guaranteed send queue depth */
73 #define NDEV_RECVQ	2	/* guaranteed receive queue depth */
74 #define NREQ_SPARES	8	/* spare send queue (request) objects */
75 #define NR_NREQ		((NDEV_SENDQ + NDEV_RECVQ) * NR_NDEV + NREQ_SPARES)
76 
77 static SIMPLEQ_HEAD(, ndev_req) nreq_freelist;
78 
79 static struct ndev_req {
80 	SIMPLEQ_ENTRY(ndev_req) nreq_next;	/* next request in queue */
81 	int nreq_type;				/* type of request message */
82 	cp_grant_id_t nreq_grant[NDEV_IOV_MAX];	/* grants for request */
83 } nreq_array[NR_NREQ];
84 
85 static unsigned int nreq_spares;	/* number of free spare objects */
86 
87 struct ndev_queue {
88 	uint32_t nq_head;		/* ID of oldest pending request */
89 	uint8_t nq_count;		/* current nr of pending requests */
90 	uint8_t nq_max;			/* maximum nr of pending requests */
91 	SIMPLEQ_HEAD(, ndev_req) nq_req; /* queue of pending requests */
92 };
93 
94 static struct ndev {
95 	endpoint_t ndev_endpt;		/* driver endpoint */
96 	char ndev_label[LABEL_MAX];	/* driver label */
97 	struct ethif *ndev_ethif;	/* ethif object, or NULL if init'ing */
98 	struct ndev_queue ndev_sendq;	/* packet send and configure queue */
99 	struct ndev_queue ndev_recvq;	/* packet receive queue */
100 } ndev_array[NR_NDEV];
101 
102 static ndev_id_t ndev_max;		/* highest driver count ever seen */
103 
104 /*
105  * This macro checks whether the network driver is active rather than
106  * initializing.  See above for more information.
107  */
108 #define NDEV_ACTIVE(ndev)	((ndev)->ndev_sendq.nq_max > 0)
109 
110 static int ndev_pending;		/* number of initializing drivers */
111 
112 /* The CTL_MINIX MINIX_LWIP "drivers" subtree.  Dynamically numbered. */
113 static struct rmib_node minix_lwip_drivers_table[] = {
114 	RMIB_INTPTR(RMIB_RO, &ndev_pending, "pending",
115 	    "Number of drivers currently initializing"),
116 };
117 
118 static struct rmib_node minix_lwip_drivers_node =
119     RMIB_NODE(RMIB_RO, minix_lwip_drivers_table, "drivers",
120 	"Network driver information");
121 
122 /*
123  * Initialize the network driver communication module.
124  */
125 void
ndev_init(void)126 ndev_init(void)
127 {
128 	unsigned int slot;
129 	int r;
130 
131 	/* Initialize local variables. */
132 	ndev_max = 0;
133 
134 	SIMPLEQ_INIT(&nreq_freelist);
135 
136 	for (slot = 0; slot < __arraycount(nreq_array); slot++)
137 		SIMPLEQ_INSERT_TAIL(&nreq_freelist, &nreq_array[slot],
138 		    nreq_next);
139 
140 	nreq_spares = NREQ_SPARES;
141 
142 	/*
143 	 * Preallocate the total number of grants that we could possibly need
144 	 * concurrently.  Even though it is extremely unlikely that we will
145 	 * ever need that many grants in practice, the alternative is runtime
146 	 * dynamic memory (re)allocation which is something we prefer to avoid
147 	 * altogether.  At time of writing, we end up preallocating 320 grants
148 	 * using up a total of a bit under 9KB of memory.
149 	 */
150 	cpf_prealloc(NR_NREQ * NDEV_IOV_MAX);
151 
152 
153 	/*
154 	 * Not needed, just for ultimate safety: start off all queues with
155 	 * wildly different request sequence numbers, to minimize the chance
156 	 * that any two replies will ever be confused.
157 	 */
158 	for (slot = 0; slot < __arraycount(ndev_array); slot++) {
159 		ndev_array[slot].ndev_sendq.nq_head = slot << 21;
160 		ndev_array[slot].ndev_recvq.nq_head = (slot * 2 + 1) << 20;
161 	}
162 
163 	/* Subscribe to Data Store (DS) events from network drivers. */
164 	if ((r = ds_subscribe("drv\\.net\\..*",
165 	    DSF_INITIAL | DSF_OVERWRITE)) != OK)
166 		panic("unable to subscribe to driver events: %d", r);
167 
168 	/*
169 	 * Keep track of how many drivers are in "pending" state, which means
170 	 * that they have not yet replied to our initialization request.
171 	 */
172 	ndev_pending = 0;
173 
174 	/* Register the minix.lwip.drivers subtree. */
175 	mibtree_register_lwip(&minix_lwip_drivers_node);
176 }
177 
178 /*
179  * Initialize a queue for first use.
180  */
181 static void
ndev_queue_init(struct ndev_queue * nq)182 ndev_queue_init(struct ndev_queue * nq)
183 {
184 
185 	/*
186 	 * Only ever increase sequence numbers, to minimize the chance that
187 	 * two (e.g. from different driver instances) happen to be the same.
188 	 */
189 	nq->nq_head++;
190 
191 	nq->nq_count = 0;
192 	nq->nq_max = 0;
193 	SIMPLEQ_INIT(&nq->nq_req);
194 }
195 
196 /*
197  * Advance the given request queue, freeing up the request at the head of the
198  * queue including any grants in use for it.
199  */
200 static void
ndev_queue_advance(struct ndev_queue * nq)201 ndev_queue_advance(struct ndev_queue * nq)
202 {
203 	struct ndev_req * nreq;
204 	cp_grant_id_t grant;
205 	unsigned int i;
206 
207 	nreq = SIMPLEQ_FIRST(&nq->nq_req);
208 
209 	for (i = 0; i < __arraycount(nreq->nreq_grant); i++) {
210 		grant = nreq->nreq_grant[i];
211 
212 		if (!GRANT_VALID(grant))
213 			break;
214 
215 		/* TODO: make the safecopies code stop using errno. */
216 		if (cpf_revoke(grant) != 0)
217 			panic("unable to revoke grant: %d", -errno);
218 	}
219 
220 	if (nreq->nreq_type != NDEV_RECV && nq->nq_count > NDEV_SENDQ) {
221 		nreq_spares++;
222 
223 		assert(nreq_spares <= NREQ_SPARES);
224 	}
225 
226 	SIMPLEQ_REMOVE_HEAD(&nq->nq_req, nreq_next);
227 
228 	SIMPLEQ_INSERT_HEAD(&nreq_freelist, nreq, nreq_next);
229 
230 	nq->nq_head++;
231 	nq->nq_count--;
232 }
233 
234 /*
235  * Clear any outstanding requests from the given queue and reset it to a
236  * pre-initialization state.
237  */
238 static void
ndev_queue_reset(struct ndev_queue * nq)239 ndev_queue_reset(struct ndev_queue * nq)
240 {
241 
242 	while (nq->nq_count > 0) {
243 		assert(!SIMPLEQ_EMPTY(&nq->nq_req));
244 
245 		ndev_queue_advance(nq);
246 	}
247 
248 	nq->nq_max = 0;
249 }
250 
251 /*
252  * Obtain a request object for use in a new request.  Return the request
253  * object, with its request type field set to 'type', and with the request
254  * sequence ID returned in 'seq'.  Return NULL if no request objects are
255  * available for the given request type.  If the caller does send off the
256  * request, a call to ndev_queue_add() must follow immediately after.  If the
257  * caller fails to send off the request for other reasons, it need not do
258  * anything: this function does not perform any actions that need to be undone.
259  */
260 static struct ndev_req *
ndev_queue_get(struct ndev_queue * nq,int type,uint32_t * seq)261 ndev_queue_get(struct ndev_queue * nq, int type, uint32_t * seq)
262 {
263 	struct ndev_req *nreq;
264 
265 	/* Has the hard queue depth limit been reached? */
266 	if (nq->nq_count == nq->nq_max)
267 		return NULL;
268 
269 	/*
270 	 * For send requests, we may use request objects from a shared "spares"
271 	 * pool, if available.
272 	 */
273 	if (type != NDEV_RECV && nq->nq_count >= NDEV_SENDQ &&
274 	    nreq_spares == 0)
275 		return NULL;
276 
277 	assert(!SIMPLEQ_EMPTY(&nreq_freelist));
278 	nreq = SIMPLEQ_FIRST(&nreq_freelist);
279 
280 	nreq->nreq_type = type;
281 
282 	*seq = nq->nq_head + nq->nq_count;
283 
284 	return nreq;
285 }
286 
287 /*
288  * Add a successfully sent request to the given queue.  The request must have
289  * been obtained using ndev_queue_get() directly before the call to this
290  * function.  This function never fails.
291  */
292 static void
ndev_queue_add(struct ndev_queue * nq,struct ndev_req * nreq)293 ndev_queue_add(struct ndev_queue * nq, struct ndev_req * nreq)
294 {
295 
296 	if (nreq->nreq_type != NDEV_RECV && nq->nq_count >= NDEV_SENDQ) {
297 		assert(nreq_spares > 0);
298 
299 		nreq_spares--;
300 	}
301 
302 	SIMPLEQ_REMOVE_HEAD(&nreq_freelist, nreq_next);
303 
304 	SIMPLEQ_INSERT_TAIL(&nq->nq_req, nreq, nreq_next);
305 
306 	nq->nq_count++;
307 }
308 
309 /*
310  * Remove the head of the given request queue, but only if it matches the given
311  * request type and sequence ID.  Return TRUE if the head was indeed removed,
312  * or FALSE if the head of the request queue (if any) did not match the given
313  * type and/or sequence ID.
314  */
315 static int
ndev_queue_remove(struct ndev_queue * nq,int type,uint32_t seq)316 ndev_queue_remove(struct ndev_queue * nq, int type, uint32_t seq)
317 {
318 	struct ndev_req *nreq;
319 
320 	if (nq->nq_count < 1 || nq->nq_head != seq)
321 		return FALSE;
322 
323 	assert(!SIMPLEQ_EMPTY(&nq->nq_req));
324 	nreq = SIMPLEQ_FIRST(&nq->nq_req);
325 
326 	if (nreq->nreq_type != type)
327 		return FALSE;
328 
329 	ndev_queue_advance(nq);
330 
331 	return TRUE;
332 }
333 
334 /*
335  * Send an initialization request to a driver.  If this is a new driver, the
336  * ethif module does not get to know about the driver until it answers to this
337  * request, as the ethif module needs much of what the reply contains.  On the
338  * other hand, if this is a restarted driver, it will stay disabled until the
339  * init reply comes in.
340  */
341 static void
ndev_send_init(struct ndev * ndev)342 ndev_send_init(struct ndev * ndev)
343 {
344 	message m;
345 	int r;
346 
347 	memset(&m, 0, sizeof(m));
348 	m.m_type = NDEV_INIT;
349 	m.m_ndev_netdriver_init.id = ndev->ndev_sendq.nq_head;
350 
351 	if ((r = asynsend3(ndev->ndev_endpt, &m, AMF_NOREPLY)) != OK)
352 		panic("asynsend to driver failed: %d", r);
353 }
354 
355 /*
356  * A network device driver has been started or restarted.
357  */
358 static void
ndev_up(const char * label,endpoint_t endpt)359 ndev_up(const char * label, endpoint_t endpt)
360 {
361 	static int reported = FALSE;
362 	struct ndev *ndev;
363 	ndev_id_t slot;
364 
365 	/*
366 	 * First see if we already had an entry for this driver.  If so, it has
367 	 * been restarted, and we need to report it as not running to ethif.
368 	 */
369 	ndev = NULL;
370 
371 	for (slot = 0; slot < ndev_max; slot++) {
372 		if (ndev_array[slot].ndev_endpt == NONE) {
373 			if (ndev == NULL)
374 				ndev = &ndev_array[slot];
375 
376 			continue;
377 		}
378 
379 		if (!strcmp(ndev_array[slot].ndev_label, label)) {
380 			/* Cancel any ongoing requests. */
381 			ndev_queue_reset(&ndev_array[slot].ndev_sendq);
382 			ndev_queue_reset(&ndev_array[slot].ndev_recvq);
383 
384 			if (ndev_array[slot].ndev_ethif != NULL) {
385 				ethif_disable(ndev_array[slot].ndev_ethif);
386 
387 				ndev_pending++;
388 			}
389 
390 			ndev_array[slot].ndev_endpt = endpt;
391 
392 			/* Attempt to resume communication. */
393 			ndev_send_init(&ndev_array[slot]);
394 
395 			return;
396 		}
397 	}
398 
399 	if (ndev == NULL) {
400 		/*
401 		 * If there is no free slot for this driver in our table, we
402 		 * necessarily have to ignore the driver altogether.  We report
403 		 * such cases once, so that the user can recompile if desired.
404 		 */
405 		if (ndev_max == __arraycount(ndev_array)) {
406 			if (!reported) {
407 				printf("LWIP: not enough ndev slots!\n");
408 
409 				reported = TRUE;
410 			}
411 			return;
412 		}
413 
414 		ndev = &ndev_array[ndev_max++];
415 	}
416 
417 	/* Initialize the slot. */
418 	ndev->ndev_endpt = endpt;
419 	strlcpy(ndev->ndev_label, label, sizeof(ndev->ndev_label));
420 	ndev->ndev_ethif = NULL;
421 	ndev_queue_init(&ndev->ndev_sendq);
422 	ndev_queue_init(&ndev->ndev_recvq);
423 
424 	ndev_send_init(ndev);
425 
426 	ndev_pending++;
427 }
428 
429 /*
430  * A network device driver has been terminated.
431  */
432 static void
ndev_down(struct ndev * ndev)433 ndev_down(struct ndev * ndev)
434 {
435 
436 	/* Cancel any ongoing requests. */
437 	ndev_queue_reset(&ndev->ndev_sendq);
438 	ndev_queue_reset(&ndev->ndev_recvq);
439 
440 	/*
441 	 * If this ndev object had a corresponding ethif object, tell the ethif
442 	 * layer that the device is really gone now.
443 	 */
444 	if (ndev->ndev_ethif != NULL)
445 		ethif_remove(ndev->ndev_ethif);
446 	else
447 		ndev_pending--;
448 
449 	/* Remove the driver from our own administration. */
450 	ndev->ndev_endpt = NONE;
451 
452 	while (ndev_max > 0 && ndev_array[ndev_max - 1].ndev_endpt == NONE)
453 		ndev_max--;
454 }
455 
456 /*
457  * The DS service has notified us of changes to our subscriptions.  That means
458  * that network drivers may have been started, restarted, and/or shut down.
459  * Find out what has changed, and act accordingly.
460  */
461 void
ndev_check(void)462 ndev_check(void)
463 {
464 	static const char *prefix = "drv.net.";
465 	char key[DS_MAX_KEYLEN], *label;
466 	size_t prefixlen;
467 	endpoint_t endpt;
468 	uint32_t val;
469 	ndev_id_t slot;
470 	int r;
471 
472 	prefixlen = strlen(prefix);
473 
474 	/* Check whether any drivers have been (re)started. */
475 	while ((r = ds_check(key, NULL, &endpt)) == OK) {
476 		if (strncmp(key, prefix, prefixlen) != 0 || endpt == NONE)
477 			continue;
478 
479 		if (ds_retrieve_u32(key, &val) != OK || val != DS_DRIVER_UP)
480 			continue;
481 
482 		label = &key[prefixlen];
483 		if (label[0] == '\0' || memchr(label, '\0', LABEL_MAX) == NULL)
484 			continue;
485 
486 		ndev_up(label, endpt);
487 	}
488 
489 	if (r != ENOENT)
490 		printf("LWIP: DS check failed (%d)\n", r);
491 
492 	/*
493 	 * Check whether the drivers we currently know about are still up.  The
494 	 * ones that are not are really gone.  It is no problem that we recheck
495 	 * any drivers that have just been reported by ds_check() above.
496 	 * However, we cannot check the same key: while the driver is being
497 	 * restarted, its driver status is already gone from DS. Instead, see
498 	 * if there is still an entry for its label, as that entry remains in
499 	 * existence during the restart.  The associated endpoint may still
500 	 * change however, so do not check that part: in such cases we will get
501 	 * a driver-up announcement later anyway.
502 	 */
503 	for (slot = 0; slot < ndev_max; slot++) {
504 		if (ndev_array[slot].ndev_endpt == NONE)
505 			continue;
506 
507 		if (ds_retrieve_label_endpt(ndev_array[slot].ndev_label,
508 		    &endpt) != OK)
509 			ndev_down(&ndev_array[slot]);
510 	}
511 }
512 
513 /*
514  * A network device driver has sent a reply to our initialization request.
515  */
516 static void
ndev_init_reply(struct ndev * ndev,const message * m_ptr)517 ndev_init_reply(struct ndev * ndev, const message * m_ptr)
518 {
519 	struct ndev_hwaddr hwaddr;
520 	uint8_t hwaddr_len, max_send, max_recv;
521 	const char *name;
522 	int enabled;
523 
524 	/*
525 	 * Make sure that we were waiting for a reply to an initialization
526 	 * request, and that this is the reply to that request.
527 	 */
528 	if (NDEV_ACTIVE(ndev) ||
529 	    m_ptr->m_netdriver_ndev_init_reply.id != ndev->ndev_sendq.nq_head)
530 		return;
531 
532 	/*
533 	 * Do just enough sanity checking on the data to pass it up to the
534 	 * ethif layer, which will check the rest (e.g., name duplicates).
535 	 */
536 	if (memchr(m_ptr->m_netdriver_ndev_init_reply.name, '\0',
537 	    sizeof(m_ptr->m_netdriver_ndev_init_reply.name)) == NULL ||
538 	    m_ptr->m_netdriver_ndev_init_reply.name[0] == '\0') {
539 		printf("LWIP: driver %d provided invalid name\n",
540 		    m_ptr->m_source);
541 
542 		ndev_down(ndev);
543 
544 		return;
545 	}
546 
547 	hwaddr_len = m_ptr->m_netdriver_ndev_init_reply.hwaddr_len;
548 	if (hwaddr_len < 1 || hwaddr_len > __arraycount(hwaddr.nhwa_addr)) {
549 		printf("LWIP: driver %d provided invalid HW-addr length\n",
550 		    m_ptr->m_source);
551 
552 		ndev_down(ndev);
553 
554 		return;
555 	}
556 
557 	if ((max_send = m_ptr->m_netdriver_ndev_init_reply.max_send) < 1 ||
558 	    (max_recv = m_ptr->m_netdriver_ndev_init_reply.max_recv) < 1) {
559 		printf("LWIP: driver %d provided invalid queue maximum\n",
560 		    m_ptr->m_source);
561 
562 		ndev_down(ndev);
563 
564 		return;
565 	}
566 
567 	/*
568 	 * If the driver is new, allocate a new ethif object for it.  On
569 	 * success, or if the driver was restarted, (re)enable the interface.
570 	 * Both calls may fail, in which case we should forget about the
571 	 * driver.  It may continue to send us messages, which we should then
572 	 * discard.
573 	 */
574 	name = m_ptr->m_netdriver_ndev_init_reply.name;
575 
576 	if (ndev->ndev_ethif == NULL) {
577 		ndev->ndev_ethif = ethif_add((ndev_id_t)(ndev - ndev_array),
578 		    name, m_ptr->m_netdriver_ndev_init_reply.caps);
579 		name = NULL;
580 	}
581 
582 	if (ndev->ndev_ethif != NULL) {
583 		/*
584 		 * Set the maximum numbers of pending requests (for each
585 		 * direction) first, because enabling the interface may cause
586 		 * the ethif layer to start sending requests immediately.
587 		 */
588 		ndev->ndev_sendq.nq_max = max_send;
589 		ndev->ndev_sendq.nq_head++;
590 
591 		/*
592 		 * Limit the maximum number of concurrently pending receive
593 		 * requests to our configured maximum.  For send requests, we
594 		 * use a more dynamic approach with spare request objects.
595 		 */
596 		if (max_recv > NDEV_RECVQ)
597 			max_recv = NDEV_RECVQ;
598 		ndev->ndev_recvq.nq_max = max_recv;
599 		ndev->ndev_recvq.nq_head++;
600 
601 		memset(&hwaddr, 0, sizeof(hwaddr));
602 		memcpy(hwaddr.nhwa_addr,
603 		    m_ptr->m_netdriver_ndev_init_reply.hwaddr, hwaddr_len);
604 
605 		/*
606 		 * Provide a NULL pointer for the name if we have only just
607 		 * added the interface at all.  The callee may use this to
608 		 * determine whether the driver is new or has been restarted.
609 		 */
610 		enabled = ethif_enable(ndev->ndev_ethif, name, &hwaddr,
611 		    m_ptr->m_netdriver_ndev_init_reply.hwaddr_len,
612 		    m_ptr->m_netdriver_ndev_init_reply.caps,
613 		    m_ptr->m_netdriver_ndev_init_reply.link,
614 		    m_ptr->m_netdriver_ndev_init_reply.media);
615 	} else
616 		enabled = FALSE;
617 
618 	/*
619 	 * If we did not manage to enable the interface, remove it again,
620 	 * possibly also from the ethif layer.
621 	 */
622 	if (!enabled)
623 		ndev_down(ndev);
624 	else
625 		ndev_pending--;
626 }
627 
628 /*
629  * Request that a network device driver change its configuration.  This
630  * function allows for configuration of various different driver and device
631  * aspects: the I/O mode (and multicast receipt list), the enabled (sub)set of
632  * capabilities, the driver-specific flags, and the hardware address.  Each of
633  * these settings may be changed by setting the corresponding NDEV_SET_ flag in
634  * the 'set' field of the given configuration structure.  It is explicitly
635  * allowed to generate a request with no NDEV_SET_ flags; such a request will
636  * be sent to the driver and ultimately generate a response.  Return OK if the
637  * configuration request was sent to the driver, EBUSY if no (more) requests
638  * can be sent to the driver right now, or ENOMEM on grant allocation failure.
639  */
640 int
ndev_conf(ndev_id_t id,const struct ndev_conf * nconf)641 ndev_conf(ndev_id_t id, const struct ndev_conf * nconf)
642 {
643 	struct ndev *ndev;
644 	struct ndev_req *nreq;
645 	uint32_t seq;
646 	message m;
647 	cp_grant_id_t grant;
648 	int r;
649 
650 	assert(id < __arraycount(ndev_array));
651 	ndev = &ndev_array[id];
652 
653 	assert(ndev->ndev_endpt != NONE);
654 	assert(NDEV_ACTIVE(ndev));
655 
656 	if ((nreq = ndev_queue_get(&ndev->ndev_sendq, NDEV_CONF,
657 	    &seq)) == NULL)
658 		return EBUSY;
659 
660 	memset(&m, 0, sizeof(m));
661 	m.m_type = NDEV_CONF;
662 	m.m_ndev_netdriver_conf.id = seq;
663 	m.m_ndev_netdriver_conf.set = nconf->nconf_set;
664 
665 	grant = GRANT_INVALID;
666 
667 	if (nconf->nconf_set & NDEV_SET_MODE) {
668 		m.m_ndev_netdriver_conf.mode = nconf->nconf_mode;
669 
670 		if (nconf->nconf_mode & NDEV_MODE_MCAST_LIST) {
671 			assert(nconf->nconf_mclist != NULL);
672 			assert(nconf->nconf_mccount != 0);
673 
674 			grant = cpf_grant_direct(ndev->ndev_endpt,
675 			    (vir_bytes)nconf->nconf_mclist,
676 			    sizeof(nconf->nconf_mclist[0]) *
677 			    nconf->nconf_mccount, CPF_READ);
678 
679 			if (!GRANT_VALID(grant))
680 				return ENOMEM;
681 
682 			m.m_ndev_netdriver_conf.mcast_count =
683 			    nconf->nconf_mccount;
684 		}
685 	}
686 
687 	m.m_ndev_netdriver_conf.mcast_grant = grant;
688 
689 	if (nconf->nconf_set & NDEV_SET_CAPS)
690 		m.m_ndev_netdriver_conf.caps = nconf->nconf_caps;
691 
692 	if (nconf->nconf_set & NDEV_SET_FLAGS)
693 		m.m_ndev_netdriver_conf.flags = nconf->nconf_flags;
694 
695 	if (nconf->nconf_set & NDEV_SET_MEDIA)
696 		m.m_ndev_netdriver_conf.media = nconf->nconf_media;
697 
698 	if (nconf->nconf_set & NDEV_SET_HWADDR)
699 		memcpy(m.m_ndev_netdriver_conf.hwaddr,
700 		    nconf->nconf_hwaddr.nhwa_addr,
701 		    __arraycount(m.m_ndev_netdriver_conf.hwaddr));
702 
703 	if ((r = asynsend3(ndev->ndev_endpt, &m, AMF_NOREPLY)) != OK)
704 		panic("asynsend to driver failed: %d", r);
705 
706 	nreq->nreq_grant[0] = grant; /* may also be invalid */
707 	nreq->nreq_grant[1] = GRANT_INVALID;
708 
709 	ndev_queue_add(&ndev->ndev_sendq, nreq);
710 
711 	return OK;
712 }
713 
714 /*
715  * The network device driver has sent a reply to a configuration request.
716  */
717 static void
ndev_conf_reply(struct ndev * ndev,const message * m_ptr)718 ndev_conf_reply(struct ndev * ndev, const message * m_ptr)
719 {
720 
721 	/*
722 	 * Was this the request we were waiting for?  If so, remove it from the
723 	 * send queue.  Otherwise, ignore this reply message.
724 	 */
725 	if (!NDEV_ACTIVE(ndev) || !ndev_queue_remove(&ndev->ndev_sendq,
726 	    NDEV_CONF, m_ptr->m_netdriver_ndev_reply.id))
727 		return;
728 
729 	/* Tell the ethif layer about the updated configuration. */
730 	assert(ndev->ndev_ethif != NULL);
731 
732 	ethif_configured(ndev->ndev_ethif,
733 	    m_ptr->m_netdriver_ndev_reply.result);
734 }
735 
736 /*
737  * Construct a packet send or receive request and send it off to a network
738  * driver.  The given pbuf chain may be part of a queue.  Return OK if the
739  * request was successfully sent, or ENOMEM on grant allocation failure.
740  */
741 static int
ndev_transfer(struct ndev * ndev,const struct pbuf * pbuf,int do_send,uint32_t seq,struct ndev_req * nreq)742 ndev_transfer(struct ndev * ndev, const struct pbuf * pbuf, int do_send,
743 	uint32_t seq, struct ndev_req * nreq)
744 {
745 	cp_grant_id_t grant;
746 	message m;
747 	unsigned int i;
748 	size_t left;
749 	int r;
750 
751 	memset(&m, 0, sizeof(m));
752 	m.m_type = (do_send) ? NDEV_SEND : NDEV_RECV;
753 	m.m_ndev_netdriver_transfer.id = seq;
754 
755 	left = pbuf->tot_len;
756 
757 	for (i = 0; left > 0; i++) {
758 		assert(i < NDEV_IOV_MAX);
759 
760 		grant = cpf_grant_direct(ndev->ndev_endpt,
761 		    (vir_bytes)pbuf->payload, pbuf->len,
762 		    (do_send) ? CPF_READ : CPF_WRITE);
763 
764 		if (!GRANT_VALID(grant)) {
765 			while (i-- > 0)
766 				(void)cpf_revoke(nreq->nreq_grant[i]);
767 
768 			return ENOMEM;
769 		}
770 
771 		m.m_ndev_netdriver_transfer.grant[i] = grant;
772 		m.m_ndev_netdriver_transfer.len[i] = pbuf->len;
773 
774 		nreq->nreq_grant[i] = grant;
775 
776 		assert(left >= pbuf->len);
777 		left -= pbuf->len;
778 		pbuf = pbuf->next;
779 	}
780 
781 	m.m_ndev_netdriver_transfer.count = i;
782 
783 	/*
784 	 * Unless the array is full, an invalid grant marks the end of the list
785 	 * of invalid grants.
786 	 */
787 	if (i < __arraycount(nreq->nreq_grant))
788 		nreq->nreq_grant[i] = GRANT_INVALID;
789 
790 	if ((r = asynsend3(ndev->ndev_endpt, &m, AMF_NOREPLY)) != OK)
791 		panic("asynsend to driver failed: %d", r);
792 
793 	return OK;
794 }
795 
796 /*
797  * Send a packet to the given network driver.  Return OK if the packet is sent
798  * off to the driver, EBUSY if no (more) packets can be sent to the driver at
799  * this time, or ENOMEM on grant allocation failure.
800  *
801  * The use of 'pbuf' in this interface is a bit ugly, but it saves us from
802  * having to go through an intermediate representation (e.g. an iovec array)
803  * for the data being sent.  The same applies to ndev_receive().
804  */
805 int
ndev_send(ndev_id_t id,const struct pbuf * pbuf)806 ndev_send(ndev_id_t id, const struct pbuf * pbuf)
807 {
808 	struct ndev *ndev;
809 	struct ndev_req *nreq;
810 	uint32_t seq;
811 	int r;
812 
813 	assert(id < __arraycount(ndev_array));
814 	ndev = &ndev_array[id];
815 
816 	assert(ndev->ndev_endpt != NONE);
817 	assert(NDEV_ACTIVE(ndev));
818 
819 	if ((nreq = ndev_queue_get(&ndev->ndev_sendq, NDEV_SEND,
820 	    &seq)) == NULL)
821 		return EBUSY;
822 
823 	if ((r = ndev_transfer(ndev, pbuf, TRUE /*do_send*/, seq, nreq)) != OK)
824 		return r;
825 
826 	ndev_queue_add(&ndev->ndev_sendq, nreq);
827 
828 	return OK;
829 }
830 
831 /*
832  * The network device driver has sent a reply to a send request.
833  */
834 static void
ndev_send_reply(struct ndev * ndev,const message * m_ptr)835 ndev_send_reply(struct ndev * ndev, const message * m_ptr)
836 {
837 
838 	/*
839 	 * Was this the request we were waiting for?  If so, remove it from the
840 	 * send queue.  Otherwise, ignore this reply message.
841 	 */
842 	if (!NDEV_ACTIVE(ndev) || !ndev_queue_remove(&ndev->ndev_sendq,
843 	    NDEV_SEND, m_ptr->m_netdriver_ndev_reply.id))
844 		return;
845 
846 	/* Tell the ethif layer about the result of the transmission. */
847 	assert(ndev->ndev_ethif != NULL);
848 
849 	ethif_sent(ndev->ndev_ethif,
850 	    m_ptr->m_netdriver_ndev_reply.result);
851 }
852 
853 /*
854  * Return TRUE if a new receive request can be spawned for a particular network
855  * driver, or FALSE if its queue of receive requests is full.  This call exists
856  * merely to avoid needless buffer allocatin in the case that ndev_recv() is
857  * going to return EBUSY anyway.
858  */
859 int
ndev_can_recv(ndev_id_t id)860 ndev_can_recv(ndev_id_t id)
861 {
862 	struct ndev *ndev;
863 
864 	assert(id < __arraycount(ndev_array));
865 	ndev = &ndev_array[id];
866 
867 	assert(ndev->ndev_endpt != NONE);
868 	assert(NDEV_ACTIVE(ndev));
869 
870 	return (ndev->ndev_recvq.nq_count < ndev->ndev_recvq.nq_max);
871 }
872 
873 /*
874  * Start the process of receiving a packet from a network driver.  The packet
875  * will be stored in the given pbuf chain upon completion.  Return OK if the
876  * receive request is sent to the driver, EBUSY if the maximum number of
877  * concurrent receive requests has been reached for this driver, or ENOMEM on
878  * grant allocation failure.
879  */
880 int
ndev_recv(ndev_id_t id,struct pbuf * pbuf)881 ndev_recv(ndev_id_t id, struct pbuf * pbuf)
882 {
883 	struct ndev *ndev;
884 	struct ndev_req *nreq;
885 	uint32_t seq;
886 	int r;
887 
888 	assert(id < __arraycount(ndev_array));
889 	ndev = &ndev_array[id];
890 
891 	assert(ndev->ndev_endpt != NONE);
892 	assert(NDEV_ACTIVE(ndev));
893 
894 	if ((nreq = ndev_queue_get(&ndev->ndev_recvq, NDEV_RECV,
895 	    &seq)) == NULL)
896 		return EBUSY;
897 
898 	if ((r = ndev_transfer(ndev, pbuf, FALSE /*do_send*/, seq,
899 	    nreq)) != OK)
900 		return r;
901 
902 	ndev_queue_add(&ndev->ndev_recvq, nreq);
903 
904 	return OK;
905 }
906 
907 /*
908  * The network device driver has sent a reply to a receive request.
909  */
910 static void
ndev_recv_reply(struct ndev * ndev,const message * m_ptr)911 ndev_recv_reply(struct ndev * ndev, const message * m_ptr)
912 {
913 
914 	/*
915 	 * Was this the request we were waiting for?  If so, remove it from the
916 	 * receive queue.  Otherwise, ignore this reply message.
917 	 */
918 	if (!NDEV_ACTIVE(ndev) || !ndev_queue_remove(&ndev->ndev_recvq,
919 	    NDEV_RECV, m_ptr->m_netdriver_ndev_reply.id))
920 		return;
921 
922 	/* Tell the ethif layer about the result of the receipt. */
923 	assert(ndev->ndev_ethif != NULL);
924 
925 	ethif_received(ndev->ndev_ethif,
926 	    m_ptr->m_netdriver_ndev_reply.result);
927 }
928 
929 /*
930  * A network device driver sent a status report to us.  Process it and send a
931  * reply.
932  */
933 static void
ndev_status(struct ndev * ndev,const message * m_ptr)934 ndev_status(struct ndev * ndev, const message * m_ptr)
935 {
936 	message m;
937 	int r;
938 
939 	if (!NDEV_ACTIVE(ndev))
940 		return;
941 
942 	/* Tell the ethif layer about the status update. */
943 	assert(ndev->ndev_ethif != NULL);
944 
945 	ethif_status(ndev->ndev_ethif, m_ptr->m_netdriver_ndev_status.link,
946 	    m_ptr->m_netdriver_ndev_status.media,
947 	    m_ptr->m_netdriver_ndev_status.oerror,
948 	    m_ptr->m_netdriver_ndev_status.coll,
949 	    m_ptr->m_netdriver_ndev_status.ierror,
950 	    m_ptr->m_netdriver_ndev_status.iqdrop);
951 
952 	/*
953 	 * Send a reply, so that the driver knows it can send a new status
954 	 * update without risking asynsend queue overflows.  The ID of these
955 	 * messages is chosen by the driver and and we simply echo it.
956 	 */
957 	memset(&m, 0, sizeof(m));
958 	m.m_type = NDEV_STATUS_REPLY;
959 	m.m_ndev_netdriver_status_reply.id = m_ptr->m_netdriver_ndev_status.id;
960 
961 	if ((r = asynsend(m_ptr->m_source, &m)) != OK)
962 		panic("asynsend to driver failed: %d", r);
963 }
964 
965 /*
966  * Process a network driver reply message.
967  */
968 void
ndev_process(const message * m_ptr,int ipc_status)969 ndev_process(const message * m_ptr, int ipc_status)
970 {
971 	struct ndev *ndev;
972 	endpoint_t endpt;
973 	ndev_id_t slot;
974 
975 	/* Find the slot of the driver that sent the message, if any. */
976 	endpt = m_ptr->m_source;
977 
978 	for (slot = 0, ndev = ndev_array; slot < ndev_max; slot++, ndev++)
979 		if (ndev->ndev_endpt == endpt)
980 			break;
981 
982 	/*
983 	 * If we cannot find a slot for the driver, drop the message.  We may
984 	 * be ignoring the driver because it misbehaved or we are out of slots.
985 	 */
986 	if (slot == ndev_max)
987 		return;
988 
989 	/*
990 	 * Process the reply message.  For future compatibility, ignore any
991 	 * unrecognized message types.
992 	 */
993 	switch (m_ptr->m_type) {
994 	case NDEV_INIT_REPLY:
995 		ndev_init_reply(ndev, m_ptr);
996 
997 		break;
998 
999 	case NDEV_CONF_REPLY:
1000 		ndev_conf_reply(ndev, m_ptr);
1001 
1002 		break;
1003 
1004 	case NDEV_SEND_REPLY:
1005 		ndev_send_reply(ndev, m_ptr);
1006 
1007 		break;
1008 
1009 	case NDEV_RECV_REPLY:
1010 		ndev_recv_reply(ndev, m_ptr);
1011 
1012 		break;
1013 
1014 	case NDEV_STATUS:
1015 		ndev_status(ndev, m_ptr);
1016 
1017 		break;
1018 	}
1019 }
1020