Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH 1/2] net: asix: init ASIX AX88772B MAC from EEPROM
From: Oliver Neukum @ 2012-12-18 13:11 UTC (permalink / raw)
  To: Lucas Stach; +Cc: netdev, linux-usb
In-Reply-To: <1355832626-3034-1-git-send-email-dev@lynxeye.de>

On Tuesday 18 December 2012 13:10:25 Lucas Stach wrote:
> diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
> index 9bbeabf..8e9516f 100644
> --- a/include/linux/usb/usbnet.h
> +++ b/include/linux/usb/usbnet.h
> @@ -106,6 +106,7 @@ struct driver_info {
>   */
>  #define FLAG_MULTI_PACKET      0x2000
>  #define FLAG_RX_ASSEMBLE       0x4000  /* rx packets may span >1 frames */
> +#define FLAG_EEPROM_MAC                0x8000  /* initialize device MAC from eeprom */

Hi,

this looks sensible, but
why are you adding a flag unused in usbnet to usbnet.h?

	Regards
		Oliver

^ permalink raw reply

* [PATCH] net: fec: forbid FEC_PTP on SoCs that do not support
From: Shawn Guo @ 2012-12-18 13:06 UTC (permalink / raw)
  To: netdev; +Cc: Sascha Hauer, Richard Cochran, David S. Miller, Shawn Guo

Beside imx6q, the kernel built from imx_v6_v7_defconfig is also
supposed to be running on other IMX SoCs that do not have the PTP
block.  Before fec driver gets fixed to run-time detect target hardware
rather than conditional compiling with #ifdef CONFIG_FEC_PTP, let's
give it a quick fix in Kconfig to forbid FEC_PTP on those IMX SoCs that
do not support PTP.

Reported-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/net/ethernet/freescale/Kconfig |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 5ba6e1c..ec490d7 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -94,9 +94,8 @@ config GIANFAR
 
 config FEC_PTP
 	bool "PTP Hardware Clock (PHC)"
-	depends on FEC && ARCH_MXC
+	depends on FEC && ARCH_MXC && !SOC_IMX25 && !SOC_IMX27 && !SOC_IMX35 && !SOC_IMX5
 	select PTP_1588_CLOCK
-	default y if SOC_IMX6Q
 	--help---
 	  Say Y here if you want to use PTP Hardware Clock (PHC) in the
 	  driver.  Only the basic clock operations have been implemented.
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH v2] netlink: align attributes on 64-bits
From: Thomas Graf @ 2012-12-18 12:57 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: bhutchings, netdev, davem, David.Laight
In-Reply-To: <1355762980-4285-1-git-send-email-nicolas.dichtel@6wind.com>

On 12/17/12 at 05:49pm, Nicolas Dichtel wrote:
> @@ -492,6 +492,15 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb,
>   */
>  static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags)
>  {
> +	/* Because attributes may be aligned on 64-bits boundary with fake
> +	 * attribute (type 0, size 4 (attributes are 32-bits align by default)),
> +	 * an exact payload size cannot be calculated. Hence, we need to reserve
> +	 * more space for these attributes.
> +	 * 128 is arbitrary: it allows to align up to 32 attributes.
> +	 */
> +	if (payload < NLMSG_DEFAULT_SIZE)
> +		payload = min(payload + 128, (size_t)NLMSG_DEFAULT_SIZE);

This is doomed to fail eventually. A netlink message may carry
hundreds of attributes eventually. See my suggestion below.

> diff --git a/lib/nlattr.c b/lib/nlattr.c
> index 18eca78..7440a80 100644
> --- a/lib/nlattr.c
> +++ b/lib/nlattr.c
> @@ -450,9 +450,18 @@ EXPORT_SYMBOL(__nla_put_nohdr);
>   */
>  int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
>  {
> -	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
> +	int align = IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8) ? 0 : 4;

This does not look right. In order for the attribute data to be
aligned properly you would need to check skb_tail_pointer(skb) +
NLA_HDRLEN for proper alignment or you end up aligning the
attribute header.

How about we change nla_total_size() to return the size with
needed padding taken into account. That should fix the message
size caluclation problem and we only need to reserve room for
the initial padding to align the very first attribute.

Below is an untested patch that does this. What do you think?

diff --git a/include/net/netlink.h b/include/net/netlink.h
index 9690b0f..7ce8e76 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -114,7 +114,6 @@
  * Attribute Length Calculations:
  *   nla_attr_size(payload)		length of attribute w/o padding
  *   nla_total_size(payload)		length of attribute w/ padding
- *   nla_padlen(payload)		length of padding
  *
  * Attribute Payload Access:
  *   nla_data(nla)			head of attribute payload
@@ -492,6 +491,14 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb,
  */
 static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags)
 {
+	/* If an exact size if specified, reserve some additional space to
+	 * align the first attribute, all subsequent attributes should have
+	 * padding accounted for.
+	 */
+	if (payload != NLMSG_DEFAULT_SIZE)
+		payload = min_t(size_t, payload + NLA_ATTR_ALIGN,
+				NLMSG_DEFAULT_SIZE);
+
 	return alloc_skb(nlmsg_total_size(payload), flags);
 }
 
@@ -653,16 +660,12 @@ static inline int nla_attr_size(int payload)
  */
 static inline int nla_total_size(int payload)
 {
-	return NLA_ALIGN(nla_attr_size(payload));
-}
+	size_t len = NLA_ALIGN(nla_attr_size(payload));
 
-/**
- * nla_padlen - length of padding at the tail of attribute
- * @payload: length of payload
- */
-static inline int nla_padlen(int payload)
-{
-	return nla_total_size(payload) - nla_attr_size(payload);
+	if (!IS_ALIGNED(len, NLA_ATTR_ALIGN))
+		len = ALIGN(len + NLA_HDRLEN, NLA_ATTR_ALIGN);
+
+	return len;
 }
 
 /**
diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index 78d5b8a..1856729 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -149,5 +149,10 @@ struct nlattr {
 #define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
 #define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
 
+/* Padding attribute type, added automatically to align attributes,
+ * must be ignored by readers. */
+#define NLA_PADDING		0
+#define NLA_ATTR_ALIGN		8
+
 
 #endif /* _UAPI__LINUX_NETLINK_H */
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 18eca78..b09473c 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -322,18 +322,36 @@ int nla_strcmp(const struct nlattr *nla, const char *str)
  * Adds a netlink attribute header to a socket buffer and reserves
  * room for the payload but does not copy it.
  *
+ * May add a padding attribute of type NLA_PADDING before the
+ * real attribute to ensure proper alignment.
+ *
  * The caller is responsible to ensure that the skb provides enough
  * tailroom for the attribute header and payload.
  */
 struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 {
 	struct nlattr *nla;
+	size_t offset;
+
+	offset = (size_t) skb_tail_pointer(skb);
+	if (!IS_ALIGNED(offset + NLA_HDRLEN, NLA_ATTR_ALIGN)) {
+		struct nlattr *pad;
+		size_t padlen;
+
+		padlen = nla_total_size(offset) - offset - NLA_HDRLEN;
+		pad = (struct nlattr *) skb_put(skb, nla_attr_size(padlen));
+		pad->nla_type = 0;
+		pad->nla_len = nla_attr_size(padlen);
+
+		memset((unsigned char *) pad + NLA_HDRLEN, 0, padlen);
+	}
 
-	nla = (struct nlattr *) skb_put(skb, nla_total_size(attrlen));
+	nla = (struct nlattr *) skb_put(skb, NLA_ALIGN(nla_attr_size(attrlen)));
 	nla->nla_type = attrtype;
 	nla->nla_len = nla_attr_size(attrlen);
 
-	memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
+	memset((unsigned char *) nla + nla->nla_len, 0,
+	       NLA_ALIGN(nla->nla_len) - nla->nla_len);
 
 	return nla;
 }
@@ -360,6 +378,23 @@ void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
 }
 EXPORT_SYMBOL(__nla_reserve_nohdr);
 
+static size_t nla_pre_padlen(struct sk_buff *skb)
+{
+	size_t offset = (size_t) skb_tail_pointer(skb);
+
+	if (!IS_ALIGNED(offset + NLA_HDRLEN, NLA_ATTR_ALIGN))
+		return nla_total_size(offset) - offset - NLA_HDRLEN;
+
+	return 0;
+}
+
+static bool nla_insufficient_space(struct sk_buff *skb, int attrlen)
+{
+	size_t needed = nla_pre_padlen(skb) + nla_total_size(attrlen);
+
+	return (skb_tailroom(skb) < needed);
+}
+
 /**
  * nla_reserve - reserve room for attribute on the skb
  * @skb: socket buffer to reserve room on
@@ -374,7 +409,7 @@ EXPORT_SYMBOL(__nla_reserve_nohdr);
  */
 struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 {
-	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
+	if (unlikely(nla_insufficient_space(skb, attrlen)))
 		return NULL;
 
 	return __nla_reserve(skb, attrtype, attrlen);
@@ -450,7 +485,7 @@ EXPORT_SYMBOL(__nla_put_nohdr);
  */
 int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
 {
-	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
+	if (unlikely(nla_insufficient_space(skb, attrlen)))
 		return -EMSGSIZE;
 
 	__nla_put(skb, attrtype, attrlen, data);

^ permalink raw reply related

* RE: [PATCH net-next] be2net: fix INTx ISR for interrupt behaviour on BE2
From: Perla, Sathya @ 2012-12-18 12:57 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: netdev@vger.kernel.org
In-Reply-To: <1354134328.2768.16.camel@bwh-desktop.uk.solarflarecom.com>

>-----Original Message-----
>From: Ben Hutchings [mailto:bhutchings@solarflare.com]

>On Wed, 2012-11-28 at 20:20 +0000, Ben Hutchings wrote:
>> On Wed, 2012-11-28 at 11:20 +0530, Sathya Perla wrote:
>> > On BE2 chip, an interrupt may be raised even when EQ is in un-armed state.
>> > As a result be_intx()::events_get() and be_poll:events_get() can race and
>> > notify an EQ wrongly.
>> >
>> > Fix this by counting events only in be_poll(). Commit 0b545a629 fixes
>> > the same issue in the MSI-x path.
>> >
>> > But, on Lancer, INTx can be de-asserted only by notifying num evts. This
>> > is not an issue as the above BE2 behavior doesn't exist/has never been
>> > seen on Lancer.
>> [...]
>> > @@ -2014,15 +1996,23 @@ static int be_rx_cqs_create(struct be_adapter
>*adapter)
>> >
>> >  static irqreturn_t be_intx(int irq, void *dev)
>> >  {
>> > -	struct be_adapter *adapter = dev;
>> > -	int num_evts;
>> > +	struct be_eq_obj *eqo = dev;
>> > +	struct be_adapter *adapter = eqo->adapter;
>> > +	int num_evts = 0;
>> >
>> > -	/* With INTx only one EQ is used */
>> > -	num_evts = event_handle(&adapter->eq_obj[0]);
>> > -	if (num_evts)
>> > -		return IRQ_HANDLED;
>> > -	else
>> > -		return IRQ_NONE;
>> > +	/* On Lancer, clear-intr bit of the EQ DB does not work.
>> > +	 * INTx is de-asserted only on notifying num evts.
>> > +	 */
>> > +	if (lancer_chip(adapter))
>> > +		num_evts = events_get(eqo);
>> > +
>> > +	/* The EQ-notify may not de-assert INTx rightaway, causing
>> > +	 * the ISR to be invoked again. So, return HANDLED even when
>> > +	 * num_evts is zero.
>> > +	 */
>> > +	be_eq_notify(adapter, eqo->q.id, false, true, num_evts);
>> > +	napi_schedule(&eqo->napi);
>> > +	return IRQ_HANDLED;
>> >  }
>> [...]
>>
>> You shouldn't unconditionally return IRQ_HANDLED.  This prevents
>> interrupt storm detection from working, not just for your device but for
>> anything else sharing its IRQ.
>>
>> I understand there is a real problem to be fixed (PCIe write completions
>> overtaking INTx deassertion, and maybe a specific hardware bug).
>[...]
>
>I was thinking of read completions; there are no write completions to
>wait for so you're pretty much guaranteed to get called a second time.
>Maybe you should add an MMIO read after calling be_eq_notify().

Ben, I'm very sorry for not replying to this thread earlier. I needed time to play with
your suggested solution and better understand the HW behavior in this case.

Adding an extra PCI memory read after the EQ-notify helps in syncing the PCI de-assert
message *only* if it was already issued.
But, there are cases when the HW block takes some time (longer) to initiate the INTx de-assert.
The PCI memory read would complete but the de-assert wouldn't have happened yet.
The PCI read sync will work only if the de-assert was issued *before* the PCI-read request was seen by the HW.

thanks,
-Sathya

^ permalink raw reply

* Re: RFC [PATCH] iproute2: temporary solution to fix xt breakage
From: Jamal Hadi Salim @ 2012-12-18 12:28 UTC (permalink / raw)
  To: Hasan Chowdhury
  Cc: Stephen Hemminger, Jan Engelhardt, Yury Stankevich,
	netdev@vger.kernel.org, pablo, netfilter-devel
In-Reply-To: <CAASe=fRuJdtisEvp7uo=PHwN3nKHqsYDW4Om1gk2MK-vyNvBrA@mail.gmail.com>

On 12-12-17 11:10 AM, Hasan Chowdhury wrote:
> Juts noticed , the attached patch does not have the modification for
> m_xt.c , without it   ,I guess this patch  is not going  to work.


Thats in the first patch i sent out which I hope Stephen will apply
right away.
This one depends on that. So you must apply that patch, then this.

cheers,
jamal



^ permalink raw reply

* [PATCH 1/2] net: asix: init ASIX AX88772B MAC from EEPROM
From: Lucas Stach @ 2012-12-18 12:10 UTC (permalink / raw)
  To: netdev; +Cc: Oliver Neukum, linux-usb

The device comes up with a MAC address of all zeros. We need to read the
initial device MAC from EEPROM so it can be set properly later.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
---
A similar fix was added into U-Boot:
http://patchwork.ozlabs.org/patch/179409/
---
 drivers/net/usb/asix_devices.c | 29 ++++++++++++++++++++++++++---
 include/linux/usb/usbnet.h     |  1 +
 2 Dateien geändert, 27 Zeilen hinzugefügt(+), 3 Zeilen entfernt(-)

diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 7a6e758..06f7f7cb 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -422,14 +422,25 @@ static const struct net_device_ops ax88772_netdev_ops = {
 
 static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-	int ret, embd_phy;
+	int ret, embd_phy, i;
 	u8 buf[ETH_ALEN];
 	u32 phyid;
 
 	usbnet_get_endpoints(dev,intf);
 
 	/* Get the MAC address */
-	ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
+	if (dev->driver_info->flags & FLAG_EEPROM_MAC) {
+		for (i = 0; i < (ETH_ALEN >> 1); i++) {
+			ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i,
+					0, 2, buf + i * 2);
+			if (ret < 0)
+				break;
+		}
+	} else {
+		ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+				0, 0, ETH_ALEN, buf);
+	}
+
 	if (ret < 0) {
 		netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
 		return ret;
@@ -872,6 +883,18 @@ static const struct driver_info ax88772_info = {
 	.tx_fixup = asix_tx_fixup,
 };
 
+static const struct driver_info ax88772b_info = {
+	.description = "ASIX AX88772B USB 2.0 Ethernet",
+	.bind = ax88772_bind,
+	.status = asix_status,
+	.link_reset = ax88772_link_reset,
+	.reset = ax88772_reset,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+	         FLAG_MULTI_PACKET | FLAG_EEPROM_MAC,
+	.rx_fixup = asix_rx_fixup,
+	.tx_fixup = asix_tx_fixup,
+};
+
 static const struct driver_info ax88178_info = {
 	.description = "ASIX AX88178 USB 2.0 Ethernet",
 	.bind = ax88178_bind,
@@ -953,7 +976,7 @@ static const struct usb_device_id	products [] = {
 }, {
 	// ASIX AX88772B 10/100
 	USB_DEVICE (0x0b95, 0x772b),
-	.driver_info = (unsigned long) &ax88772_info,
+	.driver_info = (unsigned long) &ax88772b_info,
 }, {
 	// ASIX AX88772 10/100
 	USB_DEVICE (0x0b95, 0x7720),
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 9bbeabf..8e9516f 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -106,6 +106,7 @@ struct driver_info {
  */
 #define FLAG_MULTI_PACKET	0x2000
 #define FLAG_RX_ASSEMBLE	0x4000	/* rx packets may span >1 frames */
+#define FLAG_EEPROM_MAC		0x8000	/* initialize device MAC from eeprom */
 
 	/* init device ... can sleep, or cause probe() failure */
 	int	(*bind)(struct usbnet *, struct usb_interface *);
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH 2/2] net: asix: handle packets crossing URB boundaries
From: Lucas Stach @ 2012-12-18 12:10 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Oliver Neukum, linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1355832626-3034-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>

ASIX AX88772B started to pack data even more tightly. Packets and the ASIX packet
header may now cross URB boundaries. To handle this we have to introduce
some state between individual calls to asix_rx_fixup().

Signed-off-by: Lucas Stach <dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
---
I've running this patch for some weeks already now and it gets rid of all
the commonly seen rx failures with AX88772B.
---
 drivers/net/usb/asix.h         | 10 ++++++
 drivers/net/usb/asix_common.c  | 81 +++++++++++++++++++++++++++++-------------
 drivers/net/usb/asix_devices.c |  8 +++++
 3 Dateien geändert, 75 Zeilen hinzugefügt(+), 24 Zeilen entfernt(-)

diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h
index e889631..3b4f7a8 100644
--- a/drivers/net/usb/asix.h
+++ b/drivers/net/usb/asix.h
@@ -167,6 +167,16 @@ struct asix_data {
 	u8 res;
 };
 
+struct asix_rx_fixup_info {
+	struct sk_buff *ax_skb;
+	u32 header;
+	u16 size;
+	bool split_head;
+};
+struct asix_private {
+	struct asix_rx_fixup_info rx_fixup_info;
+};
+
 int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
 		  u16 size, void *data);
 
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 50d1673..17f9801 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -53,44 +53,77 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
 
 int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
+	struct asix_private *dp = dev->driver_priv;
+	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
 	int offset = 0;
 
-	while (offset + sizeof(u32) < skb->len) {
-		struct sk_buff *ax_skb;
-		u16 size;
-		u32 header = get_unaligned_le32(skb->data + offset);
-
-		offset += sizeof(u32);
-
-		/* get the packet length */
-		size = (u16) (header & 0x7ff);
-		if (size != ((~header >> 16) & 0x07ff)) {
-			netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
-			return 0;
+	while (offset + sizeof(u16) <= skb->len) {
+		u16 remaining = 0;
+		unsigned char *data;
+
+		if (!rx->size) {
+			if ((skb->len - offset == sizeof(u16)) ||
+			    rx->split_head) {
+				if(!rx->split_head) {
+					rx->header = get_unaligned_le16(
+							skb->data + offset);
+					rx->split_head = true;
+					offset += sizeof(u16);
+					break;
+				} else {
+					rx->header |= (get_unaligned_le16(
+							skb->data + offset)
+							<< 16);
+					rx->split_head = false;
+					offset += sizeof(u16);
+				}
+			} else {
+				rx->header = get_unaligned_le32(skb->data +
+								offset);
+				offset += sizeof(u32);
+			}
+
+			/* get the packet length */
+			rx->size = (u16) (rx->header & 0x7ff);
+			if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
+				netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
+					   rx->header, offset);
+				rx->size = 0;
+				return 0;
+			}
+			rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
+							       rx->size);
+			if (!rx->ax_skb)
+				return 0;
 		}
 
-		if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
-		    (size + offset > skb->len)) {
+		if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
 			netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
-				   size);
+				   rx->size);
+			kfree_skb(rx->ax_skb);
 			return 0;
 		}
-		ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
-		if (!ax_skb)
-			return 0;
 
-		skb_put(ax_skb, size);
-		memcpy(ax_skb->data, skb->data + offset, size);
-		usbnet_skb_return(dev, ax_skb);
+		if (rx->size > skb->len - offset) {
+			remaining = rx->size - (skb->len - offset);
+			rx->size = skb->len - offset;
+		}
+
+		data = skb_put(rx->ax_skb, rx->size);
+		memcpy(data, skb->data + offset, rx->size);
+		if (!remaining)
+			usbnet_skb_return(dev, rx->ax_skb);
 
-		offset += (size + 1) & 0xfffe;
+		offset += (rx->size + 1) & 0xfffe;
+		rx->size = remaining;
 	}
 
 	if (skb->len != offset) {
-		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
-			   skb->len);
+		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
+			   skb->len, offset);
 		return 0;
 	}
+
 	return 1;
 }
 
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 06f7f7cb..2e1f3ec 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -495,6 +495,10 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
 		dev->rx_urb_size = 2048;
 	}
 
+	dev->driver_priv = kzalloc(sizeof(struct asix_private), GFP_KERNEL);
+	if (!dev->driver_priv)
+		return -ENOMEM;
+
 	return 0;
 }
 
@@ -829,6 +833,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
 		dev->rx_urb_size = 2048;
 	}
 
+	dev->driver_priv = kzalloc(sizeof(struct asix_private), GFP_KERNEL);
+	if (!dev->driver_priv)
+			return -ENOMEM;
+
 	return 0;
 }
 
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [GIT PULL net-next 17/17] ndisc: Use return value of __skb_put(), instead of icmp6_hdr().
From: YOSHIFUJI Hideaki @ 2012-12-18 10:56 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

It is safe to use __skb_put() here and it returns buffer for
ICMPv6 header.  Let's use it.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index e614388..232daea 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1469,8 +1469,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	if (!buff)
 		goto release;
 
-	skb_put(buff, sizeof(struct red_msg));
-	msg = (struct red_msg *)icmp6_hdr(buff);
+	msg = (struct red_msg *)__skb_put(buff, sizeof(struct red_msg));
 	*msg = (struct red_msg) {
 		.icmph = {
 			.icmp6_type = NDISC_REDIRECT,
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 16/17] ndisc: Fill in ND message on skb directly.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:56 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Use compound literals to fill out ND message on skb.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   55 +++++++++++++++++++++++++++---------------------------
 1 file changed, 27 insertions(+), 28 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 580a2f0..e614388 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -477,9 +477,6 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 	struct in6_addr tmpaddr;
 	struct inet6_ifaddr *ifp;
 	const struct in6_addr *src_addr;
-	struct icmp6hdr icmp6h = {
-		.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
-	};
 	struct nd_msg *msg;
 	int optlen = 0;
 	struct sk_buff *skb;
@@ -505,17 +502,20 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 	if (inc_opt)
 		optlen += ndisc_opt_addr_space(dev);
 
-	icmp6h.icmp6_router = router;
-	icmp6h.icmp6_solicited = solicited;
-	icmp6h.icmp6_override = override;
-
 	skb = ndisc_alloc_skb(dev, sizeof(struct nd_msg) + optlen);
 	if (!skb)
 		return;
 
 	msg = (struct nd_msg *)__skb_put(skb, sizeof(struct nd_msg));
-	memcpy(msg, &icmp6h, sizeof(icmp6h));
-	msg->target = *solicited_addr;
+	*msg = (struct nd_msg) {
+		.icmph = {
+			.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
+			.icmp6_router = router,
+			.icmp6_solicited = solicited,
+			.icmp6_override = override,
+		},
+		.target = *solicited_addr,
+	};
 
 	if (inc_opt)
 		ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
@@ -550,9 +550,6 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 		   const struct in6_addr *daddr, const struct in6_addr *saddr)
 {
 	struct in6_addr addr_buf;
-	struct icmp6hdr icmp6h = {
-		.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
-	};
 	struct nd_msg *msg;
 	int inc_opt = dev->addr_len;
 	int optlen = 0;
@@ -575,8 +572,12 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 		return;
 
 	msg = (struct nd_msg *)__skb_put(skb, sizeof(struct nd_msg));
-	memcpy(&msg->icmph, &icmp6h, sizeof(msg->icmph));
-	msg->target = *solicit;
+	*msg = (struct nd_msg) {
+		.icmph = {
+			.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
+		},
+		.target = *solicit,
+	};
 
 	if (inc_opt)
 		ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
@@ -588,9 +589,6 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
 		   const struct in6_addr *daddr)
 {
-	struct icmp6hdr icmp6h = {
-		.icmp6_type = NDISC_ROUTER_SOLICITATION,
-	};
 	struct rs_msg *msg;
 	int send_sllao = dev->addr_len;
 	int optlen = 0;
@@ -628,7 +626,11 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
 		return;
 
 	msg = (struct rs_msg *)__skb_put(skb, sizeof(struct rs_msg));
-	memcpy(&msg->icmph, &icmp6h, sizeof(msg->icmph));
+	*msg = (struct rs_msg) {
+		.icmph = {
+			.icmp6_type = NDISC_ROUTER_SOLICITATION,
+		},
+	};
 
 	if (send_sllao)
 		ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
@@ -1469,16 +1471,13 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 
 	skb_put(buff, sizeof(struct red_msg));
 	msg = (struct red_msg *)icmp6_hdr(buff);
-
-	memset(&msg->icmph, 0, sizeof(struct icmp6hdr));
-	msg->icmph.icmp6_type = NDISC_REDIRECT;
-
-	/*
-	 *	copy target and destination addresses
-	 */
-
-	msg->target = *target;
-	msg->dest = ipv6_hdr(skb)->daddr;
+	*msg = (struct red_msg) {
+		.icmph = {
+			.icmp6_type = NDISC_REDIRECT,
+		},
+		.target = *target,
+		.dest = ipv6_hdr(skb)->daddr,
+	};
 
 	/*
 	 *	include target_address option
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 15/17] ndisc: Break down ndisc_build_skb().
From: YOSHIFUJI Hideaki @ 2012-12-18 10:56 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Split up ndisc_build_skb() into pieces; sk_buff allocation
by ndisc_allocl_skb(), filling out the core message and
options.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   98 ++++++++++++++++++++++++++----------------------------
 1 file changed, 48 insertions(+), 50 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index c974d9d..580a2f0 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -410,47 +410,6 @@ static void ip6_nd_hdr(struct sk_buff *skb, const struct in6_addr *saddr,
 	hdr->payload_len = htons(len);
 }
 
-static struct sk_buff *ndisc_build_skb(struct net_device *dev,
-				       const struct in6_addr *daddr,
-				       const struct in6_addr *saddr,
-				       struct icmp6hdr *icmp6h,
-				       const struct in6_addr *target,
-				       int llinfo)
-{
-	struct sk_buff *skb;
-	struct icmp6hdr *hdr;
-	int len;
-	int optlen = 0;
-	u8 *opt;
-
-	if (!dev->addr_len)
-		llinfo = 0;
-
-	len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
-	if (llinfo)
-		optlen += ndisc_opt_addr_space(dev);
-
-	skb = ndisc_alloc_skb(dev, len + optlen);
-	if (!skb)
-		return NULL;
-
-	skb_put(skb, len);
-
-	hdr = (struct icmp6hdr *)skb_transport_header(skb);
-	memcpy(hdr, icmp6h, sizeof(*hdr));
-
-	opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
-	if (target) {
-		*(struct in6_addr *)opt = *target;
-		opt += sizeof(*target);
-	}
-
-	if (llinfo)
-		ndisc_fill_addr_option(skb, llinfo, dev->dev_addr);
-
-	return skb;
-}
-
 static void __ndisc_send(struct sk_buff *skb, struct dst_entry *dst,
 			 const struct in6_addr *daddr,
 			 const struct in6_addr *saddr)
@@ -521,6 +480,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 	struct icmp6hdr icmp6h = {
 		.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
 	};
+	struct nd_msg *msg;
+	int optlen = 0;
 	struct sk_buff *skb;
 
 	/* for anycast or proxy, solicited_addr != src_addr */
@@ -539,16 +500,27 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 		src_addr = &tmpaddr;
 	}
 
+	if (!dev->addr_len)
+		inc_opt = 0;
+	if (inc_opt)
+		optlen += ndisc_opt_addr_space(dev);
+
 	icmp6h.icmp6_router = router;
 	icmp6h.icmp6_solicited = solicited;
 	icmp6h.icmp6_override = override;
 
-	skb = ndisc_build_skb(dev, daddr, src_addr,
-			      &icmp6h, solicited_addr,
-			      inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
+	skb = ndisc_alloc_skb(dev, sizeof(struct nd_msg) + optlen);
 	if (!skb)
 		return;
 
+	msg = (struct nd_msg *)__skb_put(skb, sizeof(struct nd_msg));
+	memcpy(msg, &icmp6h, sizeof(icmp6h));
+	msg->target = *solicited_addr;
+
+	if (inc_opt)
+		ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
+				       dev->dev_addr);
+
 	ndisc_send(skb, neigh, daddr, src_addr);
 }
 
@@ -581,6 +553,9 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 	struct icmp6hdr icmp6h = {
 		.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
 	};
+	struct nd_msg *msg;
+	int inc_opt = dev->addr_len;
+	int optlen = 0;
 	struct sk_buff *skb;
 
 	if (saddr == NULL) {
@@ -590,12 +565,23 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 		saddr = &addr_buf;
 	}
 
-	skb = ndisc_build_skb(dev, daddr, saddr,
-			      &icmp6h, solicit,
-			      !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
+	if (ipv6_addr_any(saddr))
+		inc_opt = 0;
+	if (inc_opt)
+		optlen += ndisc_opt_addr_space(dev);
+
+	skb = ndisc_alloc_skb(dev, sizeof(struct nd_msg) + optlen);
 	if (!skb)
 		return;
 
+	msg = (struct nd_msg *)__skb_put(skb, sizeof(struct nd_msg));
+	memcpy(&msg->icmph, &icmp6h, sizeof(msg->icmph));
+	msg->target = *solicit;
+
+	if (inc_opt)
+		ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
+				       dev->dev_addr);
+
 	ndisc_send(skb, neigh, daddr, saddr);
 }
 
@@ -605,7 +591,9 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
 	struct icmp6hdr icmp6h = {
 		.icmp6_type = NDISC_ROUTER_SOLICITATION,
 	};
+	struct rs_msg *msg;
 	int send_sllao = dev->addr_len;
+	int optlen = 0;
 	struct sk_buff *skb;
 
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -630,12 +618,22 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
 		}
 	}
 #endif
-	skb = ndisc_build_skb(dev, daddr, saddr,
-			      &icmp6h, NULL,
-			      send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
+	if (!dev->addr_len)
+		send_sllao = 0;
+	if (send_sllao)
+		optlen += ndisc_opt_addr_space(dev);
+
+	skb = ndisc_alloc_skb(dev, sizeof(struct rs_msg) + optlen);
 	if (!skb)
 		return;
 
+	msg = (struct rs_msg *)__skb_put(skb, sizeof(struct rs_msg));
+	memcpy(&msg->icmph, &icmp6h, sizeof(msg->icmph));
+
+	if (send_sllao)
+		ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
+				       dev->dev_addr);
+
 	ndisc_send(skb, NULL, daddr, saddr);
 }
 
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 14/17] ndisc: Concentrate ndisc_send() on sending message.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:56 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Build NDISC message outside ndisc_send() and concentrate the
function sending sk_buff with given destination/source.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   51 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 30 insertions(+), 21 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index c0937d3..c974d9d 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -488,26 +488,20 @@ static void __ndisc_send(struct sk_buff *skb, struct dst_entry *dst,
 /*
  *	Send a Neighbour Discover packet
  */
-static void ndisc_send(struct net_device *dev,
+static void ndisc_send(struct sk_buff *skb,
 		       struct neighbour *neigh,
 		       const struct in6_addr *daddr,
-		       const struct in6_addr *saddr,
-		       struct icmp6hdr *icmp6h, const struct in6_addr *target,
-		       int llinfo)
+		       const struct in6_addr *saddr)
 {
 	struct flowi6 fl6;
 	struct dst_entry *dst;
-	struct net *net = dev_net(dev);
+	struct net *net = dev_net(skb->dev);
 	struct sock *sk = net->ipv6.ndisc_sk;
-	struct sk_buff *skb;
+	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
 	u8 type = icmp6h->icmp6_type;
 
-	skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
-	if (!skb)
-		return;
-
-	icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
-	dst = icmp6_dst_alloc(dev, neigh, &fl6);
+	icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
+	dst = icmp6_dst_alloc(skb->dev, neigh, &fl6);
 	if (IS_ERR(dst)) {
 		kfree_skb(skb);
 		return;
@@ -527,6 +521,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 	struct icmp6hdr icmp6h = {
 		.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
 	};
+	struct sk_buff *skb;
 
 	/* for anycast or proxy, solicited_addr != src_addr */
 	ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
@@ -548,9 +543,13 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 	icmp6h.icmp6_solicited = solicited;
 	icmp6h.icmp6_override = override;
 
-	ndisc_send(dev, neigh, daddr, src_addr,
-		   &icmp6h, solicited_addr,
-		   inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
+	skb = ndisc_build_skb(dev, daddr, src_addr,
+			      &icmp6h, solicited_addr,
+			      inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
+	if (!skb)
+		return;
+
+	ndisc_send(skb, neigh, daddr, src_addr);
 }
 
 static void ndisc_send_unsol_na(struct net_device *dev)
@@ -582,6 +581,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 	struct icmp6hdr icmp6h = {
 		.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
 	};
+	struct sk_buff *skb;
 
 	if (saddr == NULL) {
 		if (ipv6_get_lladdr(dev, &addr_buf,
@@ -590,9 +590,13 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 		saddr = &addr_buf;
 	}
 
-	ndisc_send(dev, neigh, daddr, saddr,
-		   &icmp6h, solicit,
-		   !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
+	skb = ndisc_build_skb(dev, daddr, saddr,
+			      &icmp6h, solicit,
+			      !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
+	if (!skb)
+		return;
+
+	ndisc_send(skb, neigh, daddr, saddr);
 }
 
 void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
@@ -602,6 +606,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
 		.icmp6_type = NDISC_ROUTER_SOLICITATION,
 	};
 	int send_sllao = dev->addr_len;
+	struct sk_buff *skb;
 
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
 	/*
@@ -625,9 +630,13 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
 		}
 	}
 #endif
-	ndisc_send(dev, NULL, daddr, saddr,
-		   &icmp6h, NULL,
-		   send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
+	skb = ndisc_build_skb(dev, daddr, saddr,
+			      &icmp6h, NULL,
+			      send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
+	if (!skb)
+		return;
+
+	ndisc_send(skb, NULL, daddr, saddr);
 }
 
 
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 13/17] ndisc: Calculate checksum and build IPv6 header in __ndisc_send().
From: YOSHIFUJI Hideaki @ 2012-12-18 10:56 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 5458aed..c0937d3 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -417,8 +417,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 				       const struct in6_addr *target,
 				       int llinfo)
 {
-	struct net *net = dev_net(dev);
-	struct sock *sk = net->ipv6.ndisc_sk;
 	struct sk_buff *skb;
 	struct icmp6hdr *hdr;
 	int len;
@@ -450,19 +448,15 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	if (llinfo)
 		ndisc_fill_addr_option(skb, llinfo, dev->dev_addr);
 
-	hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
-					   IPPROTO_ICMPV6,
-					   csum_partial(hdr,
-							skb->len, 0));
-
-	ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
-
 	return skb;
 }
 
-static void __ndisc_send(struct sk_buff *skb, struct dst_entry *dst)
+static void __ndisc_send(struct sk_buff *skb, struct dst_entry *dst,
+			 const struct in6_addr *daddr,
+			 const struct in6_addr *saddr)
 {
 	struct net *net = dev_net(dst->dev);
+	struct sock *sk = net->ipv6.ndisc_sk;
 	struct inet6_dev *idev;
 	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
 	u8 type = icmp6h->icmp6_type;
@@ -470,6 +464,13 @@ static void __ndisc_send(struct sk_buff *skb, struct dst_entry *dst)
 
 	skb_dst_set(skb, dst);
 
+	icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr,
+					      skb->len, IPPROTO_ICMPV6,
+					      csum_partial(icmp6h, skb->len, 0));
+
+	ip6_nd_hdr(skb, saddr, daddr,
+		   inet6_sk(sk)->hop_limit, skb->len);
+
 	rcu_read_lock();
 	idev = __in6_dev_get(dst->dev);
 	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
@@ -512,7 +513,7 @@ static void ndisc_send(struct net_device *dev,
 		return;
 	}
 
-	__ndisc_send(skb, dst);
+	__ndisc_send(skb, dst, daddr, saddr);
 }
 
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
@@ -1486,14 +1487,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	if (rd_len)
 		ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
 
-	msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
-						 buff->len, IPPROTO_ICMPV6,
-						 csum_partial(msg, buff->len, 0));
-
-	ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr,
-		   inet6_sk(sk)->hop_limit, buff->len);
-
-	__ndisc_send(buff, dst);
+	__ndisc_send(buff, dst, &ipv6_hdr(skb)->saddr, &saddr_buf);
 	return;
 
 release:
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 12/17] ndisc: Make ndisc_fill_xxx_option() for sk_buff.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:55 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 1100559..5458aed 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -148,11 +148,12 @@ static inline int ndisc_opt_addr_space(struct net_device *dev)
 	return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
 }
 
-static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
-				  unsigned short addr_type)
+static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
 {
-	int pad   = ndisc_addr_option_pad(addr_type);
+	int data_len = skb->dev->addr_len;
+	int pad   = ndisc_addr_option_pad(skb->dev->type);
 	int space = NDISC_OPT_SPACE(data_len + pad);
+	u8 *opt = __skb_put(skb, space);
 
 	opt[0] = type;
 	opt[1] = space>>3;
@@ -166,7 +167,6 @@ static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
 	opt += data_len;
 	if ((space -= data_len) > 0)
 		memset(opt, 0, space);
-	return opt + space;
 }
 
 static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
@@ -436,7 +436,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	if (!skb)
 		return NULL;
 
-	skb_put(skb, len + optlen);
+	skb_put(skb, len);
 
 	hdr = (struct icmp6hdr *)skb_transport_header(skb);
 	memcpy(hdr, icmp6h, sizeof(*hdr));
@@ -448,8 +448,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	}
 
 	if (llinfo)
-		ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
-				       dev->addr_len, dev->type);
+		ndisc_fill_addr_option(skb, llinfo, dev->dev_addr);
 
 	hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
 					   IPPROTO_ICMPV6,
@@ -1360,17 +1359,18 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
 	icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
 }
 
-static u8 *ndisc_fill_redirect_hdr_option(u8 *opt, struct sk_buff *orig_skb,
-					  int rd_len)
+static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
+					   struct sk_buff *orig_skb,
+					   int rd_len)
 {
+	u8 *opt = __skb_put(skb, rd_len);
+
 	memset(opt, 0, 8);
 	*(opt++) = ND_OPT_REDIRECT_HDR;
 	*(opt++) = (rd_len >> 3);
 	opt += 6;
 
 	memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
-
-	return opt;
 }
 
 void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
@@ -1386,7 +1386,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	struct rt6_info *rt;
 	struct dst_entry *dst;
 	struct flowi6 fl6;
-	u8 *opt;
 	int rd_len;
 	u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
 	bool ret;
@@ -1460,7 +1459,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	if (!buff)
 		goto release;
 
-	skb_put(buff, sizeof(struct red_msg) + optlen);
+	skb_put(buff, sizeof(struct red_msg));
 	msg = (struct red_msg *)icmp6_hdr(buff);
 
 	memset(&msg->icmph, 0, sizeof(struct icmp6hdr));
@@ -1473,22 +1472,19 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	msg->target = *target;
 	msg->dest = ipv6_hdr(skb)->daddr;
 
-	opt = msg->opt;
-
 	/*
 	 *	include target_address option
 	 */
 
 	if (ha)
-		opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
-					     dev->addr_len, dev->type);
+		ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha);
 
 	/*
 	 *	build redirect option and copy skb over to the new packet.
 	 */
 
 	if (rd_len)
-		opt = ndisc_fill_redirect_hdr_option(opt, skb, rd_len);
+		ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
 
 	msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
 						 buff->len, IPPROTO_ICMPV6,
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 11/17] ndisc: Calculate message body length and option length separately.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:55 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 073e52a..1100559 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -422,6 +422,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	struct sk_buff *skb;
 	struct icmp6hdr *hdr;
 	int len;
+	int optlen = 0;
 	u8 *opt;
 
 	if (!dev->addr_len)
@@ -429,13 +430,13 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 
 	len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
 	if (llinfo)
-		len += ndisc_opt_addr_space(dev);
+		optlen += ndisc_opt_addr_space(dev);
 
-	skb = ndisc_alloc_skb(dev, len);
+	skb = ndisc_alloc_skb(dev, len + optlen);
 	if (!skb)
 		return NULL;
 
-	skb_put(skb, len);
+	skb_put(skb, len + optlen);
 
 	hdr = (struct icmp6hdr *)skb_transport_header(skb);
 	memcpy(hdr, icmp6h, sizeof(*hdr));
@@ -1377,7 +1378,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	struct net_device *dev = skb->dev;
 	struct net *net = dev_net(dev);
 	struct sock *sk = net->ipv6.ndisc_sk;
-	int len = sizeof(struct red_msg);
+	int optlen = 0;
 	struct inet_peer *peer;
 	struct sk_buff *buff;
 	struct red_msg *msg;
@@ -1442,7 +1443,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 			memcpy(ha_buf, neigh->ha, dev->addr_len);
 			read_unlock_bh(&neigh->lock);
 			ha = ha_buf;
-			len += ndisc_opt_addr_space(dev);
+			optlen += ndisc_opt_addr_space(dev);
 		} else
 			read_unlock_bh(&neigh->lock);
 
@@ -1450,15 +1451,16 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	}
 
 	rd_len = min_t(unsigned int,
-		     IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
+		       IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct red_msg) - optlen,
+		       skb->len + 8);
 	rd_len &= ~0x7;
-	len += rd_len;
+	optlen += rd_len;
 
-	buff = ndisc_alloc_skb(dev, len);
+	buff = ndisc_alloc_skb(dev, sizeof(struct red_msg) + optlen);
 	if (!buff)
 		goto release;
 
-	skb_put(buff, len);
+	skb_put(buff, sizeof(struct red_msg) + optlen);
 	msg = (struct red_msg *)icmp6_hdr(buff);
 
 	memset(&msg->icmph, 0, sizeof(struct icmp6hdr));
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 10/17] ndisc: Reset skb->transport_header inside ndisc_alloc_send_skb().
From: YOSHIFUJI Hideaki @ 2012-12-18 10:55 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2ebb2fb..073e52a 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -392,6 +392,8 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
 	skb->dev = dev;
 
 	skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
+	skb_reset_transport_header(skb);
+
 	return skb;
 }
 
@@ -433,7 +435,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	if (!skb)
 		return NULL;
 
-	skb->transport_header = skb->tail;
 	skb_put(skb, len);
 
 	hdr = (struct icmp6hdr *)skb_transport_header(skb);
@@ -1457,7 +1458,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	if (!buff)
 		goto release;
 
-	skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
 	skb_put(buff, len);
 	msg = (struct red_msg *)icmp6_hdr(buff);
 
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 09/17] ndisc: Defer building IPv6 header.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:54 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Fill out IPv6 header just before sending ND message.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index b32f079..2ebb2fb 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -391,7 +391,7 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
 	skb->protocol = htons(ETH_P_IPV6);
 	skb->dev = dev;
 
-	skb_reserve(skb, hlen);
+	skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
 	return skb;
 }
 
@@ -400,8 +400,8 @@ static void ip6_nd_hdr(struct sk_buff *skb, const struct in6_addr *saddr,
 {
 	struct ipv6hdr *hdr;
 
+	__skb_push(skb, sizeof(*hdr));
 	skb_reset_network_header(skb);
-	skb_put(skb, sizeof(struct ipv6hdr));
 	hdr = ipv6_hdr(skb);
 
 	__ip6_hdr(hdr, 0, 0, IPPROTO_ICMPV6, hoplimit, saddr, daddr);
@@ -433,8 +433,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	if (!skb)
 		return NULL;
 
-	ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, len);
-
 	skb->transport_header = skb->tail;
 	skb_put(skb, len);
 
@@ -451,10 +449,12 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 		ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
 				       dev->addr_len, dev->type);
 
-	hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
+	hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
 					   IPPROTO_ICMPV6,
 					   csum_partial(hdr,
-							len, 0));
+							skb->len, 0));
+
+	ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
 
 	return skb;
 }
@@ -1457,9 +1457,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	if (!buff)
 		goto release;
 
-	ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr,
-		   inet6_sk(sk)->hop_limit, len);
-
 	skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
 	skb_put(buff, len);
 	msg = (struct red_msg *)icmp6_hdr(buff);
@@ -1492,8 +1489,11 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 		opt = ndisc_fill_redirect_hdr_option(opt, skb, rd_len);
 
 	msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
-						 len, IPPROTO_ICMPV6,
-						 csum_partial(msg, len, 0));
+						 buff->len, IPPROTO_ICMPV6,
+						 csum_partial(msg, buff->len, 0));
+
+	ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr,
+		   inet6_sk(sk)->hop_limit, buff->len);
 
 	__ndisc_send(buff, dst);
 	return;
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 08/17] ndisc: Set skb->dev and skb->protocol inside ndisc_alloc_skb().
From: YOSHIFUJI Hideaki @ 2012-12-18 10:54 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index f2942f3..b32f079 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -388,20 +388,18 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
 		return NULL;
 	}
 
+	skb->protocol = htons(ETH_P_IPV6);
+	skb->dev = dev;
+
 	skb_reserve(skb, hlen);
 	return skb;
 }
 
-static void ip6_nd_hdr(struct sk_buff *skb, struct net_device *dev,
-		       const struct in6_addr *saddr,
-		       const struct in6_addr *daddr,
-		       int hoplimit, int len)
+static void ip6_nd_hdr(struct sk_buff *skb, const struct in6_addr *saddr,
+		       const struct in6_addr *daddr, int hoplimit, int len)
 {
 	struct ipv6hdr *hdr;
 
-	skb->protocol = htons(ETH_P_IPV6);
-	skb->dev = dev;
-
 	skb_reset_network_header(skb);
 	skb_put(skb, sizeof(struct ipv6hdr));
 	hdr = ipv6_hdr(skb);
@@ -435,7 +433,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	if (!skb)
 		return NULL;
 
-	ip6_nd_hdr(skb, dev, saddr, daddr, inet6_sk(sk)->hop_limit, len);
+	ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, len);
 
 	skb->transport_header = skb->tail;
 	skb_put(skb, len);
@@ -1459,7 +1457,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	if (!buff)
 		goto release;
 
-	ip6_nd_hdr(buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
+	ip6_nd_hdr(buff, &saddr_buf, &ipv6_hdr(skb)->saddr,
 		   inet6_sk(sk)->hop_limit, len);
 
 	skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 07/17] ipv6: Move ip6_nd_hdr() to its users' source files.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:54 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

This also makes return type to void since this function
never fails, and uses hoplimit argument instead of pointer
to struct sock.  For ND, it also removes protocol argument.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 include/net/ipv6.h    |    7 -------
 net/ipv6/ip6_output.c |   27 ---------------------------
 net/ipv6/mcast.c      |   24 ++++++++++++++++++++++--
 net/ipv6/ndisc.c      |   24 +++++++++++++++++++++---
 4 files changed, 43 insertions(+), 39 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 710bf2b..dcc4b45 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -570,13 +570,6 @@ extern int			ip6_xmit(struct sock *sk,
 					 struct ipv6_txoptions *opt,
 					 int tclass);
 
-extern int			ip6_nd_hdr(struct sock *sk,
-					   struct sk_buff *skb,
-					   struct net_device *dev,
-					   const struct in6_addr *saddr,
-					   const struct in6_addr *daddr,
-					   int proto, int len);
-
 extern int			ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
 
 extern int			ip6_append_data(struct sock *sk,
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 8c597b3..bb0c4cc 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -241,33 +241,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
 
 EXPORT_SYMBOL(ip6_xmit);
 
-/*
- *	To avoid extra problems ND packets are send through this
- *	routine. It's code duplication but I really want to avoid
- *	extra checks since ipv6_build_header is used by TCP (which
- *	is for us performance critical)
- */
-
-int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
-	       const struct in6_addr *saddr, const struct in6_addr *daddr,
-	       int proto, int len)
-{
-	struct ipv6_pinfo *np = inet6_sk(sk);
-	struct ipv6hdr *hdr;
-
-	skb->protocol = htons(ETH_P_IPV6);
-	skb->dev = dev;
-
-	skb_reset_network_header(skb);
-	skb_put(skb, sizeof(struct ipv6hdr));
-	hdr = ipv6_hdr(skb);
-
-	__ip6_hdr(hdr, 0, 0, proto, np->hop_limit, saddr, daddr);
-	hdr->payload_len = htons(len);
-
-	return 0;
-}
-
 static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
 {
 	struct ip6_ra_chain *ra;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 28dfa5f..7c42776 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1340,6 +1340,24 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
 	return scount;
 }
 
+static void ip6_mc_hdr(struct sk_buff *skb, struct net_device *dev,
+		       const struct in6_addr *saddr,
+		       const struct in6_addr *daddr,
+		       int proto, int hoplimit, int len)
+{
+	struct ipv6hdr *hdr;
+
+	skb->protocol = htons(ETH_P_IPV6);
+	skb->dev = dev;
+
+	skb_reset_network_header(skb);
+	skb_put(skb, sizeof(struct ipv6hdr));
+	hdr = ipv6_hdr(skb);
+
+	__ip6_hdr(hdr, 0, 0, proto, hoplimit, saddr, daddr);
+	hdr->payload_len = htons(len);
+}
+
 static struct sk_buff *mld_newpack(struct net_device *dev, int size)
 {
 	struct net *net = dev_net(dev);
@@ -1375,7 +1393,8 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
 	} else
 		saddr = &addr_buf;
 
-	ip6_nd_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0);
+	ip6_mc_hdr(skb, dev, saddr, &mld2_all_mcr,
+		   NEXTHDR_HOP, inet6_sk(sk)->hop_limit, 0);
 
 	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
 
@@ -1767,7 +1786,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 	} else
 		saddr = &addr_buf;
 
-	ip6_nd_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len);
+	ip6_mc_hdr(skb, dev, saddr, snd_addr, NEXTHDR_HOP,
+		   inet6_sk(sk)->hop_limit, payload_len);
 
 	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
 
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 45ce72c..f2942f3 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -392,6 +392,24 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
 	return skb;
 }
 
+static void ip6_nd_hdr(struct sk_buff *skb, struct net_device *dev,
+		       const struct in6_addr *saddr,
+		       const struct in6_addr *daddr,
+		       int hoplimit, int len)
+{
+	struct ipv6hdr *hdr;
+
+	skb->protocol = htons(ETH_P_IPV6);
+	skb->dev = dev;
+
+	skb_reset_network_header(skb);
+	skb_put(skb, sizeof(struct ipv6hdr));
+	hdr = ipv6_hdr(skb);
+
+	__ip6_hdr(hdr, 0, 0, IPPROTO_ICMPV6, hoplimit, saddr, daddr);
+	hdr->payload_len = htons(len);
+}
+
 static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 				       const struct in6_addr *daddr,
 				       const struct in6_addr *saddr,
@@ -417,7 +435,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	if (!skb)
 		return NULL;
 
-	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
+	ip6_nd_hdr(skb, dev, saddr, daddr, inet6_sk(sk)->hop_limit, len);
 
 	skb->transport_header = skb->tail;
 	skb_put(skb, len);
@@ -1441,8 +1459,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	if (!buff)
 		goto release;
 
-	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
-		   IPPROTO_ICMPV6, len);
+	ip6_nd_hdr(buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
+		   inet6_sk(sk)->hop_limit, len);
 
 	skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
 	skb_put(buff, len);
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 06/17] ndisc: Introduce ndisc_send_skb_alloc() for sk_buff allocation.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:54 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   50 ++++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index a293676..45ce72c 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -370,6 +370,28 @@ static void pndisc_destructor(struct pneigh_entry *n)
 	ipv6_dev_mc_dec(dev, &maddr);
 }
 
+static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
+				       int len)
+{
+	int hlen = LL_RESERVED_SPACE(dev);
+	int tlen = dev->needed_tailroom;
+	struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
+	struct sk_buff *skb;
+	int err;
+
+	skb = sock_alloc_send_skb(sk,
+				  hlen + sizeof(struct ipv6hdr) + len + tlen,
+				  1, &err);
+	if (!skb) {
+		ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n",
+			  __func__, err);
+		return NULL;
+	}
+
+	skb_reserve(skb, hlen);
+	return skb;
+}
+
 static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 				       const struct in6_addr *daddr,
 				       const struct in6_addr *saddr,
@@ -381,10 +403,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	struct sock *sk = net->ipv6.ndisc_sk;
 	struct sk_buff *skb;
 	struct icmp6hdr *hdr;
-	int hlen = LL_RESERVED_SPACE(dev);
-	int tlen = dev->needed_tailroom;
 	int len;
-	int err;
 	u8 *opt;
 
 	if (!dev->addr_len)
@@ -394,16 +413,10 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	if (llinfo)
 		len += ndisc_opt_addr_space(dev);
 
-	skb = sock_alloc_send_skb(sk,
-				  hlen + sizeof(struct ipv6hdr) + len + tlen,
-				  1, &err);
-	if (!skb) {
-		ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n",
-			  __func__, err);
+	skb = ndisc_alloc_skb(dev, len);
+	if (!skb)
 		return NULL;
-	}
 
-	skb_reserve(skb, hlen);
 	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
 
 	skb->transport_header = skb->tail;
@@ -1356,9 +1369,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	struct dst_entry *dst;
 	struct flowi6 fl6;
 	u8 *opt;
-	int hlen, tlen;
 	int rd_len;
-	int err;
 	u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
 	bool ret;
 
@@ -1426,19 +1437,10 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	rd_len &= ~0x7;
 	len += rd_len;
 
-	hlen = LL_RESERVED_SPACE(dev);
-	tlen = dev->needed_tailroom;
-	buff = sock_alloc_send_skb(sk,
-				   hlen + sizeof(struct ipv6hdr) + len + tlen,
-				   1, &err);
-	if (buff == NULL) {
-		ND_PRINTK(0, err,
-			  "Redirect: %s failed to allocate an skb, err=%d\n",
-			  __func__, err);
+	buff = ndisc_alloc_skb(dev, len);
+	if (!buff)
 		goto release;
-	}
 
-	skb_reserve(buff, hlen);
 	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
 		   IPPROTO_ICMPV6, len);
 
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 05/17] ndisc: Rename and break up __ndisc_send().
From: YOSHIFUJI Hideaki @ 2012-12-18 10:54 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Rename (old) __ndisc_send() to ndisc_send() and create new
__ndisc_send() for more trivial work without dst_entry allocation.
Use new __ndisc_send() for redirect.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   81 ++++++++++++++++++++++--------------------------------
 1 file changed, 33 insertions(+), 48 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 0a4f3a9..a293676 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -430,28 +430,13 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 	return skb;
 }
 
-static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
-			   struct neighbour *neigh,
-			   const struct in6_addr *daddr,
-			   const struct in6_addr *saddr,
-			   struct icmp6hdr *icmp6h)
+static void __ndisc_send(struct sk_buff *skb, struct dst_entry *dst)
 {
-	struct flowi6 fl6;
-	struct dst_entry *dst;
-	struct net *net = dev_net(dev);
-	struct sock *sk = net->ipv6.ndisc_sk;
+	struct net *net = dev_net(dst->dev);
 	struct inet6_dev *idev;
+	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
+	u8 type = icmp6h->icmp6_type;
 	int err;
-	u8 type;
-
-	type = icmp6h->icmp6_type;
-
-	icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
-	dst = icmp6_dst_alloc(dev, neigh, &fl6);
-	if (IS_ERR(dst)) {
-		kfree_skb(skb);
-		return;
-	}
 
 	skb_dst_set(skb, dst);
 
@@ -472,20 +457,32 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
 /*
  *	Send a Neighbour Discover packet
  */
-static void __ndisc_send(struct net_device *dev,
-			 struct neighbour *neigh,
-			 const struct in6_addr *daddr,
-			 const struct in6_addr *saddr,
-			 struct icmp6hdr *icmp6h, const struct in6_addr *target,
-			 int llinfo)
+static void ndisc_send(struct net_device *dev,
+		       struct neighbour *neigh,
+		       const struct in6_addr *daddr,
+		       const struct in6_addr *saddr,
+		       struct icmp6hdr *icmp6h, const struct in6_addr *target,
+		       int llinfo)
 {
+	struct flowi6 fl6;
+	struct dst_entry *dst;
+	struct net *net = dev_net(dev);
+	struct sock *sk = net->ipv6.ndisc_sk;
 	struct sk_buff *skb;
+	u8 type = icmp6h->icmp6_type;
 
 	skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
 	if (!skb)
 		return;
 
-	ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
+	icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
+	dst = icmp6_dst_alloc(dev, neigh, &fl6);
+	if (IS_ERR(dst)) {
+		kfree_skb(skb);
+		return;
+	}
+
+	__ndisc_send(skb, dst);
 }
 
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
@@ -520,9 +517,9 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 	icmp6h.icmp6_solicited = solicited;
 	icmp6h.icmp6_override = override;
 
-	__ndisc_send(dev, neigh, daddr, src_addr,
-		     &icmp6h, solicited_addr,
-		     inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
+	ndisc_send(dev, neigh, daddr, src_addr,
+		   &icmp6h, solicited_addr,
+		   inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
 }
 
 static void ndisc_send_unsol_na(struct net_device *dev)
@@ -562,9 +559,9 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 		saddr = &addr_buf;
 	}
 
-	__ndisc_send(dev, neigh, daddr, saddr,
-		     &icmp6h, solicit,
-		     !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
+	ndisc_send(dev, neigh, daddr, saddr,
+		   &icmp6h, solicit,
+		   !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
 }
 
 void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
@@ -597,9 +594,9 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
 		}
 	}
 #endif
-	__ndisc_send(dev, NULL, daddr, saddr,
-		     &icmp6h, NULL,
-		     send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
+	ndisc_send(dev, NULL, daddr, saddr,
+		   &icmp6h, NULL,
+		   send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
 }
 
 
@@ -1357,7 +1354,6 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	struct in6_addr saddr_buf;
 	struct rt6_info *rt;
 	struct dst_entry *dst;
-	struct inet6_dev *idev;
 	struct flowi6 fl6;
 	u8 *opt;
 	int hlen, tlen;
@@ -1481,18 +1477,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 						 len, IPPROTO_ICMPV6,
 						 csum_partial(msg, len, 0));
 
-	skb_dst_set(buff, dst);
-	rcu_read_lock();
-	idev = __in6_dev_get(dst->dev);
-	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
-	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
-		      dst_output);
-	if (!err) {
-		ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
-		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
-	}
-
-	rcu_read_unlock();
+	__ndisc_send(buff, dst);
 	return;
 
 release:
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 04/17] ndisc: Introduce ndisc_fill_redirect_hdr_option().
From: YOSHIFUJI Hideaki @ 2012-12-18 10:54 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |   21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index a181113..0a4f3a9 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1332,6 +1332,19 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
 	icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
 }
 
+static u8 *ndisc_fill_redirect_hdr_option(u8 *opt, struct sk_buff *orig_skb,
+					  int rd_len)
+{
+	memset(opt, 0, 8);
+	*(opt++) = ND_OPT_REDIRECT_HDR;
+	*(opt++) = (rd_len >> 3);
+	opt += 6;
+
+	memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
+
+	return opt;
+}
+
 void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 {
 	struct net_device *dev = skb->dev;
@@ -1461,12 +1474,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	 *	build redirect option and copy skb over to the new packet.
 	 */
 
-	memset(opt, 0, 8);
-	*(opt++) = ND_OPT_REDIRECT_HDR;
-	*(opt++) = (rd_len >> 3);
-	opt += 6;
-
-	memcpy(opt, ipv6_hdr(skb), rd_len - 8);
+	if (rd_len)
+		opt = ndisc_fill_redirect_hdr_option(opt, skb, rd_len);
 
 	msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
 						 len, IPPROTO_ICMPV6,
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 03/17] ndisc: Introduce struct red_msg for redirect message.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:53 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 include/net/ndisc.h |    7 +++++++
 net/ipv6/ndisc.c    |   25 +++++++++++--------------
 net/ipv6/route.c    |   24 ++++++++++--------------
 3 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 7af1ea8..a7df01d 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -78,6 +78,13 @@ struct ra_msg {
 	__be32			retrans_timer;
 };
 
+struct red_msg {
+	struct icmp6hdr		icmph;
+	struct in6_addr		target;
+	struct in6_addr		dest;
+	__u8			opt[0];
+};
+
 struct nd_opt_hdr {
 	__u8		nd_opt_type;
 	__u8		nd_opt_len;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index a1d2a45..a181113 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1337,12 +1337,11 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	struct net_device *dev = skb->dev;
 	struct net *net = dev_net(dev);
 	struct sock *sk = net->ipv6.ndisc_sk;
-	int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+	int len = sizeof(struct red_msg);
 	struct inet_peer *peer;
 	struct sk_buff *buff;
-	struct icmp6hdr *icmph;
+	struct red_msg *msg;
 	struct in6_addr saddr_buf;
-	struct in6_addr *addrp;
 	struct rt6_info *rt;
 	struct dst_entry *dst;
 	struct inet6_dev *idev;
@@ -1436,21 +1435,19 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 
 	skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
 	skb_put(buff, len);
-	icmph = icmp6_hdr(buff);
+	msg = (struct red_msg *)icmp6_hdr(buff);
 
-	memset(icmph, 0, sizeof(struct icmp6hdr));
-	icmph->icmp6_type = NDISC_REDIRECT;
+	memset(&msg->icmph, 0, sizeof(struct icmp6hdr));
+	msg->icmph.icmp6_type = NDISC_REDIRECT;
 
 	/*
 	 *	copy target and destination addresses
 	 */
 
-	addrp = (struct in6_addr *)(icmph + 1);
-	*addrp = *target;
-	addrp++;
-	*addrp = ipv6_hdr(skb)->daddr;
+	msg->target = *target;
+	msg->dest = ipv6_hdr(skb)->daddr;
 
-	opt = (u8*) (addrp + 1);
+	opt = msg->opt;
 
 	/*
 	 *	include target_address option
@@ -1471,9 +1468,9 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 
 	memcpy(opt, ipv6_hdr(skb), rd_len - 8);
 
-	icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
-					     len, IPPROTO_ICMPV6,
-					     csum_partial(icmph, len, 0));
+	msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
+						 len, IPPROTO_ICMPV6,
+						 csum_partial(msg, len, 0));
 
 	skb_dst_set(buff, dst);
 	rcu_read_lock();
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index e229a3b..ec31862 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1705,37 +1705,33 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
 	struct net *net = dev_net(skb->dev);
 	struct netevent_redirect netevent;
 	struct rt6_info *rt, *nrt = NULL;
-	const struct in6_addr *target;
 	struct ndisc_options ndopts;
-	const struct in6_addr *dest;
 	struct neighbour *old_neigh;
 	struct inet6_dev *in6_dev;
 	struct neighbour *neigh;
-	struct icmp6hdr *icmph;
+	struct red_msg *msg;
 	int optlen, on_link;
 	u8 *lladdr;
 
 	optlen = skb->tail - skb->transport_header;
-	optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+	optlen -= sizeof(*msg);
 
 	if (optlen < 0) {
 		net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
 		return;
 	}
 
-	icmph = icmp6_hdr(skb);
-	target = (const struct in6_addr *) (icmph + 1);
-	dest = target + 1;
+	msg = (struct red_msg *)icmp6_hdr(skb);
 
-	if (ipv6_addr_is_multicast(dest)) {
+	if (ipv6_addr_is_multicast(&msg->dest)) {
 		net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
 		return;
 	}
 
 	on_link = 0;
-	if (ipv6_addr_equal(dest, target)) {
+	if (ipv6_addr_equal(&msg->dest, &msg->target)) {
 		on_link = 1;
-	} else if (ipv6_addr_type(target) !=
+	} else if (ipv6_addr_type(&msg->target) !=
 		   (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
 		net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
 		return;
@@ -1752,7 +1748,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
 	 *	first-hop router for the specified ICMP Destination Address.
 	 */
 
-	if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
+	if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
 		net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
 		return;
 	}
@@ -1779,7 +1775,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
 	 */
 	dst_confirm(&rt->dst);
 
-	neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
+	neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
 	if (!neigh)
 		return;
 
@@ -1799,7 +1795,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
 				     NEIGH_UPDATE_F_ISROUTER))
 		     );
 
-	nrt = ip6_rt_copy(rt, dest);
+	nrt = ip6_rt_copy(rt, &msg->dest);
 	if (!nrt)
 		goto out;
 
@@ -1817,7 +1813,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
 	netevent.old_neigh = old_neigh;
 	netevent.new = &nrt->dst;
 	netevent.new_neigh = neigh;
-	netevent.daddr = dest;
+	netevent.daddr = &msg->dest;
 	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
 
 	if (rt->rt6i_flags & RTF_CACHE) {
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 02/17] ipv6: Introduce __ip6_hdr() for setting IPv6 header.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:52 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 include/net/ipv6.h    |   15 +++++++++++++++
 net/ipv6/ip6_gre.c    |   18 ++++++------------
 net/ipv6/ip6_output.c |   26 +++++---------------------
 net/ipv6/ip6_tunnel.c |   12 +++++-------
 4 files changed, 31 insertions(+), 40 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 5af66b2..710bf2b 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -622,6 +622,21 @@ extern int			ip6_mc_input(struct sk_buff *skb);
 extern int			__ip6_local_out(struct sk_buff *skb);
 extern int			ip6_local_out(struct sk_buff *skb);
 
+static inline void		__ip6_hdr(struct ipv6hdr *hdr,
+					  unsigned int tclass,
+					  __be32 flowlabel,
+					  unsigned int proto,
+					  unsigned int hoplimit,
+					  const struct in6_addr *saddr,
+					  const struct in6_addr *daddr)
+{
+	*(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel;
+	hdr->nexthdr = proto;
+	hdr->hop_limit = hoplimit;
+	hdr->saddr = *saddr;
+	hdr->daddr = *daddr;
+}
+
 /*
  *	Extension header (options) processing
  */
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 867466c..d91deaa 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -773,13 +773,10 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
 	 *	Push down and install the IP header.
 	 */
 	ipv6h = ipv6_hdr(skb);
-	*(__be32 *)ipv6h = fl6->flowlabel | htonl(0x60000000);
-	dsfield = INET_ECN_encapsulate(0, dsfield);
-	ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
-	ipv6h->hop_limit = tunnel->parms.hop_limit;
-	ipv6h->nexthdr = proto;
-	ipv6h->saddr = fl6->saddr;
-	ipv6h->daddr = fl6->daddr;
+
+	__ip6_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
+		  fl6->flowlabel, proto, tunnel->parms.hop_limit,
+		  &fl6->saddr, &fl6->daddr);
 
 	((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags;
 	((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ?
@@ -1241,11 +1238,8 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
 	struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen);
 	__be16 *p = (__be16 *)(ipv6h+1);
 
-	*(__be32 *)ipv6h = t->fl.u.ip6.flowlabel | htonl(0x60000000);
-	ipv6h->hop_limit = t->parms.hop_limit;
-	ipv6h->nexthdr = NEXTHDR_GRE;
-	ipv6h->saddr = t->parms.laddr;
-	ipv6h->daddr = t->parms.raddr;
+	__ip6_hdr(ipv6h, 0, t->fl.u.ip6.flowlabel, NEXTHDR_GRE,
+		  t->parms.hop_limit, &t->parms.laddr, &t->parms.raddr);
 
 	p[0]		= t->parms.o_flags;
 	p[1]		= htons(type);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5552d13..8c597b3 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -216,14 +216,9 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
 	if (hlimit < 0)
 		hlimit = ip6_dst_hoplimit(dst);
 
-	*(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel;
-
+	__ip6_hdr(hdr, tclass, fl6->flowlabel, proto, hlimit,
+		  &fl6->saddr, first_hop);
 	hdr->payload_len = htons(seg_len);
-	hdr->nexthdr = proto;
-	hdr->hop_limit = hlimit;
-
-	hdr->saddr = fl6->saddr;
-	hdr->daddr = *first_hop;
 
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
@@ -267,14 +262,8 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
 	skb_put(skb, sizeof(struct ipv6hdr));
 	hdr = ipv6_hdr(skb);
 
-	*(__be32*)hdr = htonl(0x60000000);
-
+	__ip6_hdr(hdr, 0, 0, proto, np->hop_limit, saddr, daddr);
 	hdr->payload_len = htons(len);
-	hdr->nexthdr = proto;
-	hdr->hop_limit = np->hop_limit;
-
-	hdr->saddr = *saddr;
-	hdr->daddr = *daddr;
 
 	return 0;
 }
@@ -1548,13 +1537,8 @@ int ip6_push_pending_frames(struct sock *sk)
 	skb_reset_network_header(skb);
 	hdr = ipv6_hdr(skb);
 
-	*(__be32*)hdr = fl6->flowlabel |
-		     htonl(0x60000000 | ((int)np->cork.tclass << 20));
-
-	hdr->hop_limit = np->cork.hop_limit;
-	hdr->nexthdr = proto;
-	hdr->saddr = fl6->saddr;
-	hdr->daddr = *final_dst;
+	__ip6_hdr(hdr, np->cork.tclass, fl6->flowlabel, proto,
+		  np->cork.hop_limit, &fl6->saddr, final_dst);
 
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index a14f28b..28e4bf0 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1030,13 +1030,11 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 	skb_push(skb, sizeof(struct ipv6hdr));
 	skb_reset_network_header(skb);
 	ipv6h = ipv6_hdr(skb);
-	*(__be32*)ipv6h = fl6->flowlabel | htonl(0x60000000);
-	dsfield = INET_ECN_encapsulate(0, dsfield);
-	ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
-	ipv6h->hop_limit = t->parms.hop_limit;
-	ipv6h->nexthdr = proto;
-	ipv6h->saddr = fl6->saddr;
-	ipv6h->daddr = fl6->daddr;
+
+	__ip6_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
+		  fl6->flowlabel, proto, t->parms.hop_limit,
+		  &fl6->saddr, &fl6->daddr);
+
 	nf_reset(skb);
 	pkt_len = skb->len;
 	err = ip6_local_out(skb);
-- 
1.7.9.5

^ permalink raw reply related

* [GIT PULL net-next 01/17] ndisc: Fix size calculation for headers.
From: YOSHIFUJI Hideaki @ 2012-12-18 10:52 UTC (permalink / raw)
  To: davem, netdev; +Cc: yoshfuji
In-Reply-To: <50CF84A5.7030706@linux-ipv6.org>

We used to allocate MAX_HEADER bytes more than needed but
reserved hlen only (not MAX_HEADER + hlen) and the MAX_HEADER
was left behind.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/ndisc.c |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index f2a007b..a1d2a45 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -395,8 +395,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 		len += ndisc_opt_addr_space(dev);
 
 	skb = sock_alloc_send_skb(sk,
-				  (MAX_HEADER + sizeof(struct ipv6hdr) +
-				   len + hlen + tlen),
+				  hlen + sizeof(struct ipv6hdr) + len + tlen,
 				  1, &err);
 	if (!skb) {
 		ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n",
@@ -1422,8 +1421,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 	hlen = LL_RESERVED_SPACE(dev);
 	tlen = dev->needed_tailroom;
 	buff = sock_alloc_send_skb(sk,
-				   (MAX_HEADER + sizeof(struct ipv6hdr) +
-				    len + hlen + tlen),
+				   hlen + sizeof(struct ipv6hdr) + len + tlen,
 				   1, &err);
 	if (buff == NULL) {
 		ND_PRINTK(0, err,
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH v2] netlink: align attributes on 64-bits
From: Nicolas Dichtel @ 2012-12-18 10:18 UTC (permalink / raw)
  To: David Laight; +Cc: bhutchings, tgraf, netdev, davem
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6026B70F2@saturn3.aculab.com>

Le 18/12/2012 10:19, David Laight a écrit :
>> Le 17/12/2012 18:06, David Laight a écrit :
>>>>    int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
>>>>    {
>>>> -	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
>>>> +	int align = IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8) ? 0 : 4;
>>>
>>> I've just realised where you are adding this!
>>> You only want to add pad if the attribute is a single 64bit item,
>>> not whenever the destination is misaligned.
>> As said in the commit log, I want to align all attributes. An attribute can be
>> like this:
>>
>> struct foo {
>> 	__u32 bar1;
>> 	__u32 bar2;
>> 	__u64 bar3;
>> }
>>
>> nla_put() don't know what is contained in the attribute.
>
> Put there is no need to 8-byte align something whose size isn't a
> multiple of 8 bytes.
Even if you cast the structure in a buffer and read bar3 (without any memcpy 
before)?

>
>>> ...
>>>> +	if (align) {
>>>> +		/* Goal is to add an attribute with size 4. We know that
>>>> +		 * NLA_HDRLEN is 4, hence payload is 0.
>>>> +		 */
>>>> +		__nla_reserve(skb, 0, 0);
>>>
>>> One of those zeros should be 'align - 4', then the comment
>>> can be more descriptive.
>
>> I thought if you were to research why we use 0, you would know that the first 0
>> is the type and the second is the payload size...
>
> I can tell that one is the type and the other the size, you've
> implied that the 'type+size' actually total 4 bytes.
> I don't need to find out which is which!
> Now you've told me I'd have written:
> 	_nla_reserve(skb, 0, align - NLA_HDRLEN);
>
> The compiler could well have tracked the value - so know it is 4.
> OTOH you might want to generate the size of 'align' without
> using a conditional.
Yes, it is the goal ;-)

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox