1/**
2 * \file
3 * \brief Communication between LWIP and net_ports deamon
4 *
5 *  This code provides interface to commuincate with net_ports for purposes like
6 *  opening/closing ports, get IP address, etc
7 */
8
9/*
10 * Copyright (c) 2007-11 ETH Zurich
11 * All rights reserved.
12 *
13 * This file is distributed under the terms in the attached LICENSE file.
14 * If you do not find this file, copies can be found by writing to:
15 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
16 */
17
18#include <barrelfish/barrelfish.h>
19#include <barrelfish/nameservice_client.h>
20#include <net_interfaces/net_interfaces.h>
21#include <trace/trace.h>
22#include <netif/etharp.h>
23#include <netif/bfeth.h>
24#include "lwip/init.h"
25#include <netbench/netbench.h>
26#include <if/net_ports_defs.h>
27#include <if/net_ports_defs.h>
28#include <stdio.h>
29#include <assert.h>
30#include "lwip/barrelfish.h"
31#include "idc_barrelfish.h"
32
33#include "lwip_barrelfish_debug.h"
34
35// Can be used
36#define DISABLE_PORTMNG 1
37
38
39/*
40 * If we are the owner of lwip stack, then we dont need rpc
41 */
42static bool is_owner = 0;
43static uint16_t(*alloc_tcp_port) (void) = NULL;
44static uint16_t(*alloc_udp_port) (void) = NULL;
45
46static uint16_t(*bind_port) (uint16_t port, net_ports_port_type_t type) = NULL;
47static void (*close_port) (uint16_t port, net_ports_port_type_t type) = NULL;
48
49/*************************************************************
50 * \defGroup LocalStates Local states
51 *
52 * @{
53 *
54 ****************************************************************/
55static struct net_ports_binding *net_ports_binding;
56static bool net_ports_service_connected = false;
57
58static net_ports_appid_t appid_delete = 0;
59
60static struct netif netif;
61
62//static struct thread *trace_thread = NULL;
63void thread_debug_regs(struct thread *t);
64
65// Variables shared with idc_barrelfish.c
66extern struct waitset *lwip_waitset;
67extern uint64_t lwip_queue_id;
68
69/**
70 * \brief handle msgs on the tx, rx and then the rest connections in that priority
71 */
72void network_polling_loop(void)
73{
74    errval_t err;
75
76    while (1) {
77        err = event_dispatch(lwip_waitset);
78        if (err_is_fail(err)) {
79            DEBUG_ERR(err, "in event_dispatch");
80            break;
81        }
82#if 0
83        if (trace_thread != NULL) {
84            static int iter = 0;
85
86            iter++;
87            if (iter % 10 == 0) {
88                thread_debug_regs(trace_thread);
89            }
90        }
91#endif
92    }
93}
94
95errval_t lwip_err_to_errval(err_t e)
96{
97    switch (e) {
98        case ERR_OK:
99            return SYS_ERR_OK;
100        case ERR_MEM:
101            return LWIP_ERR_MEM;
102        case ERR_BUF:
103            return LWIP_ERR_BUF;
104        case ERR_TIMEOUT:
105            return LWIP_ERR_TIMEOUT;
106        case ERR_RTE:
107            return LWIP_ERR_RTE;
108        case ERR_ABRT:
109            return LWIP_ERR_ABRT;
110        case ERR_RST:
111            return LWIP_ERR_RST;
112        case ERR_CLSD:
113            return LWIP_ERR_CLSD;
114        case ERR_CONN:
115            return LWIP_ERR_CONN;
116        case ERR_VAL:
117            return LWIP_ERR_VAL;
118        case ERR_ARG:
119            return LWIP_ERR_ARG;
120        case ERR_USE:
121            return LWIP_ERR_USE;
122        case ERR_IF:
123            return LWIP_ERR_IF;
124        case ERR_ISCONN:
125            return LWIP_ERR_ISCONN;
126        case ERR_INPROGRESS:
127            return LWIP_ERR_INPROGRESS;
128        default:
129            USER_PANIC("unknown LWIP error in lwip_err_to_errval");
130    }
131}
132
133/***************************************************************
134    Adding new code to communicate with net_ports server
135*/
136
137/****************************************************************
138 * \defGroup net_ports_connectivity  Code to connect and work with net_ports.
139 *
140 * @{
141 *
142 *****************************************************************/
143/**
144 * \brief Callback function when bind is successful.
145 *  Code inspired (ie. copied) from "start_client" function.
146 */
147static void net_ports_bind_cb(void *st, errval_t err, struct net_ports_binding *b)
148{
149    if (err_is_fail(err)) {
150        DEBUG_ERR(err, "bind failed for net_ports");
151        abort();
152    }
153    LWIPBF_DEBUG("net_ports_bind_cb: called\n");
154
155    net_ports_binding = b;
156    net_ports_rpc_client_init(net_ports_binding);
157    net_ports_service_connected = true;
158    LWIPBF_DEBUG("net_ports_bind_cb: net_ports bind successful!\n");
159}
160
161/**
162 * \brief Connects the lwip instance with net_ports daemon.
163 *  Code inspired (ie. copied) from "start_client" function.
164 */
165static void init_net_ports_connection(char *service_name)
166{
167    LWIPBF_DEBUG("init_net_ports_connection: called\n");
168    assert(service_name != NULL);
169    LWIPBF_DEBUG("init_net_ports_connection: connecting to [%s]\n", service_name);
170
171    errval_t err;
172    iref_t iref;
173
174    LWIPBF_DEBUG("init_net_ports_connection: resolving driver %s\n", service_name);
175
176    err = nameservice_blocking_lookup(service_name, &iref);
177    if (err_is_fail(err)) {
178        DEBUG_ERR(err, "lwip: could not connect to the net_ports driver.\n"
179                  "Terminating.\n");
180        abort();
181    }
182    assert(iref != 0);
183
184    LWIPBF_DEBUG("init_net_ports_connection: connecting\n");
185
186    err = net_ports_bind(iref, net_ports_bind_cb, NULL, lwip_waitset,
187                    IDC_BIND_FLAGS_DEFAULT);
188    if (!err_is_ok(err)) {
189        printf("net_ports_bind_cb failed in init\n");
190        abort();
191    }
192
193    LWIPBF_DEBUG("init_net_ports_connection: terminated\n");
194}
195
196
197// Connects to the port manager service
198// Blocking call: returns only when connection is done
199// In case of error, it will panic!!
200void idc_connect_port_manager_service(char *service_name)
201{
202    //LWIPBF_DEBUG
203    printf("idc_c_port_mng_srv: trying to [%s]\n", service_name);
204
205    /* FIXME: decide if this is the best place to connect with net_ports */
206    init_net_ports_connection(service_name);
207
208    // XXX: dispatch on default waitset until bound
209    struct waitset *dws = get_default_waitset();
210
211    while (!net_ports_service_connected) {
212        errval_t err = event_dispatch(dws);
213
214        if (err_is_fail(err)) {
215            USER_PANIC_ERR(err, "in event_dispatch while binding");
216        }
217    }
218    //LWIPBF_DEBUG
219    printf("idc_c_port_mng_srv: success [%s]\n", service_name);
220}
221
222
223void idc_get_ip(void)
224{
225    if (is_owner) {
226        assert(!"owner of lwip should never ask for ip through API\n");
227        abort();
228    }
229    LWIPBF_DEBUG("On the way of getting IP\n");
230
231    errval_t err;
232    struct ip_addr ip, gw, nm;
233
234    err = net_ports_binding->rpc_tx_vtbl.get_ip_info(net_ports_binding, &ip.addr, &gw.addr,
235            &nm.addr);
236    if (err_is_fail(err)) {
237        USER_PANIC_ERR(err, "error sending get_ip_info");
238    }
239
240    LWIPBF_DEBUG("got answer, now setting up things\n");
241    netif_add(&netif, &ip, &nm, &gw, NULL, bfeth_init, ethernet_input);
242    netif_set_default(&netif);
243    netif_set_up(&netif);
244
245    LWIPBF_DEBUG("client1: owner has the IP address %d.%d.%d.%d\n",
246                 ip4_addr1(&netif.ip_addr), ip4_addr2(&netif.ip_addr),
247                 ip4_addr3(&netif.ip_addr), ip4_addr4(&netif.ip_addr));
248}
249
250
251
252/***********************************************************/
253/************* Port management *******************/
254
255static err_t idc_close_port(uint16_t port, int port_type)
256{
257    LWIPBF_DEBUG("idc_close_port: called\n");
258    if (is_owner) {
259        close_port((uint64_t) port, port_type);
260        return ERR_OK;
261    }
262
263    LWIPBF_DEBUG("idc_close_port: called\n");
264
265    errval_t err, msgerr;
266
267    err = net_ports_binding->rpc_tx_vtbl.close_port(net_ports_binding, port_type, port,
268                                  appid_delete, lwip_queue_id,
269                                  &msgerr);
270    if (err_is_fail(err)) {
271        USER_PANIC_ERR(err, "error sending get_ip_info");
272    }
273
274    LWIPBF_DEBUG("idc_close_tcp_port: returning\n");
275
276    if (msgerr == PORT_ERR_IN_USE) {
277        return ERR_USE;
278    }                           // FIXME: other errors?
279    return ERR_OK;
280}
281
282
283err_t idc_close_udp_port(uint16_t port)
284{
285    return idc_close_port(port, net_ports_PORT_UDP);
286}
287
288
289err_t idc_close_tcp_port(uint16_t port)
290{
291    return idc_close_port(port, net_ports_PORT_TCP);
292}
293
294static err_t idc_bind_port(uint16_t port, net_ports_port_type_t port_type)
295{
296    if (is_owner) {
297        LWIPBF_DEBUG("idc_bind_port: called by owner\n");
298        return bind_port(port, port_type);
299    }
300
301    LWIPBF_DEBUG("idc_bind_port: called\n");
302
303    errval_t err, msgerr;
304
305    /* getting the proper buffer id's here */
306    err = net_ports_binding->rpc_tx_vtbl.bind_port(net_ports_binding, port_type, port,
307                                  /* buffer for RX */
308                                   get_rx_bufferid(),
309                                  /* buffer for TX */
310                                   get_tx_bufferid(),
311                                  appid_delete, lwip_queue_id,
312                                  &msgerr);
313    if (err_is_fail(err)) {
314        USER_PANIC_ERR(err, "error sending get_ip_info");
315    }
316
317    LWIPBF_DEBUG("idc_new_tcp_port: terminated\n");
318
319    if (msgerr == PORT_ERR_IN_USE) {
320        return ERR_USE;
321    }                           // FIXME: other errors?
322    return ERR_OK;
323}
324
325
326err_t idc_bind_udp_port(uint16_t port)
327{
328    return idc_bind_port(port, net_ports_PORT_UDP);
329}
330
331
332err_t idc_bind_tcp_port(uint16_t port)
333{
334    return idc_bind_port(port, net_ports_PORT_TCP);
335}
336
337static err_t idc_new_port(uint16_t * port_no, net_ports_port_type_t port_type)
338{
339    /* NOTE: function with same name exists in Kaver's code for reference
340       purpose */
341    errval_t err, msgerr;
342
343    //printf
344    LWIPBF_DEBUG
345        ("idc_new_port: ################################### called\n");
346
347    // antoinek: FIXME: Need to figure out how to deal with this
348    //assert(!"NYI");
349
350    /* getting the proper buffer id's here */
351    err = net_ports_binding->rpc_tx_vtbl.get_port(net_ports_binding, port_type,
352                                 /* buffer for RX */
353                                 get_rx_bufferid(),
354                                 /* buffer for TX */
355                                 get_tx_bufferid(),
356                                 appid_delete, lwip_queue_id,
357                                 &msgerr, port_no);
358    if (err_is_fail(err)) {
359        USER_PANIC_ERR(err, "error sending get_ip_info");
360    }
361
362    //printf
363    LWIPBF_DEBUG
364        ("idc_new_port: ################################### terminated\n");
365    return msgerr;
366}
367
368err_t idc_tcp_new_port(uint16_t * port_no)
369{
370    if (is_owner) {
371        *port_no = alloc_tcp_port();
372        return SYS_ERR_OK;
373    }
374
375    return idc_new_port(port_no, net_ports_PORT_TCP);
376}
377
378
379err_t idc_udp_new_port(uint16_t * port_no)
380{
381    if (is_owner) {
382        *port_no = alloc_udp_port();
383        return SYS_ERR_OK;
384
385    }
386
387    return idc_new_port(port_no, net_ports_PORT_UDP);
388}
389
390
391static err_t idc_redirect(struct ip_addr *local_ip, u16_t local_port,
392                          struct ip_addr *remote_ip, u16_t remote_port,
393                          net_ports_port_type_t port_type)
394{
395    if (is_owner) {
396        // redirecting doesn't make sense if we are the owner
397        return ERR_USE;         // TODO: correct error
398    }
399
400    errval_t msgerr;
401//    errval_t err;
402
403    USER_PANIC("Pause: NYI");
404    abort();
405
406#if 0
407    /* getting the proper buffer id's here */
408    err =
409      net_ports_binding->rpc_tx_vtbl.redirect(net_ports_binding, port_type, local_ip->addr, local_port,
410                             remote_ip->addr, remote_port,
411                             /* buffer for RX */
412                             get_rx_bufferid(),
413                             /* buffer for TX */
414                             get_tx_bufferid(),
415                             &msgerr);
416    if (err_is_fail(err)) {
417        USER_PANIC_ERR(err, "error sending redirect");
418    }
419#endif // 0
420
421    if (msgerr == PORT_ERR_IN_USE) {
422        return ERR_USE;
423    } else if (msgerr == PORT_ERR_REDIRECT) {
424        return ERR_USE;         // TODO: correct error
425    }
426// FIXME: other errors?
427    return ERR_OK;
428}
429
430static err_t idc_pause(struct ip_addr *local_ip, u16_t local_port,
431                       struct ip_addr *remote_ip, u16_t remote_port,
432                       net_ports_port_type_t port_type)
433{
434    if (is_owner) {
435        // redirecting doesn't make sense if we are the owner
436        return ERR_USE;         // TODO: correct error
437    }
438
439    errval_t msgerr;
440//    errval_t err;
441
442    USER_PANIC("Pausing not support anymore");
443    abort();
444#if 0
445    /* getting the proper buffer id's here */
446    err =
447      net_ports_binding->rpc_tx_vtbl.redirect_pause(net_ports_binding, port_type, local_ip->addr,
448                                   local_port, remote_ip->addr, remote_port,
449                                   /* buffer for RX */
450                                   ((struct client_closure_NC *)
451                                    driver_connection[RECEIVE_CONNECTION]->st)->
452                                   buff_ptr->buffer_id,
453                                   /* buffer for TX */
454                                   ((struct client_closure_NC *)
455                                    driver_connection[TRANSMIT_CONNECTION]->
456                                    st)->buff_ptr->buffer_id, &msgerr);
457    if (err_is_fail(err)) {
458        USER_PANIC_ERR(err, "error sending pause");
459    }
460
461#endif // 0
462    if (msgerr == PORT_ERR_IN_USE) {
463        return ERR_USE;
464    } else if (msgerr == PORT_ERR_REDIRECT) {
465        return ERR_USE;         // TODO: correct error
466    }
467// FIXME: other errors?
468    return ERR_OK;
469}
470
471
472/*
473err_t idc_redirect_udp_port(uint16_t port)
474{
475    return idc_redirect_port(port, net_ports_PORT_UDP);
476}
477*/
478
479err_t idc_redirect_tcp(struct ip_addr * local_ip, u16_t local_port,
480                       struct ip_addr * remote_ip, u16_t remote_port)
481{
482    return idc_redirect(local_ip, local_port, remote_ip, remote_port,
483                        net_ports_PORT_TCP);
484}
485
486err_t idc_pause_tcp(struct ip_addr * local_ip, u16_t local_port,
487                    struct ip_addr * remote_ip, u16_t remote_port)
488{
489    return idc_pause(local_ip, local_port, remote_ip, remote_port,
490                     net_ports_PORT_TCP);
491}
492
493
494void perform_ownership_housekeeping(uint16_t(*alloc_tcp_ptr) (void),
495                                    uint16_t(*alloc_udp_ptr) (void),
496                                    uint16_t(*bind_port_ptr) (uint16_t,
497                                              enum net_ports_port_type_t),
498                                    void (*close_port_ptr) (uint16_t,
499                                              enum net_ports_port_type_t))
500{
501    is_owner = true;
502    alloc_tcp_port = alloc_tcp_ptr;
503    alloc_udp_port = alloc_udp_ptr;
504    bind_port = bind_port_ptr;
505    close_port = close_port_ptr;
506}
507