2 * Copyright (c) 2017, ETH Zurich.
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, Universitätstrasse 4, CH-8092 Zurich. Attn: Systems Group.
13 #include <barrelfish/barrelfish.h>
14 #include <barrelfish/waitset.h>
15 #include <devif/queue_interface.h>
16 #include <devif/backends/net/udp.h>
17 #include <lwip/inet_chksum.h>
18 #include <lwip/lwip/inet.h>
19 #include <net_interfaces/flags.h>
21 #include <net/net_filter.h>
23 #include "../../../queue_interface_internal.h"
24 #include "../headers.h"
26 #define MAX_NUM_REGIONS 64
28 //#define DEBUG_ENABLED
30 #if defined(DEBUG_ENABLED)
31 #define DEBUG(x...) do { printf("UDP_QUEUE: %s.%d:%s:%d: ", \
32 disp_name(), disp_get_core_id(), __func__, __LINE__); \
37 #define DEBUG(x...) ((void)0)
48 struct udp_hdr header; // can fill in this header and reuse it by copying
49 struct region_vaddr regions[MAX_NUM_REGIONS];
50 struct net_filter_state* filter;
55 static void print_buffer(struct udp_q* q, void* start, uint64_t len)
57 uint8_t* buf = (uint8_t*) start;
58 printf("Packet in region at address %p len %zu \n",
60 for (int i = 0; i < len; i+=2) {
61 if (((i % 16) == 0) && i > 0) {
64 printf("%2X", buf[i]);
65 printf("%2X ", buf[i+1]);
71 static errval_t udp_register(struct devq* q, struct capref cap,
76 struct frame_identity frameid = { .base = 0, .bytes = 0 };
78 struct udp_q* que = (struct udp_q*) q;
80 // Map device registers
81 invoke_frame_identify(cap, &frameid);
83 err = vspace_map_one_frame_attr(&que->regions[rid % MAX_NUM_REGIONS].va,
84 frameid.bytes, cap, VREGION_FLAGS_READ_WRITE,
86 if (err_is_fail(err)) {
87 DEBUG_ERR(err, "vspace_map_one_frame failed");
90 que->regions[rid % MAX_NUM_REGIONS].rid = rid;
91 DEBUG("id-%d va-%p \n", que->regions[rid % MAX_NUM_REGIONS].rid,
92 que->regions[rid % MAX_NUM_REGIONS].va);
94 return que->q->f.reg(que->q, cap, rid);
97 static errval_t udp_deregister(struct devq* q, regionid_t rid)
100 struct udp_q* que = (struct udp_q*) q;
101 que->regions[rid % MAX_NUM_REGIONS].va = NULL;
102 que->regions[rid % MAX_NUM_REGIONS].rid = 0;
103 return que->q->f.dereg(que->q, rid);
107 static errval_t udp_control(struct devq* q, uint64_t cmd, uint64_t value,
110 struct udp_q* que = (struct udp_q*) q;
111 return que->q->f.ctrl(que->q, cmd, value, result);
115 static errval_t udp_notify(struct devq* q)
117 struct udp_q* que = (struct udp_q*) q;
118 return que->q->f.notify(que->q);
121 static errval_t udp_enqueue(struct devq* q, regionid_t rid,
122 genoffset_t offset, genoffset_t length,
123 genoffset_t valid_data, genoffset_t valid_length,
127 // for now limit length
128 // TODO fragmentation
130 struct udp_q* que = (struct udp_q*) q;
131 if (flags & NETIF_TXFLAG) {
133 DEBUG("TX rid: %d offset %ld length %ld valid_length %ld \n", rid, offset,
134 length, valid_length);
135 assert(valid_length <= 1500);
136 que->header.len = htons(valid_length + UDP_HLEN);
138 assert(que->regions[rid % MAX_NUM_REGIONS].va != NULL);
140 uint8_t* start = (uint8_t*) que->regions[rid % MAX_NUM_REGIONS].va +
141 offset + valid_data + ETH_HLEN + IP_HLEN;
143 memcpy(start, &que->header, sizeof(que->header));
145 return que->q->f.enq(que->q, rid, offset, length, valid_data,
146 valid_length + UDP_HLEN, flags);
149 if (flags & NETIF_RXFLAG) {
150 assert(valid_length <= 2048);
151 DEBUG("RX rid: %d offset %ld length %ld valid_length %ld \n", rid, offset,
152 length, valid_length);
153 return que->q->f.enq(que->q, rid, offset, length, valid_data,
154 valid_length, flags);
157 return NET_QUEUE_ERR_UNKNOWN_BUF_TYPE;
160 static errval_t udp_dequeue(struct devq* q, regionid_t* rid, genoffset_t* offset,
161 genoffset_t* length, genoffset_t* valid_data,
162 genoffset_t* valid_length, uint64_t* flags)
165 struct udp_q* que = (struct udp_q*) q;
167 err = que->q->f.deq(que->q, rid, offset, length, valid_data, valid_length, flags);
168 if (err_is_fail(err)) {
172 if (*flags & NETIF_RXFLAG) {
173 DEBUG("RX rid: %d offset %ld valid_data %ld length %ld va %p \n", *rid,
174 *offset, *valid_data,
175 *valid_length, que->regions[*rid % MAX_NUM_REGIONS].va + *offset + *valid_data);
177 struct udp_hdr* header = (struct udp_hdr*)
178 (que->regions[*rid % MAX_NUM_REGIONS].va +
179 *offset + *valid_data);
181 // Correct port for this queue?
182 if (header->dest != que->header.dest) {
183 printf("UDP queue: dropping packet, wrong port %d %d \n",
184 header->dest, que->header.dest);
185 err = que->q->f.enq(que->q, *rid, *offset, *length, 0, 0, NETIF_RXFLAG);
186 return err_push(err, NET_QUEUE_ERR_WRONG_PORT);
190 print_buffer(que, que->regions[*rid % MAX_NUM_REGIONS].va + *offset, *valid_length);
193 *valid_length = ntohs(header->len) - UDP_HLEN;
194 *valid_data += UDP_HLEN;
195 //print_buffer(que, que->regions[*rid % MAX_NUM_REGIONS].va + *offset+ *valid_data, *valid_length);
200 DEBUG("TX rid: %d offset %ld length %ld \n", *rid, *offset,
211 errval_t udp_create(struct udp_q** q, const char* card_name,
212 uint16_t src_port, uint16_t dst_port,
213 uint32_t dst_ip, struct eth_addr dst_mac,
214 void(*interrupt)(void*), bool poll)
218 que = calloc(1, sizeof(struct udp_q));
222 err = net_config_current_ip_query(NET_FLAGS_BLOCKING_INIT, &src_ip);
223 if (err_is_fail(err)) {
229 err = ip_create((struct ip_q**) &que->q, card_name, &qid, UDP_PROT, dst_ip,
230 dst_mac, interrupt, poll);
231 if (err_is_fail(err)) {
235 err = net_filter_init(&que->filter, card_name);
236 if (err_is_fail(err)) {
240 src_ip = htonl(src_ip);
241 struct net_filter_ip ip = {
245 .port_dst = dst_port,
246 .type = NET_FILTER_UDP,
249 err = net_filter_ip_install(que->filter, &ip);
250 if (err_is_fail(err)) {
254 err = devq_init(&que->my_q, false);
255 if (err_is_fail(err)) {
257 err2 = net_filter_ip_remove(que->filter, &ip);
258 if (err_is_fail(err)) {
259 return err_push(err2, err);
265 que->header.src = htons(src_port);
266 que->header.dest = htons(dst_port);
267 que->header.chksum = 0x0;
269 que->my_q.f.reg = udp_register;
270 que->my_q.f.dereg = udp_deregister;
271 que->my_q.f.ctrl = udp_control;
272 que->my_q.f.notify = udp_notify;
273 que->my_q.f.enq = udp_enqueue;
274 que->my_q.f.deq = udp_dequeue;
280 errval_t udp_destroy(struct udp_q* q)
282 // TODO destroy q->q;
288 errval_t udp_write_buffer(struct udp_q* q, regionid_t rid, genoffset_t offset,
289 void* data, uint16_t len)
292 if (q->regions[rid % MAX_NUM_REGIONS].va != NULL) {
293 uint8_t* start = q->regions[rid % MAX_NUM_REGIONS].va + offset
294 + sizeof (struct udp_hdr)
295 + sizeof (struct ip_hdr)
296 + sizeof (struct eth_hdr);
297 memcpy(start, data, len);
300 return DEVQ_ERR_INVALID_REGION_ARGS;