xref: /freebsd/stand/libsa/netif.c (revision 2e3f49888ec8851bafb22011533217487764fdb0)
1 /*	$NetBSD: netif.c,v 1.10 1997/09/06 13:57:14 drochner Exp $	*/
2 
3 /*
4  * Copyright (c) 1993 Adam Glass
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Adam Glass.
18  * 4. The name of the Author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/cdefs.h>
37 #include <string.h>
38 
39 #include <netinet/in.h>
40 #include <netinet/in_systm.h>
41 
42 #include "stand.h"
43 #include "net.h"
44 #include "netif.h"
45 
46 typedef TAILQ_HEAD(socket_list, iodesc) socket_list_t;
47 
48 /*
49  * Open socket list. The current implementation and assumption is,
50  * we only remove entries from tail and we only add new entries to tail.
51  * This decision is to keep iodesc id management simple - we get list
52  * entries ordered by continiously growing io_id field.
53  * If we do have multiple sockets open and we do close socket not from tail,
54  * this entry will be marked unused. netif_open() will reuse unused entry, or
55  * netif_close() will free all unused tail entries.
56  */
57 static socket_list_t sockets = TAILQ_HEAD_INITIALIZER(sockets);
58 
59 #ifdef NETIF_DEBUG
60 int netif_debug = 0;
61 #endif
62 
63 /*
64  * netif_init:
65  *
66  * initialize the generic network interface layer
67  */
68 
69 void
70 netif_init(void)
71 {
72 	struct netif_driver *drv;
73 	int d, i;
74 
75 #ifdef NETIF_DEBUG
76 	if (netif_debug)
77 		printf("netif_init: called\n");
78 #endif
79 	for (d = 0; netif_drivers[d]; d++) {
80 		drv = netif_drivers[d];
81 		for (i = 0; i < drv->netif_nifs; i++)
82 			drv->netif_ifs[i].dif_used = 0;
83 	}
84 }
85 
86 int
87 netif_match(struct netif *nif, void *machdep_hint)
88 {
89 	struct netif_driver *drv = nif->nif_driver;
90 
91 #ifdef NETIF_DEBUG
92 	if (netif_debug)
93 		printf("%s%d: netif_match (%d)\n", drv->netif_bname,
94 		    nif->nif_unit, nif->nif_sel);
95 #endif
96 	return drv->netif_match(nif, machdep_hint);
97 }
98 
99 struct netif *
100 netif_select(void *machdep_hint)
101 {
102 	int d, u, s;
103 	struct netif_driver *drv;
104 	struct netif cur_if;
105 	static struct netif best_if;
106 	int best_val;
107 	int val;
108 
109 	best_val = 0;
110 	best_if.nif_driver = NULL;
111 
112 	for (d = 0; netif_drivers[d] != NULL; d++) {
113 		cur_if.nif_driver = netif_drivers[d];
114 		drv = cur_if.nif_driver;
115 
116 		for (u = 0; u < drv->netif_nifs; u++) {
117 			cur_if.nif_unit = u;
118 
119 #ifdef NETIF_DEBUG
120 			if (netif_debug)
121 				printf("\t%s%d:", drv->netif_bname,
122 				    cur_if.nif_unit);
123 #endif
124 
125 			for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) {
126 				cur_if.nif_sel = s;
127 
128 				if (drv->netif_ifs[u].dif_used & (1 << s)) {
129 #ifdef NETIF_DEBUG
130 					if (netif_debug)
131 						printf(" [%d used]", s);
132 #endif
133 					continue;
134 				}
135 
136 				val = netif_match(&cur_if, machdep_hint);
137 #ifdef NETIF_DEBUG
138 				if (netif_debug)
139 					printf(" [%d -> %d]", s, val);
140 #endif
141 				if (val > best_val) {
142 					best_val = val;
143 					best_if = cur_if;
144 				}
145 			}
146 #ifdef NETIF_DEBUG
147 			if (netif_debug)
148 				printf("\n");
149 #endif
150 		}
151 	}
152 
153 	if (best_if.nif_driver == NULL)
154 		return NULL;
155 
156 	best_if.nif_driver->
157 	    netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel);
158 
159 #ifdef NETIF_DEBUG
160 	if (netif_debug)
161 		printf("netif_select: %s%d(%d) wins\n",
162 			best_if.nif_driver->netif_bname,
163 			best_if.nif_unit, best_if.nif_sel);
164 #endif
165 	return &best_if;
166 }
167 
168 int
169 netif_probe(struct netif *nif, void *machdep_hint)
170 {
171 	struct netif_driver *drv = nif->nif_driver;
172 
173 #ifdef NETIF_DEBUG
174 	if (netif_debug)
175 		printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit);
176 #endif
177 	return drv->netif_probe(nif, machdep_hint);
178 }
179 
180 void
181 netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint)
182 {
183 	struct netif_driver *drv = nif->nif_driver;
184 
185 #ifdef NETIF_DEBUG
186 	if (netif_debug)
187 		printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit);
188 #endif
189 	desc->io_netif = nif;
190 #ifdef PARANOID
191 	if (drv->netif_init == NULL)
192 		panic("%s%d: no netif_init support", drv->netif_bname,
193 		    nif->nif_unit);
194 #endif
195 	drv->netif_init(desc, machdep_hint);
196 	bzero(drv->netif_ifs[nif->nif_unit].dif_stats,
197 	    sizeof(struct netif_stats));
198 }
199 
200 void
201 netif_detach(struct netif *nif)
202 {
203 	struct netif_driver *drv = nif->nif_driver;
204 
205 #ifdef NETIF_DEBUG
206 	if (netif_debug)
207 		printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit);
208 #endif
209 #ifdef PARANOID
210 	if (drv->netif_end == NULL)
211 		panic("%s%d: no netif_end support", drv->netif_bname,
212 		    nif->nif_unit);
213 #endif
214 	drv->netif_end(nif);
215 }
216 
217 ssize_t
218 netif_get(struct iodesc *desc, void **pkt, time_t timo)
219 {
220 #ifdef NETIF_DEBUG
221 	struct netif *nif = desc->io_netif;
222 #endif
223 	struct netif_driver *drv = desc->io_netif->nif_driver;
224 	ssize_t rv;
225 
226 #ifdef NETIF_DEBUG
227 	if (netif_debug)
228 		printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit);
229 #endif
230 #ifdef PARANOID
231 	if (drv->netif_get == NULL)
232 		panic("%s%d: no netif_get support", drv->netif_bname,
233 		    nif->nif_unit);
234 #endif
235 	rv = drv->netif_get(desc, pkt, timo);
236 #ifdef NETIF_DEBUG
237 	if (netif_debug)
238 		printf("%s%d: netif_get returning %d\n", drv->netif_bname,
239 		    nif->nif_unit, (int)rv);
240 #endif
241 	return (rv);
242 }
243 
244 ssize_t
245 netif_put(struct iodesc *desc, void *pkt, size_t len)
246 {
247 #ifdef NETIF_DEBUG
248 	struct netif *nif = desc->io_netif;
249 #endif
250 	struct netif_driver *drv = desc->io_netif->nif_driver;
251 	ssize_t rv;
252 
253 #ifdef NETIF_DEBUG
254 	if (netif_debug)
255 		printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit);
256 #endif
257 #ifdef PARANOID
258 	if (drv->netif_put == NULL)
259 		panic("%s%d: no netif_put support", drv->netif_bname,
260 		    nif->nif_unit);
261 #endif
262 	rv = drv->netif_put(desc, pkt, len);
263 #ifdef NETIF_DEBUG
264 	if (netif_debug)
265 		printf("%s%d: netif_put returning %d\n", drv->netif_bname,
266 		    nif->nif_unit, (int)rv);
267 #endif
268 	return (rv);
269 }
270 
271 /*
272  * socktodesc_impl:
273  *
274  * Walk socket list and return pointer to iodesc structure.
275  * if id is < 0, return first unused iodesc.
276  */
277 static struct iodesc *
278 socktodesc_impl(int socket)
279 {
280 	struct iodesc *s;
281 
282 	TAILQ_FOREACH(s, &sockets, io_link) {
283 		/* search by socket id */
284 		if (socket >= 0) {
285 			if (s->io_id == socket)
286 				break;
287 			continue;
288 		}
289 		/* search for first unused entry */
290 		if (s->io_netif == NULL)
291 			break;
292 	}
293 	return (s);
294 }
295 
296 struct iodesc *
297 socktodesc(int sock)
298 {
299 	struct iodesc *desc;
300 
301 	if (sock < 0)
302 		desc = NULL;
303 	else
304 		desc = socktodesc_impl(sock);
305 
306 	if (desc == NULL)
307 		errno = EBADF;
308 
309 	return (desc);
310 }
311 
312 int
313 netif_open(void *machdep_hint)
314 {
315 	struct iodesc *s;
316 	struct netif *nif;
317 
318 	/* find a free socket */
319 	s = socktodesc_impl(-1);
320 	if (s == NULL) {
321 		struct iodesc *last;
322 
323 		s = calloc(1, sizeof (*s));
324 		if (s == NULL)
325 			return (-1);
326 
327 		last = TAILQ_LAST(&sockets, socket_list);
328 		if (last != NULL)
329 			s->io_id = last->io_id + 1;
330 		TAILQ_INSERT_TAIL(&sockets, s, io_link);
331 	}
332 
333 	netif_init();
334 	nif = netif_select(machdep_hint);
335 	if (!nif)
336 		panic("netboot: no interfaces left untried");
337 	if (netif_probe(nif, machdep_hint)) {
338 		printf("netboot: couldn't probe %s%d\n",
339 		    nif->nif_driver->netif_bname, nif->nif_unit);
340 		errno = EINVAL;
341 		return (-1);
342 	}
343 	netif_attach(nif, s, machdep_hint);
344 
345 	return (s->io_id);
346 }
347 
348 int
349 netif_close(int sock)
350 {
351 	struct iodesc *s, *last;
352 	int err;
353 
354 	err = 0;
355 	s = socktodesc_impl(sock);
356 	if (s == NULL || sock < 0) {
357 		err = EBADF;
358 		return (-1);
359 	}
360 	netif_detach(s->io_netif);
361 	bzero(&s->destip, sizeof (s->destip));
362 	bzero(&s->myip, sizeof (s->myip));
363 	s->destport = 0;
364 	s->myport = 0;
365 	s->xid = 0;
366 	bzero(s->myea, sizeof (s->myea));
367 	s->io_netif = NULL;
368 
369 	/* free unused entries from tail. */
370 	TAILQ_FOREACH_REVERSE_SAFE(last, &sockets, socket_list, io_link, s) {
371 		if (last->io_netif != NULL)
372 			break;
373 		TAILQ_REMOVE(&sockets, last, io_link);
374 		free(last);
375 	}
376 
377 	if (err) {
378 		errno = err;
379 		return (-1);
380 	}
381 
382 	return (0);
383 }
384