Free (GPLv2) TCP/IP stack developed by TASS Belgium
Fork of PicoTCP by
modules/pico_udp.c
- Committer:
- daniele
- Date:
- 2013-08-03
- Revision:
- 51:18637a3d071f
- Parent:
- 3:b4047e8a0123
File content as of revision 51:18637a3d071f:
/********************************************************************* PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. . Authors: Daniele Lacamera *********************************************************************/ #include "pico_udp.h" #include "pico_config.h" #include "pico_eth.h" #include "pico_socket.h" #include "pico_stack.h" /* Queues */ static struct pico_queue udp_in = {}; static struct pico_queue udp_out = {}; /* Functions */ uint16_t pico_udp_checksum_ipv4(struct pico_frame *f) { struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; struct pico_socket *s = f->sock; struct pico_ipv4_pseudo_hdr pseudo; if (s) { /* Case of outgoing frame */ //dbg("UDP CRC: on outgoing frame\n"); pseudo.src.addr = s->local_addr.ip4.addr; pseudo.dst.addr = s->remote_addr.ip4.addr; } else { /* Case of incomming frame */ //dbg("UDP CRC: on incomming frame\n"); pseudo.src.addr = hdr->src.addr; pseudo.dst.addr = hdr->dst.addr; } pseudo.zeros = 0; pseudo.proto = PICO_PROTO_UDP; pseudo.len = short_be(f->transport_len); return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), udp_hdr, f->transport_len); } static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f) { return pico_network_send(f); } static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f) { struct pico_udp_hdr *hdr = (struct pico_udp_hdr *) f->transport_hdr; struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info; /* this (fragmented) frame should contain a transport header */ if (f->transport_hdr != f->payload) { hdr->trans.sport = f->sock->local_port; if (remote_duple) { hdr->trans.dport = remote_duple->remote_port; } else { hdr->trans.dport = f->sock->remote_port; } hdr->len = short_be(f->transport_len); /* do not perform CRC validation. If you want to, a system needs to be implemented to calculate the CRC over the total payload of a fragmented payload */ hdr->crc = 0; } if (pico_enqueue(self->q_out, f) > 0) { return f->payload_len; } else { return 0; } } /* Interface: protocol definition */ struct pico_protocol pico_proto_udp = { .name = "udp", .proto_number = PICO_PROTO_UDP, .layer = PICO_LAYER_TRANSPORT, .process_in = pico_transport_process_in, .process_out = pico_udp_process_out, .push = pico_udp_push, .q_in = &udp_in, .q_out = &udp_out, }; #define PICO_UDP_MODE_UNICAST 0x01 #define PICO_UDP_MODE_MULTICAST 0x02 #define PICO_UDP_MODE_BROADCAST 0xFF struct pico_socket_udp { struct pico_socket sock; int mode; #ifdef PICO_SUPPORT_MCAST uint8_t mc_ttl; /* Multicasting TTL */ #endif }; #ifdef PICO_SUPPORT_MCAST int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl) { struct pico_socket_udp *u; if(!s) { pico_err = PICO_ERR_EINVAL; return -1; } u = (struct pico_socket_udp *) s; u->mc_ttl = ttl; return 0; } int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl) { struct pico_socket_udp *u; if(!s) return -1; u = (struct pico_socket_udp *) s; *ttl = u->mc_ttl; return 0; } #endif /* PICO_SUPPORT_MCAST */ struct pico_socket *pico_udp_open(void) { struct pico_socket_udp *u = pico_zalloc(sizeof(struct pico_socket_udp)); if (!u) return NULL; u->mode = PICO_UDP_MODE_UNICAST; #ifdef PICO_SUPPORT_MCAST u->mc_ttl = PICO_IP_DEFAULT_MULTICAST_TTL; /* enable multicast loopback by default */ u->sock.opt_flags |= (1 << PICO_SOCKET_OPT_MULTICAST_LOOP); #endif return &u->sock; } int pico_udp_recv(struct pico_socket *s, void *buf, int len, void *src, uint16_t *port) { struct pico_frame *f = pico_queue_peek(&s->q_in); if (f) { f->payload = f->transport_hdr + sizeof(struct pico_udp_hdr); f->payload_len = f->transport_len - sizeof(struct pico_udp_hdr); // dbg("expected: %d, got: %d\n", len, f->payload_len); if (src) pico_store_network_origin(src, f); if (port) { struct pico_trans *hdr = (struct pico_trans *)f->transport_hdr; *port = hdr->sport; } if (f->payload_len > len) { memcpy(buf, f->payload, len); f->payload += len; f->payload_len -= len; return len; } else { int ret = f->payload_len; memcpy(buf, f->payload, f->payload_len); f = pico_dequeue(&s->q_in); pico_frame_discard(f); return ret; } } else return 0; }