1 /* devices.c - Handle network devices.
14 #include <sys/ioctl.h>
15 #include <sys/asynchio.h>
17 #include <net/gen/in.h>
18 #include <net/gen/ether.h>
19 #include <net/gen/eth_hdr.h>
20 #include <net/gen/eth_io.h>
21 #include <net/gen/ip_hdr.h>
22 #include <net/gen/ip_io.h>
23 #include <net/gen/udp.h>
24 #include <net/gen/udp_hdr.h>
25 #include <net/gen/udp_io.h>
26 #include <net/gen/dhcp.h>
29 void get_buf(buf_t
**bp
)
31 /* Allocate and return a buffer pointer iff *bp == nil. */
33 /* Already has one. */
35 /* Get one from the heap. */
36 buf_t
*new= allocate(sizeof(*new));
37 new->dhcp
= (dhcp_t
*) (new->buf
+ sizeof(eth_hdr_t
)
38 + sizeof(ip_hdr_t
) + sizeof(udp_hdr_t
));
39 new->udpio
= ((udp_io_hdr_t
*) new->dhcp
) - 1;
40 new->udp
= ((udp_hdr_t
*) new->dhcp
) - 1;
41 new->ip
= ((ip_hdr_t
*) new->udp
) - 1;
42 new->eth
= ((eth_hdr_t
*) new->ip
) - 1;
47 void put_buf(buf_t
**bp
)
49 /* Return a buffer to the heap. */
56 void give_buf(buf_t
**dbp
, buf_t
**sbp
)
58 /* Hand over a buffer to another variable. */
65 #define N_FDS 16 /* Minix-vmd can go async on many fds. */
67 #define N_FDS 1 /* Minix doesn't have async I/O. */
70 static fd_t fds
[N_FDS
]; /* List of open descriptors. */
71 static struct network
*fdwaitq
; /* Queue of nets waiting for fds. */
73 network_t
*newnetwork(void)
75 /* Create and initialize a network structure. */
78 new= allocate(sizeof(*new));
79 memset(new, 0, sizeof(*new));
86 void closefd(fd_t
*fdp
)
88 /* Close a descriptor. */
89 if (fdp
->fdtype
!= FT_CLOSED
) {
90 asyn_close(&asyn
, fdp
->fd
);
92 fdp
->fdtype
= FT_CLOSED
;
95 if (debug
>= 3) printf("%s: Closed\n", fdp
->device
);
99 int opendev(network_t
*np
, fdtype_t fdtype
, int compete
)
101 /* Make sure that a network has the proper device open and configured.
102 * Return true if this is made so, or false if the device doesn't exist.
103 * If compete is true then the caller competes for old descriptors.
104 * The errno value is EAGAIN if we're out of descriptors.
108 nwio_ethstat_t ethstat
;
109 nwio_ethopt_t ethopt
;
111 nwio_udpopt_t udpopt
;
113 static char devbytype
[][4] = { "", "eth", "ip", "udp", "udp" };
115 /* Don't attempt to open higher level devices if not bound. */
116 if (!(np
->flags
& NF_BOUND
) && fdtype
> FT_ETHERNET
) {
121 /* Check if already open / Find the oldest descriptor. */
124 for (fdp
= fds
; fdp
< arraylimit(fds
); fdp
++) {
125 if (fdp
->n
== np
->n
&& fdp
->fdtype
== fdtype
) {
130 if (fdp
->since
<= oldest
) { fdold
= fdp
; oldest
= fdp
->since
; }
133 /* None free? Then wait for one to get old if so desired. */
134 if (fdold
->fdtype
!= FT_CLOSED
&& !compete
) {
139 if (!(np
->flags
& NF_WAIT
)) {
140 for (pqp
= &fdwaitq
; *pqp
!= nil
; pqp
= &(*pqp
)->wait
) {}
143 np
->flags
|= NF_WAIT
;
146 /* We allow a net to keep a descriptor for half of the fast period. */
147 oldest
+= DELTA_FAST
/2;
149 if (fdwaitq
!= np
|| (fdold
->fdtype
!= FT_CLOSED
&& oldest
> now
)) {
150 /* This net is not the first in the queue, or the oldest isn't
151 * old enough. Forget it for now.
153 if (oldest
< event
) event
= oldest
;
158 /* The oldest is mine. */
159 np
->flags
&= ~NF_WAIT
;
163 /* Open the proper device in the proper mode. */
166 sprintf(fdp
->device
, "/dev/%s%d", devbytype
[fdtype
], np
->n
);
169 if ((fdp
->fd
= open(fdp
->device
, O_RDWR
)) < 0) {
170 if (errno
== ENOENT
|| errno
== ENODEV
|| errno
== ENXIO
) return 0;
176 /* Set NONBLOCK to avoid waiting for a device driver to become ready */
177 fcntl(np
->fdp
->fd
, F_SETFL
, fcntl(np
->fdp
->fd
, F_GETFL
) | O_NONBLOCK
);
178 if (ioctl(np
->fdp
->fd
, NWIOGETHSTAT
, ðstat
) < 0) {
179 /* Not an Ethernet. */
183 fcntl(np
->fdp
->fd
, F_SETFL
, fcntl(np
->fdp
->fd
, F_GETFL
) & ~O_NONBLOCK
);
184 np
->eth
= ethstat
.nwes_addr
;
185 ethopt
.nweo_flags
= NWEO_COPY
| NWEO_EN_LOC
| NWEO_EN_BROAD
186 | NWEO_REMANY
| NWEO_TYPEANY
| NWEO_RWDATALL
;
188 if (ioctl(fdp
->fd
, NWIOSETHOPT
, ðopt
) < 0) {
189 fprintf(stderr
, "%s: %s: Unable to set eth options: %s\n",
190 program
, fdp
->device
, strerror(errno
));
196 ipopt
.nwio_flags
= NWIO_COPY
| NWIO_EN_LOC
| NWIO_EN_BROAD
197 | NWIO_REMANY
| NWIO_PROTOSPEC
198 | NWIO_HDR_O_SPEC
| NWIO_RWDATALL
;
202 ipopt
.nwio_hdropt
.iho_opt_siz
= 0;
203 ipopt
.nwio_proto
= IPPROTO_ICMP
;
205 if (ioctl(fdp
->fd
, NWIOSIPOPT
, &ipopt
) < 0) {
206 fprintf(stderr
, "%s: %s: Unable to set IP options: %s\n",
207 program
, fdp
->device
, strerror(errno
));
213 udpopt
.nwuo_flags
= NWUO_COPY
| NWUO_EN_LOC
| NWUO_EN_BROAD
214 | NWUO_RP_ANY
| NWUO_RA_ANY
| NWUO_RWDATALL
215 | NWUO_DI_IPOPT
| NWUO_LP_SET
;
216 udpopt
.nwuo_locport
= port_client
;
220 udpopt
.nwuo_flags
= NWUO_EXCL
| NWUO_EN_LOC
| NWUO_EN_BROAD
221 | NWUO_RP_ANY
| NWUO_RA_ANY
| NWUO_RWDATALL
222 | NWUO_DI_IPOPT
| NWUO_LP_SET
;
223 udpopt
.nwuo_locport
= port_server
;
225 if (ioctl(fdp
->fd
, NWIOSUDPOPT
, &udpopt
) == -1) {
226 fprintf(stderr
, "%s: %s: Unable to set UDP options: %s\n",
227 program
, fdp
->device
, strerror(errno
));
237 if (debug
>= 3) printf("%s: Opened\n", fdp
->device
);
241 void closedev(network_t
*np
, fdtype_t fdtype
)
243 /* We no longer need a given type of device to be open. */
246 for (fdp
= fds
; fdp
< arraylimit(fds
); fdp
++) {
247 if (fdp
->n
== np
->n
&& (fdp
->fdtype
== fdtype
|| fdtype
== FT_ALL
)) {
255 /* IP device for network #n. */
256 static char device
[sizeof("/dev/ipNNN")];
258 sprintf(device
, "/dev/ip%d", n
);
262 void set_ipconf(char *device
, ipaddr_t ip
, ipaddr_t mask
, unsigned mtu
)
264 /* Set IP address and netmask of an IP device. */
266 nwio_ipconf_t ipconf
;
268 if (test
> 0) return;
270 if ((fd
= open(device
, O_RDWR
)) < 0) fatal(device
);
271 ipconf
.nwic_flags
= NWIC_IPADDR_SET
| NWIC_NETMASK_SET
;
272 ipconf
.nwic_ipaddr
= ip
;
273 ipconf
.nwic_netmask
= mask
;
276 ipconf
.nwic_flags
|= NWIC_MTU_SET
;
277 ipconf
.nwic_mtu
= mtu
;
280 if (ioctl(fd
, NWIOSIPCONF
, &ipconf
) < 0) fatal(device
);