32
32
#include "lwip/tcp.h"
33
33
#include "lwip/ip.h"
34
34
#include "lwip/mld6.h"
35
+ #include "lwip/igmp.h"
35
36
#include "lwip/dns.h"
36
37
#include "lwip/udp.h"
38
+ #include "lwip_errno.h"
37
39
#include "netif/lwip_ethernet.h"
38
40
#include "emac_api.h"
39
41
#include "ppp_lwip.h"
@@ -46,6 +48,10 @@ static nsapi_error_t mbed_lwip_err_remap(err_t err);
46
48
#define MBED_NETIF_INIT_FN eth_arch_enetif_init
47
49
#endif
48
50
51
+ #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
52
+ #define LWIP_SOCKET_MAX_MEMBERSHIPS 4
53
+ #endif
54
+
49
55
/* Static arena of sockets */
50
56
static struct lwip_socket {
51
57
bool in_use ;
@@ -56,13 +62,39 @@ static struct lwip_socket {
56
62
57
63
void (* cb )(void * );
58
64
void * data ;
65
+
66
+ // Track multicast addresses subscribed to by this socket
67
+ nsapi_ip_mreq_t * multicast_memberships ;
68
+ uint32_t multicast_memberships_count ;
69
+ uint32_t multicast_memberships_registry ;
70
+
59
71
} lwip_arena [MEMP_NUM_NETCONN ];
60
72
61
73
static bool lwip_inited = false;
62
74
static bool lwip_connected = false;
63
75
static bool netif_inited = false;
64
76
static bool netif_is_ppp = false;
65
77
78
+ static nsapi_error_t mbed_lwip_setsockopt (nsapi_stack_t * stack , nsapi_socket_t handle , int level , int optname , const void * optval , unsigned optlen );
79
+
80
+ static inline uint32_t next_registered_multicast_member (const struct lwip_socket * s , uint32_t index ) {
81
+ while (!(s -> multicast_memberships_registry & (0x0001 << index ))) { index ++ ; }
82
+ return index ;
83
+ }
84
+
85
+ static inline uint32_t next_free_multicast_member (const struct lwip_socket * s , uint32_t index ) {
86
+ while ((s -> multicast_memberships_registry & (0x0001 << index ))) { index ++ ; }
87
+ return index ;
88
+ }
89
+
90
+ static inline void set_multicast_member_registry_bit (struct lwip_socket * s , uint32_t index ) {
91
+ s -> multicast_memberships_registry |= (0x0001 << index );
92
+ }
93
+
94
+ static inline void clear_multicast_member_registry_bit (struct lwip_socket * s , uint32_t index ) {
95
+ s -> multicast_memberships_registry &= ~(0x0001 << index );
96
+ }
97
+
66
98
static struct lwip_socket * mbed_lwip_arena_alloc (void )
67
99
{
68
100
sys_prot_t prot = sys_arch_protect ();
@@ -84,6 +116,18 @@ static struct lwip_socket *mbed_lwip_arena_alloc(void)
84
116
static void mbed_lwip_arena_dealloc (struct lwip_socket * s )
85
117
{
86
118
s -> in_use = false;
119
+
120
+ while (s -> multicast_memberships_count > 0 ) {
121
+ uint32_t index = 0 ;
122
+ index = next_registered_multicast_member (s , index );
123
+
124
+ mbed_lwip_setsockopt (NULL , s , NSAPI_SOCKET , NSAPI_DROP_MEMBERSHIP , & s -> multicast_memberships [index ],
125
+ sizeof (s -> multicast_memberships [index ]));
126
+ index ++ ;
127
+ }
128
+
129
+ free (s -> multicast_memberships );
130
+ s -> multicast_memberships = NULL ;
87
131
}
88
132
89
133
static void mbed_lwip_socket_callback (struct netconn * nc , enum netconn_evt eh , u16_t len )
@@ -1083,6 +1127,24 @@ static nsapi_size_or_error_t mbed_lwip_socket_recvfrom(nsapi_stack_t *stack, nsa
1083
1127
return recv ;
1084
1128
}
1085
1129
1130
+ static int32_t find_multicast_member (const struct lwip_socket * s , const nsapi_ip_mreq_t * imr ) {
1131
+ uint32_t count = 0 ;
1132
+ uint32_t index = 0 ;
1133
+ // Set upper limit on while loop, should break out when the membership pair is found
1134
+ while (count < s -> multicast_memberships_count ) {
1135
+ index = next_registered_multicast_member (s , index );
1136
+
1137
+ if (memcmp (& s -> multicast_memberships [index ].imr_multiaddr , & imr -> imr_multiaddr , sizeof (nsapi_addr_t )) == 0 &&
1138
+ memcmp (& s -> multicast_memberships [index ].imr_interface , & imr -> imr_interface , sizeof (nsapi_addr_t )) == 0 ) {
1139
+ return index ;
1140
+ }
1141
+ count ++ ;
1142
+ index ++ ;
1143
+ }
1144
+
1145
+ return -1 ;
1146
+ }
1147
+
1086
1148
static nsapi_error_t mbed_lwip_setsockopt (nsapi_stack_t * stack , nsapi_socket_t handle , int level , int optname , const void * optval , unsigned optlen )
1087
1149
{
1088
1150
struct lwip_socket * s = (struct lwip_socket * )handle ;
@@ -1126,6 +1188,103 @@ static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t h
1126
1188
}
1127
1189
return 0 ;
1128
1190
1191
+ case NSAPI_ADD_MEMBERSHIP :
1192
+ case NSAPI_DROP_MEMBERSHIP : {
1193
+ if (optlen != sizeof (nsapi_ip_mreq_t )) {
1194
+ return NSAPI_ERROR_PARAMETER ;
1195
+ }
1196
+ err_t igmp_err ;
1197
+ const nsapi_ip_mreq_t * imr = optval ;
1198
+
1199
+ /* Check interface address type matches group, or is unspecified */
1200
+ if (imr -> imr_interface .version != NSAPI_UNSPEC && imr -> imr_interface .version != imr -> imr_multiaddr .version ) {
1201
+ return NSAPI_ERROR_PARAMETER ;
1202
+ }
1203
+
1204
+ ip_addr_t if_addr ;
1205
+ ip_addr_t multi_addr ;
1206
+
1207
+ /* Convert the group address */
1208
+ if (!convert_mbed_addr_to_lwip (& multi_addr , & imr -> imr_multiaddr )) {
1209
+ return NSAPI_ERROR_PARAMETER ;
1210
+ }
1211
+
1212
+ /* Convert the interface address, or make sure it's the correct sort of "any" */
1213
+ if (imr -> imr_interface .version != NSAPI_UNSPEC ) {
1214
+ if (!convert_mbed_addr_to_lwip (& if_addr , & imr -> imr_interface )) {
1215
+ return NSAPI_ERROR_PARAMETER ;
1216
+ }
1217
+ } else {
1218
+ ip_addr_set_any (IP_IS_V6 (& if_addr ), & if_addr );
1219
+ }
1220
+
1221
+ igmp_err = ERR_USE ; // Maps to NSAPI_ERROR_UNSUPPORTED
1222
+ int32_t member_pair_index = find_multicast_member (s , imr );
1223
+
1224
+ if (optname == NSAPI_ADD_MEMBERSHIP ) {
1225
+ if (!s -> multicast_memberships ) {
1226
+ // First multicast join on this socket, allocate space for membership tracking
1227
+ s -> multicast_memberships = malloc (sizeof (nsapi_ip_mreq_t ) * LWIP_SOCKET_MAX_MEMBERSHIPS );
1228
+ if (!s -> multicast_memberships ) {
1229
+ return NSAPI_ERROR_NO_MEMORY ;
1230
+ }
1231
+ } else if (s -> multicast_memberships_count == LWIP_SOCKET_MAX_MEMBERSHIPS ) {
1232
+ return NSAPI_ERROR_NO_MEMORY ;
1233
+ }
1234
+
1235
+ if (member_pair_index != -1 ) {
1236
+ return NSAPI_ERROR_ADDRESS_IN_USE ;
1237
+ }
1238
+
1239
+ member_pair_index = next_free_multicast_member (s , 0 );
1240
+
1241
+ sys_prot_t prot = sys_arch_protect ();
1242
+
1243
+ #if LWIP_IPV4
1244
+ if (IP_IS_V4 (& if_addr )) {
1245
+ igmp_err = igmp_joingroup (ip_2_ip4 (& if_addr ), ip_2_ip4 (& multi_addr ));
1246
+ }
1247
+ #endif
1248
+ #if LWIP_IPV6
1249
+ if (IP_IS_V6 (& if_addr )) {
1250
+ igmp_err = mld6_joingroup (ip_2_ip6 (& if_addr ), ip_2_ip6 (& multi_addr ));
1251
+ }
1252
+ #endif
1253
+
1254
+ sys_arch_unprotect (prot );
1255
+
1256
+ if (igmp_err == ERR_OK ) {
1257
+ set_multicast_member_registry_bit (s , member_pair_index );
1258
+ s -> multicast_memberships [member_pair_index ] = * imr ;
1259
+ s -> multicast_memberships_count ++ ;
1260
+ }
1261
+ } else {
1262
+ if (member_pair_index == -1 ) {
1263
+ return NSAPI_ERROR_NO_ADDRESS ;
1264
+ }
1265
+
1266
+ clear_multicast_member_registry_bit (s , member_pair_index );
1267
+ s -> multicast_memberships_count -- ;
1268
+
1269
+ sys_prot_t prot = sys_arch_protect ();
1270
+
1271
+ #if LWIP_IPV4
1272
+ if (IP_IS_V4 (& if_addr )) {
1273
+ igmp_err = igmp_leavegroup (ip_2_ip4 (& if_addr ), ip_2_ip4 (& multi_addr ));
1274
+ }
1275
+ #endif
1276
+ #if LWIP_IPV6
1277
+ if (IP_IS_V6 (& if_addr )) {
1278
+ igmp_err = mld6_leavegroup (ip_2_ip6 (& if_addr ), ip_2_ip6 (& multi_addr ));
1279
+ }
1280
+ #endif
1281
+
1282
+ sys_arch_unprotect (prot );
1283
+ }
1284
+
1285
+ return mbed_lwip_err_remap (igmp_err );
1286
+ }
1287
+
1129
1288
default :
1130
1289
return NSAPI_ERROR_UNSUPPORTED ;
1131
1290
}
0 commit comments