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.

Committer:
tass picotcp@tass.be
Date:
Wed Apr 09 14:31:41 2014 +0200
Revision:
149:5f4cb161cec3
Child:
152:a3d286bf94e5
Update from git masterbranch

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass picotcp@tass.be 149:5f4cb161cec3 1 #include <stdint.h>
tass picotcp@tass.be 149:5f4cb161cec3 2 #include "pico_socket.h"
tass picotcp@tass.be 149:5f4cb161cec3 3 #include "pico_socket_multicast.h"
tass picotcp@tass.be 149:5f4cb161cec3 4 #include "pico_tree.h"
tass picotcp@tass.be 149:5f4cb161cec3 5 #include "pico_ipv4.h"
tass picotcp@tass.be 149:5f4cb161cec3 6 #include "pico_udp.h"
tass picotcp@tass.be 149:5f4cb161cec3 7
tass picotcp@tass.be 149:5f4cb161cec3 8 #ifdef PICO_SUPPORT_MCAST
tass picotcp@tass.be 149:5f4cb161cec3 9 # define so_mcast_dbg(...) do {} while(0) /* ip_mcast_dbg in pico_ipv4.c */
tass picotcp@tass.be 149:5f4cb161cec3 10 /* #define so_mcast_dbg dbg */
tass picotcp@tass.be 149:5f4cb161cec3 11
tass picotcp@tass.be 149:5f4cb161cec3 12 /* socket
tass picotcp@tass.be 149:5f4cb161cec3 13 * |
tass picotcp@tass.be 149:5f4cb161cec3 14 * MCASTListen
tass picotcp@tass.be 149:5f4cb161cec3 15 * | | |
tass picotcp@tass.be 149:5f4cb161cec3 16 * ------------ | ------------
tass picotcp@tass.be 149:5f4cb161cec3 17 * | | |
tass picotcp@tass.be 149:5f4cb161cec3 18 * MCASTSources MCASTSources MCASTSources
tass picotcp@tass.be 149:5f4cb161cec3 19 * | | | | | | | | | | | |
tass picotcp@tass.be 149:5f4cb161cec3 20 * S S S S S S S S S S S S
tass picotcp@tass.be 149:5f4cb161cec3 21 *
tass picotcp@tass.be 149:5f4cb161cec3 22 * MCASTListen: RBTree(mcast_link, mcast_group)
tass picotcp@tass.be 149:5f4cb161cec3 23 * MCASTSources: RBTree(source)
tass picotcp@tass.be 149:5f4cb161cec3 24 */
tass picotcp@tass.be 149:5f4cb161cec3 25 struct pico_mcast_listen
tass picotcp@tass.be 149:5f4cb161cec3 26 {
tass picotcp@tass.be 149:5f4cb161cec3 27 uint8_t filter_mode;
tass picotcp@tass.be 149:5f4cb161cec3 28 union pico_address mcast_link;
tass picotcp@tass.be 149:5f4cb161cec3 29 union pico_address mcast_group;
tass picotcp@tass.be 149:5f4cb161cec3 30 struct pico_tree MCASTSources;
tass picotcp@tass.be 149:5f4cb161cec3 31 };
tass picotcp@tass.be 149:5f4cb161cec3 32
tass picotcp@tass.be 149:5f4cb161cec3 33 static int mcast_listen_link_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b)
tass picotcp@tass.be 149:5f4cb161cec3 34 {
tass picotcp@tass.be 149:5f4cb161cec3 35 /* TODO: IPv6 */
tass picotcp@tass.be 149:5f4cb161cec3 36 if (a->mcast_link.ip4.addr < b->mcast_link.ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 37 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 38
tass picotcp@tass.be 149:5f4cb161cec3 39 /* TODO: IPv6 */
tass picotcp@tass.be 149:5f4cb161cec3 40 if (a->mcast_link.ip4.addr > b->mcast_link.ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 41 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 42
tass picotcp@tass.be 149:5f4cb161cec3 43 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 44 }
tass picotcp@tass.be 149:5f4cb161cec3 45
tass picotcp@tass.be 149:5f4cb161cec3 46 static int mcast_listen_cmp(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 47 {
tass picotcp@tass.be 149:5f4cb161cec3 48 struct pico_mcast_listen *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 49 if (a->mcast_group.ip4.addr < b->mcast_group.ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 50 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 51
tass picotcp@tass.be 149:5f4cb161cec3 52 if (a->mcast_group.ip4.addr > b->mcast_group.ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 53 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 54
tass picotcp@tass.be 149:5f4cb161cec3 55 return mcast_listen_link_cmp(a, b);
tass picotcp@tass.be 149:5f4cb161cec3 56
tass picotcp@tass.be 149:5f4cb161cec3 57 }
tass picotcp@tass.be 149:5f4cb161cec3 58
tass picotcp@tass.be 149:5f4cb161cec3 59 static int mcast_sources_cmp(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 60 {
tass picotcp@tass.be 149:5f4cb161cec3 61 union pico_address *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 62 if (a->ip4.addr < b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 63 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 64
tass picotcp@tass.be 149:5f4cb161cec3 65 if (a->ip4.addr > b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 66 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 67
tass picotcp@tass.be 149:5f4cb161cec3 68 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 69 }
tass picotcp@tass.be 149:5f4cb161cec3 70
tass picotcp@tass.be 149:5f4cb161cec3 71 static int mcast_socket_cmp(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 72 {
tass picotcp@tass.be 149:5f4cb161cec3 73 struct pico_socket *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 74 if (a < b)
tass picotcp@tass.be 149:5f4cb161cec3 75 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 76
tass picotcp@tass.be 149:5f4cb161cec3 77 if (a > b)
tass picotcp@tass.be 149:5f4cb161cec3 78 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 79
tass picotcp@tass.be 149:5f4cb161cec3 80 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 81 }
tass picotcp@tass.be 149:5f4cb161cec3 82
tass picotcp@tass.be 149:5f4cb161cec3 83 /* gather all multicast sockets to hasten filter aggregation */
tass picotcp@tass.be 149:5f4cb161cec3 84 PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp);
tass picotcp@tass.be 149:5f4cb161cec3 85
tass picotcp@tass.be 149:5f4cb161cec3 86 static int mcast_filter_cmp(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 87 {
tass picotcp@tass.be 149:5f4cb161cec3 88 union pico_address *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 89 if (a->ip4.addr < b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 90 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 91
tass picotcp@tass.be 149:5f4cb161cec3 92 if (a->ip4.addr > b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 93 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 94
tass picotcp@tass.be 149:5f4cb161cec3 95 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 96 }
tass picotcp@tass.be 149:5f4cb161cec3 97 /* gather sources to be filtered */
tass picotcp@tass.be 149:5f4cb161cec3 98 PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp);
tass picotcp@tass.be 149:5f4cb161cec3 99
tass picotcp@tass.be 149:5f4cb161cec3 100 static struct pico_mcast_listen *listen_find(struct pico_socket *s, union pico_address *lnk, union pico_address *grp)
tass picotcp@tass.be 149:5f4cb161cec3 101 {
tass picotcp@tass.be 149:5f4cb161cec3 102 struct pico_mcast_listen ltest = {
tass picotcp@tass.be 149:5f4cb161cec3 103 0
tass picotcp@tass.be 149:5f4cb161cec3 104 };
tass picotcp@tass.be 149:5f4cb161cec3 105 ltest.mcast_link.ip4.addr = lnk->ip4.addr;
tass picotcp@tass.be 149:5f4cb161cec3 106 ltest.mcast_group.ip4.addr = grp->ip4.addr;
tass picotcp@tass.be 149:5f4cb161cec3 107 return pico_tree_findKey(s->MCASTListen, &ltest);
tass picotcp@tass.be 149:5f4cb161cec3 108 }
tass picotcp@tass.be 149:5f4cb161cec3 109
tass picotcp@tass.be 149:5f4cb161cec3 110 static uint8_t pico_mcast_filter_excl_excl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 111 {
tass picotcp@tass.be 149:5f4cb161cec3 112 /* filter = intersection of EXCLUDEs */
tass picotcp@tass.be 149:5f4cb161cec3 113 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 114 /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */
tass picotcp@tass.be 149:5f4cb161cec3 115 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 116 union pico_address *source = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 117 pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 118 {
tass picotcp@tass.be 149:5f4cb161cec3 119 source = pico_tree_findKey(&listen->MCASTSources, index->keyValue);
tass picotcp@tass.be 149:5f4cb161cec3 120 if (!source)
tass picotcp@tass.be 149:5f4cb161cec3 121 pico_tree_delete(&MCASTFilter, index->keyValue);
tass picotcp@tass.be 149:5f4cb161cec3 122 }
tass picotcp@tass.be 149:5f4cb161cec3 123 return PICO_IP_MULTICAST_EXCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 124 }
tass picotcp@tass.be 149:5f4cb161cec3 125
tass picotcp@tass.be 149:5f4cb161cec3 126 static uint8_t pico_mcast_filter_excl_incl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 127 {
tass picotcp@tass.be 149:5f4cb161cec3 128 /* filter = EXCLUDE - INCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 129 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 130 /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */
tass picotcp@tass.be 149:5f4cb161cec3 131 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 132 union pico_address *source = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 133 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 134 {
tass picotcp@tass.be 149:5f4cb161cec3 135 source = pico_tree_findKey(&MCASTFilter, index->keyValue);
tass picotcp@tass.be 149:5f4cb161cec3 136 if (source)
tass picotcp@tass.be 149:5f4cb161cec3 137 pico_tree_delete(&MCASTFilter, source);
tass picotcp@tass.be 149:5f4cb161cec3 138 }
tass picotcp@tass.be 149:5f4cb161cec3 139 return PICO_IP_MULTICAST_EXCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 140 }
tass picotcp@tass.be 149:5f4cb161cec3 141
tass picotcp@tass.be 149:5f4cb161cec3 142 static uint8_t pico_mcast_filter_incl_excl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 143 {
tass picotcp@tass.be 149:5f4cb161cec3 144 /* filter = EXCLUDE - INCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 145 /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */
tass picotcp@tass.be 149:5f4cb161cec3 146 struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 147 union pico_address *source = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 148 pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
tass picotcp@tass.be 149:5f4cb161cec3 149 {
tass picotcp@tass.be 149:5f4cb161cec3 150 source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
tass picotcp@tass.be 149:5f4cb161cec3 151 if (!source)
tass picotcp@tass.be 149:5f4cb161cec3 152 pico_tree_delete(&MCASTFilter, index2->keyValue);
tass picotcp@tass.be 149:5f4cb161cec3 153 }
tass picotcp@tass.be 149:5f4cb161cec3 154 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 155
tass picotcp@tass.be 149:5f4cb161cec3 156 /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */
tass picotcp@tass.be 149:5f4cb161cec3 157 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 158 {
tass picotcp@tass.be 149:5f4cb161cec3 159 source = pico_tree_insert(&MCASTFilter, index->keyValue);
tass picotcp@tass.be 149:5f4cb161cec3 160 if (source)
tass picotcp@tass.be 149:5f4cb161cec3 161 pico_tree_delete(&MCASTFilter, source);
tass picotcp@tass.be 149:5f4cb161cec3 162 }
tass picotcp@tass.be 149:5f4cb161cec3 163 return PICO_IP_MULTICAST_EXCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 164 }
tass picotcp@tass.be 149:5f4cb161cec3 165
tass picotcp@tass.be 149:5f4cb161cec3 166 static uint8_t pico_mcast_filter_incl_incl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 167 {
tass picotcp@tass.be 149:5f4cb161cec3 168 /* filter = summation of INCLUDEs */
tass picotcp@tass.be 149:5f4cb161cec3 169 /* mode stays INCLUDE, add all sources to filter */
tass picotcp@tass.be 149:5f4cb161cec3 170 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 171 union pico_address *source = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 172 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 173 {
tass picotcp@tass.be 149:5f4cb161cec3 174 source = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 175 pico_tree_insert(&MCASTFilter, source);
tass picotcp@tass.be 149:5f4cb161cec3 176 }
tass picotcp@tass.be 149:5f4cb161cec3 177 return PICO_IP_MULTICAST_INCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 178 }
tass picotcp@tass.be 149:5f4cb161cec3 179
tass picotcp@tass.be 149:5f4cb161cec3 180 struct pico_mcast_filter_aggregation
tass picotcp@tass.be 149:5f4cb161cec3 181 {
tass picotcp@tass.be 149:5f4cb161cec3 182 uint8_t (*call)(struct pico_mcast_listen *);
tass picotcp@tass.be 149:5f4cb161cec3 183 };
tass picotcp@tass.be 149:5f4cb161cec3 184
tass picotcp@tass.be 149:5f4cb161cec3 185 static const struct pico_mcast_filter_aggregation mcast_filter_aggr_call[2][2] =
tass picotcp@tass.be 149:5f4cb161cec3 186 {
tass picotcp@tass.be 149:5f4cb161cec3 187 {
tass picotcp@tass.be 149:5f4cb161cec3 188 /* EXCL + EXCL */ {.call = pico_mcast_filter_excl_excl},
tass picotcp@tass.be 149:5f4cb161cec3 189 /* EXCL + INCL */ {.call = pico_mcast_filter_excl_incl}
tass picotcp@tass.be 149:5f4cb161cec3 190 },
tass picotcp@tass.be 149:5f4cb161cec3 191
tass picotcp@tass.be 149:5f4cb161cec3 192 {
tass picotcp@tass.be 149:5f4cb161cec3 193 /* INCL + EXCL */ {.call = pico_mcast_filter_incl_excl},
tass picotcp@tass.be 149:5f4cb161cec3 194 /* INCL + INCL */ {.call = pico_mcast_filter_incl_incl}
tass picotcp@tass.be 149:5f4cb161cec3 195 }
tass picotcp@tass.be 149:5f4cb161cec3 196 };
tass picotcp@tass.be 149:5f4cb161cec3 197
tass picotcp@tass.be 149:5f4cb161cec3 198 static int mcast_aggr_validate(uint8_t fm, struct pico_mcast_listen *l)
tass picotcp@tass.be 149:5f4cb161cec3 199 {
tass picotcp@tass.be 149:5f4cb161cec3 200 if (!l)
tass picotcp@tass.be 149:5f4cb161cec3 201 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 202
tass picotcp@tass.be 149:5f4cb161cec3 203 if (fm > 1)
tass picotcp@tass.be 149:5f4cb161cec3 204 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 205
tass picotcp@tass.be 149:5f4cb161cec3 206 if (l->filter_mode > 1)
tass picotcp@tass.be 149:5f4cb161cec3 207 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 208
tass picotcp@tass.be 149:5f4cb161cec3 209 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 210 }
tass picotcp@tass.be 149:5f4cb161cec3 211
tass picotcp@tass.be 149:5f4cb161cec3 212
tass picotcp@tass.be 149:5f4cb161cec3 213 /* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */
tass picotcp@tass.be 149:5f4cb161cec3 214 static int pico_socket_aggregate_mcastfilters(union pico_address *mcast_link, union pico_address *mcast_group)
tass picotcp@tass.be 149:5f4cb161cec3 215 {
tass picotcp@tass.be 149:5f4cb161cec3 216 uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 217 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 218 struct pico_socket *mcast_sock = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 219 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 220
tass picotcp@tass.be 149:5f4cb161cec3 221
tass picotcp@tass.be 149:5f4cb161cec3 222 /* cleanup old filter */
tass picotcp@tass.be 149:5f4cb161cec3 223 pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 224 {
tass picotcp@tass.be 149:5f4cb161cec3 225 pico_tree_delete(&MCASTFilter, index->keyValue);
tass picotcp@tass.be 149:5f4cb161cec3 226 }
tass picotcp@tass.be 149:5f4cb161cec3 227
tass picotcp@tass.be 149:5f4cb161cec3 228 /* construct new filter */
tass picotcp@tass.be 149:5f4cb161cec3 229 pico_tree_foreach_safe(index, &MCASTSockets, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 230 {
tass picotcp@tass.be 149:5f4cb161cec3 231 mcast_sock = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 232 listen = listen_find(mcast_sock, mcast_link, mcast_group);
tass picotcp@tass.be 149:5f4cb161cec3 233 if (listen) {
tass picotcp@tass.be 149:5f4cb161cec3 234 if (mcast_aggr_validate(filter_mode, listen) < 0) {
tass picotcp@tass.be 149:5f4cb161cec3 235 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 236 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 237 }
tass picotcp@tass.be 149:5f4cb161cec3 238
tass picotcp@tass.be 149:5f4cb161cec3 239 if (mcast_filter_aggr_call[filter_mode][listen->filter_mode].call) {
tass picotcp@tass.be 149:5f4cb161cec3 240 filter_mode = mcast_filter_aggr_call[filter_mode][listen->filter_mode].call(listen);
tass picotcp@tass.be 149:5f4cb161cec3 241 if (filter_mode > 1)
tass picotcp@tass.be 149:5f4cb161cec3 242 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 243 }
tass picotcp@tass.be 149:5f4cb161cec3 244 }
tass picotcp@tass.be 149:5f4cb161cec3 245 }
tass picotcp@tass.be 149:5f4cb161cec3 246 return filter_mode;
tass picotcp@tass.be 149:5f4cb161cec3 247 }
tass picotcp@tass.be 149:5f4cb161cec3 248
tass picotcp@tass.be 149:5f4cb161cec3 249 static int pico_socket_mcast_filter_include(struct pico_mcast_listen *listen, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 250 {
tass picotcp@tass.be 149:5f4cb161cec3 251 struct pico_tree_node *index = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 252 pico_tree_foreach(index, &listen->MCASTSources)
tass picotcp@tass.be 149:5f4cb161cec3 253 {
tass picotcp@tass.be 149:5f4cb161cec3 254 if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) {
tass picotcp@tass.be 149:5f4cb161cec3 255 so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->ip4.addr);
tass picotcp@tass.be 149:5f4cb161cec3 256 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 257 }
tass picotcp@tass.be 149:5f4cb161cec3 258 }
tass picotcp@tass.be 149:5f4cb161cec3 259 so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->ip4.addr);
tass picotcp@tass.be 149:5f4cb161cec3 260 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 261
tass picotcp@tass.be 149:5f4cb161cec3 262 }
tass picotcp@tass.be 149:5f4cb161cec3 263
tass picotcp@tass.be 149:5f4cb161cec3 264 static int pico_socket_mcast_filter_exclude(struct pico_mcast_listen *listen, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 265 {
tass picotcp@tass.be 149:5f4cb161cec3 266 struct pico_tree_node *index = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 267 pico_tree_foreach(index, &listen->MCASTSources)
tass picotcp@tass.be 149:5f4cb161cec3 268 {
tass picotcp@tass.be 149:5f4cb161cec3 269 if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) {
tass picotcp@tass.be 149:5f4cb161cec3 270 so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->ip4.addr);
tass picotcp@tass.be 149:5f4cb161cec3 271 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 272 }
tass picotcp@tass.be 149:5f4cb161cec3 273 }
tass picotcp@tass.be 149:5f4cb161cec3 274 so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->ip4.addr);
tass picotcp@tass.be 149:5f4cb161cec3 275 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 276 }
tass picotcp@tass.be 149:5f4cb161cec3 277
tass picotcp@tass.be 149:5f4cb161cec3 278 static int pico_socket_mcast_source_filtering(struct pico_mcast_listen *listen, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 279 {
tass picotcp@tass.be 149:5f4cb161cec3 280 /* perform source filtering */
tass picotcp@tass.be 149:5f4cb161cec3 281 if (listen->filter_mode == PICO_IP_MULTICAST_INCLUDE)
tass picotcp@tass.be 149:5f4cb161cec3 282 return pico_socket_mcast_filter_include(listen, src);
tass picotcp@tass.be 149:5f4cb161cec3 283
tass picotcp@tass.be 149:5f4cb161cec3 284 if (listen->filter_mode == PICO_IP_MULTICAST_EXCLUDE)
tass picotcp@tass.be 149:5f4cb161cec3 285 return pico_socket_mcast_filter_exclude(listen, src);
tass picotcp@tass.be 149:5f4cb161cec3 286
tass picotcp@tass.be 149:5f4cb161cec3 287 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 288 }
tass picotcp@tass.be 149:5f4cb161cec3 289
tass picotcp@tass.be 149:5f4cb161cec3 290 static struct pico_ipv4_link *pico_socket_mcast_filter_link_get(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 291 {
tass picotcp@tass.be 149:5f4cb161cec3 292 /* check if no multicast enabled on socket */
tass picotcp@tass.be 149:5f4cb161cec3 293 if (!s->MCASTListen)
tass picotcp@tass.be 149:5f4cb161cec3 294 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 295
tass picotcp@tass.be 149:5f4cb161cec3 296 return pico_ipv4_link_get(&s->local_addr.ip4);
tass picotcp@tass.be 149:5f4cb161cec3 297 }
tass picotcp@tass.be 149:5f4cb161cec3 298
tass picotcp@tass.be 149:5f4cb161cec3 299 int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 300 {
tass picotcp@tass.be 149:5f4cb161cec3 301 struct pico_ipv4_link *mcast_link = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 302 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 303
tass picotcp@tass.be 149:5f4cb161cec3 304 mcast_link = pico_socket_mcast_filter_link_get(s);
tass picotcp@tass.be 149:5f4cb161cec3 305 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 306 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 307
tass picotcp@tass.be 149:5f4cb161cec3 308 listen = listen_find(s, (union pico_address *)&mcast_link->address, mcast_group);
tass picotcp@tass.be 149:5f4cb161cec3 309 if (!listen)
tass picotcp@tass.be 149:5f4cb161cec3 310 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 311
tass picotcp@tass.be 149:5f4cb161cec3 312 return pico_socket_mcast_source_filtering(listen, src);
tass picotcp@tass.be 149:5f4cb161cec3 313 }
tass picotcp@tass.be 149:5f4cb161cec3 314
tass picotcp@tass.be 149:5f4cb161cec3 315 static struct pico_ipv4_link *get_mcast_link(union pico_address *a)
tass picotcp@tass.be 149:5f4cb161cec3 316 {
tass picotcp@tass.be 149:5f4cb161cec3 317 if (!a->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 318 return pico_ipv4_get_default_mcastlink();
tass picotcp@tass.be 149:5f4cb161cec3 319
tass picotcp@tass.be 149:5f4cb161cec3 320 return pico_ipv4_link_get(&a->ip4);
tass picotcp@tass.be 149:5f4cb161cec3 321 }
tass picotcp@tass.be 149:5f4cb161cec3 322
tass picotcp@tass.be 149:5f4cb161cec3 323
tass picotcp@tass.be 149:5f4cb161cec3 324 static int pico_socket_setoption_pre_validation(struct pico_ip_mreq *mreq)
tass picotcp@tass.be 149:5f4cb161cec3 325 {
tass picotcp@tass.be 149:5f4cb161cec3 326 if (!mreq)
tass picotcp@tass.be 149:5f4cb161cec3 327 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 328
tass picotcp@tass.be 149:5f4cb161cec3 329 if (!mreq->mcast_group_addr.addr)
tass picotcp@tass.be 149:5f4cb161cec3 330 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 331
tass picotcp@tass.be 149:5f4cb161cec3 332 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 333 }
tass picotcp@tass.be 149:5f4cb161cec3 334
tass picotcp@tass.be 149:5f4cb161cec3 335 static struct pico_ipv4_link *pico_socket_setoption_validate_mreq(struct pico_ip_mreq *mreq)
tass picotcp@tass.be 149:5f4cb161cec3 336 {
tass picotcp@tass.be 149:5f4cb161cec3 337 if (pico_socket_setoption_pre_validation(mreq) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 338 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 339
tass picotcp@tass.be 149:5f4cb161cec3 340 if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
tass picotcp@tass.be 149:5f4cb161cec3 341 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 342
tass picotcp@tass.be 149:5f4cb161cec3 343 return get_mcast_link((union pico_address *)&mreq->mcast_link_addr);
tass picotcp@tass.be 149:5f4cb161cec3 344 }
tass picotcp@tass.be 149:5f4cb161cec3 345
tass picotcp@tass.be 149:5f4cb161cec3 346 static int pico_socket_setoption_pre_validation_s(struct pico_ip_mreq_source *mreq)
tass picotcp@tass.be 149:5f4cb161cec3 347 {
tass picotcp@tass.be 149:5f4cb161cec3 348 if (!mreq)
tass picotcp@tass.be 149:5f4cb161cec3 349 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 350
tass picotcp@tass.be 149:5f4cb161cec3 351 if (!mreq->mcast_group_addr.addr)
tass picotcp@tass.be 149:5f4cb161cec3 352 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 353
tass picotcp@tass.be 149:5f4cb161cec3 354 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 355 }
tass picotcp@tass.be 149:5f4cb161cec3 356
tass picotcp@tass.be 149:5f4cb161cec3 357 static struct pico_ipv4_link *pico_socket_setoption_validate_s_mreq(struct pico_ip_mreq_source *mreq)
tass picotcp@tass.be 149:5f4cb161cec3 358 {
tass picotcp@tass.be 149:5f4cb161cec3 359 if (pico_socket_setoption_pre_validation_s(mreq) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 360 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 361
tass picotcp@tass.be 149:5f4cb161cec3 362 if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
tass picotcp@tass.be 149:5f4cb161cec3 363 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 364
tass picotcp@tass.be 149:5f4cb161cec3 365 if (!pico_ipv4_is_unicast(mreq->mcast_source_addr.addr))
tass picotcp@tass.be 149:5f4cb161cec3 366 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 367
tass picotcp@tass.be 149:5f4cb161cec3 368 return get_mcast_link((union pico_address *)&mreq->mcast_link_addr);
tass picotcp@tass.be 149:5f4cb161cec3 369 }
tass picotcp@tass.be 149:5f4cb161cec3 370
tass picotcp@tass.be 149:5f4cb161cec3 371
tass picotcp@tass.be 149:5f4cb161cec3 372 static struct pico_ipv4_link *setop_multicast_link_search(void *value, int bysource)
tass picotcp@tass.be 149:5f4cb161cec3 373 {
tass picotcp@tass.be 149:5f4cb161cec3 374
tass picotcp@tass.be 149:5f4cb161cec3 375 struct pico_ip_mreq *mreq = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 376 struct pico_ipv4_link *mcast_link = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 377 struct pico_ip_mreq_source *mreq_src = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 378 if (!bysource) {
tass picotcp@tass.be 149:5f4cb161cec3 379 mreq = (struct pico_ip_mreq *) value;
tass picotcp@tass.be 149:5f4cb161cec3 380 mcast_link = pico_socket_setoption_validate_mreq(mreq);
tass picotcp@tass.be 149:5f4cb161cec3 381 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 382 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 383
tass picotcp@tass.be 149:5f4cb161cec3 384 if (!mreq->mcast_link_addr.addr)
tass picotcp@tass.be 149:5f4cb161cec3 385 mreq->mcast_link_addr.addr = mcast_link->address.addr;
tass picotcp@tass.be 149:5f4cb161cec3 386 } else {
tass picotcp@tass.be 149:5f4cb161cec3 387 mreq_src = (struct pico_ip_mreq_source *) value;
tass picotcp@tass.be 149:5f4cb161cec3 388 if (!mreq_src)
tass picotcp@tass.be 149:5f4cb161cec3 389 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 390
tass picotcp@tass.be 149:5f4cb161cec3 391 mcast_link = pico_socket_setoption_validate_s_mreq(mreq_src);
tass picotcp@tass.be 149:5f4cb161cec3 392 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 393 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 394
tass picotcp@tass.be 149:5f4cb161cec3 395 if (!mreq_src->mcast_link_addr.addr)
tass picotcp@tass.be 149:5f4cb161cec3 396 mreq_src->mcast_link_addr.addr = mcast_link->address.addr;
tass picotcp@tass.be 149:5f4cb161cec3 397 }
tass picotcp@tass.be 149:5f4cb161cec3 398
tass picotcp@tass.be 149:5f4cb161cec3 399 return mcast_link;
tass picotcp@tass.be 149:5f4cb161cec3 400 }
tass picotcp@tass.be 149:5f4cb161cec3 401
tass picotcp@tass.be 149:5f4cb161cec3 402 static int setop_verify_listen_tree(struct pico_socket *s, int alloc)
tass picotcp@tass.be 149:5f4cb161cec3 403 {
tass picotcp@tass.be 149:5f4cb161cec3 404 if(!alloc)
tass picotcp@tass.be 149:5f4cb161cec3 405 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 406
tass picotcp@tass.be 149:5f4cb161cec3 407 s->MCASTListen = PICO_ZALLOC(sizeof(struct pico_tree));
tass picotcp@tass.be 149:5f4cb161cec3 408 if (!s->MCASTListen) {
tass picotcp@tass.be 149:5f4cb161cec3 409 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 410 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 411 }
tass picotcp@tass.be 149:5f4cb161cec3 412
tass picotcp@tass.be 149:5f4cb161cec3 413 s->MCASTListen->root = &LEAF;
tass picotcp@tass.be 149:5f4cb161cec3 414 s->MCASTListen->compare = mcast_listen_cmp;
tass picotcp@tass.be 149:5f4cb161cec3 415 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 416 }
tass picotcp@tass.be 149:5f4cb161cec3 417
tass picotcp@tass.be 149:5f4cb161cec3 418
tass picotcp@tass.be 149:5f4cb161cec3 419 static struct pico_ipv4_link *setopt_multicast_check(struct pico_socket *s, void *value, int alloc, int bysource)
tass picotcp@tass.be 149:5f4cb161cec3 420 {
tass picotcp@tass.be 149:5f4cb161cec3 421 struct pico_ipv4_link *mcast_link = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 422
tass picotcp@tass.be 149:5f4cb161cec3 423 if (!value) {
tass picotcp@tass.be 149:5f4cb161cec3 424 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 425 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 426 }
tass picotcp@tass.be 149:5f4cb161cec3 427
tass picotcp@tass.be 149:5f4cb161cec3 428 mcast_link = setop_multicast_link_search(value, bysource);
tass picotcp@tass.be 149:5f4cb161cec3 429
tass picotcp@tass.be 149:5f4cb161cec3 430 if (!mcast_link) {
tass picotcp@tass.be 149:5f4cb161cec3 431 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 432 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 433 }
tass picotcp@tass.be 149:5f4cb161cec3 434
tass picotcp@tass.be 149:5f4cb161cec3 435 if (!s->MCASTListen) { /* No RBTree allocated yet */
tass picotcp@tass.be 149:5f4cb161cec3 436 if (setop_verify_listen_tree(s, alloc) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 437 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 438 }
tass picotcp@tass.be 149:5f4cb161cec3 439
tass picotcp@tass.be 149:5f4cb161cec3 440 return mcast_link;
tass picotcp@tass.be 149:5f4cb161cec3 441 }
tass picotcp@tass.be 149:5f4cb161cec3 442
tass picotcp@tass.be 149:5f4cb161cec3 443
tass picotcp@tass.be 149:5f4cb161cec3 444 void pico_multicast_delete(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 445 {
tass picotcp@tass.be 149:5f4cb161cec3 446 int filter_mode;
tass picotcp@tass.be 149:5f4cb161cec3 447 struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 448 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 449 union pico_address *source = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 450 if (s->MCASTListen) {
tass picotcp@tass.be 149:5f4cb161cec3 451 pico_tree_delete(&MCASTSockets, s);
tass picotcp@tass.be 149:5f4cb161cec3 452 pico_tree_foreach_safe(index, s->MCASTListen, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 453 {
tass picotcp@tass.be 149:5f4cb161cec3 454 listen = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 455 pico_tree_foreach_safe(index2, &listen->MCASTSources, _tmp2)
tass picotcp@tass.be 149:5f4cb161cec3 456 {
tass picotcp@tass.be 149:5f4cb161cec3 457 source = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 458 pico_tree_delete(&listen->MCASTSources, source);
tass picotcp@tass.be 149:5f4cb161cec3 459 PICO_FREE(source);
tass picotcp@tass.be 149:5f4cb161cec3 460 }
tass picotcp@tass.be 149:5f4cb161cec3 461 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&listen->mcast_link, (union pico_address *)&listen->mcast_group);
tass picotcp@tass.be 149:5f4cb161cec3 462 if (filter_mode >= 0)
tass picotcp@tass.be 149:5f4cb161cec3 463 pico_ipv4_mcast_leave(&listen->mcast_link.ip4, &listen->mcast_group.ip4, 1, (uint8_t)filter_mode, &MCASTFilter);
tass picotcp@tass.be 149:5f4cb161cec3 464
tass picotcp@tass.be 149:5f4cb161cec3 465 pico_tree_delete(s->MCASTListen, listen);
tass picotcp@tass.be 149:5f4cb161cec3 466 PICO_FREE(listen);
tass picotcp@tass.be 149:5f4cb161cec3 467 }
tass picotcp@tass.be 149:5f4cb161cec3 468 PICO_FREE(s->MCASTListen);
tass picotcp@tass.be 149:5f4cb161cec3 469 }
tass picotcp@tass.be 149:5f4cb161cec3 470 }
tass picotcp@tass.be 149:5f4cb161cec3 471
tass picotcp@tass.be 149:5f4cb161cec3 472
tass picotcp@tass.be 149:5f4cb161cec3 473 int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 474 {
tass picotcp@tass.be 149:5f4cb161cec3 475 switch(option) {
tass picotcp@tass.be 149:5f4cb161cec3 476 case PICO_IP_MULTICAST_IF:
tass picotcp@tass.be 149:5f4cb161cec3 477 pico_err = PICO_ERR_EOPNOTSUPP;
tass picotcp@tass.be 149:5f4cb161cec3 478 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 479
tass picotcp@tass.be 149:5f4cb161cec3 480 case PICO_IP_MULTICAST_TTL:
tass picotcp@tass.be 149:5f4cb161cec3 481 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass picotcp@tass.be 149:5f4cb161cec3 482 pico_udp_get_mc_ttl(s, (uint8_t *) value);
tass picotcp@tass.be 149:5f4cb161cec3 483 } else {
tass picotcp@tass.be 149:5f4cb161cec3 484 *(uint8_t *)value = 0;
tass picotcp@tass.be 149:5f4cb161cec3 485 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 486 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 487 }
tass picotcp@tass.be 149:5f4cb161cec3 488
tass picotcp@tass.be 149:5f4cb161cec3 489 break;
tass picotcp@tass.be 149:5f4cb161cec3 490
tass picotcp@tass.be 149:5f4cb161cec3 491 case PICO_IP_MULTICAST_LOOP:
tass picotcp@tass.be 149:5f4cb161cec3 492 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass picotcp@tass.be 149:5f4cb161cec3 493 *(uint8_t *)value = (uint8_t)PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
tass picotcp@tass.be 149:5f4cb161cec3 494 } else {
tass picotcp@tass.be 149:5f4cb161cec3 495 *(uint8_t *)value = 0;
tass picotcp@tass.be 149:5f4cb161cec3 496 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 497 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 498 }
tass picotcp@tass.be 149:5f4cb161cec3 499
tass picotcp@tass.be 149:5f4cb161cec3 500 break;
tass picotcp@tass.be 149:5f4cb161cec3 501 default:
tass picotcp@tass.be 149:5f4cb161cec3 502 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 503 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 504 }
tass picotcp@tass.be 149:5f4cb161cec3 505
tass picotcp@tass.be 149:5f4cb161cec3 506 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 507 }
tass picotcp@tass.be 149:5f4cb161cec3 508
tass picotcp@tass.be 149:5f4cb161cec3 509 static int mcast_so_loop(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 510 {
tass picotcp@tass.be 149:5f4cb161cec3 511 uint8_t val = (*(uint8_t *)value);
tass picotcp@tass.be 149:5f4cb161cec3 512 if (val == 0u) {
tass picotcp@tass.be 149:5f4cb161cec3 513 PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
tass picotcp@tass.be 149:5f4cb161cec3 514 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 515 } else if (val == 1u) {
tass picotcp@tass.be 149:5f4cb161cec3 516 PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
tass picotcp@tass.be 149:5f4cb161cec3 517 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 518 }
tass picotcp@tass.be 149:5f4cb161cec3 519
tass picotcp@tass.be 149:5f4cb161cec3 520 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 521 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 522 }
tass picotcp@tass.be 149:5f4cb161cec3 523
tass picotcp@tass.be 149:5f4cb161cec3 524 static int mcast_so_addm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 525 {
tass picotcp@tass.be 149:5f4cb161cec3 526 int filter_mode;
tass picotcp@tass.be 149:5f4cb161cec3 527 struct pico_mcast_listen *listen;
tass picotcp@tass.be 149:5f4cb161cec3 528 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
tass picotcp@tass.be 149:5f4cb161cec3 529 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 0);
tass picotcp@tass.be 149:5f4cb161cec3 530 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 531 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 532
tass picotcp@tass.be 149:5f4cb161cec3 533 listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 534 if (listen) {
tass picotcp@tass.be 149:5f4cb161cec3 535 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass picotcp@tass.be 149:5f4cb161cec3 536 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass picotcp@tass.be 149:5f4cb161cec3 537 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 538 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 539 } else {
tass picotcp@tass.be 149:5f4cb161cec3 540 so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 541 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 542 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 543 }
tass picotcp@tass.be 149:5f4cb161cec3 544 } else {
tass picotcp@tass.be 149:5f4cb161cec3 545 listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen));
tass picotcp@tass.be 149:5f4cb161cec3 546 if (!listen) {
tass picotcp@tass.be 149:5f4cb161cec3 547 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 548 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 549 }
tass picotcp@tass.be 149:5f4cb161cec3 550
tass picotcp@tass.be 149:5f4cb161cec3 551 listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 552 listen->mcast_link.ip4 = mreq->mcast_link_addr;
tass picotcp@tass.be 149:5f4cb161cec3 553 listen->mcast_group.ip4 = mreq->mcast_group_addr;
tass picotcp@tass.be 149:5f4cb161cec3 554 listen->MCASTSources.root = &LEAF;
tass picotcp@tass.be 149:5f4cb161cec3 555 listen->MCASTSources.compare = mcast_sources_cmp;
tass picotcp@tass.be 149:5f4cb161cec3 556 pico_tree_insert(s->MCASTListen, listen);
tass picotcp@tass.be 149:5f4cb161cec3 557 }
tass picotcp@tass.be 149:5f4cb161cec3 558
tass picotcp@tass.be 149:5f4cb161cec3 559 pico_tree_insert(&MCASTSockets, s);
tass picotcp@tass.be 149:5f4cb161cec3 560 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 561 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 562 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 563
tass picotcp@tass.be 149:5f4cb161cec3 564 so_mcast_dbg("PICO_IP_ADD_MEMBERSHIP - success, added %p\n", s);
tass picotcp@tass.be 149:5f4cb161cec3 565 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
tass picotcp@tass.be 149:5f4cb161cec3 566 }
tass picotcp@tass.be 149:5f4cb161cec3 567
tass picotcp@tass.be 149:5f4cb161cec3 568 static int mcast_so_dropm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 569 {
tass picotcp@tass.be 149:5f4cb161cec3 570 int filter_mode = 0;
tass picotcp@tass.be 149:5f4cb161cec3 571 struct pico_mcast_listen *listen;
tass picotcp@tass.be 149:5f4cb161cec3 572 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
tass picotcp@tass.be 149:5f4cb161cec3 573 union pico_address *source = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 574 struct pico_tree_node *index, *_tmp;
tass picotcp@tass.be 149:5f4cb161cec3 575 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 0);
tass picotcp@tass.be 149:5f4cb161cec3 576 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 577 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 578
tass picotcp@tass.be 149:5f4cb161cec3 579 listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 580 if (!listen) {
tass picotcp@tass.be 149:5f4cb161cec3 581 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 582 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 583 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 584 } else {
tass picotcp@tass.be 149:5f4cb161cec3 585 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 586 {
tass picotcp@tass.be 149:5f4cb161cec3 587 source = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 588 pico_tree_delete(&listen->MCASTSources, source);
tass picotcp@tass.be 149:5f4cb161cec3 589 PICO_FREE(source);
tass picotcp@tass.be 149:5f4cb161cec3 590 }
tass picotcp@tass.be 149:5f4cb161cec3 591 pico_tree_delete(s->MCASTListen, listen);
tass picotcp@tass.be 149:5f4cb161cec3 592 PICO_FREE(listen);
tass picotcp@tass.be 149:5f4cb161cec3 593 if (pico_tree_empty(s->MCASTListen)) {
tass picotcp@tass.be 149:5f4cb161cec3 594 PICO_FREE(s->MCASTListen);
tass picotcp@tass.be 149:5f4cb161cec3 595 s->MCASTListen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 596 pico_tree_delete(&MCASTSockets, s);
tass picotcp@tass.be 149:5f4cb161cec3 597 }
tass picotcp@tass.be 149:5f4cb161cec3 598 }
tass picotcp@tass.be 149:5f4cb161cec3 599
tass picotcp@tass.be 149:5f4cb161cec3 600 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 601 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 602 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 603
tass picotcp@tass.be 149:5f4cb161cec3 604 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
tass picotcp@tass.be 149:5f4cb161cec3 605 }
tass picotcp@tass.be 149:5f4cb161cec3 606
tass picotcp@tass.be 149:5f4cb161cec3 607 static int mcast_so_unblock_src(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 608 {
tass picotcp@tass.be 149:5f4cb161cec3 609 int filter_mode = 0;
tass picotcp@tass.be 149:5f4cb161cec3 610 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass picotcp@tass.be 149:5f4cb161cec3 611 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 612 union pico_address *source = NULL, stest;
tass picotcp@tass.be 149:5f4cb161cec3 613 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
tass picotcp@tass.be 149:5f4cb161cec3 614
tass picotcp@tass.be 149:5f4cb161cec3 615 memset(&stest, 0, sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 616 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 617 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 618
tass picotcp@tass.be 149:5f4cb161cec3 619
tass picotcp@tass.be 149:5f4cb161cec3 620 listen = listen_find(s, (union pico_address *) &mreq->mcast_link_addr, (union pico_address *) &mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 621 if (!listen) {
tass picotcp@tass.be 149:5f4cb161cec3 622 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 623 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 624 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 625 } else {
tass picotcp@tass.be 149:5f4cb161cec3 626 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass picotcp@tass.be 149:5f4cb161cec3 627 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass picotcp@tass.be 149:5f4cb161cec3 628 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 629 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 630 }
tass picotcp@tass.be 149:5f4cb161cec3 631
tass picotcp@tass.be 149:5f4cb161cec3 632 stest.ip4.addr = mreq->mcast_source_addr.addr;
tass picotcp@tass.be 149:5f4cb161cec3 633 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass picotcp@tass.be 149:5f4cb161cec3 634 if (!source) {
tass picotcp@tass.be 149:5f4cb161cec3 635 so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n");
tass picotcp@tass.be 149:5f4cb161cec3 636 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 637 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 638 } else {
tass picotcp@tass.be 149:5f4cb161cec3 639 pico_tree_delete(&listen->MCASTSources, source);
tass picotcp@tass.be 149:5f4cb161cec3 640 PICO_FREE(source);
tass picotcp@tass.be 149:5f4cb161cec3 641 }
tass picotcp@tass.be 149:5f4cb161cec3 642 }
tass picotcp@tass.be 149:5f4cb161cec3 643
tass picotcp@tass.be 149:5f4cb161cec3 644 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 645 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 646 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 647
tass picotcp@tass.be 149:5f4cb161cec3 648 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
tass picotcp@tass.be 149:5f4cb161cec3 649 }
tass picotcp@tass.be 149:5f4cb161cec3 650
tass picotcp@tass.be 149:5f4cb161cec3 651 static int mcast_so_block_src(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 652 {
tass picotcp@tass.be 149:5f4cb161cec3 653 int filter_mode = 0;
tass picotcp@tass.be 149:5f4cb161cec3 654 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass picotcp@tass.be 149:5f4cb161cec3 655 struct pico_mcast_listen *listen;
tass picotcp@tass.be 149:5f4cb161cec3 656 union pico_address *source, stest;
tass picotcp@tass.be 149:5f4cb161cec3 657 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
tass picotcp@tass.be 149:5f4cb161cec3 658 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 659 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 660
tass picotcp@tass.be 149:5f4cb161cec3 661 memset(&stest, 0, sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 662
tass picotcp@tass.be 149:5f4cb161cec3 663 listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 664 if (!listen) {
tass picotcp@tass.be 149:5f4cb161cec3 665 dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 666 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 667 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 668 } else {
tass picotcp@tass.be 149:5f4cb161cec3 669 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass picotcp@tass.be 149:5f4cb161cec3 670 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass picotcp@tass.be 149:5f4cb161cec3 671 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 672 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 673 }
tass picotcp@tass.be 149:5f4cb161cec3 674
tass picotcp@tass.be 149:5f4cb161cec3 675 stest.ip4.addr = mreq->mcast_source_addr.addr;
tass picotcp@tass.be 149:5f4cb161cec3 676 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass picotcp@tass.be 149:5f4cb161cec3 677 if (source) {
tass picotcp@tass.be 149:5f4cb161cec3 678 so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n");
tass picotcp@tass.be 149:5f4cb161cec3 679 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 680 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 681 } else {
tass picotcp@tass.be 149:5f4cb161cec3 682 source = PICO_ZALLOC(sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 683 if (!source) {
tass picotcp@tass.be 149:5f4cb161cec3 684 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 685 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 686 }
tass picotcp@tass.be 149:5f4cb161cec3 687
tass picotcp@tass.be 149:5f4cb161cec3 688 source->ip4.addr = mreq->mcast_source_addr.addr;
tass picotcp@tass.be 149:5f4cb161cec3 689 pico_tree_insert(&listen->MCASTSources, source);
tass picotcp@tass.be 149:5f4cb161cec3 690 }
tass picotcp@tass.be 149:5f4cb161cec3 691 }
tass picotcp@tass.be 149:5f4cb161cec3 692
tass picotcp@tass.be 149:5f4cb161cec3 693 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 694 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 695 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 696
tass picotcp@tass.be 149:5f4cb161cec3 697 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
tass picotcp@tass.be 149:5f4cb161cec3 698 }
tass picotcp@tass.be 149:5f4cb161cec3 699
tass picotcp@tass.be 149:5f4cb161cec3 700 static int mcast_so_addsrcm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 701 {
tass picotcp@tass.be 149:5f4cb161cec3 702 int filter_mode = 0, reference_count = 0;
tass picotcp@tass.be 149:5f4cb161cec3 703 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass picotcp@tass.be 149:5f4cb161cec3 704 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 705 union pico_address *source = NULL, stest;
tass picotcp@tass.be 149:5f4cb161cec3 706 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 1);
tass picotcp@tass.be 149:5f4cb161cec3 707 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 708 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 709
tass picotcp@tass.be 149:5f4cb161cec3 710 memset(&stest, 0, sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 711
tass picotcp@tass.be 149:5f4cb161cec3 712 listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *) &mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 713 if (listen) {
tass picotcp@tass.be 149:5f4cb161cec3 714 if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
tass picotcp@tass.be 149:5f4cb161cec3 715 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
tass picotcp@tass.be 149:5f4cb161cec3 716 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 717 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 718 }
tass picotcp@tass.be 149:5f4cb161cec3 719
tass picotcp@tass.be 149:5f4cb161cec3 720 stest.ip4.addr = mreq->mcast_source_addr.addr;
tass picotcp@tass.be 149:5f4cb161cec3 721 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass picotcp@tass.be 149:5f4cb161cec3 722 if (source) {
tass picotcp@tass.be 149:5f4cb161cec3 723 so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n");
tass picotcp@tass.be 149:5f4cb161cec3 724 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 725 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 726 } else {
tass picotcp@tass.be 149:5f4cb161cec3 727 source = PICO_ZALLOC(sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 728 if (!source) {
tass picotcp@tass.be 149:5f4cb161cec3 729 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 730 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 731 }
tass picotcp@tass.be 149:5f4cb161cec3 732
tass picotcp@tass.be 149:5f4cb161cec3 733 source->ip4.addr = mreq->mcast_source_addr.addr;
tass picotcp@tass.be 149:5f4cb161cec3 734 pico_tree_insert(&listen->MCASTSources, source);
tass picotcp@tass.be 149:5f4cb161cec3 735 }
tass picotcp@tass.be 149:5f4cb161cec3 736 } else {
tass picotcp@tass.be 149:5f4cb161cec3 737 listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen));
tass picotcp@tass.be 149:5f4cb161cec3 738 if (!listen) {
tass picotcp@tass.be 149:5f4cb161cec3 739 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 740 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 741 }
tass picotcp@tass.be 149:5f4cb161cec3 742
tass picotcp@tass.be 149:5f4cb161cec3 743 listen->filter_mode = PICO_IP_MULTICAST_INCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 744 listen->mcast_link.ip4 = mreq->mcast_link_addr;
tass picotcp@tass.be 149:5f4cb161cec3 745 listen->mcast_group.ip4 = mreq->mcast_group_addr;
tass picotcp@tass.be 149:5f4cb161cec3 746 listen->MCASTSources.root = &LEAF;
tass picotcp@tass.be 149:5f4cb161cec3 747 listen->MCASTSources.compare = mcast_sources_cmp;
tass picotcp@tass.be 149:5f4cb161cec3 748 source = PICO_ZALLOC(sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 749 if (!source) {
tass picotcp@tass.be 149:5f4cb161cec3 750 PICO_FREE(listen);
tass picotcp@tass.be 149:5f4cb161cec3 751 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 752 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 753 }
tass picotcp@tass.be 149:5f4cb161cec3 754
tass picotcp@tass.be 149:5f4cb161cec3 755 source->ip4.addr = mreq->mcast_source_addr.addr;
tass picotcp@tass.be 149:5f4cb161cec3 756 pico_tree_insert(&listen->MCASTSources, source);
tass picotcp@tass.be 149:5f4cb161cec3 757 pico_tree_insert(s->MCASTListen, listen);
tass picotcp@tass.be 149:5f4cb161cec3 758 reference_count = 1;
tass picotcp@tass.be 149:5f4cb161cec3 759 }
tass picotcp@tass.be 149:5f4cb161cec3 760
tass picotcp@tass.be 149:5f4cb161cec3 761 pico_tree_insert(&MCASTSockets, s);
tass picotcp@tass.be 149:5f4cb161cec3 762 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 763 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 764 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 765
tass picotcp@tass.be 149:5f4cb161cec3 766 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
tass picotcp@tass.be 149:5f4cb161cec3 767 }
tass picotcp@tass.be 149:5f4cb161cec3 768
tass picotcp@tass.be 149:5f4cb161cec3 769 static int mcast_so_dropsrcm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 770 {
tass picotcp@tass.be 149:5f4cb161cec3 771 int filter_mode = 0, reference_count = 0;
tass picotcp@tass.be 149:5f4cb161cec3 772 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass picotcp@tass.be 149:5f4cb161cec3 773 struct pico_mcast_listen *listen;
tass picotcp@tass.be 149:5f4cb161cec3 774 union pico_address *source, stest;
tass picotcp@tass.be 149:5f4cb161cec3 775 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
tass picotcp@tass.be 149:5f4cb161cec3 776 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 777 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 778
tass picotcp@tass.be 149:5f4cb161cec3 779 memset(&stest, 0, sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 780
tass picotcp@tass.be 149:5f4cb161cec3 781 listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 782 if (!listen) {
tass picotcp@tass.be 149:5f4cb161cec3 783 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 784 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 785 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 786 } else {
tass picotcp@tass.be 149:5f4cb161cec3 787 if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
tass picotcp@tass.be 149:5f4cb161cec3 788 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
tass picotcp@tass.be 149:5f4cb161cec3 789 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 790 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 791 }
tass picotcp@tass.be 149:5f4cb161cec3 792
tass picotcp@tass.be 149:5f4cb161cec3 793 stest.ip4.addr = mreq->mcast_source_addr.addr;
tass picotcp@tass.be 149:5f4cb161cec3 794 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass picotcp@tass.be 149:5f4cb161cec3 795 if (!source) {
tass picotcp@tass.be 149:5f4cb161cec3 796 so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n");
tass picotcp@tass.be 149:5f4cb161cec3 797 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 798 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 799 } else {
tass picotcp@tass.be 149:5f4cb161cec3 800 pico_tree_delete(&listen->MCASTSources, source);
tass picotcp@tass.be 149:5f4cb161cec3 801 PICO_FREE(source);
tass picotcp@tass.be 149:5f4cb161cec3 802 if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */
tass picotcp@tass.be 149:5f4cb161cec3 803 reference_count = 1;
tass picotcp@tass.be 149:5f4cb161cec3 804 pico_tree_delete(s->MCASTListen, listen);
tass picotcp@tass.be 149:5f4cb161cec3 805 PICO_FREE(listen);
tass picotcp@tass.be 149:5f4cb161cec3 806 if (pico_tree_empty(s->MCASTListen)) {
tass picotcp@tass.be 149:5f4cb161cec3 807 PICO_FREE(s->MCASTListen);
tass picotcp@tass.be 149:5f4cb161cec3 808 s->MCASTListen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 809 pico_tree_delete(&MCASTSockets, s);
tass picotcp@tass.be 149:5f4cb161cec3 810 }
tass picotcp@tass.be 149:5f4cb161cec3 811 }
tass picotcp@tass.be 149:5f4cb161cec3 812 }
tass picotcp@tass.be 149:5f4cb161cec3 813 }
tass picotcp@tass.be 149:5f4cb161cec3 814
tass picotcp@tass.be 149:5f4cb161cec3 815 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 816 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 817 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 818
tass picotcp@tass.be 149:5f4cb161cec3 819 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
tass picotcp@tass.be 149:5f4cb161cec3 820 }
tass picotcp@tass.be 149:5f4cb161cec3 821
tass picotcp@tass.be 149:5f4cb161cec3 822 struct pico_setsockopt_mcast_call
tass picotcp@tass.be 149:5f4cb161cec3 823 {
tass picotcp@tass.be 149:5f4cb161cec3 824 int option;
tass picotcp@tass.be 149:5f4cb161cec3 825 int (*call)(struct pico_socket *, void *);
tass picotcp@tass.be 149:5f4cb161cec3 826 };
tass picotcp@tass.be 149:5f4cb161cec3 827
tass picotcp@tass.be 149:5f4cb161cec3 828 static const struct pico_setsockopt_mcast_call mcast_so_calls[1 + PICO_IP_DROP_SOURCE_MEMBERSHIP - PICO_IP_MULTICAST_IF] =
tass picotcp@tass.be 149:5f4cb161cec3 829 {
tass picotcp@tass.be 149:5f4cb161cec3 830 { PICO_IP_MULTICAST_IF, NULL },
tass picotcp@tass.be 149:5f4cb161cec3 831 { PICO_IP_MULTICAST_TTL, pico_udp_set_mc_ttl },
tass picotcp@tass.be 149:5f4cb161cec3 832 { PICO_IP_MULTICAST_LOOP, mcast_so_loop },
tass picotcp@tass.be 149:5f4cb161cec3 833 { PICO_IP_ADD_MEMBERSHIP, mcast_so_addm },
tass picotcp@tass.be 149:5f4cb161cec3 834 { PICO_IP_DROP_MEMBERSHIP, mcast_so_dropm },
tass picotcp@tass.be 149:5f4cb161cec3 835 { PICO_IP_UNBLOCK_SOURCE, mcast_so_unblock_src },
tass picotcp@tass.be 149:5f4cb161cec3 836 { PICO_IP_BLOCK_SOURCE, mcast_so_block_src },
tass picotcp@tass.be 149:5f4cb161cec3 837 { PICO_IP_ADD_SOURCE_MEMBERSHIP, mcast_so_addsrcm },
tass picotcp@tass.be 149:5f4cb161cec3 838 { PICO_IP_DROP_SOURCE_MEMBERSHIP, mcast_so_dropsrcm }
tass picotcp@tass.be 149:5f4cb161cec3 839 };
tass picotcp@tass.be 149:5f4cb161cec3 840
tass picotcp@tass.be 149:5f4cb161cec3 841
tass picotcp@tass.be 149:5f4cb161cec3 842 static int mcast_so_check_socket(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 843 {
tass picotcp@tass.be 149:5f4cb161cec3 844 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 845 if (!s)
tass picotcp@tass.be 149:5f4cb161cec3 846 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 847
tass picotcp@tass.be 149:5f4cb161cec3 848 if (!s->proto)
tass picotcp@tass.be 149:5f4cb161cec3 849 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 850
tass picotcp@tass.be 149:5f4cb161cec3 851 if (s->proto->proto_number != PICO_PROTO_UDP)
tass picotcp@tass.be 149:5f4cb161cec3 852 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 853
tass picotcp@tass.be 149:5f4cb161cec3 854 pico_err = PICO_ERR_NOERR;
tass picotcp@tass.be 149:5f4cb161cec3 855 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 856 }
tass picotcp@tass.be 149:5f4cb161cec3 857
tass picotcp@tass.be 149:5f4cb161cec3 858 int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 859 {
tass picotcp@tass.be 149:5f4cb161cec3 860 int arrayn = option - PICO_IP_MULTICAST_IF;
tass picotcp@tass.be 149:5f4cb161cec3 861 if (option < PICO_IP_MULTICAST_IF || option > PICO_IP_DROP_SOURCE_MEMBERSHIP) {
tass picotcp@tass.be 149:5f4cb161cec3 862 pico_err = PICO_ERR_EOPNOTSUPP;
tass picotcp@tass.be 149:5f4cb161cec3 863 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 864 }
tass picotcp@tass.be 149:5f4cb161cec3 865
tass picotcp@tass.be 149:5f4cb161cec3 866 if (mcast_so_check_socket(s) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 867 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 868
tass picotcp@tass.be 149:5f4cb161cec3 869 if (!mcast_so_calls[arrayn].call) {
tass picotcp@tass.be 149:5f4cb161cec3 870 pico_err = PICO_ERR_EOPNOTSUPP;
tass picotcp@tass.be 149:5f4cb161cec3 871 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 872 }
tass picotcp@tass.be 149:5f4cb161cec3 873
tass picotcp@tass.be 149:5f4cb161cec3 874 return (mcast_so_calls[arrayn].call(s, value));
tass picotcp@tass.be 149:5f4cb161cec3 875 }
tass picotcp@tass.be 149:5f4cb161cec3 876
tass picotcp@tass.be 149:5f4cb161cec3 877 int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl)
tass picotcp@tass.be 149:5f4cb161cec3 878 {
tass picotcp@tass.be 149:5f4cb161cec3 879 struct pico_socket_udp *u;
tass picotcp@tass.be 149:5f4cb161cec3 880 uint8_t ttl = *(uint8_t *)_ttl;
tass picotcp@tass.be 149:5f4cb161cec3 881 if(!s) {
tass picotcp@tass.be 149:5f4cb161cec3 882 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 883 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 884 }
tass picotcp@tass.be 149:5f4cb161cec3 885
tass picotcp@tass.be 149:5f4cb161cec3 886 u = (struct pico_socket_udp *) s;
tass picotcp@tass.be 149:5f4cb161cec3 887 u->mc_ttl = ttl;
tass picotcp@tass.be 149:5f4cb161cec3 888 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 889 }
tass picotcp@tass.be 149:5f4cb161cec3 890
tass picotcp@tass.be 149:5f4cb161cec3 891 int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
tass picotcp@tass.be 149:5f4cb161cec3 892 {
tass picotcp@tass.be 149:5f4cb161cec3 893 struct pico_socket_udp *u;
tass picotcp@tass.be 149:5f4cb161cec3 894 if(!s)
tass picotcp@tass.be 149:5f4cb161cec3 895 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 896
tass picotcp@tass.be 149:5f4cb161cec3 897 u = (struct pico_socket_udp *) s;
tass picotcp@tass.be 149:5f4cb161cec3 898 *ttl = u->mc_ttl;
tass picotcp@tass.be 149:5f4cb161cec3 899 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 900 }
tass picotcp@tass.be 149:5f4cb161cec3 901 #else
tass picotcp@tass.be 149:5f4cb161cec3 902 int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl)
tass picotcp@tass.be 149:5f4cb161cec3 903 {
tass picotcp@tass.be 149:5f4cb161cec3 904 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 905 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 906 }
tass picotcp@tass.be 149:5f4cb161cec3 907
tass picotcp@tass.be 149:5f4cb161cec3 908 int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
tass picotcp@tass.be 149:5f4cb161cec3 909 {
tass picotcp@tass.be 149:5f4cb161cec3 910 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 911 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 912 }
tass picotcp@tass.be 149:5f4cb161cec3 913
tass picotcp@tass.be 149:5f4cb161cec3 914 int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 915 {
tass picotcp@tass.be 149:5f4cb161cec3 916 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 917 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 918 }
tass picotcp@tass.be 149:5f4cb161cec3 919
tass picotcp@tass.be 149:5f4cb161cec3 920 void pico_multicast_delete(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 921 {
tass picotcp@tass.be 149:5f4cb161cec3 922 (void)s;
tass picotcp@tass.be 149:5f4cb161cec3 923 }
tass picotcp@tass.be 149:5f4cb161cec3 924
tass picotcp@tass.be 149:5f4cb161cec3 925 int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 926 {
tass picotcp@tass.be 149:5f4cb161cec3 927 (void)s;
tass picotcp@tass.be 149:5f4cb161cec3 928 (void)option;
tass picotcp@tass.be 149:5f4cb161cec3 929 (void)value;
tass picotcp@tass.be 149:5f4cb161cec3 930 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 931 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 932 }
tass picotcp@tass.be 149:5f4cb161cec3 933
tass picotcp@tass.be 149:5f4cb161cec3 934 int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 935 {
tass picotcp@tass.be 149:5f4cb161cec3 936 (void)s;
tass picotcp@tass.be 149:5f4cb161cec3 937 (void)option;
tass picotcp@tass.be 149:5f4cb161cec3 938 (void)value;
tass picotcp@tass.be 149:5f4cb161cec3 939 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 940 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 941
tass picotcp@tass.be 149:5f4cb161cec3 942 }
tass picotcp@tass.be 149:5f4cb161cec3 943 #endif /* PICO_SUPPORT_MCAST */
tass picotcp@tass.be 149:5f4cb161cec3 944