diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 14 | ||||
-rw-r--r-- | net/core/ethtool.c | 53 | ||||
-rw-r--r-- | net/core/skbuff.c | 75 |
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 | ||
96 | u32 ethtool_op_get_ufo(struct net_device *dev) | ||
97 | { | ||
98 | return (dev->features & NETIF_F_UFO) != 0; | ||
99 | } | ||
100 | |||
101 | int 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 | ||
98 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) | 112 | static 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 | ||
591 | static 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 | } | ||
602 | static 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 | |||
572 | static int ethtool_self_test(struct net_device *dev, char __user *useraddr) | 617 | static 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); | |||
882 | EXPORT_SYMBOL(ethtool_op_set_tso); | 933 | EXPORT_SYMBOL(ethtool_op_set_tso); |
883 | EXPORT_SYMBOL(ethtool_op_set_tx_csum); | 934 | EXPORT_SYMBOL(ethtool_op_set_tx_csum); |
884 | EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); | 935 | EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); |
936 | EXPORT_SYMBOL(ethtool_op_set_ufo); | ||
937 | EXPORT_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; | ||
179 | out: | 181 | out: |
180 | return skb; | 182 | return skb; |
181 | nodata: | 183 | nodata: |
@@ -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 | */ | ||
1712 | int 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 | |||
1699 | void __init skb_init(void) | 1773 | void __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); | |||
1747 | EXPORT_SYMBOL(skb_seq_read); | 1821 | EXPORT_SYMBOL(skb_seq_read); |
1748 | EXPORT_SYMBOL(skb_abort_seq_read); | 1822 | EXPORT_SYMBOL(skb_abort_seq_read); |
1749 | EXPORT_SYMBOL(skb_find_text); | 1823 | EXPORT_SYMBOL(skb_find_text); |
1824 | EXPORT_SYMBOL(skb_append_datato_frags); | ||