diff --git a/[refs] b/[refs] index aa71c21bcc48..9641b67dc39c 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 9f651cace30c42e27e726a92f35e4edc55f1ec08 +refs/heads/master: a048b40e0f9502bc75d7f9904c5399a0a87fa479 diff --git a/trunk/arch/arm/mach-at91/Kconfig b/trunk/arch/arm/mach-at91/Kconfig index 682abf13d0f4..b14207101938 100644 --- a/trunk/arch/arm/mach-at91/Kconfig +++ b/trunk/arch/arm/mach-at91/Kconfig @@ -45,6 +45,7 @@ config SOC_AT91RM9200 config SOC_AT91SAM9260 bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20" select HAVE_AT91_DBGU0 + select HAVE_NET_MACB select SOC_AT91SAM9 help Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE @@ -62,6 +63,7 @@ config SOC_AT91SAM9263 bool "AT91SAM9263" select HAVE_AT91_DBGU1 select HAVE_FB_ATMEL + select HAVE_NET_MACB select SOC_AT91SAM9 config SOC_AT91SAM9RL @@ -74,6 +76,7 @@ config SOC_AT91SAM9G45 bool "AT91SAM9G45 or AT91SAM9M10 families" select HAVE_AT91_DBGU1 select HAVE_FB_ATMEL + select HAVE_NET_MACB select SOC_AT91SAM9 help Select this if you are using one of Atmel's AT91SAM9G45 family SoC. @@ -83,6 +86,7 @@ config SOC_AT91SAM9X5 bool "AT91SAM9x5 family" select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL + select HAVE_NET_MACB select SOC_AT91SAM9 help Select this if you are using one of Atmel's AT91SAM9x5 family SoC. diff --git a/trunk/arch/arm/mach-at91/board-csb337.c b/trunk/arch/arm/mach-at91/board-csb337.c index aa9b320bad59..3e37437a7a61 100644 --- a/trunk/arch/arm/mach-at91/board-csb337.c +++ b/trunk/arch/arm/mach-at91/board-csb337.c @@ -53,8 +53,6 @@ static void __init csb337_init_early(void) static struct macb_platform_data __initdata csb337_eth_data = { .phy_irq_pin = AT91_PIN_PC2, .is_rmii = 0, - /* The CSB337 bootloader stores the MAC the wrong-way around */ - .rev_eth_addr = 1, }; static struct at91_usbh_data __initdata csb337_usbh_data = { diff --git a/trunk/arch/avr32/Kconfig b/trunk/arch/avr32/Kconfig index 09f9fa800b33..06e73bf665e9 100644 --- a/trunk/arch/avr32/Kconfig +++ b/trunk/arch/avr32/Kconfig @@ -80,6 +80,7 @@ config PLATFORM_AT32AP select ARCH_REQUIRE_GPIOLIB select GENERIC_ALLOCATOR select HAVE_FB_ATMEL + select HAVE_NET_MACB # # CPU types diff --git a/trunk/drivers/net/ethernet/cadence/Kconfig b/trunk/drivers/net/ethernet/cadence/Kconfig index 40172d1ca605..57f78abe11d9 100644 --- a/trunk/drivers/net/ethernet/cadence/Kconfig +++ b/trunk/drivers/net/ethernet/cadence/Kconfig @@ -2,9 +2,13 @@ # Atmel device configuration # +config HAVE_NET_MACB + bool + config NET_CADENCE bool "Cadence devices" default y + depends on HAVE_NET_MACB || (ARM && ARCH_AT91RM9200) ---help--- If you have a network (Ethernet) card belonging to this class, say Y. Make sure you know the name of your card. Read the Ethernet-HOWTO, @@ -21,14 +25,16 @@ if NET_CADENCE config ARM_AT91_ETHER tristate "AT91RM9200 Ethernet support" + depends on ARM && ARCH_AT91RM9200 select NET_CORE - select MACB + select PHYLIB ---help--- If you wish to compile a kernel for the AT91RM9200 and enable ethernet support, then you should always answer Y to this. config MACB tristate "Cadence MACB/GEM support" + depends on HAVE_NET_MACB select PHYLIB ---help--- The Cadence MACB ethernet interface is found on many Atmel AT32 and diff --git a/trunk/drivers/net/ethernet/cadence/Makefile b/trunk/drivers/net/ethernet/cadence/Makefile index 9068b8331ed1..798b1e0fd220 100644 --- a/trunk/drivers/net/ethernet/cadence/Makefile +++ b/trunk/drivers/net/ethernet/cadence/Makefile @@ -2,5 +2,5 @@ # Makefile for the Atmel network device drivers. # -obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o +obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o macb.o obj-$(CONFIG_MACB) += macb.o diff --git a/trunk/drivers/net/ethernet/cadence/at91_ether.c b/trunk/drivers/net/ethernet/cadence/at91_ether.c index b92815aabc65..375d272d1a5f 100644 --- a/trunk/drivers/net/ethernet/cadence/at91_ether.c +++ b/trunk/drivers/net/ethernet/cadence/at91_ether.c @@ -32,6 +32,8 @@ #include #include +#include + #include "macb.h" #define DRV_NAME "at91_ether" @@ -59,10 +61,9 @@ static short __init unpack_mac_address(struct net_device *dev, unsigned int hi, unsigned int lo) { - struct macb *lp = netdev_priv(dev); char addr[6]; - if (lp->board_data.rev_eth_addr) { + if (machine_is_csb337()) { addr[5] = (lo & 0xff); /* The CSB337 bootloader stores the MAC the wrong-way around */ addr[4] = (lo & 0xff00) >> 8; addr[3] = (lo & 0xff0000) >> 16; diff --git a/trunk/drivers/net/ethernet/cadence/macb.c b/trunk/drivers/net/ethernet/cadence/macb.c index 6a4f4998cfe5..6c84a1104aff 100644 --- a/trunk/drivers/net/ethernet/cadence/macb.c +++ b/trunk/drivers/net/ethernet/cadence/macb.c @@ -553,7 +553,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) while (status) { /* close possible race with dev_close */ if (unlikely(!netif_running(dev))) { - macb_writel(bp, IDR, -1); + macb_writel(bp, IDR, ~0UL); break; } @@ -789,11 +789,11 @@ static void macb_reset_hw(struct macb *bp) macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); /* Clear all status flags */ - macb_writel(bp, TSR, -1); - macb_writel(bp, RSR, -1); + macb_writel(bp, TSR, ~0UL); + macb_writel(bp, RSR, ~0UL); /* Disable all interrupts */ - macb_writel(bp, IDR, -1); + macb_writel(bp, IDR, ~0UL); macb_readl(bp, ISR); } diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index e2a6691cbd7c..3ef74f893c2e 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1244,6 +1244,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data, struct vlan_hdr *vlan; /* l3 headers */ struct iphdr *ipv4; + struct ipv6hdr *ipv6; } hdr; __be16 protocol; u8 nexthdr = 0; /* default to not TCP */ @@ -1284,6 +1285,13 @@ static unsigned int ixgbe_get_headlen(unsigned char *data, /* record next protocol */ nexthdr = hdr.ipv4->protocol; hdr.network += hlen; + } else if (protocol == __constant_htons(ETH_P_IPV6)) { + if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr))) + return max_len; + + /* record next protocol */ + nexthdr = hdr.ipv6->nexthdr; + hdr.network += sizeof(struct ipv6hdr); #ifdef IXGBE_FCOE } else if (protocol == __constant_htons(ETH_P_FCOE)) { if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN)) @@ -1294,7 +1302,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data, return hdr.network - data; } - /* finally sort out TCP */ + /* finally sort out TCP/UDP */ if (nexthdr == IPPROTO_TCP) { if ((hdr.network - data) > (max_len - sizeof(struct tcphdr))) return max_len; @@ -1307,6 +1315,11 @@ static unsigned int ixgbe_get_headlen(unsigned char *data, return hdr.network - data; hdr.network += hlen; + } else if (nexthdr == IPPROTO_UDP) { + if ((hdr.network - data) > (max_len - sizeof(struct udphdr))) + return max_len; + + hdr.network += sizeof(struct udphdr); } /* diff --git a/trunk/drivers/net/usb/Kconfig b/trunk/drivers/net/usb/Kconfig index 2ab8043e1e28..c1ae76968f47 100644 --- a/trunk/drivers/net/usb/Kconfig +++ b/trunk/drivers/net/usb/Kconfig @@ -219,24 +219,6 @@ config USB_NET_CDC_NCM * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design) * Ericsson F5521gw Mobile Broadband Module -config USB_NET_CDC_MBIM - tristate "CDC MBIM support" - depends on USB_USBNET - select USB_WDM - select USB_NET_CDC_NCM - help - This driver provides support for CDC MBIM (Mobile Broadband - Interface Model) devices. The CDC MBIM specification is - available from . - - MBIM devices require configuration using the management - protocol defined by the MBIM specification. This driver - provides unfiltered access to the MBIM control channel - through the associated /dev/cdc-wdmx character device. - - To compile this driver as a module, choose M here: the - module will be called cdc_mbim. - config USB_NET_DM9601 tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" depends on USB_USBNET diff --git a/trunk/drivers/net/usb/Makefile b/trunk/drivers/net/usb/Makefile index 478691326f37..bf063008c1af 100644 --- a/trunk/drivers/net/usb/Makefile +++ b/trunk/drivers/net/usb/Makefile @@ -31,5 +31,4 @@ obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o obj-$(CONFIG_USB_VL600) += lg-vl600.o obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o -obj-$(CONFIG_USB_NET_CDC_MBIM) += cdc_mbim.o diff --git a/trunk/drivers/net/usb/cdc_mbim.c b/trunk/drivers/net/usb/cdc_mbim.c deleted file mode 100644 index 42f51c71ec1f..000000000000 --- a/trunk/drivers/net/usb/cdc_mbim.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (c) 2012 Smith Micro Software, Inc. - * Copyright (c) 2012 Bjørn Mork - * - * This driver is based on and reuse most of cdc_ncm, which is - * Copyright (C) ST-Ericsson 2010-2012 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* driver specific data - must match cdc_ncm usage */ -struct cdc_mbim_state { - struct cdc_ncm_ctx *ctx; - atomic_t pmcount; - struct usb_driver *subdriver; - struct usb_interface *control; - struct usb_interface *data; -}; - -/* using a counter to merge subdriver requests with our own into a combined state */ -static int cdc_mbim_manage_power(struct usbnet *dev, int on) -{ - struct cdc_mbim_state *info = (void *)&dev->data; - int rv = 0; - - dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(&info->pmcount), on); - - if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) { - /* need autopm_get/put here to ensure the usbcore sees the new value */ - rv = usb_autopm_get_interface(dev->intf); - if (rv < 0) - goto err; - dev->intf->needs_remote_wakeup = on; - usb_autopm_put_interface(dev->intf); - } -err: - return rv; -} - -static int cdc_mbim_wdm_manage_power(struct usb_interface *intf, int status) -{ - struct usbnet *dev = usb_get_intfdata(intf); - - /* can be called while disconnecting */ - if (!dev) - return 0; - - return cdc_mbim_manage_power(dev, status); -} - - -static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) -{ - struct cdc_ncm_ctx *ctx; - struct usb_driver *subdriver = ERR_PTR(-ENODEV); - int ret = -ENODEV; - u8 data_altsetting = CDC_NCM_DATA_ALTSETTING_NCM; - struct cdc_mbim_state *info = (void *)&dev->data; - - /* see if interface supports MBIM alternate setting */ - if (intf->num_altsetting == 2) { - if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) - usb_set_interface(dev->udev, - intf->cur_altsetting->desc.bInterfaceNumber, - CDC_NCM_COMM_ALTSETTING_MBIM); - data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM; - } - - /* Probably NCM, defer for cdc_ncm_bind */ - if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) - goto err; - - ret = cdc_ncm_bind_common(dev, intf, data_altsetting); - if (ret) - goto err; - - ctx = info->ctx; - - /* The MBIM descriptor and the status endpoint are required */ - if (ctx->mbim_desc && dev->status) - subdriver = usb_cdc_wdm_register(ctx->control, - &dev->status->desc, - le16_to_cpu(ctx->mbim_desc->wMaxControlMessage), - cdc_mbim_wdm_manage_power); - if (IS_ERR(subdriver)) { - ret = PTR_ERR(subdriver); - cdc_ncm_unbind(dev, intf); - goto err; - } - - /* can't let usbnet use the interrupt endpoint */ - dev->status = NULL; - info->subdriver = subdriver; - - /* MBIM cannot do ARP */ - dev->net->flags |= IFF_NOARP; - - /* no need to put the VLAN tci in the packet headers */ - dev->net->features |= NETIF_F_HW_VLAN_TX; -err: - return ret; -} - -static void cdc_mbim_unbind(struct usbnet *dev, struct usb_interface *intf) -{ - struct cdc_mbim_state *info = (void *)&dev->data; - struct cdc_ncm_ctx *ctx = info->ctx; - - /* disconnect subdriver from control interface */ - if (info->subdriver && info->subdriver->disconnect) - info->subdriver->disconnect(ctx->control); - info->subdriver = NULL; - - /* let NCM unbind clean up both control and data interface */ - cdc_ncm_unbind(dev, intf); -} - - -static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) -{ - struct sk_buff *skb_out; - struct cdc_mbim_state *info = (void *)&dev->data; - struct cdc_ncm_ctx *ctx = info->ctx; - __le32 sign = cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN); - u16 tci = 0; - u8 *c; - - if (!ctx) - goto error; - - if (skb) { - if (skb->len <= sizeof(ETH_HLEN)) - goto error; - - /* mapping VLANs to MBIM sessions: - * no tag => IPS session <0> - * 1 - 255 => IPS session - * 256 - 511 => DSS session - * 512 - 4095 => unsupported, drop - */ - vlan_get_tag(skb, &tci); - - switch (tci & 0x0f00) { - case 0x0000: /* VLAN ID 0 - 255 */ - /* verify that datagram is IPv4 or IPv6 */ - skb_reset_mac_header(skb); - switch (eth_hdr(skb)->h_proto) { - case htons(ETH_P_IP): - case htons(ETH_P_IPV6): - break; - default: - goto error; - } - c = (u8 *)&sign; - c[3] = tci; - break; - case 0x0100: /* VLAN ID 256 - 511 */ - sign = cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN); - c = (u8 *)&sign; - c[3] = tci; - break; - default: - netif_err(dev, tx_err, dev->net, - "unsupported tci=0x%04x\n", tci); - goto error; - } - skb_pull(skb, ETH_HLEN); - } - - spin_lock_bh(&ctx->mtx); - skb_out = cdc_ncm_fill_tx_frame(ctx, skb, sign); - spin_unlock_bh(&ctx->mtx); - return skb_out; - -error: - if (skb) - dev_kfree_skb_any(skb); - - return NULL; -} - -static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_t len, u16 tci) -{ - __be16 proto = htons(ETH_P_802_3); - struct sk_buff *skb = NULL; - - if (tci < 256) { /* IPS session? */ - if (len < sizeof(struct iphdr)) - goto err; - - switch (*buf & 0xf0) { - case 0x40: - proto = htons(ETH_P_IP); - break; - case 0x60: - proto = htons(ETH_P_IPV6); - break; - default: - goto err; - } - } - - skb = netdev_alloc_skb_ip_align(dev->net, len + ETH_HLEN); - if (!skb) - goto err; - - /* add an ethernet header */ - skb_put(skb, ETH_HLEN); - skb_reset_mac_header(skb); - eth_hdr(skb)->h_proto = proto; - memset(eth_hdr(skb)->h_source, 0, ETH_ALEN); - memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN); - - /* add datagram */ - memcpy(skb_put(skb, len), buf, len); - - /* map MBIM session to VLAN */ - if (tci) - vlan_put_tag(skb, tci); -err: - return skb; -} - -static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) -{ - struct sk_buff *skb; - struct cdc_mbim_state *info = (void *)&dev->data; - struct cdc_ncm_ctx *ctx = info->ctx; - int len; - int nframes; - int x; - int offset; - struct usb_cdc_ncm_ndp16 *ndp16; - struct usb_cdc_ncm_dpe16 *dpe16; - int ndpoffset; - int loopcount = 50; /* arbitrary max preventing infinite loop */ - u8 *c; - u16 tci; - - ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in); - if (ndpoffset < 0) - goto error; - -next_ndp: - nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset); - if (nframes < 0) - goto error; - - ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset); - - switch (ndp16->dwSignature & cpu_to_le32(0x00ffffff)) { - case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN): - c = (u8 *)&ndp16->dwSignature; - tci = c[3]; - break; - case cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN): - c = (u8 *)&ndp16->dwSignature; - tci = c[3] + 256; - break; - default: - netif_dbg(dev, rx_err, dev->net, - "unsupported NDP signature <0x%08x>\n", - le32_to_cpu(ndp16->dwSignature)); - goto err_ndp; - - } - - dpe16 = ndp16->dpe16; - for (x = 0; x < nframes; x++, dpe16++) { - offset = le16_to_cpu(dpe16->wDatagramIndex); - len = le16_to_cpu(dpe16->wDatagramLength); - - /* - * CDC NCM ch. 3.7 - * All entries after first NULL entry are to be ignored - */ - if ((offset == 0) || (len == 0)) { - if (!x) - goto err_ndp; /* empty NTB */ - break; - } - - /* sanity checking */ - if (((offset + len) > skb_in->len) || (len > ctx->rx_max)) { - netif_dbg(dev, rx_err, dev->net, - "invalid frame detected (ignored) offset[%u]=%u, length=%u, skb=%p\n", - x, offset, len, skb_in); - if (!x) - goto err_ndp; - break; - } else { - skb = cdc_mbim_process_dgram(dev, skb_in->data + offset, len, tci); - if (!skb) - goto error; - usbnet_skb_return(dev, skb); - } - } -err_ndp: - /* are there more NDPs to process? */ - ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex); - if (ndpoffset && loopcount--) - goto next_ndp; - - return 1; -error: - return 0; -} - -static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message) -{ - int ret = 0; - struct usbnet *dev = usb_get_intfdata(intf); - struct cdc_mbim_state *info = (void *)&dev->data; - struct cdc_ncm_ctx *ctx = info->ctx; - - if (ctx == NULL) { - ret = -1; - goto error; - } - - ret = usbnet_suspend(intf, message); - if (ret < 0) - goto error; - - if (intf == ctx->control && info->subdriver && info->subdriver->suspend) - ret = info->subdriver->suspend(intf, message); - if (ret < 0) - usbnet_resume(intf); - -error: - return ret; -} - -static int cdc_mbim_resume(struct usb_interface *intf) -{ - int ret = 0; - struct usbnet *dev = usb_get_intfdata(intf); - struct cdc_mbim_state *info = (void *)&dev->data; - struct cdc_ncm_ctx *ctx = info->ctx; - bool callsub = (intf == ctx->control && info->subdriver && info->subdriver->resume); - - if (callsub) - ret = info->subdriver->resume(intf); - if (ret < 0) - goto err; - ret = usbnet_resume(intf); - if (ret < 0 && callsub && info->subdriver->suspend) - info->subdriver->suspend(intf, PMSG_SUSPEND); -err: - return ret; -} - -static const struct driver_info cdc_mbim_info = { - .description = "CDC MBIM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, - .bind = cdc_mbim_bind, - .unbind = cdc_mbim_unbind, - .manage_power = cdc_mbim_manage_power, - .rx_fixup = cdc_mbim_rx_fixup, - .tx_fixup = cdc_mbim_tx_fixup, -}; - -static const struct usb_device_id mbim_devs[] = { - /* This duplicate NCM entry is intentional. MBIM devices can - * be disguised as NCM by default, and this is necessary to - * allow us to bind the correct driver_info to such devices. - * - * bind() will sort out this for us, selecting the correct - * entry and reject the other - */ - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&cdc_mbim_info, - }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&cdc_mbim_info, - }, - { - }, -}; -MODULE_DEVICE_TABLE(usb, mbim_devs); - -static struct usb_driver cdc_mbim_driver = { - .name = "cdc_mbim", - .id_table = mbim_devs, - .probe = usbnet_probe, - .disconnect = usbnet_disconnect, - .suspend = cdc_mbim_suspend, - .resume = cdc_mbim_resume, - .reset_resume = cdc_mbim_resume, - .supports_autosuspend = 1, - .disable_hub_initiated_lpm = 1, -}; -module_usb_driver(cdc_mbim_driver); - -MODULE_AUTHOR("Greg Suarez "); -MODULE_AUTHOR("Bjørn Mork "); -MODULE_DESCRIPTION("USB CDC MBIM host driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/usb/cdc_ncm.c b/trunk/drivers/net/usb/cdc_ncm.c index 0ed03b1ba39a..4cd582a4f625 100644 --- a/trunk/drivers/net/usb/cdc_ncm.c +++ b/trunk/drivers/net/usb/cdc_ncm.c @@ -51,10 +51,90 @@ #include #include #include -#include #define DRIVER_VERSION "14-Mar-2012" +/* CDC NCM subclass 3.2.1 */ +#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 + +/* Maximum NTB length */ +#define CDC_NCM_NTB_MAX_SIZE_TX 32768 /* bytes */ +#define CDC_NCM_NTB_MAX_SIZE_RX 32768 /* bytes */ + +/* Minimum value for MaxDatagramSize, ch. 6.2.9 */ +#define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */ + +#define CDC_NCM_MIN_TX_PKT 512 /* bytes */ + +/* Default value for MaxDatagramSize */ +#define CDC_NCM_MAX_DATAGRAM_SIZE 8192 /* bytes */ + +/* + * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting + * the last NULL entry. + */ +#define CDC_NCM_DPT_DATAGRAMS_MAX 40 + +/* Restart the timer, if amount of datagrams is less than given value */ +#define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 +#define CDC_NCM_TIMER_PENDING_CNT 2 +#define CDC_NCM_TIMER_INTERVAL (400UL * NSEC_PER_USEC) + +/* The following macro defines the minimum header space */ +#define CDC_NCM_MIN_HDR_SIZE \ + (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \ + (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) + +struct cdc_ncm_data { + struct usb_cdc_ncm_nth16 nth16; + struct usb_cdc_ncm_ndp16 ndp16; + struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1]; +}; + +struct cdc_ncm_ctx { + struct cdc_ncm_data tx_ncm; + struct usb_cdc_ncm_ntb_parameters ncm_parm; + struct hrtimer tx_timer; + struct tasklet_struct bh; + + const struct usb_cdc_ncm_desc *func_desc; + const struct usb_cdc_header_desc *header_desc; + const struct usb_cdc_union_desc *union_desc; + const struct usb_cdc_ether_desc *ether_desc; + + struct net_device *netdev; + struct usb_device *udev; + struct usb_host_endpoint *in_ep; + struct usb_host_endpoint *out_ep; + struct usb_host_endpoint *status_ep; + struct usb_interface *intf; + struct usb_interface *control; + struct usb_interface *data; + + struct sk_buff *tx_curr_skb; + struct sk_buff *tx_rem_skb; + + spinlock_t mtx; + atomic_t stop; + + u32 tx_timer_pending; + u32 tx_curr_offset; + u32 tx_curr_last_offset; + u32 tx_curr_frame_num; + u32 rx_speed; + u32 tx_speed; + u32 rx_max; + u32 tx_max; + u32 max_datagram_size; + u16 tx_max_datagrams; + u16 tx_remainder; + u16 tx_modulus; + u16 tx_ndp_modulus; + u16 tx_seq; + u16 rx_seq; + u16 connected; +}; + static void cdc_ncm_txpath_bh(unsigned long param); static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx); static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); @@ -78,10 +158,7 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) u8 flags; u8 iface_no; int err; - int eth_hlen; u16 ntb_fmt_supported; - u32 min_dgram_size; - u32 min_hdr_size; iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; @@ -107,19 +184,10 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams); ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported); - eth_hlen = ETH_HLEN; - min_dgram_size = CDC_NCM_MIN_DATAGRAM_SIZE; - min_hdr_size = CDC_NCM_MIN_HDR_SIZE; - if (ctx->mbim_desc != NULL) { - flags = ctx->mbim_desc->bmNetworkCapabilities; - eth_hlen = 0; - min_dgram_size = CDC_MBIM_MIN_DATAGRAM_SIZE; - min_hdr_size = 0; - } else if (ctx->func_desc != NULL) { + if (ctx->func_desc != NULL) flags = ctx->func_desc->bmNetworkCapabilities; - } else { + else flags = 0; - } pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u " "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u " @@ -147,21 +215,41 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* inform device about NTB input size changes */ if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) { - __le32 *dwNtbInMaxSize; - dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize), GFP_KERNEL); - if (!dwNtbInMaxSize) { - err = -ENOMEM; - goto size_err; + if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) { + struct usb_cdc_ncm_ndp_input_size *ndp_in_sz; + + ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL); + if (!ndp_in_sz) { + err = -ENOMEM; + goto size_err; + } + + err = usb_control_msg(ctx->udev, + usb_sndctrlpipe(ctx->udev, 0), + USB_CDC_SET_NTB_INPUT_SIZE, + USB_TYPE_CLASS | USB_DIR_OUT + | USB_RECIP_INTERFACE, + 0, iface_no, ndp_in_sz, 8, 1000); + kfree(ndp_in_sz); + } else { + __le32 *dwNtbInMaxSize; + dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize), + GFP_KERNEL); + if (!dwNtbInMaxSize) { + err = -ENOMEM; + goto size_err; + } + *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); + + err = usb_control_msg(ctx->udev, + usb_sndctrlpipe(ctx->udev, 0), + USB_CDC_SET_NTB_INPUT_SIZE, + USB_TYPE_CLASS | USB_DIR_OUT + | USB_RECIP_INTERFACE, + 0, iface_no, dwNtbInMaxSize, 4, 1000); + kfree(dwNtbInMaxSize); } - *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); - err = usb_control_msg(ctx->udev, - usb_sndctrlpipe(ctx->udev, 0), - USB_CDC_SET_NTB_INPUT_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, iface_no, dwNtbInMaxSize, 4, 1000); - kfree(dwNtbInMaxSize); size_err: if (err < 0) pr_debug("Setting NTB Input Size failed\n"); @@ -169,7 +257,7 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* verify maximum size of transmitted NTB in bytes */ if ((ctx->tx_max < - (min_hdr_size + min_dgram_size)) || + (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) || (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) { pr_debug("Using default maximum transmit length=%d\n", CDC_NCM_NTB_MAX_SIZE_TX); @@ -211,8 +299,8 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) } /* adjust TX-remainder according to NCM specification. */ - ctx->tx_remainder = ((ctx->tx_remainder - eth_hlen) & - (ctx->tx_modulus - 1)); + ctx->tx_remainder = ((ctx->tx_remainder - ETH_HLEN) & + (ctx->tx_modulus - 1)); /* additional configuration */ @@ -239,18 +327,12 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) pr_debug("Setting NTB format to 16-bit failed\n"); } - ctx->max_datagram_size = min_dgram_size; + ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE; /* set Max Datagram Size (MTU) */ if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { __le16 *max_datagram_size; - u16 eth_max_sz; - if (ctx->ether_desc != NULL) - eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); - else if (ctx->mbim_desc != NULL) - eth_max_sz = le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize); - else - goto max_dgram_err; + u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); max_datagram_size = kzalloc(sizeof(*max_datagram_size), GFP_KERNEL); @@ -267,7 +349,7 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) 2, 1000); if (err < 0) { pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", - min_dgram_size); + CDC_NCM_MIN_DATAGRAM_SIZE); } else { ctx->max_datagram_size = le16_to_cpu(*max_datagram_size); @@ -276,10 +358,12 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) ctx->max_datagram_size = eth_max_sz; if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE) - ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE; + ctx->max_datagram_size = + CDC_NCM_MAX_DATAGRAM_SIZE; - if (ctx->max_datagram_size < min_dgram_size) - ctx->max_datagram_size = min_dgram_size; + if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE) + ctx->max_datagram_size = + CDC_NCM_MIN_DATAGRAM_SIZE; /* if value changed, update device */ if (ctx->max_datagram_size != @@ -300,8 +384,8 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) } max_dgram_err: - if (ctx->netdev->mtu != (ctx->max_datagram_size - eth_hlen)) - ctx->netdev->mtu = ctx->max_datagram_size - eth_hlen; + if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN)) + ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN; return 0; } @@ -367,7 +451,7 @@ static const struct ethtool_ops cdc_ncm_ethtool_ops = { .nway_reset = usbnet_nway_reset, }; -int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting) +static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) { struct cdc_ncm_ctx *ctx; struct usb_driver *driver; @@ -441,13 +525,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf; break; - case USB_CDC_MBIM_TYPE: - if (buf[0] < sizeof(*(ctx->mbim_desc))) - break; - - ctx->mbim_desc = (const struct usb_cdc_mbim_desc *)buf; - break; - default: break; } @@ -460,7 +537,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ /* check if we got everything */ if ((ctx->control == NULL) || (ctx->data == NULL) || - ((!ctx->mbim_desc) && ((ctx->ether_desc == NULL) || (ctx->control != intf)))) + (ctx->ether_desc == NULL) || (ctx->control != intf)) goto error; /* claim interfaces, if any */ @@ -480,7 +557,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ goto error2; /* configure data interface */ - temp = usb_set_interface(dev->udev, iface_no, data_altsetting); + temp = usb_set_interface(dev->udev, iface_no, 1); if (temp) goto error2; @@ -497,13 +574,11 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ usb_set_intfdata(ctx->control, dev); usb_set_intfdata(ctx->intf, dev); - if (ctx->ether_desc) { - temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress); - if (temp) - goto error2; - dev_info(&dev->udev->dev, "MAC-Address: %pM\n", dev->net->dev_addr); - } + temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress); + if (temp) + goto error2; + dev_info(&dev->udev->dev, "MAC-Address: %pM\n", dev->net->dev_addr); dev->in = usb_rcvbulkpipe(dev->udev, ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); @@ -512,6 +587,13 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ dev->status = ctx->status_ep; dev->rx_urb_size = ctx->rx_max; + /* + * We should get an event when network connection is "connected" or + * "disconnected". Set network connection in "disconnected" state + * (carrier is OFF) during attach, so the IP network stack does not + * start IPv6 negotiation and more. + */ + netif_carrier_off(dev->net); ctx->tx_speed = ctx->rx_speed = 0; return 0; @@ -525,9 +607,8 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ dev_info(&dev->udev->dev, "bind() failure\n"); return -ENODEV; } -EXPORT_SYMBOL_GPL(cdc_ncm_bind_common); -void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) +static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) { struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; struct usb_driver *driver = driver_of(intf); @@ -557,121 +638,52 @@ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) usb_set_intfdata(ctx->intf, NULL); cdc_ncm_free(ctx); } -EXPORT_SYMBOL_GPL(cdc_ncm_unbind); -static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) -{ - int ret; - - /* The MBIM spec defines a NCM compatible default altsetting, - * which we may have matched: - * - * "Functions that implement both NCM 1.0 and MBIM (an - * “NCM/MBIM function”) according to this recommendation - * shall provide two alternate settings for the - * Communication Interface. Alternate setting 0, and the - * associated class and endpoint descriptors, shall be - * constructed according to the rules given for the - * Communication Interface in section 5 of [USBNCM10]. - * Alternate setting 1, and the associated class and - * endpoint descriptors, shall be constructed according to - * the rules given in section 6 (USB Device Model) of this - * specification." - * - * Do not bind to such interfaces, allowing cdc_mbim to handle - * them - */ -#if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM) - if ((intf->num_altsetting == 2) && - !usb_set_interface(dev->udev, - intf->cur_altsetting->desc.bInterfaceNumber, - CDC_NCM_COMM_ALTSETTING_MBIM) && - cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) - return -ENODEV; -#endif - - /* NCM data altsetting is always 1 */ - ret = cdc_ncm_bind_common(dev, intf, 1); - - /* - * We should get an event when network connection is "connected" or - * "disconnected". Set network connection in "disconnected" state - * (carrier is OFF) during attach, so the IP network stack does not - * start IPv6 negotiation and more. - */ - netif_carrier_off(dev->net); - return ret; -} - -static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max) -{ - size_t align = ALIGN(skb->len, modulus) - skb->len + remainder; - - if (skb->len + align > max) - align = max - skb->len; - if (align && skb_tailroom(skb) >= align) - memset(skb_put(skb, align), 0, align); -} - -/* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly - * allocating a new one within skb - */ -static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve) +static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max) { - struct usb_cdc_ncm_ndp16 *ndp16 = NULL; - struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data; - size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex); - - /* follow the chain of NDPs, looking for a match */ - while (ndpoffset) { - ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset); - if (ndp16->dwSignature == sign) - return ndp16; - ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex); - } - - /* align new NDP */ - cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); - - /* verify that there is room for the NDP and the datagram (reserve) */ - if ((ctx->tx_max - skb->len - reserve) < CDC_NCM_NDP_SIZE) - return NULL; - - /* link to it */ - if (ndp16) - ndp16->wNextNdpIndex = cpu_to_le16(skb->len); - else - nth16->wNdpIndex = cpu_to_le16(skb->len); - - /* push a new empty NDP */ - ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, CDC_NCM_NDP_SIZE), 0, CDC_NCM_NDP_SIZE); - ndp16->dwSignature = sign; - ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16)); - return ndp16; + if (first >= max) + return; + if (first >= end) + return; + if (end > max) + end = max; + memset(ptr + first, 0, end - first); } -struct sk_buff * -cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) +static struct sk_buff * +cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) { - struct usb_cdc_ncm_nth16 *nth16; - struct usb_cdc_ncm_ndp16 *ndp16; struct sk_buff *skb_out; - u16 n = 0, index, ndplen; + u32 rem; + u32 offset; + u32 last_offset; + u16 n = 0, index; u8 ready2send = 0; /* if there is a remaining skb, it gets priority */ - if (skb != NULL) { + if (skb != NULL) swap(skb, ctx->tx_rem_skb); - swap(sign, ctx->tx_rem_sign); - } else { + else ready2send = 1; - } + + /* + * +----------------+ + * | skb_out | + * +----------------+ + * ^ offset + * ^ last_offset + */ /* check if we are resuming an OUT skb */ - skb_out = ctx->tx_curr_skb; + if (ctx->tx_curr_skb != NULL) { + /* pop variables */ + skb_out = ctx->tx_curr_skb; + offset = ctx->tx_curr_offset; + last_offset = ctx->tx_curr_last_offset; + n = ctx->tx_curr_frame_num; - /* allocate a new OUT skb */ - if (!skb_out) { + } else { + /* reset variables */ skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); if (skb_out == NULL) { if (skb != NULL) { @@ -680,21 +692,35 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) } goto exit_no_skb; } - /* fill out the initial 16-bit NTB header */ - nth16 = (struct usb_cdc_ncm_nth16 *)memset(skb_put(skb_out, sizeof(struct usb_cdc_ncm_nth16)), 0, sizeof(struct usb_cdc_ncm_nth16)); - nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); - nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16)); - nth16->wSequence = cpu_to_le16(ctx->tx_seq++); - /* count total number of frames in this NTB */ + /* make room for NTH and NDP */ + offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16), + ctx->tx_ndp_modulus) + + sizeof(struct usb_cdc_ncm_ndp16) + + (ctx->tx_max_datagrams + 1) * + sizeof(struct usb_cdc_ncm_dpe16); + + /* store last valid offset before alignment */ + last_offset = offset; + /* align first Datagram offset correctly */ + offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; + /* zero buffer till the first IP datagram */ + cdc_ncm_zero_fill(skb_out->data, 0, offset, offset); + n = 0; ctx->tx_curr_frame_num = 0; } - for (n = ctx->tx_curr_frame_num; n < ctx->tx_max_datagrams; n++) { - /* send any remaining skb first */ + for (; n < ctx->tx_max_datagrams; n++) { + /* check if end of transmit buffer is reached */ + if (offset >= ctx->tx_max) { + ready2send = 1; + break; + } + /* compute maximum buffer size */ + rem = ctx->tx_max - offset; + if (skb == NULL) { skb = ctx->tx_rem_skb; - sign = ctx->tx_rem_sign; ctx->tx_rem_skb = NULL; /* check for end of skb */ @@ -702,14 +728,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) break; } - /* get the appropriate NDP for this skb */ - ndp16 = cdc_ncm_ndp(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder); - - /* align beginning of next frame */ - cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); - - /* check if we had enough room left for both NDP and frame */ - if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) { + if (skb->len > rem) { if (n == 0) { /* won't fit, MTU problem? */ dev_kfree_skb_any(skb); @@ -722,30 +741,31 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) ctx->netdev->stats.tx_dropped++; } ctx->tx_rem_skb = skb; - ctx->tx_rem_sign = sign; skb = NULL; ready2send = 1; } break; } - /* calculate frame number withing this NDP */ - ndplen = le16_to_cpu(ndp16->wLength); - index = (ndplen - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16) - 1; + memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len); + + ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len); + ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset); + + /* update offset */ + offset += skb->len; + + /* store last valid offset before alignment */ + last_offset = offset; + + /* align offset correctly */ + offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; - /* OK, add this skb */ - ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len); - ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len); - ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16)); - memcpy(skb_put(skb_out, skb->len), skb->data, skb->len); + /* zero padding */ + cdc_ncm_zero_fill(skb_out->data, last_offset, offset, + ctx->tx_max); dev_kfree_skb_any(skb); skb = NULL; - - /* send now if this NDP is full */ - if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) { - ready2send = 1; - break; - } } /* free up any dangling skb */ @@ -761,12 +781,16 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) /* wait for more frames */ /* push variables */ ctx->tx_curr_skb = skb_out; + ctx->tx_curr_offset = offset; + ctx->tx_curr_last_offset = last_offset; goto exit_no_skb; } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) { /* wait for more frames */ /* push variables */ ctx->tx_curr_skb = skb_out; + ctx->tx_curr_offset = offset; + ctx->tx_curr_last_offset = last_offset; /* set the pending count */ if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT; @@ -777,24 +801,75 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) /* variables will be reset at next call */ } + /* check for overflow */ + if (last_offset > ctx->tx_max) + last_offset = ctx->tx_max; + + /* revert offset */ + offset = last_offset; + /* * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes, * we send buffers as it is. If we get more data, it would be more * efficient for USB HS mobile device with DMA engine to receive a full * size NTB, than canceling DMA transfer and receiving a short packet. */ - if (skb_out->len > CDC_NCM_MIN_TX_PKT) - /* final zero padding */ - memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0, ctx->tx_max - skb_out->len); + if (offset > CDC_NCM_MIN_TX_PKT) + offset = ctx->tx_max; + + /* final zero padding */ + cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max); + + /* store last offset */ + last_offset = offset; + + if (((last_offset < ctx->tx_max) && ((last_offset % + le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) || + (((last_offset == ctx->tx_max) && ((ctx->tx_max % + le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) && + (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) { + /* force short packet */ + *(((u8 *)skb_out->data) + last_offset) = 0; + last_offset++; + } + + /* zero the rest of the DPEs plus the last NULL entry */ + for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) { + ctx->tx_ncm.dpe16[n].wDatagramLength = 0; + ctx->tx_ncm.dpe16[n].wDatagramIndex = 0; + } - /* do we need to prevent a ZLP? */ - if (((skb_out->len % le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0) && - (skb_out->len < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)) && skb_tailroom(skb_out)) - *skb_put(skb_out, 1) = 0; /* force short packet */ + /* fill out 16-bit NTB header */ + ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); + ctx->tx_ncm.nth16.wHeaderLength = + cpu_to_le16(sizeof(ctx->tx_ncm.nth16)); + ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq); + ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset); + index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus); + ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index); + + memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16)); + ctx->tx_seq++; + + /* fill out 16-bit NDP table */ + ctx->tx_ncm.ndp16.dwSignature = + cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN); + rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) * + sizeof(struct usb_cdc_ncm_dpe16)); + ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem); + ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */ + + memcpy(((u8 *)skb_out->data) + index, + &(ctx->tx_ncm.ndp16), + sizeof(ctx->tx_ncm.ndp16)); + + memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16), + &(ctx->tx_ncm.dpe16), + (ctx->tx_curr_frame_num + 1) * + sizeof(struct usb_cdc_ncm_dpe16)); - /* set final frame length */ - nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; - nth16->wBlockLength = cpu_to_le16(skb_out->len); + /* set frame length */ + skb_put(skb_out, last_offset); /* return skb */ ctx->tx_curr_skb = NULL; @@ -807,7 +882,6 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign) cdc_ncm_tx_timeout_start(ctx); return NULL; } -EXPORT_SYMBOL_GPL(cdc_ncm_fill_tx_frame); static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx) { @@ -862,7 +936,7 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) goto error; spin_lock_bh(&ctx->mtx); - skb_out = cdc_ncm_fill_tx_frame(ctx, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN)); + skb_out = cdc_ncm_fill_tx_frame(ctx, skb); spin_unlock_bh(&ctx->mtx); return skb_out; @@ -873,12 +947,17 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) return NULL; } -/* verify NTB header and return offset of first NDP, or negative error */ -int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in) +static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) { - struct usb_cdc_ncm_nth16 *nth16; + struct sk_buff *skb; + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; int len; - int ret = -EINVAL; + int nframes; + int x; + int offset; + struct usb_cdc_ncm_nth16 *nth16; + struct usb_cdc_ncm_ndp16 *ndp16; + struct usb_cdc_ncm_dpe16 *dpe16; if (ctx == NULL) goto error; @@ -912,23 +991,20 @@ int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in) } ctx->rx_seq = le16_to_cpu(nth16->wSequence); - ret = le16_to_cpu(nth16->wNdpIndex); -error: - return ret; -} -EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth16); + len = le16_to_cpu(nth16->wNdpIndex); + if ((len + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) { + pr_debug("invalid DPT16 index <%u>\n", + le16_to_cpu(nth16->wNdpIndex)); + goto error; + } -/* verify NDP header and return number of datagrams, or negative error */ -int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset) -{ - struct usb_cdc_ncm_ndp16 *ndp16; - int ret = -EINVAL; + ndp16 = (struct usb_cdc_ncm_ndp16 *)(((u8 *)skb_in->data) + len); - if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) { - pr_debug("invalid NDP offset <%u>\n", ndpoffset); + if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) { + pr_debug("invalid DPT16 signature <%u>\n", + le32_to_cpu(ndp16->dwSignature)); goto error; } - ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset); if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) { pr_debug("invalid DPT16 length <%u>\n", @@ -936,52 +1012,20 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset) goto error; } - ret = ((le16_to_cpu(ndp16->wLength) - + nframes = ((le16_to_cpu(ndp16->wLength) - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16)); - ret--; /* we process NDP entries except for the last one */ - - if ((sizeof(struct usb_cdc_ncm_ndp16) + ret * (sizeof(struct usb_cdc_ncm_dpe16))) > - skb_in->len) { - pr_debug("Invalid nframes = %d\n", ret); - ret = -EINVAL; - } - -error: - return ret; -} -EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp16); - -static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) -{ - struct sk_buff *skb; - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; - int len; - int nframes; - int x; - int offset; - struct usb_cdc_ncm_ndp16 *ndp16; - struct usb_cdc_ncm_dpe16 *dpe16; - int ndpoffset; - int loopcount = 50; /* arbitrary max preventing infinite loop */ + nframes--; /* we process NDP entries except for the last one */ - ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in); - if (ndpoffset < 0) - goto error; + len += sizeof(struct usb_cdc_ncm_ndp16); -next_ndp: - nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset); - if (nframes < 0) + if ((len + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > + skb_in->len) { + pr_debug("Invalid nframes = %d\n", nframes); goto error; - - ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset); - - if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) { - pr_debug("invalid DPT16 signature <%u>\n", - le32_to_cpu(ndp16->dwSignature)); - goto err_ndp; } - dpe16 = ndp16->dpe16; + + dpe16 = (struct usb_cdc_ncm_dpe16 *)(((u8 *)skb_in->data) + len); for (x = 0; x < nframes; x++, dpe16++) { offset = le16_to_cpu(dpe16->wDatagramIndex); @@ -993,7 +1037,7 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) */ if ((offset == 0) || (len == 0)) { if (!x) - goto err_ndp; /* empty NTB */ + goto error; /* empty NTB */ break; } @@ -1004,7 +1048,7 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) "offset[%u]=%u, length=%u, skb=%p\n", x, offset, len, skb_in); if (!x) - goto err_ndp; + goto error; break; } else { @@ -1017,12 +1061,6 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) usbnet_skb_return(dev, skb); } } -err_ndp: - /* are there more NDPs to process? */ - ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex); - if (ndpoffset && loopcount--) - goto next_ndp; - return 1; error: return 0; diff --git a/trunk/include/linux/platform_data/macb.h b/trunk/include/linux/platform_data/macb.h index 044a124bfbbc..b081c7245ec8 100644 --- a/trunk/include/linux/platform_data/macb.h +++ b/trunk/include/linux/platform_data/macb.h @@ -12,7 +12,6 @@ struct macb_platform_data { u32 phy_mask; int phy_irq_pin; /* PHY IRQ */ u8 is_rmii; /* using RMII interface? */ - u8 rev_eth_addr; /* reverse Ethernet address byte order */ }; #endif /* __MACB_PDATA_H__ */ diff --git a/trunk/include/linux/usb/cdc.h b/trunk/include/linux/usb/cdc.h index f35aa0a338c7..81a927930bfd 100644 --- a/trunk/include/linux/usb/cdc.h +++ b/trunk/include/linux/usb/cdc.h @@ -19,7 +19,6 @@ #define USB_CDC_SUBCLASS_OBEX 0x0b #define USB_CDC_SUBCLASS_EEM 0x0c #define USB_CDC_SUBCLASS_NCM 0x0d -#define USB_CDC_SUBCLASS_MBIM 0x0e #define USB_CDC_PROTO_NONE 0 @@ -34,7 +33,6 @@ #define USB_CDC_PROTO_EEM 7 #define USB_CDC_NCM_PROTO_NTB 1 -#define USB_CDC_MBIM_PROTO_NTB 2 /*-------------------------------------------------------------------------*/ @@ -55,7 +53,6 @@ #define USB_CDC_DMM_TYPE 0x14 #define USB_CDC_OBEX_TYPE 0x15 #define USB_CDC_NCM_TYPE 0x1a -#define USB_CDC_MBIM_TYPE 0x1b /* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ struct usb_cdc_header_desc { @@ -190,21 +187,6 @@ struct usb_cdc_ncm_desc { __le16 bcdNcmVersion; __u8 bmNetworkCapabilities; } __attribute__ ((packed)); - -/* "MBIM Control Model Functional Descriptor" */ -struct usb_cdc_mbim_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __le16 bcdMBIMVersion; - __le16 wMaxControlMessage; - __u8 bNumberFilters; - __u8 bMaxFilterSize; - __le16 wMaxSegmentSize; - __u8 bmNetworkCapabilities; -} __attribute__ ((packed)); - /*-------------------------------------------------------------------------*/ /* @@ -350,11 +332,6 @@ struct usb_cdc_ncm_nth32 { #define USB_CDC_NCM_NDP32_CRC_SIGN 0x316D636E /* ncm1 */ #define USB_CDC_NCM_NDP32_NOCRC_SIGN 0x306D636E /* ncm0 */ -#define USB_CDC_MBIM_NDP16_IPS_SIGN 0x00535049 /* IPS : IPS0 for now */ -#define USB_CDC_MBIM_NDP32_IPS_SIGN 0x00737069 /* ips : ips0 for now */ -#define USB_CDC_MBIM_NDP16_DSS_SIGN 0x00535344 /* DSS */ -#define USB_CDC_MBIM_NDP32_DSS_SIGN 0x00737364 /* dss */ - /* 16-bit NCM Datagram Pointer Entry */ struct usb_cdc_ncm_dpe16 { __le16 wDatagramIndex; diff --git a/trunk/include/linux/usb/cdc_ncm.h b/trunk/include/linux/usb/cdc_ncm.h deleted file mode 100644 index 3b8f9d4fc3fe..000000000000 --- a/trunk/include/linux/usb/cdc_ncm.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) ST-Ericsson 2010-2012 - * Contact: Alexey Orishko - * Original author: Hans Petter Selasky - * - * USB Host Driver for Network Control Model (NCM) - * http://www.usb.org/developers/devclass_docs/NCM10.zip - * - * The NCM encoding, decoding and initialization logic - * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h - * - * This software is available to you under a choice of one of two - * licenses. You may choose this file to be licensed under the terms - * of the GNU General Public License (GPL) Version 2 or the 2-clause - * BSD license listed below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define CDC_NCM_COMM_ALTSETTING_NCM 0 -#define CDC_NCM_COMM_ALTSETTING_MBIM 1 - -#define CDC_NCM_DATA_ALTSETTING_NCM 1 -#define CDC_NCM_DATA_ALTSETTING_MBIM 2 - -/* CDC NCM subclass 3.2.1 */ -#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 - -/* Maximum NTB length */ -#define CDC_NCM_NTB_MAX_SIZE_TX 32768 /* bytes */ -#define CDC_NCM_NTB_MAX_SIZE_RX 32768 /* bytes */ - -/* Minimum value for MaxDatagramSize, ch. 6.2.9 */ -#define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */ - -/* Minimum value for MaxDatagramSize, ch. 8.1.3 */ -#define CDC_MBIM_MIN_DATAGRAM_SIZE 2048 /* bytes */ - -#define CDC_NCM_MIN_TX_PKT 512 /* bytes */ - -/* Default value for MaxDatagramSize */ -#define CDC_NCM_MAX_DATAGRAM_SIZE 8192 /* bytes */ - -/* - * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting - * the last NULL entry. - */ -#define CDC_NCM_DPT_DATAGRAMS_MAX 40 - -/* Restart the timer, if amount of datagrams is less than given value */ -#define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 -#define CDC_NCM_TIMER_PENDING_CNT 2 -#define CDC_NCM_TIMER_INTERVAL (400UL * NSEC_PER_USEC) - -/* The following macro defines the minimum header space */ -#define CDC_NCM_MIN_HDR_SIZE \ - (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \ - (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) - -#define CDC_NCM_NDP_SIZE \ - (sizeof(struct usb_cdc_ncm_ndp16) + \ - (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) - -#define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \ - (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE) -#define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB) - -struct cdc_ncm_ctx { - struct usb_cdc_ncm_ntb_parameters ncm_parm; - struct hrtimer tx_timer; - struct tasklet_struct bh; - - const struct usb_cdc_ncm_desc *func_desc; - const struct usb_cdc_mbim_desc *mbim_desc; - const struct usb_cdc_header_desc *header_desc; - const struct usb_cdc_union_desc *union_desc; - const struct usb_cdc_ether_desc *ether_desc; - - struct net_device *netdev; - struct usb_device *udev; - struct usb_host_endpoint *in_ep; - struct usb_host_endpoint *out_ep; - struct usb_host_endpoint *status_ep; - struct usb_interface *intf; - struct usb_interface *control; - struct usb_interface *data; - - struct sk_buff *tx_curr_skb; - struct sk_buff *tx_rem_skb; - __le32 tx_rem_sign; - - spinlock_t mtx; - atomic_t stop; - - u32 tx_timer_pending; - u32 tx_curr_frame_num; - u32 rx_speed; - u32 tx_speed; - u32 rx_max; - u32 tx_max; - u32 max_datagram_size; - u16 tx_max_datagrams; - u16 tx_remainder; - u16 tx_modulus; - u16 tx_ndp_modulus; - u16 tx_seq; - u16 rx_seq; - u16 connected; -}; - -extern int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); -extern void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); -extern struct sk_buff *cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign); -extern int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in); -extern int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset); diff --git a/trunk/include/net/ip6_fib.h b/trunk/include/net/ip6_fib.h index 20210d79e36a..8a2a203eb15d 100644 --- a/trunk/include/net/ip6_fib.h +++ b/trunk/include/net/ip6_fib.h @@ -47,8 +47,6 @@ struct fib6_config { unsigned long fc_expires; struct nlattr *fc_mx; int fc_mx_len; - int fc_mp_len; - struct nlattr *fc_mp; struct nl_info fc_nlinfo; }; @@ -101,14 +99,6 @@ struct rt6_info { struct in6_addr rt6i_gateway; - /* Multipath routes: - * siblings is a list of rt6_info that have the the same metric/weight, - * destination, but not the same gateway. nsiblings is just a cache - * to speed up lookup. - */ - struct list_head rt6i_siblings; - unsigned int rt6i_nsiblings; - atomic_t rt6i_ref; /* These are in a separate cache line. */ diff --git a/trunk/net/ipv6/ip6_fib.c b/trunk/net/ipv6/ip6_fib.c index 710cafd2e1a9..24995a93ef8c 100644 --- a/trunk/net/ipv6/ip6_fib.c +++ b/trunk/net/ipv6/ip6_fib.c @@ -672,8 +672,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, iter->rt6i_idev == rt->rt6i_idev && ipv6_addr_equal(&iter->rt6i_gateway, &rt->rt6i_gateway)) { - if (rt->rt6i_nsiblings) - rt->rt6i_nsiblings = 0; if (!(iter->rt6i_flags & RTF_EXPIRES)) return -EEXIST; if (!(rt->rt6i_flags & RTF_EXPIRES)) @@ -682,21 +680,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, rt6_set_expires(iter, rt->dst.expires); return -EEXIST; } - /* If we have the same destination and the same metric, - * but not the same gateway, then the route we try to - * add is sibling to this route, increment our counter - * of siblings, and later we will add our route to the - * list. - * Only static routes (which don't have flag - * RTF_EXPIRES) are used for ECMPv6. - * - * To avoid long list, we only had siblings if the - * route have a gateway. - */ - if (rt->rt6i_flags & RTF_GATEWAY && - !(rt->rt6i_flags & RTF_EXPIRES) && - !(iter->rt6i_flags & RTF_EXPIRES)) - rt->rt6i_nsiblings++; } if (iter->rt6i_metric > rt->rt6i_metric) @@ -709,35 +692,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, if (ins == &fn->leaf) fn->rr_ptr = NULL; - /* Link this route to others same route. */ - if (rt->rt6i_nsiblings) { - unsigned int rt6i_nsiblings; - struct rt6_info *sibling, *temp_sibling; - - /* Find the first route that have the same metric */ - sibling = fn->leaf; - while (sibling) { - if (sibling->rt6i_metric == rt->rt6i_metric) { - list_add_tail(&rt->rt6i_siblings, - &sibling->rt6i_siblings); - break; - } - sibling = sibling->dst.rt6_next; - } - /* For each sibling in the list, increment the counter of - * siblings. BUG() if counters does not match, list of siblings - * is broken! - */ - rt6i_nsiblings = 0; - list_for_each_entry_safe(sibling, temp_sibling, - &rt->rt6i_siblings, rt6i_siblings) { - sibling->rt6i_nsiblings++; - BUG_ON(sibling->rt6i_nsiblings != rt->rt6i_nsiblings); - rt6i_nsiblings++; - } - BUG_ON(rt6i_nsiblings != rt->rt6i_nsiblings); - } - /* * insert node */ @@ -1239,17 +1193,6 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, if (fn->rr_ptr == rt) fn->rr_ptr = NULL; - /* Remove this entry from other siblings */ - if (rt->rt6i_nsiblings) { - struct rt6_info *sibling, *next_sibling; - - list_for_each_entry_safe(sibling, next_sibling, - &rt->rt6i_siblings, rt6i_siblings) - sibling->rt6i_nsiblings--; - rt->rt6i_nsiblings = 0; - list_del_init(&rt->rt6i_siblings); - } - /* Adjust walkers */ read_lock(&fib6_walker_lock); FOR_WALKERS(w) { diff --git a/trunk/net/ipv6/route.c b/trunk/net/ipv6/route.c index 126da562d3eb..7c7e963260e1 100644 --- a/trunk/net/ipv6/route.c +++ b/trunk/net/ipv6/route.c @@ -57,7 +57,6 @@ #include #include #include -#include #include @@ -290,8 +289,6 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers); rt->rt6i_genid = rt_genid(net); - INIT_LIST_HEAD(&rt->rt6i_siblings); - rt->rt6i_nsiblings = 0; } return rt; } @@ -388,69 +385,6 @@ static bool rt6_need_strict(const struct in6_addr *daddr) (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); } -/* Multipath route selection: - * Hash based function using packet header and flowlabel. - * Adapted from fib_info_hashfn() - */ -static int rt6_info_hash_nhsfn(unsigned int candidate_count, - const struct flowi6 *fl6) -{ - unsigned int val = fl6->flowi6_proto; - - val ^= fl6->daddr.s6_addr32[0]; - val ^= fl6->daddr.s6_addr32[1]; - val ^= fl6->daddr.s6_addr32[2]; - val ^= fl6->daddr.s6_addr32[3]; - - val ^= fl6->saddr.s6_addr32[0]; - val ^= fl6->saddr.s6_addr32[1]; - val ^= fl6->saddr.s6_addr32[2]; - val ^= fl6->saddr.s6_addr32[3]; - - /* Work only if this not encapsulated */ - switch (fl6->flowi6_proto) { - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_SCTP: - val ^= fl6->fl6_sport; - val ^= fl6->fl6_dport; - break; - - case IPPROTO_ICMPV6: - val ^= fl6->fl6_icmp_type; - val ^= fl6->fl6_icmp_code; - break; - } - /* RFC6438 recommands to use flowlabel */ - val ^= fl6->flowlabel; - - /* Perhaps, we need to tune, this function? */ - val = val ^ (val >> 7) ^ (val >> 12); - return val % candidate_count; -} - -static struct rt6_info *rt6_multipath_select(struct rt6_info *match, - struct flowi6 *fl6) -{ - struct rt6_info *sibling, *next_sibling; - int route_choosen; - - route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6); - /* Don't change the route, if route_choosen == 0 - * (siblings does not include ourself) - */ - if (route_choosen) - list_for_each_entry_safe(sibling, next_sibling, - &match->rt6i_siblings, rt6i_siblings) { - route_choosen--; - if (route_choosen == 0) { - match = sibling; - break; - } - } - return match; -} - /* * Route lookup. Any table->tb6_lock is implied. */ @@ -768,8 +702,6 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, restart: rt = fn->leaf; rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); - if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0) - rt = rt6_multipath_select(rt, fl6); BACKTRACK(net, &fl6->saddr); out: dst_use(&rt->dst, jiffies); @@ -931,8 +863,7 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, restart: rt = rt6_select(fn, oif, strict | reachable); - if (rt->rt6i_nsiblings && oif == 0) - rt = rt6_multipath_select(rt, fl6); + BACKTRACK(net, &fl6->saddr); if (rt == net->ipv6.ip6_null_entry || rt->rt6i_flags & RTF_CACHE) @@ -2318,7 +2249,6 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_IIF] = { .type = NLA_U32 }, [RTA_PRIORITY] = { .type = NLA_U32 }, [RTA_METRICS] = { .type = NLA_NESTED }, - [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, }; static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2396,65 +2326,11 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, if (tb[RTA_TABLE]) cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); - if (tb[RTA_MULTIPATH]) { - cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); - cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); - } - err = 0; errout: return err; } -static int ip6_route_multipath(struct fib6_config *cfg, int add) -{ - struct fib6_config r_cfg; - struct rtnexthop *rtnh; - int remaining; - int attrlen; - int err = 0, last_err = 0; - -beginning: - rtnh = (struct rtnexthop *)cfg->fc_mp; - remaining = cfg->fc_mp_len; - - /* Parse a Multipath Entry */ - while (rtnh_ok(rtnh, remaining)) { - memcpy(&r_cfg, cfg, sizeof(*cfg)); - if (rtnh->rtnh_ifindex) - r_cfg.fc_ifindex = rtnh->rtnh_ifindex; - - attrlen = rtnh_attrlen(rtnh); - if (attrlen > 0) { - struct nlattr *nla, *attrs = rtnh_attrs(rtnh); - - nla = nla_find(attrs, attrlen, RTA_GATEWAY); - if (nla) { - nla_memcpy(&r_cfg.fc_gateway, nla, 16); - r_cfg.fc_flags |= RTF_GATEWAY; - } - } - err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg); - if (err) { - last_err = err; - /* If we are trying to remove a route, do not stop the - * loop when ip6_route_del() fails (because next hop is - * already gone), we should try to remove all next hops. - */ - if (add) { - /* If add fails, we should try to delete all - * next hops that have been already added. - */ - add = 0; - goto beginning; - } - } - rtnh = rtnh_next(rtnh, &remaining); - } - - return last_err; -} - static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { struct fib6_config cfg; @@ -2464,10 +2340,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a if (err < 0) return err; - if (cfg.fc_mp) - return ip6_route_multipath(&cfg, 0); - else - return ip6_route_del(&cfg); + return ip6_route_del(&cfg); } static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) @@ -2479,10 +2352,7 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a if (err < 0) return err; - if (cfg.fc_mp) - return ip6_route_multipath(&cfg, 1); - else - return ip6_route_add(&cfg); + return ip6_route_add(&cfg); } static inline size_t rt6_nlmsg_size(void)