* net/bluetooth/rfcomm/tty.c: use-after-free
From: Adrian Bunk @ 2007-07-23 1:25 UTC (permalink / raw)
To: Ville Tervo, Marcel Holtmann, maxk; +Cc: bluez-devel, linux-kernel, netdev
Commit 8de0a15483b357d0f0b821330ec84d1660cadc4e added the following
use-after-free in net/bluetooth/rfcomm/tty.c:
<-- snip -->
...
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
{
...
if (IS_ERR(dev->tty_dev)) {
list_del(&dev->list);
kfree(dev);
return PTR_ERR(dev->tty_dev);
}
...
<-- snip -->
Spotted by the Coverity checker.
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
^ permalink raw reply
* net/9p/mux.c: use-after-free
From: Adrian Bunk @ 2007-07-23 1:20 UTC (permalink / raw)
To: Latchesar Ionkov, Eric Van Hensbergen
Cc: v9fs-developer, netdev, linux-kernel
The Coverity checker spotted the following use-after-free
in net/9p/mux.c:
<-- snip -->
...
struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize,
unsigned char *extended)
{
...
if (!m->tagpool) {
kfree(m);
return ERR_PTR(PTR_ERR(m->tagpool));
}
...
<-- snip -->
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
^ permalink raw reply
* drivers/net/xen-netfront.c: bogus code
From: Adrian Bunk @ 2007-07-22 23:26 UTC (permalink / raw)
To: Jeremy Fitzhardinge, Chris Wright, Jeff Garzik
Cc: xen-devel, netdev, linux-kernel
The Coverity checker spotted the following bogus code
in drivers/net/xen-netfront.c:
<-- snip -->
...
static void xennet_alloc_rx_buffers(struct net_device *dev)
{
...
for (nr_flips = i = 0; ; i++) {
skb = __skb_dequeue(&np->rx_batch);
if (skb == NULL)
break;
skb->dev = dev;
id = xennet_rxidx(req_prod + i);
BUG_ON(np->rx_skbs[id]);
np->rx_skbs[id] = skb;
ref = gnttab_claim_grant_reference(&np->gref_rx_head);
BUG_ON((signed short)ref < 0);
np->grant_rx_ref[id] = ref;
pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
vaddr = page_address(skb_shinfo(skb)->frags[0].page);
req = RING_GET_REQUEST(&np->rx, req_prod + i);
gnttab_grant_foreign_access_ref(ref,
np->xbdev->otherend_id,
pfn_to_mfn(pfn),
0);
req->id = id;
req->gref = ref;
}
if (nr_flips != 0) {
...
<-- snip -->
Note that "nr_flips" is always 0 in the last line.
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
^ permalink raw reply
* Re: NFS mount gives ENETDOWN in -git15
From: Yinghai Lu @ 2007-07-22 23:10 UTC (permalink / raw)
To: Andi Kleen; +Cc: netdev, trond.myklebust, linux-kernel
In-Reply-To: <200707211531.17750.ak@suse.de>
On 7/21/07, Andi Kleen <ak@suse.de> wrote:
>
> I tried to mount another nfs mount on a system running with nfsroot.
> But I get
>
> # mount basil:/home /basil/home/
> mount: Network is down
>
> The network is not down of course, the system is happily running with nfs root from that
> server. Userland is older SUSE 10.0
>
> Excerpt from strace mount:
>
> -Andi
>
What is your CONFIG_NETDEVICES_MULTIQUEUE in .config?
YH
^ permalink raw reply
* [PATCH] [IrDA] KS959 USB IrDA dongle support
From: Samuel Ortiz @ 2007-07-22 21:32 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, irda-users, linux-usb-devel, a_villacis
Hi Dave,
Last IrDA patch for 2.6.23-rc1, if it's not too late...
This patch adds support for the KingSun KS-959 USB IrDA dongle.
This dongle does not follow the usb-irda specification, so it needs its own
special driver. First, it uses control URBs for data transfer, instead of
bulk or interrupt transfers; the only interrupt endpoint exposed seems to
be a dummy to prevent the interface from being rejected. Second, it uses
obfuscation and padding at the USB traffic level, for no apparent reason
other than to make reverse engineering harder (full details on obfuscation
in comments at beginning of source). Although it is advertised as a "4 Mbps
FIR dongle", it apparently loses packets at speeds greater than 57600 bps.
On plugin, this dongle reports vendor and device IDs: 0x07d0:0x4959 .
From: Alex Villacís Lasso <a_villacis@palosanto.com>
Signed-off-by: Alex Villacís Lasso <a_villacis@palosanto.com>
Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
---
drivers/net/irda/Kconfig | 14 +
drivers/net/irda/Makefile | 1 +
drivers/net/irda/ks959-sir.c | 919 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 934 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/irda/ks959-sir.c
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 2098d0a..35321dc 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -164,6 +164,20 @@ config EP7211_DONGLE
+config KS959_DONGLE
+ tristate "KingSun KS-959 IrDA-USB dongle"
+ depends on IRDA && USB && EXPERIMENTAL
+ help
+ Say Y or M here if you want to build support for the KingSun KS-959
+ IrDA-USB bridge device driver.
+
+ This USB bridge does not conform to the IrDA-USB device class
+ specification, and therefore needs its own specific driver.
+ This dongle supports SIR speeds only (9600 through 57600 bps).
+
+ To compile it as a module, choose M here: the module will be called
+ ks959-sir.
+
comment "Old SIR device drivers"
config IRPORT_SIR
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 2808ef5..9212c15 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o
obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
+obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o
# The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
new file mode 100644
index 0000000..12e3435
--- /dev/null
+++ b/drivers/net/irda/ks959-sir.c
@@ -0,0 +1,919 @@
+/*****************************************************************************
+*
+* Filename: ks959-sir.c
+* Version: 0.1.2
+* Description: Irda KingSun KS-959 USB Dongle
+* Status: Experimental
+* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
+* with help from Domen Puncer <domen@coderock.org>
+*
+* Based on stir4200, mcs7780, kingsun-sir drivers.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * Following is my most current (2007-07-17) understanding of how the Kingsun
+ * KS-959 dongle is supposed to work. This information was deduced by
+ * reverse-engineering and examining the USB traffic captured with USBSnoopy
+ * from the WinXP driver. Feel free to update here as more of the dongle is
+ * known.
+ *
+ * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for
+ * invaluable help in cracking the obfuscation and padding required for this
+ * dongle.
+ *
+ * General: This dongle exposes one interface with one interrupt IN endpoint.
+ * However, the interrupt endpoint is NOT used at all for this dongle. Instead,
+ * this dongle uses control transfers for everything, including sending and
+ * receiving the IrDA frame data. Apparently the interrupt endpoint is just a
+ * dummy to ensure the dongle has a valid interface to present to the PC. And I
+ * thought the DonShine dongle was weird... In addition, this dongle uses
+ * obfuscation (?!?!?), applied at the USB level, to hide the traffic, both sent
+ * and received, from the dongle. I call it obfuscation because the XOR keying
+ * and padding required to produce an USB traffic acceptable for the dongle can
+ * not be explained by any other technical requirement.
+ *
+ * Transmission: To transmit an IrDA frame, the driver must prepare a control
+ * URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue <length of valid data before padding, little endian>
+ * wIndex 0x0000
+ * wLength <length of padded data>
+ * The payload packet must be manually wrapped and escaped (as in stir4200.c),
+ * then padded and obfuscated before being sent. Both padding and obfuscation
+ * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the
+ * designer/programmer of the dongle used his name as a source for the
+ * obfuscation. WTF?!
+ * Apparently the dongle cannot handle payloads larger than 256 bytes. The
+ * driver has to perform fragmentation in order to send anything larger than
+ * this limit.
+ *
+ * Reception: To receive data, the driver must poll the dongle regularly (like
+ * kingsun-sir.c) with control URBs and the following as a setup packet:
+ * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x01
+ * wValue 0x0200
+ * wIndex 0x0000
+ * wLength 0x0800 (size of available buffer)
+ * If there is data to be read, it will be returned as the response payload.
+ * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate
+ * it, the driver must XOR every byte, in sequence, with a value that starts at
+ * 1 and is incremented with each byte processed, and then with 0x55. The value
+ * incremented with each byte processed overflows as an unsigned char. The
+ * resulting bytes form a wrapped SIR frame that is then unwrapped and unescaped
+ * as in stir4200.c The incremented value is NOT reset with each frame, but is
+ * kept across the entire session with the dongle. Also, the dongle inserts an
+ * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which
+ * must be skipped.
+ *
+ * Speed change: To change the speed of the dongle, the driver prepares a
+ * control URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue 0x0200
+ * wIndex 0x0001
+ * wLength 0x0008 (length of the payload)
+ * The payload is a 8-byte record, apparently identical to the one used in
+ * drivers/usb/serial/cypress_m8.c to change speed:
+ * __u32 baudSpeed;
+ * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
+ * unsigned int : 1;
+ * unsigned int stopBits : 1;
+ * unsigned int parityEnable : 1;
+ * unsigned int parityType : 1;
+ * unsigned int : 1;
+ * unsigned int reset : 1;
+ * unsigned char reserved[3]; // set to 0
+ *
+ * For now only SIR speeds have been observed with this dongle. Therefore,
+ * nothing is known on what changes (if any) must be done to frame wrapping /
+ * unwrapping for higher than SIR speeds. This driver assumes no change is
+ * necessary and announces support for all the way to 57600 bps. Although the
+ * package announces support for up to 4MBps, tests with a Sony Ericcson K300
+ * phone show corruption when receiving large frames at 115200 bps, the highest
+ * speed announced by the phone. However, transmission at 115200 bps is OK. Go
+ * figure. Since I don't know whether the phone or the dongle is at fault, max
+ * announced speed is 57600 bps until someone produces a device that can run
+ * at higher speeds with this dongle.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#define KS959_VENDOR_ID 0x07d0
+#define KS959_PRODUCT_ID 0x4959
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+ /* KingSun Co,Ltd IrDA/USB Bridge */
+ { USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+#define KINGSUN_REQ_RECV 0x01
+#define KINGSUN_REQ_SEND 0x09
+
+#define KINGSUN_RCV_FIFO_SIZE 512 /* Max length we can receive */
+#define KINGSUN_SND_FIFO_SIZE 512 /* Max packet we can send */
+#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */
+
+struct ks959_speedparams {
+ __le32 baudrate; /* baud rate, little endian */
+ __u8 flags;
+ __u8 reserved[3];
+} __attribute__ ((packed));
+
+#define KS_DATA_5_BITS 0x00
+#define KS_DATA_6_BITS 0x01
+#define KS_DATA_7_BITS 0x02
+#define KS_DATA_8_BITS 0x03
+
+#define KS_STOP_BITS_1 0x00
+#define KS_STOP_BITS_2 0x08
+
+#define KS_PAR_DISABLE 0x00
+#define KS_PAR_EVEN 0x10
+#define KS_PAR_ODD 0x30
+#define KS_RESET 0x80
+
+struct ks959_cb {
+ struct usb_device *usbdev; /* init: probe_irda */
+ struct net_device *netdev; /* network layer */
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+ struct net_device_stats stats; /* network statistics */
+ struct qos_info qos;
+
+ struct usb_ctrlrequest * tx_setuprequest;
+ struct urb * tx_urb;
+ __u8 * tx_buf_clear;
+ unsigned int tx_buf_clear_used;
+ unsigned int tx_buf_clear_sent;
+ __u8 * tx_buf_xored;
+
+ struct usb_ctrlrequest * rx_setuprequest;
+ struct urb * rx_urb;
+ __u8 * rx_buf;
+ __u8 rx_variable_xormask;
+ iobuff_t rx_unwrap_buff;
+ struct timeval rx_time;
+
+ struct usb_ctrlrequest * speed_setuprequest;
+ struct urb * speed_urb;
+ struct ks959_speedparams speedparams;
+ unsigned int new_speed;
+
+ spinlock_t lock;
+ int receiving;
+};
+
+/* Procedure to perform the obfuscation/padding expected by the dongle
+ *
+ * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit
+ * len_cleartext (IN) Length of the cleartext version of IrDA frame
+ * buf_xoredtext (OUT) Obfuscated version of frame built by proc
+ * len_maxbuf (OUT) Maximum space available at buf_xoredtext
+ *
+ * (return) length of obfuscated frame with padding
+ *
+ * If not enough space (as indicated by len_maxbuf vs. required padding),
+ * zero is returned
+ *
+ * The value of lookup_string is actually a required portion of the algorithm.
+ * Seems the designer of the dongle wanted to state who exactly is responsible
+ * for implementing obfuscation. Send your best (or other) wishes to him ]:-)
+ */
+static unsigned int obfuscate_tx_buffer(
+ const __u8 * buf_cleartext, unsigned int len_cleartext,
+ __u8 * buf_xoredtext, unsigned int len_maxbuf)
+{
+ unsigned int len_xoredtext;
+
+ /* Calculate required length with padding, check for necessary space */
+ len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10;
+ if (len_xoredtext <= len_maxbuf) {
+ static const __u8 lookup_string[] = "wangshuofei19710";
+ __u8 xor_mask;
+
+ /* Unlike the WinXP driver, we *do* clear out the padding */
+ memset(buf_xoredtext, 0, len_xoredtext);
+
+ xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55;
+
+ while (len_cleartext-- > 0) {
+ *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask;
+ }
+ } else {
+ len_xoredtext = 0;
+ }
+ return len_xoredtext;
+}
+
+/* Callback transmission routine */
+static void ks959_speed_irq(struct urb *urb)
+{
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ks959_speed_irq: urb asynchronously failed - %d", urb->status);
+ }
+}
+
+/* Send a control request to change speed of the dongle */
+static int ks959_change_speed(struct ks959_cb * kingsun, unsigned speed)
+{
+ static unsigned int supported_speeds[] = {2400, 9600, 19200, 38400,
+ 57600, 115200, 576000, 1152000, 4000000, 0};
+ int err;
+ unsigned int i;
+
+ if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
+ return -ENOMEM;
+
+ /* Check that requested speed is among the supported ones */
+ for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++);
+ if (supported_speeds[i] == 0) return -EOPNOTSUPP;
+
+ memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams));
+ kingsun->speedparams.baudrate = cpu_to_le32(speed);
+ kingsun->speedparams.flags = KS_DATA_8_BITS;
+
+ /* speed_setuprequest pre-filled in ks959_probe */
+ usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->speed_setuprequest,
+ &(kingsun->speedparams), sizeof(struct ks959_speedparams),
+ ks959_speed_irq, kingsun);
+ kingsun->speed_urb->status = 0;
+ err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
+
+ return err;
+}
+
+/* Submit one fragment of an IrDA frame to the dongle */
+static void ks959_send_irq(struct urb *urb);
+static int ks959_submit_tx_fragment(struct ks959_cb *kingsun)
+{
+ unsigned int padlen;
+ unsigned int wraplen;
+ int ret;
+
+ /* Check whether current plaintext can produce a padded buffer that fits
+ within the range handled by the dongle */
+ wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10;
+ if (wraplen > kingsun->tx_buf_clear_used)
+ wraplen = kingsun->tx_buf_clear_used;
+
+ /* Perform dongle obfuscation. Also remove the portion of the frame that
+ was just obfuscated and will now be sent to the dongle. */
+ padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen,
+ kingsun->tx_buf_xored, KINGSUN_SND_PACKET_SIZE);
+
+ /* Calculate how much data can be transmitted in this urb */
+ kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen);
+ kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen);
+ /* Rest of the fields were filled in ks959_probe */
+ usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->tx_setuprequest,
+ kingsun->tx_buf_xored, padlen,
+ ks959_send_irq, kingsun);
+ kingsun->tx_urb->status = 0;
+ ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
+
+ /* Remember how much data was sent, in order to update at callback */
+ kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
+ return ret;
+}
+
+
+/* Callback transmission routine */
+static void ks959_send_irq(struct urb *urb)
+{
+ struct ks959_cb *kingsun = urb->context;
+ struct net_device *netdev = kingsun->netdev;
+ int ret = 0;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ err("ks959_send_irq: Network not running!");
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ks959_send_irq: urb asynchronously failed - %d", urb->status);
+ return;
+ }
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* Update data remaining to be sent */
+ if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
+ memmove(kingsun->tx_buf_clear,
+ kingsun->tx_buf_clear + kingsun->tx_buf_clear_sent,
+ kingsun->tx_buf_clear_used - kingsun->tx_buf_clear_sent);
+ }
+ kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
+ kingsun->tx_buf_clear_sent = 0;
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* There is more data to be sent */
+ if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+ err("ks959_send_irq: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ }
+ } else {
+ /* All data sent, send next speed && wake network queue */
+ if (kingsun->new_speed != -1 &&
+ cpu_to_le32(kingsun->new_speed) != kingsun->speedparams.baudrate)
+ ks959_change_speed(kingsun, kingsun->new_speed);
+
+ netif_wake_queue(netdev);
+ }
+ }
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ks959_cb *kingsun;
+ unsigned int wraplen;
+ int ret = 0;
+
+ if (skb == NULL || netdev == NULL)
+ return -EINVAL;
+
+ netif_stop_queue(netdev);
+
+ /* the IRDA wrapping routines don't deal with non linear skb */
+ SKB_LINEAR_ASSERT(skb);
+
+ kingsun = netdev_priv(netdev);
+
+ spin_lock(&kingsun->lock);
+ kingsun->new_speed = irda_get_next_speed(skb);
+
+ /* Append data to the end of whatever data remains to be transmitted */
+ wraplen = async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
+ kingsun->tx_buf_clear_used = wraplen;
+
+ if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+ err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ } else {
+ kingsun->stats.tx_packets++;
+ kingsun->stats.tx_bytes += skb->len;
+ }
+
+ dev_kfree_skb(skb);
+ spin_unlock(&kingsun->lock);
+
+ return ret;
+}
+
+/* Receive callback function */
+static void ks959_rcv_irq(struct urb *urb)
+{
+ struct ks959_cb *kingsun = urb->context;
+ int ret;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ kingsun->receiving = 0;
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("kingsun_rcv_irq: urb asynchronously failed - %d", urb->status);
+ kingsun->receiving = 0;
+ return;
+ }
+
+ if (urb->actual_length > 0) {
+ __u8 *bytes = urb->transfer_buffer;
+ unsigned int i;
+
+ for (i = 0; i < urb->actual_length; i++) {
+ /* De-obfuscation implemented here: variable portion of
+ xormask is incremented, and then used with the encoded
+ byte for the XOR. The result of the operation is used
+ to unwrap the SIR frame. */
+ kingsun->rx_variable_xormask++;
+ bytes[i] = bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u;
+
+ /* rx_variable_xormask doubles as an index counter so we
+ can skip the byte at 0xff (wrapped around to 0).
+ */
+ if (kingsun->rx_variable_xormask != 0) {
+ async_unwrap_char(kingsun->netdev, &kingsun->stats,
+ &kingsun->rx_unwrap_buff, bytes[i]);
+ }
+ }
+ kingsun->netdev->last_rx = jiffies;
+ do_gettimeofday(&kingsun->rx_time);
+ kingsun->receiving =
+ (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
+ }
+
+ /* This urb has already been filled in kingsun_net_open. Setup
+ packet must be re-filled, but it is assumed that urb keeps the
+ pointer to the initial setup packet, as well as the payload buffer.
+ Setup packet is already pre-filled at ks959_probe.
+ */
+ urb->status = 0;
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ * Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int ks959_net_open(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ int err = -ENOMEM;
+ char hwname[16];
+
+ /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+ kingsun->receiving = 0;
+
+ /* Initialize for SIR to copy data directly into skb. */
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
+ kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+ if (!kingsun->rx_unwrap_buff.skb)
+ goto free_mem;
+
+ skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
+ kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
+ do_gettimeofday(&kingsun->rx_time);
+
+ kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->rx_urb)
+ goto free_mem;
+
+ kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->tx_urb)
+ goto free_mem;
+
+ kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->speed_urb)
+ goto free_mem;
+
+ /* Initialize speed for dongle */
+ kingsun->new_speed = 9600;
+ err = ks959_change_speed(kingsun, 9600);
+ if (err < 0) goto free_mem;
+
+ /*
+ * Now that everything should be initialized properly,
+ * Open new IrLAP layer instance to take care of us...
+ */
+ sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+ kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+ if (!kingsun->irlap) {
+ err("ks959-sir: irlap_open failed");
+ goto free_mem;
+ }
+
+ /* Start reception. Setup request already pre-filled in ks959_probe*/
+ usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev,
+ usb_rcvctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->rx_setuprequest,
+ kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE,
+ ks959_rcv_irq, kingsun);
+ kingsun->rx_urb->status = 0;
+ err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ if (err) {
+ err("ks959-sir: first urb-submit failed: %d", err);
+ goto close_irlap;
+ }
+
+ netif_start_queue(netdev);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - urbs allocated and ready to fill
+ - max rx packet known (in max_rx)
+ - unwrap state machine initialized, in state outside of any frame
+ - receive request in progress
+ - IrLAP layer started, about to hand over packets to send
+ */
+
+ return 0;
+
+close_irlap:
+ irlap_close(kingsun->irlap);
+free_mem:
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ if (kingsun->rx_unwrap_buff.skb) {
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ }
+ return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ * Network device is taken down. Usually this is done by
+ * "ifconfig irda0 down"
+ */
+static int ks959_net_close(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+
+ /* Stop transmit processing */
+ netif_stop_queue(netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->receiving = 0;
+
+ /* Stop and remove instance of IrLAP */
+ if (kingsun->irlap)
+ irlap_close(kingsun->irlap);
+
+ kingsun->irlap = NULL;
+
+ return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *) rq;
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the device is still there */
+ if (netif_device_present(kingsun->netdev))
+ return ks959_change_speed(kingsun, irq->ifr_baudrate);
+ break;
+
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the IrDA stack is still there */
+ if (netif_running(kingsun->netdev))
+ irda_device_set_media_busy(kingsun->netdev, TRUE);
+ break;
+
+ case SIOCGRECEIVING:
+ /* Only approximately true */
+ irq->ifr_receiving = kingsun->receiving;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int ks959_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct ks959_cb *kingsun = NULL;
+ struct net_device *net = NULL;
+ int ret = -ENOMEM;
+
+
+ /* Allocate network device container. */
+ net = alloc_irdadev(sizeof(*kingsun));
+ if(!net)
+ goto err_out1;
+
+ SET_MODULE_OWNER(net);
+ SET_NETDEV_DEV(net, &intf->dev);
+ kingsun = netdev_priv(net);
+ kingsun->netdev = net;
+ kingsun->usbdev = dev;
+ kingsun->irlap = NULL;
+ kingsun->tx_setuprequest = NULL;
+ kingsun->tx_urb = NULL;
+ kingsun->tx_buf_clear = NULL;
+ kingsun->tx_buf_xored = NULL;
+ kingsun->tx_buf_clear_used = 0;
+ kingsun->tx_buf_clear_sent = 0;
+
+ kingsun->rx_setuprequest = NULL;
+ kingsun->rx_urb = NULL;
+ kingsun->rx_buf = NULL;
+ kingsun->rx_variable_xormask = 0;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->receiving = 0;
+ spin_lock_init(&kingsun->lock);
+
+ kingsun->speed_setuprequest = NULL;
+ kingsun->speed_urb = NULL;
+ kingsun->speedparams.baudrate = 0;
+
+ /* Allocate input buffer */
+ kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->rx_buf)
+ goto free_mem;
+
+ /* Allocate input setup packet */
+ kingsun->rx_setuprequest = kmalloc(
+ sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->rx_setuprequest)
+ goto free_mem;
+ kingsun->rx_setuprequest->bRequestType =
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV;
+ kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->rx_setuprequest->wIndex = 0;
+ kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE);
+
+ /* Allocate output buffer */
+ kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_clear)
+ goto free_mem;
+ kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_xored)
+ goto free_mem;
+
+ /* Allocate and initialize output setup packet */
+ kingsun->tx_setuprequest = kmalloc(
+ sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->tx_setuprequest)
+ goto free_mem;
+ kingsun->tx_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->tx_setuprequest->wValue = 0;
+ kingsun->tx_setuprequest->wIndex = 0;
+ kingsun->tx_setuprequest->wLength = 0;
+
+ /* Allocate and initialize speed setup packet */
+ kingsun->speed_setuprequest = kmalloc(
+ sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->speed_setuprequest)
+ goto free_mem;
+ kingsun->speed_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
+ kingsun->speed_setuprequest->wLength =
+ cpu_to_le16(sizeof(struct ks959_speedparams));
+
+ printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, "
+ "Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&kingsun->qos);
+
+ /* Baud rates known to be supported. Please uncomment if devices (other
+ than a SonyEriccson K300 phone) can be shown to support higher speeds
+ with this dongle.
+ */
+ kingsun->qos.baud_rate.bits =
+ IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600;
+ kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+ irda_qos_bits_to_value(&kingsun->qos);
+
+ /* Override the network functions we need to use */
+ net->hard_start_xmit = ks959_hard_xmit;
+ net->open = ks959_net_open;
+ net->stop = ks959_net_close;
+ net->get_stats = ks959_net_get_stats;
+ net->do_ioctl = ks959_net_ioctl;
+
+ ret = register_netdev(net);
+ if (ret != 0)
+ goto free_mem;
+
+ info("IrDA: Registered KingSun KS-959 device %s", net->name);
+
+ usb_set_intfdata(intf, kingsun);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - setup requests pre-filled
+ - urbs not allocated, set to NULL
+ - max rx packet known (is KINGSUN_FIFO_SIZE)
+ - unwrap state machine (partially) initialized, but skb == NULL
+ */
+
+ return 0;
+
+free_mem:
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_setuprequest);
+ kfree(kingsun->tx_buf_xored);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_setuprequest);
+ kfree(kingsun->rx_buf);
+ free_netdev(net);
+err_out1:
+ return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void ks959_disconnect(struct usb_interface *intf)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ if (!kingsun)
+ return;
+
+ unregister_netdev(kingsun->netdev);
+
+ /* Mop up receive && transmit urb's */
+ if (kingsun->speed_urb != NULL) {
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ }
+ if (kingsun->tx_urb != NULL) {
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ }
+ if (kingsun->rx_urb != NULL) {
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ }
+
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_setuprequest);
+ kfree(kingsun->tx_buf_xored);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_setuprequest);
+ kfree(kingsun->rx_buf);
+ free_netdev(kingsun->netdev);
+
+ usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int ks959_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ netif_device_detach(kingsun->netdev);
+ if (kingsun->speed_urb != NULL) usb_kill_urb(kingsun->speed_urb);
+ if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
+ if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
+ return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int ks959_resume(struct usb_interface *intf)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ if (kingsun->rx_urb != NULL) {
+ /* Setup request already filled in ks959_probe */
+ usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ }
+ netif_device_attach(kingsun->netdev);
+
+ return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+ .name = "ks959-sir",
+ .probe = ks959_probe,
+ .disconnect = ks959_disconnect,
+ .id_table = dongles,
+#ifdef CONFIG_PM
+ .suspend = ks959_suspend,
+ .resume = ks959_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init ks959_init(void)
+{
+ return usb_register(&irda_driver);
+}
+module_init(ks959_init);
+
+/*
+ * Module removal
+ */
+static void __exit ks959_cleanup(void)
+{
+ /* Deregister the driver and remove all pending instances */
+ usb_deregister(&irda_driver);
+}
+module_exit(ks959_cleanup);
+
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959");
+MODULE_LICENSE("GPL");
+
--
1.5.2.3
^ permalink raw reply related
* RE: [PATCH] NET: Fix sch_prio to detect the root qdisc loading
From: Waskiewicz Jr, Peter P @ 2007-07-22 18:56 UTC (permalink / raw)
To: Patrick McHardy; +Cc: davem, netdev, jeff
In-Reply-To: <46A386A0.4050406@trash.net>
> As explained in my last mail, sch->parent is an integer. And
> it is set when grafting the qdisc, not on initilization, so
> it is always 0 here when coming from prio_init.
>
> This untested patch should make sure its always set correctly.
Yes, I'm using NULL and 0 interchangeably here, since in the sch_api
code, qdisc_graft(), sch->parent is referenced using NULL and not 0. I
know it's a u32, and the value is getting set to the proper handle when
the qdisc is not the root qdisc. When it's the root qdisc, it's left to
be 0.
This patch was tested as well, but looking at the history now, I didn't
set bands correctly, so that's why the multiqueue case failed. My
mistake, and I'll keep working on this.
Sorry for the extra noise,
-PJ
^ permalink raw reply
* bug in tcp/ip stack
From: john @ 2007-07-22 18:24 UTC (permalink / raw)
To: netdev
I tracked down something that appears to be a small bug in networking code.
The way in witch i can reproduce it a complex one but it works 100%, so
here comes the details:
I noticed strange packets on my fw coming from mail server with RST/ACK
flags set coming from source port with no one listening on it and no
connection attempts made to them from outside.
There are few messages on forums describing same problem and calling
them alien ACK/RST packets.
Postfix mail server gives this behavior if for some reason client resets
connection but some packets from client arrives after the RST, the serer
box responds with RST and then with RST/ACK (with the wrong source port
number).
Here is packet dump
1 0.000000 10.0.0.254 10.0.0.68 TCP 50000 > smtp [SYN]
Seq=0 Len=0
2 0.001036 10.0.0.68 10.0.0.254 TCP smtp > 50000 [SYN,
ACK] Seq=0 Ack=1 Win=5840 Len=0 MSS=1460
3 0.001096 10.0.0.254 10.0.0.68 TCP 50000 > smtp [ACK]
Seq=1 Ack=1 Win=1500 Len=0
4 0.001125 10.0.0.254 10.0.0.68 SMTP Command: EHLO localhost
5 0.001150 10.0.0.254 10.0.0.68 TCP 50000 > smtp [RST]
Seq=17 Len=0
6 0.001175 10.0.0.254 10.0.0.68 TCP 50000 > smtp [FIN,
ACK] Seq=17 Ack=1 Win=1500 Len=0
7 0.001251 10.0.0.68 10.0.0.254 TCP smtp > 50000 [ACK]
Seq=1 Ack=17 Win=5840 Len=0
8 0.001284 10.0.0.68 10.0.0.254 TCP smtp > 50000 [RST]
Seq=1 Len=0
!!!9 0.218427 10.0.0.68 10.0.0.254 TCP 32768 > 50000
[RST, ACK] Seq=0 Ack=0 Win=5840 Len=0
It is not the postfix bug, it is present in current 2.6.x and 2.4.x
kernel versions but not in the 2.2.x tree, so after investigation i
found it was introduced in 2.4.0-test9-pre3 back in year 2000 and
survived for 7 years WOW :)
Whole 2.4.0-test9-pre3 diff is pretty big, but i managed to find lines
responsible for this,
they are located in include/net/tcp.h
in function tcp_enter_cwr
if (sk->prev && !(sk->userlocks&SOCK_BINDPORT_LOCK))
tcp_put_port(sk);
It is not a big problem but under some setups the fw's conntrack table
can get filled pretty quickly, because wrong port number changes every
time.
Can, you please check this out?
Evalds
^ permalink raw reply
* netlink messages on 'ip l s down' event
From: Milan Kocian @ 2007-07-22 17:30 UTC (permalink / raw)
To: netdev
hello,
I noticed that ipv4 subsystem sends RTM_NEWLINK message with new flags
on 'ip l s down' event, but ipv6 subsystem sends RTM_DELLINK message. Is
it inconsistency or feature? If it is inconsistency, which approach will
be used in future? (tested kernels 2.6.20,21,22)
Thanks for reply.
regards,
--
Milan Kocian <milon@wq.cz>
^ permalink raw reply
* Re: NFS mount gives ENETDOWN in -git15
From: Trond Myklebust @ 2007-07-22 17:55 UTC (permalink / raw)
To: Andi Kleen; +Cc: netdev, linux-kernel
In-Reply-To: <200707211531.17750.ak@suse.de>
[-- Attachment #1: Type: text/plain, Size: 382 bytes --]
On Sat, 2007-07-21 at 15:31 +0200, Andi Kleen wrote:
> I tried to mount another nfs mount on a system running with nfsroot.
> But I get
>
> # mount basil:/home /basil/home/
> mount: Network is down
>
> The network is not down of course, the system is happily running with nfs root from that
> server. Userland is older SUSE 10.0
Does Al's patch help in any way?
Cheers
Trond
[-- Attachment #2: Attached message - [PATCH] fix broken handling of port=... in NFS option parsing --]
[-- Type: message/rfc822, Size: 2417 bytes --]
From: Al Viro <viro@ftp.linux.org.uk>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Chuck Lever <chuck.lever@oracle.com>, Trond Myklebust <Trond.Myklebust@netapp.com>, linux-kernel@vger.kernel.org
Subject: [PATCH] fix broken handling of port=... in NFS option parsing
Date: Sun, 22 Jul 2007 10:59:06 +0100
Message-ID: <20070722095906.GX21668@ftp.linux.org.uk>
Obviously broken on little-endian; fortunately, the option is
not frequently used...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b34b7a7..b2a851c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -732,7 +732,7 @@ static int nfs_parse_mount_options(char *raw,
return 0;
if (option < 0 || option > 65535)
return 0;
- mnt->nfs_server.address.sin_port = htonl(option);
+ mnt->nfs_server.address.sin_port = htons(option);
break;
case Opt_rsize:
if (match_int(args, &mnt->rsize))
^ permalink raw reply related
* Re: [PATCH 06/12 -Rev2] rtnetlink changes.
From: Patrick McHardy @ 2007-07-22 17:10 UTC (permalink / raw)
To: Krishna Kumar
Cc: davem, rdreier, johnpol, Robert.Olsson, peter.p.waskiewicz.jr,
herbert, gaagaan, kumarkr, xma, rick.jones2, mcarlson, netdev,
jagana, general, mchan, tgraf, jeff, hadi, sri
In-Reply-To: <20070722090553.7787.28728.sendpatchset@K50wks273871wss.in.ibm.com>
Krishna Kumar wrote:
> diff -ruNp org/include/linux/if_link.h rev2/include/linux/if_link.h
> --- org/include/linux/if_link.h 2007-07-20 16:33:35.000000000 +0530
> +++ rev2/include/linux/if_link.h 2007-07-20 16:35:08.000000000 +0530
> @@ -78,6 +78,8 @@ enum
> IFLA_LINKMODE,
> IFLA_LINKINFO,
> #define IFLA_LINKINFO IFLA_LINKINFO
> + IFLA_TXBTHSKB, /* Driver support for Batch'd skbs */
> +#define IFLA_TXBTHSKB IFLA_TXBTHSKB
Ughh what a name :) I prefer pronouncable names since they are
much easier to remember and don't need comments explaining
what they mean.
But I actually think offering just an ethtool interface would
be better, at least for now.
^ permalink raw reply
* [ofa-general] Re: [PATCH 02/12 -Rev2] Changes to netdevice.h
From: Patrick McHardy @ 2007-07-22 17:06 UTC (permalink / raw)
To: Krishna Kumar
Cc: johnpol, Robert.Olsson, herbert, gaagaan, kumarkr, rdreier,
peter.p.waskiewicz.jr, mcarlson, jagana, general, netdev, tgraf,
jeff, sri, hadi, davem, mchan
In-Reply-To: <20070722090516.7787.79695.sendpatchset@K50wks273871wss.in.ibm.com>
Krishna Kumar wrote:
> @@ -472,6 +474,9 @@ struct net_device
> void *priv; /* pointer to private data */
> int (*hard_start_xmit) (struct sk_buff *skb,
> struct net_device *dev);
> + int (*hard_start_xmit_batch) (struct net_device
> + *dev);
> +
Os this function really needed? Can't you just call hard_start_xmit with
a NULL skb and have the driver use dev->blist?
> /* These may be needed for future network-power-down code. */
> unsigned long trans_start; /* Time (in jiffies) of last Tx */
>
> @@ -582,6 +587,8 @@ struct net_device
> #define NETDEV_ALIGN 32
> #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1)
>
> +#define BATCHING_ON(dev) ((dev->features & NETIF_F_BATCH_ON) != 0)
> +
> static inline void *netdev_priv(const struct net_device *dev)
> {
> return dev->priv;
> @@ -832,6 +839,8 @@ extern int dev_set_mac_address(struct n
> struct sockaddr *);
> extern int dev_hard_start_xmit(struct sk_buff *skb,
> struct net_device *dev);
> +extern int dev_add_skb_to_blist(struct sk_buff *skb,
> + struct net_device *dev);
Again, function signatures should be introduced in the same patch
that contains the function. Splitting by file doesn't make sense.
^ permalink raw reply
* Re: [ofa-general] Re: [PATCH 05/10] sch_generic.c changes.
From: Patrick McHardy @ 2007-07-22 17:03 UTC (permalink / raw)
To: Krishna Kumar2
Cc: jagana, johnpol, herbert, gaagaan, Robert.Olsson, kumarkr,
rdreier, peter.p.waskiewicz.jr, hadi, mcarlson, jeff, general,
mchan, tgraf, netdev, davem, sri
In-Reply-To: <OF206CB1B7.31D1C39B-ON6525731F.00254E4C-6525731F.00261F1A@in.ibm.com>
Krishna Kumar2 wrote:
> Patrick McHardy <kaber@trash.net> wrote on 07/20/2007 11:46:36 PM:
>
>>The check for tx_queue_len is wrong though,
>>its only a default which can be overriden and some qdiscs don't
>>care for it at all.
>
>
> I think it should not matter whether qdiscs use this or not, or even if it
> is modified (unless it is made zero in which case this breaks). The
> intention behind this check is to make sure that not more than tx_queue_len
> skbs are in all queues put together (q->qdisc + dev->skb_blist), otherwise
> the blist can become too large and breaks the idea of tx_queue_len. Is that
> a good justification ?
Its a good justification, but on second thought the entire idea of
a single queue after qdiscs that is refilled independantly of
transmissions times etc. make be worry a bit. By changing the
timing you're effectively changing the qdiscs behaviour, at least
in some cases. SFQ is a good example, but I believe it affects most
work-conserving qdiscs. Think of this situation:
100 packets of flow 1 arrive
50 packets of flow 1 are sent
100 packets for flow 2 arrive
remaining packets are sent
On the wire you'll first see 50 packets of flow 1, than 100 packets
alternate of flow 1 and 2, then 50 packets flow 2.
With your additional queue all packets of flow 1 are pulled out of
the qdisc immediately and put in the fifo. When the 100 packets of
the second flow arrive they will also get pulled out immediately
and are put in the fifo behind the remaining 50 packets of flow 1.
So what you get on the wire is:
100 packets of flow 1
100 packets of flow 1
So SFQ is without any effect. This is not completely avoidable of
course, but you can and should limit the damage by only pulling
out as much packets as the driver can take and have the driver
stop the queue afterwards.
^ permalink raw reply
* [PATCH] Fix irlan_eth.c - unused variable 'in_dev' warning
From: Gabriel C @ 2007-07-22 16:58 UTC (permalink / raw)
To: Linux Kernel Mailing List; +Cc: Dag Brattli, netdev
Hi,
I got this warning on current git:
...
net/irda/irlan/irlan_eth.c: In function 'irlan_eth_send_gratuitous_arp':
net/irda/irlan/irlan_eth.c:301: warning: unused variable 'in_dev'
...
This is because CONFIG_INET is not set in my config.
Signed-off-by: Gabriel Craciunescu <nix.or.die@googlemail.com>
---
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index c421521..ea0b21a 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -298,6 +298,7 @@ void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
*/
void irlan_eth_send_gratuitous_arp(struct net_device *dev)
{
+#ifdef CONFIG_INET
struct in_device *in_dev;
/*
@@ -305,7 +306,6 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
* is useful if we have changed access points on the same
* subnet.
*/
-#ifdef CONFIG_INET
IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
^ permalink raw reply related
* Re: [PATCH] NET: Fix sch_prio to detect the root qdisc loading
From: Patrick McHardy @ 2007-07-22 16:32 UTC (permalink / raw)
To: PJ Waskiewicz; +Cc: davem, netdev, jeff
In-Reply-To: <20070721191459.2146.48448.stgit@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 1408 bytes --]
PJ Waskiewicz wrote:
> The sch->parent handle will be NULL for the scheduler that is TC_H_ROOT.
> Change this check in prio_tune() so that only the root qdisc can be
> multiqueue-enabled.
>
> Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
> ---
>
> net/sched/sch_prio.c | 6 ++++--
> 1 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
> index 2d8c084..271051e 100644
> --- a/net/sched/sch_prio.c
> +++ b/net/sched/sch_prio.c
> @@ -239,11 +239,13 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
> /* If we're multiqueue, make sure the number of incoming bands
> * matches the number of queues on the device we're associating with.
> * If the number of bands requested is zero, then set q->bands to
> - * dev->egress_subqueue_count.
> + * dev->egress_subqueue_count. Also, the root qdisc must be the
> + * only one that is enabled for multiqueue, since it's the only one
> + * that interacts with the underlying device.
> */
> q->mq = RTA_GET_FLAG(tb[TCA_PRIO_MQ - 1]);
> if (q->mq) {
> - if (sch->handle != TC_H_ROOT)
> + if (sch->parent != NULL)
As explained in my last mail, sch->parent is an integer. And it is
set when grafting the qdisc, not on initilization, so it is always
0 here when coming from prio_init.
This untested patch should make sure its always set correctly.
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 1835 bytes --]
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 13c09bc..0975547 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -380,6 +380,10 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
return;
while ((parentid = sch->parent)) {
sch = qdisc_lookup(sch->dev, TC_H_MAJ(parentid));
+ if (sch == NULL) {
+ WARN_ON(parentid != TC_H_ROOT);
+ return;
+ }
cops = sch->ops->cl_ops;
if (cops->qlen_notify) {
cl = cops->get(sch, parentid);
@@ -420,8 +424,6 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
unsigned long cl = cops->get(parent, classid);
if (cl) {
err = cops->graft(parent, cl, new, old);
- if (new)
- new->parent = classid;
cops->put(parent, cl);
}
}
@@ -436,7 +438,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
*/
static struct Qdisc *
-qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
+qdisc_create(struct net_device *dev, u32 parent, u32 handle,
+ struct rtattr **tca, int *errp)
{
int err;
struct rtattr *kind = tca[TCA_KIND-1];
@@ -482,6 +485,8 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
goto err_out2;
}
+ new->parent = parent;
+
if (handle == TC_H_INGRESS) {
sch->flags |= TCQ_F_INGRESS;
sch->stats_lock = &dev->ingress_lock;
@@ -758,9 +763,11 @@ create_n_graft:
if (!(n->nlmsg_flags&NLM_F_CREATE))
return -ENOENT;
if (clid == TC_H_INGRESS)
- q = qdisc_create(dev, tcm->tcm_parent, tca, &err);
+ q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_parent,
+ tca, &err);
else
- q = qdisc_create(dev, tcm->tcm_handle, tca, &err);
+ q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_handle,
+ tca, &err);
if (q == NULL) {
if (err == -EAGAIN)
goto replay;
^ permalink raw reply related
* Re: Question: how to detect if a qdisc is root or not?
From: Patrick McHardy @ 2007-07-22 16:24 UTC (permalink / raw)
To: Waskiewicz Jr, Peter P; +Cc: netdev
In-Reply-To: <D5C1322C3E673F459512FB59E0DDC3290344621B@orsmsx414.amr.corp.intel.com>
Waskiewicz Jr, Peter P wrote:
>>I dont think I understand. Whats the problem with setting
>>sch->parent on initialization instead on grafting as I did in
>>my example patch?
>>Please explain the problems arrising on unload in detail.
>
>
> sch->parent is getting set on initialization, and for the root and
> ingress qdiscs, it's left at zero. If I change that value, when the
> root qdisc is unloaded and pfifo_fast is put back into place, the
> qdisc_destroy() walks the tree and attempts to free memory from the
> handle pointed at by sch->parent.
First of all, qdisc destruction never propagates up, only down
the tree. Secondly neither qdisc_destroy nor pfifo nor prio
even look at sch->parent. So this is completely wrong, the only
place where sch->parent is used for walking through the tree
is qdisc_tree_decrease_qlen.
> It stops when sch->parent is NULL,
Where are you getting this? sch->parent is an *integer*.
> so
> sch->parent is actually being set as intended. The only thing that
> confused me is that nowhere in the qdisc is TC_H_ROOT included
> explicitly, rather, the root qdisc is where sch->parent is NULL.
>
> So I misunderstood what was actually wrong. The qdisc code is ok as-is,
> it's just that the top-level qdisc (root and ingress) have a sch->parent
> of NULL, which is being set correctly today.
>
> Hope that clarifies.
Not at all :)
^ permalink raw reply
* Re: checksum of lsrr
From: Ken-ichirou MATSUZAWA @ 2007-07-22 15:31 UTC (permalink / raw)
To: netdev
In-Reply-To: <20070704.222824.74749937.chamas@h4.dion.ne.jp>
Hello,
From: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
Subject: checksum of lsrr
Date: Wed, 04 Jul 2007 22:28:24 +0900 (JST)
> if we change destination address, we need recompute not only ip
> checksum but also tcp's, don't we?
I was ashamed of myself for much confused. My simple story is:
rt1 ---- rt2 ---- mybox
rt1 is far from rt2 and when I changed bandwith between rt1 and rt2,
I want to confirm if it was changed correctly. A idea occured to me
is using lsrr. Then I tried with nc but it was not worked. To accept
packet from rt2 to mybox which src and dst address are mybox, I
changed:
--- net/ipv4/fib_frontend.c.orig 2007-07-23 00:01:17.000000000 +0900
+++ net/ipv4/fib_frontend.c 2007-07-23 00:03:11.000000000 +0900
@@ -206,7 +206,7 @@
if (fib_lookup(&fl, &res))
goto last_resort;
- if (res.type != RTN_UNICAST)
+ if (res.type != RTN_UNICAST && likely(res.type != RTN_LOCAL))
goto e_inval_res;
*spec_dst = FIB_RES_PREFSRC(res);
fib_combine_itag(itag, &res);
Would you tell me is this acceptable? I'm afraid of security issue.
thanks,
^ permalink raw reply
* [ofa-general] Re: [PATCH 00/10] Implement batching skb API
From: jamal @ 2007-07-22 12:51 UTC (permalink / raw)
To: Krishna Kumar2
Cc: jagana, johnpol, gaagaan, jeff, Robert.Olsson, kumarkr, rdreier,
peter.p.waskiewicz.jr, mcarlson, kaber, netdev, general, mchan,
tgraf, sri, davem, herbert
In-Reply-To: <OF0F9581FE.472D94A6-ON65257320.001FC787-65257320.00238386@in.ibm.com>
KK,
On Sun, 2007-22-07 at 11:57 +0530, Krishna Kumar2 wrote:
> Batching need not be useful for every hardware.
My concern is there is no consistency in results. I see improvements on
something which you say dont. You see improvement in something that
Evgeniy doesnt etc.
There are many knobs and we need in the minimal to find out how those
play.
> I don't quite agree with that approach, eg, if the blist is empty and the
> driver tells there is space for one packet, you will add one packet and
> the driver sends it out and the device is stopped (with potentially lot of
> skbs on dev->q). Then no packets are added till the queue is enabled, at
> which time a flood of skbs will be processed increasing latency and holding
> lock for a single longer duration. My approach will mitigate holding lock
> for longer times and instead send skbs to the device as long as we are
> within the limits.
Just as a side note _I do have this feature_ in the pktgen piece.
Infact, You can tell pktgen what that bound is as opposed to the hard
coding(look at the pktgen "batchl" parameter). I have not found it to be
useful experimentally; actually, i should say i could not "zone" on a
useful value by experimenting and it was better to turn it off.
I never tried adding it to the qdisc path - but this is something i
could try and as i said it may prove useful.
> Since E1000 doesn't seem to use the TX lock on RX (atleast I couldn't find
> it),
> I feel having prep will not help as no other cpu can execute the queue/xmit
> code anyway (E1000 is also a LLTX driver).
My experiments show it is useful (in a very visible way using pktgen)
for e1000 to have the prep() interface.
> Other driver that hold tx lock could get improvement however.
So you do see the value then with non LLTX drivers, right? ;->
The value is also there in LLTX drivers even if in just formating a skb
ready for transmit. If this is not clear i could do a much longer
writeup on my thought evolution towards adding prep().
> I wonder if you tried enabling/disabling 'prep' on E1000 to see how the
> performance is affected.
Absolutely. And regardless of whether its beneficial or not for e1000,
theres clear benefit in the tg3 for example.
> If it helps, I guess you could send me a patch to
> add that and I can also test it to see what the effect is. I didn't add it
> since IPoIB wouldn't be able to exploit it (unless someone is kind enough
> to show me how to).
Such core code should not just be focussed on IPOIB.
> I think the code I have is ready and stable,
I am not sure how to intepret that - are you saying all-is-good and we
should just push your code in? It sounds disingenuous but i may have
misread you.
cheers,
jamal
^ permalink raw reply
* Re: tg3 issues
From: patric @ 2007-07-22 11:43 UTC (permalink / raw)
To: netdev
In-Reply-To: <46A113BA.7050805@imperialnet.org>
patric wrote:
> Hi,
>
> Think i got something working for me at least, and the fix is quite
> minimal and only downside that i could see from it was that you might
> get a small delay when bringing up the interface, but that's probably
> better than getting a non-functional interface that reports that it's up.
>
> The fix seems to be quite simple with just a random sleep at the end
> of "tg3_setup_fiber_by_hand():"
>
> tw32_f(MAC_MODE, tp->mac_mode);
> udelay(40);
> }
>
> out:
> udelay( net_random() % 400 );
> return current_link_up;
> }
>
> Not sure that this is a good fix or if it might break on other
> systems, but maybe you could have a quick look at that?
>
> Regards,
> Patric
>
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Last update on this.
"udelay( 100 + net_random % 300 )" seems to work much better and i have
not had a single problem getting the link up within 10 seconds of a cold
or warm-boot, and most often the link comes up directly without any sort
of delay instead like before when it could hang for 30 seconds before
getting a link, if you even got a link.
/Patric
^ permalink raw reply
* [RTNETLINK]: Fix warning if !CONFIG_KMOD
From: Thomas Graf @ 2007-07-22 10:37 UTC (permalink / raw)
To: davem; +Cc: netdev
replay label is unused otherwise.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Index: net-2.6/net/core/rtnetlink.c
===================================================================
--- net-2.6.orig/net/core/rtnetlink.c 2007-07-22 11:41:46.000000000 +0200
+++ net-2.6/net/core/rtnetlink.c 2007-07-22 12:04:27.000000000 +0200
@@ -952,7 +952,9 @@ static int rtnl_newlink(struct sk_buff *
struct nlattr *linkinfo[IFLA_INFO_MAX+1];
int err;
+#ifdef CONFIG_KMOD
replay:
+#endif
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
if (err < 0)
return err;
^ permalink raw reply
* [NEIGH]: Netlink notifications
From: Thomas Graf @ 2007-07-22 10:35 UTC (permalink / raw)
To: davem; +Cc: netdev
Currently neighbour event notifications are limited to update
notifications and only sent if the ARP daemon is enabled. This
patch extends the existing notification code by also reporting
neighbours being removed due to gc or administratively and
removes the dependency on the ARP daemon. This allows to keep
track of neighbour states without periodically fetching the
complete neighbour table.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Index: net-2.6/net/core/neighbour.c
===================================================================
--- net-2.6.orig/net/core/neighbour.c 2007-07-22 11:42:02.000000000 +0200
+++ net-2.6/net/core/neighbour.c 2007-07-22 11:49:15.000000000 +0200
@@ -54,9 +54,8 @@
#define PNEIGH_HASHMASK 0xF
static void neigh_timer_handler(unsigned long arg);
-#ifdef CONFIG_ARPD
-static void neigh_app_notify(struct neighbour *n);
-#endif
+static void __neigh_notify(struct neighbour *n, int type, int flags);
+static void neigh_update_notify(struct neighbour *neigh);
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
@@ -109,6 +108,7 @@ static void neigh_cleanup_and_release(st
if (neigh->parms->neigh_cleanup)
neigh->parms->neigh_cleanup(neigh);
+ __neigh_notify(neigh, RTM_DELNEIGH, 0);
neigh_release(neigh);
}
@@ -829,13 +829,10 @@ static void neigh_timer_handler(unsigned
out:
write_unlock(&neigh->lock);
}
+
if (notify)
- call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
+ neigh_update_notify(neigh);
-#ifdef CONFIG_ARPD
- if (notify && neigh->parms->app_probes)
- neigh_app_notify(neigh);
-#endif
neigh_release(neigh);
}
@@ -1064,11 +1061,8 @@ out:
write_unlock_bh(&neigh->lock);
if (notify)
- call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
-#ifdef CONFIG_ARPD
- if (notify && neigh->parms->app_probes)
- neigh_app_notify(neigh);
-#endif
+ neigh_update_notify(neigh);
+
return err;
}
@@ -2001,6 +1995,11 @@ nla_put_failure:
return -EMSGSIZE;
}
+static void neigh_update_notify(struct neighbour *neigh)
+{
+ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
+ __neigh_notify(neigh, RTM_NEWNEIGH, 0);
+}
static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
struct netlink_callback *cb)
@@ -2420,7 +2419,6 @@ static const struct file_operations neig
#endif /* CONFIG_PROC_FS */
-#ifdef CONFIG_ARPD
static inline size_t neigh_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ndmsg))
@@ -2452,16 +2450,11 @@ errout:
rtnl_set_sk_err(RTNLGRP_NEIGH, err);
}
+#ifdef CONFIG_ARPD
void neigh_app_ns(struct neighbour *n)
{
__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
}
-
-static void neigh_app_notify(struct neighbour *n)
-{
- __neigh_notify(n, RTM_NEWNEIGH, 0);
-}
-
#endif /* CONFIG_ARPD */
#ifdef CONFIG_SYSCTL
^ permalink raw reply
* [NEIGH]: Combine neighbour cleanup and release
From: Thomas Graf @ 2007-07-22 10:35 UTC (permalink / raw)
To: davem; +Cc: netdev
Introduces neigh_cleanup_and_release() to be used after a
neighbour has been removed from its neighbour table. Serves
as preparation to add event notifications.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Index: net-2.6/net/core/neighbour.c
===================================================================
--- net-2.6.orig/net/core/neighbour.c 2007-07-22 11:41:46.000000000 +0200
+++ net-2.6/net/core/neighbour.c 2007-07-22 11:42:02.000000000 +0200
@@ -104,6 +104,14 @@ static int neigh_blackhole(struct sk_buf
return -ENETDOWN;
}
+static void neigh_cleanup_and_release(struct neighbour *neigh)
+{
+ if (neigh->parms->neigh_cleanup)
+ neigh->parms->neigh_cleanup(neigh);
+
+ neigh_release(neigh);
+}
+
/*
* It is random distribution in the interval (1/2)*base...(3/2)*base.
* It corresponds to default IPv6 settings and is not overridable,
@@ -140,9 +148,7 @@ static int neigh_forced_gc(struct neigh_
n->dead = 1;
shrunk = 1;
write_unlock(&n->lock);
- if (n->parms->neigh_cleanup)
- n->parms->neigh_cleanup(n);
- neigh_release(n);
+ neigh_cleanup_and_release(n);
continue;
}
write_unlock(&n->lock);
@@ -213,9 +219,7 @@ static void neigh_flush_dev(struct neigh
NEIGH_PRINTK2("neigh %p is stray.\n", n);
}
write_unlock(&n->lock);
- if (n->parms->neigh_cleanup)
- n->parms->neigh_cleanup(n);
- neigh_release(n);
+ neigh_cleanup_and_release(n);
}
}
}
@@ -676,9 +680,7 @@ static void neigh_periodic_timer(unsigne
*np = n->next;
n->dead = 1;
write_unlock(&n->lock);
- if (n->parms->neigh_cleanup)
- n->parms->neigh_cleanup(n);
- neigh_release(n);
+ neigh_cleanup_and_release(n);
continue;
}
write_unlock(&n->lock);
@@ -2094,11 +2096,8 @@ void __neigh_for_each_release(struct nei
} else
np = &n->next;
write_unlock(&n->lock);
- if (release) {
- if (n->parms->neigh_cleanup)
- n->parms->neigh_cleanup(n);
- neigh_release(n);
- }
+ if (release)
+ neigh_cleanup_and_release(n);
}
}
}
^ permalink raw reply
* Re: [PATCH] CONFIG_NET=n - lots of link time errors
From: Jan Engelhardt @ 2007-07-22 10:10 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-kernel, akpm
In-Reply-To: <20070721.191223.15264470.davem@davemloft.net>
On Jul 21 2007 19:12, David Miller wrote:
>> Enabling drivers from "Devices > Networking" (in menuconfig), for
>> example SLIP and/or PLIP, throws link time errors when CONFIG_NET itself
>> is =n. Have CONFIG_NETDEVICES depend on CONFIG_NET.
>>
>> Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
>
>This is the second time I've seen this change in the past few
>days, and people seem to hit it quite readily with randconfig.
>
>It seems reasonable and I'll apply it, thanks Jan.
While randconfig is nice and good, this error actually came by manually
tuning the .config for a specific goal (namely: make a small kernel for an
ancient i386 without modifying any code). Turning off CONFIG_NET
was then just an idea away, because I knew that TCP was quite big.
Jan
--
^ permalink raw reply
* Re: [PATCH 11/12 -Rev2] IPoIB xmit API addition
From: Michael S. Tsirkin @ 2007-07-22 9:41 UTC (permalink / raw)
To: Krishna Kumar
Cc: davem, rdreier, johnpol, Robert.Olsson, peter.p.waskiewicz.jr,
herbert, gaagaan, kumarkr, mcarlson, jagana, general, netdev,
tgraf, jeff, hadi, kaber, mchan, sri
In-Reply-To: <20070722090649.7787.47960.sendpatchset@K50wks273871wss.in.ibm.com>
> + /*
> + * Handle skbs completion from tx_tail to wr_id. It is possible to
> + * handle WC's from earlier post_sends (possible multiple) in this
> + * iteration as we move from tx_tail to wr_id, since if the last
> + * WR (which is the one which had a completion request) failed to be
> + * sent for any of those earlier request(s), no completion
> + * notification is generated for successful WR's of those earlier
> + * request(s).
> + */
AFAIK a signalled WR will always generate a completion.
What am I missing?
>
> + /*
> + * Better error handling can be done here, like free
> + * all untried skbs if err == -ENOMEM. However at this
> + * time, we re-try all the skbs, all of which will
> + * likely fail anyway (unless device finished sending
> + * some out in the meantime). This is not a regression
> + * since the earlier code is not doing this either.
> + */
Are you retrying posting skbs? Why is this a good idea?
AFAIK, earlier code did not retry posting WRs at all.
The comment seems to imply that post send fails as a result of SQ overflow -
do you see SQ overflow errors in your testing?
AFAIK, IPoIB should never overflow the SQ.
--
MST
^ permalink raw reply
* [ofa-general] [PATCH 12/12 -Rev2] IPoIB xmit internals changes (ipoib_ib.c)
From: Krishna Kumar @ 2007-07-22 9:06 UTC (permalink / raw)
To: davem, rdreier
Cc: johnpol, Robert.Olsson, herbert, gaagaan, kumarkr,
peter.p.waskiewicz.jr, mcarlson, kaber, jagana, general, mchan,
tgraf, jeff, sri, hadi, netdev
In-Reply-To: <20070722090457.7787.4601.sendpatchset@K50wks273871wss.in.ibm.com>
diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_main.c rev2/drivers/infiniband/ulp/ipoib/ipoib_main.c
--- org/drivers/infiniband/ulp/ipoib/ipoib_main.c 2007-07-20 07:49:28.000000000 +0530
+++ rev2/drivers/infiniband/ulp/ipoib/ipoib_main.c 2007-07-22 00:08:28.000000000 +0530
@@ -558,7 +558,8 @@ static void neigh_add_path(struct sk_buf
goto err_drop;
}
} else
- ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha));
+ ipoib_send(dev, skb, path->ah,
+ IPOIB_QPN(skb->dst->neighbour->ha), 1);
} else {
neigh->ah = NULL;
@@ -638,7 +639,7 @@ static void unicast_arp_send(struct sk_b
ipoib_dbg(priv, "Send unicast ARP to %04x\n",
be16_to_cpu(path->pathrec.dlid));
- ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr));
+ ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr), 1);
} else if ((path->query || !path_rec_start(dev, path)) &&
skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */
@@ -704,7 +705,8 @@ static int ipoib_start_xmit(struct sk_bu
goto out;
}
- ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
+ ipoib_send(dev, skb, neigh->ah,
+ IPOIB_QPN(skb->dst->neighbour->ha), 1);
goto out;
}
@@ -753,6 +755,175 @@ out:
return NETDEV_TX_OK;
}
+#define XMIT_QUEUED_SKBS() \
+ do { \
+ if (num_skbs) { \
+ ipoib_send(dev, NULL, old_neigh->ah, old_qpn, \
+ num_skbs); \
+ num_skbs = 0; \
+ } \
+ } while (0)
+
+/*
+ * TODO: Merge with ipoib_start_xmit to use the same code and have a
+ * transparent wrapper caller to xmit's, etc.
+ */
+static int ipoib_start_xmit_frames(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct sk_buff_head *blist;
+ int max_skbs, num_skbs = 0, tx_ring_index = -1;
+ u32 qpn, old_qpn = 0;
+ struct ipoib_neigh *neigh, *old_neigh = NULL;
+ unsigned long flags;
+
+ if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
+ return NETDEV_TX_LOCKED;
+
+ blist = &dev->skb_blist;
+
+ /*
+ * Send atmost 'max_skbs' skbs. This also prevents the device getting
+ * full.
+ */
+ max_skbs = ipoib_sendq_size - (priv->tx_head - priv->tx_tail);
+ while (max_skbs-- > 0 && (skb = __skb_dequeue(blist)) != NULL) {
+ /*
+ * From here on, ipoib_send() cannot stop the queue as it
+ * uses the same initialization as 'max_skbs'. So we can
+ * optimize to not check for queue stopped for every skb.
+ */
+ if (likely(skb->dst && skb->dst->neighbour)) {
+ if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
+ XMIT_QUEUED_SKBS();
+ ipoib_path_lookup(skb, dev);
+ continue;
+ }
+
+ neigh = *to_ipoib_neigh(skb->dst->neighbour);
+
+ if (ipoib_cm_get(neigh)) {
+ if (ipoib_cm_up(neigh)) {
+ XMIT_QUEUED_SKBS();
+ ipoib_cm_send(dev, skb,
+ ipoib_cm_get(neigh));
+ continue;
+ }
+ } else if (neigh->ah) {
+ if (unlikely(memcmp(&neigh->dgid.raw,
+ skb->dst->neighbour->ha + 4,
+ sizeof(union ib_gid)))) {
+ spin_lock(&priv->lock);
+ /*
+ * It's safe to call ipoib_put_ah()
+ * inside priv->lock here, because we
+ * know that path->ah will always hold
+ * one more reference, so ipoib_put_ah()
+ * will never do more than decrement
+ * the ref count.
+ */
+ ipoib_put_ah(neigh->ah);
+ list_del(&neigh->list);
+ ipoib_neigh_free(dev, neigh);
+ spin_unlock(&priv->lock);
+ XMIT_QUEUED_SKBS();
+ ipoib_path_lookup(skb, dev);
+ continue;
+ }
+
+ qpn = IPOIB_QPN(skb->dst->neighbour->ha);
+ if (neigh != old_neigh || qpn != old_qpn) {
+ /*
+ * Sending to a different destination
+ * from earlier skb's - send all
+ * existing skbs (if any).
+ */
+ if (tx_ring_index == -1) {
+ /*
+ * First time, find where to
+ * store skb.
+ */
+ tx_ring_index = priv->tx_head &
+ (ipoib_sendq_size - 1);
+ } else {
+ /* Some skbs to send */
+ XMIT_QUEUED_SKBS();
+ }
+ old_neigh = neigh;
+ old_qpn = IPOIB_QPN(skb->dst->neighbour->ha);
+ }
+
+ if (ipoib_process_skb(dev, skb, priv, num_skbs,
+ tx_ring_index, neigh->ah,
+ qpn))
+ continue;
+
+ num_skbs++;
+
+ /* Queue'd one skb, get index for next skb */
+ if (max_skbs)
+ tx_ring_index = (tx_ring_index + 1) &
+ (ipoib_sendq_size - 1);
+ continue;
+ }
+
+ if (skb_queue_len(&neigh->queue) <
+ IPOIB_MAX_PATH_REC_QUEUE) {
+ spin_lock(&priv->lock);
+ __skb_queue_tail(&neigh->queue, skb);
+ spin_unlock(&priv->lock);
+ } else {
+ dev_kfree_skb_any(skb);
+ ++priv->stats.tx_dropped;
+ ++max_skbs;
+ }
+ } else {
+ struct ipoib_pseudoheader *phdr =
+ (struct ipoib_pseudoheader *) skb->data;
+ skb_pull(skb, sizeof *phdr);
+
+ if (phdr->hwaddr[4] == 0xff) {
+ /* Add in the P_Key for multicast*/
+ phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
+ phdr->hwaddr[9] = priv->pkey & 0xff;
+
+ XMIT_QUEUED_SKBS();
+ ipoib_mcast_send(dev, phdr->hwaddr + 4, skb);
+ } else {
+ /* unicast GID -- should be ARP or RARP reply */
+
+ if ((be16_to_cpup((__be16 *) skb->data) !=
+ ETH_P_ARP) &&
+ (be16_to_cpup((__be16 *) skb->data) !=
+ ETH_P_RARP)) {
+ ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x "
+ IPOIB_GID_FMT "\n",
+ skb->dst ? "neigh" : "dst",
+ be16_to_cpup((__be16 *)
+ skb->data),
+ IPOIB_QPN(phdr->hwaddr),
+ IPOIB_GID_RAW_ARG(phdr->hwaddr
+ + 4));
+ dev_kfree_skb_any(skb);
+ ++priv->stats.tx_dropped;
+ ++max_skbs;
+ continue;
+ }
+ XMIT_QUEUED_SKBS();
+ unicast_arp_send(skb, dev, phdr);
+ }
+ }
+ }
+
+ /* Send out last packets (if any) */
+ XMIT_QUEUED_SKBS();
+
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+ return skb_queue_empty(blist) ? NETDEV_TX_OK : NETDEV_TX_BUSY;
+}
+
static struct net_device_stats *ipoib_get_stats(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -898,11 +1069,35 @@ int ipoib_dev_init(struct net_device *de
/* priv->tx_head & tx_tail are already 0 */
- if (ipoib_ib_dev_init(dev, ca, port))
+ /* Allocate tx_sge */
+ priv->tx_sge = kmalloc(ipoib_sendq_size * sizeof *priv->tx_sge,
+ GFP_KERNEL);
+ if (!priv->tx_sge) {
+ printk(KERN_WARNING "%s: failed to allocate TX sge (%d entries)\n",
+ ca->name, ipoib_sendq_size);
goto out_tx_ring_cleanup;
+ }
+
+ /* Allocate tx_wr */
+ priv->tx_wr = kmalloc(ipoib_sendq_size * sizeof *priv->tx_wr,
+ GFP_KERNEL);
+ if (!priv->tx_wr) {
+ printk(KERN_WARNING "%s: failed to allocate TX wr (%d entries)\n",
+ ca->name, ipoib_sendq_size);
+ goto out_tx_sge_cleanup;
+ }
+
+ if (ipoib_ib_dev_init(dev, ca, port))
+ goto out_tx_wr_cleanup;
return 0;
+out_tx_wr_cleanup:
+ kfree(priv->tx_wr);
+
+out_tx_sge_cleanup:
+ kfree(priv->tx_sge);
+
out_tx_ring_cleanup:
kfree(priv->tx_ring);
@@ -930,9 +1125,13 @@ void ipoib_dev_cleanup(struct net_device
kfree(priv->rx_ring);
kfree(priv->tx_ring);
+ kfree(priv->tx_sge);
+ kfree(priv->tx_wr);
priv->rx_ring = NULL;
priv->tx_ring = NULL;
+ priv->tx_sge = NULL;
+ priv->tx_wr = NULL;
}
static void ipoib_setup(struct net_device *dev)
@@ -943,6 +1142,7 @@ static void ipoib_setup(struct net_devic
dev->stop = ipoib_stop;
dev->change_mtu = ipoib_change_mtu;
dev->hard_start_xmit = ipoib_start_xmit;
+ dev->hard_start_xmit_batch = ipoib_start_xmit_frames;
dev->get_stats = ipoib_get_stats;
dev->tx_timeout = ipoib_timeout;
dev->hard_header = ipoib_hard_header;
^ permalink raw reply
* [ofa-general] [PATCH 11/12 -Rev2] IPoIB xmit API addition
From: Krishna Kumar @ 2007-07-22 9:06 UTC (permalink / raw)
To: davem, rdreier
Cc: johnpol, Robert.Olsson, peter.p.waskiewicz.jr, herbert, gaagaan,
kumarkr, mcarlson, jagana, general, netdev, tgraf, jeff, hadi,
kaber, mchan, sri
In-Reply-To: <20070722090457.7787.4601.sendpatchset@K50wks273871wss.in.ibm.com>
diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_ib.c rev2/drivers/infiniband/ulp/ipoib/ipoib_ib.c
--- org/drivers/infiniband/ulp/ipoib/ipoib_ib.c 2007-07-20 07:49:28.000000000 +0530
+++ rev2/drivers/infiniband/ulp/ipoib/ipoib_ib.c 2007-07-22 00:08:37.000000000 +0530
@@ -242,8 +242,9 @@ repost:
static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
+ int i = 0, num_completions;
+ int tx_ring_index = priv->tx_tail & (ipoib_sendq_size - 1);
unsigned int wr_id = wc->wr_id;
- struct ipoib_tx_buf *tx_req;
unsigned long flags;
ipoib_dbg_data(priv, "send completion: id %d, status: %d\n",
@@ -255,23 +256,57 @@ static void ipoib_ib_handle_tx_wc(struct
return;
}
- tx_req = &priv->tx_ring[wr_id];
+ num_completions = wr_id - tx_ring_index + 1;
+ if (num_completions <= 0)
+ num_completions += ipoib_sendq_size;
- ib_dma_unmap_single(priv->ca, tx_req->mapping,
- tx_req->skb->len, DMA_TO_DEVICE);
+ /*
+ * Handle skbs completion from tx_tail to wr_id. It is possible to
+ * handle WC's from earlier post_sends (possible multiple) in this
+ * iteration as we move from tx_tail to wr_id, since if the last
+ * WR (which is the one which had a completion request) failed to be
+ * sent for any of those earlier request(s), no completion
+ * notification is generated for successful WR's of those earlier
+ * request(s).
+ */
+ while (1) {
+ /*
+ * Could use while (i < num_completions), but it is costly
+ * since in most cases there is 1 completion, and we end up
+ * doing an extra "index = (index+1) & (ipoib_sendq_size-1)"
+ */
+ struct ipoib_tx_buf *tx_req = &priv->tx_ring[tx_ring_index];
+
+ if (likely(tx_req->skb)) {
+ ib_dma_unmap_single(priv->ca, tx_req->mapping,
+ tx_req->skb->len, DMA_TO_DEVICE);
- ++priv->stats.tx_packets;
- priv->stats.tx_bytes += tx_req->skb->len;
+ ++priv->stats.tx_packets;
+ priv->stats.tx_bytes += tx_req->skb->len;
- dev_kfree_skb_any(tx_req->skb);
+ dev_kfree_skb_any(tx_req->skb);
+ }
+ /*
+ * else this skb failed synchronously when posted and was
+ * freed immediately.
+ */
+
+ if (++i == num_completions)
+ break;
+
+ /* More WC's to handle */
+ tx_ring_index = (tx_ring_index + 1) & (ipoib_sendq_size - 1);
+ }
spin_lock_irqsave(&priv->tx_lock, flags);
- ++priv->tx_tail;
+
+ priv->tx_tail += num_completions;
if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags)) &&
priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) {
clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
netif_wake_queue(dev);
}
+
spin_unlock_irqrestore(&priv->tx_lock, flags);
if (wc->status != IB_WC_SUCCESS &&
@@ -340,78 +375,178 @@ void ipoib_ib_completion(struct ib_cq *c
netif_rx_schedule(dev_ptr);
}
-static inline int post_send(struct ipoib_dev_priv *priv,
- unsigned int wr_id,
- struct ib_ah *address, u32 qpn,
- u64 addr, int len)
+/*
+ * post_send : Post WR(s) to the device.
+ *
+ * num_skbs is the number of WR's, 'start_index' is the first slot in
+ * tx_wr[] or tx_sge[]. Note: 'start_index' is normally zero, unless a
+ * previous post_send returned error and we are trying to send the untried
+ * WR's, in which case start_index will point to the first untried WR.
+ *
+ * We also break the WR link before posting so that the driver knows how
+ * many WR's to process, and this is set back after the post.
+ */
+static inline int post_send(struct ipoib_dev_priv *priv, u32 qpn,
+ int start_index, int num_skbs,
+ struct ib_send_wr **bad_wr)
{
- struct ib_send_wr *bad_wr;
+ int ret;
+ struct ib_send_wr *last_wr, *next_wr;
+
+ last_wr = &priv->tx_wr[start_index + num_skbs - 1];
+
+ /* Set Completion Notification for last WR */
+ last_wr->send_flags = IB_SEND_SIGNALED;
- priv->tx_sge.addr = addr;
- priv->tx_sge.length = len;
+ /* Terminate the last WR */
+ next_wr = last_wr->next;
+ last_wr->next = NULL;
- priv->tx_wr.wr_id = wr_id;
- priv->tx_wr.wr.ud.remote_qpn = qpn;
- priv->tx_wr.wr.ud.ah = address;
+ /* Send all the WR's in one doorbell */
+ ret = ib_post_send(priv->qp, &priv->tx_wr[start_index], bad_wr);
- return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr);
+ /* Restore send_flags & WR chain */
+ last_wr->send_flags = 0;
+ last_wr->next = next_wr;
+
+ return ret;
}
-void ipoib_send(struct net_device *dev, struct sk_buff *skb,
- struct ipoib_ah *address, u32 qpn)
+/*
+ * Map skb & store skb/mapping in tx_req; and details of the WR in tx_wr
+ * to pass to the driver.
+ *
+ * Returns :
+ * - 0 on successful processing of the skb
+ * - 1 if the skb was freed.
+ */
+int ipoib_process_skb(struct net_device *dev, struct sk_buff *skb,
+ struct ipoib_dev_priv *priv, int wr_num,
+ int tx_ring_index, struct ipoib_ah *address, u32 qpn)
{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
- struct ipoib_tx_buf *tx_req;
u64 addr;
+ struct ipoib_tx_buf *tx_req;
if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) {
- ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
+ ipoib_warn(priv, "packet len %d (> %d) too long to "
+ "send, dropping\n",
skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN);
++priv->stats.tx_dropped;
++priv->stats.tx_errors;
ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu);
- return;
+ return 1;
}
- ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n",
+ ipoib_dbg_data(priv, "sending packet, length=%d address=%p "
+ "qpn=0x%06x\n",
skb->len, address, qpn);
/*
* We put the skb into the tx_ring _before_ we call post_send()
* because it's entirely possible that the completion handler will
- * run before we execute anything after the post_send(). That
+ * run before we execute anything after the post_send(). That
* means we have to make sure everything is properly recorded and
* our state is consistent before we call post_send().
*/
- tx_req = &priv->tx_ring[priv->tx_head & (ipoib_sendq_size - 1)];
- tx_req->skb = skb;
- addr = ib_dma_map_single(priv->ca, skb->data, skb->len,
- DMA_TO_DEVICE);
+ addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
++priv->stats.tx_errors;
dev_kfree_skb_any(skb);
- return;
+ return 1;
}
+
+ tx_req = &priv->tx_ring[tx_ring_index];
+ tx_req->skb = skb;
tx_req->mapping = addr;
+ priv->tx_sge[wr_num].addr = addr;
+ priv->tx_sge[wr_num].length = skb->len;
+ priv->tx_wr[wr_num].wr_id = tx_ring_index;
+ priv->tx_wr[wr_num].wr.ud.remote_qpn = qpn;
+ priv->tx_wr[wr_num].wr.ud.ah = address->ah;
- if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
- address->ah, qpn, addr, skb->len))) {
- ipoib_warn(priv, "post_send failed\n");
- ++priv->stats.tx_errors;
- ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(skb);
- } else {
- dev->trans_start = jiffies;
+ return 0;
+}
+
+/*
+ * If an skb is passed to this function, it is the single, unprocessed skb
+ * send case. Otherwise if skb is NULL, it means that all skbs are already
+ * processed and put on the priv->tx_wr,tx_sge,tx_ring, etc.
+ */
+void ipoib_send(struct net_device *dev, struct sk_buff *skb,
+ struct ipoib_ah *address, u32 qpn, int num_skbs)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ int start_index = 0;
- address->last_send = priv->tx_head;
- ++priv->tx_head;
+ if (skb && ipoib_process_skb(dev, skb, priv, 0, priv->tx_head &
+ (ipoib_sendq_size - 1), address, qpn))
+ return;
- if (priv->tx_head - priv->tx_tail == ipoib_sendq_size) {
- ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
- netif_stop_queue(dev);
- set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
+ /* Send out all the skb's in one post */
+ while (num_skbs) {
+ struct ib_send_wr *bad_wr;
+
+ if (unlikely((post_send(priv, qpn, start_index, num_skbs,
+ &bad_wr)))) {
+ int done;
+
+ /*
+ * Better error handling can be done here, like free
+ * all untried skbs if err == -ENOMEM. However at this
+ * time, we re-try all the skbs, all of which will
+ * likely fail anyway (unless device finished sending
+ * some out in the meantime). This is not a regression
+ * since the earlier code is not doing this either.
+ */
+ ipoib_warn(priv, "post_send failed\n");
+
+ /* Get #WR's that finished successfully */
+ done = bad_wr - &priv->tx_wr[start_index];
+
+ /* Handle 1 error */
+ priv->stats.tx_errors++;
+ ib_dma_unmap_single(priv->ca,
+ priv->tx_sge[start_index + done].addr,
+ priv->tx_sge[start_index + done].length,
+ DMA_TO_DEVICE);
+
+ /* Handle 'n' successes */
+ if (done) {
+ dev->trans_start = jiffies;
+ address->last_send = priv->tx_head;
+ }
+
+ /* Free failed WR & reset for WC handler to recognize */
+ dev_kfree_skb_any(priv->tx_ring[bad_wr->wr_id].skb);
+ priv->tx_ring[bad_wr->wr_id].skb = NULL;
+
+ /* Move head to first untried WR */
+ priv->tx_head += (done + 1);
+ /* + 1 for WR that was tried & failed */
+
+ /* Get count of skbs that were not tried */
+ num_skbs -= (done + 1);
+
+ /* Get start index for next iteration */
+ start_index += (done + 1);
+ } else {
+ dev->trans_start = jiffies;
+
+ address->last_send = priv->tx_head;
+ priv->tx_head += num_skbs;
+ num_skbs = 0;
}
}
+
+ if (unlikely(priv->tx_head - priv->tx_tail == ipoib_sendq_size)) {
+ /*
+ * Not accurate as some intermediate slots could have been
+ * freed on error, but no harm - only queue stopped earlier.
+ */
+ ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
+ netif_stop_queue(dev);
+ set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
+ }
}
static void __ipoib_reap_ah(struct net_device *dev)
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox