Daniele Lacamera / PicoTCP-Experimental_CDC_ECM_Branch

Fork of PicoTCP by Daniele Lacamera

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 TASS Belgium NV. 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 
00018 /* Queues */
00019 static struct pico_queue udp_in = {};
00020 static struct pico_queue udp_out = {};
00021 
00022 
00023 /* Functions */
00024 
00025 uint16_t pico_udp_checksum_ipv4(struct pico_frame *f)
00026 {
00027   struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
00028   struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
00029   struct pico_socket *s = f->sock;
00030   struct pico_ipv4_pseudo_hdr pseudo;
00031 
00032   if (s) {
00033     /* Case of outgoing frame */
00034     //dbg("UDP CRC: on outgoing frame\n");
00035     pseudo.src.addr = s->local_addr.ip4.addr;
00036     pseudo.dst.addr = s->remote_addr.ip4.addr;
00037   } else {
00038     /* Case of incomming frame */
00039     //dbg("UDP CRC: on incomming frame\n");
00040     pseudo.src.addr = hdr->src.addr;
00041     pseudo.dst.addr = hdr->dst.addr;
00042   }
00043   pseudo.zeros = 0;
00044   pseudo.proto = PICO_PROTO_UDP;
00045   pseudo.len = short_be(f->transport_len);
00046 
00047   return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), udp_hdr, f->transport_len);
00048 }
00049 
00050 
00051 static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f)
00052 {
00053   return pico_network_send(f); 
00054 }
00055 
00056 static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f)
00057 {
00058   struct pico_udp_hdr *hdr = (struct pico_udp_hdr *) f->transport_hdr;
00059   struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info;
00060 
00061   /* this (fragmented) frame should contain a transport header */
00062   if (f->transport_hdr != f->payload) {
00063     hdr->trans.sport = f->sock->local_port;
00064     if (remote_duple) {
00065       hdr->trans.dport = remote_duple->remote_port;
00066     } else {
00067       hdr->trans.dport = f->sock->remote_port;
00068     }
00069     hdr->len = short_be(f->transport_len);
00070     /* do not perform CRC validation. If you want to, a system needs to be 
00071        implemented to calculate the CRC over the total payload of a 
00072        fragmented payload */
00073     hdr->crc = 0;
00074   }
00075 
00076   if (pico_enqueue(self->q_out, f) > 0) {
00077     return f->payload_len;
00078   } else {
00079     return 0;
00080   }    
00081 }
00082 
00083 /* Interface: protocol definition */
00084 struct pico_protocol pico_proto_udp = {
00085   .name = "udp",
00086   .proto_number = PICO_PROTO_UDP,
00087   .layer = PICO_LAYER_TRANSPORT,
00088   .process_in = pico_transport_process_in,
00089   .process_out = pico_udp_process_out,
00090   .push = pico_udp_push,
00091   .q_in = &udp_in,
00092   .q_out = &udp_out,
00093 };
00094 
00095 
00096 #define PICO_UDP_MODE_UNICAST 0x01
00097 #define PICO_UDP_MODE_MULTICAST 0x02
00098 #define PICO_UDP_MODE_BROADCAST 0xFF
00099 
00100 struct pico_socket_udp
00101 {
00102   struct pico_socket sock;
00103   int mode;
00104 #ifdef PICO_SUPPORT_MCAST
00105   uint8_t mc_ttl; /* Multicasting TTL */
00106 #endif
00107 };
00108 
00109 #ifdef PICO_SUPPORT_MCAST
00110 int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl)
00111 {
00112   struct pico_socket_udp *u;
00113   if(!s) {
00114     pico_err = PICO_ERR_EINVAL;
00115     return -1;
00116   }
00117   u = (struct pico_socket_udp *) s;
00118   u->mc_ttl = ttl;
00119   return 0;
00120 }
00121 
00122 int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
00123 {
00124   struct pico_socket_udp *u;
00125   if(!s)
00126     return -1;
00127   u = (struct pico_socket_udp *) s;
00128   *ttl = u->mc_ttl;
00129   return 0;
00130 }
00131 #endif /* PICO_SUPPORT_MCAST */
00132 
00133 struct pico_socket *pico_udp_open(void)
00134 {
00135   struct pico_socket_udp *u = pico_zalloc(sizeof(struct pico_socket_udp));
00136   if (!u)
00137     return NULL;
00138   u->mode = PICO_UDP_MODE_UNICAST;
00139 
00140 #ifdef PICO_SUPPORT_MCAST
00141   u->mc_ttl = PICO_IP_DEFAULT_MULTICAST_TTL;
00142   /* enable multicast loopback by default */
00143   u->sock.opt_flags |= (1 << PICO_SOCKET_OPT_MULTICAST_LOOP);
00144 #endif
00145 
00146   return &u->sock;
00147 }
00148 
00149 int pico_udp_recv(struct pico_socket *s, void *buf, int len, void *src, uint16_t *port)
00150 {
00151   struct pico_frame *f = pico_queue_peek(&s->q_in);
00152   if (f) {
00153     f->payload = f->transport_hdr + sizeof(struct pico_udp_hdr);
00154     f->payload_len = f->transport_len - sizeof(struct pico_udp_hdr);
00155 //    dbg("expected: %d, got: %d\n", len, f->payload_len);
00156     if (src)
00157       pico_store_network_origin(src, f);
00158     if (port) {
00159       struct pico_trans *hdr = (struct pico_trans *)f->transport_hdr;
00160       *port = hdr->sport;
00161     }
00162     if (f->payload_len > len) {
00163       memcpy(buf, f->payload, len);
00164       f->payload += len;
00165       f->payload_len -= len;
00166       return len;
00167     } else {
00168       int ret = f->payload_len;
00169       memcpy(buf, f->payload, f->payload_len);
00170       f = pico_dequeue(&s->q_in);
00171       pico_frame_discard(f);
00172       return ret;
00173     }
00174   } else return 0;
00175 }
00176