[linux-dvb] Patch for broken dst_ca

linuxtv at zacglen.com.au linuxtv at zacglen.com.au
Wed Apr 12 14:56:05 CEST 2006


Here is a patch for dst_ca.c which addresses the issue of
messages over 128 bytes long (when asn1 length is more than 1 byte).

Ok, so apparently nobody has this problem except myself.
Ok, so I have already posted about this but it has fallen on deaf ears.
Ok, so I also vote Abraham off as the weakest link.

Here is it (btw it also replicates some existing patches):
===============================================================================

--- kernel-2.6.14/linux-2.6.14/drivers/media/dvb/bt8xx/dst_ca.c.mxy	2005-10-28 10:02:08.000000000 +1000
+++ kernel-2.6.14/linux-2.6.14/drivers/media/dvb/bt8xx/dst_ca.c	2006-04-09 11:41:33.000000000 +1000
@@ -275,7 +275,7 @@
 	return 0;
 }
 
-static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
+static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, int lensize, struct ca_msg *hw_buffer, u32 length)
 {
 	if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
 		hw_buffer->msg[2] = p_ca_message->msg[1];	/*	MSB	*/
@@ -286,17 +286,26 @@
 			return -1;
 		}
 		hw_buffer->msg[0] = (length & 0xff) + 7;
+		/*
+		 * This is probably a resource, as per EN50221 8.2.2 Table 15.
+		 *	   type=1	 2 bits
+		 *	  class=3 (CA)	14 bits
+		 *	   type=0	10 bits
+		 *	version=3	 6 bits
+		 */
 		hw_buffer->msg[1] = 0x40;
 		hw_buffer->msg[2] = 0x03;
 		hw_buffer->msg[3] = 0x00;
 		hw_buffer->msg[4] = 0x03;
+
+		/* But this is odd ... not asn1, and lsb,msb? */
 		hw_buffer->msg[5] = length & 0xff;
 		hw_buffer->msg[6] = 0x00;
 		/*
 		 *	Need to compute length for EN50221 section 8.3.2, for the time being
 		 *	assuming 8.3.2 is not applicable
 		 */
-		memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
+		memcpy(&hw_buffer->msg[7], &p_ca_message->msg[3+lensize], length);
 	}
 	return 0;
 }
@@ -315,11 +324,12 @@
 	return 0;
 }
 
-u32 asn_1_decode(u8 *asn_1_array)
+u32 asn_1_decode(u8 *asn_1_array, int *plensize)
 {
 	u8 length_field = 0, word_count = 0, count = 0;
 	u32 length = 0;
 
+	*plensize = 1;
 	length_field = asn_1_array[0];
 	dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
 	if (length_field < 0x80) {
@@ -327,8 +337,10 @@
 		dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
 	} else {
 		word_count = length_field & 0x7f;
+		*plensize += word_count;
 		for (count = 0; count < word_count; count++) {
-			length = (length | asn_1_array[count + 1]) << 8;
+			length = length << 8;
+			length += asn_1_array[count + 1];
 			dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
 		}
 	}
@@ -350,14 +362,17 @@
 static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
 {
 	u32 length = 0;
-	u8 tag_length = 8;
+	u8 tag_length = 7+1;	/* 1 for checksum */
+	int	lensize = 0;
 
-	length = asn_1_decode(&p_ca_message->msg[3]);
+	length = asn_1_decode(&p_ca_message->msg[3], &lensize);
 	dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
-	debug_string(&p_ca_message->msg[4], length, 0); /*	length is excluding tag & length	*/
+	if (length > sizeof(p_ca_message->msg))
+	    return -1;
+	debug_string(&p_ca_message->msg[3+lensize], length, 0); /*	length is excluding tag & length	*/
 
 	memset(hw_buffer->msg, '\0', length);
-	handle_dst_tag(state, p_ca_message, hw_buffer, length);
+	handle_dst_tag(state, p_ca_message, lensize, hw_buffer, length);
 	put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
 
 	debug_string(hw_buffer->msg, (length + tag_length), 0); /*	tags too	*/
@@ -430,7 +445,7 @@
 
 		switch (command) {
 		case CA_PMT:
-			dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
+			dprintk(verbose, DST_CA_DEBUG, 1, "Command = CA_PMT");
 			if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {	// code simplification started
 				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
 				return -1;




More information about the linux-dvb mailing list