ChangeSet 1.1043.1.7, 2003/02/16 09:39:17-08:00, duncan.sands@math.u-psud.fr

[PATCH] USB speedtouch: on-the-fly AAL5/ATM encoding for speedtouch

Add a new encoding routine, udsl_write_cell, which extracts one ATM cell from a skb
and writes it, doing the AAL5/ATM encoding on the fly.  To make this possible, various
bits of info about the AAL5/ATM structure need to be stored beforehand in the skb.
This is done by udsl_groom_skb using the udsl_control structure introduced in the
previous patch.


diff -Nru a/drivers/usb/misc/speedtouch.c b/drivers/usb/misc/speedtouch.c
--- a/drivers/usb/misc/speedtouch.c	Tue Feb 18 16:42:23 2003
+++ b/drivers/usb/misc/speedtouch.c	Tue Feb 18 16:42:23 2003
@@ -242,6 +242,86 @@
 };
 
 
+/*************
+**  encode  **
+*************/
+
+static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb) {
+	struct udsl_control *ctrl = UDSL_SKB (skb);
+	unsigned int zero_padding;
+	int i;
+	u32 crc;
+
+	ctrl->atm_data.vcc = vcc;
+	ctrl->cell_header [0] = vcc->vpi >> 4;
+	ctrl->cell_header [1] = (vcc->vpi << 4) | (vcc->vci >> 12);
+	ctrl->cell_header [2] = vcc->vci >> 4;
+	ctrl->cell_header [3] = vcc->vci << 4;
+	ctrl->cell_header [4] = 0xec;
+
+	ctrl->num_cells = (skb->len + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD;
+	ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
+
+	zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
+
+	if (ctrl->num_entire + 1 < ctrl->num_cells)
+		ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
+	else
+		ctrl->pdu_padding = zero_padding;
+
+	ctrl->aal5_trailer [0] = 0; /* UU = 0 */
+	ctrl->aal5_trailer [1] = 0; /* CPI = 0 */
+	ctrl->aal5_trailer [2] = skb->len >> 8;
+	ctrl->aal5_trailer [3] = skb->len;
+
+	crc = crc32 (~0, skb->data, skb->len);
+	for (i = 0; i < zero_padding; i++)
+		crc = CRC32 (0, crc);
+	crc = crc32 (crc, ctrl->aal5_trailer, 4);
+	crc = ~crc;
+
+	ctrl->aal5_trailer [4] = crc >> 24;
+	ctrl->aal5_trailer [5] = crc >> 16;
+	ctrl->aal5_trailer [6] = crc >> 8;
+	ctrl->aal5_trailer [7] = crc;
+}
+
+static char *udsl_write_cell (struct sk_buff *skb, char *target) {
+	struct udsl_control *ctrl = UDSL_SKB (skb);
+
+	ctrl->num_cells--;
+
+	memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
+	target += ATM_CELL_HEADER;
+
+	if (ctrl->num_entire) {
+		ctrl->num_entire--;
+		memcpy (target, skb->data, ATM_CELL_PAYLOAD);
+		target += ATM_CELL_PAYLOAD;
+		__skb_pull (skb, ATM_CELL_PAYLOAD);
+		return target;
+	}
+
+	memcpy (target, skb->data, skb->len);
+	target += skb->len;
+	__skb_pull (skb, skb->len);
+
+	memset (target, 0, ctrl->pdu_padding);
+	target += ctrl->pdu_padding;
+
+	if (ctrl->num_cells) {
+		ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
+	} else {
+		memcpy (target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
+		target += ATM_AAL5_TRAILER;
+		/* set pti bit in last cell */
+		*(target + 3 - ATM_CELL_SIZE) |= 0x2;
+	}
+
+	return target;
+}
+
+
 /**************
 **  receive  **
 **************/
