diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/bnx2.c | 2 | ||||
-rw-r--r-- | drivers/net/loopback.c | 67 | ||||
-rw-r--r-- | drivers/net/tun.c | 105 |
3 files changed, 102 insertions, 72 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d4548101e495..2486a656f12d 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -35,8 +35,8 @@ | |||
35 | #include <linux/time.h> | 35 | #include <linux/time.h> |
36 | #include <linux/ethtool.h> | 36 | #include <linux/ethtool.h> |
37 | #include <linux/mii.h> | 37 | #include <linux/mii.h> |
38 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | ||
39 | #include <linux/if_vlan.h> | 38 | #include <linux/if_vlan.h> |
39 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | ||
40 | #define BCM_VLAN 1 | 40 | #define BCM_VLAN 1 |
41 | #endif | 41 | #endif |
42 | #include <net/ip.h> | 42 | #include <net/ip.h> |
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 49f6bc036a92..3b43bfd85a0f 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c | |||
@@ -64,68 +64,6 @@ struct pcpu_lstats { | |||
64 | unsigned long bytes; | 64 | unsigned long bytes; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | /* KISS: just allocate small chunks and copy bits. | ||
68 | * | ||
69 | * So, in fact, this is documentation, explaining what we expect | ||
70 | * of largesending device modulo TCP checksum, which is ignored for loopback. | ||
71 | */ | ||
72 | |||
73 | #ifdef LOOPBACK_TSO | ||
74 | static void emulate_large_send_offload(struct sk_buff *skb) | ||
75 | { | ||
76 | struct iphdr *iph = ip_hdr(skb); | ||
77 | struct tcphdr *th = (struct tcphdr *)(skb_network_header(skb) + | ||
78 | (iph->ihl * 4)); | ||
79 | unsigned int doffset = (iph->ihl + th->doff) * 4; | ||
80 | unsigned int mtu = skb_shinfo(skb)->gso_size + doffset; | ||
81 | unsigned int offset = 0; | ||
82 | u32 seq = ntohl(th->seq); | ||
83 | u16 id = ntohs(iph->id); | ||
84 | |||
85 | while (offset + doffset < skb->len) { | ||
86 | unsigned int frag_size = min(mtu, skb->len - offset) - doffset; | ||
87 | struct sk_buff *nskb = alloc_skb(mtu + 32, GFP_ATOMIC); | ||
88 | |||
89 | if (!nskb) | ||
90 | break; | ||
91 | skb_reserve(nskb, 32); | ||
92 | skb_set_mac_header(nskb, -ETH_HLEN); | ||
93 | skb_reset_network_header(nskb); | ||
94 | iph = ip_hdr(nskb); | ||
95 | skb_copy_to_linear_data(nskb, skb_network_header(skb), | ||
96 | doffset); | ||
97 | if (skb_copy_bits(skb, | ||
98 | doffset + offset, | ||
99 | nskb->data + doffset, | ||
100 | frag_size)) | ||
101 | BUG(); | ||
102 | skb_put(nskb, doffset + frag_size); | ||
103 | nskb->ip_summed = CHECKSUM_UNNECESSARY; | ||
104 | nskb->dev = skb->dev; | ||
105 | nskb->priority = skb->priority; | ||
106 | nskb->protocol = skb->protocol; | ||
107 | nskb->dst = dst_clone(skb->dst); | ||
108 | memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); | ||
109 | nskb->pkt_type = skb->pkt_type; | ||
110 | |||
111 | th = (struct tcphdr *)(skb_network_header(nskb) + iph->ihl * 4); | ||
112 | iph->tot_len = htons(frag_size + doffset); | ||
113 | iph->id = htons(id); | ||
114 | iph->check = 0; | ||
115 | iph->check = ip_fast_csum((unsigned char *) iph, iph->ihl); | ||
116 | th->seq = htonl(seq); | ||
117 | if (offset + doffset + frag_size < skb->len) | ||
118 | th->fin = th->psh = 0; | ||
119 | netif_rx(nskb); | ||
120 | offset += frag_size; | ||
121 | seq += frag_size; | ||
122 | id++; | ||
123 | } | ||
124 | |||
125 | dev_kfree_skb(skb); | ||
126 | } | ||
127 | #endif /* LOOPBACK_TSO */ | ||
128 | |||
129 | /* | 67 | /* |
130 | * The higher levels take care of making this non-reentrant (it's | 68 | * The higher levels take care of making this non-reentrant (it's |
131 | * called with bh's disabled). | 69 | * called with bh's disabled). |
@@ -137,9 +75,6 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) | |||
137 | skb_orphan(skb); | 75 | skb_orphan(skb); |
138 | 76 | ||
139 | skb->protocol = eth_type_trans(skb,dev); | 77 | skb->protocol = eth_type_trans(skb,dev); |
140 | #ifndef LOOPBACK_MUST_CHECKSUM | ||
141 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
142 | #endif | ||
143 | 78 | ||
144 | #ifdef LOOPBACK_TSO | 79 | #ifdef LOOPBACK_TSO |
145 | if (skb_is_gso(skb)) { | 80 | if (skb_is_gso(skb)) { |
@@ -234,9 +169,7 @@ static void loopback_setup(struct net_device *dev) | |||
234 | dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ | 169 | dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ |
235 | dev->flags = IFF_LOOPBACK; | 170 | dev->flags = IFF_LOOPBACK; |
236 | dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | 171 | dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
237 | #ifdef LOOPBACK_TSO | ||
238 | | NETIF_F_TSO | 172 | | NETIF_F_TSO |
239 | #endif | ||
240 | | NETIF_F_NO_CSUM | 173 | | NETIF_F_NO_CSUM |
241 | | NETIF_F_HIGHDMA | 174 | | NETIF_F_HIGHDMA |
242 | | NETIF_F_LLTX | 175 | | NETIF_F_LLTX |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e6bbc639c2d0..6daea0c91862 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -358,6 +358,66 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) | |||
358 | return mask; | 358 | return mask; |
359 | } | 359 | } |
360 | 360 | ||
361 | /* prepad is the amount to reserve at front. len is length after that. | ||
362 | * linear is a hint as to how much to copy (usually headers). */ | ||
363 | static struct sk_buff *tun_alloc_skb(size_t prepad, size_t len, size_t linear, | ||
364 | gfp_t gfp) | ||
365 | { | ||
366 | struct sk_buff *skb; | ||
367 | unsigned int i; | ||
368 | |||
369 | skb = alloc_skb(prepad + len, gfp|__GFP_NOWARN); | ||
370 | if (skb) { | ||
371 | skb_reserve(skb, prepad); | ||
372 | skb_put(skb, len); | ||
373 | return skb; | ||
374 | } | ||
375 | |||
376 | /* Under a page? Don't bother with paged skb. */ | ||
377 | if (prepad + len < PAGE_SIZE) | ||
378 | return NULL; | ||
379 | |||
380 | /* Start with a normal skb, and add pages. */ | ||
381 | skb = alloc_skb(prepad + linear, gfp); | ||
382 | if (!skb) | ||
383 | return NULL; | ||
384 | |||
385 | skb_reserve(skb, prepad); | ||
386 | skb_put(skb, linear); | ||
387 | |||
388 | len -= linear; | ||
389 | |||
390 | for (i = 0; i < MAX_SKB_FRAGS; i++) { | ||
391 | skb_frag_t *f = &skb_shinfo(skb)->frags[i]; | ||
392 | |||
393 | f->page = alloc_page(gfp|__GFP_ZERO); | ||
394 | if (!f->page) | ||
395 | break; | ||
396 | |||
397 | f->page_offset = 0; | ||
398 | f->size = PAGE_SIZE; | ||
399 | |||
400 | skb->data_len += PAGE_SIZE; | ||
401 | skb->len += PAGE_SIZE; | ||
402 | skb->truesize += PAGE_SIZE; | ||
403 | skb_shinfo(skb)->nr_frags++; | ||
404 | |||
405 | if (len < PAGE_SIZE) { | ||
406 | len = 0; | ||
407 | break; | ||
408 | } | ||
409 | len -= PAGE_SIZE; | ||
410 | } | ||
411 | |||
412 | /* Too large, or alloc fail? */ | ||
413 | if (unlikely(len)) { | ||
414 | kfree_skb(skb); | ||
415 | skb = NULL; | ||
416 | } | ||
417 | |||
418 | return skb; | ||
419 | } | ||
420 | |||
361 | /* Get packet from user space buffer */ | 421 | /* Get packet from user space buffer */ |
362 | static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count) | 422 | static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count) |
363 | { | 423 | { |
@@ -391,14 +451,12 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, | |||
391 | return -EINVAL; | 451 | return -EINVAL; |
392 | } | 452 | } |
393 | 453 | ||
394 | if (!(skb = alloc_skb(len + align, GFP_KERNEL))) { | 454 | if (!(skb = tun_alloc_skb(align, len, gso.hdr_len, GFP_KERNEL))) { |
395 | tun->dev->stats.rx_dropped++; | 455 | tun->dev->stats.rx_dropped++; |
396 | return -ENOMEM; | 456 | return -ENOMEM; |
397 | } | 457 | } |
398 | 458 | ||
399 | if (align) | 459 | if (skb_copy_datagram_from_iovec(skb, 0, iv, len)) { |
400 | skb_reserve(skb, align); | ||
401 | if (memcpy_fromiovec(skb_put(skb, len), iv, len)) { | ||
402 | tun->dev->stats.rx_dropped++; | 460 | tun->dev->stats.rx_dropped++; |
403 | kfree_skb(skb); | 461 | kfree_skb(skb); |
404 | return -EFAULT; | 462 | return -EFAULT; |
@@ -748,6 +806,36 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
748 | return err; | 806 | return err; |
749 | } | 807 | } |
750 | 808 | ||
809 | static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) | ||
810 | { | ||
811 | struct tun_struct *tun = file->private_data; | ||
812 | |||
813 | if (!tun) | ||
814 | return -EBADFD; | ||
815 | |||
816 | DBG(KERN_INFO "%s: tun_get_iff\n", tun->dev->name); | ||
817 | |||
818 | strcpy(ifr->ifr_name, tun->dev->name); | ||
819 | |||
820 | ifr->ifr_flags = 0; | ||
821 | |||
822 | if (ifr->ifr_flags & TUN_TUN_DEV) | ||
823 | ifr->ifr_flags |= IFF_TUN; | ||
824 | else | ||
825 | ifr->ifr_flags |= IFF_TAP; | ||
826 | |||
827 | if (tun->flags & TUN_NO_PI) | ||
828 | ifr->ifr_flags |= IFF_NO_PI; | ||
829 | |||
830 | if (tun->flags & TUN_ONE_QUEUE) | ||
831 | ifr->ifr_flags |= IFF_ONE_QUEUE; | ||
832 | |||
833 | if (tun->flags & TUN_VNET_HDR) | ||
834 | ifr->ifr_flags |= IFF_VNET_HDR; | ||
835 | |||
836 | return 0; | ||
837 | } | ||
838 | |||
751 | /* This is like a cut-down ethtool ops, except done via tun fd so no | 839 | /* This is like a cut-down ethtool ops, except done via tun fd so no |
752 | * privs required. */ | 840 | * privs required. */ |
753 | static int set_offload(struct net_device *dev, unsigned long arg) | 841 | static int set_offload(struct net_device *dev, unsigned long arg) |
@@ -833,6 +921,15 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
833 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); | 921 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); |
834 | 922 | ||
835 | switch (cmd) { | 923 | switch (cmd) { |
924 | case TUNGETIFF: | ||
925 | ret = tun_get_iff(current->nsproxy->net_ns, file, &ifr); | ||
926 | if (ret) | ||
927 | return ret; | ||
928 | |||
929 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | ||
930 | return -EFAULT; | ||
931 | break; | ||
932 | |||
836 | case TUNSETNOCSUM: | 933 | case TUNSETNOCSUM: |
837 | /* Disable/Enable checksum */ | 934 | /* Disable/Enable checksum */ |
838 | if (arg) | 935 | if (arg) |