diff -ur --new-file old/linux/net/atm/lec.c new/linux/net/atm/lec.c --- old/linux/net/atm/lec.c Tue Nov 3 18:57:03 1998 +++ new/linux/net/atm/lec.c Tue Nov 3 18:57:50 1998 @@ -32,16 +32,19 @@ #include "tunable.h" #include "resources.h" /* for bind_vcc() */ -#define DPRINTK(format,args...) -/* +#if 0 #define DPRINTK printk -*/ +#else +#define DPRINTK(format,args...) +#endif + #define DUMP_PACKETS 0 /* 0 = None, * 1 = 30 first bytes * 2 = Whole packet */ -#define LEC_UNRES_QUE_LEN 8 +#define LEC_UNRES_QUE_LEN 8 /* number of tx packets to queue for a + single destination while waiting for SVC */ static int lec_open(struct device *dev); static int lec_send_packet(struct sk_buff *skb, struct device *dev); @@ -102,9 +105,11 @@ static int lec_send_packet(struct sk_buff *skb, struct device *dev) { + struct sk_buff *skb2; struct lec_priv *priv = (struct lec_priv *)dev->priv; struct lecdatahdr_8023 *lec_h; struct atm_vcc *send_vcc; + struct lec_arp_table *entry = NULL; unsigned char *nb; #if DUMP_PACKETS > 0 char buf[300]; @@ -171,9 +176,9 @@ printk("%s...\n",buf); #endif /* DUMP_PACKETS > 0 */ /* Send to right vcc */ - send_vcc = lec_arp_resolve(priv, lec_h->h_dest); - DPRINTK("%s:send_vcc:%p vcc_flags:%x\n", dev->name, - send_vcc, send_vcc?send_vcc->flags:0); + send_vcc = lec_arp_resolve(priv, lec_h->h_dest, &entry); + DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name, + send_vcc, send_vcc?send_vcc->flags:0, entry); if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) { #if 0 /* 24.8.1998 hessu@cs.tut.fi */ priv->stats.tx_dropped++; @@ -183,7 +188,7 @@ dev->tbusy=0; return 0; #endif -#if 1 /* 26.8.1998 hessu@cs.tut.fi */ +#if 0 /* 26.8.1998 hessu@cs.tut.fi */ priv->stats.tx_errors++; printk("%s:lec_send_packet: handing back ", dev->name); printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -192,37 +197,73 @@ dev->tbusy = 1; return 1; #endif - } else { +#if 1 /* 30.10.1998 s156953@cs.tut.fi hessu@cs.tut.fi */ + if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { + printk("%s:lec_send_packet: queuing packet, ", dev->name); + printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], + lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + skb_queue_tail(&entry->tx_wait, skb); + } else { + printk("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name); + printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], + lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + priv->stats.tx_dropped++; + dev_kfree_skb(skb); + dev->tbusy = 0; + return 0; + } +#endif + + } + /* Minimum ethernet-frame size */ + if (skb->len <62) { + if (skb->truesize < 62) { + printk("%s:data packet %d / %d\n", + dev->name, + skb->len,skb->truesize); + nb=(unsigned char*)kmalloc(64, GFP_ATOMIC); + memcpy(nb,skb->data,skb->len); + kfree(skb->head); + skb->head = skb->data = nb; + skb->tail = nb+62; + skb->end = nb+64; + skb->len=62; + skb->truesize = 64; + } else { + skb->len = 62; + } + } + if(!send_vcc){ + dev->tbusy=0; + return 0; + } + #if DUMP_PACKETS > 0 - printk("%s:sending to vpi:%d vci:%d\n", dev->name, - send_vcc->vpi, send_vcc->vci); + printk("%s:sending to vpi:%d vci:%d\n", dev->name, + send_vcc->vpi, send_vcc->vci); #endif /* DUMP_PACKETS > 0 */ - ATM_SKB(skb)->vcc = send_vcc; - /* Minimum ethernet-frame size */ - if (skb->len <62) { - if (skb->truesize < 62) { - printk("%s:data packet %d / %d\n", - dev->name, - skb->len,skb->truesize); - nb=(unsigned char*)kmalloc(64, - GFP_ATOMIC); - memcpy(nb,skb->data,skb->len); - kfree(skb->head); - skb->head = skb->data = nb; - skb->tail = nb+62; - skb->end = nb+64; - skb->len=62; - skb->truesize = 64; - } else { - skb->len = 62; - } - } - atomic_add(skb->truesize, &send_vcc->tx_inuse); - ATM_SKB(skb)->iovcnt = 0; - ATM_SKB(skb)->atm_options = send_vcc->atm_options; - send_vcc->dev->ops->send(send_vcc, skb); + + while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { + printk("lec.c: emptying tx queue, "); + printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], + lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + ATM_SKB(skb2)->vcc = send_vcc; + atomic_add(skb2->truesize, &send_vcc->tx_inuse); + ATM_SKB(skb2)->iovcnt = 0; + ATM_SKB(skb2)->atm_options = send_vcc->atm_options; + send_vcc->dev->ops->send(send_vcc, skb2); priv->stats.tx_packets++; } + + ATM_SKB(skb)->vcc = send_vcc; + atomic_add(skb->truesize, &send_vcc->tx_inuse); + ATM_SKB(skb)->iovcnt = 0; + ATM_SKB(skb)->atm_options = send_vcc->atm_options; + send_vcc->dev->ops->send(send_vcc, skb); + priv->stats.tx_packets++; } /* Should we wait for card's device driver to notify us? */ dev->tbusy=0; @@ -1079,13 +1120,13 @@ if (remove_vcc) lec_arp_clear_vccs(to_remove); } + skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ restore_flags(flags); DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1], 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3], 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]); - - return 0; + return 0; } #if DEBUG_ARP_TABLE @@ -1254,6 +1295,7 @@ next = entry->next; del_timer(&entry->timer); lec_arp_clear_vccs(entry); + skb_queue_purge(&entry->tx_wait); kfree(entry); entry = next; } @@ -1263,6 +1305,7 @@ next = entry->next; del_timer(&entry->timer); lec_arp_clear_vccs(entry); + skb_queue_purge(&entry->tx_wait); kfree(entry); entry = next; } @@ -1320,6 +1363,7 @@ to_return->timer.data = (unsigned long)to_return; to_return->last_used = jiffies; to_return->priv = priv; + skb_queue_head_init(&to_return->tx_wait); return to_return; } @@ -1478,7 +1522,8 @@ * */ struct atm_vcc* -lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find) +lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, + struct lec_arp_table **ret_entry) { unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; struct lec_arp_table *entry; @@ -1503,6 +1548,7 @@ if (entry->status == ESI_FORWARD_DIRECT) { /* Connection Ok */ entry->last_used = jiffies; + *ret_entry = entry; return entry->vcc; } if (entry->status == ESI_UNKNOWN) { @@ -1519,6 +1565,7 @@ DPRINTK("LEC_ARP: Flooding..\n"); return priv->mcast_vcc; } + *ret_entry = entry; return NULL; } else { /* No matching entry was found */ @@ -1538,6 +1585,7 @@ entry->timer.expires = jiffies + (1*HZ); entry->timer.function = lec_arp_expire_arp; add_timer(&entry->timer); + *ret_entry = entry; return priv->mcast_vcc; } } @@ -1577,6 +1625,7 @@ unsigned int targetless_le_arp) { struct lec_arp_table *entry, *tmp; + struct sk_buff *skb; int i; DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " "); @@ -1616,6 +1665,8 @@ tmp->vcc = entry->vcc; tmp->old_push = entry->old_push; tmp->last_used = jiffies; + while((skb = skb_dequeue(&entry->tx_wait)) != NULL) + skb_queue_tail(&tmp->tx_wait, skb); kfree(entry); entry=tmp; } else { diff -ur --new-file old/linux/net/atm/lec_arpc.h new/linux/net/atm/lec_arpc.h --- old/linux/net/atm/lec_arpc.h Tue Nov 3 18:57:03 1998 +++ new/linux/net/atm/lec_arpc.h Tue Nov 3 18:57:50 1998 @@ -45,6 +45,7 @@ u8 *tlvs; /* LANE2: Each MAC address can have TLVs */ u32 sizeoftlvs; /* associated with it. sizeoftlvs tells the */ /* the length of the tlvs array */ + struct sk_buff_head tx_wait; /* wait queue for outgoing packets */ }; struct tlv { /* LANE2: Template tlv struct for accessing */ @@ -94,7 +95,8 @@ void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc); struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, - unsigned char *mac_to_addr); + unsigned char *mac_to_addr, + struct lec_arp_table **ret_entry); void lec_vcc_added(struct lec_priv *dev, struct atmlec_ioc *ioc_data, struct atm_vcc *vcc, void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb)); .