Browse code

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.

Andrei Pelinescu-Onciul authored on 21/05/2009 15:41:16
Showing 1 changed files
... ...
@@ -193,14 +193,27 @@ error:
193 193
    WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */
194 194
 static int sctp_init_sock_opt_common(int s)
195 195
 {
196
-	struct sctp_event_subscribe es;
197 196
 	int optval;
198 197
 	int pd_point;
199 198
 	int saved_errno;
200 199
 	socklen_t optlen;
201 200
 	int sctp_err;
201
+#ifdef __OS_linux
202
+	union {
203
+		struct sctp_event_subscribe s;
204
+		char padding[sizeof(struct sctp_event_subscribe)+sizeof(__u8)];
205
+	} es;
206
+#else
207
+	struct sctp_event_subscribe es;
208
+#endif
209
+	struct sctp_event_subscribe* ev_s;
202 210
 	
203 211
 	sctp_err=0;
212
+#ifdef __OS_linux
213
+	ev_s=&es.s;
214
+#else
215
+	ev_s=&es;
216
+#endif
204 217
 	/* set tos */
205 218
 	optval = tos;
206 219
 	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)
349 349
 	memset(&es, 0, sizeof(es));
350 350
 	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
351 351
 	 *  information in sctp_sndrcvinfo */
352
-	es.sctp_data_io_event=1;
352
+	ev_s->sctp_data_io_event=1;
353 353
 	/* enable association event notifications */
354
-	es.sctp_association_event=1; /* SCTP_ASSOC_CHANGE */
355
-	es.sctp_address_event=1;  /* enable address events notifications */
356
-	es.sctp_send_failure_event=1; /* SCTP_SEND_FAILED */
357
-	es.sctp_peer_error_event=1;   /* SCTP_REMOTE_ERROR */
358
-	es.sctp_shutdown_event=1;     /* SCTP_SHUTDOWN_EVENT */
359
-	es.sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */
360
-	/* es.sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/
361
-	/* es.sctp_authentication_event=1; -- not supported on linux 2.6.25 */
354
+	ev_s->sctp_association_event=1; /* SCTP_ASSOC_CHANGE */
355
+	ev_s->sctp_address_event=1;  /* enable address events notifications */
356
+	ev_s->sctp_send_failure_event=1; /* SCTP_SEND_FAILED */
357
+	ev_s->sctp_peer_error_event=1;   /* SCTP_REMOTE_ERROR */
358
+	ev_s->sctp_shutdown_event=1;     /* SCTP_SHUTDOWN_EVENT */
359
+	ev_s->sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */
360
+	/* ev_s->sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/
361
+	/* ev_s->sctp_authentication_event=1; -- not supported on linux 2.6.25 */
362 362
 	
363 363
 	/* enable the SCTP_EVENTS */
364 364
 #ifdef SCTP_EVENTS
365
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, &es, sizeof(es))==-1){
365
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s))==-1){
366
+		/* on linux the checks for the struct sctp_event_subscribe size
367
+		   are too strict, making certain lksctp/kernel combination
368
+		   unworkable => since we don't use the extra information
369
+		   (sctp_authentication_event) added in newer version, we can
370
+		   try with different sizes) */
371
+#ifdef __OS_linux
372
+		/* 1. lksctp 1.0.9 with kernel < 2.6.26 -> kernel expects 
373
+		      the structure without the authentication event member */
374
+		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s)-1)==0)
375
+			goto ev_success;
376
+		/* 2. lksctp < 1.0.9? with kernel >= 2.6.26: the sctp.h structure
377
+		   does not have the authentication member, but the newer kernels 
378
+		   check only for optlen > sizeof(...) => we should never reach
379
+		   this point. */
380
+		/* 3. just to be foolproof if we reached this point, try
381
+		    with a bigger size before giving up  (out of desperation) */
382
+		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(es))==0)
383
+			goto ev_success;
384
+
385
+#endif
366 386
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
367 387
 				"SCTP_EVENTS: %s\n", strerror(errno));
368 388
 		sctp_err++;
369
-		/* non critical, try to continue */
389
+		goto error; /* critical */
370 390
 	}
391
+#ifdef __OS_linux
392
+ev_success:
393
+#endif
371 394
 #else
372
-#warning no sctp lib support for SCTP_EVENTS, consider upgrading
395
+#error no sctp lib support for SCTP_EVENTS, consider upgrading
373 396
 #endif /* SCTP_EVENTS */
374 397
 	
375 398
 	if (sctp_err){