Commit 11c4348e authored by David S. Miller's avatar David S. Miller

[IPV4]: Fix ipconfig to be PKT_CAN_SHARE_SKB.

parent ba0c5354
...@@ -390,6 +390,7 @@ static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct pack ...@@ -390,6 +390,7 @@ static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct pack
static struct packet_type rarp_packet_type __initdata = { static struct packet_type rarp_packet_type __initdata = {
.type = __constant_htons(ETH_P_RARP), .type = __constant_htons(ETH_P_RARP),
.func = ic_rarp_recv, .func = ic_rarp_recv,
.data = PKT_CAN_SHARE_SKB,
}; };
static inline void ic_rarp_init(void) static inline void ic_rarp_init(void)
...@@ -408,27 +409,21 @@ static inline void ic_rarp_cleanup(void) ...@@ -408,27 +409,21 @@ static inline void ic_rarp_cleanup(void)
static int __init static int __init
ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{ {
struct arphdr *rarp = (struct arphdr *)skb->h.raw; struct arphdr *rarp;
unsigned char *rarp_ptr = (unsigned char *) (rarp + 1); unsigned char *rarp_ptr;
unsigned long sip, tip; unsigned long sip, tip;
unsigned char *sha, *tha; /* s for "source", t for "target" */ unsigned char *sha, *tha; /* s for "source", t for "target" */
struct ic_device *d; struct ic_device *d;
/* One reply at a time, please. */ if (!pskb_may_pull(skb, sizeof(arphdr)))
spin_lock(&ic_recv_lock);
/* If we already have a reply, just drop the packet */
if (ic_got_reply)
goto drop; goto drop;
/* Find the ic_device that the packet arrived on */ /* Basic sanity checks can be done without the lock. */
d = ic_first_dev; rarp = (struct arphdr *)skb->h.raw;
while (d && d->dev != dev)
d = d->next;
if (!d)
goto drop; /* should never happen */
/* If this test doesn't pass, it's not IP, or we should ignore it anyway */ /* If this test doesn't pass, it's not IP, or we should
* ignore it anyway.
*/
if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
goto drop; goto drop;
...@@ -440,6 +435,30 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ...@@ -440,6 +435,30 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
if (rarp->ar_pro != htons(ETH_P_IP)) if (rarp->ar_pro != htons(ETH_P_IP))
goto drop; goto drop;
if (!pskb_may_pull(skb,
sizeof(arphdr) +
(2 * dev->addr_len) +
(2 * 4)))
goto drop;
/* OK, it is all there and looks valid, process... */
rarp = (struct arphdr *)skb->h.raw;
rarp_ptr = (unsigned char *) (rarp + 1);
/* One reply at a time, please. */
spin_lock(&ic_recv_lock);
/* If we already have a reply, just drop the packet */
if (ic_got_reply)
goto drop_unlock;
/* Find the ic_device that the packet arrived on */
d = ic_first_dev;
while (d && d->dev != dev)
d = d->next;
if (!d)
goto drop_unlock; /* should never happen */
/* Extract variable-width fields */ /* Extract variable-width fields */
sha = rarp_ptr; sha = rarp_ptr;
rarp_ptr += dev->addr_len; rarp_ptr += dev->addr_len;
...@@ -451,11 +470,11 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ...@@ -451,11 +470,11 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
/* Discard packets which are not meant for us. */ /* Discard packets which are not meant for us. */
if (memcmp(tha, dev->dev_addr, dev->addr_len)) if (memcmp(tha, dev->dev_addr, dev->addr_len))
goto drop; goto drop_unlock;
/* Discard packets which are not from specified server. */ /* Discard packets which are not from specified server. */
if (ic_servaddr != INADDR_NONE && ic_servaddr != sip) if (ic_servaddr != INADDR_NONE && ic_servaddr != sip)
goto drop; goto drop_unlock;
/* We have a winner! */ /* We have a winner! */
ic_dev = dev; ic_dev = dev;
...@@ -464,10 +483,11 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ...@@ -464,10 +483,11 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
ic_servaddr = sip; ic_servaddr = sip;
ic_got_reply = IC_RARP; ic_got_reply = IC_RARP;
drop: drop_unlock:
/* Show's over. Nothing to see here. */ /* Show's over. Nothing to see here. */
spin_unlock(&ic_recv_lock); spin_unlock(&ic_recv_lock);
drop:
/* Throw the packet out. */ /* Throw the packet out. */
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
...@@ -530,6 +550,7 @@ static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct pac ...@@ -530,6 +550,7 @@ static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct pac
static struct packet_type bootp_packet_type __initdata = { static struct packet_type bootp_packet_type __initdata = {
.type = __constant_htons(ETH_P_IP), .type = __constant_htons(ETH_P_IP),
.func = ic_bootp_recv, .func = ic_bootp_recv,
.data = PKT_CAN_SHARE_SKB,
}; };
...@@ -793,51 +814,79 @@ static void __init ic_do_bootp_ext(u8 *ext) ...@@ -793,51 +814,79 @@ static void __init ic_do_bootp_ext(u8 *ext)
*/ */
static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{ {
struct bootp_pkt *b = (struct bootp_pkt *) skb->nh.iph; struct bootp_pkt *b;
struct iphdr *h = &b->iph; struct iphdr *h;
struct ic_device *d; struct ic_device *d;
int len; int len;
/* Perform verifications before taking the lock. */
if (skb->pkt_type == PACKET_OTHERHOST)
goto drop;
if (!pskb_may_pull(skb,
sizeof(struct iphdr) +
sizeof(struct udphdr)))
goto drop;
b = (struct bootp_pkt *) skb->nh.iph;
h = &b->iph;
if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP)
goto drop;
/* Fragments are not supported */
if (h->frag_off & htons(IP_OFFSET | IP_MF)) {
if (net_ratelimit())
printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented "
"reply.\n");
goto drop;
}
if (skb->len < ntohs(h->tot_len))
goto drop;
if (ip_fast_csum((char *) h, h->ihl))
goto drop;
if (b->udph.source != htons(67) || b->udph.dest != htons(68))
goto drop;
if (ntohs(h->tot_len) < ntohs(b->udhp.len) + sizeof(struct iphdr))
goto drop;
len = ntohs(b->udph.len) - sizeof(struct udphdr);
if (len < 300)
goto drop;
/* Ok the front looks good, make sure we can get at the rest. */
if (!pskb_may_pull(skb, skb->len))
goto drop;
b = (struct bootp_pkt *) skb->nh.iph;
h = &b->iph;
/* One reply at a time, please. */ /* One reply at a time, please. */
spin_lock(&ic_recv_lock); spin_lock(&ic_recv_lock);
/* If we already have a reply, just drop the packet */ /* If we already have a reply, just drop the packet */
if (ic_got_reply) if (ic_got_reply)
goto drop; goto drop_unlock;
/* Find the ic_device that the packet arrived on */ /* Find the ic_device that the packet arrived on */
d = ic_first_dev; d = ic_first_dev;
while (d && d->dev != dev) while (d && d->dev != dev)
d = d->next; d = d->next;
if (!d) if (!d)
goto drop; /* should never happen */ goto drop_unlock; /* should never happen */
/* Check whether it's a BOOTP packet */
if (skb->pkt_type == PACKET_OTHERHOST ||
skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) ||
h->ihl != 5 ||
h->version != 4 ||
ip_fast_csum((char *) h, h->ihl) != 0 ||
skb->len < ntohs(h->tot_len) ||
h->protocol != IPPROTO_UDP ||
b->udph.source != htons(67) ||
b->udph.dest != htons(68) ||
ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
goto drop;
/* Fragments are not supported */
if (h->frag_off & htons(IP_OFFSET | IP_MF)) {
printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented reply.\n");
goto drop;
}
/* Is it a reply to our BOOTP request? */ /* Is it a reply to our BOOTP request? */
len = ntohs(b->udph.len) - sizeof(struct udphdr); if (b->op != BOOTP_REPLY ||
if (len < 300 || /* See RFC 951:2.1 */
b->op != BOOTP_REPLY ||
b->xid != d->xid) { b->xid != d->xid) {
printk("?"); if (net_ratelimit())
goto drop; printk(KERN_ERR "DHCP/BOOTP: Reply not for us, "
"op[%x] xid[%x]\n",
b->op, b->xid);
goto drop_unlock;
} }
/* Parse extensions */ /* Parse extensions */
...@@ -880,7 +929,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ...@@ -880,7 +929,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
* ignore all others. * ignore all others.
*/ */
if (ic_myaddr != INADDR_NONE) if (ic_myaddr != INADDR_NONE)
goto drop; goto drop_unlock;
/* Let's accept that offer. */ /* Let's accept that offer. */
ic_myaddr = b->your_ip; ic_myaddr = b->your_ip;
...@@ -908,7 +957,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ...@@ -908,7 +957,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
/* Urque. Forget it*/ /* Urque. Forget it*/
ic_myaddr = INADDR_NONE; ic_myaddr = INADDR_NONE;
ic_servaddr = INADDR_NONE; ic_servaddr = INADDR_NONE;
goto drop; goto drop_unlock;
}; };
ic_dhcp_msgtype = mt; ic_dhcp_msgtype = mt;
...@@ -937,10 +986,11 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ...@@ -937,10 +986,11 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
ic_nameservers[0] = ic_servaddr; ic_nameservers[0] = ic_servaddr;
ic_got_reply = IC_BOOTP; ic_got_reply = IC_BOOTP;
drop: drop_unlock:
/* Show's over. Nothing to see here. */ /* Show's over. Nothing to see here. */
spin_unlock(&ic_recv_lock); spin_unlock(&ic_recv_lock);
drop:
/* Throw the packet out. */ /* Throw the packet out. */
kfree_skb(skb); kfree_skb(skb);
......
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