1/*
2 * Copyright (c) 2017, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10// stdlib includes
11
12// barrelfish includes
13
14// lwip includes
15#include "lwip/init.h"
16#include "lwip/netif.h"
17#include "lwip/ip.h"
18#include "lwip/dhcp.h"
19#include "lwip/prot/ethernet.h"
20#include "lwip/timeouts.h"
21
22#include <barrelfish/barrelfish.h>
23#include <barrelfish/deferred.h>
24#include <barrelfish/waitset.h>
25#include <barrelfish/waitset_chan.h>
26
27#include <net/net_filter.h>
28#include <net_sockets/net_sockets.h>
29#include <net_interfaces/flags.h>
30#include "networking_internal.h"
31#include "net_queue_internal.h"
32
33struct net_state state = {0};
34struct waitset_chanstate net_loopback_poll_channel;
35struct deferred_event net_lwip_timer;
36
37#define NETWORKING_DEFAULT_QUEUE_ID 0
38#define NETWORKING_BUFFER_COUNT (4096 * 3)
39#define NETWORKING_BUFFER_RX_POPULATE (4096 - 10)
40#define NETWORKING_BUFFER_SIZE  2048
41
42static const char* default_name = "net_sockets_server";
43
44#define NETDEBUG_SUBSYSTEM "net"
45
46/**
47 * @brief obtains the default setting for initializaion of the driver
48 *
49 * @param queue     returns the queue to be used
50 * @param cardname  returns the card name to be used
51 *
52 * @return SYS_ERR_OK on success, SKB_ERR_* on failure
53 */
54errval_t networking_get_defaults(uint64_t *queue, const char **cardname, uint32_t *flags)
55{
56    /* TODO: get some reasonable values */
57
58    *queue = NETWORKING_DEFAULT_QUEUE_ID;
59    *cardname = default_name;
60    *flags = NET_FLAGS_POLLING | NET_FLAGS_BLOCKING_INIT;
61
62    return SYS_ERR_OK;
63}
64
65static void int_handler(void* args)
66{
67    NETDEBUG("Enter int_handler!\n");
68    struct net_state *st = devq_get_state(args);
69
70    if (st) {
71        net_if_poll(&st->netif);
72        net_lwip_timeout();
73    }
74}
75
76static void net_loopback_poll(void *arg)
77{
78    netif_poll_all();
79    net_lwip_timeout();
80}
81
82void net_if_trigger_loopback(void)
83{
84    errval_t err;
85
86    err = waitset_chan_trigger(&net_loopback_poll_channel);
87    assert(err_is_ok(err));
88}
89
90void net_lwip_timeout(void)
91{
92    errval_t err;
93
94    sys_check_timeouts();
95    deferred_event_cancel(&net_lwip_timer);
96    uint32_t delay = sys_timeouts_sleeptime();
97    if (delay != 0xffffffff) {
98        err = deferred_event_register(&net_lwip_timer, get_default_waitset(),
99            delay * 1000, MKCLOSURE((void (*)(void *))net_lwip_timeout, NULL));
100        assert(err_is_ok(err));
101    }
102}
103
104/**
105 * @brief creates a queue to the given card and the queueid
106 *
107 * @param cardname  network card to create the queue for
108 * @param ep        endpoint to networking card, possibly null
109 * @param queueid   queueid of the network card
110 * @param retqueue  returns endpoint to netfilter interface of this queue
111 * @param retqueue  returns the pointer to the queue
112 *
113 * @return SYS_ERR_OK on success, errval on failure
114 */
115errval_t networking_create_queue(const char *cardname, struct capref* ep,
116                                 uint64_t* queueid, struct capref* filter_ep,
117                                 struct devq **retqueue)
118{
119    struct net_state *st = get_default_net_state();
120    bool poll = st->flags & NET_FLAGS_POLLING;
121    bool default_q = st->flags & NET_FLAGS_DEFAULT_QUEUE;
122    return net_queue_internal_create(int_handler, cardname, ep, queueid, default_q,
123                                     poll, filter_ep, retqueue);
124}
125
126
127static errval_t networking_poll_st(struct net_state *st)
128{
129    event_dispatch_non_block(get_default_waitset());
130    if (st->flags & NET_FLAGS_POLLING) {
131        return net_if_poll(&st->netif);
132    } else {
133        return event_dispatch(get_default_waitset());
134    }
135}
136
137/**
138 * @brief initializes the networking library with a given device queue
139 *
140 * @param st        the networking state to initialize
141 * @param q         the device queue to initialize the networking on
142 * @param flags     supplied initialization flags
143 *
144 * @return SYS_ERR_OK on success, errval on failure
145 */
146static errval_t networking_init_with_queue_st(struct net_state *st, struct devq *q,
147                                              net_flags_t flags)
148{
149    errval_t err;
150
151    NETDEBUG("initializing networking with devq=%p, flags=%" PRIx32 "...\n", q,
152             flags);
153
154    if (st->initialized) {
155        debug_printf("WARNING. initialize called twice. Ignoring\n");
156        return SYS_ERR_OK;
157    }
158
159    /* set the variables */
160    st->flags = flags;
161    st->queue = q;
162    st->initialized = true;
163    st->waitset = get_default_waitset();
164
165    /* associate the net state with the device queue */
166    devq_set_state(st->queue, st);
167
168    /* create buffers and add them to the interface*/
169    err = net_buf_pool_alloc(st->queue, NETWORKING_BUFFER_COUNT,
170                             NETWORKING_BUFFER_SIZE, &st->pool);
171    if (err_is_fail(err)) {
172        //net_if_destroy(&st->netif);
173        goto out_err1;
174    }
175
176    deferred_event_init(&net_lwip_timer);
177    /* initialize the device queue */
178    NETDEBUG("initializing LWIP...\n");
179    lwip_init();
180
181    /* create the LWIP network interface and initialize it */
182    NETDEBUG("creating netif for LWIP...\n");
183    err = net_if_init_devq(&st->netif, st->queue);
184    if (err_is_fail(err)) {
185        goto out_err1;
186    }
187
188    err = net_if_add(&st->netif, st);
189    if (err_is_fail(err)) {
190        goto out_err1;
191    }
192
193    if (!(flags & NET_FLAGS_NO_NET_FILTER) && st->hw_filter) {
194        NETDEBUG("initializing hw filter...\n");
195
196        if (!capref_is_null(st->filter_ep)) {
197            debug_printf("Connecting to net filter interface using EP \n");
198            err = net_filter_init_with_ep(&st->filter, st->filter_ep);
199            if (err_is_fail(err)) {
200                USER_PANIC("Init filter infrastructure failed: %s \n", err_getstring(err));
201            }
202        } else {
203            debug_printf("Connecting to net filter interface using name \n");
204            err = net_filter_init(&st->filter, st->cardname);
205            if (err_is_fail(err)) {
206                USER_PANIC("Init filter infrastructure failed: %s \n", err_getstring(err));
207            }
208        }
209    }
210
211    NETDEBUG("setting default netif...\n");
212    netif_set_default(&st->netif);
213
214    NETDEBUG("adding RX buffers\n");
215    for (int i = 0; i < NETWORKING_BUFFER_RX_POPULATE; i++) {
216        struct pbuf *p = net_buf_alloc(st->pool);
217        if (p == NULL) {
218            NETDEBUG("net: WARNING there was no buffer\n");
219            break;
220        }
221        err = net_if_add_rx_buf(&st->netif, p);
222        if (err_is_fail(err)) {
223            break;
224        }
225    }
226
227    if (flags & NET_FLAGS_DO_DHCP) {
228        err = dhcpd_start(flags);
229        if (err_is_fail(err)) {
230            DEBUG_ERR(err, "failed to start DHCP.\n");
231        }
232
233        err = arp_service_start();
234        if (err_is_fail(err)) {
235            DEBUG_ERR(err,  "failed to start the ARP service\n");
236        }
237    } else {
238        /* get static IP config */
239        err = net_config_static_ip_query(flags);
240        if (err_is_fail(err)) {
241            DEBUG_ERR(err, "failed to set IP.\n");
242        }
243
244        err = arp_service_subscribe();
245        if (err_is_fail(err)) {
246            DEBUG_ERR(err, "failed to subscribte the ARP service\n");
247        }
248    }
249
250    waitset_chanstate_init(&net_loopback_poll_channel, CHANTYPE_OTHER);
251    net_loopback_poll_channel.persistent = true;
252    err = waitset_chan_register(get_default_waitset(), &net_loopback_poll_channel,
253                               MKCLOSURE(net_loopback_poll, NULL));
254
255    NETDEBUG("initialization complete.\n");
256
257    return SYS_ERR_OK;
258
259    out_err1:
260    st->initialized = false;
261
262    return err;
263
264}
265
266/**
267 * @brief initializes the networking library
268 *
269 * @param st        the networking state to be initalized
270 * @param nic       the nic to use with the networking library
271 * @param ep        endpoint to the nic, ignored if NULL
272 * @param flags     flags to use to initialize the networking library
273 *
274 * @return SYS_ERR_OK on success, errval on failure
275 */
276static errval_t networking_init_st(struct net_state *st, const char *nic, net_flags_t flags)
277{
278    errval_t err;
279
280    NETDEBUG("initializing networking with nic=%s, flags=%" PRIx32 "...\n", nic,
281             flags);
282
283    if(st->initialized) {
284        NETDEBUG("WARNING. initialize called twice. Ignoring\n");
285        return SYS_ERR_OK;
286    }
287
288    st->cardname = nic;
289    st->flags = flags;
290
291    // default no hw filters
292    st->hw_filter = false;
293
294    // if the NIC has a net_sockets_server prependend -> connect to net_socket server
295    // ontop of a nic
296    if (strncmp("net_sockets_server", nic, strlen("net_sockets_server")) == 0) {
297        return net_sockets_init_with_card(nic);
298    } else {
299        /* create the queue wit the given nic and card name */
300        err = networking_create_queue(nic, NULL, &st->queueid, &st->filter_ep, &st->queue);
301        if (err_is_fail(err)) {
302            return err;
303        }
304
305        assert(st->queue != NULL);
306
307        err = networking_init_with_queue_st(st, st->queue, flags);
308        if (err_is_fail(err)) {
309           // devq_destroy(st->queue);
310        }
311
312        return err;
313    }
314}
315
316/**
317 * @brief initializes the networking with the defaults
318 *
319 * @param st    the networking state to be initialized
320 *
321 * @return SYS_ERR_OK on sucess, errval on failure
322 */
323static errval_t networking_init_default_st(struct net_state *st)
324{
325    errval_t err;
326
327    NETDEBUG("initializing networking with default options...\n");
328
329    if(st->initialized) {
330        NETDEBUG("WARNING. initialize called twice. Ignoring\n");
331        return SYS_ERR_OK;
332    }
333
334    // obtain the settings to create the queue
335    err = networking_get_defaults(&st->queueid, &st->cardname, &st->flags);
336    if (err_is_fail(err)) {
337        return err;
338    }
339
340    return networking_init_st(st, st->cardname, st->flags);
341}
342
343
344
345/*
346 * ===========================================================================
347 * Public interface
348 * ===========================================================================
349 */
350
351/**
352 * @brief initializes the networking library with a given device queue
353 *
354 * @param q         the device queue to initialize the networking on
355 * @param flags     supplied initialization flags
356 *
357 * @return SYS_ERR_OK on success, errval on failure
358 */
359errval_t networking_init_with_queue(struct devq *q, net_flags_t flags)
360{
361    struct net_state *st = get_default_net_state();
362    return networking_init_with_queue_st(st, q, flags);
363}
364
365/**
366 * @brief initializes the networking library
367 *
368 * @param nic       the nic to use with the networking library
369 * @param flags     flags to use to initialize the networking library
370 *
371 * @return SYS_ERR_OK on success, errval on failure
372 */
373errval_t networking_init_with_nic(const char *nic, net_flags_t flags)
374{
375    struct net_state *st = get_default_net_state();
376    return networking_init_st(st, nic, flags);
377}
378
379/**
380 * @brief initializes the networking library
381 *
382 * @param nic       the nic to use with the networking library
383 * @param ep        endpoint to the nic
384 * @param flags     flags to use to initialize the networking library
385 *
386 * @return SYS_ERR_OK on success, errval on failure
387 */
388errval_t networking_init_with_ep(const char *nic, struct capref ep,
389                                 net_flags_t flags)
390{
391    errval_t err;
392
393    struct net_state *st = get_default_net_state();
394    st->flags = flags;
395    st->cardname = nic;
396
397    /* create the queue wit the given nic and card name */
398    err = networking_create_queue(nic, &ep, &st->queueid, &st->filter_ep,
399                                  &st->queue);
400    if (err_is_fail(err)) {
401        return err;
402    }
403
404    return networking_init_with_queue_st(st, st->queue, flags);
405}
406
407
408/**
409 * @brief initializes the networking with the defaults
410 *
411 * @return SYS_ERR_OK on success, errval on failure
412 */
413errval_t networking_init_default(void)
414{
415    struct net_state *st = get_default_net_state();
416    if (!st->initialized) {
417        return networking_init_default_st(st);
418    }
419    return SYS_ERR_OK;
420}
421
422
423/**
424 * @brief polls the network for new packets
425 *
426 * @return SYS_ERR_OK on success, errval on failure
427 */
428errval_t networking_poll(void)
429{
430    //return net_if_poll_all();
431    struct net_state *st = &state;
432    return networking_poll_st(st);
433}
434
435
436/**
437 * @brief Install L3/L4 filter
438 *
439 * @param tcp       should TCP packets be filtered or UPD
440 * @param src_ip    source ip of the filter, 0 for wildcard
441 * @param src_port  source port of the filter, 0 for wildcard
442 * @param dst_port  destination port fo the filter
443 *
444 * @return SYS_ERR_OK on success, NET_FILTER_ERR_* on failure
445 */
446errval_t networking_install_ip_filter(bool tcp, struct in_addr *src,
447                                      uint16_t src_port, uint16_t dst_port)
448{
449    errval_t err;
450    if (!state.hw_filter) {
451        debug_printf("Not adding filter as there are no HW filters");
452        return SYS_ERR_OK;
453    }
454
455    if (state.filter == NULL) {
456        return NET_FILTER_ERR_NOT_INITIALIZED;
457    }
458
459    struct net_filter_state *st = state.filter;
460
461    // get current config
462    struct in_addr dst_ip;
463    err = netif_get_ipconfig(&dst_ip, NULL, NULL);
464    if (err_is_fail(err)) {
465        return err;
466    }
467
468    struct net_filter_ip ip = {
469        .qid = state.queueid,
470        .ip_src = (uint32_t) src->s_addr,
471        .ip_dst = (uint32_t) dst_ip.s_addr,
472        .port_dst = dst_port,
473        .port_src = src_port,
474    };
475
476    if (tcp) {
477        ip.type = NET_FILTER_TCP;
478    } else {
479        ip.type = NET_FILTER_UDP;
480    }
481
482    return net_filter_ip_install(st, &ip);
483}
484
485/**
486 * @brief Remove L3/L4 filter
487 *
488 * @param tcp       should TCP packets be filtered or UPD
489 * @param src_ip    source ip of the filter, 0 for wildcard
490 * @param src_port  source port of the filter, 0 for wildcard
491 * @param dst_port  destination port fo the filter
492 *
493 * @return SYS_ERR_OK on success, NET_FILTER_ERR_* on failure
494 */
495errval_t networking_remove_ip_filter(bool tcp, struct in_addr *src,
496                                     uint16_t src_port, uint16_t dst_port)
497{
498
499    errval_t err;
500    if (!state.hw_filter) {
501        debug_printf("Not removing filter as there are no HW filters");
502        return SYS_ERR_OK;
503    }
504
505    if (state.filter == NULL) {
506        return NET_FILTER_ERR_NOT_INITIALIZED;
507    }
508
509    struct net_filter_state *st = state.filter;
510
511    // get current config
512    struct in_addr dst_ip;
513    err = netif_get_ipconfig(&dst_ip, NULL, NULL);
514    if (err_is_fail(err)) {
515        return err;
516    }
517
518    struct net_filter_ip ip = {
519        .qid = state.queueid,
520        .ip_src = (uint32_t) src->s_addr,
521        .ip_dst = (uint32_t) dst_ip.s_addr,
522        .port_dst = dst_port,
523        .port_src = src_port,
524    };
525
526    if (tcp) {
527        ip.type = NET_FILTER_TCP;
528    } else {
529        ip.type = NET_FILTER_UDP;
530    }
531
532    return net_filter_ip_remove(st, &ip);
533}
534