source: trunk/minix/commands/dhcpd/devices.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 6.9 KB
Line 
1/* devices.c - Handle network devices.
2 * Author: Kees J. Bot
3 * 11 Jun 1999
4 */
5#include <sys/types.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <fcntl.h>
10#include <errno.h>
11#include <string.h>
12#include <limits.h>
13#include <time.h>
14#include <sys/ioctl.h>
15#include <sys/asynchio.h>
16#include <net/hton.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>
27#include "dhcpd.h"
28
29void get_buf(buf_t **bp)
30{
31 /* Allocate and return a buffer pointer iff *bp == nil. */
32 if (*bp != nil) {
33 /* Already has one. */
34 } else {
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;
43 *bp= new;
44 }
45}
46
47void put_buf(buf_t **bp)
48{
49 /* Return a buffer to the heap. */
50 if (*bp != nil) {
51 free(*bp);
52 *bp= nil;
53 }
54}
55
56void give_buf(buf_t **dbp, buf_t **sbp)
57{
58 /* Hand over a buffer to another variable. */
59 put_buf(dbp);
60 *dbp= *sbp;
61 *sbp= nil;
62}
63
64#if __minix_vmd
65#define N_FDS 16 /* Minix-vmd can go async on many fds. */
66#else
67#define N_FDS 1 /* Minix doesn't have async I/O. */
68#endif
69
70static fd_t fds[N_FDS]; /* List of open descriptors. */
71static struct network *fdwaitq; /* Queue of nets waiting for fds. */
72
73network_t *newnetwork(void)
74{
75 /* Create and initialize a network structure. */
76 network_t *new;
77
78 new= allocate(sizeof(*new));
79 memset(new, 0, sizeof(*new));
80 new->hostname= nil;
81 new->solicit= NEVER;
82 new->sol_ct= -1;
83 return new;
84}
85
86void closefd(fd_t *fdp)
87{
88 /* Close a descriptor. */
89 if (fdp->fdtype != FT_CLOSED) {
90 asyn_close(&asyn, fdp->fd);
91 close(fdp->fd);
92 fdp->fdtype= FT_CLOSED;
93 fdp->since= 0;
94 put_buf(&fdp->bp);
95 if (debug >= 3) printf("%s: Closed\n", fdp->device);
96 }
97}
98
99int opendev(network_t *np, fdtype_t fdtype, int compete)
100{
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.
105 */
106 fd_t *fdp, *fdold;
107 time_t oldest;
108 nwio_ethstat_t ethstat;
109 nwio_ethopt_t ethopt;
110 nwio_ipopt_t ipopt;
111 nwio_udpopt_t udpopt;
112 network_t **pqp;
113 static char devbytype[][4] = { "", "eth", "ip", "udp", "udp" };
114
115 /* Don't attempt to open higher level devices if not bound. */
116 if (!(np->flags & NF_BOUND) && fdtype > FT_ETHERNET) {
117 errno= EAGAIN;
118 return 0;
119 }
120
121 /* Check if already open / Find the oldest descriptor. */
122 fdold= nil;
123 oldest= NEVER;
124 for (fdp= fds; fdp < arraylimit(fds); fdp++) {
125 if (fdp->n == np->n && fdp->fdtype == fdtype) {
126 /* Already open. */
127 np->fdp= fdp;
128 return 1;
129 }
130 if (fdp->since <= oldest) { fdold= fdp; oldest= fdp->since; }
131 }
132
133 /* None free? Then wait for one to get old if so desired. */
134 if (fdold->fdtype != FT_CLOSED && !compete) {
135 errno= EAGAIN;
136 return 0;
137 }
138
139 if (!(np->flags & NF_WAIT)) {
140 for (pqp= &fdwaitq; *pqp != nil; pqp= &(*pqp)->wait) {}
141 *pqp= np;
142 np->wait= nil;
143 np->flags |= NF_WAIT;
144 }
145
146 /* We allow a net to keep a descriptor for half of the fast period. */
147 oldest += DELTA_FAST/2;
148
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.
152 */
153 if (oldest < event) event= oldest;
154 errno= EAGAIN;
155 return 0;
156 }
157
158 /* The oldest is mine. */
159 np->flags &= ~NF_WAIT;
160 fdwaitq= np->wait;
161 closefd(fdold);
162
163 /* Open the proper device in the proper mode. */
164 fdp= fdold;
165 fdp->n= np->n;
166 sprintf(fdp->device, "/dev/%s%d", devbytype[fdtype], np->n);
167 np->fdp= fdp;
168
169 if ((fdp->fd= open(fdp->device, O_RDWR)) < 0) {
170 if (errno == ENOENT || errno == ENODEV || errno == ENXIO) return 0;
171 fatal(fdp->device);
172 }
173
174 switch (fdtype) {
175 case FT_ETHERNET:
176 fcntl(np->fdp->fd, F_SETFL, fcntl(np->fdp->fd, F_GETFL) | O_NONBLOCK);
177 if (ioctl(np->fdp->fd, NWIOGETHSTAT, &ethstat) < 0) {
178 /* Not an Ethernet. */
179 close(fdp->fd);
180 return 0;
181 }
182 np->eth= ethstat.nwes_addr;
183 ethopt.nweo_flags= NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD
184 | NWEO_REMANY | NWEO_TYPEANY | NWEO_RWDATALL;
185
186 if (ioctl(fdp->fd, NWIOSETHOPT, &ethopt) < 0) {
187 fprintf(stderr, "%s: %s: Unable to set eth options: %s\n",
188 program, fdp->device, strerror(errno));
189 exit(1);
190 }
191 break;
192
193 case FT_ICMP:
194 ipopt.nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD
195 | NWIO_REMANY | NWIO_PROTOSPEC
196 | NWIO_HDR_O_SPEC | NWIO_RWDATALL;
197 ipopt.nwio_tos= 0;
198 ipopt.nwio_ttl= 1;
199 ipopt.nwio_df= 0;
200 ipopt.nwio_hdropt.iho_opt_siz= 0;
201 ipopt.nwio_proto= IPPROTO_ICMP;
202
203 if (ioctl(fdp->fd, NWIOSIPOPT, &ipopt) < 0) {
204 fprintf(stderr, "%s: %s: Unable to set IP options: %s\n",
205 program, fdp->device, strerror(errno));
206 exit(1);
207 }
208 break;
209
210 case FT_BOOTPC:
211 udpopt.nwuo_flags= NWUO_COPY | NWUO_EN_LOC | NWUO_EN_BROAD
212 | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL
213 | NWUO_DI_IPOPT | NWUO_LP_SET;
214 udpopt.nwuo_locport= port_client;
215 goto udp;
216
217 case FT_BOOTPS:
218 udpopt.nwuo_flags= NWUO_EXCL | NWUO_EN_LOC | NWUO_EN_BROAD
219 | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL
220 | NWUO_DI_IPOPT | NWUO_LP_SET;
221 udpopt.nwuo_locport= port_server;
222 udp:
223 if (ioctl(fdp->fd, NWIOSUDPOPT, &udpopt) == -1) {
224 fprintf(stderr, "%s: %s: Unable to set UDP options: %s\n",
225 program, fdp->device, strerror(errno));
226 exit(1);
227 }
228 break;
229
230 default:;
231 }
232
233 fdp->fdtype= fdtype;
234 fdp->since= now;
235 if (debug >= 3) printf("%s: Opened\n", fdp->device);
236 return 1;
237}
238
239void closedev(network_t *np, fdtype_t fdtype)
240{
241 /* We no longer need a given type of device to be open. */
242 fd_t *fdp;
243
244 for (fdp= fds; fdp < arraylimit(fds); fdp++) {
245 if (fdp->n == np->n && (fdp->fdtype == fdtype || fdtype == FT_ALL)) {
246 closefd(fdp);
247 }
248 }
249}
250
251char *ipdev(int n)
252{
253 /* IP device for network #n. */
254 static char device[sizeof("/dev/ipNNN")];
255
256 sprintf(device, "/dev/ip%d", n);
257 return device;
258}
259
260void set_ipconf(char *device, ipaddr_t ip, ipaddr_t mask, unsigned mtu)
261{
262 /* Set IP address and netmask of an IP device. */
263 int fd;
264 nwio_ipconf_t ipconf;
265
266 if (test > 0) return;
267
268 if ((fd= open(device, O_RDWR)) < 0) fatal(device);
269 ipconf.nwic_flags= NWIC_IPADDR_SET | NWIC_NETMASK_SET;
270 ipconf.nwic_ipaddr= ip;
271 ipconf.nwic_netmask= mask;
272#ifdef NWIC_MTU_SET
273 if (mtu != 0) {
274 ipconf.nwic_flags |= NWIC_MTU_SET;
275 ipconf.nwic_mtu= mtu;
276 }
277#endif
278 if (ioctl(fd, NWIOSIPCONF, &ipconf) < 0) fatal(device);
279 close(fd);
280}
Note: See TracBrowser for help on using the repository browser.