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 )
@@ -1081,6 +1125,24 @@ static nsapi_size_or_error_t mbed_lwip_socket_recvfrom(nsapi_stack_t *stack, nsa
1081
1125
return recv ;
1082
1126
}
1083
1127
1128
+ static int32_t find_multicast_member (const struct lwip_socket * s , const nsapi_ip_mreq_t * imr ) {
1129
+ uint32_t count = 0 ;
1130
+ uint32_t index = 0 ;
1131
+ // Set upper limit on while loop, should break out when the membership pair is found
1132
+ while (count < s -> multicast_memberships_count ) {
1133
+ index = next_registered_multicast_member (s , index );
1134
+
1135
+ if (memcmp (& s -> multicast_memberships [index ].imr_multiaddr , & imr -> imr_multiaddr , sizeof (nsapi_addr_t )) == 0 &&
1136
+ memcmp (& s -> multicast_memberships [index ].imr_interface , & imr -> imr_interface , sizeof (nsapi_addr_t )) == 0 ) {
1137
+ return index ;
1138
+ }
1139
+ count ++ ;
1140
+ index ++ ;
1141
+ }
1142
+
1143
+ return -1 ;
1144
+ }
1145
+
1084
1146
static nsapi_error_t mbed_lwip_setsockopt (nsapi_stack_t * stack , nsapi_socket_t handle , int level , int optname , const void * optval , unsigned optlen )
1085
1147
{
1086
1148
struct lwip_socket * s = (struct lwip_socket * )handle ;
@@ -1124,6 +1186,103 @@ static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t h
1124
1186
}
1125
1187
return 0 ;
1126
1188
1189
+ case NSAPI_ADD_MEMBERSHIP :
1190
+ case NSAPI_DROP_MEMBERSHIP : {
1191
+ if (optlen != sizeof (nsapi_ip_mreq_t )) {
1192
+ return NSAPI_ERROR_PARAMETER ;
1193
+ }
1194
+ err_t igmp_err ;
1195
+ const nsapi_ip_mreq_t * imr = optval ;
1196
+
1197
+ /* Check interface address type matches group, or is unspecified */
1198
+ if (imr -> imr_interface .version != NSAPI_UNSPEC && imr -> imr_interface .version != imr -> imr_multiaddr .version ) {
1199
+ return NSAPI_ERROR_PARAMETER ;
1200
+ }
1201
+
1202
+ ip_addr_t if_addr ;
1203
+ ip_addr_t multi_addr ;
1204
+
1205
+ /* Convert the group address */
1206
+ if (!convert_mbed_addr_to_lwip (& multi_addr , & imr -> imr_multiaddr )) {
1207
+ return NSAPI_ERROR_PARAMETER ;
1208
+ }
1209
+
1210
+ /* Convert the interface address, or make sure it's the correct sort of "any" */
1211
+ if (imr -> imr_interface .version != NSAPI_UNSPEC ) {
1212
+ if (!convert_mbed_addr_to_lwip (& if_addr , & imr -> imr_interface )) {
1213
+ return NSAPI_ERROR_PARAMETER ;
1214
+ }
1215
+ } else {
1216
+ ip_addr_set_any (IP_IS_V6 (& if_addr ), & if_addr );
1217
+ }
1218
+
1219
+ igmp_err = ERR_USE ; // Maps to NSAPI_ERROR_UNSUPPORTED
1220
+ int32_t member_pair_index = find_multicast_member (s , imr );
1221
+
1222
+ if (optname == NSAPI_ADD_MEMBERSHIP ) {
1223
+ if (!s -> multicast_memberships ) {
1224
+ // First multicast join on this socket, allocate space for membership tracking
1225
+ s -> multicast_memberships = malloc (sizeof (nsapi_ip_mreq_t ) * LWIP_SOCKET_MAX_MEMBERSHIPS );
1226
+ if (!s -> multicast_memberships ) {
1227
+ return NSAPI_ERROR_NO_MEMORY ;
1228
+ }
1229
+ } else if (s -> multicast_memberships_count == LWIP_SOCKET_MAX_MEMBERSHIPS ) {
1230
+ return NSAPI_ERROR_NO_MEMORY ;
1231
+ }
1232
+
1233
+ if (member_pair_index != -1 ) {
1234
+ return NSAPI_ERROR_ADDRESS_IN_USE ;
1235
+ }
1236
+
1237
+ member_pair_index = next_free_multicast_member (s , 0 );
1238
+
1239
+ sys_prot_t prot = sys_arch_protect ();
1240
+
1241
+ #if LWIP_IPV4
1242
+ if (IP_IS_V4 (& if_addr )) {
1243
+ igmp_err = igmp_joingroup (ip_2_ip4 (& if_addr ), ip_2_ip4 (& multi_addr ));
1244
+ }
1245
+ #endif
1246
+ #if LWIP_IPV6
1247
+ if (IP_IS_V6 (& if_addr )) {
1248
+ igmp_err = mld6_joingroup (ip_2_ip6 (& if_addr ), ip_2_ip6 (& multi_addr ));
1249
+ }
1250
+ #endif
1251
+
1252
+ sys_arch_unprotect (prot );
1253
+
1254
+ if (igmp_err == ERR_OK ) {
1255
+ set_multicast_member_registry_bit (s , member_pair_index );
1256
+ s -> multicast_memberships [member_pair_index ] = * imr ;
1257
+ s -> multicast_memberships_count ++ ;
1258
+ }
1259
+ } else {
1260
+ if (member_pair_index == -1 ) {
1261
+ return NSAPI_ERROR_NO_ADDRESS ;
1262
+ }
1263
+
1264
+ clear_multicast_member_registry_bit (s , member_pair_index );
1265
+ s -> multicast_memberships_count -- ;
1266
+
1267
+ sys_prot_t prot = sys_arch_protect ();
1268
+
1269
+ #if LWIP_IPV4
1270
+ if (IP_IS_V4 (& if_addr )) {
1271
+ igmp_err = igmp_leavegroup (ip_2_ip4 (& if_addr ), ip_2_ip4 (& multi_addr ));
1272
+ }
1273
+ #endif
1274
+ #if LWIP_IPV6
1275
+ if (IP_IS_V6 (& if_addr )) {
1276
+ igmp_err = mld6_leavegroup (ip_2_ip6 (& if_addr ), ip_2_ip6 (& multi_addr ));
1277
+ }
1278
+ #endif
1279
+
1280
+ sys_arch_unprotect (prot );
1281
+ }
1282
+
1283
+ return mbed_lwip_err_remap (igmp_err );
1284
+ }
1285
+
1127
1286
default :
1128
1287
return NSAPI_ERROR_UNSUPPORTED ;
1129
1288
}
0 commit comments