Remove building with NOCRYPTO option
[minix.git] / minix / net / lwip / lwip.c
blob1f602ab0a56ec7056e4e24246203a3ebff07820d
1 /* LWIP service - lwip.c - main program and dispatch code */
3 #include "lwip.h"
4 #include "tcpisn.h"
5 #include "mcast.h"
6 #include "ethif.h"
7 #include "rtsock.h"
8 #include "route.h"
9 #include "bpfdev.h"
11 #include "lwip/init.h"
12 #include "lwip/sys.h"
13 #include "lwip/timeouts.h"
14 #include "arch/cc.h"
16 static int running, recheck_timer;
17 static minix_timer_t lwip_timer;
19 static void expire_lwip_timer(int);
22 * Return the system uptime in milliseconds. Also remember that lwIP retrieved
23 * the system uptime during this call, so that we know to check for timer
24 * updates at the end of the current iteration of the message loop.
26 uint32_t
27 sys_now(void)
30 recheck_timer = TRUE;
32 /* TODO: avoid 64-bit arithmetic if possible. */
33 return (uint32_t)(((uint64_t)getticks() * 1000) / sys_hz());
37 * Check if and when lwIP has its next timeout, and set or cancel our timer
38 * accordingly.
40 static void
41 set_lwip_timer(void)
43 uint32_t next_timeout;
44 clock_t ticks;
46 /* Ask lwIP when the next alarm is supposed to go off, if any. */
47 next_timeout = sys_timeouts_sleeptime();
50 * Set or update the lwIP timer. We rely on set_timer() asking the
51 * kernel for an alarm only if the timeout is different from the one we
52 * gave it last time (if at all). However, due to conversions between
53 * absolute and relative times, and the fact that we cannot guarantee
54 * that the uptime itself does not change while executing these
55 * routines, set_timer() will sometimes be issuing a kernel call even
56 * if the alarm has not changed. Not a huge deal, but fixing this will
57 * require a different interface to lwIP and/or the timers library.
59 if (next_timeout != (uint32_t)-1) {
61 * Round up the next timeout (which is in milliseconds) to the
62 * number of clock ticks to add to the current time. Avoid any
63 * potential for overflows, no matter how unrealistic..
65 if (next_timeout > TMRDIFF_MAX / sys_hz())
66 ticks = TMRDIFF_MAX;
67 else
68 ticks = (next_timeout * sys_hz() + 999) / 1000;
70 set_timer(&lwip_timer, ticks, expire_lwip_timer, 0 /*unused*/);
71 } else
72 cancel_timer(&lwip_timer); /* not really needed.. */
76 * The timer for lwIP timeouts has gone off. Check timeouts, and possibly set
77 * a new timer.
79 static void
80 expire_lwip_timer(int arg __unused)
83 /* Let lwIP do its work. */
84 sys_check_timeouts();
87 * See if we have to update our timer for the next lwIP timer. Doing
88 * this here, rather than from the main loop, avoids one kernel call.
90 set_lwip_timer();
92 recheck_timer = FALSE;
96 * Check whether we should adjust our local timer based on a change in the next
97 * lwIP timeout.
99 static void
100 check_lwip_timer(void)
104 * We make the assumption that whenever lwIP starts a timer, it will
105 * need to retrieve the current time. Thus, whenever sys_now() is
106 * called, we set the 'recheck_timer' flag. Here, we check whether to
107 * (re)set our lwIP timer only if the flag is set. As a result, we do
108 * not have to mess with timers for literally every incoming message.
110 * When lwIP stops a timer, it does not call sys_now(), and thus, we
111 * may miss such updates. However, timers being stopped should be rare
112 * and getting too many alarm messages is not a big deal.
114 if (!recheck_timer)
115 return;
117 set_lwip_timer();
119 /* Reset the flag for the next message loop iteration. */
120 recheck_timer = FALSE;
124 * Return a random number, for use by lwIP.
126 uint32_t
127 lwip_hook_rand(void)
131 * The current known uses of this hook are for selection of initial
132 * TCP/UDP port numbers and for multicast-related timer randomness.
133 * The former case exists only to avoid picking the same starting port
134 * numbers after a reboot. After that, simple sequential iteration of
135 * the port numbers is used. The latter case varies the response time
136 * for sending multicast messages. Thus, none of the current uses of
137 * this function require proper randomness, and so we use the simplest
138 * approach, with time-based initialization to cover the reboot case.
139 * The sequential port number selection could be improved upon, but
140 * such an extension would probably bypass this hook anyway.
142 return lrand48();
146 * Create a new socket, with the given domain, type, and protocol, for the user
147 * process identified by 'user_endpt'. On success, return the new socket's
148 * identifier, with the libsockevent socket stored in 'sock' and an operations
149 * table stored in 'ops'. On failure, return a negative error code.
151 static sockid_t
152 alloc_socket(int domain, int type, int protocol, endpoint_t user_endpt,
153 struct sock ** sock, const struct sockevent_ops **ops)
156 switch (domain) {
157 case PF_INET:
158 #ifdef INET6
159 case PF_INET6:
160 #endif /* INET6 */
161 switch (type) {
162 case SOCK_STREAM:
163 return tcpsock_socket(domain, protocol, sock, ops);
165 case SOCK_DGRAM:
166 return udpsock_socket(domain, protocol, sock, ops);
168 case SOCK_RAW:
169 if (!util_is_root(user_endpt))
170 return EACCES;
172 return rawsock_socket(domain, protocol, sock, ops);
174 default:
175 return EPROTOTYPE;
178 case PF_ROUTE:
179 return rtsock_socket(type, protocol, sock, ops);
181 case PF_LINK:
182 return lnksock_socket(type, protocol, sock, ops);
184 default:
185 /* This means that the service has been misconfigured. */
186 printf("socket() with unsupported domain %d\n", domain);
188 return EAFNOSUPPORT;
193 * Initialize the service.
195 static int
196 init(int type __unused, sef_init_info_t * init __unused)
200 * Initialize the random number seed. See the lwip_hook_rand() comment
201 * on why this weak random number source is currently sufficient.
203 srand48(clock_time(NULL));
205 /* Initialize the lwIP library. */
206 lwip_init();
208 /* Initialize the socket events library. */
209 sockevent_init(alloc_socket);
211 /* Initialize various helper modules. */
212 mempool_init();
213 tcpisn_init();
214 mcast_init();
216 /* Initialize the high-level socket modules. */
217 ipsock_init();
218 tcpsock_init();
219 udpsock_init();
220 rawsock_init();
222 /* Initialize the various network interface modules. */
223 ifdev_init();
224 loopif_init();
225 ethif_init();
227 /* Initialize the network device driver module. */
228 ndev_init();
230 /* Initialize the low-level socket modules. */
231 rtsock_init();
232 lnksock_init();
234 /* Initialize the routing module. */
235 route_init();
237 /* Initialize other device modules. */
238 bpfdev_init();
241 * Initialize the MIB module, after all other modules have registered
242 * their subtrees with this module.
244 mibtree_init();
247 * After everything else has been initialized, set up the default
248 * configuration - in particular, a loopback interface.
250 ifconf_init();
253 * Initialize the master timer for all the lwIP timers. Just in case
254 * lwIP starts a timer right away, perform a first check upon entry of
255 * the message loop.
257 init_timer(&lwip_timer);
259 recheck_timer = TRUE;
261 running = TRUE;
263 return OK;
267 * Perform initialization using the System Event Framework (SEF).
269 static void
270 startup(void)
273 sef_setcb_init_fresh(init);
275 * This service requires stateless restarts, in that several parts of
276 * the system (including VFS and drivers) expect that if restarted,
277 * this service comes back up with a new endpoint. Therefore, do not
278 * set a _restart callback here.
280 * TODO: support for live update.
282 * TODO: support for immediate shutdown if no sockets are in use, as
283 * also done by UDS. For now, we never shut down immediately, giving
284 * other processes the opportunity to close sockets on system shutdown.
287 sef_startup();
291 * The lwIP-based TCP/IP sockets driver.
294 main(void)
296 message m;
297 int r, ipc_status;
299 startup();
301 while (running) {
303 * For various reasons, the loopback interface does not pass
304 * packets back into the stack right away. Instead, it queues
305 * them up for later processing. We do that processing here.
307 ifdev_poll();
310 * Unfortunately, lwIP does not tell us when it starts or stops
311 * timers. This means that we have to check ourselves every
312 * time we have called into lwIP. For simplicity, we perform
313 * the check here.
315 check_lwip_timer();
317 if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK) {
318 if (r == EINTR)
319 continue; /* sef_cancel() was called */
321 panic("sef_receive_status failed: %d", r);
324 /* Process the received message. */
325 if (is_ipc_notify(ipc_status)) {
326 switch (m.m_source) {
327 case CLOCK:
328 expire_timers(m.m_notify.timestamp);
330 break;
332 case DS_PROC_NR:
333 /* Network drivers went up and/or down. */
334 ndev_check();
336 break;
338 default:
339 printf("unexpected notify from %d\n",
340 m.m_source);
343 continue;
346 switch (m.m_source) {
347 case MIB_PROC_NR:
348 rmib_process(&m, ipc_status);
350 break;
352 case VFS_PROC_NR:
353 /* Is this a socket device request? */
354 if (IS_SDEV_RQ(m.m_type)) {
355 sockevent_process(&m, ipc_status);
357 break;
360 /* Is this a character (or block) device request? */
361 if (IS_CDEV_RQ(m.m_type) || IS_BDEV_RQ(m.m_type)) {
362 bpfdev_process(&m, ipc_status);
364 break;
367 /* FALLTHROUGH */
368 default:
369 /* Is this a network device driver response? */
370 if (IS_NDEV_RS(m.m_type)) {
371 ndev_process(&m, ipc_status);
373 break;
376 printf("unexpected message %d from %d\n",
377 m.m_type, m.m_source);
381 return 0;