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
Date:
Thu Jan 28 15:12:00 2016 +0100
Revision:
155:a70f34550c34
Parent:
154:6c0e92a80c4a
Adding TCP flag for FIN.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 152:a3d286bf94e5 1 #include "pico_config.h"
tass 152:a3d286bf94e5 2 #include "pico_stack.h"
tass picotcp@tass.be 149:5f4cb161cec3 3 #include "pico_socket.h"
tass picotcp@tass.be 149:5f4cb161cec3 4 #include "pico_socket_multicast.h"
tass picotcp@tass.be 149:5f4cb161cec3 5 #include "pico_tree.h"
tass picotcp@tass.be 149:5f4cb161cec3 6 #include "pico_ipv4.h"
tass 152:a3d286bf94e5 7 #include "pico_ipv6.h"
tass picotcp@tass.be 149:5f4cb161cec3 8 #include "pico_udp.h"
tass picotcp@tass.be 149:5f4cb161cec3 9
tass picotcp@tass.be 149:5f4cb161cec3 10 #ifdef PICO_SUPPORT_MCAST
tass 152:a3d286bf94e5 11 # define so_mcast_dbg(...) do { }while(0) /* ip_mcast_dbg in pico_ipv4.c */
tass picotcp@tass.be 149:5f4cb161cec3 12 /* #define so_mcast_dbg dbg */
tass picotcp@tass.be 149:5f4cb161cec3 13
tass picotcp@tass.be 149:5f4cb161cec3 14 /* socket
tass 152:a3d286bf94e5 15 * |
tass 152:a3d286bf94e5 16 * MCASTListen
tass 152:a3d286bf94e5 17 * | | |
tass 152:a3d286bf94e5 18 * ------------ | ------------
tass 152:a3d286bf94e5 19 * | | |
tass 152:a3d286bf94e5 20 * MCASTSources MCASTSources MCASTSources
tass 152:a3d286bf94e5 21 * | | | | | | | | | | | |
tass 152:a3d286bf94e5 22 * S S S S S S S S S S S S
tass 152:a3d286bf94e5 23 *
tass 152:a3d286bf94e5 24 * MCASTListen: RBTree(mcast_link, mcast_group)
tass 152:a3d286bf94e5 25 * MCASTSources: RBTree(source)
tass 152:a3d286bf94e5 26 */
tass picotcp@tass.be 149:5f4cb161cec3 27 struct pico_mcast_listen
tass picotcp@tass.be 149:5f4cb161cec3 28 {
tass picotcp@tass.be 149:5f4cb161cec3 29 uint8_t filter_mode;
tass picotcp@tass.be 149:5f4cb161cec3 30 union pico_address mcast_link;
tass picotcp@tass.be 149:5f4cb161cec3 31 union pico_address mcast_group;
tass picotcp@tass.be 149:5f4cb161cec3 32 struct pico_tree MCASTSources;
tass 152:a3d286bf94e5 33 struct pico_tree MCASTSources_ipv6;
tass 152:a3d286bf94e5 34 uint16_t proto;
tass picotcp@tass.be 149:5f4cb161cec3 35 };
tass 152:a3d286bf94e5 36 //Parameters
tass 152:a3d286bf94e5 37 struct pico_mcast
tass 152:a3d286bf94e5 38 {
tass 152:a3d286bf94e5 39 struct pico_socket *s;
tass 154:6c0e92a80c4a 40 struct pico_ip_mreq *mreq;
tass 154:6c0e92a80c4a 41 struct pico_ip_mreq_source *mreq_s;
tass 152:a3d286bf94e5 42 union pico_address *address;
tass 152:a3d286bf94e5 43 union pico_link *mcast_link;
tass 152:a3d286bf94e5 44 struct pico_mcast_listen *listen;
tass 152:a3d286bf94e5 45 };
tass picotcp@tass.be 149:5f4cb161cec3 46 static int mcast_listen_link_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b)
tass picotcp@tass.be 149:5f4cb161cec3 47 {
tass 152:a3d286bf94e5 48
tass 152:a3d286bf94e5 49 if (a->proto < b->proto)
tass picotcp@tass.be 149:5f4cb161cec3 50 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 51
tass 152:a3d286bf94e5 52 if (a->proto > b->proto)
tass picotcp@tass.be 149:5f4cb161cec3 53 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 54
tass 152:a3d286bf94e5 55 return pico_address_compare(&a->mcast_link, &b->mcast_link, a->proto);
tass picotcp@tass.be 149:5f4cb161cec3 56 }
tass picotcp@tass.be 149:5f4cb161cec3 57
tass 152:a3d286bf94e5 58 static int mcast_listen_grp_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b)
tass picotcp@tass.be 149:5f4cb161cec3 59 {
tass picotcp@tass.be 149:5f4cb161cec3 60 if (a->mcast_group.ip4.addr < b->mcast_group.ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 61 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 62
tass picotcp@tass.be 149:5f4cb161cec3 63 if (a->mcast_group.ip4.addr > b->mcast_group.ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 64 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 65
tass picotcp@tass.be 149:5f4cb161cec3 66 return mcast_listen_link_cmp(a, b);
tass 152:a3d286bf94e5 67 }
tass 152:a3d286bf94e5 68 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 69 static int mcast_listen_grp_cmp_ipv6(struct pico_mcast_listen *a, struct pico_mcast_listen *b)
tass 152:a3d286bf94e5 70 {
tass 152:a3d286bf94e5 71 int tmp = memcmp(&a->mcast_group.ip6, &b->mcast_group.ip6, sizeof(struct pico_ip6));
tass 152:a3d286bf94e5 72 if(!tmp)
tass 152:a3d286bf94e5 73 return mcast_listen_link_cmp(a, b);
tass 152:a3d286bf94e5 74 return tmp;
tass picotcp@tass.be 149:5f4cb161cec3 75 }
tass 152:a3d286bf94e5 76 #endif
tass picotcp@tass.be 149:5f4cb161cec3 77
tass 152:a3d286bf94e5 78 static int mcast_listen_cmp(void *ka, void *kb)
tass 152:a3d286bf94e5 79 {
tass 152:a3d286bf94e5 80 struct pico_mcast_listen *a = ka, *b = kb;
tass 152:a3d286bf94e5 81 if (a->proto < b->proto)
tass 152:a3d286bf94e5 82 return -1;
tass 152:a3d286bf94e5 83
tass 152:a3d286bf94e5 84 if (a->proto > b->proto)
tass 152:a3d286bf94e5 85 return 1;
tass 152:a3d286bf94e5 86
tass 152:a3d286bf94e5 87 return mcast_listen_grp_cmp(a, b);
tass 152:a3d286bf94e5 88 }
tass 152:a3d286bf94e5 89 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 90 static int mcast_listen_cmp_ipv6(void *ka, void *kb)
tass 152:a3d286bf94e5 91 {
tass 152:a3d286bf94e5 92 struct pico_mcast_listen *a = ka, *b = kb;
tass 152:a3d286bf94e5 93 if (a->proto < b->proto)
tass 152:a3d286bf94e5 94 return -1;
tass 152:a3d286bf94e5 95
tass 152:a3d286bf94e5 96 if (a->proto > b->proto)
tass 152:a3d286bf94e5 97 return 1;
tass 152:a3d286bf94e5 98
tass 152:a3d286bf94e5 99 return mcast_listen_grp_cmp_ipv6(a, b);
tass 152:a3d286bf94e5 100 }
tass 152:a3d286bf94e5 101 #endif
tass picotcp@tass.be 149:5f4cb161cec3 102 static int mcast_sources_cmp(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 103 {
tass picotcp@tass.be 149:5f4cb161cec3 104 union pico_address *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 105 if (a->ip4.addr < b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 106 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 107
tass picotcp@tass.be 149:5f4cb161cec3 108 if (a->ip4.addr > b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 109 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 110
tass picotcp@tass.be 149:5f4cb161cec3 111 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 112 }
tass 152:a3d286bf94e5 113 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 114 static int mcast_sources_cmp_ipv6(void *ka, void *kb)
tass 152:a3d286bf94e5 115 {
tass 152:a3d286bf94e5 116 union pico_address *a = ka, *b = kb;
tass 152:a3d286bf94e5 117 return memcmp(&a->ip6, &b->ip6, sizeof(struct pico_ip6));
tass 152:a3d286bf94e5 118 }
tass 152:a3d286bf94e5 119 #endif
tass picotcp@tass.be 149:5f4cb161cec3 120 static int mcast_socket_cmp(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 121 {
tass picotcp@tass.be 149:5f4cb161cec3 122 struct pico_socket *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 123 if (a < b)
tass picotcp@tass.be 149:5f4cb161cec3 124 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 125
tass picotcp@tass.be 149:5f4cb161cec3 126 if (a > b)
tass picotcp@tass.be 149:5f4cb161cec3 127 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 128
tass picotcp@tass.be 149:5f4cb161cec3 129 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 130 }
tass picotcp@tass.be 149:5f4cb161cec3 131
tass picotcp@tass.be 149:5f4cb161cec3 132 /* gather all multicast sockets to hasten filter aggregation */
tass picotcp@tass.be 149:5f4cb161cec3 133 PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp);
tass picotcp@tass.be 149:5f4cb161cec3 134
tass picotcp@tass.be 149:5f4cb161cec3 135 static int mcast_filter_cmp(void *ka, void *kb)
tass picotcp@tass.be 149:5f4cb161cec3 136 {
tass picotcp@tass.be 149:5f4cb161cec3 137 union pico_address *a = ka, *b = kb;
tass picotcp@tass.be 149:5f4cb161cec3 138 if (a->ip4.addr < b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 139 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 140
tass picotcp@tass.be 149:5f4cb161cec3 141 if (a->ip4.addr > b->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 142 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 143
tass picotcp@tass.be 149:5f4cb161cec3 144 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 145 }
tass picotcp@tass.be 149:5f4cb161cec3 146 /* gather sources to be filtered */
tass picotcp@tass.be 149:5f4cb161cec3 147 PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp);
tass picotcp@tass.be 149:5f4cb161cec3 148
tass 152:a3d286bf94e5 149 static int mcast_filter_cmp_ipv6(void *ka, void *kb)
tass 152:a3d286bf94e5 150 {
tass 152:a3d286bf94e5 151 union pico_address *a = ka, *b = kb;
tass 152:a3d286bf94e5 152 return memcmp(&a->ip6, &b->ip6, sizeof(struct pico_ip6));
tass 152:a3d286bf94e5 153 }
tass 152:a3d286bf94e5 154 /* gather sources to be filtered */
tass 152:a3d286bf94e5 155 PICO_TREE_DECLARE(MCASTFilter_ipv6, mcast_filter_cmp_ipv6);
tass 152:a3d286bf94e5 156
tass 152:a3d286bf94e5 157 inline static struct pico_tree *mcast_get_src_tree(struct pico_socket *s,struct pico_mcast *mcast) {
tass 152:a3d286bf94e5 158 if( IS_SOCK_IPV4(s)) {
tass 152:a3d286bf94e5 159 mcast->listen->MCASTSources.compare = mcast_sources_cmp;
tass 152:a3d286bf94e5 160 return &mcast->listen->MCASTSources;
tass 152:a3d286bf94e5 161 }
tass 152:a3d286bf94e5 162 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 163 else if( IS_SOCK_IPV6(s) ) {
tass 152:a3d286bf94e5 164 mcast->listen->MCASTSources_ipv6.compare = mcast_sources_cmp_ipv6;
tass 152:a3d286bf94e5 165 return &mcast->listen->MCASTSources_ipv6;
tass 152:a3d286bf94e5 166 }
tass 152:a3d286bf94e5 167 #endif
tass 152:a3d286bf94e5 168 return NULL;
tass 152:a3d286bf94e5 169 }
tass 152:a3d286bf94e5 170 inline static struct pico_tree *mcast_get_listen_tree(struct pico_socket *s) {
tass 152:a3d286bf94e5 171 if( IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 172 return s->MCASTListen;
tass 152:a3d286bf94e5 173 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 174 else if( IS_SOCK_IPV6(s) )
tass 152:a3d286bf94e5 175 return s->MCASTListen_ipv6;
tass 152:a3d286bf94e5 176 #endif
tass 152:a3d286bf94e5 177 return NULL;
tass 152:a3d286bf94e5 178 }
tass 152:a3d286bf94e5 179 inline static void mcast_set_listen_tree_p_null(struct pico_socket *s) {
tass 152:a3d286bf94e5 180 if( IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 181 s->MCASTListen = NULL;
tass 152:a3d286bf94e5 182 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 183 else if( IS_SOCK_IPV6(s) )
tass 152:a3d286bf94e5 184 s->MCASTListen_ipv6 = NULL;
tass 152:a3d286bf94e5 185 #endif
tass 152:a3d286bf94e5 186 }
tass picotcp@tass.be 149:5f4cb161cec3 187 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 188 {
tass picotcp@tass.be 149:5f4cb161cec3 189 struct pico_mcast_listen ltest = {
tass picotcp@tass.be 149:5f4cb161cec3 190 0
tass picotcp@tass.be 149:5f4cb161cec3 191 };
tass 152:a3d286bf94e5 192 ltest.mcast_link = *lnk;
tass 152:a3d286bf94e5 193 ltest.mcast_group = *grp;
tass 152:a3d286bf94e5 194
tass 152:a3d286bf94e5 195 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 196 return pico_tree_findKey(s->MCASTListen, &ltest);
tass 152:a3d286bf94e5 197 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 198 else if(IS_SOCK_IPV6(s) ) {
tass 152:a3d286bf94e5 199 ltest.proto = PICO_PROTO_IPV6;
tass 152:a3d286bf94e5 200 return pico_tree_findKey(s->MCASTListen_ipv6, &ltest);
tass 152:a3d286bf94e5 201 }
tass 152:a3d286bf94e5 202 #endif
tass 152:a3d286bf94e5 203 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 204 }
tass 152:a3d286bf94e5 205 static union pico_address *pico_mcast_get_link_address(struct pico_socket *s, union pico_link *mcast_link) {
tass 152:a3d286bf94e5 206 if( IS_SOCK_IPV4(s) )
tass 152:a3d286bf94e5 207 return (union pico_address *) &mcast_link->ipv4.address;
tass 152:a3d286bf94e5 208 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 209 if( IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 210 return (union pico_address *) &mcast_link->ipv6.address;
tass 152:a3d286bf94e5 211 #endif
tass 152:a3d286bf94e5 212 return NULL;
tass 152:a3d286bf94e5 213 }
tass picotcp@tass.be 149:5f4cb161cec3 214 static uint8_t pico_mcast_filter_excl_excl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 215 {
tass picotcp@tass.be 149:5f4cb161cec3 216 /* filter = intersection of EXCLUDEs */
tass picotcp@tass.be 149:5f4cb161cec3 217 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 218 /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */
tass picotcp@tass.be 149:5f4cb161cec3 219 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 220 union pico_address *source = NULL;
tass 152:a3d286bf94e5 221 if(!pico_tree_empty(&MCASTFilter)) {
tass 152:a3d286bf94e5 222 pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
tass 152:a3d286bf94e5 223 {
tass 152:a3d286bf94e5 224 source = pico_tree_findKey(&listen->MCASTSources, index->keyValue);
tass 152:a3d286bf94e5 225 if (!source)
tass 152:a3d286bf94e5 226 pico_tree_delete(&MCASTFilter, index->keyValue);
tass 152:a3d286bf94e5 227 }
tass picotcp@tass.be 149:5f4cb161cec3 228 }
tass 152:a3d286bf94e5 229 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 230 if(!pico_tree_empty(&MCASTFilter_ipv6)) {
tass 152:a3d286bf94e5 231 pico_tree_foreach_safe(index, &MCASTFilter_ipv6, _tmp)
tass 152:a3d286bf94e5 232 {
tass 152:a3d286bf94e5 233 source = pico_tree_findKey(&listen->MCASTSources_ipv6, index->keyValue);
tass 152:a3d286bf94e5 234 if (!source)
tass 152:a3d286bf94e5 235 pico_tree_delete(&MCASTFilter_ipv6, index->keyValue);
tass 152:a3d286bf94e5 236 }
tass 152:a3d286bf94e5 237 }
tass 152:a3d286bf94e5 238 #endif
tass picotcp@tass.be 149:5f4cb161cec3 239 return PICO_IP_MULTICAST_EXCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 240 }
tass picotcp@tass.be 149:5f4cb161cec3 241
tass picotcp@tass.be 149:5f4cb161cec3 242 static uint8_t pico_mcast_filter_excl_incl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 243 {
tass picotcp@tass.be 149:5f4cb161cec3 244 /* filter = EXCLUDE - INCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 245 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 246 /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */
tass picotcp@tass.be 149:5f4cb161cec3 247 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 248 union pico_address *source = NULL;
tass 152:a3d286bf94e5 249 if(!pico_tree_empty(&listen->MCASTSources)) {
tass 152:a3d286bf94e5 250 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass 152:a3d286bf94e5 251 {
tass 152:a3d286bf94e5 252 source = pico_tree_findKey(&MCASTFilter, index->keyValue);
tass 152:a3d286bf94e5 253 if (source)
tass 152:a3d286bf94e5 254 pico_tree_delete(&MCASTFilter, source);
tass 152:a3d286bf94e5 255 }
tass picotcp@tass.be 149:5f4cb161cec3 256 }
tass 152:a3d286bf94e5 257 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 258 if(!pico_tree_empty(&listen->MCASTSources_ipv6)) {
tass 152:a3d286bf94e5 259 pico_tree_foreach_safe(index, &listen->MCASTSources_ipv6, _tmp)
tass 152:a3d286bf94e5 260 {
tass 152:a3d286bf94e5 261 source = pico_tree_findKey(&MCASTFilter_ipv6, index->keyValue);
tass 152:a3d286bf94e5 262 if (source)
tass 152:a3d286bf94e5 263 pico_tree_delete(&MCASTFilter_ipv6, source);
tass 152:a3d286bf94e5 264 }
tass 152:a3d286bf94e5 265 }
tass 152:a3d286bf94e5 266 #endif
tass picotcp@tass.be 149:5f4cb161cec3 267 return PICO_IP_MULTICAST_EXCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 268 }
tass picotcp@tass.be 149:5f4cb161cec3 269
tass picotcp@tass.be 149:5f4cb161cec3 270 static uint8_t pico_mcast_filter_incl_excl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 271 {
tass picotcp@tass.be 149:5f4cb161cec3 272 /* filter = EXCLUDE - INCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 273 /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */
tass 152:a3d286bf94e5 274 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 275 union pico_address *source = NULL;
tass 152:a3d286bf94e5 276 if(!pico_tree_empty(&listen->MCASTSources)) {
tass 152:a3d286bf94e5 277 pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
tass 152:a3d286bf94e5 278 {
tass 152:a3d286bf94e5 279 source = pico_tree_findKey(&listen->MCASTSources, index->keyValue);
tass 152:a3d286bf94e5 280 if (!source)
tass 152:a3d286bf94e5 281 pico_tree_delete(&MCASTFilter, index->keyValue);
tass 152:a3d286bf94e5 282 }
tass picotcp@tass.be 149:5f4cb161cec3 283 }
tass 152:a3d286bf94e5 284 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 285 if(!pico_tree_empty(&listen->MCASTSources_ipv6)) {
tass 152:a3d286bf94e5 286 pico_tree_foreach_safe(index, &MCASTFilter_ipv6, _tmp)
tass 152:a3d286bf94e5 287 {
tass 152:a3d286bf94e5 288 source = pico_tree_findKey(&listen->MCASTSources_ipv6, index->keyValue);
tass 152:a3d286bf94e5 289 if (!source)
tass 152:a3d286bf94e5 290 pico_tree_delete(&MCASTFilter_ipv6, index->keyValue);
tass 152:a3d286bf94e5 291 }
tass 152:a3d286bf94e5 292 }
tass 152:a3d286bf94e5 293 #endif
tass picotcp@tass.be 149:5f4cb161cec3 294 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass picotcp@tass.be 149:5f4cb161cec3 295
tass picotcp@tass.be 149:5f4cb161cec3 296 /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */
tass 152:a3d286bf94e5 297 if(!pico_tree_empty(&listen->MCASTSources)) {
tass 152:a3d286bf94e5 298 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass 152:a3d286bf94e5 299 {
tass 152:a3d286bf94e5 300 source = pico_tree_insert(&MCASTFilter, index->keyValue);
tass 152:a3d286bf94e5 301 if (source)
tass 152:a3d286bf94e5 302 pico_tree_delete(&MCASTFilter, source);
tass 152:a3d286bf94e5 303 }
tass picotcp@tass.be 149:5f4cb161cec3 304 }
tass 152:a3d286bf94e5 305 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 306 if(!pico_tree_empty(&listen->MCASTSources_ipv6)) {
tass 152:a3d286bf94e5 307 pico_tree_foreach_safe(index, &listen->MCASTSources_ipv6, _tmp)
tass 152:a3d286bf94e5 308 {
tass 152:a3d286bf94e5 309 source = pico_tree_insert(&MCASTFilter_ipv6, index->keyValue);
tass 152:a3d286bf94e5 310 if (source)
tass 152:a3d286bf94e5 311 pico_tree_delete(&MCASTFilter_ipv6, source);
tass 152:a3d286bf94e5 312 }
tass 152:a3d286bf94e5 313 }
tass 152:a3d286bf94e5 314 #endif
tass picotcp@tass.be 149:5f4cb161cec3 315 return PICO_IP_MULTICAST_EXCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 316 }
tass picotcp@tass.be 149:5f4cb161cec3 317
tass picotcp@tass.be 149:5f4cb161cec3 318 static uint8_t pico_mcast_filter_incl_incl(struct pico_mcast_listen *listen)
tass picotcp@tass.be 149:5f4cb161cec3 319 {
tass picotcp@tass.be 149:5f4cb161cec3 320 /* filter = summation of INCLUDEs */
tass picotcp@tass.be 149:5f4cb161cec3 321 /* mode stays INCLUDE, add all sources to filter */
tass picotcp@tass.be 149:5f4cb161cec3 322 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 323 union pico_address *source = NULL;
tass 152:a3d286bf94e5 324
tass 152:a3d286bf94e5 325 if( !pico_tree_empty(&listen->MCASTSources)) {
tass 152:a3d286bf94e5 326 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass 152:a3d286bf94e5 327 {
tass 152:a3d286bf94e5 328 source = index->keyValue;
tass 152:a3d286bf94e5 329 pico_tree_insert(&MCASTFilter, source);
tass 152:a3d286bf94e5 330 }
tass picotcp@tass.be 149:5f4cb161cec3 331 }
tass 152:a3d286bf94e5 332 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 333 if( !pico_tree_empty(&listen->MCASTSources_ipv6)) {
tass 152:a3d286bf94e5 334 pico_tree_foreach_safe(index, &listen->MCASTSources_ipv6, _tmp)
tass 152:a3d286bf94e5 335 {
tass 152:a3d286bf94e5 336 source = index->keyValue;
tass 152:a3d286bf94e5 337 pico_tree_insert(&MCASTFilter_ipv6, source);
tass 152:a3d286bf94e5 338 }
tass 152:a3d286bf94e5 339 }
tass 152:a3d286bf94e5 340 #endif
tass picotcp@tass.be 149:5f4cb161cec3 341 return PICO_IP_MULTICAST_INCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 342 }
tass picotcp@tass.be 149:5f4cb161cec3 343
tass picotcp@tass.be 149:5f4cb161cec3 344 struct pico_mcast_filter_aggregation
tass picotcp@tass.be 149:5f4cb161cec3 345 {
tass picotcp@tass.be 149:5f4cb161cec3 346 uint8_t (*call)(struct pico_mcast_listen *);
tass picotcp@tass.be 149:5f4cb161cec3 347 };
tass picotcp@tass.be 149:5f4cb161cec3 348
tass picotcp@tass.be 149:5f4cb161cec3 349 static const struct pico_mcast_filter_aggregation mcast_filter_aggr_call[2][2] =
tass picotcp@tass.be 149:5f4cb161cec3 350 {
tass picotcp@tass.be 149:5f4cb161cec3 351 {
tass 152:a3d286bf94e5 352 /* EXCL + EXCL */ {.call = pico_mcast_filter_excl_excl},
tass 152:a3d286bf94e5 353 /* EXCL + INCL */ {.call = pico_mcast_filter_excl_incl}
tass picotcp@tass.be 149:5f4cb161cec3 354 },
tass picotcp@tass.be 149:5f4cb161cec3 355
tass picotcp@tass.be 149:5f4cb161cec3 356 {
tass 152:a3d286bf94e5 357 /* INCL + EXCL */ {.call = pico_mcast_filter_incl_excl},
tass 152:a3d286bf94e5 358 /* INCL + INCL */ {.call = pico_mcast_filter_incl_incl}
tass picotcp@tass.be 149:5f4cb161cec3 359 }
tass picotcp@tass.be 149:5f4cb161cec3 360 };
tass picotcp@tass.be 149:5f4cb161cec3 361
tass picotcp@tass.be 149:5f4cb161cec3 362 static int mcast_aggr_validate(uint8_t fm, struct pico_mcast_listen *l)
tass picotcp@tass.be 149:5f4cb161cec3 363 {
tass picotcp@tass.be 149:5f4cb161cec3 364 if (!l)
tass picotcp@tass.be 149:5f4cb161cec3 365 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 366
tass picotcp@tass.be 149:5f4cb161cec3 367 if (fm > 1)
tass picotcp@tass.be 149:5f4cb161cec3 368 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 369
tass picotcp@tass.be 149:5f4cb161cec3 370 if (l->filter_mode > 1)
tass picotcp@tass.be 149:5f4cb161cec3 371 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 372
tass picotcp@tass.be 149:5f4cb161cec3 373 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 374 }
tass picotcp@tass.be 149:5f4cb161cec3 375
tass picotcp@tass.be 149:5f4cb161cec3 376
tass picotcp@tass.be 149:5f4cb161cec3 377 /* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */
tass picotcp@tass.be 149:5f4cb161cec3 378 static int pico_socket_aggregate_mcastfilters(union pico_address *mcast_link, union pico_address *mcast_group)
tass picotcp@tass.be 149:5f4cb161cec3 379 {
tass picotcp@tass.be 149:5f4cb161cec3 380 uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE;
tass picotcp@tass.be 149:5f4cb161cec3 381 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 382 struct pico_socket *mcast_sock = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 383 struct pico_tree_node *index = NULL, *_tmp = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 384
tass picotcp@tass.be 149:5f4cb161cec3 385 /* cleanup old filter */
tass 152:a3d286bf94e5 386 if(!pico_tree_empty(&MCASTFilter)) {
tass 152:a3d286bf94e5 387 pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
tass 152:a3d286bf94e5 388 {
tass 152:a3d286bf94e5 389 pico_tree_delete(&MCASTFilter, index->keyValue);
tass 152:a3d286bf94e5 390 }
tass picotcp@tass.be 149:5f4cb161cec3 391 }
tass 152:a3d286bf94e5 392 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 393 if(!pico_tree_empty(&MCASTFilter_ipv6)) {
tass 152:a3d286bf94e5 394 pico_tree_foreach_safe(index, &MCASTFilter_ipv6, _tmp)
tass 152:a3d286bf94e5 395 {
tass 152:a3d286bf94e5 396 pico_tree_delete(&MCASTFilter_ipv6, index->keyValue);
tass 152:a3d286bf94e5 397 }
tass 152:a3d286bf94e5 398 }
tass 152:a3d286bf94e5 399 #endif
tass picotcp@tass.be 149:5f4cb161cec3 400 /* construct new filter */
tass picotcp@tass.be 149:5f4cb161cec3 401 pico_tree_foreach_safe(index, &MCASTSockets, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 402 {
tass picotcp@tass.be 149:5f4cb161cec3 403 mcast_sock = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 404 listen = listen_find(mcast_sock, mcast_link, mcast_group);
tass picotcp@tass.be 149:5f4cb161cec3 405 if (listen) {
tass picotcp@tass.be 149:5f4cb161cec3 406 if (mcast_aggr_validate(filter_mode, listen) < 0) {
tass picotcp@tass.be 149:5f4cb161cec3 407 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 408 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 409 }
tass picotcp@tass.be 149:5f4cb161cec3 410 if (mcast_filter_aggr_call[filter_mode][listen->filter_mode].call) {
tass picotcp@tass.be 149:5f4cb161cec3 411 filter_mode = mcast_filter_aggr_call[filter_mode][listen->filter_mode].call(listen);
tass picotcp@tass.be 149:5f4cb161cec3 412 if (filter_mode > 1)
tass picotcp@tass.be 149:5f4cb161cec3 413 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 414 }
tass 152:a3d286bf94e5 415 }
tass picotcp@tass.be 149:5f4cb161cec3 416 }
tass picotcp@tass.be 149:5f4cb161cec3 417 return filter_mode;
tass picotcp@tass.be 149:5f4cb161cec3 418 }
tass picotcp@tass.be 149:5f4cb161cec3 419
tass picotcp@tass.be 149:5f4cb161cec3 420 static int pico_socket_mcast_filter_include(struct pico_mcast_listen *listen, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 421 {
tass picotcp@tass.be 149:5f4cb161cec3 422 struct pico_tree_node *index = NULL;
tass 152:a3d286bf94e5 423 #ifdef PICO_DEBUG_MCAST
tass 152:a3d286bf94e5 424 char tmp_string[PICO_IPV6_STRING];
tass 152:a3d286bf94e5 425 #endif
tass 152:a3d286bf94e5 426 if(!pico_tree_empty(&listen->MCASTSources)) {
tass 152:a3d286bf94e5 427 pico_tree_foreach(index, &listen->MCASTSources)
tass 152:a3d286bf94e5 428 {
tass 152:a3d286bf94e5 429 if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) {
tass 152:a3d286bf94e5 430 so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->ip4.addr);
tass 152:a3d286bf94e5 431 return 0;
tass 152:a3d286bf94e5 432 }
tass picotcp@tass.be 149:5f4cb161cec3 433 }
tass picotcp@tass.be 149:5f4cb161cec3 434 }
tass 152:a3d286bf94e5 435 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 436 if(!pico_tree_empty(&listen->MCASTSources_ipv6)) {
tass 152:a3d286bf94e5 437 pico_tree_foreach(index, &listen->MCASTSources_ipv6)
tass 152:a3d286bf94e5 438 {
tass 152:a3d286bf94e5 439 if (memcmp(&src->ip6 , &((union pico_address *)index->keyValue)->ip6, sizeof(struct pico_ip6))) {
tass 152:a3d286bf94e5 440 #ifdef PICO_DEBUG_MCAST
tass 152:a3d286bf94e5 441 pico_ipv6_to_string(tmp_string, src->ip6.addr);
tass 152:a3d286bf94e5 442 so_mcast_dbg("MCAST: IP %s in included socket source list\n", tmp_string);
tass 152:a3d286bf94e5 443 #endif
tass 152:a3d286bf94e5 444 return 0;
tass 152:a3d286bf94e5 445 }
tass 152:a3d286bf94e5 446 }
tass 152:a3d286bf94e5 447 }
tass 152:a3d286bf94e5 448 #endif
tass 152:a3d286bf94e5 449 /* XXX IPV6 ADDRESS */
tass picotcp@tass.be 149:5f4cb161cec3 450 so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->ip4.addr);
tass picotcp@tass.be 149:5f4cb161cec3 451 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 452
tass picotcp@tass.be 149:5f4cb161cec3 453 }
tass picotcp@tass.be 149:5f4cb161cec3 454
tass picotcp@tass.be 149:5f4cb161cec3 455 static int pico_socket_mcast_filter_exclude(struct pico_mcast_listen *listen, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 456 {
tass picotcp@tass.be 149:5f4cb161cec3 457 struct pico_tree_node *index = NULL;
tass 152:a3d286bf94e5 458 #ifdef PICO_DEBUG_MCAST
tass 152:a3d286bf94e5 459 char tmp_string[PICO_IPV6_STRING];
tass 152:a3d286bf94e5 460 #endif
tass 152:a3d286bf94e5 461 if(!pico_tree_empty(&listen->MCASTSources)) {
tass 152:a3d286bf94e5 462 pico_tree_foreach(index, &listen->MCASTSources)
tass 152:a3d286bf94e5 463 {
tass 152:a3d286bf94e5 464 if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) {
tass 152:a3d286bf94e5 465 so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->ip4.addr);
tass 152:a3d286bf94e5 466 return -1;
tass 152:a3d286bf94e5 467 }
tass picotcp@tass.be 149:5f4cb161cec3 468 }
tass picotcp@tass.be 149:5f4cb161cec3 469 }
tass 152:a3d286bf94e5 470 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 471 if(!pico_tree_empty(&listen->MCASTSources_ipv6)) {
tass 152:a3d286bf94e5 472 pico_tree_foreach(index, &listen->MCASTSources_ipv6)
tass 152:a3d286bf94e5 473 {
tass 152:a3d286bf94e5 474 if (memcmp(&src->ip6 , &((union pico_address *)index->keyValue)->ip6, sizeof(struct pico_ip6))) {
tass 152:a3d286bf94e5 475 #ifdef PICO_DEBUG_MCAST
tass 152:a3d286bf94e5 476 pico_ipv6_to_string(tmp_string, src->ip6.addr);
tass 152:a3d286bf94e5 477 so_mcast_dbg("MCAST: IP %s in excluded socket source list\n", tmp_string);
tass 152:a3d286bf94e5 478 #endif
tass 152:a3d286bf94e5 479 return 0;
tass 152:a3d286bf94e5 480 }
tass 152:a3d286bf94e5 481 }
tass 152:a3d286bf94e5 482 }
tass 152:a3d286bf94e5 483 #endif
tass 152:a3d286bf94e5 484 /* XXX IPV6 ADDRESS */
tass picotcp@tass.be 149:5f4cb161cec3 485 so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->ip4.addr);
tass picotcp@tass.be 149:5f4cb161cec3 486 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 487 }
tass picotcp@tass.be 149:5f4cb161cec3 488
tass picotcp@tass.be 149:5f4cb161cec3 489 static int pico_socket_mcast_source_filtering(struct pico_mcast_listen *listen, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 490 {
tass picotcp@tass.be 149:5f4cb161cec3 491 /* perform source filtering */
tass picotcp@tass.be 149:5f4cb161cec3 492 if (listen->filter_mode == PICO_IP_MULTICAST_INCLUDE)
tass picotcp@tass.be 149:5f4cb161cec3 493 return pico_socket_mcast_filter_include(listen, src);
tass picotcp@tass.be 149:5f4cb161cec3 494
tass picotcp@tass.be 149:5f4cb161cec3 495 if (listen->filter_mode == PICO_IP_MULTICAST_EXCLUDE)
tass picotcp@tass.be 149:5f4cb161cec3 496 return pico_socket_mcast_filter_exclude(listen, src);
tass picotcp@tass.be 149:5f4cb161cec3 497
tass picotcp@tass.be 149:5f4cb161cec3 498 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 499 }
tass picotcp@tass.be 149:5f4cb161cec3 500
tass 152:a3d286bf94e5 501 static void *pico_socket_mcast_filter_link_get(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 502 {
tass picotcp@tass.be 149:5f4cb161cec3 503 /* check if no multicast enabled on socket */
tass picotcp@tass.be 149:5f4cb161cec3 504 if (!s->MCASTListen)
tass picotcp@tass.be 149:5f4cb161cec3 505 return NULL;
tass 152:a3d286bf94e5 506 if( IS_SOCK_IPV4(s) ) {
tass 152:a3d286bf94e5 507 if (!s->local_addr.ip4.addr)
tass 152:a3d286bf94e5 508 return pico_ipv4_get_default_mcastlink();
tass picotcp@tass.be 149:5f4cb161cec3 509
tass 152:a3d286bf94e5 510 return pico_ipv4_link_get(&s->local_addr.ip4);
tass 152:a3d286bf94e5 511 }
tass 152:a3d286bf94e5 512 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 513 else if( IS_SOCK_IPV6(s)) {
tass 152:a3d286bf94e5 514 if (pico_ipv6_is_null_address(&s->local_addr.ip6))
tass 152:a3d286bf94e5 515 return pico_ipv6_get_default_mcastlink();
tass 152:a3d286bf94e5 516
tass 152:a3d286bf94e5 517 return pico_ipv6_link_get(&s->local_addr.ip6);
tass 152:a3d286bf94e5 518 }
tass 152:a3d286bf94e5 519 #endif
tass 152:a3d286bf94e5 520 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 521 }
tass picotcp@tass.be 149:5f4cb161cec3 522
tass picotcp@tass.be 149:5f4cb161cec3 523 int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 524 {
tass 152:a3d286bf94e5 525 void *mcast_link = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 526 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 527 mcast_link = pico_socket_mcast_filter_link_get(s);
tass picotcp@tass.be 149:5f4cb161cec3 528 if (!mcast_link)
tass picotcp@tass.be 149:5f4cb161cec3 529 return -1;
tass 152:a3d286bf94e5 530 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 531 listen = listen_find(s,(union pico_address *) &((struct pico_ipv4_link*)(mcast_link))->address, mcast_group);
tass 152:a3d286bf94e5 532 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 533 else if(IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 534 listen = listen_find(s, (union pico_address *)&((struct pico_ipv6_link*)(mcast_link))->address, mcast_group);
tass 152:a3d286bf94e5 535 #endif
tass picotcp@tass.be 149:5f4cb161cec3 536 if (!listen)
tass picotcp@tass.be 149:5f4cb161cec3 537 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 538
tass picotcp@tass.be 149:5f4cb161cec3 539 return pico_socket_mcast_source_filtering(listen, src);
tass picotcp@tass.be 149:5f4cb161cec3 540 }
tass picotcp@tass.be 149:5f4cb161cec3 541
tass 152:a3d286bf94e5 542
tass 152:a3d286bf94e5 543 static struct pico_ipv4_link *get_mcast_link(union pico_address *a) {
tass picotcp@tass.be 149:5f4cb161cec3 544 if (!a->ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 545 return pico_ipv4_get_default_mcastlink();
tass picotcp@tass.be 149:5f4cb161cec3 546 return pico_ipv4_link_get(&a->ip4);
tass picotcp@tass.be 149:5f4cb161cec3 547 }
tass 152:a3d286bf94e5 548 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 549 static struct pico_ipv6_link *get_mcast_link_ipv6(union pico_address *a) {
tass picotcp@tass.be 149:5f4cb161cec3 550
tass 152:a3d286bf94e5 551 if (pico_ipv6_is_null_address(&a->ip6)) {
tass 152:a3d286bf94e5 552 return pico_ipv6_get_default_mcastlink();
tass 152:a3d286bf94e5 553 }
tass 152:a3d286bf94e5 554 return pico_ipv6_link_get(&a->ip6);
tass 152:a3d286bf94e5 555 }
tass 152:a3d286bf94e5 556 #endif
tass 152:a3d286bf94e5 557
tass 154:6c0e92a80c4a 558 static int pico_socket_setoption_pre_validation(struct pico_ip_mreq *mreq)
tass 152:a3d286bf94e5 559 {
tass 152:a3d286bf94e5 560 if (!mreq)
tass picotcp@tass.be 149:5f4cb161cec3 561 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 562
tass 152:a3d286bf94e5 563 if (!mreq->mcast_group_addr.ip4.addr)
tass picotcp@tass.be 149:5f4cb161cec3 564 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 565
tass picotcp@tass.be 149:5f4cb161cec3 566 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 567 }
tass 152:a3d286bf94e5 568 #ifdef PICO_SUPPORT_IPV6
tass 154:6c0e92a80c4a 569 static int pico_socket_setoption_pre_validation_ipv6(struct pico_ip_mreq *mreq)
tass picotcp@tass.be 149:5f4cb161cec3 570 {
tass picotcp@tass.be 149:5f4cb161cec3 571 if (!mreq)
tass picotcp@tass.be 149:5f4cb161cec3 572 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 573
tass 152:a3d286bf94e5 574 if (pico_ipv6_is_null_address((struct pico_ip6*)&mreq->mcast_group_addr))
tass picotcp@tass.be 149:5f4cb161cec3 575 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 576
tass picotcp@tass.be 149:5f4cb161cec3 577 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 578 }
tass 152:a3d286bf94e5 579 #endif
tass picotcp@tass.be 149:5f4cb161cec3 580
tass 154:6c0e92a80c4a 581 static struct pico_ipv4_link *pico_socket_setoption_validate_mreq(struct pico_ip_mreq *mreq)
tass picotcp@tass.be 149:5f4cb161cec3 582 {
tass 152:a3d286bf94e5 583 if (pico_socket_setoption_pre_validation(mreq) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 584 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 585
tass 152:a3d286bf94e5 586 if (pico_ipv4_is_unicast(mreq->mcast_group_addr.ip4.addr))
tass picotcp@tass.be 149:5f4cb161cec3 587 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 588
tass picotcp@tass.be 149:5f4cb161cec3 589 return get_mcast_link((union pico_address *)&mreq->mcast_link_addr);
tass picotcp@tass.be 149:5f4cb161cec3 590 }
tass picotcp@tass.be 149:5f4cb161cec3 591
tass 152:a3d286bf94e5 592 #ifdef PICO_SUPPORT_IPV6
tass 154:6c0e92a80c4a 593 static struct pico_ipv6_link *pico_socket_setoption_validate_mreq_ipv6(struct pico_ip_mreq *mreq)
tass 152:a3d286bf94e5 594 {
tass 152:a3d286bf94e5 595 if (pico_socket_setoption_pre_validation_ipv6(mreq) < 0)
tass 152:a3d286bf94e5 596 return NULL;
tass 152:a3d286bf94e5 597
tass 152:a3d286bf94e5 598 if (pico_ipv6_is_unicast((struct pico_ip6 *)&mreq->mcast_group_addr))
tass 152:a3d286bf94e5 599 return NULL;
tass 152:a3d286bf94e5 600 return get_mcast_link_ipv6((union pico_address *)&mreq->mcast_link_addr);
tass 152:a3d286bf94e5 601 }
tass 152:a3d286bf94e5 602 #endif
tass 152:a3d286bf94e5 603
tass 154:6c0e92a80c4a 604 static int pico_socket_setoption_pre_validation_s(struct pico_ip_mreq_source *mreq)
tass 152:a3d286bf94e5 605 {
tass 152:a3d286bf94e5 606 if (!mreq)
tass 152:a3d286bf94e5 607 return -1;
tass 152:a3d286bf94e5 608
tass 152:a3d286bf94e5 609 if (!mreq->mcast_group_addr.ip4.addr)
tass 152:a3d286bf94e5 610 return -1;
tass 152:a3d286bf94e5 611
tass 152:a3d286bf94e5 612 return 0;
tass 152:a3d286bf94e5 613 }
tass 152:a3d286bf94e5 614 #ifdef PICO_SUPPORT_IPV6
tass 154:6c0e92a80c4a 615 static int pico_socket_setoption_pre_validation_s_ipv6(struct pico_ip_mreq_source *mreq)
tass 152:a3d286bf94e5 616 {
tass 152:a3d286bf94e5 617 if (!mreq)
tass 152:a3d286bf94e5 618 return -1;
tass 152:a3d286bf94e5 619
tass 152:a3d286bf94e5 620 if (pico_ipv6_is_null_address((struct pico_ip6 *)&mreq->mcast_group_addr))
tass 152:a3d286bf94e5 621 return -1;
tass 152:a3d286bf94e5 622
tass 152:a3d286bf94e5 623 return 0;
tass 152:a3d286bf94e5 624 }
tass 152:a3d286bf94e5 625 #endif
tass 152:a3d286bf94e5 626
tass 154:6c0e92a80c4a 627 static struct pico_ipv4_link *pico_socket_setoption_validate_s_mreq(struct pico_ip_mreq_source *mreq)
tass 152:a3d286bf94e5 628 {
tass 152:a3d286bf94e5 629 if (pico_socket_setoption_pre_validation_s(mreq) < 0)
tass 152:a3d286bf94e5 630 return NULL;
tass 152:a3d286bf94e5 631
tass 152:a3d286bf94e5 632 if (pico_ipv4_is_unicast(mreq->mcast_group_addr.ip4.addr))
tass 152:a3d286bf94e5 633 return NULL;
tass 152:a3d286bf94e5 634
tass 152:a3d286bf94e5 635 if (!pico_ipv4_is_unicast(mreq->mcast_source_addr.ip4.addr))
tass 152:a3d286bf94e5 636 return NULL;
tass 152:a3d286bf94e5 637
tass 152:a3d286bf94e5 638 return get_mcast_link((union pico_address *)&mreq->mcast_link_addr);
tass 152:a3d286bf94e5 639 }
tass 152:a3d286bf94e5 640 #ifdef PICO_SUPPORT_IPV6
tass 154:6c0e92a80c4a 641 static struct pico_ipv6_link *pico_socket_setoption_validate_s_mreq_ipv6(struct pico_ip_mreq_source *mreq)
tass 152:a3d286bf94e5 642 {
tass 152:a3d286bf94e5 643 if (pico_socket_setoption_pre_validation_s_ipv6(mreq) < 0) {
tass 152:a3d286bf94e5 644 return NULL;
tass 152:a3d286bf94e5 645 }
tass 152:a3d286bf94e5 646 if (pico_ipv6_is_unicast((struct pico_ip6 *)&mreq->mcast_group_addr)){
tass 152:a3d286bf94e5 647 return NULL;
tass 152:a3d286bf94e5 648 }
tass 152:a3d286bf94e5 649 if (!pico_ipv6_is_unicast((struct pico_ip6 *)&mreq->mcast_source_addr)){
tass 152:a3d286bf94e5 650 return NULL;
tass 152:a3d286bf94e5 651 }
tass 152:a3d286bf94e5 652
tass 152:a3d286bf94e5 653 return get_mcast_link_ipv6(&mreq->mcast_link_addr);
tass 152:a3d286bf94e5 654 }
tass 152:a3d286bf94e5 655 #endif
tass picotcp@tass.be 149:5f4cb161cec3 656
tass picotcp@tass.be 149:5f4cb161cec3 657 static struct pico_ipv4_link *setop_multicast_link_search(void *value, int bysource)
tass picotcp@tass.be 149:5f4cb161cec3 658 {
tass picotcp@tass.be 149:5f4cb161cec3 659
tass 154:6c0e92a80c4a 660 struct pico_ip_mreq *mreq = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 661 struct pico_ipv4_link *mcast_link = NULL;
tass 154:6c0e92a80c4a 662 struct pico_ip_mreq_source *mreq_src = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 663 if (!bysource) {
tass 154:6c0e92a80c4a 664 mreq = (struct pico_ip_mreq *)value;
tass picotcp@tass.be 149:5f4cb161cec3 665 mcast_link = pico_socket_setoption_validate_mreq(mreq);
tass 152:a3d286bf94e5 666 if (!mcast_link)
tass 152:a3d286bf94e5 667 return NULL;
tass 152:a3d286bf94e5 668 if (!mreq->mcast_link_addr.ip4.addr)
tass 152:a3d286bf94e5 669 mreq->mcast_link_addr.ip4.addr = mcast_link->address.addr;
tass picotcp@tass.be 149:5f4cb161cec3 670 } else {
tass 154:6c0e92a80c4a 671 mreq_src = (struct pico_ip_mreq_source *)value;
tass 152:a3d286bf94e5 672 if (!mreq_src) {
tass 152:a3d286bf94e5 673 return NULL;
tass 152:a3d286bf94e5 674 }
tass picotcp@tass.be 149:5f4cb161cec3 675
tass picotcp@tass.be 149:5f4cb161cec3 676 mcast_link = pico_socket_setoption_validate_s_mreq(mreq_src);
tass 152:a3d286bf94e5 677 if (!mcast_link) {
tass picotcp@tass.be 149:5f4cb161cec3 678 return NULL;
tass 152:a3d286bf94e5 679 }
tass picotcp@tass.be 149:5f4cb161cec3 680
tass 152:a3d286bf94e5 681 if (!mreq_src->mcast_link_addr.ip4.addr)
tass 152:a3d286bf94e5 682 mreq_src->mcast_link_addr.ip4 = mcast_link->address;
tass picotcp@tass.be 149:5f4cb161cec3 683 }
tass picotcp@tass.be 149:5f4cb161cec3 684
tass picotcp@tass.be 149:5f4cb161cec3 685 return mcast_link;
tass picotcp@tass.be 149:5f4cb161cec3 686 }
tass 152:a3d286bf94e5 687 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 688 static struct pico_ipv6_link *setop_multicast_link_search_ipv6(void *value, int bysource)
tass 152:a3d286bf94e5 689 {
tass 154:6c0e92a80c4a 690 struct pico_ip_mreq *mreq = NULL;
tass 152:a3d286bf94e5 691 struct pico_ipv6_link *mcast_link = NULL;
tass 154:6c0e92a80c4a 692 struct pico_ip_mreq_source *mreq_src = NULL;
tass 152:a3d286bf94e5 693 if (!bysource) {
tass 154:6c0e92a80c4a 694 mreq = (struct pico_ip_mreq *)value;
tass 152:a3d286bf94e5 695 mcast_link = pico_socket_setoption_validate_mreq_ipv6(mreq);
tass 152:a3d286bf94e5 696 if (!mcast_link) {
tass 152:a3d286bf94e5 697 return NULL;
tass 152:a3d286bf94e5 698 }
tass 152:a3d286bf94e5 699 if (pico_ipv6_is_null_address(&mreq->mcast_link_addr.ip6))
tass 152:a3d286bf94e5 700 mreq->mcast_link_addr.ip6 = mcast_link->address;
tass 152:a3d286bf94e5 701 } else {
tass 154:6c0e92a80c4a 702 mreq_src = (struct pico_ip_mreq_source *)value;
tass 152:a3d286bf94e5 703 if (!mreq_src) {
tass 152:a3d286bf94e5 704 return NULL;
tass 152:a3d286bf94e5 705 }
tass picotcp@tass.be 149:5f4cb161cec3 706
tass 152:a3d286bf94e5 707 mcast_link = pico_socket_setoption_validate_s_mreq_ipv6(mreq_src);
tass 152:a3d286bf94e5 708 if (!mcast_link) {
tass 152:a3d286bf94e5 709 return NULL;
tass 152:a3d286bf94e5 710 }
tass 152:a3d286bf94e5 711 if (pico_ipv6_is_null_address(&mreq_src->mcast_link_addr.ip6))
tass 152:a3d286bf94e5 712 mreq_src->mcast_link_addr.ip6 = mcast_link->address;
tass 152:a3d286bf94e5 713 }
tass 152:a3d286bf94e5 714 return mcast_link;
tass 152:a3d286bf94e5 715 }
tass 152:a3d286bf94e5 716 #endif
tass picotcp@tass.be 149:5f4cb161cec3 717 static int setop_verify_listen_tree(struct pico_socket *s, int alloc)
tass picotcp@tass.be 149:5f4cb161cec3 718 {
tass picotcp@tass.be 149:5f4cb161cec3 719 if(!alloc)
tass picotcp@tass.be 149:5f4cb161cec3 720 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 721
tass 152:a3d286bf94e5 722 if( IS_SOCK_IPV4(s) ) {
tass 152:a3d286bf94e5 723
tass 152:a3d286bf94e5 724 s->MCASTListen = PICO_ZALLOC(sizeof(struct pico_tree));
tass 152:a3d286bf94e5 725 if (!s->MCASTListen) {
tass 152:a3d286bf94e5 726 pico_err = PICO_ERR_ENOMEM;
tass 152:a3d286bf94e5 727 return -1;
tass 152:a3d286bf94e5 728 }
tass 152:a3d286bf94e5 729
tass 152:a3d286bf94e5 730 s->MCASTListen->root = &LEAF;
tass 152:a3d286bf94e5 731 s->MCASTListen->compare = mcast_listen_cmp;
tass 152:a3d286bf94e5 732 return 0;
tass 152:a3d286bf94e5 733 }
tass 152:a3d286bf94e5 734 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 735 else if( IS_SOCK_IPV6(s)){
tass 152:a3d286bf94e5 736 s->MCASTListen_ipv6 = PICO_ZALLOC(sizeof(struct pico_tree));
tass 152:a3d286bf94e5 737 if (!s->MCASTListen_ipv6) {
tass 152:a3d286bf94e5 738 pico_err = PICO_ERR_ENOMEM;
tass 152:a3d286bf94e5 739 return -1;
tass 152:a3d286bf94e5 740 }
tass 152:a3d286bf94e5 741
tass 152:a3d286bf94e5 742 s->MCASTListen_ipv6->root = &LEAF;
tass 152:a3d286bf94e5 743 s->MCASTListen_ipv6->compare = mcast_listen_cmp_ipv6;
tass 152:a3d286bf94e5 744 return 0;
tass 152:a3d286bf94e5 745
tass picotcp@tass.be 149:5f4cb161cec3 746 }
tass 152:a3d286bf94e5 747 #endif
tass 152:a3d286bf94e5 748 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 749 }
tass picotcp@tass.be 149:5f4cb161cec3 750
tass picotcp@tass.be 149:5f4cb161cec3 751
tass 152:a3d286bf94e5 752 static void *setopt_multicast_check(struct pico_socket *s, void *value, int alloc, int bysource)
tass picotcp@tass.be 149:5f4cb161cec3 753 {
tass 152:a3d286bf94e5 754 void *mcast_link = NULL;
tass 152:a3d286bf94e5 755 struct pico_tree *listen_tree = mcast_get_listen_tree(s);
tass picotcp@tass.be 149:5f4cb161cec3 756 if (!value) {
tass picotcp@tass.be 149:5f4cb161cec3 757 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 758 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 759 }
tass 152:a3d286bf94e5 760 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 761 mcast_link = setop_multicast_link_search(value, bysource);
tass 152:a3d286bf94e5 762 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 763 else if(IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 764 mcast_link = setop_multicast_link_search_ipv6(value, bysource);
tass 152:a3d286bf94e5 765 #endif
tass picotcp@tass.be 149:5f4cb161cec3 766 if (!mcast_link) {
tass picotcp@tass.be 149:5f4cb161cec3 767 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 768 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 769 }
tass 152:a3d286bf94e5 770 if (!listen_tree) { /* No RBTree allocated yet */
tass 152:a3d286bf94e5 771 if (setop_verify_listen_tree(s, alloc) < 0) {
tass picotcp@tass.be 149:5f4cb161cec3 772 return NULL;
tass 152:a3d286bf94e5 773 }
tass picotcp@tass.be 149:5f4cb161cec3 774 }
tass picotcp@tass.be 149:5f4cb161cec3 775 return mcast_link;
tass picotcp@tass.be 149:5f4cb161cec3 776 }
tass picotcp@tass.be 149:5f4cb161cec3 777
tass picotcp@tass.be 149:5f4cb161cec3 778 void pico_multicast_delete(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 779 {
tass picotcp@tass.be 149:5f4cb161cec3 780 int filter_mode;
tass picotcp@tass.be 149:5f4cb161cec3 781 struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 782 struct pico_mcast_listen *listen = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 783 union pico_address *source = NULL;
tass 152:a3d286bf94e5 784 struct pico_tree *tree, *listen_tree;
tass 152:a3d286bf94e5 785 struct pico_mcast mcast;
tass 152:a3d286bf94e5 786 listen_tree = mcast_get_listen_tree(s);
tass 152:a3d286bf94e5 787 if(listen_tree) {
tass picotcp@tass.be 149:5f4cb161cec3 788 pico_tree_delete(&MCASTSockets, s);
tass 152:a3d286bf94e5 789 pico_tree_foreach_safe(index, listen_tree, _tmp)
tass picotcp@tass.be 149:5f4cb161cec3 790 {
tass picotcp@tass.be 149:5f4cb161cec3 791 listen = index->keyValue;
tass 152:a3d286bf94e5 792 mcast.listen = listen;
tass 152:a3d286bf94e5 793 tree = mcast_get_src_tree(s, &mcast);
tass 152:a3d286bf94e5 794 pico_tree_foreach_safe(index2, tree, _tmp2)
tass picotcp@tass.be 149:5f4cb161cec3 795 {
tass picotcp@tass.be 149:5f4cb161cec3 796 source = index->keyValue;
tass 152:a3d286bf94e5 797 pico_tree_delete(tree, source);
tass picotcp@tass.be 149:5f4cb161cec3 798 PICO_FREE(source);
tass picotcp@tass.be 149:5f4cb161cec3 799 }
tass picotcp@tass.be 149:5f4cb161cec3 800 filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&listen->mcast_link, (union pico_address *)&listen->mcast_group);
tass 152:a3d286bf94e5 801 if (filter_mode >= 0) {
tass 152:a3d286bf94e5 802 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 803 pico_ipv4_mcast_leave(&listen->mcast_link.ip4, &listen->mcast_group.ip4, 1, (uint8_t)filter_mode, &MCASTFilter);
tass 152:a3d286bf94e5 804 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 805 else if(IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 806 pico_ipv6_mcast_leave(&listen->mcast_link.ip6, &listen->mcast_group.ip6, 1, (uint8_t)filter_mode, &MCASTFilter_ipv6);
tass 152:a3d286bf94e5 807 #endif
tass 152:a3d286bf94e5 808 }
tass 152:a3d286bf94e5 809 pico_tree_delete(listen_tree, listen);
tass picotcp@tass.be 149:5f4cb161cec3 810 PICO_FREE(listen);
tass picotcp@tass.be 149:5f4cb161cec3 811 }
tass 152:a3d286bf94e5 812 PICO_FREE(listen_tree);
tass 152:a3d286bf94e5 813 mcast_set_listen_tree_p_null(s);
tass picotcp@tass.be 149:5f4cb161cec3 814 }
tass picotcp@tass.be 149:5f4cb161cec3 815 }
tass picotcp@tass.be 149:5f4cb161cec3 816
tass picotcp@tass.be 149:5f4cb161cec3 817
tass picotcp@tass.be 149:5f4cb161cec3 818 int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 819 {
tass picotcp@tass.be 149:5f4cb161cec3 820 switch(option) {
tass picotcp@tass.be 149:5f4cb161cec3 821 case PICO_IP_MULTICAST_IF:
tass picotcp@tass.be 149:5f4cb161cec3 822 pico_err = PICO_ERR_EOPNOTSUPP;
tass picotcp@tass.be 149:5f4cb161cec3 823 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 824
tass picotcp@tass.be 149:5f4cb161cec3 825 case PICO_IP_MULTICAST_TTL:
tass picotcp@tass.be 149:5f4cb161cec3 826 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass picotcp@tass.be 149:5f4cb161cec3 827 pico_udp_get_mc_ttl(s, (uint8_t *) value);
tass picotcp@tass.be 149:5f4cb161cec3 828 } else {
tass picotcp@tass.be 149:5f4cb161cec3 829 *(uint8_t *)value = 0;
tass picotcp@tass.be 149:5f4cb161cec3 830 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 831 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 832 }
tass picotcp@tass.be 149:5f4cb161cec3 833
tass picotcp@tass.be 149:5f4cb161cec3 834 break;
tass picotcp@tass.be 149:5f4cb161cec3 835
tass picotcp@tass.be 149:5f4cb161cec3 836 case PICO_IP_MULTICAST_LOOP:
tass picotcp@tass.be 149:5f4cb161cec3 837 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass picotcp@tass.be 149:5f4cb161cec3 838 *(uint8_t *)value = (uint8_t)PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
tass picotcp@tass.be 149:5f4cb161cec3 839 } else {
tass picotcp@tass.be 149:5f4cb161cec3 840 *(uint8_t *)value = 0;
tass picotcp@tass.be 149:5f4cb161cec3 841 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 842 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 843 }
tass picotcp@tass.be 149:5f4cb161cec3 844
tass picotcp@tass.be 149:5f4cb161cec3 845 break;
tass picotcp@tass.be 149:5f4cb161cec3 846 default:
tass picotcp@tass.be 149:5f4cb161cec3 847 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 848 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 849 }
tass picotcp@tass.be 149:5f4cb161cec3 850
tass picotcp@tass.be 149:5f4cb161cec3 851 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 852 }
tass picotcp@tass.be 149:5f4cb161cec3 853
tass picotcp@tass.be 149:5f4cb161cec3 854 static int mcast_so_loop(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 855 {
tass picotcp@tass.be 149:5f4cb161cec3 856 uint8_t val = (*(uint8_t *)value);
tass picotcp@tass.be 149:5f4cb161cec3 857 if (val == 0u) {
tass picotcp@tass.be 149:5f4cb161cec3 858 PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
tass picotcp@tass.be 149:5f4cb161cec3 859 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 860 } else if (val == 1u) {
tass picotcp@tass.be 149:5f4cb161cec3 861 PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
tass picotcp@tass.be 149:5f4cb161cec3 862 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 863 }
tass picotcp@tass.be 149:5f4cb161cec3 864
tass picotcp@tass.be 149:5f4cb161cec3 865 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 866 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 867 }
tass 152:a3d286bf94e5 868 static int mcast_get_param(struct pico_mcast *mcast, struct pico_socket *s, void *value,int alloc, int by_source) {
tass 152:a3d286bf94e5 869 if(by_source)
tass 154:6c0e92a80c4a 870 mcast->mreq_s = (struct pico_ip_mreq_source *)value;
tass 152:a3d286bf94e5 871 else
tass 154:6c0e92a80c4a 872 mcast->mreq = (struct pico_ip_mreq *)value;
tass 152:a3d286bf94e5 873 mcast->mcast_link = setopt_multicast_check(s, value, alloc, by_source);
tass 152:a3d286bf94e5 874 if (!mcast->mcast_link)
tass 152:a3d286bf94e5 875 return -1;
tass 152:a3d286bf94e5 876 mcast->address = pico_mcast_get_link_address(s, mcast->mcast_link);
tass 152:a3d286bf94e5 877 if(by_source)
tass 152:a3d286bf94e5 878 mcast->listen = listen_find(s, &(mcast->mreq_s)->mcast_link_addr, &mcast->mreq_s->mcast_group_addr);
tass 152:a3d286bf94e5 879 else
tass 152:a3d286bf94e5 880 mcast->listen = listen_find(s, &(mcast->mreq)->mcast_link_addr, &mcast->mreq->mcast_group_addr);
tass 152:a3d286bf94e5 881 return 0;
tass 152:a3d286bf94e5 882 }
tass picotcp@tass.be 149:5f4cb161cec3 883 static int mcast_so_addm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 884 {
tass 152:a3d286bf94e5 885 int filter_mode = 0;
tass 152:a3d286bf94e5 886 struct pico_mcast mcast;
tass 152:a3d286bf94e5 887 struct pico_tree *tree, *listen_tree;
tass 152:a3d286bf94e5 888 if(mcast_get_param(&mcast, s, value, 1,0) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 889 return -1;
tass 152:a3d286bf94e5 890
tass 152:a3d286bf94e5 891 if (mcast.listen) {
tass 152:a3d286bf94e5 892 if (mcast.listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass picotcp@tass.be 149:5f4cb161cec3 893 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass 152:a3d286bf94e5 894 } else {
tass picotcp@tass.be 149:5f4cb161cec3 895 so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 896 }
tass 152:a3d286bf94e5 897 pico_err = PICO_ERR_EINVAL;
tass 152:a3d286bf94e5 898 return -1;
tass 152:a3d286bf94e5 899 }
tass 152:a3d286bf94e5 900 mcast.listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen));
tass 152:a3d286bf94e5 901 if (!mcast.listen) {
tass 152:a3d286bf94e5 902 pico_err = PICO_ERR_ENOMEM;
tass 152:a3d286bf94e5 903 return -1;
tass 152:a3d286bf94e5 904 }
tass 152:a3d286bf94e5 905 mcast.listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE;
tass 152:a3d286bf94e5 906 mcast.listen->mcast_link = mcast.mreq->mcast_link_addr;
tass 152:a3d286bf94e5 907 mcast.listen->mcast_group = mcast.mreq->mcast_group_addr;
tass 152:a3d286bf94e5 908 mcast.listen->proto = s->net->proto_number;
tass picotcp@tass.be 149:5f4cb161cec3 909
tass 152:a3d286bf94e5 910 tree = mcast_get_src_tree(s, &mcast);
tass 152:a3d286bf94e5 911 listen_tree = mcast_get_listen_tree(s);
tass 152:a3d286bf94e5 912 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 913 if( IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 914 mcast.listen->proto = PICO_PROTO_IPV6;
tass 152:a3d286bf94e5 915 #endif
tass 152:a3d286bf94e5 916 tree->root = &LEAF;
tass 152:a3d286bf94e5 917 pico_tree_insert(listen_tree, mcast.listen);
tass 152:a3d286bf94e5 918
tass picotcp@tass.be 149:5f4cb161cec3 919 pico_tree_insert(&MCASTSockets, s);
tass 152:a3d286bf94e5 920 filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 921 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 922 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 923 so_mcast_dbg("PICO_IP_ADD_MEMBERSHIP - success, added %p\n", s);
tass 152:a3d286bf94e5 924 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 925 return pico_ipv4_mcast_join((struct pico_ip4*)&mcast.mreq->mcast_link_addr,(struct pico_ip4*) &mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
tass 152:a3d286bf94e5 926 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 927 else if(IS_SOCK_IPV6(s)) {
tass 152:a3d286bf94e5 928 return pico_ipv6_mcast_join((struct pico_ip6*)&mcast.mreq->mcast_link_addr,(struct pico_ip6*)&mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter_ipv6);
tass 152:a3d286bf94e5 929 }
tass 152:a3d286bf94e5 930 #endif
tass 152:a3d286bf94e5 931 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 932 }
tass picotcp@tass.be 149:5f4cb161cec3 933
tass picotcp@tass.be 149:5f4cb161cec3 934 static int mcast_so_dropm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 935 {
tass picotcp@tass.be 149:5f4cb161cec3 936 int filter_mode = 0;
tass picotcp@tass.be 149:5f4cb161cec3 937 union pico_address *source = NULL;
tass 152:a3d286bf94e5 938 struct pico_tree_node *_tmp,*index;
tass 152:a3d286bf94e5 939 struct pico_mcast mcast;
tass 152:a3d286bf94e5 940 struct pico_tree *listen_tree,*tree;
tass 152:a3d286bf94e5 941 if(mcast_get_param(&mcast, s, value, 0,0) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 942 return -1;
tass 152:a3d286bf94e5 943 if (!mcast.listen) {
tass picotcp@tass.be 149:5f4cb161cec3 944 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 945 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 946 return -1;
tass 152:a3d286bf94e5 947 }
tass 152:a3d286bf94e5 948 tree = mcast_get_src_tree(s,&mcast);
tass 152:a3d286bf94e5 949 listen_tree = mcast_get_listen_tree(s);
tass 152:a3d286bf94e5 950
tass 152:a3d286bf94e5 951 pico_tree_foreach_safe(index, tree, _tmp)
tass 152:a3d286bf94e5 952 {
tass 152:a3d286bf94e5 953 source = index->keyValue;
tass 152:a3d286bf94e5 954 pico_tree_delete(tree, source);
tass picotcp@tass.be 149:5f4cb161cec3 955 }
tass 152:a3d286bf94e5 956 pico_tree_delete(listen_tree, mcast.listen);
tass 152:a3d286bf94e5 957 PICO_FREE(mcast.listen);
tass 152:a3d286bf94e5 958 if (pico_tree_empty(listen_tree)) {
tass 152:a3d286bf94e5 959 PICO_FREE(listen_tree);
tass 152:a3d286bf94e5 960 mcast_set_listen_tree_p_null(s);
tass 152:a3d286bf94e5 961 pico_tree_delete(&MCASTSockets, s);
tass 152:a3d286bf94e5 962 }
tass 152:a3d286bf94e5 963
tass 152:a3d286bf94e5 964 filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 965 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 966 return -1;
tass 152:a3d286bf94e5 967 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 968 return pico_ipv4_mcast_leave((struct pico_ip4*) &mcast.mreq->mcast_link_addr,(struct pico_ip4 *) &mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
tass 152:a3d286bf94e5 969 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 970 else if(IS_SOCK_IPV6(s)) { }
tass 152:a3d286bf94e5 971 return pico_ipv6_mcast_leave((struct pico_ip6*)&mcast.mreq->mcast_link_addr,(struct pico_ip6*)&mcast.mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter_ipv6);
tass 152:a3d286bf94e5 972 #endif
tass 152:a3d286bf94e5 973 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 974 }
tass picotcp@tass.be 149:5f4cb161cec3 975
tass picotcp@tass.be 149:5f4cb161cec3 976 static int mcast_so_unblock_src(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 977 {
tass picotcp@tass.be 149:5f4cb161cec3 978 int filter_mode = 0;
tass 152:a3d286bf94e5 979 union pico_address stest, *source = NULL;
tass 152:a3d286bf94e5 980 struct pico_mcast mcast;
tass 152:a3d286bf94e5 981 if(mcast_get_param(&mcast, s, value, 0,1) < 0)
tass 152:a3d286bf94e5 982 return -1;
tass 152:a3d286bf94e5 983
tass picotcp@tass.be 149:5f4cb161cec3 984 memset(&stest, 0, sizeof(union pico_address));
tass 152:a3d286bf94e5 985 if (!mcast.listen) {
tass picotcp@tass.be 149:5f4cb161cec3 986 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 987 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 988 return -1;
tass 152:a3d286bf94e5 989 }
tass 152:a3d286bf94e5 990 if (mcast.listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass 152:a3d286bf94e5 991 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass 152:a3d286bf94e5 992 pico_err = PICO_ERR_EINVAL;
tass 152:a3d286bf94e5 993 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 994 }
tass picotcp@tass.be 149:5f4cb161cec3 995
tass 152:a3d286bf94e5 996 stest = mcast.mreq_s->mcast_source_addr;
tass 152:a3d286bf94e5 997 if( IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 998 source = pico_tree_findKey(&mcast.listen->MCASTSources, &stest);
tass 152:a3d286bf94e5 999 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1000 else if( IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 1001 source = pico_tree_findKey(&mcast.listen->MCASTSources_ipv6, &stest);
tass 152:a3d286bf94e5 1002 #endif
tass 152:a3d286bf94e5 1003 if (!source) {
tass 152:a3d286bf94e5 1004 so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n");
tass 152:a3d286bf94e5 1005 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 152:a3d286bf94e5 1006 return -1;
tass 152:a3d286bf94e5 1007 }
tass 152:a3d286bf94e5 1008 if( IS_SOCK_IPV4(s) )
tass 152:a3d286bf94e5 1009 pico_tree_delete(&mcast.listen->MCASTSources, source);
tass 152:a3d286bf94e5 1010 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1011 else if( IS_SOCK_IPV6(s) )
tass 152:a3d286bf94e5 1012 pico_tree_delete(&mcast.listen->MCASTSources_ipv6, source);
tass 152:a3d286bf94e5 1013 #endif
tass 152:a3d286bf94e5 1014
tass 152:a3d286bf94e5 1015 filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 1016 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1017 return -1;
tass 152:a3d286bf94e5 1018 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 1019 return pico_ipv4_mcast_leave((struct pico_ip4 *)&mcast.mreq_s->mcast_link_addr,(struct pico_ip4*) &mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
tass 152:a3d286bf94e5 1020 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1021 else if(IS_SOCK_IPV6(s)) { }
tass 152:a3d286bf94e5 1022 return pico_ipv6_mcast_leave((struct pico_ip6*)&mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter_ipv6);
tass 152:a3d286bf94e5 1023 #endif
tass 152:a3d286bf94e5 1024 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1025 }
tass picotcp@tass.be 149:5f4cb161cec3 1026
tass picotcp@tass.be 149:5f4cb161cec3 1027 static int mcast_so_block_src(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 1028 {
tass picotcp@tass.be 149:5f4cb161cec3 1029 int filter_mode = 0;
tass 152:a3d286bf94e5 1030 union pico_address stest, *source = NULL;
tass 152:a3d286bf94e5 1031 struct pico_mcast mcast;
tass 152:a3d286bf94e5 1032 if(mcast_get_param(&mcast, s, value, 0,1) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1033 return -1;
tass 152:a3d286bf94e5 1034
tass picotcp@tass.be 149:5f4cb161cec3 1035 memset(&stest, 0, sizeof(union pico_address));
tass 152:a3d286bf94e5 1036 if (!mcast.listen) {
tass picotcp@tass.be 149:5f4cb161cec3 1037 dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
tass picotcp@tass.be 149:5f4cb161cec3 1038 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 1039 return -1;
tass 152:a3d286bf94e5 1040 }
tass 152:a3d286bf94e5 1041 if (mcast.listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass 152:a3d286bf94e5 1042 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass 152:a3d286bf94e5 1043 pico_err = PICO_ERR_EINVAL;
tass 152:a3d286bf94e5 1044 return -1;
tass 152:a3d286bf94e5 1045 }
tass 152:a3d286bf94e5 1046 stest = mcast.mreq_s->mcast_source_addr;
tass 152:a3d286bf94e5 1047 if( IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 1048 source = pico_tree_findKey(&mcast.listen->MCASTSources, &stest);
tass 152:a3d286bf94e5 1049 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1050 else if( IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 1051 source = pico_tree_findKey(&mcast.listen->MCASTSources_ipv6, &stest);
tass 152:a3d286bf94e5 1052 #endif
tass 152:a3d286bf94e5 1053 if (source) {
tass 152:a3d286bf94e5 1054 so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n");
tass 152:a3d286bf94e5 1055 pico_err = PICO_ERR_ENOMEM;
tass 152:a3d286bf94e5 1056 return -1;
tass 152:a3d286bf94e5 1057 }
tass 152:a3d286bf94e5 1058 source = PICO_ZALLOC(sizeof(union pico_address));
tass 152:a3d286bf94e5 1059 if (!source) {
tass 152:a3d286bf94e5 1060 pico_err = PICO_ERR_ENOMEM;
tass 152:a3d286bf94e5 1061 return -1;
tass 152:a3d286bf94e5 1062 }
tass 152:a3d286bf94e5 1063 *source = mcast.mreq_s->mcast_source_addr;
tass 152:a3d286bf94e5 1064 if( IS_SOCK_IPV4(s) )
tass 152:a3d286bf94e5 1065 pico_tree_insert(&mcast.listen->MCASTSources, source);
tass 152:a3d286bf94e5 1066 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1067 else if( IS_SOCK_IPV6(s) )
tass 152:a3d286bf94e5 1068 pico_tree_insert(&mcast.listen->MCASTSources_ipv6, source);
tass 152:a3d286bf94e5 1069 #endif
tass picotcp@tass.be 149:5f4cb161cec3 1070
tass 152:a3d286bf94e5 1071 filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 1072 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1073 return -1;
tass 152:a3d286bf94e5 1074 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 1075 return pico_ipv4_mcast_join((struct pico_ip4 *) &mcast.mreq_s->mcast_link_addr, (struct pico_ip4*)&mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
tass 152:a3d286bf94e5 1076 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1077 else if(IS_SOCK_IPV6(s)) { }
tass 152:a3d286bf94e5 1078 return pico_ipv6_mcast_join((struct pico_ip6 *)&mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter_ipv6);
tass 152:a3d286bf94e5 1079 #endif
tass 152:a3d286bf94e5 1080 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1081 }
tass picotcp@tass.be 149:5f4cb161cec3 1082
tass picotcp@tass.be 149:5f4cb161cec3 1083 static int mcast_so_addsrcm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 1084 {
tass picotcp@tass.be 149:5f4cb161cec3 1085 int filter_mode = 0, reference_count = 0;
tass 152:a3d286bf94e5 1086 union pico_address stest, *source = NULL;
tass 152:a3d286bf94e5 1087 struct pico_mcast mcast;
tass 152:a3d286bf94e5 1088 struct pico_tree *tree,*listen_tree;
tass 152:a3d286bf94e5 1089 if(mcast_get_param(&mcast, s, value, 1,1) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1090 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1091
tass picotcp@tass.be 149:5f4cb161cec3 1092 memset(&stest, 0, sizeof(union pico_address));
tass 152:a3d286bf94e5 1093 listen_tree = mcast_get_listen_tree(s);
tass 152:a3d286bf94e5 1094 if (mcast.listen) {
tass 152:a3d286bf94e5 1095 tree = mcast_get_src_tree(s,&mcast);
tass 152:a3d286bf94e5 1096 if (mcast.listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
tass picotcp@tass.be 149:5f4cb161cec3 1097 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
tass picotcp@tass.be 149:5f4cb161cec3 1098 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 1099 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1100 }
tass 152:a3d286bf94e5 1101 stest = mcast.mreq_s->mcast_source_addr;
tass 152:a3d286bf94e5 1102 source = pico_tree_findKey(tree, &stest);
tass picotcp@tass.be 149:5f4cb161cec3 1103 if (source) {
tass picotcp@tass.be 149:5f4cb161cec3 1104 so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n");
tass 152:a3d286bf94e5 1105 pico_err = PICO_ERR_ENOMEM;
tass 152:a3d286bf94e5 1106 return -1;
tass 152:a3d286bf94e5 1107 }
tass 152:a3d286bf94e5 1108 source = PICO_ZALLOC(sizeof(union pico_address));
tass 152:a3d286bf94e5 1109 if (!source) {
tass picotcp@tass.be 149:5f4cb161cec3 1110 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 1111 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1112 }
tass 152:a3d286bf94e5 1113 *source = mcast.mreq_s->mcast_source_addr;
tass 152:a3d286bf94e5 1114 pico_tree_insert(tree, source);
tass 152:a3d286bf94e5 1115
tass picotcp@tass.be 149:5f4cb161cec3 1116 } else {
tass 152:a3d286bf94e5 1117 mcast.listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen));
tass 152:a3d286bf94e5 1118 if (!mcast.listen) {
tass picotcp@tass.be 149:5f4cb161cec3 1119 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 1120 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1121 }
tass 152:a3d286bf94e5 1122 tree = mcast_get_src_tree(s,&mcast);
tass 152:a3d286bf94e5 1123 mcast.listen->filter_mode = PICO_IP_MULTICAST_INCLUDE;
tass 152:a3d286bf94e5 1124 mcast.listen->mcast_link = mcast.mreq_s->mcast_link_addr;
tass 152:a3d286bf94e5 1125 mcast.listen->mcast_group = mcast.mreq_s->mcast_group_addr;
tass 152:a3d286bf94e5 1126 tree->root = &LEAF;
tass picotcp@tass.be 149:5f4cb161cec3 1127 source = PICO_ZALLOC(sizeof(union pico_address));
tass picotcp@tass.be 149:5f4cb161cec3 1128 if (!source) {
tass 152:a3d286bf94e5 1129 PICO_FREE(mcast.listen);
tass picotcp@tass.be 149:5f4cb161cec3 1130 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 1131 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1132 }
tass 152:a3d286bf94e5 1133 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1134 if( IS_SOCK_IPV6(s))
tass 152:a3d286bf94e5 1135 mcast.listen->proto = PICO_PROTO_IPV6;
tass 152:a3d286bf94e5 1136 #endif
tass 152:a3d286bf94e5 1137 *source = mcast.mreq_s->mcast_source_addr;
tass 152:a3d286bf94e5 1138 pico_tree_insert(tree, source);
tass 152:a3d286bf94e5 1139 pico_tree_insert(listen_tree, mcast.listen);
tass picotcp@tass.be 149:5f4cb161cec3 1140 reference_count = 1;
tass picotcp@tass.be 149:5f4cb161cec3 1141 }
tass picotcp@tass.be 149:5f4cb161cec3 1142 pico_tree_insert(&MCASTSockets, s);
tass 152:a3d286bf94e5 1143 filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 1144 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1145 return -1;
tass 152:a3d286bf94e5 1146 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 1147 return pico_ipv4_mcast_join((struct pico_ip4 *)&mcast.mreq_s->mcast_link_addr, (struct pico_ip4*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
tass 152:a3d286bf94e5 1148 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1149 else if(IS_SOCK_IPV6(s)) { }
tass 152:a3d286bf94e5 1150 return pico_ipv6_mcast_join((struct pico_ip6 *) &mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter_ipv6);
tass 152:a3d286bf94e5 1151 #endif
tass 152:a3d286bf94e5 1152 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1153 }
tass picotcp@tass.be 149:5f4cb161cec3 1154
tass picotcp@tass.be 149:5f4cb161cec3 1155 static int mcast_so_dropsrcm(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 1156 {
tass picotcp@tass.be 149:5f4cb161cec3 1157 int filter_mode = 0, reference_count = 0;
tass 152:a3d286bf94e5 1158 union pico_address stest, *source = NULL;
tass 152:a3d286bf94e5 1159 struct pico_mcast mcast;
tass 152:a3d286bf94e5 1160 struct pico_tree *tree,*listen_tree;
tass 152:a3d286bf94e5 1161 if(mcast_get_param(&mcast, s, value, 0,1) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1162 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1163
tass picotcp@tass.be 149:5f4cb161cec3 1164 memset(&stest, 0, sizeof(union pico_address));
tass 152:a3d286bf94e5 1165 listen_tree = mcast_get_listen_tree(s);
tass 152:a3d286bf94e5 1166 if (!mcast.listen) {
tass picotcp@tass.be 149:5f4cb161cec3 1167 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 1168 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass picotcp@tass.be 149:5f4cb161cec3 1169 return -1;
tass 152:a3d286bf94e5 1170 }
tass 152:a3d286bf94e5 1171 if (mcast.listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
tass 152:a3d286bf94e5 1172 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
tass 152:a3d286bf94e5 1173 pico_err = PICO_ERR_EINVAL;
tass 152:a3d286bf94e5 1174 return -1;
tass 152:a3d286bf94e5 1175 }
tass 152:a3d286bf94e5 1176 tree = mcast_get_src_tree(s, &mcast);
tass 152:a3d286bf94e5 1177 stest = mcast.mreq_s->mcast_source_addr;
tass 152:a3d286bf94e5 1178 source = pico_tree_findKey(tree, &stest);
tass 152:a3d286bf94e5 1179 if (!source) {
tass 152:a3d286bf94e5 1180 so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n");
tass 152:a3d286bf94e5 1181 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 152:a3d286bf94e5 1182 return -1;
tass 152:a3d286bf94e5 1183 }
tass 152:a3d286bf94e5 1184 pico_tree_delete(tree, source);
tass 152:a3d286bf94e5 1185 if (pico_tree_empty(tree)) { /* 1 if empty, 0 otherwise */
tass 152:a3d286bf94e5 1186 reference_count = 1;
tass 152:a3d286bf94e5 1187 pico_tree_delete(listen_tree, mcast.listen);
tass 152:a3d286bf94e5 1188 PICO_FREE(mcast.listen);
tass 152:a3d286bf94e5 1189 if (pico_tree_empty(listen_tree)) {
tass 152:a3d286bf94e5 1190 PICO_FREE(listen_tree);
tass 152:a3d286bf94e5 1191 mcast_set_listen_tree_p_null(s);
tass 152:a3d286bf94e5 1192 pico_tree_delete(&MCASTSockets, s);
tass picotcp@tass.be 149:5f4cb161cec3 1193 }
tass picotcp@tass.be 149:5f4cb161cec3 1194 }
tass picotcp@tass.be 149:5f4cb161cec3 1195
tass 152:a3d286bf94e5 1196 filter_mode = pico_socket_aggregate_mcastfilters(mcast.address, &mcast.mreq_s->mcast_group_addr);
tass picotcp@tass.be 149:5f4cb161cec3 1197 if (filter_mode < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1198 return -1;
tass 152:a3d286bf94e5 1199 if(IS_SOCK_IPV4(s))
tass 152:a3d286bf94e5 1200 return pico_ipv4_mcast_leave((struct pico_ip4 *) &mcast.mreq_s->mcast_link_addr, (struct pico_ip4*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
tass 152:a3d286bf94e5 1201 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 1202 else if(IS_SOCK_IPV6(s)) { }
tass 152:a3d286bf94e5 1203 return pico_ipv6_mcast_leave((struct pico_ip6 *)&mcast.mreq_s->mcast_link_addr,(struct pico_ip6*)&mcast.mreq_s->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter_ipv6);
tass 152:a3d286bf94e5 1204 #endif
tass 152:a3d286bf94e5 1205 return -1;
tass 152:a3d286bf94e5 1206 }
tass picotcp@tass.be 149:5f4cb161cec3 1207
tass picotcp@tass.be 149:5f4cb161cec3 1208
tass picotcp@tass.be 149:5f4cb161cec3 1209 struct pico_setsockopt_mcast_call
tass picotcp@tass.be 149:5f4cb161cec3 1210 {
tass picotcp@tass.be 149:5f4cb161cec3 1211 int option;
tass picotcp@tass.be 149:5f4cb161cec3 1212 int (*call)(struct pico_socket *, void *);
tass picotcp@tass.be 149:5f4cb161cec3 1213 };
tass picotcp@tass.be 149:5f4cb161cec3 1214
tass picotcp@tass.be 149:5f4cb161cec3 1215 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 1216 {
tass picotcp@tass.be 149:5f4cb161cec3 1217 { PICO_IP_MULTICAST_IF, NULL },
tass picotcp@tass.be 149:5f4cb161cec3 1218 { PICO_IP_MULTICAST_TTL, pico_udp_set_mc_ttl },
tass picotcp@tass.be 149:5f4cb161cec3 1219 { PICO_IP_MULTICAST_LOOP, mcast_so_loop },
tass picotcp@tass.be 149:5f4cb161cec3 1220 { PICO_IP_ADD_MEMBERSHIP, mcast_so_addm },
tass picotcp@tass.be 149:5f4cb161cec3 1221 { PICO_IP_DROP_MEMBERSHIP, mcast_so_dropm },
tass picotcp@tass.be 149:5f4cb161cec3 1222 { PICO_IP_UNBLOCK_SOURCE, mcast_so_unblock_src },
tass picotcp@tass.be 149:5f4cb161cec3 1223 { PICO_IP_BLOCK_SOURCE, mcast_so_block_src },
tass picotcp@tass.be 149:5f4cb161cec3 1224 { PICO_IP_ADD_SOURCE_MEMBERSHIP, mcast_so_addsrcm },
tass picotcp@tass.be 149:5f4cb161cec3 1225 { PICO_IP_DROP_SOURCE_MEMBERSHIP, mcast_so_dropsrcm }
tass picotcp@tass.be 149:5f4cb161cec3 1226 };
tass picotcp@tass.be 149:5f4cb161cec3 1227
tass picotcp@tass.be 149:5f4cb161cec3 1228
tass picotcp@tass.be 149:5f4cb161cec3 1229 static int mcast_so_check_socket(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 1230 {
tass picotcp@tass.be 149:5f4cb161cec3 1231 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 1232 if (!s)
tass picotcp@tass.be 149:5f4cb161cec3 1233 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1234
tass picotcp@tass.be 149:5f4cb161cec3 1235 if (!s->proto)
tass picotcp@tass.be 149:5f4cb161cec3 1236 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1237
tass picotcp@tass.be 149:5f4cb161cec3 1238 if (s->proto->proto_number != PICO_PROTO_UDP)
tass picotcp@tass.be 149:5f4cb161cec3 1239 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1240
tass picotcp@tass.be 149:5f4cb161cec3 1241 pico_err = PICO_ERR_NOERR;
tass picotcp@tass.be 149:5f4cb161cec3 1242 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 1243 }
tass picotcp@tass.be 149:5f4cb161cec3 1244
tass picotcp@tass.be 149:5f4cb161cec3 1245 int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 1246 {
tass picotcp@tass.be 149:5f4cb161cec3 1247 int arrayn = option - PICO_IP_MULTICAST_IF;
tass picotcp@tass.be 149:5f4cb161cec3 1248 if (option < PICO_IP_MULTICAST_IF || option > PICO_IP_DROP_SOURCE_MEMBERSHIP) {
tass picotcp@tass.be 149:5f4cb161cec3 1249 pico_err = PICO_ERR_EOPNOTSUPP;
tass picotcp@tass.be 149:5f4cb161cec3 1250 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1251 }
tass picotcp@tass.be 149:5f4cb161cec3 1252
tass picotcp@tass.be 149:5f4cb161cec3 1253 if (mcast_so_check_socket(s) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 1254 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1255
tass picotcp@tass.be 149:5f4cb161cec3 1256 if (!mcast_so_calls[arrayn].call) {
tass picotcp@tass.be 149:5f4cb161cec3 1257 pico_err = PICO_ERR_EOPNOTSUPP;
tass picotcp@tass.be 149:5f4cb161cec3 1258 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1259 }
tass picotcp@tass.be 149:5f4cb161cec3 1260
tass picotcp@tass.be 149:5f4cb161cec3 1261 return (mcast_so_calls[arrayn].call(s, value));
tass picotcp@tass.be 149:5f4cb161cec3 1262 }
tass picotcp@tass.be 149:5f4cb161cec3 1263
tass picotcp@tass.be 149:5f4cb161cec3 1264 int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl)
tass picotcp@tass.be 149:5f4cb161cec3 1265 {
tass picotcp@tass.be 149:5f4cb161cec3 1266 struct pico_socket_udp *u;
tass picotcp@tass.be 149:5f4cb161cec3 1267 uint8_t ttl = *(uint8_t *)_ttl;
tass picotcp@tass.be 149:5f4cb161cec3 1268 if(!s) {
tass picotcp@tass.be 149:5f4cb161cec3 1269 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 1270 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1271 }
tass picotcp@tass.be 149:5f4cb161cec3 1272
tass picotcp@tass.be 149:5f4cb161cec3 1273 u = (struct pico_socket_udp *) s;
tass picotcp@tass.be 149:5f4cb161cec3 1274 u->mc_ttl = ttl;
tass picotcp@tass.be 149:5f4cb161cec3 1275 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 1276 }
tass picotcp@tass.be 149:5f4cb161cec3 1277
tass picotcp@tass.be 149:5f4cb161cec3 1278 int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
tass picotcp@tass.be 149:5f4cb161cec3 1279 {
tass picotcp@tass.be 149:5f4cb161cec3 1280 struct pico_socket_udp *u;
tass picotcp@tass.be 149:5f4cb161cec3 1281 if(!s)
tass picotcp@tass.be 149:5f4cb161cec3 1282 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1283
tass picotcp@tass.be 149:5f4cb161cec3 1284 u = (struct pico_socket_udp *) s;
tass picotcp@tass.be 149:5f4cb161cec3 1285 *ttl = u->mc_ttl;
tass picotcp@tass.be 149:5f4cb161cec3 1286 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 1287 }
tass picotcp@tass.be 149:5f4cb161cec3 1288 #else
tass picotcp@tass.be 149:5f4cb161cec3 1289 int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl)
tass picotcp@tass.be 149:5f4cb161cec3 1290 {
tass 154:6c0e92a80c4a 1291 IGNORE_PARAMETER(s);
tass 154:6c0e92a80c4a 1292 IGNORE_PARAMETER(_ttl);
tass picotcp@tass.be 149:5f4cb161cec3 1293 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 1294 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1295 }
tass picotcp@tass.be 149:5f4cb161cec3 1296
tass picotcp@tass.be 149:5f4cb161cec3 1297 int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
tass picotcp@tass.be 149:5f4cb161cec3 1298 {
tass 154:6c0e92a80c4a 1299 IGNORE_PARAMETER(s);
tass 154:6c0e92a80c4a 1300 IGNORE_PARAMETER(ttl);
tass picotcp@tass.be 149:5f4cb161cec3 1301 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 1302 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1303 }
tass picotcp@tass.be 149:5f4cb161cec3 1304
tass picotcp@tass.be 149:5f4cb161cec3 1305 int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src)
tass picotcp@tass.be 149:5f4cb161cec3 1306 {
tass 154:6c0e92a80c4a 1307 IGNORE_PARAMETER(s);
tass 154:6c0e92a80c4a 1308 IGNORE_PARAMETER(mcast_group);
tass 154:6c0e92a80c4a 1309 IGNORE_PARAMETER(src);
tass picotcp@tass.be 149:5f4cb161cec3 1310 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 1311 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1312 }
tass picotcp@tass.be 149:5f4cb161cec3 1313
tass picotcp@tass.be 149:5f4cb161cec3 1314 void pico_multicast_delete(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 1315 {
tass picotcp@tass.be 149:5f4cb161cec3 1316 (void)s;
tass picotcp@tass.be 149:5f4cb161cec3 1317 }
tass picotcp@tass.be 149:5f4cb161cec3 1318
tass picotcp@tass.be 149:5f4cb161cec3 1319 int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 1320 {
tass picotcp@tass.be 149:5f4cb161cec3 1321 (void)s;
tass picotcp@tass.be 149:5f4cb161cec3 1322 (void)option;
tass picotcp@tass.be 149:5f4cb161cec3 1323 (void)value;
tass picotcp@tass.be 149:5f4cb161cec3 1324 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 1325 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1326 }
tass picotcp@tass.be 149:5f4cb161cec3 1327
tass picotcp@tass.be 149:5f4cb161cec3 1328 int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 1329 {
tass picotcp@tass.be 149:5f4cb161cec3 1330 (void)s;
tass picotcp@tass.be 149:5f4cb161cec3 1331 (void)option;
tass picotcp@tass.be 149:5f4cb161cec3 1332 (void)value;
tass picotcp@tass.be 149:5f4cb161cec3 1333 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 1334 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 1335
tass picotcp@tass.be 149:5f4cb161cec3 1336 }
tass picotcp@tass.be 149:5f4cb161cec3 1337 #endif /* PICO_SUPPORT_MCAST */
tass picotcp@tass.be 149:5f4cb161cec3 1338