Handle the SCTP_GET_LOCAL_ADDRS and SCTP_GET_PEER_ADDRS getsockopt
calls correctly. Fix to bug #111231.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@4549 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 94d15f2..ab9476d 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -1146,10 +1146,17 @@
    Addr optval_p  = arg3;
    Addr optlen_p  = arg4;
    /* vg_assert(sizeof(socklen_t) == sizeof(UInt)); */
-   if (optval_p != (Addr)NULL) 
+   if (optval_p != (Addr)NULL) {
       buf_and_len_pre_check ( tid, optval_p, optlen_p,
                               "socketcall.getsockopt(optval)",
                               "socketcall.getsockopt(optlen)" );
+      if (arg1 == VKI_SOL_SCTP &&
+          (arg2 == VKI_SCTP_GET_PEER_ADDRS || arg2 == VKI_SCTP_GET_LOCAL_ADDRS)) {
+         struct vki_sctp_getaddrs *ga = (struct vki_sctp_getaddrs*)arg3;
+         int address_bytes = sizeof(struct vki_sockaddr_in6) * ga->addr_num;
+         PRE_MEM_WRITE( "socketcall.getsockopt(optval.addrs)", (Addr)ga->addrs, address_bytes );
+      }
+   }
 }
 
 void 
@@ -1161,9 +1168,28 @@
    Addr optval_p  = arg3;
    Addr optlen_p  = arg4;
    vg_assert(!res.isError); /* guaranteed by caller */
-   if (optval_p != (Addr)NULL) 
+   if (optval_p != (Addr)NULL) {
       buf_and_len_post_check ( tid, res, optval_p, optlen_p,
                                "socketcall.getsockopt(optlen_out)" );
+      if (arg1 == VKI_SOL_SCTP &&
+          (arg2 == VKI_SCTP_GET_PEER_ADDRS || arg2 == VKI_SCTP_GET_LOCAL_ADDRS)) {
+         struct vki_sctp_getaddrs *ga = (struct vki_sctp_getaddrs*)arg3;
+         struct vki_sockaddr *a = ga->addrs;
+         int i;
+         for (i = 0; i < ga->addr_num; i++) {
+            int sl = 0;
+            if (a->sa_family == VKI_AF_INET)
+               sl = sizeof(struct vki_sockaddr_in);
+            else if (a->sa_family == VKI_AF_INET6)
+               sl = sizeof(struct vki_sockaddr_in6);
+            else {
+               VG_(message)(Vg_UserMsg, "Warning: getsockopt: unhandled address type %d", a->sa_family);
+            }
+            a = (struct vki_sockaddr*)((char*)a + sl);
+         }
+         POST_MEM_WRITE( (Addr)ga->addrs, (char*)a - (char*)ga->addrs );
+      }
+   }
 }
 
 /* ------ */
diff --git a/include/vki-amd64-linux.h b/include/vki-amd64-linux.h
index d1c2876..7eb1906 100644
--- a/include/vki-amd64-linux.h
+++ b/include/vki-amd64-linux.h
@@ -44,6 +44,7 @@
 typedef __signed__ short __vki_s16;
 typedef unsigned short __vki_u16;
 
+typedef __signed__ int __vki_s32;
 typedef unsigned int __vki_u32;
 
 typedef __signed__ long long __vki_s64;
diff --git a/include/vki-linux.h b/include/vki-linux.h
index 6868e3b..5d6df36 100644
--- a/include/vki-linux.h
+++ b/include/vki-linux.h
@@ -587,6 +587,8 @@
 
 #define VKI_MSG_NOSIGNAL	0x4000	/* Do not generate SIGPIPE */
 
+#define VKI_SOL_SCTP	132
+
 //----------------------------------------------------------------------
 // From linux-2.6.8.1/include/linux/in.h
 //----------------------------------------------------------------------
@@ -772,6 +774,73 @@
 };
 
 //----------------------------------------------------------------------
+// From linux-2.6.13-rc5/include/net/sctp/user.h
+//----------------------------------------------------------------------
+
+typedef __vki_s32 vki_sctp_assoc_t;
+
+enum vki_sctp_optname {
+	VKI_SCTP_RTOINFO,
+#define VKI_SCTP_RTOINFO VKI_SCTP_RTOINFO
+	VKI_SCTP_ASSOCINFO,
+#define VKI_SCTP_ASSOCINFO VKI_SCTP_ASSOCINFO
+	VKI_SCTP_INITMSG,
+#define VKI_SCTP_INITMSG VKI_SCTP_INITMSG
+	VKI_SCTP_NODELAY, 	/* Get/set nodelay option. */
+#define VKI_SCTP_NODELAY	VKI_SCTP_NODELAY
+	VKI_SCTP_AUTOCLOSE,
+#define VKI_SCTP_AUTOCLOSE VKI_SCTP_AUTOCLOSE
+	VKI_SCTP_SET_PEER_PRIMARY_ADDR, 
+#define VKI_SCTP_SET_PEER_PRIMARY_ADDR VKI_SCTP_SET_PEER_PRIMARY_ADDR
+	VKI_SCTP_PRIMARY_ADDR,
+#define VKI_SCTP_PRIMARY_ADDR VKI_SCTP_PRIMARY_ADDR
+	VKI_SCTP_ADAPTION_LAYER,      
+#define VKI_SCTP_ADAPTION_LAYER VKI_SCTP_ADAPTION_LAYER
+	VKI_SCTP_DISABLE_FRAGMENTS,
+#define VKI_SCTP_DISABLE_FRAGMENTS VKI_SCTP_DISABLE_FRAGMENTS
+	VKI_SCTP_PEER_ADDR_PARAMS,
+#define VKI_SCTP_PEER_ADDR_PARAMS VKI_SCTP_PEER_ADDR_PARAMS
+	VKI_SCTP_DEFAULT_SEND_PARAM,
+#define VKI_SCTP_DEFAULT_SEND_PARAM VKI_SCTP_DEFAULT_SEND_PARAM
+	VKI_SCTP_EVENTS,
+#define VKI_SCTP_EVENTS VKI_SCTP_EVENTS
+	VKI_SCTP_I_WANT_MAPPED_V4_ADDR,  /* Turn on/off mapped v4 addresses  */
+#define VKI_SCTP_I_WANT_MAPPED_V4_ADDR VKI_SCTP_I_WANT_MAPPED_V4_ADDR
+	VKI_SCTP_MAXSEG, 	/* Get/set maximum fragment. */
+#define VKI_SCTP_MAXSEG 	VKI_SCTP_MAXSEG
+	VKI_SCTP_STATUS,
+#define VKI_SCTP_STATUS VKI_SCTP_STATUS
+	VKI_SCTP_GET_PEER_ADDR_INFO,
+#define VKI_SCTP_GET_PEER_ADDR_INFO VKI_SCTP_GET_PEER_ADDR_INFO
+
+	/* Internal Socket Options. Some of the sctp library functions are 
+	 * implemented using these socket options.
+	 */
+	VKI_SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */
+#define VKI_SCTP_SOCKOPT_BINDX_ADD	VKI_SCTP_SOCKOPT_BINDX_ADD
+	VKI_SCTP_SOCKOPT_BINDX_REM, /* BINDX requests for removing addresses. */
+#define VKI_SCTP_SOCKOPT_BINDX_REM	VKI_SCTP_SOCKOPT_BINDX_REM
+	VKI_SCTP_SOCKOPT_PEELOFF, 	/* peel off association. */
+#define VKI_SCTP_SOCKOPT_PEELOFF	VKI_SCTP_SOCKOPT_PEELOFF
+	VKI_SCTP_GET_PEER_ADDRS_NUM, 	/* Get number of peer addresss. */
+#define VKI_SCTP_GET_PEER_ADDRS_NUM	VKI_SCTP_GET_PEER_ADDRS_NUM
+	VKI_SCTP_GET_PEER_ADDRS, 	/* Get all peer addresss. */
+#define VKI_SCTP_GET_PEER_ADDRS	VKI_SCTP_GET_PEER_ADDRS
+	VKI_SCTP_GET_LOCAL_ADDRS_NUM, 	/* Get number of local addresss. */
+#define VKI_SCTP_GET_LOCAL_ADDRS_NUM	VKI_SCTP_GET_LOCAL_ADDRS_NUM
+	VKI_SCTP_GET_LOCAL_ADDRS, 	/* Get all local addresss. */
+#define VKI_SCTP_GET_LOCAL_ADDRS	VKI_SCTP_GET_LOCAL_ADDRS
+	VKI_SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
+#define VKI_SCTP_SOCKOPT_CONNECTX	VKI_SCTP_SOCKOPT_CONNECTX
+};
+
+struct vki_sctp_getaddrs {
+	vki_sctp_assoc_t        assoc_id;
+	int			addr_num;
+	struct vki_sockaddr	*addrs;
+};
+
+//----------------------------------------------------------------------
 // From linux-2.6.8.1/include/linux/resource.h
 //----------------------------------------------------------------------
 
diff --git a/include/vki-ppc32-linux.h b/include/vki-ppc32-linux.h
index 5d385a5..cc3d071 100644
--- a/include/vki-ppc32-linux.h
+++ b/include/vki-ppc32-linux.h
@@ -44,6 +44,7 @@
 typedef __signed__ short __vki_s16;
 typedef unsigned short __vki_u16;
 
+typedef __signed__ int __vki_s32;
 typedef unsigned int __vki_u32;
 
 typedef __signed__ long long __vki_s64;
diff --git a/include/vki-x86-linux.h b/include/vki-x86-linux.h
index f713fb3..ae73305 100644
--- a/include/vki-x86-linux.h
+++ b/include/vki-x86-linux.h
@@ -43,6 +43,7 @@
 typedef __signed__ short __vki_s16;
 typedef unsigned short __vki_u16;
 
+typedef __signed__ int __vki_s32;
 typedef unsigned int __vki_u32;
 
 typedef __signed__ long long __vki_s64;