CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2
Fork of USB_Ethernet by
modules/pico_udp.c@2:540f6e142d59, 2013-08-03 (annotated)
- Committer:
- daniele
- Date:
- Sat Aug 03 13:16:14 2013 +0000
- Revision:
- 2:540f6e142d59
Moved to single package
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
daniele | 2:540f6e142d59 | 1 | /********************************************************************* |
daniele | 2:540f6e142d59 | 2 | PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. |
daniele | 2:540f6e142d59 | 3 | See LICENSE and COPYING for usage. |
daniele | 2:540f6e142d59 | 4 | |
daniele | 2:540f6e142d59 | 5 | . |
daniele | 2:540f6e142d59 | 6 | |
daniele | 2:540f6e142d59 | 7 | Authors: Daniele Lacamera |
daniele | 2:540f6e142d59 | 8 | *********************************************************************/ |
daniele | 2:540f6e142d59 | 9 | |
daniele | 2:540f6e142d59 | 10 | |
daniele | 2:540f6e142d59 | 11 | #include "pico_udp.h" |
daniele | 2:540f6e142d59 | 12 | #include "pico_config.h" |
daniele | 2:540f6e142d59 | 13 | #include "pico_eth.h" |
daniele | 2:540f6e142d59 | 14 | #include "pico_socket.h" |
daniele | 2:540f6e142d59 | 15 | #include "pico_stack.h" |
daniele | 2:540f6e142d59 | 16 | |
daniele | 2:540f6e142d59 | 17 | |
daniele | 2:540f6e142d59 | 18 | /* Queues */ |
daniele | 2:540f6e142d59 | 19 | static struct pico_queue udp_in = {}; |
daniele | 2:540f6e142d59 | 20 | static struct pico_queue udp_out = {}; |
daniele | 2:540f6e142d59 | 21 | |
daniele | 2:540f6e142d59 | 22 | |
daniele | 2:540f6e142d59 | 23 | /* Functions */ |
daniele | 2:540f6e142d59 | 24 | |
daniele | 2:540f6e142d59 | 25 | uint16_t pico_udp_checksum_ipv4(struct pico_frame *f) |
daniele | 2:540f6e142d59 | 26 | { |
daniele | 2:540f6e142d59 | 27 | struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; |
daniele | 2:540f6e142d59 | 28 | struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; |
daniele | 2:540f6e142d59 | 29 | struct pico_socket *s = f->sock; |
daniele | 2:540f6e142d59 | 30 | struct pico_ipv4_pseudo_hdr pseudo; |
daniele | 2:540f6e142d59 | 31 | |
daniele | 2:540f6e142d59 | 32 | if (s) { |
daniele | 2:540f6e142d59 | 33 | /* Case of outgoing frame */ |
daniele | 2:540f6e142d59 | 34 | //dbg("UDP CRC: on outgoing frame\n"); |
daniele | 2:540f6e142d59 | 35 | pseudo.src.addr = s->local_addr.ip4.addr; |
daniele | 2:540f6e142d59 | 36 | pseudo.dst.addr = s->remote_addr.ip4.addr; |
daniele | 2:540f6e142d59 | 37 | } else { |
daniele | 2:540f6e142d59 | 38 | /* Case of incomming frame */ |
daniele | 2:540f6e142d59 | 39 | //dbg("UDP CRC: on incomming frame\n"); |
daniele | 2:540f6e142d59 | 40 | pseudo.src.addr = hdr->src.addr; |
daniele | 2:540f6e142d59 | 41 | pseudo.dst.addr = hdr->dst.addr; |
daniele | 2:540f6e142d59 | 42 | } |
daniele | 2:540f6e142d59 | 43 | pseudo.zeros = 0; |
daniele | 2:540f6e142d59 | 44 | pseudo.proto = PICO_PROTO_UDP; |
daniele | 2:540f6e142d59 | 45 | pseudo.len = short_be(f->transport_len); |
daniele | 2:540f6e142d59 | 46 | |
daniele | 2:540f6e142d59 | 47 | return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), udp_hdr, f->transport_len); |
daniele | 2:540f6e142d59 | 48 | } |
daniele | 2:540f6e142d59 | 49 | |
daniele | 2:540f6e142d59 | 50 | |
daniele | 2:540f6e142d59 | 51 | static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f) |
daniele | 2:540f6e142d59 | 52 | { |
daniele | 2:540f6e142d59 | 53 | return pico_network_send(f); |
daniele | 2:540f6e142d59 | 54 | } |
daniele | 2:540f6e142d59 | 55 | |
daniele | 2:540f6e142d59 | 56 | static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f) |
daniele | 2:540f6e142d59 | 57 | { |
daniele | 2:540f6e142d59 | 58 | struct pico_udp_hdr *hdr = (struct pico_udp_hdr *) f->transport_hdr; |
daniele | 2:540f6e142d59 | 59 | struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info; |
daniele | 2:540f6e142d59 | 60 | |
daniele | 2:540f6e142d59 | 61 | /* this (fragmented) frame should contain a transport header */ |
daniele | 2:540f6e142d59 | 62 | if (f->transport_hdr != f->payload) { |
daniele | 2:540f6e142d59 | 63 | hdr->trans.sport = f->sock->local_port; |
daniele | 2:540f6e142d59 | 64 | if (remote_duple) { |
daniele | 2:540f6e142d59 | 65 | hdr->trans.dport = remote_duple->remote_port; |
daniele | 2:540f6e142d59 | 66 | } else { |
daniele | 2:540f6e142d59 | 67 | hdr->trans.dport = f->sock->remote_port; |
daniele | 2:540f6e142d59 | 68 | } |
daniele | 2:540f6e142d59 | 69 | hdr->len = short_be(f->transport_len); |
daniele | 2:540f6e142d59 | 70 | /* do not perform CRC validation. If you want to, a system needs to be |
daniele | 2:540f6e142d59 | 71 | implemented to calculate the CRC over the total payload of a |
daniele | 2:540f6e142d59 | 72 | fragmented payload */ |
daniele | 2:540f6e142d59 | 73 | hdr->crc = 0; |
daniele | 2:540f6e142d59 | 74 | } |
daniele | 2:540f6e142d59 | 75 | |
daniele | 2:540f6e142d59 | 76 | if (pico_enqueue(self->q_out, f) > 0) { |
daniele | 2:540f6e142d59 | 77 | return f->payload_len; |
daniele | 2:540f6e142d59 | 78 | } else { |
daniele | 2:540f6e142d59 | 79 | return 0; |
daniele | 2:540f6e142d59 | 80 | } |
daniele | 2:540f6e142d59 | 81 | } |
daniele | 2:540f6e142d59 | 82 | |
daniele | 2:540f6e142d59 | 83 | /* Interface: protocol definition */ |
daniele | 2:540f6e142d59 | 84 | struct pico_protocol pico_proto_udp = { |
daniele | 2:540f6e142d59 | 85 | .name = "udp", |
daniele | 2:540f6e142d59 | 86 | .proto_number = PICO_PROTO_UDP, |
daniele | 2:540f6e142d59 | 87 | .layer = PICO_LAYER_TRANSPORT, |
daniele | 2:540f6e142d59 | 88 | .process_in = pico_transport_process_in, |
daniele | 2:540f6e142d59 | 89 | .process_out = pico_udp_process_out, |
daniele | 2:540f6e142d59 | 90 | .push = pico_udp_push, |
daniele | 2:540f6e142d59 | 91 | .q_in = &udp_in, |
daniele | 2:540f6e142d59 | 92 | .q_out = &udp_out, |
daniele | 2:540f6e142d59 | 93 | }; |
daniele | 2:540f6e142d59 | 94 | |
daniele | 2:540f6e142d59 | 95 | |
daniele | 2:540f6e142d59 | 96 | #define PICO_UDP_MODE_UNICAST 0x01 |
daniele | 2:540f6e142d59 | 97 | #define PICO_UDP_MODE_MULTICAST 0x02 |
daniele | 2:540f6e142d59 | 98 | #define PICO_UDP_MODE_BROADCAST 0xFF |
daniele | 2:540f6e142d59 | 99 | |
daniele | 2:540f6e142d59 | 100 | struct pico_socket_udp |
daniele | 2:540f6e142d59 | 101 | { |
daniele | 2:540f6e142d59 | 102 | struct pico_socket sock; |
daniele | 2:540f6e142d59 | 103 | int mode; |
daniele | 2:540f6e142d59 | 104 | #ifdef PICO_SUPPORT_MCAST |
daniele | 2:540f6e142d59 | 105 | uint8_t mc_ttl; /* Multicasting TTL */ |
daniele | 2:540f6e142d59 | 106 | #endif |
daniele | 2:540f6e142d59 | 107 | }; |
daniele | 2:540f6e142d59 | 108 | |
daniele | 2:540f6e142d59 | 109 | #ifdef PICO_SUPPORT_MCAST |
daniele | 2:540f6e142d59 | 110 | int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl) |
daniele | 2:540f6e142d59 | 111 | { |
daniele | 2:540f6e142d59 | 112 | struct pico_socket_udp *u; |
daniele | 2:540f6e142d59 | 113 | if(!s) { |
daniele | 2:540f6e142d59 | 114 | pico_err = PICO_ERR_EINVAL; |
daniele | 2:540f6e142d59 | 115 | return -1; |
daniele | 2:540f6e142d59 | 116 | } |
daniele | 2:540f6e142d59 | 117 | u = (struct pico_socket_udp *) s; |
daniele | 2:540f6e142d59 | 118 | u->mc_ttl = ttl; |
daniele | 2:540f6e142d59 | 119 | return 0; |
daniele | 2:540f6e142d59 | 120 | } |
daniele | 2:540f6e142d59 | 121 | |
daniele | 2:540f6e142d59 | 122 | int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl) |
daniele | 2:540f6e142d59 | 123 | { |
daniele | 2:540f6e142d59 | 124 | struct pico_socket_udp *u; |
daniele | 2:540f6e142d59 | 125 | if(!s) |
daniele | 2:540f6e142d59 | 126 | return -1; |
daniele | 2:540f6e142d59 | 127 | u = (struct pico_socket_udp *) s; |
daniele | 2:540f6e142d59 | 128 | *ttl = u->mc_ttl; |
daniele | 2:540f6e142d59 | 129 | return 0; |
daniele | 2:540f6e142d59 | 130 | } |
daniele | 2:540f6e142d59 | 131 | #endif /* PICO_SUPPORT_MCAST */ |
daniele | 2:540f6e142d59 | 132 | |
daniele | 2:540f6e142d59 | 133 | struct pico_socket *pico_udp_open(void) |
daniele | 2:540f6e142d59 | 134 | { |
daniele | 2:540f6e142d59 | 135 | struct pico_socket_udp *u = pico_zalloc(sizeof(struct pico_socket_udp)); |
daniele | 2:540f6e142d59 | 136 | if (!u) |
daniele | 2:540f6e142d59 | 137 | return NULL; |
daniele | 2:540f6e142d59 | 138 | u->mode = PICO_UDP_MODE_UNICAST; |
daniele | 2:540f6e142d59 | 139 | |
daniele | 2:540f6e142d59 | 140 | #ifdef PICO_SUPPORT_MCAST |
daniele | 2:540f6e142d59 | 141 | u->mc_ttl = PICO_IP_DEFAULT_MULTICAST_TTL; |
daniele | 2:540f6e142d59 | 142 | /* enable multicast loopback by default */ |
daniele | 2:540f6e142d59 | 143 | u->sock.opt_flags |= (1 << PICO_SOCKET_OPT_MULTICAST_LOOP); |
daniele | 2:540f6e142d59 | 144 | #endif |
daniele | 2:540f6e142d59 | 145 | |
daniele | 2:540f6e142d59 | 146 | return &u->sock; |
daniele | 2:540f6e142d59 | 147 | } |
daniele | 2:540f6e142d59 | 148 | |
daniele | 2:540f6e142d59 | 149 | int pico_udp_recv(struct pico_socket *s, void *buf, int len, void *src, uint16_t *port) |
daniele | 2:540f6e142d59 | 150 | { |
daniele | 2:540f6e142d59 | 151 | struct pico_frame *f = pico_queue_peek(&s->q_in); |
daniele | 2:540f6e142d59 | 152 | if (f) { |
daniele | 2:540f6e142d59 | 153 | f->payload = f->transport_hdr + sizeof(struct pico_udp_hdr); |
daniele | 2:540f6e142d59 | 154 | f->payload_len = f->transport_len - sizeof(struct pico_udp_hdr); |
daniele | 2:540f6e142d59 | 155 | // dbg("expected: %d, got: %d\n", len, f->payload_len); |
daniele | 2:540f6e142d59 | 156 | if (src) |
daniele | 2:540f6e142d59 | 157 | pico_store_network_origin(src, f); |
daniele | 2:540f6e142d59 | 158 | if (port) { |
daniele | 2:540f6e142d59 | 159 | struct pico_trans *hdr = (struct pico_trans *)f->transport_hdr; |
daniele | 2:540f6e142d59 | 160 | *port = hdr->sport; |
daniele | 2:540f6e142d59 | 161 | } |
daniele | 2:540f6e142d59 | 162 | if (f->payload_len > len) { |
daniele | 2:540f6e142d59 | 163 | memcpy(buf, f->payload, len); |
daniele | 2:540f6e142d59 | 164 | f->payload += len; |
daniele | 2:540f6e142d59 | 165 | f->payload_len -= len; |
daniele | 2:540f6e142d59 | 166 | return len; |
daniele | 2:540f6e142d59 | 167 | } else { |
daniele | 2:540f6e142d59 | 168 | int ret = f->payload_len; |
daniele | 2:540f6e142d59 | 169 | memcpy(buf, f->payload, f->payload_len); |
daniele | 2:540f6e142d59 | 170 | f = pico_dequeue(&s->q_in); |
daniele | 2:540f6e142d59 | 171 | pico_frame_discard(f); |
daniele | 2:540f6e142d59 | 172 | return ret; |
daniele | 2:540f6e142d59 | 173 | } |
daniele | 2:540f6e142d59 | 174 | } else return 0; |
daniele | 2:540f6e142d59 | 175 | } |
daniele | 2:540f6e142d59 | 176 |