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
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include <barrelfish/barrelfish.h>
16#include <barrelfish/nameservice_client.h>
17#include <if/net_filter_defs.h>
18#include <if/net_filter_rpcclient_defs.h>
19
20#include <net/net_filter.h>
21
22#include "networking_internal.h"
23#include "debug.h"
24
25#define MAX_NAME 128
26
27#define NETDEBUG_SUBSYSTEM "filter"
28
29/******************************************************************************
30 * Connection setup
31 ******************************************************************************/
32
33// Callback for bind
34static void bind_cb(void *st, errval_t err, struct net_filter_binding *b)
35{
36    struct net_filter_state* filt = (struct net_filter_state*) st;
37    assert(err_is_ok(err));
38
39    NETDEBUG("Sucessfully connected to management interface\n");
40
41    filt->b = b;
42    net_filter_rpc_client_init(filt->b);
43    filt->bound = true;
44}
45
46
47/** Open connection to management interface */
48static errval_t connect_to_net_filter(struct net_filter_state* st,
49                                      const char *dev_name)
50{
51    errval_t r;
52    iref_t iref;
53    const char* prefix = "net_filter_";
54    char name[strlen(dev_name) + strlen(prefix) + 1];
55
56    // Build label for management service
57    sprintf(name, "%s%s", prefix, dev_name);
58
59    NETDEBUG("Name lookup\n");
60    // Connect to service
61    r = nameservice_blocking_lookup(name, &iref);
62    if (err_is_fail(r)) {
63        return r;
64    }
65
66    NETDEBUG("Binding\n");
67    r = net_filter_bind(iref, bind_cb, st, get_default_waitset(),
68            IDC_BIND_FLAGS_DEFAULT);
69    if (err_is_fail(r)) {
70        return r;
71    }
72
73    NETDEBUG("Waiting to bind\n");
74    while(st->bound == false) {
75        event_dispatch(get_default_waitset());
76    }
77
78    NETDEBUG("finished connecting\n");
79    return SYS_ERR_OK;
80}
81
82
83/** Open connection to management interface */
84static errval_t connect_to_net_filter_ep(struct net_filter_state* st,
85                                         struct capref ep)
86{
87    errval_t r;
88
89    NETDEBUG("Binding\n");
90    r = net_filter_bind_to_endpoint(ep, bind_cb, st, get_default_waitset(),
91                                    IDC_BIND_FLAGS_DEFAULT);
92    if (err_is_fail(r)) {
93        return r;
94    }
95
96    NETDEBUG("Waiting to bind\n");
97    while(st->bound == false) {
98        event_dispatch(get_default_waitset());
99    }
100
101    NETDEBUG("finished connecting\n");
102    return SYS_ERR_OK;
103}
104
105/******************************************************************************
106 * Helper functions
107 ******************************************************************************/
108
109static bool filter_cmp_ip(struct net_filter_ip* f1, struct net_filter_ip* f2)
110{
111    if (f1->ip_src == f2->ip_src &&
112        f1->ip_dst == f2->ip_dst &&
113        f1->port_src == f2->port_src &&
114        f1->port_dst == f2->port_dst &&
115        f1->qid == f2->qid &&
116        f1->type == f2->type) {
117        return true;
118    }
119    return false;
120}
121
122/*
123static bool filter_cmp_mac(struct net_filter_mac* f1, struct net_filter_mac* f2)
124{
125    if (f1->vlan_id == f2->vlan_id &&
126        f1->mac == f2->mac &&
127        f1->type == f2->type) {
128        return true;
129    }
130    return false;
131}
132*/
133/*
134static bool is_reachable(struct net_filter_ip* filt)
135{
136    struct net_filter_ele* cur = filter_state.filters_ip.start;
137
138    while(cur != NULL) {
139        printf("reachable: port_dst: %"PRIu16" %"PRIu16" \n", cur->filter.ip.port_dst, filt->port_dst);
140        if (filter_cmp_ip(&cur->filter.ip, filt)) {
141            return true;
142        }
143        cur = cur->next;
144    }
145    return false;
146}
147*/
148/******************************************************************************
149 * Library function implementation
150 ******************************************************************************/
151
152/**
153 * @brief initalized network filtering. Sets up connection to drivers
154 *        which support hardware filtering
155 *
156 * @param st        returned net filter state;
157 * @param cardname  the card name to be used
158 *
159 * @return SYS_ERR_OK on success, error on failure
160 */
161errval_t net_filter_init(struct net_filter_state** st,
162                         const char* cardname)
163{
164    errval_t err;
165
166    struct net_filter_state* tmp = calloc(1, sizeof(struct net_filter_state));
167    assert(tmp != NULL);
168
169    tmp->filters_ip.start = NULL;
170    tmp->filters_ip.num_ele = 0;
171    tmp->filters_mac.start = NULL;
172    tmp->filters_mac.num_ele = 0;
173
174    // cardname are of the form name:vendor:device:bus:function ..
175    int end = 0;
176    for (; end < strlen(cardname); end++) {
177        if (cardname[end] == ':') {
178            break;
179        }
180    }
181
182    char name[64];
183    strncpy(name, cardname, end);
184    name[end] = '\0';
185
186    printf("cardname %s \n", name);
187    err = connect_to_net_filter(tmp, name);
188    *st = tmp;
189    return err;
190}
191
192
193/**
194 * @brief initalized network filtering. Sets up connection to drivers
195 *        which support hardware filtering
196 *
197 * @param st        returned net filter state;
198 * @param ep        endpoint to card used
199 *
200 * @return SYS_ERR_OK on success, error on failure
201 */
202errval_t net_filter_init_with_ep(struct net_filter_state** st,
203                                 struct capref ep)
204{
205    errval_t err;
206
207    struct net_filter_state* tmp = calloc(1, sizeof(struct net_filter_state));
208    assert(tmp != NULL);
209
210    tmp->filters_ip.start = NULL;
211    tmp->filters_ip.num_ele = 0;
212    tmp->filters_mac.start = NULL;
213    tmp->filters_mac.num_ele = 0;
214
215    err = connect_to_net_filter_ep(tmp, ep);
216    *st = tmp;
217    return err;
218}
219
220
221/**
222 * @brief Installs an L3/L4 filter in the hardware filter
223 *        tables
224 *
225 * @param st    net filter state
226 * @param filt  filter struct
227 *
228 * @return SYS_ERR_OK on success, error on failure
229 */
230errval_t net_filter_ip_install(struct net_filter_state* st,
231                               struct net_filter_ip* filt)
232{
233
234    assert(st->bound);
235    errval_t err;
236    uint64_t filter_id;
237
238    struct net_filter_ele* cur = st->filters_ip.start;
239    struct net_filter_ele* prev = NULL;
240
241    /* go through linked list and find last element
242     (and check if filter is already installed) */
243    if (cur == NULL) {
244        st->filters_ip.start = malloc(sizeof(struct net_filter_ele));
245        cur = st->filters_ip.start;
246    } else {
247        while(cur->next != NULL) {
248            if (filter_cmp_ip(&cur->filter.ip, filt)) {
249                return NET_FILTER_ERR_ALREADY_EXISTS;
250            }
251            prev = cur;
252            cur = cur->next;
253        }
254
255        if (filter_cmp_ip(&cur->filter.ip, filt)) {
256            return NET_FILTER_ERR_ALREADY_EXISTS;
257        }
258
259        cur->next = malloc(sizeof(struct net_filter_ele));
260        cur = cur->next;
261    }
262
263    cur->filter.ip.ip_src = filt->ip_src;
264    cur->filter.ip.ip_dst = filt->ip_dst;
265    cur->filter.ip.port_src = filt->port_src;
266    cur->filter.ip.port_dst = filt->port_dst;
267    cur->filter.ip.qid = filt->qid;
268    cur->filter.ip.type = filt->type;
269    cur->next = NULL;
270    cur->prev = prev;
271
272    st->filters_ip.num_ele++;
273
274    err = st->b->rpc_tx_vtbl.install_filter_ip(st->b,
275                                               filt->type,
276                                               filt->qid,
277                                               filt->ip_src,
278                                               filt->ip_dst,
279                                               filt->port_src,
280                                               filt->port_dst,
281                                               &filter_id);
282    if (err_is_fail(err)) {
283        free(cur);
284        return err;
285    }
286
287    cur->filter_id = filter_id;
288    return SYS_ERR_OK;
289}
290
291
292/**
293 * @brief Removes an L3/L4 filter in the hardware filter
294 *        tables
295 *
296 * @param st    net filter state
297 * @param filt  filter struct
298 *
299 * @return SYS_ERR_OK on success, error on failure
300 */
301errval_t net_filter_ip_remove(struct net_filter_state* st,
302                              struct net_filter_ip* filt)
303{
304
305    assert(st->bound);
306    errval_t err, err2;
307    uint64_t filter_id = (uint64_t)-1;
308
309    struct net_filter_ele* cur = st->filters_ip.start;
310    struct net_filter_ele* prev = NULL;
311
312
313    // no entries
314    if (cur == NULL) {
315        return NET_FILTER_ERR_NOT_FOUND;
316    }
317
318    // Multiple entries
319    while(cur != NULL) {
320        if (filter_cmp_ip(&cur->filter.ip, filt)) {
321            filter_id = cur->filter_id;
322            break;
323        }
324        prev = cur;
325        cur = cur->next;
326    }
327
328
329    if (filter_id == (uint64_t) -1) {
330        return NET_FILTER_ERR_NOT_FOUND;
331    }
332
333    err = st->b->rpc_tx_vtbl.remove_filter(st->b,
334                                           filt->type,
335                                           filter_id,
336                                           &err2);
337    if (err_is_fail(err) || err_is_fail(err2)) {
338        return err_is_fail(err) ? err: err2;
339    }
340
341    // remove from queue
342    if (prev != NULL) { // check if first
343        prev->next = cur->next;
344        if (cur->next != NULL) { // check if last
345            cur->next->prev = prev;
346        }
347    } else {
348        st->filters_ip.start = cur->next;
349    }
350
351
352    free(cur);
353
354    st->filters_ip.num_ele--;
355
356    return SYS_ERR_OK;
357}
358
359errval_t net_filter_mac_install(struct net_filter_state* st,
360                                struct net_filter_mac* filt)
361{
362   USER_PANIC("NYI \n");
363}
364
365
366errval_t net_filter_mac_remove(struct net_filter_state* st,
367                               struct net_filter_mac* filt)
368{
369   USER_PANIC("NYI \n");
370}
371