Commit 37b4c9bd authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.5

parent b12c3ada
VERSION = 1 VERSION = 1
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 4 SUBLEVEL = 5
all: Version zImage all: Version zImage
......
...@@ -50,23 +50,17 @@ loopback_xmit(struct sk_buff *skb, struct device *dev) ...@@ -50,23 +50,17 @@ loopback_xmit(struct sk_buff *skb, struct device *dev)
cli(); cli();
if (dev->tbusy != 0) { if (dev->tbusy != 0) {
sti(); sti();
printk("loopback error: called by %08lx\n",
((unsigned long *)&skb)[-1]);
stats->tx_errors++; stats->tx_errors++;
return(1); return(1);
} }
dev->tbusy = 1; dev->tbusy = 1;
sti(); sti();
start_bh_atomic();
done = dev_rint(skb->data, skb->len, 0, dev); done = dev_rint(skb->data, skb->len, 0, dev);
if (skb->free) kfree_skb(skb, FREE_WRITE); if (skb->free) kfree_skb(skb, FREE_WRITE);
end_bh_atomic();
while (done != 1) { while (done != 1) {
start_bh_atomic();
done = dev_rint(NULL, 0, 0, dev); done = dev_rint(NULL, 0, 0, dev);
end_bh_atomic();
} }
stats->tx_packets++; stats->tx_packets++;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* Alan Cox : Make ARP add its own protocol entry * Alan Cox : Make ARP add its own protocol entry
* *
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -58,10 +58,10 @@ ...@@ -58,10 +58,10 @@
* This structure defines the ARP mapping cache. As long as we make changes * This structure defines the ARP mapping cache. As long as we make changes
* in this structure, we keep interrupts of. But normally we can copy the * in this structure, we keep interrupts of. But normally we can copy the
* hardware address and the device pointer in a local variable and then make * hardware address and the device pointer in a local variable and then make
* any "long calls" to send a packet out. * any "long calls" to send a packet out.
*/ */
struct arp_table struct arp_table
{ {
struct arp_table *next; /* Linked entry list */ struct arp_table *next; /* Linked entry list */
unsigned long last_used; /* For expiry */ unsigned long last_used; /* For expiry */
...@@ -73,19 +73,19 @@ struct arp_table ...@@ -73,19 +73,19 @@ struct arp_table
struct device *dev; /* Device the entry is tied to */ struct device *dev; /* Device the entry is tied to */
/* /*
* The following entries are only used for unresolved hw addresses. * The following entries are only used for unresolved hw addresses.
*/ */
struct timer_list timer; /* expire timer */ struct timer_list timer; /* expire timer */
int retries; /* remaining retries */ int retries; /* remaining retries */
struct sk_buff_head skb; /* list of queued packets */ struct sk_buff_head skb; /* list of queued packets */
}; };
/* /*
* This structure defines an ethernet arp header. * This structure defines an ethernet arp header.
*/ */
struct arphdr struct arphdr
{ {
unsigned short ar_hrd; /* format of hardware address */ unsigned short ar_hrd; /* format of hardware address */
unsigned short ar_pro; /* format of protocol address */ unsigned short ar_pro; /* format of protocol address */
...@@ -108,31 +108,31 @@ struct arphdr ...@@ -108,31 +108,31 @@ struct arphdr
/* /*
* Configurable Parameters (don't touch unless you know what you are doing * Configurable Parameters (don't touch unless you know what you are doing
*/ */
/* /*
* If an arp request is send, ARP_RES_TIME is the timeout value until the * If an arp request is send, ARP_RES_TIME is the timeout value until the
* next request is send. * next request is send.
*/ */
#define ARP_RES_TIME (250*(HZ/10)) #define ARP_RES_TIME (250*(HZ/10))
/* /*
* The number of times an arp request is send, until the host is * The number of times an arp request is send, until the host is
* considered unreachable. * considered unreachable.
*/ */
#define ARP_MAX_TRIES 3 #define ARP_MAX_TRIES 3
/* /*
* After that time, an unused entry is deleted from the arp table. * After that time, an unused entry is deleted from the arp table.
*/ */
#define ARP_TIMEOUT (600*HZ) #define ARP_TIMEOUT (600*HZ)
/* /*
* How often is the function 'arp_check_retries' called. * How often is the function 'arp_check_retries' called.
* An entry is invalidated in the time between ARP_TIMEOUT and * An entry is invalidated in the time between ARP_TIMEOUT and
* (ARP_TIMEOUT+ARP_CHECK_INTERVAL). * (ARP_TIMEOUT+ARP_CHECK_INTERVAL).
*/ */
#define ARP_CHECK_INTERVAL (60 * HZ) #define ARP_CHECK_INTERVAL (60 * HZ)
...@@ -147,27 +147,27 @@ static struct timer_list arp_timer = ...@@ -147,27 +147,27 @@ static struct timer_list arp_timer =
/* /*
* The size of the hash table. Must be a power of two. * The size of the hash table. Must be a power of two.
* Maybe we should remove hashing in the future for arp and concentrate * Maybe we should remove hashing in the future for arp and concentrate
* on Patrick Schaaf's Host-Cache-Lookup... * on Patrick Schaaf's Host-Cache-Lookup...
*/ */
#define ARP_TABLE_SIZE 16 #define ARP_TABLE_SIZE 16
struct arp_table *arp_tables[ARP_TABLE_SIZE] = struct arp_table *arp_tables[ARP_TABLE_SIZE] =
{ {
NULL, NULL,
}; };
/* /*
* The last bits in the IP address are used for the cache lookup. * The last bits in the IP address are used for the cache lookup.
*/ */
#define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1)) #define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1))
/* /*
* Number of proxy arp entries. This is normally zero and we use it to do * Number of proxy arp entries. This is normally zero and we use it to do
* some optimizing for normal uses * some optimizing for normal uses.
*/ */
static int proxies = 0; static int proxies = 0;
...@@ -176,9 +176,9 @@ static int proxies = 0; ...@@ -176,9 +176,9 @@ static int proxies = 0;
* flag is set, they are always left in the arp cache (permanent entry). * flag is set, they are always left in the arp cache (permanent entry).
* Note: Only fully resolved entries, which don't have any packets in * Note: Only fully resolved entries, which don't have any packets in
* the queue, can be deleted, since ARP_TIMEOUT is much greater than * the queue, can be deleted, since ARP_TIMEOUT is much greater than
* ARP_MAX_TRIES*ARP_RES_TIME. * ARP_MAX_TRIES*ARP_RES_TIME.
*/ */
static void arp_check_expire(unsigned long dummy) static void arp_check_expire(unsigned long dummy)
{ {
int i; int i;
...@@ -186,43 +186,43 @@ static void arp_check_expire(unsigned long dummy) ...@@ -186,43 +186,43 @@ static void arp_check_expire(unsigned long dummy)
unsigned long flags; unsigned long flags;
save_flags(flags); save_flags(flags);
cli(); cli();
for (i = 0; i < ARP_TABLE_SIZE; i++) for (i = 0; i < ARP_TABLE_SIZE; i++)
{ {
struct arp_table *entry; struct arp_table *entry;
struct arp_table **pentry = &arp_tables[i]; struct arp_table **pentry = &arp_tables[i];
while ((entry = *pentry) != NULL) while ((entry = *pentry) != NULL)
{ {
if ((now - entry->last_used) > ARP_TIMEOUT if ((now - entry->last_used) > ARP_TIMEOUT
&& !(entry->flags & ATF_PERM)) && !(entry->flags & ATF_PERM))
{ {
*pentry = entry->next; /* remove from list */ *pentry = entry->next; /* remove from list */
if (entry->flags & ATF_PUBL) if (entry->flags & ATF_PUBL)
proxies--; proxies--;
del_timer(&entry->timer); /* Paranoia */ del_timer(&entry->timer); /* Paranoia */
kfree_s(entry, sizeof(struct arp_table)); kfree_s(entry, sizeof(struct arp_table));
} }
else else
pentry = &entry->next; /* go to next entry */ pentry = &entry->next; /* go to next entry */
} }
} }
restore_flags(flags); restore_flags(flags);
/* /*
* Set the timer again. * Set the timer again.
*/ */
del_timer(&arp_timer); del_timer(&arp_timer);
arp_timer.expires = ARP_CHECK_INTERVAL; arp_timer.expires = ARP_CHECK_INTERVAL;
add_timer(&arp_timer); add_timer(&arp_timer);
} }
/* /*
* Release all linked skb's and the memory for this entry. * Release all linked skb's and the memory for this entry.
*/ */
static void arp_release_entry(struct arp_table *entry) static void arp_release_entry(struct arp_table *entry)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -230,7 +230,7 @@ static void arp_release_entry(struct arp_table *entry) ...@@ -230,7 +230,7 @@ static void arp_release_entry(struct arp_table *entry)
if (entry->flags & ATF_PUBL) if (entry->flags & ATF_PUBL)
proxies--; proxies--;
/* Release the list of `skb' pointers. */ /* Release the list of `skb' pointers. */
while ((skb = skb_dequeue(&entry->skb)) != NULL) while ((skb = skb_dequeue(&entry->skb)) != NULL)
{ {
if (skb->free) if (skb->free)
kfree_skb(skb, FREE_WRITE); kfree_skb(skb, FREE_WRITE);
...@@ -243,9 +243,9 @@ static void arp_release_entry(struct arp_table *entry) ...@@ -243,9 +243,9 @@ static void arp_release_entry(struct arp_table *entry)
/* /*
* Create and send an arp packet. If (dest_hw == NULL), we create a broadcast * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast
* message. * message.
*/ */
static void arp_send(int type, unsigned long dest_ip, struct device *dev, static void arp_send(int type, unsigned long dest_ip, struct device *dev,
unsigned long src_ip, unsigned char *dest_hw, unsigned char *src_hw) unsigned long src_ip, unsigned char *dest_hw, unsigned char *src_hw)
{ {
...@@ -256,17 +256,17 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev, ...@@ -256,17 +256,17 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev,
/* /*
* No arp on this interface. * No arp on this interface.
*/ */
if(dev->flags&IFF_NOARP) if(dev->flags&IFF_NOARP)
return; return;
/* /*
* Allocate a buffer * Allocate a buffer
*/ */
skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
+ dev->hard_header_len, GFP_ATOMIC); + dev->hard_header_len, GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
{ {
printk("ARP: no memory to send an arp packet\n"); printk("ARP: no memory to send an arp packet\n");
return; return;
...@@ -277,7 +277,7 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev, ...@@ -277,7 +277,7 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev,
skb->free = 1; skb->free = 1;
/* /*
* Fill the device header for the ARP frame * Fill the device header for the ARP frame
*/ */
dev->hard_header(skb->data,dev,ETH_P_ARP,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len,skb); dev->hard_header(skb->data,dev,ETH_P_ARP,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len,skb);
...@@ -285,17 +285,17 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev, ...@@ -285,17 +285,17 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev,
/* Fill out the arp protocol part. */ /* Fill out the arp protocol part. */
arp = (struct arphdr *) (skb->data + dev->hard_header_len); arp = (struct arphdr *) (skb->data + dev->hard_header_len);
arp->ar_hrd = htons(dev->type); arp->ar_hrd = htons(dev->type);
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
arp->ar_pro = (dev->type != ARPHRD_AX25)? htons(ETH_P_IP) : htons(AX25_P_IP); arp->ar_pro = (dev->type != ARPHRD_AX25)? htons(ETH_P_IP) : htons(AX25_P_IP);
#else #else
arp->ar_pro = htons(ETH_P_IP); arp->ar_pro = htons(ETH_P_IP);
#endif #endif
arp->ar_hln = dev->addr_len; arp->ar_hln = dev->addr_len;
arp->ar_pln = 4; arp->ar_pln = 4;
arp->ar_op = htons(type); arp->ar_op = htons(type);
arp_ptr=(unsigned char *)(arp+1); arp_ptr=(unsigned char *)(arp+1);
memcpy(arp_ptr, src_hw, dev->addr_len); memcpy(arp_ptr, src_hw, dev->addr_len);
arp_ptr+=dev->addr_len; arp_ptr+=dev->addr_len;
memcpy(arp_ptr, &src_ip,4); memcpy(arp_ptr, &src_ip,4);
...@@ -306,39 +306,39 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev, ...@@ -306,39 +306,39 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev,
memset(arp_ptr, 0, dev->addr_len); memset(arp_ptr, 0, dev->addr_len);
arp_ptr+=dev->addr_len; arp_ptr+=dev->addr_len;
memcpy(arp_ptr, &dest_ip, 4); memcpy(arp_ptr, &dest_ip, 4);
dev_queue_xmit(skb, dev, 0); dev_queue_xmit(skb, dev, 0);
} }
/* /*
* This function is called, if an entry is not resolved in ARP_RES_TIME. * This function is called, if an entry is not resolved in ARP_RES_TIME.
* Either resend a request, or give it up and free the entry. * Either resend a request, or give it up and free the entry.
*/ */
static void arp_expire_request (unsigned long arg) static void arp_expire_request (unsigned long arg)
{ {
struct arp_table *entry = (struct arp_table *) arg; struct arp_table *entry = (struct arp_table *) arg;
struct arp_table **pentry; struct arp_table **pentry;
unsigned long hash; unsigned long hash;
unsigned long flags; unsigned long flags;
save_flags(flags); save_flags(flags);
cli(); cli();
/* /*
* Since all timeouts are handled with interrupts enabled, there is a * Since all timeouts are handled with interrupts enabled, there is a
* small chance, that this entry has just been resolved by an incoming * small chance, that this entry has just been resolved by an incoming
* packet. This is the only race condition, but it is handled... * packet. This is the only race condition, but it is handled...
*/ */
if (entry->flags & ATF_COM) if (entry->flags & ATF_COM)
{ {
restore_flags(flags); restore_flags(flags);
return; return;
} }
if (--entry->retries > 0) if (--entry->retries > 0)
{ {
unsigned long ip = entry->ip; unsigned long ip = entry->ip;
struct device *dev = entry->dev; struct device *dev = entry->dev;
...@@ -352,19 +352,19 @@ static void arp_expire_request (unsigned long arg) ...@@ -352,19 +352,19 @@ static void arp_expire_request (unsigned long arg)
dev->dev_addr); dev->dev_addr);
return; return;
} }
/* /*
* Arp request timed out. Delete entry and all waiting packets. * Arp request timed out. Delete entry and all waiting packets.
* If we give each entry a pointer to itself, we don't have to * If we give each entry a pointer to itself, we don't have to
* loop through everything again. Maybe hash is good enough, but * loop through everything again. Maybe hash is good enough, but
* I will look at it later. * I will look at it later.
*/ */
hash = HASH(entry->ip); hash = HASH(entry->ip);
pentry = &arp_tables[hash]; pentry = &arp_tables[hash];
while (*pentry != NULL) while (*pentry != NULL)
{ {
if (*pentry == entry) if (*pentry == entry)
{ {
*pentry = entry->next; /* delete from linked list */ *pentry = entry->next; /* delete from linked list */
del_timer(&entry->timer); del_timer(&entry->timer);
...@@ -377,37 +377,37 @@ static void arp_expire_request (unsigned long arg) ...@@ -377,37 +377,37 @@ static void arp_expire_request (unsigned long arg)
restore_flags(flags); restore_flags(flags);
printk("Possible ARP queue corruption.\n"); printk("Possible ARP queue corruption.\n");
/* /*
* We should never arrive here. * We should never arrive here.
*/ */
} }
/* /*
* This will try to retransmit everything on the queue. * This will try to retransmit everything on the queue.
*/ */
static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest) static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest)
{ {
struct sk_buff *skb; struct sk_buff *skb;
/* /*
* Empty the entire queue, building its data up ready to send * Empty the entire queue, building its data up ready to send
*/ */
if(!(entry->flags&ATF_COM)) if(!(entry->flags&ATF_COM))
{ {
printk("arp_send_q: incomplete entry for %s\n", printk("arp_send_q: incomplete entry for %s\n",
in_ntoa(entry->ip)); in_ntoa(entry->ip));
return; return;
} }
while((skb = skb_dequeue(&entry->skb)) != NULL) while((skb = skb_dequeue(&entry->skb)) != NULL)
{ {
IS_SKB(skb); IS_SKB(skb);
if(!skb->dev->rebuild_header(skb->data,skb->dev,skb->raddr,skb)) if(!skb->dev->rebuild_header(skb->data,skb->dev,skb->raddr,skb))
{ {
skb->arp = 1; skb->arp = 1;
if(skb->sk==NULL) if(skb->sk==NULL)
dev_queue_xmit(skb, skb->dev, 0); dev_queue_xmit(skb, skb->dev, 0);
else else
...@@ -426,9 +426,9 @@ static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest) ...@@ -426,9 +426,9 @@ static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest)
/* /*
* Delete an ARP mapping entry in the cache. * Delete an ARP mapping entry in the cache.
*/ */
void arp_destroy(unsigned long ip_addr, int force) void arp_destroy(unsigned long ip_addr, int force)
{ {
struct arp_table *entry; struct arp_table *entry;
...@@ -437,15 +437,15 @@ void arp_destroy(unsigned long ip_addr, int force) ...@@ -437,15 +437,15 @@ void arp_destroy(unsigned long ip_addr, int force)
cli(); cli();
pentry = &arp_tables[hash]; pentry = &arp_tables[hash];
while ((entry = *pentry) != NULL) while ((entry = *pentry) != NULL)
{ {
if (entry->ip == ip_addr) if (entry->ip == ip_addr)
{ {
if ((entry->flags & ATF_PERM) && !force) if ((entry->flags & ATF_PERM) && !force)
return; return;
*pentry = entry->next; *pentry = entry->next;
sti();
del_timer(&entry->timer); del_timer(&entry->timer);
sti();
arp_release_entry(entry); arp_release_entry(entry);
return; return;
} }
...@@ -455,18 +455,18 @@ void arp_destroy(unsigned long ip_addr, int force) ...@@ -455,18 +455,18 @@ void arp_destroy(unsigned long ip_addr, int force)
} }
/* /*
* Receive an arp request by the device layer. Maybe I rewrite it, to * Receive an arp request by the device layer. Maybe I rewrite it, to
* use the incoming packet for the reply. The time for the current * use the incoming packet for the reply. The time for the current
* "overhead" isn't that high... * "overhead" isn't that high...
*/ */
int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{ {
/* /*
* We shouldn't use this type conversion. Check later. * We shouldn't use this type conversion. Check later.
*/ */
struct arphdr *arp = (struct arphdr *)skb->h.raw; struct arphdr *arp = (struct arphdr *)skb->h.raw;
unsigned char *arp_ptr= (unsigned char *)(arp+1); unsigned char *arp_ptr= (unsigned char *)(arp+1);
struct arp_table *entry; struct arp_table *entry;
...@@ -480,22 +480,22 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -480,22 +480,22 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/* /*
* If this test doesn't pass, its not IP, or we should ignore it anyway * If this test doesn't pass, its not IP, or we should ignore it anyway
*/ */
if (arp->ar_hln != dev->addr_len || dev->type != ntohs(arp->ar_hrd) || dev->flags&IFF_NOARP) if (arp->ar_hln != dev->addr_len || dev->type != ntohs(arp->ar_hrd) || dev->flags&IFF_NOARP)
{ {
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return 0; return 0;
} }
/* /*
* For now we will only deal with IP addresses. * For now we will only deal with IP addresses.
*/ */
if ( if (
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
(arp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) || (arp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) ||
#endif #endif
(arp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) (arp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25)
|| arp->ar_pln != 4) || arp->ar_pln != 4)
{ {
/* This packet is not for us. Remove it. */ /* This packet is not for us. Remove it. */
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
...@@ -513,21 +513,21 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -513,21 +513,21 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
tha=arp_ptr; tha=arp_ptr;
arp_ptr+=dev->addr_len; arp_ptr+=dev->addr_len;
memcpy(&tip,arp_ptr,4); memcpy(&tip,arp_ptr,4);
/* /*
* Process entry * Process entry
*/ */
addr_hint = ip_chk_addr(tip); addr_hint = ip_chk_addr(tip);
hash = HASH(sip); hash = HASH(sip);
proxy_entry = NULL; proxy_entry = NULL;
if (proxies != 0 && addr_hint != IS_MYADDR) if (proxies != 0 && addr_hint != IS_MYADDR)
{ {
unsigned long dest_hash = HASH(tip); unsigned long dest_hash = HASH(tip);
cli(); cli();
proxy_entry = arp_tables[dest_hash]; proxy_entry = arp_tables[dest_hash];
while (proxy_entry != NULL) while (proxy_entry != NULL)
{ {
if (proxy_entry->ip == tip && proxy_entry->htype==arp->ar_hrd) if (proxy_entry->ip == tip && proxy_entry->htype==arp->ar_hrd)
break; break;
...@@ -537,15 +537,15 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -537,15 +537,15 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
memcpy(ha, proxy_entry->ha, dev->addr_len); memcpy(ha, proxy_entry->ha, dev->addr_len);
else else
proxy_entry = NULL; proxy_entry = NULL;
} }
else else
cli(); cli();
for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) for (entry = arp_tables[hash]; entry != NULL; entry = entry->next)
if (entry->ip == sip) if (entry->ip == sip)
break; break;
if (entry != NULL) if (entry != NULL)
{ {
int old_flags = entry->flags; int old_flags = entry->flags;
memcpy(entry->ha, sha, arp->ar_hln); memcpy(entry->ha, sha, arp->ar_hln);
...@@ -555,28 +555,28 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -555,28 +555,28 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
if(entry->htype==0) if(entry->htype==0)
entry->htype = dev->type; /* Not good but we have no choice */ entry->htype = dev->type; /* Not good but we have no choice */
entry->last_used = jiffies; entry->last_used = jiffies;
if (!(entry->flags & ATF_COM)) if (!(entry->flags & ATF_COM))
{ {
del_timer(&entry->timer); del_timer(&entry->timer);
entry->flags |= ATF_COM; entry->flags |= ATF_COM;
} }
sti(); sti();
if (!(old_flags & ATF_COM)) if (!(old_flags & ATF_COM))
{ {
/* Send out waiting packets. We might have problems, /* Send out waiting packets. We might have problems,
if someone is manually removing entries right now. if someone is manually removing entries right now.
I will fix this one. */ I will fix this one. */
arp_send_q(entry, sha); arp_send_q(entry, sha);
} }
if (addr_hint != IS_MYADDR && proxy_entry == NULL) if (addr_hint != IS_MYADDR && proxy_entry == NULL)
{ {
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return 0; return 0;
} }
} }
else else
{ {
if (addr_hint != IS_MYADDR && proxy_entry == NULL) if (addr_hint != IS_MYADDR && proxy_entry == NULL)
{ {
/* We don't do "smart arp" and cache all possible /* We don't do "smart arp" and cache all possible
entries. That just makes us more work. */ entries. That just makes us more work. */
...@@ -586,7 +586,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -586,7 +586,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
} }
entry = (struct arp_table *)kmalloc(sizeof(struct arp_table), entry = (struct arp_table *)kmalloc(sizeof(struct arp_table),
GFP_ATOMIC); GFP_ATOMIC);
if (entry == NULL) if (entry == NULL)
{ {
sti(); sti();
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
...@@ -610,7 +610,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -610,7 +610,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
any more. */ any more. */
if (arp->ar_op != htons(ARPOP_REQUEST) if (arp->ar_op != htons(ARPOP_REQUEST)
|| tip == INADDR_LOOPBACK) || tip == INADDR_LOOPBACK)
{ {
/* This wasn't a request, or some bad request for 127.0.0.1 /* This wasn't a request, or some bad request for 127.0.0.1
has made its way to the net, so delete it. */ has made its way to the net, so delete it. */
...@@ -629,16 +629,16 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -629,16 +629,16 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/* /*
* Find an arp mapping in the cache. If not found, post a request. * Find an arp mapping in the cache. If not found, post a request.
*/ */
int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
unsigned long saddr, struct sk_buff *skb) unsigned long saddr, struct sk_buff *skb)
{ {
struct arp_table *entry; struct arp_table *entry;
unsigned long hash; unsigned long hash;
switch (ip_chk_addr(paddr)) switch (ip_chk_addr(paddr))
{ {
case IS_MYADDR: case IS_MYADDR:
printk("ARP: arp called for own IP address\n"); printk("ARP: arp called for own IP address\n");
...@@ -653,34 +653,34 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -653,34 +653,34 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
hash = HASH(paddr); hash = HASH(paddr);
cli(); cli();
/* /*
* Find an entry * Find an entry
*/ */
for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) for (entry = arp_tables[hash]; entry != NULL; entry = entry->next)
if (entry->ip == paddr) if (entry->ip == paddr)
break; break;
if (entry != NULL) /* It exists */ if (entry != NULL) /* It exists */
{ {
if (!(entry->flags & ATF_COM)) if (!(entry->flags & ATF_COM))
{ {
/* /*
* A request was already send, but no reply yet. Thus * A request was already send, but no reply yet. Thus
* queue the packet with the previous attempt * queue the packet with the previous attempt
*/ */
if (skb != NULL) if (skb != NULL)
skb_queue_tail(&entry->skb, skb); skb_queue_tail(&entry->skb, skb);
sti(); sti();
return 1; return 1;
} }
/* /*
* Update the record * Update the record
*/ */
entry->last_used = jiffies; entry->last_used = jiffies;
memcpy(haddr, entry->ha, dev->addr_len); memcpy(haddr, entry->ha, dev->addr_len);
if (skb) if (skb)
...@@ -690,12 +690,12 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -690,12 +690,12 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
} }
/* /*
* Create a new unresolved entry. * Create a new unresolved entry.
*/ */
entry = (struct arp_table *) kmalloc(sizeof(struct arp_table), entry = (struct arp_table *) kmalloc(sizeof(struct arp_table),
GFP_ATOMIC); GFP_ATOMIC);
if (entry != NULL) if (entry != NULL)
{ {
entry->ip = paddr; entry->ip = paddr;
entry->hlen = dev->addr_len; entry->hlen = dev->addr_len;
...@@ -714,8 +714,8 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -714,8 +714,8 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
skb_queue_head_init(&entry->skb); skb_queue_head_init(&entry->skb);
if (skb != NULL) if (skb != NULL)
skb_queue_tail(&entry->skb, skb); skb_queue_tail(&entry->skb, skb);
} }
else else
{ {
if (skb != NULL && skb->free) if (skb != NULL && skb->free)
kfree_skb(skb, FREE_WRITE); kfree_skb(skb, FREE_WRITE);
...@@ -723,21 +723,21 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -723,21 +723,21 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
sti(); sti();
/* /*
* If we didn't find an entry, we will try to send an ARP packet. * If we didn't find an entry, we will try to send an ARP packet.
*/ */
arp_send(ARPOP_REQUEST, paddr, dev, saddr, NULL, dev->dev_addr); arp_send(ARPOP_REQUEST, paddr, dev, saddr, NULL, dev->dev_addr);
return 1; return 1;
} }
/* /*
* Write the contents of the ARP cache to a PROCfs file. * Write the contents of the ARP cache to a PROCfs file.
* *
* Will change soon to ASCII format * Will change soon to ASCII format
*/ */
int arp_get_info(char *buffer, char **start, off_t offset, int length) int arp_get_info(char *buffer, char **start, off_t offset, int length)
{ {
struct arp_table *entry; struct arp_table *entry;
...@@ -749,9 +749,9 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -749,9 +749,9 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length)
cli(); cli();
/* Loop over the ARP table and copy structures to the buffer. */ /* Loop over the ARP table and copy structures to the buffer. */
for (i = 0; i < ARP_TABLE_SIZE; i++) for (i = 0; i < ARP_TABLE_SIZE; i++)
{ {
for (entry = arp_tables[i]; entry; entry = entry->next) for (entry = arp_tables[i]; entry; entry = entry->next)
{ {
memset(req, 0, sizeof(struct arpreq)); memset(req, 0, sizeof(struct arpreq));
req->arp_pa.sa_family = AF_INET; req->arp_pa.sa_family = AF_INET;
...@@ -783,11 +783,11 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -783,11 +783,11 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length)
} }
/* /*
* This will find an entry in the ARP table by looking at the IP address. * This will find an entry in the ARP table by looking at the IP address.
* Be careful, interrupts are turned off on exit!!! * Be careful, interrupts are turned off on exit!!!
*/ */
static struct arp_table *arp_lookup(unsigned long paddr) static struct arp_table *arp_lookup(unsigned long paddr)
{ {
struct arp_table *entry; struct arp_table *entry;
...@@ -801,9 +801,9 @@ static struct arp_table *arp_lookup(unsigned long paddr) ...@@ -801,9 +801,9 @@ static struct arp_table *arp_lookup(unsigned long paddr)
/* /*
* Set (create) an ARP cache entry. * Set (create) an ARP cache entry.
*/ */
static int arp_req_set(struct arpreq *req) static int arp_req_set(struct arpreq *req)
{ {
struct arpreq r; struct arpreq r;
...@@ -824,7 +824,7 @@ static int arp_req_set(struct arpreq *req) ...@@ -824,7 +824,7 @@ static int arp_req_set(struct arpreq *req)
* We have to be compatible with BSD UNIX, so we have to * We have to be compatible with BSD UNIX, so we have to
* assume that a "not set" value (i.e. 0) means Ethernet. * assume that a "not set" value (i.e. 0) means Ethernet.
*/ */
switch (r.arp_ha.sa_family) { switch (r.arp_ha.sa_family) {
case 0: case 0:
/* Moan about this. ARP family 0 is NetROM and _will_ be needed */ /* Moan about this. ARP family 0 is NetROM and _will_ be needed */
...@@ -833,24 +833,24 @@ static int arp_req_set(struct arpreq *req) ...@@ -833,24 +833,24 @@ static int arp_req_set(struct arpreq *req)
htype = ARPHRD_ETHER; htype = ARPHRD_ETHER;
hlen = ETH_ALEN; hlen = ETH_ALEN;
break; break;
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
case ARPHRD_AX25: case ARPHRD_AX25:
htype = ARPHRD_AX25; htype = ARPHRD_AX25;
hlen = 7; hlen = 7;
break; break;
#endif #endif
default: default:
return -EPFNOSUPPORT; return -EPFNOSUPPORT;
} }
si = (struct sockaddr_in *) &r.arp_pa; si = (struct sockaddr_in *) &r.arp_pa;
ip = si->sin_addr.s_addr; ip = si->sin_addr.s_addr;
if (ip == 0) if (ip == 0)
{ {
printk("ARP: SETARP: requested PA is 0.0.0.0 !\n"); printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
return -EINVAL; return -EINVAL;
} }
/* /*
* Is it reachable directly ? * Is it reachable directly ?
*/ */
...@@ -860,28 +860,28 @@ static int arp_req_set(struct arpreq *req) ...@@ -860,28 +860,28 @@ static int arp_req_set(struct arpreq *req)
return -ENETUNREACH; return -ENETUNREACH;
/* /*
* Is there an existing entry for this address? * Is there an existing entry for this address?
*/ */
hash = HASH(ip); hash = HASH(ip);
cli(); cli();
/* /*
* Find the entry * Find the entry
*/ */
for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) for (entry = arp_tables[hash]; entry != NULL; entry = entry->next)
if (entry->ip == ip) if (entry->ip == ip)
break; break;
/* /*
* Do we need to create a new entry * Do we need to create a new entry
*/ */
if (entry == NULL) if (entry == NULL)
{ {
entry = (struct arp_table *) kmalloc(sizeof(struct arp_table), entry = (struct arp_table *) kmalloc(sizeof(struct arp_table),
GFP_ATOMIC); GFP_ATOMIC);
if (entry == NULL) if (entry == NULL)
{ {
sti(); sti();
return -ENOMEM; return -ENOMEM;
...@@ -892,14 +892,14 @@ static int arp_req_set(struct arpreq *req) ...@@ -892,14 +892,14 @@ static int arp_req_set(struct arpreq *req)
entry->next = arp_tables[hash]; entry->next = arp_tables[hash];
arp_tables[hash] = entry; arp_tables[hash] = entry;
skb_queue_head_init(&entry->skb); skb_queue_head_init(&entry->skb);
} }
else else
if (entry->flags & ATF_PUBL) if (entry->flags & ATF_PUBL)
proxies--; proxies--;
/* /*
* We now have a pointer to an ARP entry. Update it! * We now have a pointer to an ARP entry. Update it!
*/ */
memcpy(&entry->ha, &r.arp_ha.sa_data, hlen); memcpy(&entry->ha, &r.arp_ha.sa_data, hlen);
entry->last_used = jiffies; entry->last_used = jiffies;
entry->flags = r.arp_flags | ATF_COM; entry->flags = r.arp_flags | ATF_COM;
...@@ -913,9 +913,9 @@ static int arp_req_set(struct arpreq *req) ...@@ -913,9 +913,9 @@ static int arp_req_set(struct arpreq *req)
/* /*
* Get an ARP cache entry. * Get an ARP cache entry.
*/ */
static int arp_req_get(struct arpreq *req) static int arp_req_get(struct arpreq *req)
{ {
struct arpreq r; struct arpreq r;
...@@ -923,64 +923,64 @@ static int arp_req_get(struct arpreq *req) ...@@ -923,64 +923,64 @@ static int arp_req_get(struct arpreq *req)
struct sockaddr_in *si; struct sockaddr_in *si;
/* /*
* We only understand about IP addresses... * We only understand about IP addresses...
*/ */
memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET) memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET)
return -EPFNOSUPPORT; return -EPFNOSUPPORT;
/* /*
* Is there an existing entry for this address? * Is there an existing entry for this address?
*/ */
si = (struct sockaddr_in *) &r.arp_pa; si = (struct sockaddr_in *) &r.arp_pa;
entry = arp_lookup(si->sin_addr.s_addr); entry = arp_lookup(si->sin_addr.s_addr);
if (entry == NULL) if (entry == NULL)
{ {
sti(); sti();
return -ENXIO; return -ENXIO;
} }
/* /*
* We found it; copy into structure. * We found it; copy into structure.
*/ */
memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen); memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen);
r.arp_ha.sa_family = entry->htype; r.arp_ha.sa_family = entry->htype;
r.arp_flags = entry->flags; r.arp_flags = entry->flags;
sti(); sti();
/* /*
* Copy the information back * Copy the information back
*/ */
memcpy_tofs(req, &r, sizeof(r)); memcpy_tofs(req, &r, sizeof(r));
return 0; return 0;
} }
/* /*
* Handle an ARP layer I/O control request. * Handle an ARP layer I/O control request.
*/ */
int arp_ioctl(unsigned int cmd, void *arg) int arp_ioctl(unsigned int cmd, void *arg)
{ {
struct arpreq r; struct arpreq r;
struct sockaddr_in *si; struct sockaddr_in *si;
int err; int err;
switch(cmd) switch(cmd)
{ {
case DDIOCSDBG: case DDIOCSDBG:
return dbg_ioctl(arg, DBG_ARP); return dbg_ioctl(arg, DBG_ARP);
case SIOCDARP: case SIOCDARP:
if (!suser()) if (!suser())
return -EPERM; return -EPERM;
err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
if(err) if(err)
return err; return err;
memcpy_fromfs(&r, arg, sizeof(r)); memcpy_fromfs(&r, arg, sizeof(r));
if (r.arp_pa.sa_family != AF_INET) if (r.arp_pa.sa_family != AF_INET)
...@@ -990,14 +990,14 @@ int arp_ioctl(unsigned int cmd, void *arg) ...@@ -990,14 +990,14 @@ int arp_ioctl(unsigned int cmd, void *arg)
return 0; return 0;
case SIOCGARP: case SIOCGARP:
err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq)); err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq));
if(err) if(err)
return err; return err;
return arp_req_get((struct arpreq *)arg); return arp_req_get((struct arpreq *)arg);
case SIOCSARP: case SIOCSARP:
if (!suser()) if (!suser())
return -EPERM; return -EPERM;
err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
if(err) if(err)
return err; return err;
return arp_req_set((struct arpreq *)arg); return arp_req_set((struct arpreq *)arg);
default: default:
...@@ -1009,10 +1009,10 @@ int arp_ioctl(unsigned int cmd, void *arg) ...@@ -1009,10 +1009,10 @@ int arp_ioctl(unsigned int cmd, void *arg)
/* /*
* Called once on startup. * Called once on startup.
*/ */
static struct packet_type arp_packet_type = static struct packet_type arp_packet_type =
{ {
0, /* Should be: __constant_htons(ETH_P_ARP) - but this _doesn't_ come out constant! */ 0, /* Should be: __constant_htons(ETH_P_ARP) - but this _doesn't_ come out constant! */
0, /* copy */ 0, /* copy */
...@@ -1020,7 +1020,7 @@ static struct packet_type arp_packet_type = ...@@ -1020,7 +1020,7 @@ static struct packet_type arp_packet_type =
NULL, NULL,
NULL NULL
}; };
void arp_init (void) void arp_init (void)
{ {
/* Register the packet type */ /* Register the packet type */
......
...@@ -319,6 +319,7 @@ int dev_close(struct device *dev) ...@@ -319,6 +319,7 @@ int dev_close(struct device *dev)
void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
{ {
unsigned long flags;
int where = 0; /* used to say if the packet should go */ int where = 0; /* used to say if the packet should go */
/* at the front or the back of the */ /* at the front or the back of the */
/* queue. */ /* queue. */
...@@ -335,7 +336,6 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) ...@@ -335,7 +336,6 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
IS_SKB(skb); IS_SKB(skb);
skb->dev = dev; skb->dev = dev;
start_bh_atomic();
/* /*
* This just eliminates some race conditions, but not all... * This just eliminates some race conditions, but not all...
...@@ -348,7 +348,6 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) ...@@ -348,7 +348,6 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
*/ */
printk("dev_queue_xmit: worked around a missed interrupt\n"); printk("dev_queue_xmit: worked around a missed interrupt\n");
dev->hard_start_xmit(NULL, dev); dev->hard_start_xmit(NULL, dev);
end_bh_atomic();
return; return;
} }
...@@ -376,33 +375,27 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) ...@@ -376,33 +375,27 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
*/ */
if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) { if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) {
end_bh_atomic();
return; return;
} }
/* save_flags(flags);
* This is vitally important. We _MUST_ keep packets in order. While tcp/ip cli();
* suffers only a slow down some IPX apps, and all the AX.25 code will break if (!where) {
* if it occurs out of order. skb_queue_tail(dev->buffs + pri,skb);
* skb = skb_dequeue(dev->buffs + pri);
* This is commented out while I fix a few 'side effects' }
*/ restore_flags(flags);
if ((where==1 || skb_peek(&dev->buffs[pri])==NULL) && dev->hard_start_xmit(skb, dev) == 0) if (dev->hard_start_xmit(skb, dev) == 0) {
{
end_bh_atomic();
return; return;
} }
/* /*
* Transmission failed, put skb back into a list. * Transmission failed, put skb back into a list.
*/ */
cli();
if(where) skb_queue_head(dev->buffs + pri,skb);
skb_queue_head(&dev->buffs[pri],skb); restore_flags(flags);
else
skb_queue_tail(&dev->buffs[pri],skb);
end_bh_atomic();
} }
/* /*
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
#include <linux/string.h>
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#include <linux/types.h> #include <linux/types.h>
...@@ -39,6 +38,7 @@ ...@@ -39,6 +38,7 @@
#include <linux/in.h> #include <linux/in.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/string.h>
#include "snmp.h" #include "snmp.h"
#include "ip.h" #include "ip.h"
#include "route.h" #include "route.h"
...@@ -313,8 +313,10 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) ...@@ -313,8 +313,10 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
* Handle ICMP_REDIRECT. * Handle ICMP_REDIRECT.
*/ */
static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev) static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
struct device *dev, unsigned long source)
{ {
struct rtable *rt;
struct iphdr *iph; struct iphdr *iph;
unsigned long ip; unsigned long ip;
...@@ -340,8 +342,16 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev ...@@ -340,8 +342,16 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev
#endif #endif
case ICMP_REDIR_HOST: case ICMP_REDIR_HOST:
/* /*
* Add better route to host * Add better route to host.
* But first check that the redirect
* comes from the old gateway..
*/ */
rt = ip_rt_route(ip, NULL, NULL);
if (!rt)
break;
if (rt->rt_gateway != source)
break;
printk("redirect from %08lx\n", source);
ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
ip, 0, icmph->un.gateway, dev); ip, 0, icmph->un.gateway, dev);
break; break;
...@@ -657,7 +667,7 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, ...@@ -657,7 +667,7 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
return(0); return(0);
case ICMP_REDIRECT: case ICMP_REDIRECT:
icmp_statistics.IcmpInRedirects++; icmp_statistics.IcmpInRedirects++;
icmp_redirect(icmph, skb1, dev); icmp_redirect(icmph, skb1, dev, saddr);
return(0); return(0);
case ICMP_ECHO: case ICMP_ECHO:
icmp_statistics.IcmpInEchos++; icmp_statistics.IcmpInEchos++;
......
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