Commit 55c5396a authored by Duncan Sands's avatar Duncan Sands Committed by Greg Kroah-Hartman

[PATCH] USB speedtouch: per vcc data cleanups

Use struct list_head rather than a singly linked list in udsl_vcc_data.  Reject
attempts to open multiple vccs with the same vpi/vci pair.  Some cleanups too.
parent 104f1bec
...@@ -150,10 +150,9 @@ struct udsl_control { ...@@ -150,10 +150,9 @@ struct udsl_control {
struct udsl_vcc_data { struct udsl_vcc_data {
/* vpi/vci lookup */ /* vpi/vci lookup */
struct udsl_vcc_data *next; struct list_head list;
unsigned int vpi; short vpi;
unsigned int vci; int vci;
unsigned long atmHeader;
struct atm_vcc *vcc; struct atm_vcc *vcc;
/* raw cell reassembly */ /* raw cell reassembly */
...@@ -175,7 +174,7 @@ struct udsl_instance_data { ...@@ -175,7 +174,7 @@ struct udsl_instance_data {
/* atm device part */ /* atm device part */
struct atm_dev *atm_dev; struct atm_dev *atm_dev;
struct udsl_vcc_data *vcc_list; struct list_head vcc_list;
/* receiving */ /* receiving */
struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS]; struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS];
...@@ -247,11 +246,19 @@ static struct usb_driver udsl_usb_driver = { ...@@ -247,11 +246,19 @@ static struct usb_driver udsl_usb_driver = {
** decode ** ** decode **
*************/ *************/
#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK) static inline struct udsl_vcc_data *udsl_find_vcc (struct udsl_instance_data *instance, short vpi, int vci)
{
struct udsl_vcc_data *vcc;
list_for_each_entry (vcc, &instance->vcc_list, list)
if ((vcc->vpi == vpi) && (vcc->vci == vci))
return vcc;
return NULL;
}
static struct sk_buff *udsl_decode_rawcell (struct udsl_vcc_data *list, struct sk_buff *skb, struct udsl_vcc_data **ctx) static struct sk_buff *udsl_decode_rawcell (struct udsl_instance_data *instance, struct sk_buff *skb, struct udsl_vcc_data **ctx)
{ {
if (!list || !skb || !ctx) if (!instance || !skb || !ctx)
return NULL; return NULL;
if (!skb->data || !skb->tail) if (!skb->data || !skb->tail)
return NULL; return NULL;
...@@ -259,68 +266,66 @@ static struct sk_buff *udsl_decode_rawcell (struct udsl_vcc_data *list, struct s ...@@ -259,68 +266,66 @@ static struct sk_buff *udsl_decode_rawcell (struct udsl_vcc_data *list, struct s
while (skb->len) { while (skb->len) {
unsigned char *cell = skb->data; unsigned char *cell = skb->data;
unsigned char *cell_payload; unsigned char *cell_payload;
struct udsl_vcc_data *vcc = list; struct udsl_vcc_data *vcc;
unsigned long atmHeader = short vpi;
((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) | int vci;
((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
dbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", list, skb, ctx); vpi = ((cell[0] & 0x0f) << 4) | (cell[1] >> 4);
vci = ((cell[1] & 0x0f) << 12) | (cell[2] << 4) | (cell[3] >> 4);
dbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", instance, skb, ctx);
dbg ("udsl_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail); dbg ("udsl_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail);
/* here should the header CRC check be... */ /* here should the header CRC check be... */
/* look up correct vcc */ if (!(vcc = udsl_find_vcc (instance, vpi, vci)))
for (; dbg ("udsl_decode_rawcell: no vcc found for packet on vpi %d, vci %d", vpi, vci);
vcc else {
&& ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK)); dbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc, vpi, vci);
vcc = vcc->next);
if (skb->len >= 53) {
dbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc, cell_payload = cell + 5;
(int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
(int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT)); if (!vcc->reasBuffer)
vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
if (vcc && (skb->len >= 53)) {
cell_payload = cell + 5; /* if alloc fails, we just drop the cell. it is possible that we can still
* receive cells on other vcc's
if (!vcc->reasBuffer) */
vcc->reasBuffer = dev_alloc_skb (vcc->mtu); if (vcc->reasBuffer) {
/* if (buffer overrun) discard received cells until now */
/* if alloc fails, we just drop the cell. it is possible that we can still if ((vcc->reasBuffer->len) > (vcc->mtu - 48))
* receive cells on other vcc's skb_trim (vcc->reasBuffer, 0);
*/
if (vcc->reasBuffer) { /* copy data */
/* if (buffer overrun) discard received cells until now */ memcpy (vcc->reasBuffer->tail, cell_payload, 48);
if ((vcc->reasBuffer->len) > (vcc->mtu - 48)) skb_put (vcc->reasBuffer, 48);
skb_trim (vcc->reasBuffer, 0);
/* check for end of buffer */
/* copy data */ if (cell[3] & 0x2) {
memcpy (vcc->reasBuffer->tail, cell_payload, 48); struct sk_buff *tmp;
skb_put (vcc->reasBuffer, 48);
/* the aal5 buffer ends here, cut the buffer. */
/* check for end of buffer */ /* buffer will always have at least one whole cell, so */
if (cell[3] & 0x2) { /* don't need to check return from skb_pull */
struct sk_buff *tmp; skb_pull (skb, 53);
*ctx = vcc;
/* the aal5 buffer ends here, cut the buffer. */ tmp = vcc->reasBuffer;
/* buffer will always have at least one whole cell, so */ vcc->reasBuffer = NULL;
/* don't need to check return from skb_pull */
skb_pull (skb, 53); dbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp->len);
*ctx = vcc; return tmp;
tmp = vcc->reasBuffer; }
vcc->reasBuffer = NULL;
dbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp->len);
return tmp;
} }
/* flush the cell */
/* buffer will always contain at least one whole cell, so don't */
/* need to check return value from skb_pull */
skb_pull (skb, 53);
} else {
/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
if (skb_pull (skb, 53) == NULL)
return NULL;
} }
/* flush the cell */
/* buffer will always contain at least one whole cell, so don't */
/* need to check return value from skb_pull */
skb_pull (skb, 53);
} else {
/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
if (skb_pull (skb, 53) == NULL)
return NULL;
} }
} }
...@@ -342,8 +347,7 @@ static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_bu ...@@ -342,8 +347,7 @@ static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_bu
(skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1]; (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
pdu_length = ((length + 47 + 8) / 48) * 48; pdu_length = ((length + 47 + 8) / 48) * 48;
dbg ("udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", dbg ("udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", skb->len, length, pdu_crc, pdu_length);
skb->len, length, pdu_crc, pdu_length);
/* is skb long enough ? */ /* is skb long enough ? */
if (skb->len < pdu_length) { if (skb->len < pdu_length) {
...@@ -354,8 +358,7 @@ static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_bu ...@@ -354,8 +358,7 @@ static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_bu
/* is skb too long ? */ /* is skb too long ? */
if (skb->len > pdu_length) { if (skb->len > pdu_length) {
dbg ("udsl_decode_aal5: Warning: readjusting illegal size %d -> %d", dbg ("udsl_decode_aal5: Warning: readjusting illegal size %d -> %d", skb->len, pdu_length);
skb->len, pdu_length);
/* buffer is too long. we can try to recover /* buffer is too long. we can try to recover
* if we discard the first part of the skb. * if we discard the first part of the skb.
* the crc will decide whether this was ok * the crc will decide whether this was ok
...@@ -548,7 +551,7 @@ static void udsl_process_receive (unsigned long data) ...@@ -548,7 +551,7 @@ static void udsl_process_receive (unsigned long data)
dbg ("skb->len = %d", skb->len); dbg ("skb->len = %d", skb->len);
PACKETDEBUG (skb->data, skb->len); PACKETDEBUG (skb->data, skb->len);
while ((new = udsl_decode_rawcell (instance->vcc_list, skb, &atmsar_vcc))) { while ((new = udsl_decode_rawcell (instance, skb, &atmsar_vcc))) {
dbg ("(after cell processing)skb->len = %d", new->len); dbg ("(after cell processing)skb->len = %d", new->len);
tmp = new; tmp = new;
...@@ -923,94 +926,81 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) ...@@ -923,94 +926,81 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
return -ENODEV; return -ENODEV;
} }
if ((vpi == ATM_VPI_ANY) || (vci == ATM_VCI_ANY))
return -EINVAL;
/* only support AAL5 */ /* only support AAL5 */
if (vcc->qos.aal != ATM_AAL5) if (vcc->qos.aal != ATM_AAL5)
return -EINVAL; return -EINVAL;
if (udsl_find_vcc (instance, vpi, vci))
return -EADDRINUSE;
if (!(new = kmalloc (sizeof (struct udsl_vcc_data), GFP_KERNEL))) if (!(new = kmalloc (sizeof (struct udsl_vcc_data), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
MOD_INC_USE_COUNT;
memset (new, 0, sizeof (struct udsl_vcc_data)); memset (new, 0, sizeof (struct udsl_vcc_data));
new->vcc = vcc; new->vcc = vcc;
new->vpi = vpi; new->vpi = vpi;
new->vci = vci; new->vci = vci;
new->mtu = UDSL_MAX_AAL5_MRU; new->mtu = UDSL_MAX_AAL5_MRU;
new->atmHeader = ((unsigned long) vpi << ATM_HDR_VPI_SHIFT) |
((unsigned long) vci << ATM_HDR_VCI_SHIFT);
new->reasBuffer = NULL;
new->next = instance->vcc_list;
instance->vcc_list = new;
dbg ("Allocated new SARLib vcc 0x%p with vpi %d vci %d", new, vpi, vci);
vcc->dev_data = new; vcc->dev_data = new;
vcc->vpi = vpi; vcc->vpi = vpi;
vcc->vci = vci; vcc->vci = vci;
list_add (&new->list, &instance->vcc_list);
set_bit (ATM_VF_ADDR, &vcc->flags); set_bit (ATM_VF_ADDR, &vcc->flags);
set_bit (ATM_VF_PARTIAL, &vcc->flags); set_bit (ATM_VF_PARTIAL, &vcc->flags);
set_bit (ATM_VF_READY, &vcc->flags); set_bit (ATM_VF_READY, &vcc->flags);
dbg ("Allocated new SARLib vcc 0x%p with vpi %d vci %d", new, vpi, vci);
MOD_INC_USE_COUNT;
if (instance->firmware_loaded) if (instance->firmware_loaded)
udsl_fire_receivers (instance); udsl_fire_receivers (instance);
dbg ("udsl_atm_open successful"); dbg ("udsl_atm_open successful");
return 0; return 0;
} }
static void udsl_atm_close (struct atm_vcc *vcc) static void udsl_atm_close (struct atm_vcc *vcc)
{ {
struct udsl_instance_data *instance = vcc->dev->dev_data; struct udsl_instance_data *instance = vcc->dev->dev_data;
struct udsl_vcc_data *work; struct udsl_vcc_data *vcc_data = vcc->dev_data;
dbg ("udsl_atm_close called"); dbg ("udsl_atm_close called");
if (!instance) { if (!instance || !vcc_data) {
dbg ("NULL instance!"); dbg ("NULL data!");
return; return;
} }
/* freeing resources */ dbg ("Deallocating SARLib vcc 0x%p with vpi %d vci %d", vcc_data, vcc_data->vpi, vcc_data->vci);
/* cancel all sends on this vcc */
udsl_cancel_send (instance, vcc);
if (instance->vcc_list == vcc->dev_data) { udsl_cancel_send (instance, vcc);
instance->vcc_list = instance->vcc_list->next;
} else {
for (work = instance->vcc_list; work && work->next && (work->next != vcc->dev_data); work = work->next);
/* return if not found */
if (work->next != vcc->dev_data)
BUG ();
work->next = work->next->next;
}
if (((struct udsl_vcc_data *)vcc->dev_data)->reasBuffer) {
dev_kfree_skb (((struct udsl_vcc_data *)vcc->dev_data)->reasBuffer);
}
dbg ("Deallocated SARLib vcc 0x%p with vpi %d vci %d", vcc->dev_data, vcc->dev_data->vpi, vcc->dev_data->vci); list_del (&vcc_data->list);
kfree (vcc->dev_data); if (vcc_data->reasBuffer)
kfree_skb (vcc_data->reasBuffer);
vcc_data->reasBuffer = NULL;
kfree (vcc_data);
vcc->dev_data = NULL; vcc->dev_data = NULL;
clear_bit (ATM_VF_PARTIAL, &vcc->flags);
/* freeing address */
vcc->vpi = ATM_VPI_UNSPEC; vcc->vpi = ATM_VPI_UNSPEC;
vcc->vci = ATM_VCI_UNSPEC; vcc->vci = ATM_VCI_UNSPEC;
clear_bit (ATM_VF_READY, &vcc->flags);
clear_bit (ATM_VF_PARTIAL, &vcc->flags);
clear_bit (ATM_VF_ADDR, &vcc->flags); clear_bit (ATM_VF_ADDR, &vcc->flags);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
dbg ("udsl_atm_close successful"); dbg ("udsl_atm_close successful");
return;
} }
static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg) static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
...@@ -1089,6 +1079,8 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i ...@@ -1089,6 +1079,8 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
instance->usb_dev = dev; instance->usb_dev = dev;
INIT_LIST_HEAD (&instance->vcc_list);
spin_lock_init (&instance->spare_receivers_lock); spin_lock_init (&instance->spare_receivers_lock);
INIT_LIST_HEAD (&instance->spare_receivers); INIT_LIST_HEAD (&instance->spare_receivers);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment