aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/dev.c14
-rw-r--r--net/core/ethtool.c53
-rw-r--r--net/core/skbuff.c75
3 files changed, 142 insertions, 0 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index a44eeef24edf..8d1541595277 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2717,6 +2717,20 @@ int register_netdevice(struct net_device *dev)
2717 dev->name); 2717 dev->name);
2718 dev->features &= ~NETIF_F_TSO; 2718 dev->features &= ~NETIF_F_TSO;
2719 } 2719 }
2720 if (dev->features & NETIF_F_UFO) {
2721 if (!(dev->features & NETIF_F_HW_CSUM)) {
2722 printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no "
2723 "NETIF_F_HW_CSUM feature.\n",
2724 dev->name);
2725 dev->features &= ~NETIF_F_UFO;
2726 }
2727 if (!(dev->features & NETIF_F_SG)) {
2728 printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no "
2729 "NETIF_F_SG feature.\n",
2730 dev->name);
2731 dev->features &= ~NETIF_F_UFO;
2732 }
2733 }
2720 2734
2721 /* 2735 /*
2722 * nil rebuild_header routine, 2736 * nil rebuild_header routine,
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 404b761e82ce..0350586e9195 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -93,6 +93,20 @@ int ethtool_op_get_perm_addr(struct net_device *dev, struct ethtool_perm_addr *a
93} 93}
94 94
95 95
96u32 ethtool_op_get_ufo(struct net_device *dev)
97{
98 return (dev->features & NETIF_F_UFO) != 0;
99}
100
101int ethtool_op_set_ufo(struct net_device *dev, u32 data)
102{
103 if (data)
104 dev->features |= NETIF_F_UFO;
105 else
106 dev->features &= ~NETIF_F_UFO;
107 return 0;
108}
109
96/* Handlers for each ethtool command */ 110/* Handlers for each ethtool command */
97 111
98static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) 112static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
@@ -483,6 +497,11 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data)
483 return err; 497 return err;
484 } 498 }
485 499
500 if (!data && dev->ethtool_ops->set_ufo) {
501 err = dev->ethtool_ops->set_ufo(dev, 0);
502 if (err)
503 return err;
504 }
486 return dev->ethtool_ops->set_sg(dev, data); 505 return dev->ethtool_ops->set_sg(dev, data);
487} 506}
488 507
@@ -569,6 +588,32 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr)
569 return dev->ethtool_ops->set_tso(dev, edata.data); 588 return dev->ethtool_ops->set_tso(dev, edata.data);
570} 589}
571 590
591static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr)
592{
593 struct ethtool_value edata = { ETHTOOL_GTSO };
594
595 if (!dev->ethtool_ops->get_ufo)
596 return -EOPNOTSUPP;
597 edata.data = dev->ethtool_ops->get_ufo(dev);
598 if (copy_to_user(useraddr, &edata, sizeof(edata)))
599 return -EFAULT;
600 return 0;
601}
602static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
603{
604 struct ethtool_value edata;
605
606 if (!dev->ethtool_ops->set_ufo)
607 return -EOPNOTSUPP;
608 if (copy_from_user(&edata, useraddr, sizeof(edata)))
609 return -EFAULT;
610 if (edata.data && !(dev->features & NETIF_F_SG))
611 return -EINVAL;
612 if (edata.data && !(dev->features & NETIF_F_HW_CSUM))
613 return -EINVAL;
614 return dev->ethtool_ops->set_ufo(dev, edata.data);
615}
616
572static int ethtool_self_test(struct net_device *dev, char __user *useraddr) 617static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
573{ 618{
574 struct ethtool_test test; 619 struct ethtool_test test;
@@ -854,6 +899,12 @@ int dev_ethtool(struct ifreq *ifr)
854 case ETHTOOL_GPERMADDR: 899 case ETHTOOL_GPERMADDR:
855 rc = ethtool_get_perm_addr(dev, useraddr); 900 rc = ethtool_get_perm_addr(dev, useraddr);
856 break; 901 break;
902 case ETHTOOL_GUFO:
903 rc = ethtool_get_ufo(dev, useraddr);
904 break;
905 case ETHTOOL_SUFO:
906 rc = ethtool_set_ufo(dev, useraddr);
907 break;
857 default: 908 default:
858 rc = -EOPNOTSUPP; 909 rc = -EOPNOTSUPP;
859 } 910 }
@@ -882,3 +933,5 @@ EXPORT_SYMBOL(ethtool_op_set_sg);
882EXPORT_SYMBOL(ethtool_op_set_tso); 933EXPORT_SYMBOL(ethtool_op_set_tso);
883EXPORT_SYMBOL(ethtool_op_set_tx_csum); 934EXPORT_SYMBOL(ethtool_op_set_tx_csum);
884EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); 935EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
936EXPORT_SYMBOL(ethtool_op_set_ufo);
937EXPORT_SYMBOL(ethtool_op_get_ufo);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ef9d46b91eb9..95501e40100e 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -176,6 +176,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
176 skb_shinfo(skb)->tso_size = 0; 176 skb_shinfo(skb)->tso_size = 0;
177 skb_shinfo(skb)->tso_segs = 0; 177 skb_shinfo(skb)->tso_segs = 0;
178 skb_shinfo(skb)->frag_list = NULL; 178 skb_shinfo(skb)->frag_list = NULL;
179 skb_shinfo(skb)->ufo_size = 0;
180 skb_shinfo(skb)->ip6_frag_id = 0;
179out: 181out:
180 return skb; 182 return skb;
181nodata: 183nodata:
@@ -1696,6 +1698,78 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
1696 return textsearch_find(config, state); 1698 return textsearch_find(config, state);
1697} 1699}
1698 1700
1701/**
1702 * skb_append_datato_frags: - append the user data to a skb
1703 * @sk: sock structure
1704 * @skb: skb structure to be appened with user data.
1705 * @getfrag: call back function to be used for getting the user data
1706 * @from: pointer to user message iov
1707 * @length: length of the iov message
1708 *
1709 * Description: This procedure append the user data in the fragment part
1710 * of the skb if any page alloc fails user this procedure returns -ENOMEM
1711 */
1712int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
1713 int getfrag(void *from, char *to, int offset,
1714 int len, int odd, struct sk_buff *skb),
1715 void *from, int length)
1716{
1717 int frg_cnt = 0;
1718 skb_frag_t *frag = NULL;
1719 struct page *page = NULL;
1720 int copy, left;
1721 int offset = 0;
1722 int ret;
1723
1724 do {
1725 /* Return error if we don't have space for new frag */
1726 frg_cnt = skb_shinfo(skb)->nr_frags;
1727 if (frg_cnt >= MAX_SKB_FRAGS)
1728 return -EFAULT;
1729
1730 /* allocate a new page for next frag */
1731 page = alloc_pages(sk->sk_allocation, 0);
1732
1733 /* If alloc_page fails just return failure and caller will
1734 * free previous allocated pages by doing kfree_skb()
1735 */
1736 if (page == NULL)
1737 return -ENOMEM;
1738
1739 /* initialize the next frag */
1740 sk->sk_sndmsg_page = page;
1741 sk->sk_sndmsg_off = 0;
1742 skb_fill_page_desc(skb, frg_cnt, page, 0, 0);
1743 skb->truesize += PAGE_SIZE;
1744 atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
1745
1746 /* get the new initialized frag */
1747 frg_cnt = skb_shinfo(skb)->nr_frags;
1748 frag = &skb_shinfo(skb)->frags[frg_cnt - 1];
1749
1750 /* copy the user data to page */
1751 left = PAGE_SIZE - frag->page_offset;
1752 copy = (length > left)? left : length;
1753
1754 ret = getfrag(from, (page_address(frag->page) +
1755 frag->page_offset + frag->size),
1756 offset, copy, 0, skb);
1757 if (ret < 0)
1758 return -EFAULT;
1759
1760 /* copy was successful so update the size parameters */
1761 sk->sk_sndmsg_off += copy;
1762 frag->size += copy;
1763 skb->len += copy;
1764 skb->data_len += copy;
1765 offset += copy;
1766 length -= copy;
1767
1768 } while (length > 0);
1769
1770 return 0;
1771}
1772
1699void __init skb_init(void) 1773void __init skb_init(void)
1700{ 1774{
1701 skbuff_head_cache = kmem_cache_create("skbuff_head_cache", 1775 skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
@@ -1747,3 +1821,4 @@ EXPORT_SYMBOL(skb_prepare_seq_read);
1747EXPORT_SYMBOL(skb_seq_read); 1821EXPORT_SYMBOL(skb_seq_read);
1748EXPORT_SYMBOL(skb_abort_seq_read); 1822EXPORT_SYMBOL(skb_abort_seq_read);
1749EXPORT_SYMBOL(skb_find_text); 1823EXPORT_SYMBOL(skb_find_text);
1824EXPORT_SYMBOL(skb_append_datato_frags);