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.

Revision:
152:a3d286bf94e5
Parent:
149:5f4cb161cec3
Child:
154:6c0e92a80c4a
--- a/modules/pico_igmp.c	Wed Apr 09 17:32:25 2014 +0200
+++ b/modules/pico_igmp.c	Mon Sep 28 13:16:18 2015 +0200
@@ -1,5 +1,5 @@
 /*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
    See LICENSE and COPYING for usage.
 
    RFC 1112, 2236, 3376, 3569, 3678, 4607
@@ -18,6 +18,8 @@
 #include "pico_device.h"
 #include "pico_socket.h"
 
+#if defined(PICO_SUPPORT_IGMP) && defined(PICO_SUPPORT_MCAST) 
+
 #define igmp_dbg(...) do {} while(0)
 /* #define igmp_dbg dbg */
 
@@ -94,7 +96,7 @@
     uint8_t rsq;
     uint8_t qqic;
     uint16_t sources;
-    uint32_t source_addr[];
+    uint32_t source_addr[0];
 };
 
 PACKED_STRUCT_DEF igmpv3_group_record {
@@ -102,7 +104,7 @@
     uint8_t aux;
     uint16_t sources;
     uint32_t mcast_group;
-    uint32_t source_addr[];
+    uint32_t source_addr[0];
 };
 
 PACKED_STRUCT_DEF igmpv3_report {
@@ -111,7 +113,7 @@
     uint16_t crc;
     uint16_t res1;
     uint16_t groups;
-    struct igmpv3_group_record record[];
+    struct igmpv3_group_record record[0];
 };
 
 struct igmp_parameters {
@@ -151,61 +153,70 @@
 /* state callback prototype */
 typedef int (*callback)(struct igmp_parameters *);
 
-/* redblack trees */
-static int igmp_timer_cmp(void *ka, void *kb)
+static inline int igmpt_type_compare(struct igmp_timer *a,  struct igmp_timer *b)
 {
-    struct igmp_timer *a = ka, *b = kb;
     if (a->type < b->type)
         return -1;
 
     if (a->type > b->type)
         return 1;
 
-    if (a->mcast_group.addr < b->mcast_group.addr)
-        return -1;
-
-    if (a->mcast_group.addr > b->mcast_group.addr)
-        return 1;
-
-    if (a->mcast_link.addr < b->mcast_link.addr)
-        return -1;
-
-    if (a->mcast_link.addr > b->mcast_link.addr)
-        return 1;
-
     return 0;
 }
+
+
+static inline int igmpt_group_compare(struct igmp_timer *a,  struct igmp_timer *b)
+{
+    return pico_ipv4_compare(&a->mcast_group, &b->mcast_group);
+}
+
+static inline int igmpt_link_compare(struct igmp_timer *a,  struct igmp_timer *b)
+{
+    return pico_ipv4_compare(&a->mcast_link, &b->mcast_link);
+}
+
+/* redblack trees */
+static int igmp_timer_cmp(void *ka, void *kb)
+{
+    struct igmp_timer *a = ka, *b = kb;
+    int cmp = igmpt_type_compare(a, b);
+    if (cmp)
+        return cmp;
+
+    cmp = igmpt_group_compare(a, b);
+    if (cmp)
+        return cmp;
+
+    return igmpt_link_compare(a, b);
+
+}
 PICO_TREE_DECLARE(IGMPTimers, igmp_timer_cmp);
 
+static inline int igmpparm_group_compare(struct igmp_parameters *a,  struct igmp_parameters *b)
+{
+    return pico_ipv4_compare(&a->mcast_group, &b->mcast_group);
+}
+
+static inline int igmpparm_link_compare(struct igmp_parameters *a,  struct igmp_parameters *b)
+{
+    return pico_ipv4_compare(&a->mcast_link, &b->mcast_link);
+}
+
 static int igmp_parameters_cmp(void *ka, void *kb)
 {
     struct igmp_parameters *a = ka, *b = kb;
-    if (a->mcast_group.addr < b->mcast_group.addr)
-        return -1;
-
-    if (a->mcast_group.addr > b->mcast_group.addr)
-        return 1;
+    int cmp = igmpparm_group_compare(a, b);
+    if (cmp)
+        return cmp;
 
-    if (a->mcast_link.addr < b->mcast_link.addr)
-        return -1;
-
-    if (a->mcast_link.addr > b->mcast_link.addr)
-        return 1;
-
-    return 0;
+    return igmpparm_link_compare(a, b);
 }
 PICO_TREE_DECLARE(IGMPParameters, igmp_parameters_cmp);
 
 static int igmp_sources_cmp(void *ka, void *kb)
 {
     struct pico_ip4 *a = ka, *b = kb;
-    if (a->addr < b->addr)
-        return -1;
-
-    if (a->addr > b->addr)
-        return 1;
-
-    return 0;
+    return pico_ipv4_compare(a, b);
 }
 PICO_TREE_DECLARE(IGMPAllow, igmp_sources_cmp);
 PICO_TREE_DECLARE(IGMPBlock, igmp_sources_cmp);
@@ -432,13 +443,15 @@
     datalen = (uint8_t)(short_be(hdr->len) - ihl);
     igmp_dbg("IGMP: IHL = %u, LEN = %u, OCTETS = %u\n", ihl, short_be(hdr->len), datalen);
 
-    if (datalen > 12) {
+    if (datalen >= 12) {
         /* IGMPv3 query */
         t.type = IGMP_TIMER_V2_QUERIER;
         if (pico_igmp_timer_is_running(&t)) { /* IGMPv2 querier present timer still running */
+            igmp_dbg("Timer is already running\n");
             return -1;
         } else {
             link->mcast_compatibility = PICO_IGMPV3;
+            igmp_dbg("IGMP Compatibility: v3\n");
             return 0;
         }
     } else if (datalen == 8) {
@@ -566,7 +579,7 @@
     .q_out = &igmp_out,
 };
 
-int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *MCASTFilter, uint8_t state)
+int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state)
 {
     struct igmp_parameters *p = NULL;
 
@@ -612,7 +625,7 @@
         return -1;
     }
     p->filter_mode = filter_mode;
-    p->MCASTFilter = MCASTFilter;
+    p->MCASTFilter = _MCASTFilter;
 
     return pico_igmp_process_event(p);
 }
@@ -720,6 +733,11 @@
             p->MCASTFilter = NULL;
         }
 
+        if (p->event == IGMP_EVENT_QUERY_RECV) {
+            goto igmp3_report;
+        }
+
+
         /* cleanup filters */
         pico_tree_foreach_safe(index, &IGMPAllow, _tmp)
         {
@@ -884,6 +902,7 @@
             return -1;
         }
 
+igmp3_report:
         len = (uint16_t)(sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (sources * sizeof(struct pico_ip4)));
         p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)(IP_OPTION_ROUTER_ALERT_LEN + len));
         p->f->net_len = (uint16_t)(p->f->net_len + IP_OPTION_ROUTER_ALERT_LEN);
@@ -904,7 +923,7 @@
         record->aux = 0;
         record->sources = short_be(sources);
         record->mcast_group = p->mcast_group.addr;
-        if (!pico_tree_empty(IGMPFilter)) {
+        if (IGMPFilter && !pico_tree_empty(IGMPFilter)) {
             i = 0;
             pico_tree_foreach(index, IGMPFilter)
             {
@@ -1096,16 +1115,20 @@
 
     igmp_dbg("IGMP: event = query received | action = start timer\n");
 
-    if (pico_igmp_generate_report(p) < 0)
+    if (pico_igmp_generate_report(p) < 0) {
+        igmp_dbg("Failed to generate report\n");
         return -1;
+    }
 
-    if (!p->f)
+    if (!p->f) {
+        igmp_dbg("No pending frame\n");
         return -1;
+    }
 
     t.type = IGMP_TIMER_GROUP_REPORT;
     t.mcast_link = p->mcast_link;
     t.mcast_group = p->mcast_group;
-    t.delay = (pico_rand() % (p->max_resp_time * 100u));
+    t.delay = (pico_rand() % ((1u + p->max_resp_time) * 100u));
     t.f = p->f;
     t.callback = pico_igmp_report_expired;
     pico_igmp_timer_start(&t);
@@ -1163,7 +1186,7 @@
 
     time_to_run = (uint32_t)(t->start + t->delay - PICO_TIME_MS());
     if ((p->max_resp_time * 100u) < time_to_run) { /* max_resp_time in units of 1/10 seconds */
-        t->delay = pico_rand() % (p->max_resp_time * 100u);
+        t->delay = pico_rand() % ((1u + p->max_resp_time) * 100u);
         pico_igmp_timer_reset(t);
     }
 
@@ -1210,3 +1233,45 @@
     return 0;
 }
 
+#else
+static struct pico_queue igmp_in = {
+    0
+};
+static struct pico_queue igmp_out = {
+    0
+};
+
+static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f) {
+    IGNORE_PARAMETER(self);
+    IGNORE_PARAMETER(f);
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) {
+    IGNORE_PARAMETER(self);
+    IGNORE_PARAMETER(f);
+    return -1;
+}
+
+/* Interface: protocol definition */
+struct pico_protocol pico_proto_igmp = {
+    .name = "igmp",
+    .proto_number = PICO_PROTO_IGMP,
+    .layer = PICO_LAYER_TRANSPORT,
+    .process_in = pico_igmp_process_in,
+    .process_out = pico_igmp_process_out,
+    .q_in = &igmp_in,
+    .q_out = &igmp_out,
+};
+
+int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *_MCASTFilter, uint8_t state) {
+    IGNORE_PARAMETER(mcast_link);
+    IGNORE_PARAMETER(mcast_group);
+    IGNORE_PARAMETER(filter_mode);
+    IGNORE_PARAMETER(_MCASTFilter);
+    IGNORE_PARAMETER(state);
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+#endif