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, Universit��tstrasse 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <stdbool.h> 13#include <barrelfish/barrelfish.h> 14#include <barrelfish/waitset.h> 15#include <devif/queue_interface.h> 16#include <devif/queue_interface_backend.h> 17#include <devif/backends/net/udp.h> 18#include <lwip/inet_chksum.h> 19#include <lwip/lwip/inet.h> 20#include <net_interfaces/flags.h> 21#include <net/net.h> 22#include <net/net_filter.h> 23#include <net/dhcp.h> 24#include "../headers.h" 25 26#define MAX_NUM_REGIONS 64 27 28//#define DEBUG_ENABLED 29 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__); \ 33 printf(x);\ 34 } while (0) 35 36#else 37#define DEBUG(x...) ((void)0) 38#endif 39 40struct region_vaddr { 41 void* va; 42 regionid_t rid; 43}; 44 45struct udp_q { 46 struct devq my_q; 47 struct devq* q; 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; 51}; 52 53 54#ifdef DEBUG_ENABLED 55static void print_buffer(struct udp_q* q, void* start, uint64_t len) 56{ 57 uint8_t* buf = (uint8_t*) start; 58 printf("Packet in region at address %p len %zu \n", 59 buf, len); 60 for (int i = 0; i < len; i+=2) { 61 if (((i % 16) == 0) && i > 0) { 62 printf("\n"); 63 } 64 printf("%2X", buf[i]); 65 printf("%2X ", buf[i+1]); 66 } 67 printf("\n"); 68} 69#endif 70 71static errval_t udp_register(struct devq* q, struct capref cap, 72 regionid_t rid) 73{ 74 75 errval_t err; 76 struct frame_identity frameid = { .base = 0, .bytes = 0 }; 77 78 struct udp_q* que = (struct udp_q*) q; 79 80 // Map device registers 81 invoke_frame_identify(cap, &frameid); 82 83 err = vspace_map_one_frame_attr(&que->regions[rid % MAX_NUM_REGIONS].va, 84 frameid.bytes, cap, VREGION_FLAGS_READ_WRITE, 85 NULL, NULL); 86 if (err_is_fail(err)) { 87 DEBUG_ERR(err, "vspace_map_one_frame failed"); 88 return err; 89 } 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); 93 94 return que->q->f.reg(que->q, cap, rid); 95} 96 97static errval_t udp_deregister(struct devq* q, regionid_t rid) 98{ 99 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); 104} 105 106 107static errval_t udp_control(struct devq* q, uint64_t cmd, uint64_t value, 108 uint64_t* result) 109{ 110 struct udp_q* que = (struct udp_q*) q; 111 return que->q->f.ctrl(que->q, cmd, value, result); 112} 113 114 115static errval_t udp_notify(struct devq* q) 116{ 117 struct udp_q* que = (struct udp_q*) q; 118 return que->q->f.notify(que->q); 119} 120 121static 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, 124 uint64_t flags) 125{ 126 127 // for now limit length 128 // TODO fragmentation 129 130 struct udp_q* que = (struct udp_q*) q; 131 if (flags & NETIF_TXFLAG) { 132 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); 137 138 assert(que->regions[rid % MAX_NUM_REGIONS].va != NULL); 139 140 uint8_t* start = (uint8_t*) que->regions[rid % MAX_NUM_REGIONS].va + 141 offset + valid_data + ETH_HLEN + IP_HLEN; 142 143 memcpy(start, &que->header, sizeof(que->header)); 144 145 return que->q->f.enq(que->q, rid, offset, length, valid_data, 146 valid_length + UDP_HLEN, flags); 147 } 148 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); 155 } 156 157 return NET_QUEUE_ERR_UNKNOWN_BUF_TYPE; 158} 159 160static 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) 163{ 164 errval_t err; 165 struct udp_q* que = (struct udp_q*) q; 166 167 err = que->q->f.deq(que->q, rid, offset, length, valid_data, valid_length, flags); 168 if (err_is_fail(err)) { 169 return err; 170 } 171 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); 176 177 struct udp_hdr* header = (struct udp_hdr*) 178 (que->regions[*rid % MAX_NUM_REGIONS].va + 179 *offset + *valid_data); 180 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); 187 } 188 189#ifdef DEBUG_ENABLED 190 print_buffer(que, que->regions[*rid % MAX_NUM_REGIONS].va + *offset, *valid_length); 191#endif 192 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); 196 return SYS_ERR_OK; 197 } 198 199#ifdef DEBUG_ENABLED 200 DEBUG("TX rid: %d offset %ld length %ld \n", *rid, *offset, 201 *valid_length); 202#endif 203 204 return SYS_ERR_OK; 205} 206 207/* 208 * Public functions 209 * 210 */ 211errval_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, void(*interrupt)(void*), bool poll) 214{ 215 errval_t err; 216 struct udp_q* que; 217 que = calloc(1, sizeof(struct udp_q)); 218 assert(que); 219 220 uint32_t src_ip; 221 err = net_config_current_ip_query(NET_FLAGS_BLOCKING_INIT, &src_ip); 222 if (err_is_fail(err)) { 223 return err; 224 } 225 226 // init other queue 227 uint64_t qid; 228 err = ip_create((struct ip_q**) &que->q, card_name, &qid, UDP_PROT, dst_ip, 229 interrupt, poll); 230 if (err_is_fail(err)) { 231 return err; 232 } 233 234 err = net_filter_init(&que->filter, card_name); 235 if (err_is_fail(err)) { 236 return err; 237 } 238 239 src_ip = htonl(src_ip); 240 struct net_filter_ip ip = { 241 .qid = qid, 242 .ip_src = dst_ip, 243 .ip_dst = src_ip, 244 .port_dst = dst_port, 245 .type = NET_FILTER_UDP, 246 }; 247 248 err = net_filter_ip_install(que->filter, &ip); 249 if (err_is_fail(err)) { 250 return err; 251 } 252 253 err = devq_init(&que->my_q, false); 254 if (err_is_fail(err)) { 255 errval_t err2; 256 err2 = net_filter_ip_remove(que->filter, &ip); 257 if (err_is_fail(err)) { 258 return err_push(err2, err); 259 } 260 return err; 261 } 262 263 // UDP fields 264 que->header.src = htons(src_port); 265 que->header.dest = htons(dst_port); 266 que->header.chksum = 0x0; 267 268 que->my_q.f.reg = udp_register; 269 que->my_q.f.dereg = udp_deregister; 270 que->my_q.f.ctrl = udp_control; 271 que->my_q.f.notify = udp_notify; 272 que->my_q.f.enq = udp_enqueue; 273 que->my_q.f.deq = udp_dequeue; 274 *q = que; 275 276 return SYS_ERR_OK; 277} 278 279errval_t udp_destroy(struct udp_q* q) 280{ 281 // TODO destroy q->q; 282 free(q); 283 284 return SYS_ERR_OK; 285} 286 287errval_t udp_write_buffer(struct udp_q* q, regionid_t rid, genoffset_t offset, 288 void* data, uint16_t len) 289{ 290 assert(len <= 1500); 291 if (q->regions[rid % MAX_NUM_REGIONS].va != NULL) { 292 uint8_t* start = q->regions[rid % MAX_NUM_REGIONS].va + offset 293 + sizeof (struct udp_hdr) 294 + sizeof (struct ip_hdr) 295 + sizeof (struct eth_hdr); 296 memcpy(start, data, len); 297 return SYS_ERR_OK; 298 } else { 299 return DEVQ_ERR_INVALID_REGION_ARGS; 300 } 301} 302 303 304 305