Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_udp.c Source File

pico_udp.c

00001 /*********************************************************************
00002    PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
00003    See LICENSE and COPYING for usage.
00004 
00005    .
00006 
00007    Authors: Daniele Lacamera
00008  *********************************************************************/
00009 
00010 
00011 #include "pico_udp.h"
00012 #include "pico_config.h"
00013 #include "pico_eth.h"
00014 #include "pico_socket.h"
00015 #include "pico_stack.h"
00016 
00017 #define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))
00018 #define udp_dbg(...) do {} while(0)
00019 
00020 /* Queues */
00021 static struct pico_queue udp_in = {
00022     0
00023 };
00024 static struct pico_queue udp_out = {
00025     0
00026 };
00027 
00028 
00029 /* Functions */
00030 
00031 uint16_t pico_udp_checksum_ipv4(struct pico_frame *f)
00032 {
00033     struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
00034     struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00035     struct pico_socket *s = f->sock;
00036     struct pico_ipv4_pseudo_hdr pseudo;
00037 
00038     if (s) {
00039         /* Case of outgoing frame */
00040         udp_dbg("UDP CRC: on outgoing frame\n");
00041         pseudo.src.addr = s->local_addr.ip4.addr;
00042         pseudo.dst.addr = s->remote_addr.ip4.addr;
00043     } else {
00044         /* Case of incomming frame */
00045         udp_dbg("UDP CRC: on incomming frame\n");
00046         pseudo.src.addr = hdr->src.addr;
00047         pseudo.dst.addr = hdr->dst.addr;
00048     }
00049 
00050     pseudo.zeros = 0;
00051     pseudo.proto = PICO_PROTO_UDP;
00052     pseudo.len = short_be(f->transport_len);
00053 
00054     return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), udp_hdr, f->transport_len);
00055 }
00056 
00057 #ifdef PICO_SUPPORT_IPV6
00058 uint16_t pico_udp_checksum_ipv6(struct pico_frame *f)
00059 {
00060     struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
00061     struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *)f->transport_hdr;
00062     struct pico_ipv6_pseudo_hdr pseudo = {
00063         .src = {{0}}, .dst = {{0}}, .len = 0, .zero = {0}, .nxthdr = 0
00064     };
00065     struct pico_socket *s = f->sock;
00066     struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *)f->info;
00067 
00068     /* XXX If the IPv6 packet contains a Routing header, the Destination
00069      *     Address used in the pseudo-header is that of the final destination */
00070     if (s) {
00071         /* Case of outgoing frame */
00072         pseudo.src = s->local_addr.ip6;
00073         if (remote_endpoint)
00074             pseudo.dst = remote_endpoint->remote_addr.ip6;
00075         else
00076             pseudo.dst = s->remote_addr.ip6;
00077     } else {
00078         /* Case of incomming frame */
00079         pseudo.src = ipv6_hdr->src;
00080         pseudo.dst = ipv6_hdr->dst;
00081     }
00082 
00083     pseudo.len = long_be(f->transport_len);
00084     pseudo.nxthdr = PICO_PROTO_UDP;
00085 
00086     return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), udp_hdr, f->transport_len);
00087 }
00088 #endif
00089 
00090 
00091 
00092 static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f)
00093 {
00094     IGNORE_PARAMETER(self);
00095     return (int)pico_network_send(f);
00096 }
00097 
00098 static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f)
00099 {
00100     struct pico_udp_hdr *hdr = (struct pico_udp_hdr *) f->transport_hdr;
00101     struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *) f->info;
00102 
00103     /* this (fragmented) frame should contain a transport header */
00104     if (f->transport_hdr != f->payload) {
00105         hdr->trans.sport = f->sock->local_port;
00106         if (remote_endpoint) {
00107             hdr->trans.dport = remote_endpoint->remote_port;
00108         } else {
00109             hdr->trans.dport = f->sock->remote_port;
00110         }
00111 
00112         hdr->len = short_be(f->transport_len);
00113 
00114         /* do not perform CRC validation. If you want to, a system needs to be
00115            implemented to calculate the CRC over the total payload of a
00116            fragmented payload
00117          */
00118         hdr->crc = 0;
00119     }
00120 
00121     if (pico_enqueue(self->q_out, f) > 0) {
00122         return f->payload_len;
00123     } else {
00124         return 0;
00125     }
00126 }
00127 
00128 /* Interface: protocol definition */
00129 struct pico_protocol pico_proto_udp = {
00130     .name = "udp",
00131     .proto_number = PICO_PROTO_UDP,
00132     .layer = PICO_LAYER_TRANSPORT,
00133     .process_in = pico_transport_process_in,
00134     .process_out = pico_udp_process_out,
00135     .push = pico_udp_push,
00136     .q_in = &udp_in,
00137     .q_out = &udp_out,
00138 };
00139 
00140 
00141 
00142 struct pico_socket *pico_udp_open(void)
00143 {
00144     struct pico_socket_udp *u = PICO_ZALLOC(sizeof(struct pico_socket_udp));
00145     if (!u)
00146         return NULL;
00147 
00148     u->mode = PICO_UDP_MODE_UNICAST;
00149 
00150 #ifdef PICO_SUPPORT_MCAST
00151     u->mc_ttl = PICO_IP_DEFAULT_MULTICAST_TTL;
00152     /* enable multicast loopback by default */
00153     u->sock.opt_flags |= (1 << PICO_SOCKET_OPT_MULTICAST_LOOP);
00154 #endif
00155 
00156     return &u->sock;
00157 }
00158 
00159 static void pico_udp_get_msginfo(struct pico_frame *f, struct pico_msginfo *msginfo)
00160 {
00161     msginfo->dev = f->dev;
00162     if (!msginfo || !f->net_hdr)
00163         return;
00164 
00165     if (IS_IPV4(f)) { /* IPV4 */
00166 #ifdef PICO_SUPPORT_IPV4
00167         struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)(f->net_hdr);
00168         msginfo->ttl = hdr->ttl;
00169         msginfo->tos = hdr->tos;
00170 #endif
00171     } else {
00172 #ifdef PICO_SUPPORT_IPV6
00173         struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
00174         msginfo->ttl = hdr->hop;
00175         msginfo->tos = (hdr->vtf >> 20) & 0xFF; /* IPv6 traffic class */
00176 #endif
00177     }
00178 }
00179 
00180 uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port, struct pico_msginfo *msginfo)
00181 {
00182     struct pico_frame *f = pico_queue_peek(&s->q_in);
00183     if (f) {
00184         if(!f->payload_len) {
00185             f->payload = f->transport_hdr + sizeof(struct pico_udp_hdr);
00186             f->payload_len = (uint16_t)(f->transport_len - sizeof(struct pico_udp_hdr));
00187         }
00188 
00189         udp_dbg("expected: %d, got: %d\n", len, f->payload_len);
00190         if (src)
00191             pico_store_network_origin(src, f);
00192 
00193         if (port) {
00194             struct pico_trans *hdr = (struct pico_trans *)f->transport_hdr;
00195             *port = hdr->sport;
00196         }
00197 
00198         if (msginfo) {
00199             pico_udp_get_msginfo(f, msginfo);
00200         }
00201 
00202         if (f->payload_len > len) {
00203             memcpy(buf, f->payload, len);
00204             f->payload += len;
00205             f->payload_len = (uint16_t)(f->payload_len - len);
00206             return len;
00207         } else {
00208             uint16_t ret = f->payload_len;
00209             memcpy(buf, f->payload, f->payload_len);
00210             f = pico_dequeue(&s->q_in);
00211             pico_frame_discard(f);
00212             return ret;
00213         }
00214     } else return 0;
00215 }
00216