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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

modules/pico_socket_udp.c

Committer:
tass
Date:
2016-01-28
Revision:
155:a70f34550c34
Parent:
152:a3d286bf94e5

File content as of revision 155:a70f34550c34:

#include "pico_config.h"
#include "pico_socket.h"
#include "pico_udp.h"
#include "pico_socket_multicast.h"
#include "pico_ipv4.h"
#include "pico_ipv6.h"
#include "pico_socket_udp.h"

#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))


struct pico_socket *pico_socket_udp_open(void)
{
    struct pico_socket *s = NULL;
#ifdef PICO_SUPPORT_UDP
    s = pico_udp_open();
    if (!s) {
        pico_err = PICO_ERR_ENOMEM;
        return NULL;
    }

    s->proto = &pico_proto_udp;
    s->q_in.overhead = UDP_FRAME_OVERHEAD;
    s->q_out.overhead = UDP_FRAME_OVERHEAD;
#endif
    return s;
}


#ifdef PICO_SUPPORT_IPV4
static inline int pico_socket_udp_deliver_ipv4_mcast_initial_checks(struct pico_socket *s, struct pico_frame *f)
{
    struct pico_ip4 p_dst;
    struct pico_ipv4_hdr *ip4hdr;

    ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
    p_dst.addr = ip4hdr->dst.addr;
    if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, (union pico_address *)&ip4hdr->dst, (union pico_address *)&ip4hdr->src) < 0))
        return -1;


    if ((pico_ipv4_link_get(&ip4hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) {
        /* Datagram from ourselves, Loop disabled, discarding. */
        return -1;
    }

    return 0;
}


static int pico_socket_udp_deliver_ipv4_mcast(struct pico_socket *s, struct pico_frame *f)
{
    struct pico_ip4 s_local;
    struct pico_frame *cpy;
    struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);

    s_local.addr = s->local_addr.ip4.addr;

    if (pico_socket_udp_deliver_ipv4_mcast_initial_checks(s, f) < 0)
        return 0;

    if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
        (dev == f->dev)) {     /* the source of the bcast packet is a neighbor... */
        cpy = pico_frame_copy(f);
        if (!cpy)
            return -1;

        if (pico_enqueue(&s->q_in, cpy) > 0) {
            if (s->wakeup)
                s->wakeup(PICO_SOCK_EV_RD, s);
        }
        else
            pico_frame_discard(cpy);
    }

    return 0;
}

static int pico_socket_udp_deliver_ipv4_unicast(struct pico_socket *s, struct pico_frame *f)
{
    struct pico_frame *cpy;
    /* Either local socket is ANY, or matches dst */
    cpy = pico_frame_copy(f);
    if (!cpy)
        return -1;

    if (pico_enqueue(&s->q_in, cpy) > 0) {
        if (s->wakeup)
            s->wakeup(PICO_SOCK_EV_RD, s);
    } else {
        pico_frame_discard(cpy);
    }

    return 0;
}


static int pico_socket_udp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f)
{
    int ret = 0;
    struct pico_ip4 s_local, p_dst;
    struct pico_ipv4_hdr *ip4hdr;
    ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
    s_local.addr = s->local_addr.ip4.addr;
    p_dst.addr = ip4hdr->dst.addr;
    if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) {
        ret = pico_socket_udp_deliver_ipv4_mcast(s, f);
    } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr)) {
        ret = pico_socket_udp_deliver_ipv4_unicast(s, f);
    }

    pico_frame_discard(f);
    return ret;
}
#endif

#ifdef PICO_SUPPORT_IPV6
static inline int pico_socket_udp_deliver_ipv6_mcast(struct pico_socket *s, struct pico_frame *f)
{
    struct pico_ipv6_hdr *ip6hdr;
    struct pico_frame *cpy;
    struct pico_device *dev = pico_ipv6_link_find(&s->local_addr.ip6);

    ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);

    if ((pico_ipv6_link_get(&ip6hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) {
        /* Datagram from ourselves, Loop disabled, discarding. */
        return 0;
    }


    if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || /* If our local ip is ANY, or.. */
        (dev == f->dev)) {     /* the source of the bcast packet is a neighbor... */
        cpy = pico_frame_copy(f);
        if (!cpy)
        {
            return -1;
        }

        if (pico_enqueue(&s->q_in, cpy) > 0) {
            if (s->wakeup)
                s->wakeup(PICO_SOCK_EV_RD, s);
        }
        else
            pico_frame_discard(cpy);
    }

    return 0;
}

static int pico_socket_udp_deliver_ipv6(struct pico_socket *s, struct pico_frame *f)
{
    struct pico_ip6 s_local, p_dst;
    struct pico_ipv6_hdr *ip6hdr;
    struct pico_frame *cpy;
    ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
    s_local = s->local_addr.ip6;
    p_dst = ip6hdr->dst;
    if ((pico_ipv6_is_multicast(p_dst.addr))) {
        int retval = pico_socket_udp_deliver_ipv6_mcast(s, f);
        pico_frame_discard(f);
        return retval;
    } 
    else if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || (pico_ipv6_compare(&s_local, &p_dst) == 0))
    { /* Either local socket is ANY, or matches dst */
        cpy = pico_frame_copy(f);
        if (!cpy)
        {
            pico_frame_discard(f);
            return -1;
        }

        if (pico_enqueue(&s->q_in, cpy) > 0) {
            if (s->wakeup)
                s->wakeup(PICO_SOCK_EV_RD, s);
        }
    }

    pico_frame_discard(f);
    return 0;
}
#endif


int pico_socket_udp_deliver(struct pico_sockport *sp, struct pico_frame *f)
{
    struct pico_tree_node *index = NULL;
    struct pico_tree_node *_tmp;
    struct pico_socket *s = NULL;
    pico_err = PICO_ERR_EPROTONOSUPPORT;
    #ifdef PICO_SUPPORT_UDP
    pico_err = PICO_ERR_NOERR;
    pico_tree_foreach_safe(index, &sp->socks, _tmp){
        s = index->keyValue;
        if (IS_IPV4(f)) { /* IPV4 */
#ifdef PICO_SUPPORT_IPV4
            return pico_socket_udp_deliver_ipv4(s, f);
#endif
        } else if (IS_IPV6(f)) {
#ifdef PICO_SUPPORT_IPV6
            return pico_socket_udp_deliver_ipv6(s, f);
#endif
        } else {
            /* something wrong in the packet header*/
        }
    } /* FOREACH */
    pico_frame_discard(f);
    if (s)
        return 0;

    pico_err = PICO_ERR_ENXIO;
  #endif
    return -1;
}

int pico_setsockopt_udp(struct pico_socket *s, int option, void *value)
{
    switch(option) {
    case PICO_SOCKET_OPT_RCVBUF:
        s->q_in.max_size = (*(uint32_t*)value);
        return 0;
    case PICO_SOCKET_OPT_SNDBUF:
        s->q_out.max_size = (*(uint32_t*)value);
        return 0;
    }

    /* switch's default */
#ifdef PICO_SUPPORT_MCAST
    return pico_setsockopt_mcast(s, option, value);
#else
    pico_err = PICO_ERR_EINVAL;
    return -1;
#endif
}

int pico_getsockopt_udp(struct pico_socket *s, int option, void *value)
{
    uint32_t *val = (uint32_t *)value;
    switch(option) {
    case PICO_SOCKET_OPT_RCVBUF:
        *val = s->q_in.max_size;
        return 0;
    case PICO_SOCKET_OPT_SNDBUF:
        *val = s->q_out.max_size;
        return 0;
    }

    /* switch's default */
#ifdef PICO_SUPPORT_MCAST
    return pico_getsockopt_mcast(s, option, value);
#else
    pico_err = PICO_ERR_EINVAL;
    return -1;
#endif
}