1ca987d46SWarner Losh /* $NetBSD: netif.c,v 1.10 1997/09/06 13:57:14 drochner Exp $ */
2ca987d46SWarner Losh
3ca987d46SWarner Losh /*
4ca987d46SWarner Losh * Copyright (c) 1993 Adam Glass
5ca987d46SWarner Losh * All rights reserved.
6ca987d46SWarner Losh *
7ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without
8ca987d46SWarner Losh * modification, are permitted provided that the following conditions
9ca987d46SWarner Losh * are met:
10ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright
11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer.
12ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright
13ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the
14ca987d46SWarner Losh * documentation and/or other materials provided with the distribution.
15ca987d46SWarner Losh * 3. All advertising materials mentioning features or use of this software
16ca987d46SWarner Losh * must display the following acknowledgement:
17ca987d46SWarner Losh * This product includes software developed by Adam Glass.
18ca987d46SWarner Losh * 4. The name of the Author may not be used to endorse or promote products
19ca987d46SWarner Losh * derived from this software without specific prior written permission.
20ca987d46SWarner Losh *
21ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
22ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31ca987d46SWarner Losh * SUCH DAMAGE.
32ca987d46SWarner Losh */
33ca987d46SWarner Losh
34ca987d46SWarner Losh #include <sys/param.h>
35ca987d46SWarner Losh #include <sys/types.h>
36ca987d46SWarner Losh #include <string.h>
37ca987d46SWarner Losh
38ca987d46SWarner Losh #include <netinet/in.h>
39ca987d46SWarner Losh #include <netinet/in_systm.h>
40ca987d46SWarner Losh
41ca987d46SWarner Losh #include "stand.h"
42ca987d46SWarner Losh #include "net.h"
43ca987d46SWarner Losh #include "netif.h"
44ca987d46SWarner Losh
4597cbd5e7SToomas Soome typedef TAILQ_HEAD(socket_list, iodesc) socket_list_t;
4697cbd5e7SToomas Soome
4797cbd5e7SToomas Soome /*
4897cbd5e7SToomas Soome * Open socket list. The current implementation and assumption is,
4997cbd5e7SToomas Soome * we only remove entries from tail and we only add new entries to tail.
5097cbd5e7SToomas Soome * This decision is to keep iodesc id management simple - we get list
5197cbd5e7SToomas Soome * entries ordered by continiously growing io_id field.
5297cbd5e7SToomas Soome * If we do have multiple sockets open and we do close socket not from tail,
5397cbd5e7SToomas Soome * this entry will be marked unused. netif_open() will reuse unused entry, or
5497cbd5e7SToomas Soome * netif_close() will free all unused tail entries.
5597cbd5e7SToomas Soome */
5697cbd5e7SToomas Soome static socket_list_t sockets = TAILQ_HEAD_INITIALIZER(sockets);
5797cbd5e7SToomas Soome
58ca987d46SWarner Losh #ifdef NETIF_DEBUG
59ca987d46SWarner Losh int netif_debug = 0;
60ca987d46SWarner Losh #endif
61ca987d46SWarner Losh
62ca987d46SWarner Losh /*
63ca987d46SWarner Losh * netif_init:
64ca987d46SWarner Losh *
65ca987d46SWarner Losh * initialize the generic network interface layer
66ca987d46SWarner Losh */
67ca987d46SWarner Losh
68ca987d46SWarner Losh void
netif_init(void)69ca987d46SWarner Losh netif_init(void)
70ca987d46SWarner Losh {
71ca987d46SWarner Losh struct netif_driver *drv;
72ca987d46SWarner Losh int d, i;
73ca987d46SWarner Losh
74ca987d46SWarner Losh #ifdef NETIF_DEBUG
75ca987d46SWarner Losh if (netif_debug)
76ca987d46SWarner Losh printf("netif_init: called\n");
77ca987d46SWarner Losh #endif
78ca987d46SWarner Losh for (d = 0; netif_drivers[d]; d++) {
79ca987d46SWarner Losh drv = netif_drivers[d];
80ca987d46SWarner Losh for (i = 0; i < drv->netif_nifs; i++)
81ca987d46SWarner Losh drv->netif_ifs[i].dif_used = 0;
82ca987d46SWarner Losh }
83ca987d46SWarner Losh }
84ca987d46SWarner Losh
85ca987d46SWarner Losh int
netif_match(struct netif * nif,void * machdep_hint)86ca987d46SWarner Losh netif_match(struct netif *nif, void *machdep_hint)
87ca987d46SWarner Losh {
88ca987d46SWarner Losh struct netif_driver *drv = nif->nif_driver;
89ca987d46SWarner Losh
90*7b54d275SMichał Grzelak #ifdef NETIF_DEBUG
91ca987d46SWarner Losh if (netif_debug)
92ca987d46SWarner Losh printf("%s%d: netif_match (%d)\n", drv->netif_bname,
93ca987d46SWarner Losh nif->nif_unit, nif->nif_sel);
94ca987d46SWarner Losh #endif
95ca987d46SWarner Losh return drv->netif_match(nif, machdep_hint);
96ca987d46SWarner Losh }
97ca987d46SWarner Losh
98ca987d46SWarner Losh struct netif *
netif_select(void * machdep_hint)99ca987d46SWarner Losh netif_select(void *machdep_hint)
100ca987d46SWarner Losh {
10158e354ecSWarner Losh int d, u, s;
102ca987d46SWarner Losh struct netif_driver *drv;
103ca987d46SWarner Losh struct netif cur_if;
104ca987d46SWarner Losh static struct netif best_if;
105ca987d46SWarner Losh int best_val;
106ca987d46SWarner Losh int val;
107ca987d46SWarner Losh
108ca987d46SWarner Losh best_val = 0;
109ca987d46SWarner Losh best_if.nif_driver = NULL;
110ca987d46SWarner Losh
111ca987d46SWarner Losh for (d = 0; netif_drivers[d] != NULL; d++) {
112ca987d46SWarner Losh cur_if.nif_driver = netif_drivers[d];
113ca987d46SWarner Losh drv = cur_if.nif_driver;
114ca987d46SWarner Losh
115ca987d46SWarner Losh for (u = 0; u < drv->netif_nifs; u++) {
116ca987d46SWarner Losh cur_if.nif_unit = u;
117ca987d46SWarner Losh
118ca987d46SWarner Losh #ifdef NETIF_DEBUG
119ca987d46SWarner Losh if (netif_debug)
120ca987d46SWarner Losh printf("\t%s%d:", drv->netif_bname,
121ca987d46SWarner Losh cur_if.nif_unit);
122ca987d46SWarner Losh #endif
123ca987d46SWarner Losh
124ca987d46SWarner Losh for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) {
125ca987d46SWarner Losh cur_if.nif_sel = s;
126ca987d46SWarner Losh
127ca987d46SWarner Losh if (drv->netif_ifs[u].dif_used & (1 << s)) {
128ca987d46SWarner Losh #ifdef NETIF_DEBUG
129ca987d46SWarner Losh if (netif_debug)
130ca987d46SWarner Losh printf(" [%d used]", s);
131ca987d46SWarner Losh #endif
132ca987d46SWarner Losh continue;
133ca987d46SWarner Losh }
134ca987d46SWarner Losh
135ca987d46SWarner Losh val = netif_match(&cur_if, machdep_hint);
136ca987d46SWarner Losh #ifdef NETIF_DEBUG
137ca987d46SWarner Losh if (netif_debug)
138ca987d46SWarner Losh printf(" [%d -> %d]", s, val);
139ca987d46SWarner Losh #endif
140ca987d46SWarner Losh if (val > best_val) {
141ca987d46SWarner Losh best_val = val;
142ca987d46SWarner Losh best_if = cur_if;
143ca987d46SWarner Losh }
144ca987d46SWarner Losh }
145ca987d46SWarner Losh #ifdef NETIF_DEBUG
146ca987d46SWarner Losh if (netif_debug)
147ca987d46SWarner Losh printf("\n");
148ca987d46SWarner Losh #endif
149ca987d46SWarner Losh }
150ca987d46SWarner Losh }
151ca987d46SWarner Losh
152ca987d46SWarner Losh if (best_if.nif_driver == NULL)
153ca987d46SWarner Losh return NULL;
154ca987d46SWarner Losh
155ca987d46SWarner Losh best_if.nif_driver->
156ca987d46SWarner Losh netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel);
157ca987d46SWarner Losh
158ca987d46SWarner Losh #ifdef NETIF_DEBUG
159ca987d46SWarner Losh if (netif_debug)
160ca987d46SWarner Losh printf("netif_select: %s%d(%d) wins\n",
161ca987d46SWarner Losh best_if.nif_driver->netif_bname,
162ca987d46SWarner Losh best_if.nif_unit, best_if.nif_sel);
163ca987d46SWarner Losh #endif
164ca987d46SWarner Losh return &best_if;
165ca987d46SWarner Losh }
166ca987d46SWarner Losh
167ca987d46SWarner Losh int
netif_probe(struct netif * nif,void * machdep_hint)168ca987d46SWarner Losh netif_probe(struct netif *nif, void *machdep_hint)
169ca987d46SWarner Losh {
170ca987d46SWarner Losh struct netif_driver *drv = nif->nif_driver;
171ca987d46SWarner Losh
172ca987d46SWarner Losh #ifdef NETIF_DEBUG
173ca987d46SWarner Losh if (netif_debug)
174ca987d46SWarner Losh printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit);
175ca987d46SWarner Losh #endif
176ca987d46SWarner Losh return drv->netif_probe(nif, machdep_hint);
177ca987d46SWarner Losh }
178ca987d46SWarner Losh
179ca987d46SWarner Losh void
netif_attach(struct netif * nif,struct iodesc * desc,void * machdep_hint)180ca987d46SWarner Losh netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint)
181ca987d46SWarner Losh {
182ca987d46SWarner Losh struct netif_driver *drv = nif->nif_driver;
183ca987d46SWarner Losh
184ca987d46SWarner Losh #ifdef NETIF_DEBUG
185ca987d46SWarner Losh if (netif_debug)
186ca987d46SWarner Losh printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit);
187ca987d46SWarner Losh #endif
188ca987d46SWarner Losh desc->io_netif = nif;
189ca987d46SWarner Losh #ifdef PARANOID
190ca987d46SWarner Losh if (drv->netif_init == NULL)
19155d5c949SMaxim Sobolev panic("%s%d: no netif_init support", drv->netif_bname,
192ca987d46SWarner Losh nif->nif_unit);
193ca987d46SWarner Losh #endif
194ca987d46SWarner Losh drv->netif_init(desc, machdep_hint);
195ca987d46SWarner Losh bzero(drv->netif_ifs[nif->nif_unit].dif_stats,
196ca987d46SWarner Losh sizeof(struct netif_stats));
197ca987d46SWarner Losh }
198ca987d46SWarner Losh
199ca987d46SWarner Losh void
netif_detach(struct netif * nif)200ca987d46SWarner Losh netif_detach(struct netif *nif)
201ca987d46SWarner Losh {
202ca987d46SWarner Losh struct netif_driver *drv = nif->nif_driver;
203ca987d46SWarner Losh
204ca987d46SWarner Losh #ifdef NETIF_DEBUG
205ca987d46SWarner Losh if (netif_debug)
206ca987d46SWarner Losh printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit);
207ca987d46SWarner Losh #endif
208ca987d46SWarner Losh #ifdef PARANOID
209ca987d46SWarner Losh if (drv->netif_end == NULL)
21055d5c949SMaxim Sobolev panic("%s%d: no netif_end support", drv->netif_bname,
211ca987d46SWarner Losh nif->nif_unit);
212ca987d46SWarner Losh #endif
213ca987d46SWarner Losh drv->netif_end(nif);
214ca987d46SWarner Losh }
215ca987d46SWarner Losh
216ca987d46SWarner Losh ssize_t
netif_get(struct iodesc * desc,void ** pkt,time_t timo)217ca987d46SWarner Losh netif_get(struct iodesc *desc, void **pkt, time_t timo)
218ca987d46SWarner Losh {
219ca987d46SWarner Losh #ifdef NETIF_DEBUG
220ca987d46SWarner Losh struct netif *nif = desc->io_netif;
221ca987d46SWarner Losh #endif
222ca987d46SWarner Losh struct netif_driver *drv = desc->io_netif->nif_driver;
223ca987d46SWarner Losh ssize_t rv;
224ca987d46SWarner Losh
225ca987d46SWarner Losh #ifdef NETIF_DEBUG
226ca987d46SWarner Losh if (netif_debug)
227ca987d46SWarner Losh printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit);
228ca987d46SWarner Losh #endif
229ca987d46SWarner Losh #ifdef PARANOID
230ca987d46SWarner Losh if (drv->netif_get == NULL)
23155d5c949SMaxim Sobolev panic("%s%d: no netif_get support", drv->netif_bname,
232ca987d46SWarner Losh nif->nif_unit);
233ca987d46SWarner Losh #endif
234ca987d46SWarner Losh rv = drv->netif_get(desc, pkt, timo);
235ca987d46SWarner Losh #ifdef NETIF_DEBUG
236ca987d46SWarner Losh if (netif_debug)
237ca987d46SWarner Losh printf("%s%d: netif_get returning %d\n", drv->netif_bname,
238ca987d46SWarner Losh nif->nif_unit, (int)rv);
239ca987d46SWarner Losh #endif
240ca987d46SWarner Losh return (rv);
241ca987d46SWarner Losh }
242ca987d46SWarner Losh
243ca987d46SWarner Losh ssize_t
netif_put(struct iodesc * desc,void * pkt,size_t len)244ca987d46SWarner Losh netif_put(struct iodesc *desc, void *pkt, size_t len)
245ca987d46SWarner Losh {
246ca987d46SWarner Losh #ifdef NETIF_DEBUG
247ca987d46SWarner Losh struct netif *nif = desc->io_netif;
248ca987d46SWarner Losh #endif
249ca987d46SWarner Losh struct netif_driver *drv = desc->io_netif->nif_driver;
250ca987d46SWarner Losh ssize_t rv;
251ca987d46SWarner Losh
252ca987d46SWarner Losh #ifdef NETIF_DEBUG
253ca987d46SWarner Losh if (netif_debug)
254ca987d46SWarner Losh printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit);
255ca987d46SWarner Losh #endif
256ca987d46SWarner Losh #ifdef PARANOID
257ca987d46SWarner Losh if (drv->netif_put == NULL)
25855d5c949SMaxim Sobolev panic("%s%d: no netif_put support", drv->netif_bname,
259ca987d46SWarner Losh nif->nif_unit);
260ca987d46SWarner Losh #endif
261ca987d46SWarner Losh rv = drv->netif_put(desc, pkt, len);
262ca987d46SWarner Losh #ifdef NETIF_DEBUG
263ca987d46SWarner Losh if (netif_debug)
264ca987d46SWarner Losh printf("%s%d: netif_put returning %d\n", drv->netif_bname,
265ca987d46SWarner Losh nif->nif_unit, (int)rv);
266ca987d46SWarner Losh #endif
267ca987d46SWarner Losh return (rv);
268ca987d46SWarner Losh }
269ca987d46SWarner Losh
27097cbd5e7SToomas Soome /*
27197cbd5e7SToomas Soome * socktodesc_impl:
27297cbd5e7SToomas Soome *
27397cbd5e7SToomas Soome * Walk socket list and return pointer to iodesc structure.
27497cbd5e7SToomas Soome * if id is < 0, return first unused iodesc.
27597cbd5e7SToomas Soome */
27697cbd5e7SToomas Soome static struct iodesc *
socktodesc_impl(int socket)27797cbd5e7SToomas Soome socktodesc_impl(int socket)
27897cbd5e7SToomas Soome {
27997cbd5e7SToomas Soome struct iodesc *s;
28097cbd5e7SToomas Soome
28197cbd5e7SToomas Soome TAILQ_FOREACH(s, &sockets, io_link) {
28297cbd5e7SToomas Soome /* search by socket id */
28397cbd5e7SToomas Soome if (socket >= 0) {
28497cbd5e7SToomas Soome if (s->io_id == socket)
28597cbd5e7SToomas Soome break;
28697cbd5e7SToomas Soome continue;
28797cbd5e7SToomas Soome }
28897cbd5e7SToomas Soome /* search for first unused entry */
28997cbd5e7SToomas Soome if (s->io_netif == NULL)
29097cbd5e7SToomas Soome break;
29197cbd5e7SToomas Soome }
29297cbd5e7SToomas Soome return (s);
29397cbd5e7SToomas Soome }
29497cbd5e7SToomas Soome
295ca987d46SWarner Losh struct iodesc *
socktodesc(int sock)296ca987d46SWarner Losh socktodesc(int sock)
297ca987d46SWarner Losh {
29897cbd5e7SToomas Soome struct iodesc *desc;
29997cbd5e7SToomas Soome
30097cbd5e7SToomas Soome if (sock < 0)
30197cbd5e7SToomas Soome desc = NULL;
30297cbd5e7SToomas Soome else
30397cbd5e7SToomas Soome desc = socktodesc_impl(sock);
30497cbd5e7SToomas Soome
30597cbd5e7SToomas Soome if (desc == NULL)
306ca987d46SWarner Losh errno = EBADF;
30797cbd5e7SToomas Soome
30897cbd5e7SToomas Soome return (desc);
309ca987d46SWarner Losh }
310ca987d46SWarner Losh
311ca987d46SWarner Losh int
netif_open(void * machdep_hint)312ca987d46SWarner Losh netif_open(void *machdep_hint)
313ca987d46SWarner Losh {
314ca987d46SWarner Losh struct iodesc *s;
315ca987d46SWarner Losh struct netif *nif;
316ca987d46SWarner Losh
317ca987d46SWarner Losh /* find a free socket */
31897cbd5e7SToomas Soome s = socktodesc_impl(-1);
31997cbd5e7SToomas Soome if (s == NULL) {
32097cbd5e7SToomas Soome struct iodesc *last;
32197cbd5e7SToomas Soome
32297cbd5e7SToomas Soome s = calloc(1, sizeof (*s));
32397cbd5e7SToomas Soome if (s == NULL)
324ca987d46SWarner Losh return (-1);
325ca987d46SWarner Losh
32697cbd5e7SToomas Soome last = TAILQ_LAST(&sockets, socket_list);
32797cbd5e7SToomas Soome if (last != NULL)
32897cbd5e7SToomas Soome s->io_id = last->io_id + 1;
32997cbd5e7SToomas Soome TAILQ_INSERT_TAIL(&sockets, s, io_link);
33097cbd5e7SToomas Soome }
33197cbd5e7SToomas Soome
332ca987d46SWarner Losh netif_init();
333ca987d46SWarner Losh nif = netif_select(machdep_hint);
334ca987d46SWarner Losh if (!nif)
335ca987d46SWarner Losh panic("netboot: no interfaces left untried");
336ca987d46SWarner Losh if (netif_probe(nif, machdep_hint)) {
337ca987d46SWarner Losh printf("netboot: couldn't probe %s%d\n",
338ca987d46SWarner Losh nif->nif_driver->netif_bname, nif->nif_unit);
339ca987d46SWarner Losh errno = EINVAL;
340ca987d46SWarner Losh return (-1);
341ca987d46SWarner Losh }
342ca987d46SWarner Losh netif_attach(nif, s, machdep_hint);
343ca987d46SWarner Losh
34497cbd5e7SToomas Soome return (s->io_id);
345ca987d46SWarner Losh }
346ca987d46SWarner Losh
347ca987d46SWarner Losh int
netif_close(int sock)348ca987d46SWarner Losh netif_close(int sock)
349ca987d46SWarner Losh {
35097cbd5e7SToomas Soome struct iodesc *s, *last;
35197cbd5e7SToomas Soome int err;
35297cbd5e7SToomas Soome
35397cbd5e7SToomas Soome err = 0;
35497cbd5e7SToomas Soome s = socktodesc_impl(sock);
35597cbd5e7SToomas Soome if (s == NULL || sock < 0) {
35697cbd5e7SToomas Soome err = EBADF;
357ca987d46SWarner Losh return (-1);
358ca987d46SWarner Losh }
35997cbd5e7SToomas Soome netif_detach(s->io_netif);
36097cbd5e7SToomas Soome bzero(&s->destip, sizeof (s->destip));
36197cbd5e7SToomas Soome bzero(&s->myip, sizeof (s->myip));
36297cbd5e7SToomas Soome s->destport = 0;
36397cbd5e7SToomas Soome s->myport = 0;
36497cbd5e7SToomas Soome s->xid = 0;
36597cbd5e7SToomas Soome bzero(s->myea, sizeof (s->myea));
36697cbd5e7SToomas Soome s->io_netif = NULL;
36797cbd5e7SToomas Soome
36897cbd5e7SToomas Soome /* free unused entries from tail. */
36997cbd5e7SToomas Soome TAILQ_FOREACH_REVERSE_SAFE(last, &sockets, socket_list, io_link, s) {
37097cbd5e7SToomas Soome if (last->io_netif != NULL)
37197cbd5e7SToomas Soome break;
37297cbd5e7SToomas Soome TAILQ_REMOVE(&sockets, last, io_link);
37397cbd5e7SToomas Soome free(last);
37497cbd5e7SToomas Soome }
37597cbd5e7SToomas Soome
37697cbd5e7SToomas Soome if (err) {
37797cbd5e7SToomas Soome errno = err;
37897cbd5e7SToomas Soome return (-1);
37997cbd5e7SToomas Soome }
380ca987d46SWarner Losh
381ca987d46SWarner Losh return (0);
382ca987d46SWarner Losh }
383