xref: /minix3/minix/lib/libnetdriver/netdriver.c (revision f7df02e7476731c31f12548e38bcadbaf0233f6a)
1dbcce9ddSDavid van Moolenbroek /* The device-independent network driver framework. */
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #include <minix/drivers.h>
4433d6423SLionel Sambuc #include <minix/netdriver.h>
5433d6423SLionel Sambuc #include <minix/ds.h>
6dbcce9ddSDavid van Moolenbroek #include <assert.h>
7433d6423SLionel Sambuc 
8dbcce9ddSDavid van Moolenbroek #include "netdriver.h"
9433d6423SLionel Sambuc 
10*f7df02e7SDavid van Moolenbroek /*
11*f7df02e7SDavid van Moolenbroek  * These maximum values should be at least somewhat synchronized with the
12*f7df02e7SDavid van Moolenbroek  * values in the LWIP service's ndev module.
13*f7df02e7SDavid van Moolenbroek  */
14*f7df02e7SDavid van Moolenbroek #define NETDRIVER_SENDQ_MAX	8
15*f7df02e7SDavid van Moolenbroek #define NETDRIVER_RECVQ_MAX	2
16*f7df02e7SDavid van Moolenbroek 
17*f7df02e7SDavid van Moolenbroek /*
18*f7df02e7SDavid van Moolenbroek  * Maximum number of multicast addresses that can be copied in from the TCP/IP
19*f7df02e7SDavid van Moolenbroek  * service and passed to the driver.  If the actual number from the service
20*f7df02e7SDavid van Moolenbroek  * exceeds this maximum, the driver will be told to receive all multicast
21*f7df02e7SDavid van Moolenbroek  * packets instead.
22*f7df02e7SDavid van Moolenbroek  */
23*f7df02e7SDavid van Moolenbroek #define NETDRIVER_MCAST_MAX	16
24*f7df02e7SDavid van Moolenbroek 
25dbcce9ddSDavid van Moolenbroek static const struct netdriver *netdriver_table = NULL;
26dbcce9ddSDavid van Moolenbroek 
27dbcce9ddSDavid van Moolenbroek static int running;
28dbcce9ddSDavid van Moolenbroek 
29*f7df02e7SDavid van Moolenbroek static int init_expected;
30dbcce9ddSDavid van Moolenbroek 
31*f7df02e7SDavid van Moolenbroek static int up;
32dbcce9ddSDavid van Moolenbroek 
33*f7df02e7SDavid van Moolenbroek static unsigned int ticks;
34dbcce9ddSDavid van Moolenbroek 
35*f7df02e7SDavid van Moolenbroek static struct netdriver_data pending_sendq[NETDRIVER_SENDQ_MAX];
36*f7df02e7SDavid van Moolenbroek static unsigned int pending_sends, pending_sendtail;
37*f7df02e7SDavid van Moolenbroek 
38*f7df02e7SDavid van Moolenbroek static struct netdriver_data pending_recvq[NETDRIVER_RECVQ_MAX];
39*f7df02e7SDavid van Moolenbroek static unsigned int pending_recvs, pending_recvtail;
40*f7df02e7SDavid van Moolenbroek 
41*f7df02e7SDavid van Moolenbroek static int pending_status;
42*f7df02e7SDavid van Moolenbroek static endpoint_t status_endpt;
43*f7df02e7SDavid van Moolenbroek 
44*f7df02e7SDavid van Moolenbroek static int pending_link, pending_stat;
45*f7df02e7SDavid van Moolenbroek static uint32_t stat_oerror, stat_coll, stat_ierror, stat_iqdrop;
46*f7df02e7SDavid van Moolenbroek 
47*f7df02e7SDavid van Moolenbroek static char device_name[NDEV_NAME_MAX];
48*f7df02e7SDavid van Moolenbroek static netdriver_addr_t device_hwaddr;
49*f7df02e7SDavid van Moolenbroek static uint32_t device_caps;
50*f7df02e7SDavid van Moolenbroek 
51*f7df02e7SDavid van Moolenbroek static unsigned int device_link;
52*f7df02e7SDavid van Moolenbroek static uint32_t device_media;
53dbcce9ddSDavid van Moolenbroek 
54dbcce9ddSDavid van Moolenbroek /*
55dbcce9ddSDavid van Moolenbroek  * Announce we are up after a fresh start or restart.
56dbcce9ddSDavid van Moolenbroek  */
57*f7df02e7SDavid van Moolenbroek static void
netdriver_announce(void)58dbcce9ddSDavid van Moolenbroek netdriver_announce(void)
59433d6423SLionel Sambuc {
6065f76edbSDavid van Moolenbroek 	const char *driver_prefix = "drv.net.";
61dbcce9ddSDavid van Moolenbroek 	char label[DS_MAX_KEYLEN];
62dbcce9ddSDavid van Moolenbroek 	char key[DS_MAX_KEYLEN];
63dbcce9ddSDavid van Moolenbroek 	int r;
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc 	/* Publish a driver up event. */
66dbcce9ddSDavid van Moolenbroek 	if ((r = ds_retrieve_label_name(label, sef_self())) != OK)
67dbcce9ddSDavid van Moolenbroek 		panic("netdriver: unable to get own label: %d", r);
68dbcce9ddSDavid van Moolenbroek 
69dbcce9ddSDavid van Moolenbroek 	snprintf(key, sizeof(key), "%s%s", driver_prefix, label);
70dbcce9ddSDavid van Moolenbroek 	if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK)
71dbcce9ddSDavid van Moolenbroek 		panic("netdriver: unable to publish driver up event: %d", r);
72433d6423SLionel Sambuc }
73433d6423SLionel Sambuc 
74dbcce9ddSDavid van Moolenbroek /*
75dbcce9ddSDavid van Moolenbroek  * Prepare for copying.  Given a flat offset, return the vector element index
76dbcce9ddSDavid van Moolenbroek  * and an offset into that element.  Panic if the request does not fall
77dbcce9ddSDavid van Moolenbroek  * entirely within the vector.
78dbcce9ddSDavid van Moolenbroek  */
79dbcce9ddSDavid van Moolenbroek size_t
netdriver_prepare_copy(struct netdriver_data * data,size_t off,size_t size,unsigned int * indexp)80dbcce9ddSDavid van Moolenbroek netdriver_prepare_copy(struct netdriver_data * data, size_t off, size_t size,
81dbcce9ddSDavid van Moolenbroek 	unsigned int * indexp)
82433d6423SLionel Sambuc {
83dbcce9ddSDavid van Moolenbroek 	unsigned int i;
84433d6423SLionel Sambuc 
85dbcce9ddSDavid van Moolenbroek 	assert(data->size > 0);
86433d6423SLionel Sambuc 
87dbcce9ddSDavid van Moolenbroek 	/*
88dbcce9ddSDavid van Moolenbroek 	 * In theory we could truncate when copying out, but this creates a
89dbcce9ddSDavid van Moolenbroek 	 * problem for port-based I/O, where the size of the transfer is
90dbcce9ddSDavid van Moolenbroek 	 * typically specified in advance.  We could do extra port-based I/O
91dbcce9ddSDavid van Moolenbroek 	 * to discard the extra bytes, but the driver is better off doing such
92dbcce9ddSDavid van Moolenbroek 	 * truncation itself.  Thus, we disallow copying (in and out) beyond
93dbcce9ddSDavid van Moolenbroek 	 * the given data vector altogether.
94dbcce9ddSDavid van Moolenbroek 	 */
95dbcce9ddSDavid van Moolenbroek 	if (off + size > data->size)
96dbcce9ddSDavid van Moolenbroek 		panic("netdriver: request to copy beyond data size");
97433d6423SLionel Sambuc 
98dbcce9ddSDavid van Moolenbroek 	/*
99dbcce9ddSDavid van Moolenbroek 	 * Find the starting offset in the vector.  If this turns out to be
100dbcce9ddSDavid van Moolenbroek 	 * expensive, this can be adapted to store the last <element,offset>
101dbcce9ddSDavid van Moolenbroek 	 * pair in the "data" structure (this is the reason it is not 'const').
102dbcce9ddSDavid van Moolenbroek 	 */
103dbcce9ddSDavid van Moolenbroek 	for (i = 0; i < data->count; i++) {
104dbcce9ddSDavid van Moolenbroek 		assert(data->iovec[i].iov_size > 0);
105433d6423SLionel Sambuc 
106dbcce9ddSDavid van Moolenbroek 		if (off >= data->iovec[i].iov_size)
107dbcce9ddSDavid van Moolenbroek 			off -= data->iovec[i].iov_size;
108dbcce9ddSDavid van Moolenbroek 		else
109433d6423SLionel Sambuc 			break;
110433d6423SLionel Sambuc 	}
111433d6423SLionel Sambuc 
112dbcce9ddSDavid van Moolenbroek 	assert(i < data->count);
113dbcce9ddSDavid van Moolenbroek 
114dbcce9ddSDavid van Moolenbroek 	*indexp = i;
115dbcce9ddSDavid van Moolenbroek 	return off;
116dbcce9ddSDavid van Moolenbroek }
117dbcce9ddSDavid van Moolenbroek 
118dbcce9ddSDavid van Moolenbroek /*
119dbcce9ddSDavid van Moolenbroek  * Copy in or out packet data from/to a vector of grants.
120dbcce9ddSDavid van Moolenbroek  */
121dbcce9ddSDavid van Moolenbroek static void
netdriver_copy(struct netdriver_data * data,size_t off,vir_bytes addr,size_t size,int copyin)122dbcce9ddSDavid van Moolenbroek netdriver_copy(struct netdriver_data * data, size_t off, vir_bytes addr,
123dbcce9ddSDavid van Moolenbroek 	size_t size, int copyin)
124dbcce9ddSDavid van Moolenbroek {
125dbcce9ddSDavid van Moolenbroek 	struct vscp_vec vec[SCPVEC_NR];
126dbcce9ddSDavid van Moolenbroek 	size_t chunk;
127dbcce9ddSDavid van Moolenbroek 	unsigned int i, v;
128dbcce9ddSDavid van Moolenbroek 	int r;
129dbcce9ddSDavid van Moolenbroek 
130dbcce9ddSDavid van Moolenbroek 	off = netdriver_prepare_copy(data, off, size, &i);
131dbcce9ddSDavid van Moolenbroek 
132dbcce9ddSDavid van Moolenbroek 	/* Generate a new vector with all the individual copies to make. */
133dbcce9ddSDavid van Moolenbroek 	for (v = 0; size > 0; v++) {
134dbcce9ddSDavid van Moolenbroek 		chunk = data->iovec[i].iov_size - off;
135dbcce9ddSDavid van Moolenbroek 		if (chunk > size)
136dbcce9ddSDavid van Moolenbroek 			chunk = size;
137dbcce9ddSDavid van Moolenbroek 		assert(chunk > 0);
138dbcce9ddSDavid van Moolenbroek 
139dbcce9ddSDavid van Moolenbroek 		/*
140dbcce9ddSDavid van Moolenbroek 		 * We should be able to fit the entire I/O request in a single
141dbcce9ddSDavid van Moolenbroek 		 * copy vector.  If not, MINIX3 has been misconfigured.
142dbcce9ddSDavid van Moolenbroek 		 */
143dbcce9ddSDavid van Moolenbroek 		if (v >= SCPVEC_NR)
144dbcce9ddSDavid van Moolenbroek 			panic("netdriver: invalid vector size constant");
145dbcce9ddSDavid van Moolenbroek 
146dbcce9ddSDavid van Moolenbroek 		if (copyin) {
147dbcce9ddSDavid van Moolenbroek 			vec[v].v_from = data->endpt;
148dbcce9ddSDavid van Moolenbroek 			vec[v].v_to = SELF;
149dbcce9ddSDavid van Moolenbroek 		} else {
150dbcce9ddSDavid van Moolenbroek 			vec[v].v_from = SELF;
151dbcce9ddSDavid van Moolenbroek 			vec[v].v_to = data->endpt;
152dbcce9ddSDavid van Moolenbroek 		}
153dbcce9ddSDavid van Moolenbroek 		vec[v].v_gid = data->iovec[i].iov_grant;
154dbcce9ddSDavid van Moolenbroek 		vec[v].v_offset = off;
155dbcce9ddSDavid van Moolenbroek 		vec[v].v_addr = addr;
156dbcce9ddSDavid van Moolenbroek 		vec[v].v_bytes = chunk;
157dbcce9ddSDavid van Moolenbroek 
158dbcce9ddSDavid van Moolenbroek 		i++;
159dbcce9ddSDavid van Moolenbroek 		off = 0;
160dbcce9ddSDavid van Moolenbroek 		addr += chunk;
161dbcce9ddSDavid van Moolenbroek 		size -= chunk;
162dbcce9ddSDavid van Moolenbroek 	}
163dbcce9ddSDavid van Moolenbroek 
164dbcce9ddSDavid van Moolenbroek 	assert(v > 0 && v <= SCPVEC_NR);
165dbcce9ddSDavid van Moolenbroek 
166dbcce9ddSDavid van Moolenbroek 	/*
167dbcce9ddSDavid van Moolenbroek 	 * If only one vector element was generated, use a direct copy.  This
168dbcce9ddSDavid van Moolenbroek 	 * saves the kernel from having to copy in the vector.
169dbcce9ddSDavid van Moolenbroek 	 */
170dbcce9ddSDavid van Moolenbroek 	if (v == 1) {
171dbcce9ddSDavid van Moolenbroek 		if (copyin)
172dbcce9ddSDavid van Moolenbroek 			r = sys_safecopyfrom(vec->v_from, vec->v_gid,
173dbcce9ddSDavid van Moolenbroek 			    vec->v_offset, vec->v_addr, vec->v_bytes);
174dbcce9ddSDavid van Moolenbroek 		else
175dbcce9ddSDavid van Moolenbroek 			r = sys_safecopyto(vec->v_to, vec->v_gid,
176dbcce9ddSDavid van Moolenbroek 			    vec->v_offset, vec->v_addr, vec->v_bytes);
177dbcce9ddSDavid van Moolenbroek 	} else
178dbcce9ddSDavid van Moolenbroek 		r = sys_vsafecopy(vec, v);
179dbcce9ddSDavid van Moolenbroek 
180dbcce9ddSDavid van Moolenbroek 	if (r != OK)
181dbcce9ddSDavid van Moolenbroek 		panic("netdriver: unable to copy data: %d", r);
182dbcce9ddSDavid van Moolenbroek }
183dbcce9ddSDavid van Moolenbroek 
184dbcce9ddSDavid van Moolenbroek /*
185dbcce9ddSDavid van Moolenbroek  * Copy in packet data.
186dbcce9ddSDavid van Moolenbroek  */
187dbcce9ddSDavid van Moolenbroek void
netdriver_copyin(struct netdriver_data * __restrict data,size_t off,void * __restrict ptr,size_t size)188dbcce9ddSDavid van Moolenbroek netdriver_copyin(struct netdriver_data * __restrict data, size_t off,
189dbcce9ddSDavid van Moolenbroek 	void * __restrict ptr, size_t size)
190dbcce9ddSDavid van Moolenbroek {
191dbcce9ddSDavid van Moolenbroek 
192dbcce9ddSDavid van Moolenbroek 	netdriver_copy(data, off, (vir_bytes)ptr, size, TRUE /*copyin*/);
193dbcce9ddSDavid van Moolenbroek }
194dbcce9ddSDavid van Moolenbroek 
195dbcce9ddSDavid van Moolenbroek /*
196dbcce9ddSDavid van Moolenbroek  * Copy out packet data.
197dbcce9ddSDavid van Moolenbroek  */
198dbcce9ddSDavid van Moolenbroek void
netdriver_copyout(struct netdriver_data * __restrict data,size_t off,const void * __restrict ptr,size_t size)199dbcce9ddSDavid van Moolenbroek netdriver_copyout(struct netdriver_data * __restrict data, size_t off,
200dbcce9ddSDavid van Moolenbroek 	const void * __restrict ptr, size_t size)
201dbcce9ddSDavid van Moolenbroek {
202dbcce9ddSDavid van Moolenbroek 
203dbcce9ddSDavid van Moolenbroek 	netdriver_copy(data, off, (vir_bytes)ptr, size, FALSE /*copyin*/);
204dbcce9ddSDavid van Moolenbroek }
205dbcce9ddSDavid van Moolenbroek 
206dbcce9ddSDavid van Moolenbroek /*
207dbcce9ddSDavid van Moolenbroek  * Send a reply to a request.
208dbcce9ddSDavid van Moolenbroek  */
209dbcce9ddSDavid van Moolenbroek static void
send_reply(endpoint_t endpt,message * m_ptr)210dbcce9ddSDavid van Moolenbroek send_reply(endpoint_t endpt, message * m_ptr)
211dbcce9ddSDavid van Moolenbroek {
212dbcce9ddSDavid van Moolenbroek 	int r;
213dbcce9ddSDavid van Moolenbroek 
214*f7df02e7SDavid van Moolenbroek 	if ((r = asynsend(endpt, m_ptr)) != OK)
215dbcce9ddSDavid van Moolenbroek 		panic("netdriver: unable to send to %d: %d", endpt, r);
216dbcce9ddSDavid van Moolenbroek }
217dbcce9ddSDavid van Moolenbroek 
218dbcce9ddSDavid van Moolenbroek /*
219*f7df02e7SDavid van Moolenbroek  * A packet receive request has finished.  Send a reply and clean up.
220dbcce9ddSDavid van Moolenbroek  */
221dbcce9ddSDavid van Moolenbroek static void
finish_recv(int32_t result)222*f7df02e7SDavid van Moolenbroek finish_recv(int32_t result)
223dbcce9ddSDavid van Moolenbroek {
224*f7df02e7SDavid van Moolenbroek 	struct netdriver_data *data;
225*f7df02e7SDavid van Moolenbroek 	message m;
226dbcce9ddSDavid van Moolenbroek 
227*f7df02e7SDavid van Moolenbroek 	assert(pending_recvs > 0);
228dbcce9ddSDavid van Moolenbroek 
229*f7df02e7SDavid van Moolenbroek 	data = &pending_recvq[pending_recvtail];
230dbcce9ddSDavid van Moolenbroek 
231*f7df02e7SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
232*f7df02e7SDavid van Moolenbroek 	m.m_type = NDEV_RECV_REPLY;
233*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_reply.id = data->id;
234*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_reply.result = result;
235dbcce9ddSDavid van Moolenbroek 
236*f7df02e7SDavid van Moolenbroek 	send_reply(data->endpt, &m);
237dbcce9ddSDavid van Moolenbroek 
238*f7df02e7SDavid van Moolenbroek 	pending_recvtail = (pending_recvtail + 1) %
239*f7df02e7SDavid van Moolenbroek 	    __arraycount(pending_recvq);
240*f7df02e7SDavid van Moolenbroek 	pending_recvs--;
241dbcce9ddSDavid van Moolenbroek }
242dbcce9ddSDavid van Moolenbroek 
243dbcce9ddSDavid van Moolenbroek /*
244dbcce9ddSDavid van Moolenbroek  * Resume receiving packets.  In particular, if a receive request was pending,
245*f7df02e7SDavid van Moolenbroek  * call the driver's receive function.  If the call is successful, send a reply
246*f7df02e7SDavid van Moolenbroek  * to the requesting party.
247dbcce9ddSDavid van Moolenbroek  */
248dbcce9ddSDavid van Moolenbroek void
netdriver_recv(void)249dbcce9ddSDavid van Moolenbroek netdriver_recv(void)
250dbcce9ddSDavid van Moolenbroek {
251*f7df02e7SDavid van Moolenbroek 	struct netdriver_data *data;
252dbcce9ddSDavid van Moolenbroek 	ssize_t r;
253dbcce9ddSDavid van Moolenbroek 
254dbcce9ddSDavid van Moolenbroek 	assert(netdriver_table != NULL);
255dbcce9ddSDavid van Moolenbroek 
256*f7df02e7SDavid van Moolenbroek 	while (pending_recvs > 0) {
257*f7df02e7SDavid van Moolenbroek 		data = &pending_recvq[pending_recvtail];
258dbcce9ddSDavid van Moolenbroek 
259dbcce9ddSDavid van Moolenbroek 		/*
260*f7df02e7SDavid van Moolenbroek 		 * For convenience of driver writers: if the receive function
261*f7df02e7SDavid van Moolenbroek 		 * returns zero, simply call it again, to simplify discarding
262*f7df02e7SDavid van Moolenbroek 		 * invalid packets.
263dbcce9ddSDavid van Moolenbroek 		 */
264*f7df02e7SDavid van Moolenbroek 		do {
265*f7df02e7SDavid van Moolenbroek 			r = netdriver_table->ndr_recv(data, data->size);
266*f7df02e7SDavid van Moolenbroek 
267*f7df02e7SDavid van Moolenbroek 			/*
268*f7df02e7SDavid van Moolenbroek 			 * The default policy is: drop undersized packets,
269*f7df02e7SDavid van Moolenbroek 			 * panic on oversized packets.  The driver may
270*f7df02e7SDavid van Moolenbroek 			 * implement any other policy (e.g., pad small packets,
271*f7df02e7SDavid van Moolenbroek 			 * drop or truncate large packets), but it should at
272*f7df02e7SDavid van Moolenbroek 			 * least test against the given 'max' value.  The
273*f7df02e7SDavid van Moolenbroek 			 * reason that truncation should be implemented in the
274*f7df02e7SDavid van Moolenbroek 			 * driver rather than here, is explained in an earlier
275*f7df02e7SDavid van Moolenbroek 			 * comment about truncating copy operations.
276*f7df02e7SDavid van Moolenbroek 			 */
277*f7df02e7SDavid van Moolenbroek 			if (r >= 0 && r < NDEV_ETH_PACKET_MIN)
278dbcce9ddSDavid van Moolenbroek 				r = 0;
279*f7df02e7SDavid van Moolenbroek 			else if (r > (ssize_t)data->size)
280*f7df02e7SDavid van Moolenbroek 				panic("netdriver: oversized packet returned: "
281*f7df02e7SDavid van Moolenbroek 				    "%zd", r);
282dbcce9ddSDavid van Moolenbroek 		} while (r == 0);
283dbcce9ddSDavid van Moolenbroek 
284dbcce9ddSDavid van Moolenbroek 		if (r == SUSPEND)
285*f7df02e7SDavid van Moolenbroek 			break;
286*f7df02e7SDavid van Moolenbroek 
287dbcce9ddSDavid van Moolenbroek 		if (r < 0)
288*f7df02e7SDavid van Moolenbroek 			panic("netdriver: driver reported receive failure: %d",
289*f7df02e7SDavid van Moolenbroek 			    r);
290dbcce9ddSDavid van Moolenbroek 
291*f7df02e7SDavid van Moolenbroek 		assert(r >= NDEV_ETH_PACKET_MIN && (size_t)r <= data->size);
292dbcce9ddSDavid van Moolenbroek 
293*f7df02e7SDavid van Moolenbroek 		finish_recv(r);
294*f7df02e7SDavid van Moolenbroek 	}
295dbcce9ddSDavid van Moolenbroek }
296dbcce9ddSDavid van Moolenbroek 
297dbcce9ddSDavid van Moolenbroek /*
298*f7df02e7SDavid van Moolenbroek  * A packet send request has finished.  Send a reply and clean up.
299*f7df02e7SDavid van Moolenbroek  */
300*f7df02e7SDavid van Moolenbroek static void
finish_send(int32_t result)301*f7df02e7SDavid van Moolenbroek finish_send(int32_t result)
302*f7df02e7SDavid van Moolenbroek {
303*f7df02e7SDavid van Moolenbroek 	struct netdriver_data *data;
304*f7df02e7SDavid van Moolenbroek 	message m;
305*f7df02e7SDavid van Moolenbroek 
306*f7df02e7SDavid van Moolenbroek 	assert(pending_sends > 0);
307*f7df02e7SDavid van Moolenbroek 
308*f7df02e7SDavid van Moolenbroek 	data = &pending_sendq[pending_sendtail];
309*f7df02e7SDavid van Moolenbroek 
310*f7df02e7SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
311*f7df02e7SDavid van Moolenbroek 	m.m_type = NDEV_SEND_REPLY;
312*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_reply.id = data->id;
313*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_reply.result = result;
314*f7df02e7SDavid van Moolenbroek 
315*f7df02e7SDavid van Moolenbroek 	send_reply(data->endpt, &m);
316*f7df02e7SDavid van Moolenbroek 
317*f7df02e7SDavid van Moolenbroek 	pending_sendtail = (pending_sendtail + 1) %
318*f7df02e7SDavid van Moolenbroek 	    __arraycount(pending_sendq);
319*f7df02e7SDavid van Moolenbroek 	pending_sends--;
320*f7df02e7SDavid van Moolenbroek }
321*f7df02e7SDavid van Moolenbroek 
322*f7df02e7SDavid van Moolenbroek /*
323*f7df02e7SDavid van Moolenbroek  * Resume sending packets.  In particular, if any send requests were pending,
324*f7df02e7SDavid van Moolenbroek  * call the driver's send function for each of them, until the driver can take
325*f7df02e7SDavid van Moolenbroek  * no more.  For each successful request is successful, send a reply to the
326*f7df02e7SDavid van Moolenbroek  * requesting party.
327dbcce9ddSDavid van Moolenbroek  */
328dbcce9ddSDavid van Moolenbroek void
netdriver_send(void)329dbcce9ddSDavid van Moolenbroek netdriver_send(void)
330dbcce9ddSDavid van Moolenbroek {
331*f7df02e7SDavid van Moolenbroek 	struct netdriver_data *data;
332dbcce9ddSDavid van Moolenbroek 	int r;
333dbcce9ddSDavid van Moolenbroek 
334dbcce9ddSDavid van Moolenbroek 	assert(netdriver_table != NULL);
335dbcce9ddSDavid van Moolenbroek 
336*f7df02e7SDavid van Moolenbroek 	while (pending_sends > 0) {
337*f7df02e7SDavid van Moolenbroek 		data = &pending_sendq[pending_sendtail];
338*f7df02e7SDavid van Moolenbroek 
339*f7df02e7SDavid van Moolenbroek 		r = netdriver_table->ndr_send(data, data->size);
340dbcce9ddSDavid van Moolenbroek 
341dbcce9ddSDavid van Moolenbroek 		if (r == SUSPEND)
342*f7df02e7SDavid van Moolenbroek 			break;
343*f7df02e7SDavid van Moolenbroek 
344dbcce9ddSDavid van Moolenbroek 		if (r < 0)
345*f7df02e7SDavid van Moolenbroek 			panic("netdriver: driver reported send failure: %d",
346*f7df02e7SDavid van Moolenbroek 			    r);
347dbcce9ddSDavid van Moolenbroek 
348*f7df02e7SDavid van Moolenbroek 		finish_send(r);
349*f7df02e7SDavid van Moolenbroek 	}
350dbcce9ddSDavid van Moolenbroek }
351dbcce9ddSDavid van Moolenbroek 
352dbcce9ddSDavid van Moolenbroek /*
353*f7df02e7SDavid van Moolenbroek  * Process a request to send or receive a packet.
354dbcce9ddSDavid van Moolenbroek  */
355dbcce9ddSDavid van Moolenbroek static void
do_transfer(const struct netdriver * __restrict ndp,const message * m_ptr,int do_write)356*f7df02e7SDavid van Moolenbroek do_transfer(const struct netdriver * __restrict ndp, const message * m_ptr,
357*f7df02e7SDavid van Moolenbroek 	int do_write)
358dbcce9ddSDavid van Moolenbroek {
359dbcce9ddSDavid van Moolenbroek 	struct netdriver_data *data;
360*f7df02e7SDavid van Moolenbroek 	cp_grant_id_t grant;
361*f7df02e7SDavid van Moolenbroek 	size_t size;
362dbcce9ddSDavid van Moolenbroek 	unsigned int i;
363dbcce9ddSDavid van Moolenbroek 
364*f7df02e7SDavid van Moolenbroek 	/* Prepare the local data structure. */
365*f7df02e7SDavid van Moolenbroek 	if (do_write) {
366*f7df02e7SDavid van Moolenbroek 		if (pending_sends == __arraycount(pending_sendq))
367*f7df02e7SDavid van Moolenbroek 			panic("netdriver: too many concurrent send requests");
368dbcce9ddSDavid van Moolenbroek 
369*f7df02e7SDavid van Moolenbroek 		data = &pending_sendq[(pending_sendtail + pending_sends) %
370*f7df02e7SDavid van Moolenbroek 		    __arraycount(pending_sendq)];
371*f7df02e7SDavid van Moolenbroek 	} else {
372*f7df02e7SDavid van Moolenbroek 		if (pending_recvs == __arraycount(pending_recvq))
373*f7df02e7SDavid van Moolenbroek 			panic("netdriver: too many concurrent receive "
374*f7df02e7SDavid van Moolenbroek 			    "requests");
375dbcce9ddSDavid van Moolenbroek 
376*f7df02e7SDavid van Moolenbroek 		data = &pending_recvq[(pending_recvtail + pending_recvs) %
377*f7df02e7SDavid van Moolenbroek 		    __arraycount(pending_recvq)];
378*f7df02e7SDavid van Moolenbroek 	}
379dbcce9ddSDavid van Moolenbroek 
380*f7df02e7SDavid van Moolenbroek 	data->endpt = m_ptr->m_source;
381*f7df02e7SDavid van Moolenbroek 	data->id = m_ptr->m_ndev_netdriver_transfer.id;
382*f7df02e7SDavid van Moolenbroek 	data->count = m_ptr->m_ndev_netdriver_transfer.count;
383dbcce9ddSDavid van Moolenbroek 
384*f7df02e7SDavid van Moolenbroek 	if (data->count == 0 || data->count > NDEV_IOV_MAX)
385*f7df02e7SDavid van Moolenbroek 		panic("netdriver: bad I/O vector count: %u", data->count);
386dbcce9ddSDavid van Moolenbroek 
387*f7df02e7SDavid van Moolenbroek 	data->size = 0;
388dbcce9ddSDavid van Moolenbroek 
389*f7df02e7SDavid van Moolenbroek 	for (i = 0; i < data->count; i++) {
390*f7df02e7SDavid van Moolenbroek 		grant = m_ptr->m_ndev_netdriver_transfer.grant[i];
391*f7df02e7SDavid van Moolenbroek 		size = (size_t)m_ptr->m_ndev_netdriver_transfer.len[i];
392*f7df02e7SDavid van Moolenbroek 
393*f7df02e7SDavid van Moolenbroek 		assert(size > 0);
394*f7df02e7SDavid van Moolenbroek 
395*f7df02e7SDavid van Moolenbroek 		data->iovec[i].iov_grant = grant;
396*f7df02e7SDavid van Moolenbroek 		data->iovec[i].iov_size = size;
397*f7df02e7SDavid van Moolenbroek 		data->size += size;
398*f7df02e7SDavid van Moolenbroek 	}
399*f7df02e7SDavid van Moolenbroek 
400*f7df02e7SDavid van Moolenbroek 	if (data->size < NDEV_ETH_PACKET_MIN ||
401*f7df02e7SDavid van Moolenbroek 	    (!do_write && data->size < NDEV_ETH_PACKET_MAX_TAGGED))
402dbcce9ddSDavid van Moolenbroek 		panic("netdriver: invalid I/O vector size: %zu\n", data->size);
403dbcce9ddSDavid van Moolenbroek 
404*f7df02e7SDavid van Moolenbroek 	if (do_write)
405*f7df02e7SDavid van Moolenbroek 		pending_sends++;
406*f7df02e7SDavid van Moolenbroek 	else
407*f7df02e7SDavid van Moolenbroek 		pending_recvs++;
408dbcce9ddSDavid van Moolenbroek 
409*f7df02e7SDavid van Moolenbroek 	/*
410*f7df02e7SDavid van Moolenbroek 	 * If the driver is down, immediately abort the request again.  This
411*f7df02e7SDavid van Moolenbroek 	 * is not a common case but does occur as part of queue draining by the
412*f7df02e7SDavid van Moolenbroek 	 * TCP/IP stack, and is way easier to handle here than up there..
413*f7df02e7SDavid van Moolenbroek 	 */
414*f7df02e7SDavid van Moolenbroek 	if (!up) {
415*f7df02e7SDavid van Moolenbroek 		if (do_write)
416*f7df02e7SDavid van Moolenbroek 			finish_send(EINTR);
417*f7df02e7SDavid van Moolenbroek 		else
418*f7df02e7SDavid van Moolenbroek 			finish_recv(EINTR);
419dbcce9ddSDavid van Moolenbroek 
420*f7df02e7SDavid van Moolenbroek 		return;
421*f7df02e7SDavid van Moolenbroek 	}
422*f7df02e7SDavid van Moolenbroek 
423*f7df02e7SDavid van Moolenbroek 	/* Otherwise, resume sending or receiving. */
4247c48de6cSDavid van Moolenbroek 	if (do_write)
425dbcce9ddSDavid van Moolenbroek 		netdriver_send();
426dbcce9ddSDavid van Moolenbroek 	else
427dbcce9ddSDavid van Moolenbroek 		netdriver_recv();
428dbcce9ddSDavid van Moolenbroek }
429dbcce9ddSDavid van Moolenbroek 
430dbcce9ddSDavid van Moolenbroek /*
431*f7df02e7SDavid van Moolenbroek  * Process a request to (re)configure the driver.
432dbcce9ddSDavid van Moolenbroek  */
433dbcce9ddSDavid van Moolenbroek static void
do_conf(const struct netdriver * __restrict ndp,const message * __restrict m_ptr)434dbcce9ddSDavid van Moolenbroek do_conf(const struct netdriver * __restrict ndp,
435dbcce9ddSDavid van Moolenbroek 	const message * __restrict m_ptr)
436dbcce9ddSDavid van Moolenbroek {
437*f7df02e7SDavid van Moolenbroek 	netdriver_addr_t mcast_list[NETDRIVER_MCAST_MAX];
438*f7df02e7SDavid van Moolenbroek 	uint32_t set, mode;
439*f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count;
440*f7df02e7SDavid van Moolenbroek 	message m;
441*f7df02e7SDavid van Moolenbroek 	int r;
442dbcce9ddSDavid van Moolenbroek 
443*f7df02e7SDavid van Moolenbroek 	set = m_ptr->m_ndev_netdriver_conf.set;
444*f7df02e7SDavid van Moolenbroek 	mode = m_ptr->m_ndev_netdriver_conf.mode;
445dbcce9ddSDavid van Moolenbroek 
446*f7df02e7SDavid van Moolenbroek 	/*
447*f7df02e7SDavid van Moolenbroek 	 * If the request includes taking down the interface, perform that step
448*f7df02e7SDavid van Moolenbroek 	 * first: it is expected that in many cases, changing other settings
449*f7df02e7SDavid van Moolenbroek 	 * requires stopping and restarting the device.
450*f7df02e7SDavid van Moolenbroek 	 */
451*f7df02e7SDavid van Moolenbroek 	if ((set & NDEV_SET_MODE) && mode == NDEV_MODE_DOWN &&
452*f7df02e7SDavid van Moolenbroek 	    ndp->ndr_set_mode != NULL)
453*f7df02e7SDavid van Moolenbroek 		ndp->ndr_set_mode(mode, NULL, 0);
454dbcce9ddSDavid van Moolenbroek 
455*f7df02e7SDavid van Moolenbroek 	if ((set & NDEV_SET_CAPS) && ndp->ndr_set_caps != NULL)
456*f7df02e7SDavid van Moolenbroek 		ndp->ndr_set_caps(m_ptr->m_ndev_netdriver_conf.caps);
457*f7df02e7SDavid van Moolenbroek 
458*f7df02e7SDavid van Moolenbroek 	if ((set & NDEV_SET_FLAGS) && ndp->ndr_set_flags != NULL)
459*f7df02e7SDavid van Moolenbroek 		ndp->ndr_set_flags(m_ptr->m_ndev_netdriver_conf.flags);
460*f7df02e7SDavid van Moolenbroek 
461*f7df02e7SDavid van Moolenbroek 	if ((set & NDEV_SET_MEDIA) && ndp->ndr_set_media != NULL)
462*f7df02e7SDavid van Moolenbroek 		ndp->ndr_set_media(m_ptr->m_ndev_netdriver_conf.media);
463*f7df02e7SDavid van Moolenbroek 
464*f7df02e7SDavid van Moolenbroek 	if ((set & NDEV_SET_HWADDR) && ndp->ndr_set_hwaddr != NULL) {
465*f7df02e7SDavid van Moolenbroek 		/* Save the new hardware address. */
466*f7df02e7SDavid van Moolenbroek 		memcpy(&device_hwaddr, m_ptr->m_ndev_netdriver_conf.hwaddr,
467*f7df02e7SDavid van Moolenbroek 		    sizeof(device_hwaddr));
468*f7df02e7SDavid van Moolenbroek 
469*f7df02e7SDavid van Moolenbroek 		ndp->ndr_set_hwaddr(&device_hwaddr);
470*f7df02e7SDavid van Moolenbroek 	}
471*f7df02e7SDavid van Moolenbroek 
472*f7df02e7SDavid van Moolenbroek 	if ((set & NDEV_SET_MODE) && mode != NDEV_MODE_DOWN &&
473*f7df02e7SDavid van Moolenbroek 	    ndp->ndr_set_mode != NULL) {
474*f7df02e7SDavid van Moolenbroek 		/*
475*f7df02e7SDavid van Moolenbroek 		 * If we have a multicast list, copy it in, unless it is too
476*f7df02e7SDavid van Moolenbroek 		 * large: in that case, enable all-multicast receipt mode.
477*f7df02e7SDavid van Moolenbroek 		 */
478*f7df02e7SDavid van Moolenbroek 		if ((mode & NDEV_MODE_MCAST_LIST) &&
479*f7df02e7SDavid van Moolenbroek 		    m_ptr->m_ndev_netdriver_conf.mcast_count >
480*f7df02e7SDavid van Moolenbroek 		    __arraycount(mcast_list)) {
481*f7df02e7SDavid van Moolenbroek 			mode &= ~NDEV_MODE_MCAST_LIST;
482*f7df02e7SDavid van Moolenbroek 			mode |= NDEV_MODE_MCAST_ALL;
483*f7df02e7SDavid van Moolenbroek 		}
484*f7df02e7SDavid van Moolenbroek 
485*f7df02e7SDavid van Moolenbroek 		if (mode & NDEV_MODE_MCAST_LIST) {
486*f7df02e7SDavid van Moolenbroek 			assert(m_ptr->m_ndev_netdriver_conf.mcast_grant !=
487*f7df02e7SDavid van Moolenbroek 			    GRANT_INVALID);
488*f7df02e7SDavid van Moolenbroek 
489*f7df02e7SDavid van Moolenbroek 			mcast_count = m_ptr->m_ndev_netdriver_conf.mcast_count;
490*f7df02e7SDavid van Moolenbroek 
491*f7df02e7SDavid van Moolenbroek 			if ((r = sys_safecopyfrom(m_ptr->m_source,
492*f7df02e7SDavid van Moolenbroek 			    m_ptr->m_ndev_netdriver_conf.mcast_grant, 0,
493*f7df02e7SDavid van Moolenbroek 			    (vir_bytes)mcast_list,
494*f7df02e7SDavid van Moolenbroek 			    mcast_count * sizeof(mcast_list[0]))) != OK)
495*f7df02e7SDavid van Moolenbroek 				panic("netdriver: unable to copy data: %d", r);
496*f7df02e7SDavid van Moolenbroek 
497*f7df02e7SDavid van Moolenbroek 			ndp->ndr_set_mode(mode, mcast_list, mcast_count);
498*f7df02e7SDavid van Moolenbroek 		} else
499*f7df02e7SDavid van Moolenbroek 			ndp->ndr_set_mode(mode, NULL, 0);
500*f7df02e7SDavid van Moolenbroek 	}
501*f7df02e7SDavid van Moolenbroek 
502*f7df02e7SDavid van Moolenbroek 	/* We always report OK: the caller cannot do anything upon failure. */
503*f7df02e7SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
504*f7df02e7SDavid van Moolenbroek 	m.m_type = NDEV_CONF_REPLY;
505*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_reply.id = m_ptr->m_ndev_netdriver_conf.id;
506*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_reply.result = OK;
507*f7df02e7SDavid van Moolenbroek 
508*f7df02e7SDavid van Moolenbroek 	send_reply(m_ptr->m_source, &m);
509*f7df02e7SDavid van Moolenbroek 
510*f7df02e7SDavid van Moolenbroek 	/*
511*f7df02e7SDavid van Moolenbroek 	 * Finally, if the device has been taken down, abort pending send and
512*f7df02e7SDavid van Moolenbroek 	 * receive requests.
513*f7df02e7SDavid van Moolenbroek 	 */
514*f7df02e7SDavid van Moolenbroek 	if (set & NDEV_SET_MODE) {
515*f7df02e7SDavid van Moolenbroek 		if (mode == NDEV_MODE_DOWN) {
516*f7df02e7SDavid van Moolenbroek 			while (pending_sends > 0)
517*f7df02e7SDavid van Moolenbroek 				finish_send(EINTR);
518*f7df02e7SDavid van Moolenbroek 
519*f7df02e7SDavid van Moolenbroek 			while (pending_recvs > 0)
520*f7df02e7SDavid van Moolenbroek 				finish_recv(EINTR);
521*f7df02e7SDavid van Moolenbroek 
522*f7df02e7SDavid van Moolenbroek 			up = FALSE;
523*f7df02e7SDavid van Moolenbroek 		} else
524*f7df02e7SDavid van Moolenbroek 			up = TRUE;
525*f7df02e7SDavid van Moolenbroek 	}
526dbcce9ddSDavid van Moolenbroek }
527dbcce9ddSDavid van Moolenbroek 
528dbcce9ddSDavid van Moolenbroek /*
529*f7df02e7SDavid van Moolenbroek  * Request an update of the link state and active media of the device.  This
530*f7df02e7SDavid van Moolenbroek  * routine may be called both from the driver and internally.
531dbcce9ddSDavid van Moolenbroek  */
532dbcce9ddSDavid van Moolenbroek static void
update_link(void)533*f7df02e7SDavid van Moolenbroek update_link(void)
534dbcce9ddSDavid van Moolenbroek {
535*f7df02e7SDavid van Moolenbroek 
536*f7df02e7SDavid van Moolenbroek 	if (netdriver_table->ndr_get_link != NULL)
537*f7df02e7SDavid van Moolenbroek 		device_link = netdriver_table->ndr_get_link(&device_media);
538*f7df02e7SDavid van Moolenbroek 
539*f7df02e7SDavid van Moolenbroek 	pending_link = FALSE;
540*f7df02e7SDavid van Moolenbroek }
541*f7df02e7SDavid van Moolenbroek 
542*f7df02e7SDavid van Moolenbroek /*
543*f7df02e7SDavid van Moolenbroek  * Attempt to send a status update to the endpoint registered to receive status
544*f7df02e7SDavid van Moolenbroek  * updates, if any.
545*f7df02e7SDavid van Moolenbroek  */
546*f7df02e7SDavid van Moolenbroek static void
send_status(void)547*f7df02e7SDavid van Moolenbroek send_status(void)
548*f7df02e7SDavid van Moolenbroek {
549*f7df02e7SDavid van Moolenbroek 	message m;
550dbcce9ddSDavid van Moolenbroek 	int r;
551dbcce9ddSDavid van Moolenbroek 
552*f7df02e7SDavid van Moolenbroek 	assert(pending_link || pending_stat);
553dbcce9ddSDavid van Moolenbroek 
554*f7df02e7SDavid van Moolenbroek 	if (status_endpt == NONE || pending_status)
555*f7df02e7SDavid van Moolenbroek 		return;
556dbcce9ddSDavid van Moolenbroek 
557*f7df02e7SDavid van Moolenbroek 	if (pending_link)
558*f7df02e7SDavid van Moolenbroek 		update_link();
559dbcce9ddSDavid van Moolenbroek 
560*f7df02e7SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
561*f7df02e7SDavid van Moolenbroek 	m.m_type = NDEV_STATUS;
562*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_status.id = 0;	/* for now */
563*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_status.link = device_link;
564*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_status.media = device_media;
565*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_status.oerror = stat_oerror;
566*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_status.coll = stat_coll;
567*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_status.ierror = stat_ierror;
568*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_status.iqdrop = stat_iqdrop;
569dbcce9ddSDavid van Moolenbroek 
570*f7df02e7SDavid van Moolenbroek 	if ((r = asynsend3(status_endpt, &m, AMF_NOREPLY)) != OK)
571*f7df02e7SDavid van Moolenbroek 		panic("netdriver: unable to send status: %d", r);
572*f7df02e7SDavid van Moolenbroek 
573*f7df02e7SDavid van Moolenbroek 	/*
574*f7df02e7SDavid van Moolenbroek 	 * Do not send another status message until either the one we just sent
575*f7df02e7SDavid van Moolenbroek 	 * gets acknowledged or we get a new initialization request.  This way
576*f7df02e7SDavid van Moolenbroek 	 * we get "natural pacing" (i.e., we avoid overflowing the asynsend
577*f7df02e7SDavid van Moolenbroek 	 * message queue by design) without using timers.
578*f7df02e7SDavid van Moolenbroek 	 */
579*f7df02e7SDavid van Moolenbroek 	pending_status = TRUE;
580*f7df02e7SDavid van Moolenbroek 
581*f7df02e7SDavid van Moolenbroek 	/*
582*f7df02e7SDavid van Moolenbroek 	 * The status message sends incremental updates for statistics.  This
583*f7df02e7SDavid van Moolenbroek 	 * means that while a restart of the TCP/IP stack means the statistics
584*f7df02e7SDavid van Moolenbroek 	 * are lost (not great), a restart of the driver leaves the statistics
585*f7df02e7SDavid van Moolenbroek 	 * mostly intact (more important).
586*f7df02e7SDavid van Moolenbroek 	 */
587*f7df02e7SDavid van Moolenbroek 	stat_oerror = 0;
588*f7df02e7SDavid van Moolenbroek 	stat_coll = 0;
589*f7df02e7SDavid van Moolenbroek 	stat_ierror = 0;
590*f7df02e7SDavid van Moolenbroek 	stat_iqdrop = 0;
591*f7df02e7SDavid van Moolenbroek 	pending_stat = FALSE;
592*f7df02e7SDavid van Moolenbroek }
593*f7df02e7SDavid van Moolenbroek 
594*f7df02e7SDavid van Moolenbroek /*
595*f7df02e7SDavid van Moolenbroek  * Process a reply to a status update that we sent earlier on (supposedly).
596*f7df02e7SDavid van Moolenbroek  */
597*f7df02e7SDavid van Moolenbroek static void
do_status_reply(const struct netdriver * __restrict ndp __unused,const message * __restrict m_ptr)598*f7df02e7SDavid van Moolenbroek do_status_reply(const struct netdriver * __restrict ndp __unused,
599*f7df02e7SDavid van Moolenbroek 	const message * __restrict m_ptr)
600*f7df02e7SDavid van Moolenbroek {
601*f7df02e7SDavid van Moolenbroek 
602*f7df02e7SDavid van Moolenbroek 	if (m_ptr->m_source != status_endpt)
603*f7df02e7SDavid van Moolenbroek 		return;
604*f7df02e7SDavid van Moolenbroek 
605*f7df02e7SDavid van Moolenbroek 	if (!pending_status || m_ptr->m_ndev_netdriver_status_reply.id != 0)
606*f7df02e7SDavid van Moolenbroek 		panic("netdriver: unexpected status reply");
607*f7df02e7SDavid van Moolenbroek 
608*f7df02e7SDavid van Moolenbroek 	pending_status = FALSE;
609*f7df02e7SDavid van Moolenbroek 
610*f7df02e7SDavid van Moolenbroek 	/*
611*f7df02e7SDavid van Moolenbroek 	 * If the local status has changed since our last status update,
612*f7df02e7SDavid van Moolenbroek 	 * send a new one right away.
613*f7df02e7SDavid van Moolenbroek 	 */
614*f7df02e7SDavid van Moolenbroek 	if (pending_link || pending_stat)
615*f7df02e7SDavid van Moolenbroek 		send_status();
616*f7df02e7SDavid van Moolenbroek }
617*f7df02e7SDavid van Moolenbroek 
618*f7df02e7SDavid van Moolenbroek /*
619*f7df02e7SDavid van Moolenbroek  * The driver reports that the link state and/or active media may have changed.
620*f7df02e7SDavid van Moolenbroek  * When convenient, request the new state from the driver and send a status
621*f7df02e7SDavid van Moolenbroek  * message to the TCP/IP stack.
622*f7df02e7SDavid van Moolenbroek  */
623*f7df02e7SDavid van Moolenbroek void
netdriver_link(void)624*f7df02e7SDavid van Moolenbroek netdriver_link(void)
625*f7df02e7SDavid van Moolenbroek {
626*f7df02e7SDavid van Moolenbroek 
627*f7df02e7SDavid van Moolenbroek 	pending_link = TRUE;
628*f7df02e7SDavid van Moolenbroek 
629*f7df02e7SDavid van Moolenbroek 	send_status();
630*f7df02e7SDavid van Moolenbroek }
631*f7df02e7SDavid van Moolenbroek 
632*f7df02e7SDavid van Moolenbroek /*
633*f7df02e7SDavid van Moolenbroek  * The driver reports that a number of output errors have occurred.  Update
634*f7df02e7SDavid van Moolenbroek  * statistics accordingly.
635*f7df02e7SDavid van Moolenbroek  */
636*f7df02e7SDavid van Moolenbroek void
netdriver_stat_oerror(uint32_t count)637*f7df02e7SDavid van Moolenbroek netdriver_stat_oerror(uint32_t count)
638*f7df02e7SDavid van Moolenbroek {
639*f7df02e7SDavid van Moolenbroek 
640*f7df02e7SDavid van Moolenbroek 	if (count == 0)
641*f7df02e7SDavid van Moolenbroek 		return;
642*f7df02e7SDavid van Moolenbroek 
643*f7df02e7SDavid van Moolenbroek 	stat_oerror += count;
644*f7df02e7SDavid van Moolenbroek 	pending_stat = TRUE;
645*f7df02e7SDavid van Moolenbroek 
646*f7df02e7SDavid van Moolenbroek 	send_status();
647*f7df02e7SDavid van Moolenbroek }
648*f7df02e7SDavid van Moolenbroek 
649*f7df02e7SDavid van Moolenbroek /*
650*f7df02e7SDavid van Moolenbroek  * The driver reports that one or more packet collisions have occurred.  Update
651*f7df02e7SDavid van Moolenbroek  * statistics accordingly.
652*f7df02e7SDavid van Moolenbroek  */
653*f7df02e7SDavid van Moolenbroek void
netdriver_stat_coll(uint32_t count)654*f7df02e7SDavid van Moolenbroek netdriver_stat_coll(uint32_t count)
655*f7df02e7SDavid van Moolenbroek {
656*f7df02e7SDavid van Moolenbroek 
657*f7df02e7SDavid van Moolenbroek 	if (count == 0)
658*f7df02e7SDavid van Moolenbroek 		return;
659*f7df02e7SDavid van Moolenbroek 
660*f7df02e7SDavid van Moolenbroek 	stat_coll += count;
661*f7df02e7SDavid van Moolenbroek 	pending_stat = TRUE;
662*f7df02e7SDavid van Moolenbroek 
663*f7df02e7SDavid van Moolenbroek 	send_status();
664*f7df02e7SDavid van Moolenbroek }
665*f7df02e7SDavid van Moolenbroek 
666*f7df02e7SDavid van Moolenbroek /*
667*f7df02e7SDavid van Moolenbroek  * The driver reports that a number of input errors have occurred.  Adjust
668*f7df02e7SDavid van Moolenbroek  * statistics accordingly.
669*f7df02e7SDavid van Moolenbroek  */
670*f7df02e7SDavid van Moolenbroek void
netdriver_stat_ierror(uint32_t count)671*f7df02e7SDavid van Moolenbroek netdriver_stat_ierror(uint32_t count)
672*f7df02e7SDavid van Moolenbroek {
673*f7df02e7SDavid van Moolenbroek 
674*f7df02e7SDavid van Moolenbroek 	if (count == 0)
675*f7df02e7SDavid van Moolenbroek 		return;
676*f7df02e7SDavid van Moolenbroek 
677*f7df02e7SDavid van Moolenbroek 	stat_ierror += count;
678*f7df02e7SDavid van Moolenbroek 	pending_stat = TRUE;
679*f7df02e7SDavid van Moolenbroek 
680*f7df02e7SDavid van Moolenbroek 	send_status();
681*f7df02e7SDavid van Moolenbroek }
682*f7df02e7SDavid van Moolenbroek 
683*f7df02e7SDavid van Moolenbroek /*
684*f7df02e7SDavid van Moolenbroek  * The driver reports that a number of input queue drops have occurred.  Update
685*f7df02e7SDavid van Moolenbroek  * statistics accordingly.
686*f7df02e7SDavid van Moolenbroek  */
687*f7df02e7SDavid van Moolenbroek void
netdriver_stat_iqdrop(uint32_t count)688*f7df02e7SDavid van Moolenbroek netdriver_stat_iqdrop(uint32_t count)
689*f7df02e7SDavid van Moolenbroek {
690*f7df02e7SDavid van Moolenbroek 
691*f7df02e7SDavid van Moolenbroek 	if (count == 0)
692*f7df02e7SDavid van Moolenbroek 		return;
693*f7df02e7SDavid van Moolenbroek 
694*f7df02e7SDavid van Moolenbroek 	stat_iqdrop += count;
695*f7df02e7SDavid van Moolenbroek 	pending_stat = TRUE;
696*f7df02e7SDavid van Moolenbroek 
697*f7df02e7SDavid van Moolenbroek 	send_status();
698*f7df02e7SDavid van Moolenbroek }
699*f7df02e7SDavid van Moolenbroek 
700*f7df02e7SDavid van Moolenbroek /*
701*f7df02e7SDavid van Moolenbroek  * Process an initialization request.  Actual initialization has already taken
702*f7df02e7SDavid van Moolenbroek  * place, so we simply report the information gathered at that time.  If the
703*f7df02e7SDavid van Moolenbroek  * caller (the TCP/IP stack) has crashed and restarted, we will get another
704*f7df02e7SDavid van Moolenbroek  * initialization request message, so keep the information up-to-date.
705*f7df02e7SDavid van Moolenbroek  */
706*f7df02e7SDavid van Moolenbroek static void
do_init(const struct netdriver * __restrict ndp,const message * __restrict m_ptr)707*f7df02e7SDavid van Moolenbroek do_init(const struct netdriver * __restrict ndp,
708*f7df02e7SDavid van Moolenbroek 	const message * __restrict m_ptr)
709*f7df02e7SDavid van Moolenbroek {
710*f7df02e7SDavid van Moolenbroek 	message m;
711*f7df02e7SDavid van Moolenbroek 
712*f7df02e7SDavid van Moolenbroek 	/*
713*f7df02e7SDavid van Moolenbroek 	 * First of all, an initialization request is a sure indication that
714*f7df02e7SDavid van Moolenbroek 	 * the caller does not have any send or receive requests pending, and
715*f7df02e7SDavid van Moolenbroek 	 * will not acknowledge our previous status request, if any.  Forget
716*f7df02e7SDavid van Moolenbroek 	 * any such previous requests and start sending status requests to the
717*f7df02e7SDavid van Moolenbroek 	 * (new) endpoint.
718*f7df02e7SDavid van Moolenbroek 	 */
719*f7df02e7SDavid van Moolenbroek 	pending_sends = 0;
720*f7df02e7SDavid van Moolenbroek 	pending_recvs = 0;
721*f7df02e7SDavid van Moolenbroek 	pending_status = FALSE;
722*f7df02e7SDavid van Moolenbroek 
723*f7df02e7SDavid van Moolenbroek 	status_endpt = m_ptr->m_source;
724*f7df02e7SDavid van Moolenbroek 
725*f7df02e7SDavid van Moolenbroek 	/*
726*f7df02e7SDavid van Moolenbroek 	 * Update link and media now, because we are about to send the initial
727*f7df02e7SDavid van Moolenbroek 	 * values of those to the caller as well.
728*f7df02e7SDavid van Moolenbroek 	 */
729*f7df02e7SDavid van Moolenbroek 	update_link();
730*f7df02e7SDavid van Moolenbroek 
731*f7df02e7SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
732*f7df02e7SDavid van Moolenbroek 	m.m_type = NDEV_INIT_REPLY;
733*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_init_reply.id = m_ptr->m_ndev_netdriver_init.id;
734*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_init_reply.link = device_link;
735*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_init_reply.media = device_media;
736*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_init_reply.caps = device_caps;
737*f7df02e7SDavid van Moolenbroek 	strlcpy(m.m_netdriver_ndev_init_reply.name, device_name,
738*f7df02e7SDavid van Moolenbroek 	    sizeof(m.m_netdriver_ndev_init_reply.name));
739*f7df02e7SDavid van Moolenbroek 	assert(sizeof(device_hwaddr) <=
740*f7df02e7SDavid van Moolenbroek 	    sizeof(m.m_netdriver_ndev_init_reply.hwaddr));
741*f7df02e7SDavid van Moolenbroek 	memcpy(m.m_netdriver_ndev_init_reply.hwaddr, &device_hwaddr,
742*f7df02e7SDavid van Moolenbroek 	    sizeof(device_hwaddr));
743*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_init_reply.hwaddr_len = sizeof(device_hwaddr);
744*f7df02e7SDavid van Moolenbroek 
745*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_init_reply.max_send = __arraycount(pending_sendq);
746*f7df02e7SDavid van Moolenbroek 	m.m_netdriver_ndev_init_reply.max_recv = __arraycount(pending_recvq);
747*f7df02e7SDavid van Moolenbroek 
748*f7df02e7SDavid van Moolenbroek 	send_reply(m_ptr->m_source, &m);
749*f7df02e7SDavid van Moolenbroek 
750*f7df02e7SDavid van Moolenbroek 	/*
751*f7df02e7SDavid van Moolenbroek 	 * Also send the current status.  This is not required by the protocol
752*f7df02e7SDavid van Moolenbroek 	 * and only serves to provide updated statistics to a new TCP/IP stack
753*f7df02e7SDavid van Moolenbroek 	 * instance right away.
754*f7df02e7SDavid van Moolenbroek 	 */
755*f7df02e7SDavid van Moolenbroek 	if (pending_stat)
756*f7df02e7SDavid van Moolenbroek 		send_status();
757dbcce9ddSDavid van Moolenbroek }
758dbcce9ddSDavid van Moolenbroek 
759dbcce9ddSDavid van Moolenbroek /*
760dbcce9ddSDavid van Moolenbroek  * Process an incoming message, and send a reply.
761dbcce9ddSDavid van Moolenbroek  */
762dbcce9ddSDavid van Moolenbroek void
netdriver_process(const struct netdriver * __restrict ndp,const message * __restrict m_ptr,int ipc_status)763dbcce9ddSDavid van Moolenbroek netdriver_process(const struct netdriver * __restrict ndp,
764dbcce9ddSDavid van Moolenbroek 	const message * __restrict m_ptr, int ipc_status)
765dbcce9ddSDavid van Moolenbroek {
766dbcce9ddSDavid van Moolenbroek 
767dbcce9ddSDavid van Moolenbroek 	netdriver_table = ndp;
768dbcce9ddSDavid van Moolenbroek 
769dbcce9ddSDavid van Moolenbroek 	/* Check for notifications first. */
770dbcce9ddSDavid van Moolenbroek 	if (is_ipc_notify(ipc_status)) {
771*f7df02e7SDavid van Moolenbroek 		switch (m_ptr->m_source) {
772dbcce9ddSDavid van Moolenbroek 		case HARDWARE:
773dbcce9ddSDavid van Moolenbroek 			if (ndp->ndr_intr != NULL)
774dbcce9ddSDavid van Moolenbroek 				ndp->ndr_intr(m_ptr->m_notify.interrupts);
775dbcce9ddSDavid van Moolenbroek 			break;
776dbcce9ddSDavid van Moolenbroek 
777dbcce9ddSDavid van Moolenbroek 		case CLOCK:
778*f7df02e7SDavid van Moolenbroek 			if (ndp->ndr_tick != NULL)
779*f7df02e7SDavid van Moolenbroek 				ndp->ndr_tick();
780*f7df02e7SDavid van Moolenbroek 
781*f7df02e7SDavid van Moolenbroek 			if (ticks > 0)
782*f7df02e7SDavid van Moolenbroek 				(void)sys_setalarm(ticks, FALSE /*abs_time*/);
783dbcce9ddSDavid van Moolenbroek 			break;
784dbcce9ddSDavid van Moolenbroek 
785dbcce9ddSDavid van Moolenbroek 		default:
786dbcce9ddSDavid van Moolenbroek 			if (ndp->ndr_other != NULL)
787dbcce9ddSDavid van Moolenbroek 				ndp->ndr_other(m_ptr, ipc_status);
788dbcce9ddSDavid van Moolenbroek 		}
789dbcce9ddSDavid van Moolenbroek 
790*f7df02e7SDavid van Moolenbroek 		return;
791dbcce9ddSDavid van Moolenbroek 	}
792dbcce9ddSDavid van Moolenbroek 
793dbcce9ddSDavid van Moolenbroek 	/*
794*f7df02e7SDavid van Moolenbroek 	 * Discard datalink requests preceding a first NDEV_INIT request, so
795*f7df02e7SDavid van Moolenbroek 	 * that after a driver restart, any in-flight request is discarded.
796*f7df02e7SDavid van Moolenbroek 	 * Note that for correct driver operation it is important that
797*f7df02e7SDavid van Moolenbroek 	 * non-datalink requests, and interrupts in particular, do not go
798*f7df02e7SDavid van Moolenbroek 	 * through this check.
799dbcce9ddSDavid van Moolenbroek 	 */
800*f7df02e7SDavid van Moolenbroek 	if (IS_NDEV_RQ(m_ptr->m_type) && init_expected) {
801*f7df02e7SDavid van Moolenbroek 		if (m_ptr->m_type != NDEV_INIT)
802dbcce9ddSDavid van Moolenbroek 			return; /* do not send a reply */
803dbcce9ddSDavid van Moolenbroek 
804*f7df02e7SDavid van Moolenbroek 		init_expected = FALSE;
805dbcce9ddSDavid van Moolenbroek 	}
806dbcce9ddSDavid van Moolenbroek 
807dbcce9ddSDavid van Moolenbroek 	switch (m_ptr->m_type) {
808*f7df02e7SDavid van Moolenbroek 	case NDEV_INIT:
809*f7df02e7SDavid van Moolenbroek 		do_init(ndp, m_ptr);
810*f7df02e7SDavid van Moolenbroek 		break;
811*f7df02e7SDavid van Moolenbroek 
812*f7df02e7SDavid van Moolenbroek 	case NDEV_CONF:
813dbcce9ddSDavid van Moolenbroek 		do_conf(ndp, m_ptr);
814dbcce9ddSDavid van Moolenbroek 		break;
815dbcce9ddSDavid van Moolenbroek 
816*f7df02e7SDavid van Moolenbroek 	case NDEV_SEND:
817*f7df02e7SDavid van Moolenbroek 		do_transfer(ndp, m_ptr, TRUE /*do_write*/);
818dbcce9ddSDavid van Moolenbroek 		break;
819dbcce9ddSDavid van Moolenbroek 
820*f7df02e7SDavid van Moolenbroek 	case NDEV_RECV:
821*f7df02e7SDavid van Moolenbroek 		do_transfer(ndp, m_ptr, FALSE /*do_write*/);
822dbcce9ddSDavid van Moolenbroek 		break;
823dbcce9ddSDavid van Moolenbroek 
824*f7df02e7SDavid van Moolenbroek 	case NDEV_STATUS_REPLY:
825*f7df02e7SDavid van Moolenbroek 		do_status_reply(ndp, m_ptr);
826dbcce9ddSDavid van Moolenbroek 		break;
827dbcce9ddSDavid van Moolenbroek 
828dbcce9ddSDavid van Moolenbroek 	default:
829dbcce9ddSDavid van Moolenbroek 		if (ndp->ndr_other != NULL)
830dbcce9ddSDavid van Moolenbroek 			ndp->ndr_other(m_ptr, ipc_status);
831dbcce9ddSDavid van Moolenbroek 	}
832dbcce9ddSDavid van Moolenbroek }
833dbcce9ddSDavid van Moolenbroek 
834dbcce9ddSDavid van Moolenbroek /*
835*f7df02e7SDavid van Moolenbroek  * Set a name for the device, based on the base name 'base' and the instance
836*f7df02e7SDavid van Moolenbroek  * number 'instance'.
837*f7df02e7SDavid van Moolenbroek  */
838*f7df02e7SDavid van Moolenbroek static void
netdriver_set_name(const char * base,unsigned int instance)839*f7df02e7SDavid van Moolenbroek netdriver_set_name(const char * base, unsigned int instance)
840*f7df02e7SDavid van Moolenbroek {
841*f7df02e7SDavid van Moolenbroek 	size_t len;
842*f7df02e7SDavid van Moolenbroek 
843*f7df02e7SDavid van Moolenbroek 	assert(instance <= 255);
844*f7df02e7SDavid van Moolenbroek 
845*f7df02e7SDavid van Moolenbroek 	len = strlen(base);
846*f7df02e7SDavid van Moolenbroek 	assert(len <= sizeof(device_name) - 4);
847*f7df02e7SDavid van Moolenbroek 
848*f7df02e7SDavid van Moolenbroek 	memcpy(device_name, base, len);
849*f7df02e7SDavid van Moolenbroek 	if (instance >= 100)
850*f7df02e7SDavid van Moolenbroek 		device_name[len++] = '0' + instance / 100;
851*f7df02e7SDavid van Moolenbroek 	if (instance >= 10)
852*f7df02e7SDavid van Moolenbroek 		device_name[len++] = '0' + (instance % 100) / 10;
853*f7df02e7SDavid van Moolenbroek 	device_name[len++] = '0' + instance % 10;
854*f7df02e7SDavid van Moolenbroek 	device_name[len] = 0;
855*f7df02e7SDavid van Moolenbroek }
856*f7df02e7SDavid van Moolenbroek 
857*f7df02e7SDavid van Moolenbroek /*
858*f7df02e7SDavid van Moolenbroek  * Return the device name generated at driver initialization time.
859*f7df02e7SDavid van Moolenbroek  */
860*f7df02e7SDavid van Moolenbroek const char *
netdriver_name(void)861*f7df02e7SDavid van Moolenbroek netdriver_name(void)
862*f7df02e7SDavid van Moolenbroek {
863*f7df02e7SDavid van Moolenbroek 
864*f7df02e7SDavid van Moolenbroek 	return device_name;
865*f7df02e7SDavid van Moolenbroek }
866*f7df02e7SDavid van Moolenbroek 
867*f7df02e7SDavid van Moolenbroek /*
868dbcce9ddSDavid van Moolenbroek  * Perform initialization.  Return OK or an error code.
869dbcce9ddSDavid van Moolenbroek  */
870dbcce9ddSDavid van Moolenbroek int
netdriver_init(const struct netdriver * ndp)871dbcce9ddSDavid van Moolenbroek netdriver_init(const struct netdriver * ndp)
872dbcce9ddSDavid van Moolenbroek {
873dbcce9ddSDavid van Moolenbroek 	unsigned int instance;
874dbcce9ddSDavid van Moolenbroek 	long v;
875dbcce9ddSDavid van Moolenbroek 	int r;
876dbcce9ddSDavid van Moolenbroek 
877dbcce9ddSDavid van Moolenbroek 	/* Initialize global variables. */
878*f7df02e7SDavid van Moolenbroek 	pending_sendtail = 0;
879*f7df02e7SDavid van Moolenbroek 	pending_sends = 0;
880*f7df02e7SDavid van Moolenbroek 	pending_recvtail = 0;
881*f7df02e7SDavid van Moolenbroek 	pending_recvs = 0;
882dbcce9ddSDavid van Moolenbroek 
883*f7df02e7SDavid van Moolenbroek 	memset(device_name, 0, sizeof(device_name));
884*f7df02e7SDavid van Moolenbroek 
885*f7df02e7SDavid van Moolenbroek 	memset(&device_hwaddr, 0, sizeof(device_hwaddr));
886*f7df02e7SDavid van Moolenbroek 	device_caps = 0;
887*f7df02e7SDavid van Moolenbroek 
888*f7df02e7SDavid van Moolenbroek 	/* Use sensible defaults for the link state and active media. */
889*f7df02e7SDavid van Moolenbroek 	device_link = NDEV_LINK_UNKNOWN;
890*f7df02e7SDavid van Moolenbroek 	device_media = IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0);
891*f7df02e7SDavid van Moolenbroek 
892*f7df02e7SDavid van Moolenbroek 	status_endpt = NONE;
893*f7df02e7SDavid van Moolenbroek 	pending_status = FALSE;
894*f7df02e7SDavid van Moolenbroek 	pending_link = FALSE;
895*f7df02e7SDavid van Moolenbroek 
896*f7df02e7SDavid van Moolenbroek 	up = FALSE;
897*f7df02e7SDavid van Moolenbroek 
898*f7df02e7SDavid van Moolenbroek 	ticks = 0;
899*f7df02e7SDavid van Moolenbroek 
900*f7df02e7SDavid van Moolenbroek 	/* Get the device instance number. */
901dbcce9ddSDavid van Moolenbroek 	v = 0;
902dbcce9ddSDavid van Moolenbroek 	(void)env_parse("instance", "d", 0, &v, 0, 255);
903dbcce9ddSDavid van Moolenbroek 	instance = (unsigned int)v;
904dbcce9ddSDavid van Moolenbroek 
905*f7df02e7SDavid van Moolenbroek 	/* Generate the full driver name. */
906*f7df02e7SDavid van Moolenbroek 	netdriver_set_name(ndp->ndr_name, instance);
907dbcce9ddSDavid van Moolenbroek 
908*f7df02e7SDavid van Moolenbroek 	/* Call the initialization routine. */
909*f7df02e7SDavid van Moolenbroek 	if ((r = ndp->ndr_init(instance, &device_hwaddr, &device_caps,
910*f7df02e7SDavid van Moolenbroek 	    &ticks)) != OK)
911dbcce9ddSDavid van Moolenbroek 		return r;
912dbcce9ddSDavid van Moolenbroek 
913dbcce9ddSDavid van Moolenbroek 	/* Announce we are up! */
914dbcce9ddSDavid van Moolenbroek 	netdriver_announce();
915dbcce9ddSDavid van Moolenbroek 
916*f7df02e7SDavid van Moolenbroek 	init_expected = TRUE;
917*f7df02e7SDavid van Moolenbroek 	running = TRUE;
918*f7df02e7SDavid van Moolenbroek 
919*f7df02e7SDavid van Moolenbroek 	if (ticks > 0)
920*f7df02e7SDavid van Moolenbroek 		(void)sys_setalarm(ticks, FALSE /*abs_time*/);
921*f7df02e7SDavid van Moolenbroek 
922433d6423SLionel Sambuc 	return OK;
923433d6423SLionel Sambuc }
924433d6423SLionel Sambuc 
925dbcce9ddSDavid van Moolenbroek /*
926*f7df02e7SDavid van Moolenbroek  * Perform SEF initialization.
927dbcce9ddSDavid van Moolenbroek  */
928dbcce9ddSDavid van Moolenbroek static int
local_init(int type __unused,sef_init_info_t * info __unused)929*f7df02e7SDavid van Moolenbroek local_init(int type __unused, sef_init_info_t * info __unused)
930dbcce9ddSDavid van Moolenbroek {
931dbcce9ddSDavid van Moolenbroek 
932*f7df02e7SDavid van Moolenbroek 	assert(netdriver_table != NULL);
933dbcce9ddSDavid van Moolenbroek 
934*f7df02e7SDavid van Moolenbroek 	return netdriver_init(netdriver_table);
935dbcce9ddSDavid van Moolenbroek }
936dbcce9ddSDavid van Moolenbroek 
937dbcce9ddSDavid van Moolenbroek /*
938dbcce9ddSDavid van Moolenbroek  * Break out of the main loop after finishing the current request.
939dbcce9ddSDavid van Moolenbroek  */
940dbcce9ddSDavid van Moolenbroek void
netdriver_terminate(void)941dbcce9ddSDavid van Moolenbroek netdriver_terminate(void)
942dbcce9ddSDavid van Moolenbroek {
943dbcce9ddSDavid van Moolenbroek 
944dbcce9ddSDavid van Moolenbroek 	if (netdriver_table != NULL && netdriver_table->ndr_stop != NULL)
945dbcce9ddSDavid van Moolenbroek 		netdriver_table->ndr_stop();
946dbcce9ddSDavid van Moolenbroek 
947dbcce9ddSDavid van Moolenbroek 	running = FALSE;
948dbcce9ddSDavid van Moolenbroek 
949dbcce9ddSDavid van Moolenbroek 	sef_cancel();
950dbcce9ddSDavid van Moolenbroek }
951dbcce9ddSDavid van Moolenbroek 
952dbcce9ddSDavid van Moolenbroek /*
953dbcce9ddSDavid van Moolenbroek  * The process has received a signal.  See if we have to terminate.
954dbcce9ddSDavid van Moolenbroek  */
955dbcce9ddSDavid van Moolenbroek static void
got_signal(int sig)956dbcce9ddSDavid van Moolenbroek got_signal(int sig)
957dbcce9ddSDavid van Moolenbroek {
958dbcce9ddSDavid van Moolenbroek 
959dbcce9ddSDavid van Moolenbroek 	if (sig != SIGTERM)
960dbcce9ddSDavid van Moolenbroek 		return;
961dbcce9ddSDavid van Moolenbroek 
962dbcce9ddSDavid van Moolenbroek 	netdriver_terminate();
963dbcce9ddSDavid van Moolenbroek }
964dbcce9ddSDavid van Moolenbroek 
965dbcce9ddSDavid van Moolenbroek /*
966dbcce9ddSDavid van Moolenbroek  * Main program of any network driver.
967dbcce9ddSDavid van Moolenbroek  */
968dbcce9ddSDavid van Moolenbroek void
netdriver_task(const struct netdriver * ndp)969dbcce9ddSDavid van Moolenbroek netdriver_task(const struct netdriver * ndp)
970dbcce9ddSDavid van Moolenbroek {
971dbcce9ddSDavid van Moolenbroek 	message mess;
972dbcce9ddSDavid van Moolenbroek 	int r, ipc_status;
973dbcce9ddSDavid van Moolenbroek 
974dbcce9ddSDavid van Moolenbroek 	/* Perform SEF initialization. */
975*f7df02e7SDavid van Moolenbroek 	sef_setcb_init_fresh(local_init);
976dbcce9ddSDavid van Moolenbroek 	sef_setcb_signal_handler(got_signal);
977dbcce9ddSDavid van Moolenbroek 
978dbcce9ddSDavid van Moolenbroek 	netdriver_table = ndp;
979dbcce9ddSDavid van Moolenbroek 
980dbcce9ddSDavid van Moolenbroek 	sef_startup();
981dbcce9ddSDavid van Moolenbroek 
982dbcce9ddSDavid van Moolenbroek 	/* The main message loop. */
983dbcce9ddSDavid van Moolenbroek 	while (running) {
984dbcce9ddSDavid van Moolenbroek 		if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) {
985dbcce9ddSDavid van Moolenbroek 			if (r == EINTR)
986dbcce9ddSDavid van Moolenbroek 				continue;	/* sef_cancel() was called */
987dbcce9ddSDavid van Moolenbroek 
988dbcce9ddSDavid van Moolenbroek 			panic("netdriver: sef_receive_status failed: %d", r);
989dbcce9ddSDavid van Moolenbroek 		}
990dbcce9ddSDavid van Moolenbroek 
991dbcce9ddSDavid van Moolenbroek 		netdriver_process(ndp, &mess, ipc_status);
992dbcce9ddSDavid van Moolenbroek 	}
993dbcce9ddSDavid van Moolenbroek }
994