1 /* LWIP service - lwip.c - main program and dispatch code */
11 #include "lwip/init.h"
13 #include "lwip/timeouts.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.
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
43 uint32_t next_timeout
;
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())
68 ticks
= (next_timeout
* sys_hz() + 999) / 1000;
70 set_timer(&lwip_timer
, ticks
, expire_lwip_timer
, 0 /*unused*/);
72 cancel_timer(&lwip_timer
); /* not really needed.. */
76 * The timer for lwIP timeouts has gone off. Check timeouts, and possibly set
80 expire_lwip_timer(int arg __unused
)
83 /* Let lwIP do its work. */
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.
92 recheck_timer
= FALSE
;
96 * Check whether we should adjust our local timer based on a change in the next
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.
119 /* Reset the flag for the next message loop iteration. */
120 recheck_timer
= FALSE
;
124 * Return a random number, for use by lwIP.
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.
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.
152 alloc_socket(int domain
, int type
, int protocol
, endpoint_t user_endpt
,
153 struct sock
** sock
, const struct sockevent_ops
**ops
)
163 return tcpsock_socket(domain
, protocol
, sock
, ops
);
166 return udpsock_socket(domain
, protocol
, sock
, ops
);
169 if (!util_is_root(user_endpt
))
172 return rawsock_socket(domain
, protocol
, sock
, ops
);
179 return rtsock_socket(type
, protocol
, sock
, ops
);
182 return lnksock_socket(type
, protocol
, sock
, ops
);
185 /* This means that the service has been misconfigured. */
186 printf("socket() with unsupported domain %d\n", domain
);
193 * Initialize the service.
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. */
208 /* Initialize the socket events library. */
209 sockevent_init(alloc_socket
);
211 /* Initialize various helper modules. */
216 /* Initialize the high-level socket modules. */
222 /* Initialize the various network interface modules. */
227 /* Initialize the network device driver module. */
230 /* Initialize the low-level socket modules. */
234 /* Initialize the routing module. */
237 /* Initialize other device modules. */
241 * Initialize the MIB module, after all other modules have registered
242 * their subtrees with this module.
247 * After everything else has been initialized, set up the default
248 * configuration - in particular, a loopback interface.
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
257 init_timer(&lwip_timer
);
259 recheck_timer
= TRUE
;
267 * Perform initialization using the System Event Framework (SEF).
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.
291 * The lwIP-based TCP/IP sockets driver.
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.
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
317 if ((r
= sef_receive_status(ANY
, &m
, &ipc_status
)) != OK
) {
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
) {
328 expire_timers(m
.m_notify
.timestamp
);
333 /* Network drivers went up and/or down. */
339 printf("unexpected notify from %d\n",
346 switch (m
.m_source
) {
348 rmib_process(&m
, ipc_status
);
353 /* Is this a socket device request? */
354 if (IS_SDEV_RQ(m
.m_type
)) {
355 sockevent_process(&m
, ipc_status
);
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
);
369 /* Is this a network device driver response? */
370 if (IS_NDEV_RS(m
.m_type
)) {
371 ndev_process(&m
, ipc_status
);
376 printf("unexpected message %d from %d\n",
377 m
.m_type
, m
.m_source
);