[SR-Dev] git:ser_core_cvs: sctp: compatibility with older linux kernels

Andrei Pelinescu-Onciul andrei at iptel.org
Thu May 21 17:47:38 CEST 2009


Module: sip-router
Branch: ser_core_cvs
Commit: e5064a814654a71dc2aa28c5fe2bd6fbba76e62c
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=e5064a814654a71dc2aa28c5fe2bd6fbba76e62c

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at iptel.org>
Date:   Thu May 21 15:41:16 2009 +0000

sctp: compatibility with older linux kernels

- try hard to workaround compatibility problems between lksctp
  userspace (sctp.h) and kernel side: older kernelsi (<2.6.26)
  expect a certain size for the sctp_event_subscribe structure
  (SCTP_EVENTS sock. opt), leading to problems when using newer
  lksctp userspace (>=1.0.9) which adds an additional member to
  the structure => if the SCTP_EVENTS setsockopt() fails, try with
  different sizes (since we don't care about authentication events
  anyway).
- failure to enable SCTP_EVENTS upgraded to critical: ser will not
  start.

---

 sctp_server.c |   62 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/sctp_server.c b/sctp_server.c
index 424def8..d559ce3 100644
--- a/sctp_server.c
+++ b/sctp_server.c
@@ -193,14 +193,27 @@ error:
    WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */
 static int sctp_init_sock_opt_common(int s)
 {
-	struct sctp_event_subscribe es;
 	int optval;
 	int pd_point;
 	int saved_errno;
 	socklen_t optlen;
 	int sctp_err;
+#ifdef __OS_linux
+	union {
+		struct sctp_event_subscribe s;
+		char padding[sizeof(struct sctp_event_subscribe)+sizeof(__u8)];
+	} es;
+#else
+	struct sctp_event_subscribe es;
+#endif
+	struct sctp_event_subscribe* ev_s;
 	
 	sctp_err=0;
+#ifdef __OS_linux
+	ev_s=&es.s;
+#else
+	ev_s=&es;
+#endif
 	/* set tos */
 	optval = tos;
 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,sizeof(optval)) ==-1){
@@ -349,27 +362,50 @@ static int sctp_init_sock_opt_common(int s)
 	memset(&es, 0, sizeof(es));
 	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
 	 *  information in sctp_sndrcvinfo */
-	es.sctp_data_io_event=1;
+	ev_s->sctp_data_io_event=1;
 	/* enable association event notifications */
-	es.sctp_association_event=1; /* SCTP_ASSOC_CHANGE */
-	es.sctp_address_event=1;  /* enable address events notifications */
-	es.sctp_send_failure_event=1; /* SCTP_SEND_FAILED */
-	es.sctp_peer_error_event=1;   /* SCTP_REMOTE_ERROR */
-	es.sctp_shutdown_event=1;     /* SCTP_SHUTDOWN_EVENT */
-	es.sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */
-	/* es.sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/
-	/* es.sctp_authentication_event=1; -- not supported on linux 2.6.25 */
+	ev_s->sctp_association_event=1; /* SCTP_ASSOC_CHANGE */
+	ev_s->sctp_address_event=1;  /* enable address events notifications */
+	ev_s->sctp_send_failure_event=1; /* SCTP_SEND_FAILED */
+	ev_s->sctp_peer_error_event=1;   /* SCTP_REMOTE_ERROR */
+	ev_s->sctp_shutdown_event=1;     /* SCTP_SHUTDOWN_EVENT */
+	ev_s->sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */
+	/* ev_s->sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/
+	/* ev_s->sctp_authentication_event=1; -- not supported on linux 2.6.25 */
 	
 	/* enable the SCTP_EVENTS */
 #ifdef SCTP_EVENTS
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, &es, sizeof(es))==-1){
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s))==-1){
+		/* on linux the checks for the struct sctp_event_subscribe size
+		   are too strict, making certain lksctp/kernel combination
+		   unworkable => since we don't use the extra information
+		   (sctp_authentication_event) added in newer version, we can
+		   try with different sizes) */
+#ifdef __OS_linux
+		/* 1. lksctp 1.0.9 with kernel < 2.6.26 -> kernel expects 
+		      the structure without the authentication event member */
+		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s)-1)==0)
+			goto ev_success;
+		/* 2. lksctp < 1.0.9? with kernel >= 2.6.26: the sctp.h structure
+		   does not have the authentication member, but the newer kernels 
+		   check only for optlen > sizeof(...) => we should never reach
+		   this point. */
+		/* 3. just to be foolproof if we reached this point, try
+		    with a bigger size before giving up  (out of desperation) */
+		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(es))==0)
+			goto ev_success;
+
+#endif
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
 				"SCTP_EVENTS: %s\n", strerror(errno));
 		sctp_err++;
-		/* non critical, try to continue */
+		goto error; /* critical */
 	}
+#ifdef __OS_linux
+ev_success:
+#endif
 #else
-#warning no sctp lib support for SCTP_EVENTS, consider upgrading
+#error no sctp lib support for SCTP_EVENTS, consider upgrading
 #endif /* SCTP_EVENTS */
 	
 	if (sctp_err){




More information about the sr-dev mailing list