Index: sockets.c
===================================================================
RCS file: /sources/lwip/lwip/src/api/sockets.c,v
retrieving revision 1.44
diff -u -r1.44 sockets.c
--- sockets.c	4 May 2007 15:18:30 -0000	1.44
+++ sockets.c	4 May 2007 16:20:00 -0000
@@ -40,7 +40,11 @@
 #include "lwip/sys.h"
 #include "lwip/igmp.h"
 #include "lwip/sockets.h"
-
+#include "lwip/tcpip.h"
+#if LWIP_IGMP
+#include "lwip/api.h"
+#include "lwip/igmp.h"
+#endif
 #define NUM_SOCKETS MEMP_NUM_NETCONN
 
 struct lwip_socket {
@@ -62,6 +66,16 @@
   sys_sem_t sem;
 };
 
+struct lwip_setgetsockopt_data {
+  struct lwip_socket *sock;
+  int s;
+  int level;
+  int optname;
+  void *optval;
+  socklen_t *optlen;
+  sys_mbox_t mbox;
+};
+
 static struct lwip_socket sockets[NUM_SOCKETS];
 static struct lwip_select_cb *select_cb_list = 0;
 
@@ -927,10 +941,13 @@
   return 0;
 }
 
+static void lwip_getsockopt_internal(void *arg);
+
 int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
 {
   int err = 0;
   struct lwip_socket *sock = get_socket(s);
+  struct lwip_setgetsockopt_data data;
 
   if (!sock)
     return -1;
@@ -1038,6 +1055,37 @@
   }
 
   /* Now do the actual option processing */
+  data.sock = sock;
+  data.level = level;
+  data.optname = optname;
+  data.optval = optval;
+  data.optlen = optlen;
+  data.mbox = sock->conn->mbox;
+  tcpip_callback(lwip_getsockopt_internal, &data);
+  sys_arch_mbox_fetch(sock->conn->mbox, NULL, 0);
+
+  sock_set_errno(sock, err);
+  return err ? -1 : 0;
+}
+
+
+static void lwip_getsockopt_internal(void *arg)
+{
+  struct lwip_socket *sock;
+  int s, level, optname;
+  void *optval;
+  socklen_t *optlen;
+  struct lwip_setgetsockopt_data *data;
+
+  LWIP_ASSERT("arg != NULL", arg != NULL);
+
+  data = (struct lwip_setgetsockopt_data*)arg;
+  sock = data->sock;
+  s = data->s;
+  level = data->level;
+  optname = data->optname;
+  optval = data->optval;
+  optlen = data->optlen;
 
   switch(level) {
    
@@ -1139,15 +1187,16 @@
     }  /* switch */
     break;
   }
-
-  sock_set_errno(sock, err);
-  return err ? -1 : 0;
+  sys_mbox_post(sock->conn->mbox, NULL);
 }
 
+static void lwip_setsockopt_internal(void *arg);
+
 int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
 {
   struct lwip_socket *sock = get_socket(s);
   int err = 0;
+  struct lwip_setgetsockopt_data data;
 
   if (!sock)
     return -1;
@@ -1205,22 +1254,19 @@
         err = EINVAL;
       }
       break;
-    #if LWIP_IGMP
+#if LWIP_IGMP
     case IP_MULTICAST_TTL:
-     { 
-       /* NOTE, some BSD implementation use "int", some others "char" */
-       if(( optlen != sizeof(char) ) && ( optlen != sizeof(int) )) 
-         err = EINVAL;
-       break;
-     }
+      /* NOTE, some BSD implementation use "int", some others "char" */
+      if(( optlen != sizeof(char) ) && ( optlen != sizeof(int) )) 
+        err = EINVAL;
+      break;
     case IP_ADD_MEMBERSHIP:
     case IP_DROP_MEMBERSHIP:
-      { if( optlen < sizeof(struct ip_mreq) ) {
-          err = EINVAL;
-        }
-        break;
+      if( optlen < sizeof(struct ip_mreq) ) {
+        err = EINVAL;
       }
-    #endif /* LWIP_IGMP */
+      break;      
+#endif /* LWIP_IGMP */
       default:
         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
         err = ENOPROTOOPT;
@@ -1267,6 +1313,36 @@
 
 
   /* Now do the actual option processing */
+  data.sock = sock;
+  data.level = level;
+  data.optname = optname;
+  data.optval = (void*)optval;
+  data.optlen = &optlen;
+  data.mbox = sock->conn->mbox;
+  tcpip_callback(lwip_getsockopt_internal, &data);
+  sys_arch_mbox_fetch(sock->conn->mbox, NULL, 0);
+
+  sock_set_errno(sock, err);
+  return err ? -1 : 0;
+}
+
+static void lwip_setsockopt_internal(void *arg)
+{
+  struct lwip_socket *sock;
+  int s, level, optname;
+  const void *optval;
+  socklen_t optlen;
+  struct lwip_setgetsockopt_data *data;
+
+  LWIP_ASSERT("arg != NULL", arg != NULL);
+
+  data = (struct lwip_setgetsockopt_data*)arg;
+  sock = data->sock;
+  s = data->s;
+  level = data->level;
+  optname = data->optname;
+  optval = data->optval;
+  optlen = *(data->optlen);
 
   switch(level) {
 
@@ -1311,27 +1387,40 @@
       sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval);
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos));
       break;
-    #if LWIP_IGMP
+#if LWIP_IGMP
     case IP_MULTICAST_TTL:
-     { if (optlen==sizeof(int))  sock->conn->pcb.tcp->ttl = (u8_t)(*(int*) optval);
-       if (optlen==sizeof(u8_t)) sock->conn->pcb.tcp->ttl = (u8_t)(*(u8_t*)optval);
-       break;
-     }
+      if (optlen == sizeof(int))
+        sock->conn->pcb.tcp->ttl = (u8_t)(*(int*) optval);
+      if (optlen == sizeof(u8_t))
+        sock->conn->pcb.tcp->ttl = (u8_t)(*(u8_t*)optval);
+      break;
     case IP_ADD_MEMBERSHIP:
     case IP_DROP_MEMBERSHIP:
-     { /* If this is a TCP or a RAW socket, ignore these options. */
-       if ((sock->conn->type == NETCONN_TCP) || (sock->conn->type == NETCONN_RAW))
-        { err = EAFNOSUPPORT;
-        }
-       else
-        { struct ip_mreq *imr = (struct ip_mreq *)optval;
-          if (netconn_join_leave_group( sock->conn, (struct ip_addr *)&(imr->imr_multiaddr.s_addr), (struct ip_addr *)&(imr->imr_interface.s_addr), ((optname==IP_ADD_MEMBERSHIP)?NETCONN_JOIN:NETCONN_LEAVE)) < 0)
-           { err = EADDRNOTAVAIL;
-           }
+      /* If this is a TCP or a RAW socket, ignore these options. */
+      if ((sock->conn->type == NETCONN_TCP) || (sock->conn->type == NETCONN_RAW)) {
+        sock->conn->err = EAFNOSUPPORT;
+      } else {
+#if LWIP_UDP
+        if (sock->conn->err == ERR_OK) {
+          if (sock->conn->pcb.tcp != NULL) {
+            switch (sock->conn->type) {
+            case NETCONN_UDPLITE:
+            case NETCONN_UDPNOCHKSUM:
+            case NETCONN_UDP:
+              if(optname == IP_ADD_MEMBERSHIP){
+                sock->conn->err = igmp_joingroup(netif_default, (struct ip_addr*)optval);
+              } else {
+                sock->conn->err = igmp_leavegroup(netif_default, (struct ip_addr*)optval);
+              }
+            default:
+              break;
+            }
+          }
         }
-       break;
-     }
-    #endif /* LWIP_IGMP */
+#endif /* LWIP_UDP */
+      }
+      break;
+#endif /* LWIP_IGMP */
     }  /* switch */
     break;
 
@@ -1369,9 +1458,7 @@
     }  /* switch */
     break;
   }  /* switch */
-
-  sock_set_errno(sock, err);
-  return err ? -1 : 0;
+  sys_mbox_post(sock->conn->mbox, NULL);
 }
 
 int lwip_ioctl(int s, long cmd, void *argp)
