Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (31 commits)
  [NETFILTER]: xt_conntrack: add compat support
  [NETFILTER]: iptable_raw: ignore short packets sent by SOCK_RAW sockets
  [NETFILTER]: iptable_{filter,mangle}: more descriptive "happy cracking" message
  [NETFILTER]: nf_nat: Clears helper private area when NATing
  [NETFILTER]: ctnetlink: clear helper area and handle unchanged helper
  [NETFILTER]: nf_conntrack: Removes unused destroy operation of l3proto
  [NETFILTER]: nf_conntrack: Removes duplicated declarations
  [NETFILTER]: nf_nat: remove unused argument of function allocating binding
  [NETFILTER]: Clean up table initialization
  [NET_SCHED]: Avoid requeue warning on dev_deactivate
  [NET_SCHED]: Reread dev->qdisc for NETDEV_TX_OK
  [NET_SCHED]: Rationalise return value of qdisc_restart
  [NET]: Fix dev->qdisc race for NETDEV_TX_LOCKED case
  [UDP]: Fix AF-specific references in AF-agnostic code.
  [IrDA]: KingSun/DonShine USB IrDA dongle support.
  [IPV6] ROUTE: Assign rt6i_idev for ip6_{prohibit,blk_hole}_entry.
  [IPV6]: Do no rely on skb->dst before it is assigned.
  [IPV6]: Send ICMPv6 error on scope violations.
  [SCTP]: Do not include ABORT chunk header in the notification.
  [SCTP]: Correctly copy addresses in sctp_copy_laddrs
  ...
This commit is contained in:
Linus Torvalds 2007-05-11 09:10:19 -07:00
commit ee54d2d87a
43 changed files with 1312 additions and 726 deletions

View File

@ -307,6 +307,8 @@ static void hci_uart_tty_close(struct tty_struct *tty)
if (hu) { if (hu) {
struct hci_dev *hdev = hu->hdev; struct hci_dev *hdev = hu->hdev;
if (hdev)
hci_uart_close(hdev); hci_uart_close(hdev);
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
@ -473,12 +475,18 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
tty->low_latency = 1; tty->low_latency = 1;
} else } else
return -EBUSY; return -EBUSY;
break;
case HCIUARTGETPROTO: case HCIUARTGETPROTO:
if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
return hu->proto->id; return hu->proto->id;
return -EUNATCH; return -EUNATCH;
case HCIUARTGETDEVICE:
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
return hu->hdev->id;
return -EUNATCH;
default: default:
err = n_tty_ioctl(tty, file, cmd, arg); err = n_tty_ioctl(tty, file, cmd, arg);
break; break;

View File

@ -30,6 +30,7 @@
/* Ioctls */ /* Ioctls */
#define HCIUARTSETPROTO _IOW('U', 200, int) #define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int) #define HCIUARTGETPROTO _IOR('U', 201, int)
#define HCIUARTGETDEVICE _IOR('U', 202, int)
/* UART protocols */ /* UART protocols */
#define HCI_UART_MAX_PROTO 4 #define HCI_UART_MAX_PROTO 4

View File

@ -141,6 +141,20 @@ config ACT200L_DONGLE
To activate support for ACTiSYS IR-200L dongle you will have to To activate support for ACTiSYS IR-200L dongle you will have to
start irattach like this: "irattach -d act200l". start irattach like this: "irattach -d act200l".
config KINGSUN_DONGLE
tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
depends on IRDA && USB && EXPERIMENTAL
help
Say Y or M here if you want to build support for the KingSun/DonShine
DS-620 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 speed only (9600 bps).
To compile it as a module, choose M here: the module will be called
kingsun-sir.
comment "Old SIR device drivers" comment "Old SIR device drivers"
config IRPORT_SIR config IRPORT_SIR

View File

@ -45,6 +45,7 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o
obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
# The SIR helper module # The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o sir-dev-objs := sir_dev.o sir_dongle.o

View File

@ -0,0 +1,657 @@
/*****************************************************************************
*
* Filename: kingsun-sir.c
* Version: 0.1.1
* Description: Irda KingSun/DonShine USB Dongle
* Status: Experimental
* Author: Alex Villac<EFBFBD>s Lasso <a_villacis@palosanto.com>
*
* Based on stir4200 and mcs7780 drivers, with (strange?) differences
*
* 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.
*
*****************************************************************************/
/*
* This is my current (2007-04-25) understanding of how this dongle is supposed
* to work. This is based on reverse-engineering and examination of the packet
* data sent and received by the WinXP driver using USBSnoopy. Feel free to
* update here as more of this dongle is known:
*
* General: Unlike the other USB IrDA dongles, this particular dongle exposes,
* not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
* like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
* order to receive data.
* Transmission: Just like stir4200, this dongle uses a raw stream of data,
* which needs to be wrapped and escaped in a similar way as in stir4200.c.
* Reception: Poll-based, as in stir4200. Each read returns the contents of a
* 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
* (1-7) of valid data contained within the remaining 7 bytes. For example, if
* the buffer had the following contents:
* 06 ff ff ff c0 01 04 aa
* This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
* end is garbage (left over from a previous reception) and is discarded.
* If a read returns an "impossible" value as the length of valid data (such as
* 0x36) in the first byte, then the buffer is uninitialized (as is the case of
* first plug-in) and its contents should be discarded. There is currently no
* evidence that the top 5 bits of the 1st byte of the buffer can have values
* other than 0 once reception begins.
* Once valid bytes are collected, the assembled stream is a sequence of
* wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
* BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
* a successful read from the host, which means that in absence of further
* reception, repeated reads from the dongle will return the exact same
* contents repeatedly. Attempts to be smart and cache a previous read seem
* to result in corrupted packets, so this driver depends on the unwrap logic
* to sort out any repeated reads.
* Speed change: no commands observed so far to change speed, assumed fixed
* 9600bps (SIR).
*/
#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>
/*
* According to lsusb, 0x07c0 is assigned to
* "Code Mercenaries Hard- und Software GmbH"
*/
#define KING_VENDOR_ID 0x07c0
#define KING_PRODUCT_ID 0x4200
/* These are the currently known USB ids */
static struct usb_device_id dongles[] = {
/* KingSun Co,Ltd IrDA/USB Bridge */
{ USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
{ }
};
MODULE_DEVICE_TABLE(usb, dongles);
#define KINGSUN_MTT 0x07
#define KINGSUN_FIFO_SIZE 4096
#define KINGSUN_EP_IN 0
#define KINGSUN_EP_OUT 1
struct kingsun_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;
__u8 *in_buf; /* receive buffer */
__u8 *out_buf; /* transmit buffer */
__u8 max_rx; /* max. atomic read from dongle
(usually 8), also size of in_buf */
__u8 max_tx; /* max. atomic write to dongle
(usually 8) */
iobuff_t rx_buff; /* receive unwrap state machine */
struct timeval rx_time;
spinlock_t lock;
int receiving;
__u8 ep_in;
__u8 ep_out;
struct urb *tx_urb;
struct urb *rx_urb;
};
/* Callback transmission routine */
static void kingsun_send_irq(struct urb *urb)
{
struct kingsun_cb *kingsun = urb->context;
struct net_device *netdev = kingsun->netdev;
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
err("kingsun_send_irq: Network not running!");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
err("kingsun_send_irq: urb asynchronously failed - %d",
urb->status);
}
netif_wake_queue(netdev);
}
/*
* Called from net/core when new frame is available.
*/
static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct kingsun_cb *kingsun;
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);
/* Append data to the end of whatever data remains to be transmitted */
wraplen = async_wrap_skb(skb,
kingsun->out_buf,
KINGSUN_FIFO_SIZE);
/* Calculate how much data can be transmitted in this urb */
usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
kingsun->out_buf, wraplen, kingsun_send_irq,
kingsun, 1);
if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
err("kingsun_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 kingsun_rcv_irq(struct urb *urb)
{
struct kingsun_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 == kingsun->max_rx) {
__u8 *bytes = urb->transfer_buffer;
int i;
/* The very first byte in the buffer indicates the length of
valid data in the read. This byte must be in the range
1..kingsun->max_rx -1 . Values outside this range indicate
an uninitialized Rx buffer when the dongle has just been
plugged in. */
if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
for (i = 1; i <= bytes[0]; i++) {
async_unwrap_char(kingsun->netdev,
&kingsun->stats,
&kingsun->rx_buff, bytes[i]);
}
kingsun->netdev->last_rx = jiffies;
do_gettimeofday(&kingsun->rx_time);
kingsun->receiving =
(kingsun->rx_buff.state != OUTSIDE_FRAME)
? 1 : 0;
}
} else if (urb->actual_length > 0) {
err("%s(): Unexpected response length, expected %d got %d",
__FUNCTION__, kingsun->max_rx, urb->actual_length);
}
/* This urb has already been filled in kingsun_net_open */
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 kingsun_net_open(struct net_device *netdev)
{
struct kingsun_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_buff.in_frame = FALSE;
kingsun->rx_buff.state = OUTSIDE_FRAME;
kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
if (!kingsun->rx_buff.skb)
goto free_mem;
skb_reserve(kingsun->rx_buff.skb, 1);
kingsun->rx_buff.head = kingsun->rx_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;
/*
* 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("kingsun-sir: irlap_open failed");
goto free_mem;
}
/* Start first reception */
usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
kingsun->in_buf, kingsun->max_rx,
kingsun_rcv_irq, kingsun, 1);
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
err("kingsun-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:
if (kingsun->tx_urb) {
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
}
if (kingsun->rx_urb) {
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
}
if (kingsun->rx_buff.skb) {
kfree_skb(kingsun->rx_buff.skb);
kingsun->rx_buff.skb = NULL;
kingsun->rx_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 kingsun_net_close(struct net_device *netdev)
{
struct kingsun_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_kill_urb(kingsun->rx_urb);
usb_free_urb(kingsun->tx_urb);
usb_free_urb(kingsun->rx_urb);
kingsun->tx_urb = NULL;
kingsun->rx_urb = NULL;
kfree_skb(kingsun->rx_buff.skb);
kingsun->rx_buff.skb = NULL;
kingsun->rx_buff.head = NULL;
kingsun->rx_buff.in_frame = FALSE;
kingsun->rx_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 kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *) rq;
struct kingsun_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))
/* No observed commands for speed change */
ret = -EOPNOTSUPP;
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 *
kingsun_net_get_stats(struct net_device *netdev)
{
struct kingsun_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 kingsun_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *dev = interface_to_usbdev(intf);
struct kingsun_cb *kingsun = NULL;
struct net_device *net = NULL;
int ret = -ENOMEM;
int pipe, maxp_in, maxp_out;
__u8 ep_in;
__u8 ep_out;
/* Check that there really are two interrupt endpoints.
Check based on the one in drivers/usb/input/usbmouse.c
*/
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2) {
err("kingsun-sir: expected 2 endpoints, found %d",
interface->desc.bNumEndpoints);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
if (!usb_endpoint_is_int_in(endpoint)) {
err("kingsun-sir: endpoint 0 is not interrupt IN");
return -ENODEV;
}
ep_in = endpoint->bEndpointAddress;
pipe = usb_rcvintpipe(dev, ep_in);
maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp_in > 255 || maxp_in <= 1) {
err("%s: endpoint 0 has max packet size %d not in range",
__FILE__, maxp_in);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
if (!usb_endpoint_is_int_out(endpoint)) {
err("kingsun-sir: endpoint 1 is not interrupt OUT");
return -ENODEV;
}
ep_out = endpoint->bEndpointAddress;
pipe = usb_sndintpipe(dev, ep_out);
maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
/* 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->irlap = NULL;
kingsun->tx_urb = NULL;
kingsun->rx_urb = NULL;
kingsun->ep_in = ep_in;
kingsun->ep_out = ep_out;
kingsun->in_buf = NULL;
kingsun->out_buf = NULL;
kingsun->max_rx = (__u8)maxp_in;
kingsun->max_tx = (__u8)maxp_out;
kingsun->netdev = net;
kingsun->usbdev = dev;
kingsun->rx_buff.in_frame = FALSE;
kingsun->rx_buff.state = OUTSIDE_FRAME;
kingsun->rx_buff.skb = NULL;
kingsun->receiving = 0;
spin_lock_init(&kingsun->lock);
/* Allocate input buffer */
kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL);
if (!kingsun->in_buf)
goto free_mem;
/* Allocate output buffer */
kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
if (!kingsun->out_buf)
goto free_mem;
printk(KERN_INFO "KingSun/DonShine 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);
/* That's the Rx capability. */
kingsun->qos.baud_rate.bits &= IR_9600;
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 = kingsun_hard_xmit;
net->open = kingsun_net_open;
net->stop = kingsun_net_close;
net->get_stats = kingsun_net_get_stats;
net->do_ioctl = kingsun_net_ioctl;
ret = register_netdev(net);
if (ret != 0)
goto free_mem;
info("IrDA: Registered KingSun/DonShine device %s", net->name);
usb_set_intfdata(intf, kingsun);
/* Situation at this point:
- all work buffers allocated
- urbs not allocated, set to NULL
- max rx packet known (in max_rx)
- unwrap state machine (partially) initialized, but skb == NULL
*/
return 0;
free_mem:
if (kingsun->out_buf) kfree(kingsun->out_buf);
if (kingsun->in_buf) kfree(kingsun->in_buf);
free_netdev(net);
err_out1:
return ret;
}
/*
* The current device is removed, the USB layer tell us to shut it down...
*/
static void kingsun_disconnect(struct usb_interface *intf)
{
struct kingsun_cb *kingsun = usb_get_intfdata(intf);
if (!kingsun)
return;
unregister_netdev(kingsun->netdev);
/* Mop up receive && transmit urb's */
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->out_buf);
kfree(kingsun->in_buf);
free_netdev(kingsun->netdev);
usb_set_intfdata(intf, NULL);
}
#ifdef CONFIG_PM
/* USB suspend, so power off the transmitter/receiver */
static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
{
struct kingsun_cb *kingsun = usb_get_intfdata(intf);
netif_device_detach(kingsun->netdev);
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 kingsun_resume(struct usb_interface *intf)
{
struct kingsun_cb *kingsun = usb_get_intfdata(intf);
if (kingsun->rx_urb != NULL)
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 = "kingsun-sir",
.probe = kingsun_probe,
.disconnect = kingsun_disconnect,
.id_table = dongles,
#ifdef CONFIG_PM
.suspend = kingsun_suspend,
.resume = kingsun_resume,
#endif
};
/*
* Module insertion
*/
static int __init kingsun_init(void)
{
return usb_register(&irda_driver);
}
module_init(kingsun_init);
/*
* Module removal
*/
static void __exit kingsun_cleanup(void)
{
/* Deregister the driver and remove all pending instances */
usb_deregister(&irda_driver);
}
module_exit(kingsun_cleanup);
MODULE_AUTHOR("Alex Villac<61>s Lasso <a_villacis@palosanto.com>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
MODULE_LICENSE("GPL");

View File

@ -467,6 +467,8 @@ struct net_device
/* device index hash chain */ /* device index hash chain */
struct hlist_node index_hlist; struct hlist_node index_hlist;
struct net_device *link_watch_next;
/* register/unregister state machine */ /* register/unregister state machine */
enum { NETREG_UNINITIALIZED=0, enum { NETREG_UNINITIALIZED=0,
NETREG_REGISTERED, /* completed register_netdevice */ NETREG_REGISTERED, /* completed register_netdevice */

View File

@ -54,6 +54,14 @@ struct xt_entry_target
unsigned char data[0]; unsigned char data[0];
}; };
#define XT_TARGET_INIT(__name, __size) \
{ \
.target.u.user = { \
.target_size = XT_ALIGN(__size), \
.name = __name, \
}, \
}
struct xt_standard_target struct xt_standard_target
{ {
struct xt_entry_target target; struct xt_entry_target target;

View File

@ -238,6 +238,47 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e
*/ */
#ifdef __KERNEL__ #ifdef __KERNEL__
/* Standard entry. */
struct arpt_standard
{
struct arpt_entry entry;
struct arpt_standard_target target;
};
struct arpt_error_target
{
struct arpt_entry_target target;
char errorname[ARPT_FUNCTION_MAXNAMELEN];
};
struct arpt_error
{
struct arpt_entry entry;
struct arpt_error_target target;
};
#define ARPT_ENTRY_INIT(__size) \
{ \
.target_offset = sizeof(struct arpt_entry), \
.next_offset = (__size), \
}
#define ARPT_STANDARD_INIT(__verdict) \
{ \
.entry = ARPT_ENTRY_INIT(sizeof(struct arpt_standard)), \
.target = XT_TARGET_INIT(ARPT_STANDARD_TARGET, \
sizeof(struct arpt_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
#define ARPT_ERROR_INIT \
{ \
.entry = ARPT_ENTRY_INIT(sizeof(struct arpt_error)), \
.target = XT_TARGET_INIT(ARPT_ERROR_TARGET, \
sizeof(struct arpt_error_target)), \
.target.errorname = "ERROR", \
}
#define arpt_register_target(tgt) \ #define arpt_register_target(tgt) \
({ (tgt)->family = NF_ARP; \ ({ (tgt)->family = NF_ARP; \
xt_register_target(tgt); }) xt_register_target(tgt); })

View File

@ -295,6 +295,28 @@ struct ipt_error
struct ipt_error_target target; struct ipt_error_target target;
}; };
#define IPT_ENTRY_INIT(__size) \
{ \
.target_offset = sizeof(struct ipt_entry), \
.next_offset = (__size), \
}
#define IPT_STANDARD_INIT(__verdict) \
{ \
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_standard)), \
.target = XT_TARGET_INIT(IPT_STANDARD_TARGET, \
sizeof(struct xt_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
#define IPT_ERROR_INIT \
{ \
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_error)), \
.target = XT_TARGET_INIT(IPT_ERROR_TARGET, \
sizeof(struct ipt_error_target)), \
.target.errorname = "ERROR", \
}
extern unsigned int ipt_do_table(struct sk_buff **pskb, extern unsigned int ipt_do_table(struct sk_buff **pskb,
unsigned int hook, unsigned int hook,
const struct net_device *in, const struct net_device *in,

View File

@ -123,6 +123,28 @@ struct ip6t_error
struct ip6t_error_target target; struct ip6t_error_target target;
}; };
#define IP6T_ENTRY_INIT(__size) \
{ \
.target_offset = sizeof(struct ip6t_entry), \
.next_offset = (__size), \
}
#define IP6T_STANDARD_INIT(__verdict) \
{ \
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
.target = XT_TARGET_INIT(IP6T_STANDARD_TARGET, \
sizeof(struct ip6t_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
#define IP6T_ERROR_INIT \
{ \
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
.target = XT_TARGET_INIT(IP6T_ERROR_TARGET, \
sizeof(struct ip6t_error_target)), \
.target.errorname = "ERROR", \
}
/* /*
* New IP firewall options for [gs]etsockopt at the RAW IP level. * New IP firewall options for [gs]etsockopt at the RAW IP level.
* Unlike BSD Linux inherits IP options so you don't have to use * Unlike BSD Linux inherits IP options so you don't have to use

View File

@ -183,13 +183,6 @@ extern void nf_conntrack_hash_insert(struct nf_conn *ct);
extern void nf_conntrack_flush(void); extern void nf_conntrack_flush(void);
extern struct nf_conntrack_helper *
nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
extern struct nf_conntrack_helper *
__nf_conntrack_helper_find_byname(const char *name);
extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig); const struct nf_conntrack_tuple *orig);

View File

@ -56,9 +56,6 @@ struct nf_conntrack_l3proto
*/ */
int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb); int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
/* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *conntrack);
/* /*
* Called before tracking. * Called before tracking.
* *dataoff: offset of protocol header (TCP, UDP,...) in *pskb * *dataoff: offset of protocol header (TCP, UDP,...) in *pskb

View File

@ -10,16 +10,11 @@ extern int nf_nat_rule_find(struct sk_buff **pskb,
unsigned int hooknum, unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
struct nf_conn *ct, struct nf_conn *ct);
struct nf_nat_info *info);
extern unsigned int extern unsigned int
alloc_null_binding(struct nf_conn *ct, alloc_null_binding(struct nf_conn *ct, unsigned int hooknum);
struct nf_nat_info *info,
unsigned int hooknum);
extern unsigned int extern unsigned int
alloc_null_binding_confirmed(struct nf_conn *ct, alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum);
struct nf_nat_info *info,
unsigned int hooknum);
#endif /* _NF_NAT_RULE_H */ #endif /* _NF_NAT_RULE_H */

View File

@ -119,9 +119,16 @@ static inline void udp_lib_close(struct sock *sk, long timeout)
} }
struct udp_get_port_ops {
int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2);
int (*saddr_any)(const struct sock *sk);
unsigned int (*hash_port_and_rcv_saddr)(__u16 port,
const struct sock *sk);
};
/* net/ipv4/udp.c */ /* net/ipv4/udp.c */
extern int udp_get_port(struct sock *sk, unsigned short snum, extern int udp_get_port(struct sock *sk, unsigned short snum,
int (*saddr_cmp)(const struct sock *, const struct sock *)); const struct udp_get_port_ops *ops);
extern void udp_err(struct sk_buff *, u32); extern void udp_err(struct sk_buff *, u32);
extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,

View File

@ -120,5 +120,5 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
extern void udplite4_register(void); extern void udplite4_register(void);
extern int udplite_get_port(struct sock *sk, unsigned short snum, extern int udplite_get_port(struct sock *sk, unsigned short snum,
int (*scmp)(const struct sock *, const struct sock *)); const struct udp_get_port_ops *ops);
#endif /* _UDPLITE_H */ #endif /* _UDPLITE_H */

View File

@ -174,7 +174,7 @@ static inline int hidp_queue_event(struct hidp_session *session, struct input_de
static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{ {
struct hid_device *hid = dev->private; struct hid_device *hid = input_get_drvdata(dev);
struct hidp_session *session = hid->driver_data; struct hidp_session *session = hid->driver_data;
return hidp_queue_event(session, dev, type, code, value); return hidp_queue_event(session, dev, type, code, value);
@ -182,7 +182,7 @@ static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigne
static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{ {
struct hidp_session *session = dev->private; struct hidp_session *session = input_get_drvdata(dev);
return hidp_queue_event(session, dev, type, code, value); return hidp_queue_event(session, dev, type, code, value);
} }
@ -630,7 +630,7 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co
struct input_dev *input = session->input; struct input_dev *input = session->input;
int i; int i;
input->private = session; input_set_drvdata(input, session);
input->name = "Bluetooth HID Boot Protocol Device"; input->name = "Bluetooth HID Boot Protocol Device";
@ -663,7 +663,7 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co
input->relbit[0] |= BIT(REL_WHEEL); input->relbit[0] |= BIT(REL_WHEEL);
} }
input->cdev.dev = hidp_get_device(session); input->dev.parent = hidp_get_device(session);
input->event = hidp_input_event; input->event = hidp_input_event;
@ -864,7 +864,7 @@ failed:
if (session->hid) if (session->hid)
hid_free_device(session->hid); hid_free_device(session->hid);
kfree(session->input); input_free_device(session->input);
kfree(session); kfree(session);
return err; return err;
} }

View File

@ -19,7 +19,6 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/bitops.h> #include <linux/bitops.h>
@ -27,8 +26,7 @@
enum lw_bits { enum lw_bits {
LW_RUNNING = 0, LW_URGENT = 0,
LW_SE_USED
}; };
static unsigned long linkwatch_flags; static unsigned long linkwatch_flags;
@ -37,17 +35,9 @@ static unsigned long linkwatch_nextevent;
static void linkwatch_event(struct work_struct *dummy); static void linkwatch_event(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event);
static LIST_HEAD(lweventlist); static struct net_device *lweventlist;
static DEFINE_SPINLOCK(lweventlist_lock); static DEFINE_SPINLOCK(lweventlist_lock);
struct lw_event {
struct list_head list;
struct net_device *dev;
};
/* Avoid kmalloc() for most systems */
static struct lw_event singleevent;
static unsigned char default_operstate(const struct net_device *dev) static unsigned char default_operstate(const struct net_device *dev)
{ {
if (!netif_carrier_ok(dev)) if (!netif_carrier_ok(dev))
@ -87,25 +77,102 @@ static void rfc2863_policy(struct net_device *dev)
} }
/* Must be called with the rtnl semaphore held */ static int linkwatch_urgent_event(struct net_device *dev)
void linkwatch_run_queue(void)
{ {
struct list_head head, *n, *next; return netif_running(dev) && netif_carrier_ok(dev) &&
dev->qdisc != dev->qdisc_sleeping;
}
static void linkwatch_add_event(struct net_device *dev)
{
unsigned long flags;
spin_lock_irqsave(&lweventlist_lock, flags);
dev->link_watch_next = lweventlist;
lweventlist = dev;
spin_unlock_irqrestore(&lweventlist_lock, flags);
}
static void linkwatch_schedule_work(int urgent)
{
unsigned long delay = linkwatch_nextevent - jiffies;
if (test_bit(LW_URGENT, &linkwatch_flags))
return;
/* Minimise down-time: drop delay for up event. */
if (urgent) {
if (test_and_set_bit(LW_URGENT, &linkwatch_flags))
return;
delay = 0;
}
/* If we wrap around we'll delay it by at most HZ. */
if (delay > HZ)
delay = 0;
/*
* This is true if we've scheduled it immeditately or if we don't
* need an immediate execution and it's already pending.
*/
if (schedule_delayed_work(&linkwatch_work, delay) == !delay)
return;
/* Don't bother if there is nothing urgent. */
if (!test_bit(LW_URGENT, &linkwatch_flags))
return;
/* It's already running which is good enough. */
if (!cancel_delayed_work(&linkwatch_work))
return;
/* Otherwise we reschedule it again for immediate exection. */
schedule_delayed_work(&linkwatch_work, 0);
}
static void __linkwatch_run_queue(int urgent_only)
{
struct net_device *next;
/*
* Limit the number of linkwatch events to one
* per second so that a runaway driver does not
* cause a storm of messages on the netlink
* socket. This limit does not apply to up events
* while the device qdisc is down.
*/
if (!urgent_only)
linkwatch_nextevent = jiffies + HZ;
/* Limit wrap-around effect on delay. */
else if (time_after(linkwatch_nextevent, jiffies + HZ))
linkwatch_nextevent = jiffies;
clear_bit(LW_URGENT, &linkwatch_flags);
spin_lock_irq(&lweventlist_lock); spin_lock_irq(&lweventlist_lock);
list_replace_init(&lweventlist, &head); next = lweventlist;
lweventlist = NULL;
spin_unlock_irq(&lweventlist_lock); spin_unlock_irq(&lweventlist_lock);
list_for_each_safe(n, next, &head) { while (next) {
struct lw_event *event = list_entry(n, struct lw_event, list); struct net_device *dev = next;
struct net_device *dev = event->dev;
if (event == &singleevent) { next = dev->link_watch_next;
clear_bit(LW_SE_USED, &linkwatch_flags);
} else { if (urgent_only && !linkwatch_urgent_event(dev)) {
kfree(event); linkwatch_add_event(dev);
continue;
} }
/*
* Make sure the above read is complete since it can be
* rewritten as soon as we clear the bit below.
*/
smp_mb__before_clear_bit();
/* We are about to handle this device, /* We are about to handle this device,
* so new events can be accepted * so new events can be accepted
*/ */
@ -124,58 +191,39 @@ void linkwatch_run_queue(void)
dev_put(dev); dev_put(dev);
} }
if (lweventlist)
linkwatch_schedule_work(0);
}
/* Must be called with the rtnl semaphore held */
void linkwatch_run_queue(void)
{
__linkwatch_run_queue(0);
} }
static void linkwatch_event(struct work_struct *dummy) static void linkwatch_event(struct work_struct *dummy)
{ {
/* Limit the number of linkwatch events to one
* per second so that a runaway driver does not
* cause a storm of messages on the netlink
* socket
*/
linkwatch_nextevent = jiffies + HZ;
clear_bit(LW_RUNNING, &linkwatch_flags);
rtnl_lock(); rtnl_lock();
linkwatch_run_queue(); __linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies));
rtnl_unlock(); rtnl_unlock();
} }
void linkwatch_fire_event(struct net_device *dev) void linkwatch_fire_event(struct net_device *dev)
{ {
int urgent = linkwatch_urgent_event(dev);
if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
unsigned long flags;
struct lw_event *event;
if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) {
event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC);
if (unlikely(event == NULL)) {
clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
return;
}
} else {
event = &singleevent;
}
dev_hold(dev); dev_hold(dev);
event->dev = dev;
spin_lock_irqsave(&lweventlist_lock, flags); linkwatch_add_event(dev);
list_add_tail(&event->list, &lweventlist); } else if (!urgent)
spin_unlock_irqrestore(&lweventlist_lock, flags); return;
if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { linkwatch_schedule_work(urgent);
unsigned long delay = linkwatch_nextevent - jiffies;
/* If we wrap around we'll delay it by at most HZ. */
if (delay > HZ)
delay = 0;
schedule_delayed_work(&linkwatch_work, delay);
}
}
} }
EXPORT_SYMBOL(linkwatch_fire_event); EXPORT_SYMBOL(linkwatch_fire_event);

View File

@ -15,128 +15,34 @@ MODULE_DESCRIPTION("arptables filter table");
#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
(1 << NF_ARP_FORWARD)) (1 << NF_ARP_FORWARD))
/* Standard entry. */
struct arpt_standard
{
struct arpt_entry entry;
struct arpt_standard_target target;
};
struct arpt_error_target
{
struct arpt_entry_target target;
char errorname[ARPT_FUNCTION_MAXNAMELEN];
};
struct arpt_error
{
struct arpt_entry entry;
struct arpt_error_target target;
};
static struct static struct
{ {
struct arpt_replace repl; struct arpt_replace repl;
struct arpt_standard entries[3]; struct arpt_standard entries[3];
struct arpt_error term; struct arpt_error term;
} initial_table __initdata } initial_table __initdata = {
= { { "filter", FILTER_VALID_HOOKS, 4, .repl = {
sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error), .name = "filter",
{ [NF_ARP_IN] = 0, .valid_hooks = FILTER_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
.hook_entry = {
[NF_ARP_IN] = 0,
[NF_ARP_OUT] = sizeof(struct arpt_standard), [NF_ARP_OUT] = sizeof(struct arpt_standard),
[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
{ [NF_ARP_IN] = 0, },
.underflow = {
[NF_ARP_IN] = 0,
[NF_ARP_OUT] = sizeof(struct arpt_standard), [NF_ARP_OUT] = sizeof(struct arpt_standard),
[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
0, NULL, { } },
{
/* ARP_IN */
{
{
{
{ 0 }, { 0 }, { 0 }, { 0 },
0, 0,
{ { 0, }, { 0, } },
{ { 0, }, { 0, } },
0, 0,
0, 0,
0, 0,
"", "", { 0 }, { 0 },
0, 0
}, },
sizeof(struct arpt_entry),
sizeof(struct arpt_standard),
0,
{ 0, 0 }, { } },
{ { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 }
}, },
/* ARP_OUT */ .entries = {
{ ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_IN */
{ ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_OUT */
{ ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_FORWARD */
{ 0 }, { 0 }, { 0 }, { 0 },
0, 0,
{ { 0, }, { 0, } },
{ { 0, }, { 0, } },
0, 0,
0, 0,
0, 0,
"", "", { 0 }, { 0 },
0, 0
}, },
sizeof(struct arpt_entry), .term = ARPT_ERROR_INIT,
sizeof(struct arpt_standard),
0,
{ 0, 0 }, { } },
{ { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 }
},
/* ARP_FORWARD */
{
{
{
{ 0 }, { 0 }, { 0 }, { 0 },
0, 0,
{ { 0, }, { 0, } },
{ { 0, }, { 0, } },
0, 0,
0, 0,
0, 0,
"", "", { 0 }, { 0 },
0, 0
},
sizeof(struct arpt_entry),
sizeof(struct arpt_standard),
0,
{ 0, 0 }, { } },
{ { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 }
}
},
/* ERROR */
{
{
{
{ 0 }, { 0 }, { 0 }, { 0 },
0, 0,
{ { 0, }, { 0, } },
{ { 0, }, { 0, } },
0, 0,
0, 0,
0, 0,
"", "", { 0 }, { 0 },
0, 0
},
sizeof(struct arpt_entry),
sizeof(struct arpt_error),
0,
{ 0, 0 }, { } },
{ { { { ARPT_ALIGN(sizeof(struct arpt_error_target)), ARPT_ERROR_TARGET } },
{ } },
"ERROR"
}
}
}; };
static struct arpt_table packet_filter = { static struct arpt_table packet_filter = {

View File

@ -26,53 +26,29 @@ static struct
struct ipt_replace repl; struct ipt_replace repl;
struct ipt_standard entries[3]; struct ipt_standard entries[3];
struct ipt_error term; struct ipt_error term;
} initial_table __initdata } initial_table __initdata = {
= { { "filter", FILTER_VALID_HOOKS, 4, .repl = {
sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), .name = "filter",
{ [NF_IP_LOCAL_IN] = 0, .valid_hooks = FILTER_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
.hook_entry = {
[NF_IP_LOCAL_IN] = 0,
[NF_IP_FORWARD] = sizeof(struct ipt_standard), [NF_IP_FORWARD] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
{ [NF_IP_LOCAL_IN] = 0,
[NF_IP_FORWARD] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
0, NULL, { } },
{
/* LOCAL_IN */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* FORWARD */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } }
}, },
/* ERROR */ .underflow = {
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, [NF_IP_LOCAL_IN] = 0,
0, [NF_IP_FORWARD] = sizeof(struct ipt_standard),
sizeof(struct ipt_entry), [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
sizeof(struct ipt_error), },
0, { 0, 0 }, { } }, },
{ { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, .entries = {
{ } }, IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
"ERROR" IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
} IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
} },
.term = IPT_ERROR_INIT, /* ERROR */
}; };
static struct xt_table packet_filter = { static struct xt_table packet_filter = {
@ -105,7 +81,8 @@ ipt_local_out_hook(unsigned int hook,
if ((*pskb)->len < sizeof(struct iphdr) if ((*pskb)->len < sizeof(struct iphdr)
|| ip_hdrlen(*pskb) < sizeof(struct iphdr)) { || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
if (net_ratelimit()) if (net_ratelimit())
printk("ipt_hook: happy cracking.\n"); printk("iptable_filter: ignoring short SOCK_RAW "
"packet.\n");
return NF_ACCEPT; return NF_ACCEPT;
} }

View File

@ -33,73 +33,35 @@ static struct
struct ipt_replace repl; struct ipt_replace repl;
struct ipt_standard entries[5]; struct ipt_standard entries[5];
struct ipt_error term; struct ipt_error term;
} initial_table __initdata } initial_table __initdata = {
= { { "mangle", MANGLE_VALID_HOOKS, 6, .repl = {
sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error), .name = "mangle",
{ [NF_IP_PRE_ROUTING] = 0, .valid_hooks = MANGLE_VALID_HOOKS,
.num_entries = 6,
.size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
.hook_entry = {
[NF_IP_PRE_ROUTING] = 0,
[NF_IP_LOCAL_IN] = sizeof(struct ipt_standard), [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard),
[NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2, [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2,
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3, [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4 }, [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4,
{ [NF_IP_PRE_ROUTING] = 0,
[NF_IP_LOCAL_IN] = sizeof(struct ipt_standard),
[NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2,
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4 },
0, NULL, { } },
{
/* PRE_ROUTING */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_IN */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* FORWARD */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* POST_ROUTING */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
}, },
/* ERROR */ .underflow = {
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, [NF_IP_PRE_ROUTING] = 0,
0, [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard),
sizeof(struct ipt_entry), [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2,
sizeof(struct ipt_error), [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
0, { 0, 0 }, { } }, [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4,
{ { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, },
{ } }, },
"ERROR" .entries = {
} IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
} IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
},
.term = IPT_ERROR_INIT, /* ERROR */
}; };
static struct xt_table packet_mangler = { static struct xt_table packet_mangler = {
@ -138,7 +100,8 @@ ipt_local_hook(unsigned int hook,
if ((*pskb)->len < sizeof(struct iphdr) if ((*pskb)->len < sizeof(struct iphdr)
|| ip_hdrlen(*pskb) < sizeof(struct iphdr)) { || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
if (net_ratelimit()) if (net_ratelimit())
printk("ipt_hook: happy cracking.\n"); printk("iptable_mangle: ignoring short SOCK_RAW "
"packet.\n");
return NF_ACCEPT; return NF_ACCEPT;
} }

View File

@ -5,6 +5,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <net/ip.h>
#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) #define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
@ -21,62 +22,18 @@ static struct
.size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), .size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
.hook_entry = { .hook_entry = {
[NF_IP_PRE_ROUTING] = 0, [NF_IP_PRE_ROUTING] = 0,
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) }, [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard)
},
.underflow = { .underflow = {
[NF_IP_PRE_ROUTING] = 0, [NF_IP_PRE_ROUTING] = 0,
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) }, [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard)
},
}, },
.entries = { .entries = {
/* PRE_ROUTING */ IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
{ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
}, },
.target = { .term = IPT_ERROR_INIT, /* ERROR */
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* LOCAL_OUT */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
},
/* ERROR */
.term = {
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_error),
},
.target = {
.target = {
.u = {
.user = {
.target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
.name = IPT_ERROR_TARGET,
},
},
},
.errorname = "ERROR",
},
}
}; };
static struct xt_table packet_raw = { static struct xt_table packet_raw = {
@ -98,6 +55,24 @@ ipt_hook(unsigned int hook,
return ipt_do_table(pskb, hook, in, out, &packet_raw); return ipt_do_table(pskb, hook, in, out, &packet_raw);
} }
static unsigned int
ipt_local_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
if ((*pskb)->len < sizeof(struct iphdr) ||
ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("iptable_raw: ignoring short SOCK_RAW"
"packet.\n");
return NF_ACCEPT;
}
return ipt_do_table(pskb, hook, in, out, &packet_raw);
}
/* 'raw' is the very first table. */ /* 'raw' is the very first table. */
static struct nf_hook_ops ipt_ops[] = { static struct nf_hook_ops ipt_ops[] = {
{ {
@ -108,7 +83,7 @@ static struct nf_hook_ops ipt_ops[] = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
{ {
.hook = ipt_hook, .hook = ipt_local_hook,
.pf = PF_INET, .pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT, .hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_RAW, .priority = NF_IP_PRI_RAW,

View File

@ -46,77 +46,20 @@ static struct
.hook_entry = { .hook_entry = {
[NF_IP_PRE_ROUTING] = 0, [NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
},
.underflow = { .underflow = {
[NF_IP_PRE_ROUTING] = 0, [NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
},
}, },
.entries = { .entries = {
/* PRE_ROUTING */ IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
{ IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
.entry = { IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
}, },
.target = { .term = IPT_ERROR_INIT, /* ERROR */
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* POST_ROUTING */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* LOCAL_OUT */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
},
/* ERROR */
.term = {
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_error),
},
.target = {
.target = {
.u = {
.user = {
.target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
.name = IPT_ERROR_TARGET,
},
},
},
.errorname = "ERROR",
},
}
}; };
static struct xt_table nat_table = { static struct xt_table nat_table = {
@ -230,9 +173,7 @@ static int ipt_dnat_checkentry(const char *tablename,
} }
inline unsigned int inline unsigned int
alloc_null_binding(struct nf_conn *ct, alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
struct nf_nat_info *info,
unsigned int hooknum)
{ {
/* Force range to this IP; let proto decide mapping for /* Force range to this IP; let proto decide mapping for
per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
@ -251,9 +192,7 @@ alloc_null_binding(struct nf_conn *ct,
} }
unsigned int unsigned int
alloc_null_binding_confirmed(struct nf_conn *ct, alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
struct nf_nat_info *info,
unsigned int hooknum)
{ {
__be32 ip __be32 ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
@ -275,8 +214,7 @@ int nf_nat_rule_find(struct sk_buff **pskb,
unsigned int hooknum, unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
struct nf_conn *ct, struct nf_conn *ct)
struct nf_nat_info *info)
{ {
int ret; int ret;
@ -285,7 +223,7 @@ int nf_nat_rule_find(struct sk_buff **pskb,
if (ret == NF_ACCEPT) { if (ret == NF_ACCEPT) {
if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
/* NUL mapping */ /* NUL mapping */
ret = alloc_null_binding(ct, info, hooknum); ret = alloc_null_binding(ct, hooknum);
} }
return ret; return ret;
} }

View File

@ -80,7 +80,6 @@ nf_nat_fn(unsigned int hooknum,
struct nf_conn *ct; struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn_nat *nat; struct nf_conn_nat *nat;
struct nf_nat_info *info;
/* maniptype == SRC for postrouting. */ /* maniptype == SRC for postrouting. */
enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
@ -129,7 +128,6 @@ nf_nat_fn(unsigned int hooknum,
} }
/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
case IP_CT_NEW: case IP_CT_NEW:
info = &nat->info;
/* Seen it before? This can happen for loopback, retrans, /* Seen it before? This can happen for loopback, retrans,
or local packets.. */ or local packets.. */
@ -138,14 +136,13 @@ nf_nat_fn(unsigned int hooknum,
if (unlikely(nf_ct_is_confirmed(ct))) if (unlikely(nf_ct_is_confirmed(ct)))
/* NAT module was loaded late */ /* NAT module was loaded late */
ret = alloc_null_binding_confirmed(ct, info, ret = alloc_null_binding_confirmed(ct, hooknum);
hooknum);
else if (hooknum == NF_IP_LOCAL_IN) else if (hooknum == NF_IP_LOCAL_IN)
/* LOCAL_IN hook doesn't have a chain! */ /* LOCAL_IN hook doesn't have a chain! */
ret = alloc_null_binding(ct, info, hooknum); ret = alloc_null_binding(ct, hooknum);
else else
ret = nf_nat_rule_find(pskb, hooknum, in, out, ret = nf_nat_rule_find(pskb, hooknum, in, out,
ct, info); ct);
if (ret != NF_ACCEPT) { if (ret != NF_ACCEPT) {
return ret; return ret;
@ -160,10 +157,8 @@ nf_nat_fn(unsigned int hooknum,
/* ESTABLISHED */ /* ESTABLISHED */
NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
info = &nat->info;
} }
NF_CT_ASSERT(info);
return nf_nat_packet(ct, ctinfo, hooknum, pskb); return nf_nat_packet(ct, ctinfo, hooknum, pskb);
} }

View File

@ -118,15 +118,15 @@ static int udp_port_rover;
* Note about this hash function : * Note about this hash function :
* Typical use is probably daddr = 0, only dport is going to vary hash * Typical use is probably daddr = 0, only dport is going to vary hash
*/ */
static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr) static inline unsigned int udp_hash_port(__u16 port)
{ {
addr ^= addr >> 16; return port;
addr ^= addr >> 8;
return port ^ addr;
} }
static inline int __udp_lib_port_inuse(unsigned int hash, int port, static inline int __udp_lib_port_inuse(unsigned int hash, int port,
__be32 daddr, struct hlist_head udptable[]) const struct sock *this_sk,
struct hlist_head udptable[],
const struct udp_get_port_ops *ops)
{ {
struct sock *sk; struct sock *sk;
struct hlist_node *node; struct hlist_node *node;
@ -138,7 +138,10 @@ static inline int __udp_lib_port_inuse(unsigned int hash, int port,
inet = inet_sk(sk); inet = inet_sk(sk);
if (inet->num != port) if (inet->num != port)
continue; continue;
if (inet->rcv_saddr == daddr) if (this_sk) {
if (ops->saddr_cmp(sk, this_sk))
return 1;
} else if (ops->saddr_any(sk))
return 1; return 1;
} }
return 0; return 0;
@ -151,12 +154,11 @@ static inline int __udp_lib_port_inuse(unsigned int hash, int port,
* @snum: port number to look up * @snum: port number to look up
* @udptable: hash list table, must be of UDP_HTABLE_SIZE * @udptable: hash list table, must be of UDP_HTABLE_SIZE
* @port_rover: pointer to record of last unallocated port * @port_rover: pointer to record of last unallocated port
* @saddr_comp: AF-dependent comparison of bound local IP addresses * @ops: AF-dependent address operations
*/ */
int __udp_lib_get_port(struct sock *sk, unsigned short snum, int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_head udptable[], int *port_rover, struct hlist_head udptable[], int *port_rover,
int (*saddr_comp)(const struct sock *sk1, const struct udp_get_port_ops *ops)
const struct sock *sk2 ) )
{ {
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
@ -176,8 +178,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
int size; int size;
hash = hash_port_and_addr(result, hash = ops->hash_port_and_rcv_saddr(result, sk);
inet_sk(sk)->rcv_saddr);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
if (hlist_empty(head)) { if (hlist_empty(head)) {
if (result > sysctl_local_port_range[1]) if (result > sysctl_local_port_range[1])
@ -203,17 +204,16 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
result = sysctl_local_port_range[0] result = sysctl_local_port_range[0]
+ ((result - sysctl_local_port_range[0]) & + ((result - sysctl_local_port_range[0]) &
(UDP_HTABLE_SIZE - 1)); (UDP_HTABLE_SIZE - 1));
hash = hash_port_and_addr(result, 0); hash = udp_hash_port(result);
if (__udp_lib_port_inuse(hash, result, if (__udp_lib_port_inuse(hash, result,
0, udptable)) NULL, udptable, ops))
continue; continue;
if (!inet_sk(sk)->rcv_saddr) if (ops->saddr_any(sk))
break; break;
hash = hash_port_and_addr(result, hash = ops->hash_port_and_rcv_saddr(result, sk);
inet_sk(sk)->rcv_saddr);
if (! __udp_lib_port_inuse(hash, result, if (! __udp_lib_port_inuse(hash, result,
inet_sk(sk)->rcv_saddr, udptable)) sk, udptable, ops))
break; break;
} }
if (i >= (1 << 16) / UDP_HTABLE_SIZE) if (i >= (1 << 16) / UDP_HTABLE_SIZE)
@ -221,7 +221,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
gotit: gotit:
*port_rover = snum = result; *port_rover = snum = result;
} else { } else {
hash = hash_port_and_addr(snum, 0); hash = udp_hash_port(snum);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head) sk_for_each(sk2, node, head)
@ -231,12 +231,11 @@ gotit:
(!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_reuse || !sk->sk_reuse) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
(*saddr_comp)(sk, sk2)) ops->saddr_cmp(sk, sk2))
goto fail; goto fail;
if (inet_sk(sk)->rcv_saddr) { if (!ops->saddr_any(sk)) {
hash = hash_port_and_addr(snum, hash = ops->hash_port_and_rcv_saddr(snum, sk);
inet_sk(sk)->rcv_saddr);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head) sk_for_each(sk2, node, head)
@ -248,7 +247,7 @@ gotit:
!sk->sk_bound_dev_if || !sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if == sk2->sk_bound_dev_if ==
sk->sk_bound_dev_if) && sk->sk_bound_dev_if) &&
(*saddr_comp)(sk, sk2)) ops->saddr_cmp(sk, sk2))
goto fail; goto fail;
} }
} }
@ -266,12 +265,12 @@ fail:
} }
int udp_get_port(struct sock *sk, unsigned short snum, int udp_get_port(struct sock *sk, unsigned short snum,
int (*scmp)(const struct sock *, const struct sock *)) const struct udp_get_port_ops *ops)
{ {
return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, ops);
} }
int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
{ {
struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
@ -280,9 +279,33 @@ int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
inet1->rcv_saddr == inet2->rcv_saddr )); inet1->rcv_saddr == inet2->rcv_saddr ));
} }
static int ipv4_rcv_saddr_any(const struct sock *sk)
{
return !inet_sk(sk)->rcv_saddr;
}
static inline unsigned int ipv4_hash_port_and_addr(__u16 port, __be32 addr)
{
addr ^= addr >> 16;
addr ^= addr >> 8;
return port ^ addr;
}
static unsigned int ipv4_hash_port_and_rcv_saddr(__u16 port,
const struct sock *sk)
{
return ipv4_hash_port_and_addr(port, inet_sk(sk)->rcv_saddr);
}
const struct udp_get_port_ops udp_ipv4_ops = {
.saddr_cmp = ipv4_rcv_saddr_equal,
.saddr_any = ipv4_rcv_saddr_any,
.hash_port_and_rcv_saddr = ipv4_hash_port_and_rcv_saddr,
};
static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
{ {
return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); return udp_get_port(sk, snum, &udp_ipv4_ops);
} }
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
@ -297,8 +320,8 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
unsigned int hash, hashwild; unsigned int hash, hashwild;
int score, best = -1, hport = ntohs(dport); int score, best = -1, hport = ntohs(dport);
hash = hash_port_and_addr(hport, daddr); hash = ipv4_hash_port_and_addr(hport, daddr);
hashwild = hash_port_and_addr(hport, 0); hashwild = udp_hash_port(hport);
read_lock(&udp_hash_lock); read_lock(&udp_hash_lock);
@ -1198,8 +1221,8 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
struct sock *sk, *skw, *sknext; struct sock *sk, *skw, *sknext;
int dif; int dif;
int hport = ntohs(uh->dest); int hport = ntohs(uh->dest);
unsigned int hash = hash_port_and_addr(hport, daddr); unsigned int hash = ipv4_hash_port_and_addr(hport, daddr);
unsigned int hashwild = hash_port_and_addr(hport, 0); unsigned int hashwild = udp_hash_port(hport);
dif = skb->dev->ifindex; dif = skb->dev->ifindex;

View File

@ -5,14 +5,14 @@
#include <net/protocol.h> #include <net/protocol.h>
#include <net/inet_common.h> #include <net/inet_common.h>
extern const struct udp_get_port_ops udp_ipv4_ops;
extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int );
extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, extern int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_head udptable[], int *port_rover, struct hlist_head udptable[], int *port_rover,
int (*)(const struct sock*,const struct sock*)); const struct udp_get_port_ops *ops);
extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *);
extern int udp_setsockopt(struct sock *sk, int level, int optname, extern int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen); char __user *optval, int optlen);

View File

@ -19,14 +19,15 @@ struct hlist_head udplite_hash[UDP_HTABLE_SIZE];
static int udplite_port_rover; static int udplite_port_rover;
int udplite_get_port(struct sock *sk, unsigned short p, int udplite_get_port(struct sock *sk, unsigned short p,
int (*c)(const struct sock *, const struct sock *)) const struct udp_get_port_ops *ops)
{ {
return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); return __udp_lib_get_port(sk, p, udplite_hash,
&udplite_port_rover, ops);
} }
static int udplite_v4_get_port(struct sock *sk, unsigned short snum) static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
{ {
return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); return udplite_get_port(sk, snum, &udp_ipv4_ops);
} }
static int udplite_rcv(struct sk_buff *skb) static int udplite_rcv(struct sk_buff *skb)

View File

@ -4204,6 +4204,10 @@ int __init addrconf_init(void)
return err; return err;
ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev); ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev);
ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev);
#endif
register_netdevice_notifier(&ipv6_dev_notf); register_netdevice_notifier(&ipv6_dev_notf);

View File

@ -660,6 +660,14 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
Hop-by-hop options. Hop-by-hop options.
**********************************/ **********************************/
/*
* Note: we cannot rely on skb->dst before we assign it in ip6_route_input().
*/
static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
{
return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev);
}
/* Router Alert as of RFC 2711 */ /* Router Alert as of RFC 2711 */
static int ipv6_hop_ra(struct sk_buff **skbp, int optoff) static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
@ -688,25 +696,25 @@ static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
nh[optoff+1]); nh[optoff+1]);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IP6_INC_STATS_BH(ipv6_skb_idev(skb),
IPSTATS_MIB_INHDRERRORS); IPSTATS_MIB_INHDRERRORS);
goto drop; goto drop;
} }
pkt_len = ntohl(*(__be32 *)(nh + optoff + 2)); pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
if (pkt_len <= IPV6_MAXPLEN) { if (pkt_len <= IPV6_MAXPLEN) {
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
return 0; return 0;
} }
if (ipv6_hdr(skb)->payload_len) { if (ipv6_hdr(skb)->payload_len) {
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
return 0; return 0;
} }
if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS); IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);
goto drop; goto drop;
} }

View File

@ -463,10 +463,17 @@ int ip6_forward(struct sk_buff *skb)
*/ */
if (xrlim_allow(dst, 1*HZ)) if (xrlim_allow(dst, 1*HZ))
ndisc_send_redirect(skb, n, target); ndisc_send_redirect(skb, n, target);
} else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK } else {
|IPV6_ADDR_LINKLOCAL)) { int addrtype = ipv6_addr_type(&hdr->saddr);
/* This check is security critical. */ /* This check is security critical. */
if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK))
goto error; goto error;
if (addrtype & IPV6_ADDR_LINKLOCAL) {
icmpv6_send(skb, ICMPV6_DEST_UNREACH,
ICMPV6_NOT_NEIGHBOUR, 0, skb->dev);
goto error;
}
} }
if (skb->len > dst_mtu(dst)) { if (skb->len > dst_mtu(dst)) {

View File

@ -24,53 +24,29 @@ static struct
struct ip6t_replace repl; struct ip6t_replace repl;
struct ip6t_standard entries[3]; struct ip6t_standard entries[3];
struct ip6t_error term; struct ip6t_error term;
} initial_table __initdata } initial_table __initdata = {
= { { "filter", FILTER_VALID_HOOKS, 4, .repl = {
sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), .name = "filter",
{ [NF_IP6_LOCAL_IN] = 0, .valid_hooks = FILTER_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
.hook_entry = {
[NF_IP6_LOCAL_IN] = 0,
[NF_IP6_FORWARD] = sizeof(struct ip6t_standard), [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 }, [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
{ [NF_IP6_LOCAL_IN] = 0,
[NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 },
0, NULL, { } },
{
/* LOCAL_IN */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* FORWARD */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } }
}, },
/* ERROR */ .underflow = {
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, [NF_IP6_LOCAL_IN] = 0,
0, [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
sizeof(struct ip6t_entry), [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
sizeof(struct ip6t_error), },
0, { 0, 0 }, { } }, },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, .entries = {
{ } }, IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
"ERROR" IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
} IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
} },
.term = IP6T_ERROR_INIT, /* ERROR */
}; };
static struct xt_table packet_filter = { static struct xt_table packet_filter = {

View File

@ -32,73 +32,35 @@ static struct
struct ip6t_replace repl; struct ip6t_replace repl;
struct ip6t_standard entries[5]; struct ip6t_standard entries[5];
struct ip6t_error term; struct ip6t_error term;
} initial_table __initdata } initial_table __initdata = {
= { { "mangle", MANGLE_VALID_HOOKS, 6, .repl = {
sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), .name = "mangle",
{ [NF_IP6_PRE_ROUTING] = 0, .valid_hooks = MANGLE_VALID_HOOKS,
.num_entries = 6,
.size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
.hook_entry = {
[NF_IP6_PRE_ROUTING] = 0,
[NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard), [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard),
[NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2, [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2,
[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
[NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4}, [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4,
{ [NF_IP6_PRE_ROUTING] = 0,
[NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard),
[NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2,
[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
[NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4},
0, NULL, { } },
{
/* PRE_ROUTING */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_IN */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* FORWARD */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* POST_ROUTING */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
0, { 0, 0 }, { } },
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } }
}, },
/* ERROR */ .underflow = {
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, [NF_IP6_PRE_ROUTING] = 0,
0, [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard),
sizeof(struct ip6t_entry), [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2,
sizeof(struct ip6t_error), [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
0, { 0, 0 }, { } }, [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4,
{ { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, },
{ } }, },
"ERROR" .entries = {
} IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
} IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
},
.term = IP6T_ERROR_INIT, /* ERROR */
}; };
static struct xt_table packet_mangler = { static struct xt_table packet_mangler = {

View File

@ -35,56 +35,10 @@ static struct
}, },
}, },
.entries = { .entries = {
/* PRE_ROUTING */ IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
{ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
.entry = {
.target_offset = sizeof(struct ip6t_entry),
.next_offset = sizeof(struct ip6t_standard),
}, },
.target = { .term = IP6T_ERROR_INIT, /* ERROR */
.target = {
.u = {
.target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* LOCAL_OUT */
{
.entry = {
.target_offset = sizeof(struct ip6t_entry),
.next_offset = sizeof(struct ip6t_standard),
},
.target = {
.target = {
.u = {
.target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
},
/* ERROR */
.term = {
.entry = {
.target_offset = sizeof(struct ip6t_entry),
.next_offset = sizeof(struct ip6t_error),
},
.target = {
.target = {
.u = {
.user = {
.target_size = IP6T_ALIGN(sizeof(struct ip6t_error_target)),
.name = IP6T_ERROR_TARGET,
},
},
},
.errorname = "ERROR",
},
}
}; };
static struct xt_table packet_raw = { static struct xt_table packet_raw = {

View File

@ -52,9 +52,28 @@
DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
static int ipv6_rcv_saddr_any(const struct sock *sk)
{
struct ipv6_pinfo *np = inet6_sk(sk);
return ipv6_addr_any(&np->rcv_saddr);
}
static unsigned int ipv6_hash_port_and_rcv_saddr(__u16 port,
const struct sock *sk)
{
return port;
}
const struct udp_get_port_ops udp_ipv6_ops = {
.saddr_cmp = ipv6_rcv_saddr_equal,
.saddr_any = ipv6_rcv_saddr_any,
.hash_port_and_rcv_saddr = ipv6_hash_port_and_rcv_saddr,
};
static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
{ {
return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); return udp_get_port(sk, snum, &udp_ipv6_ops);
} }
static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,

View File

@ -6,6 +6,8 @@
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/inet_common.h> #include <net/inet_common.h>
extern const struct udp_get_port_ops udp_ipv6_ops;
extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int ); extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int );
extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
int , int , int , __be32 , struct hlist_head []); int , int , int , __be32 , struct hlist_head []);

View File

@ -37,7 +37,7 @@ static struct inet6_protocol udplitev6_protocol = {
static int udplite_v6_get_port(struct sock *sk, unsigned short snum) static int udplite_v6_get_port(struct sock *sk, unsigned short snum)
{ {
return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); return udplite_get_port(sk, snum, &udp_ipv6_ops);
} }
struct proto udplitev6_prot = { struct proto udplitev6_prot = {

View File

@ -17,6 +17,7 @@
* scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
* SSID) * SSID)
*/ */
#include <linux/delay.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
@ -27,7 +28,6 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/delay.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"

View File

@ -299,7 +299,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
{ {
struct nf_conn *ct = (struct nf_conn *)nfct; struct nf_conn *ct = (struct nf_conn *)nfct;
struct nf_conn_help *help = nfct_help(ct); struct nf_conn_help *help = nfct_help(ct);
struct nf_conntrack_l3proto *l3proto;
struct nf_conntrack_l4proto *l4proto; struct nf_conntrack_l4proto *l4proto;
typeof(nf_conntrack_destroyed) destroyed; typeof(nf_conntrack_destroyed) destroyed;
@ -317,10 +316,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
* destroy_conntrack() MUST NOT be called with a write lock * destroy_conntrack() MUST NOT be called with a write lock
* to nf_conntrack_lock!!! -HW */ * to nf_conntrack_lock!!! -HW */
rcu_read_lock(); rcu_read_lock();
l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
if (l3proto && l3proto->destroy)
l3proto->destroy(ct);
l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num,
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
if (l4proto && l4proto->destroy) if (l4proto && l4proto->destroy)
@ -893,8 +888,13 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
NF_CT_DUMP_TUPLE(newreply); NF_CT_DUMP_TUPLE(newreply);
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
if (!ct->master && help && help->expecting == 0) if (!ct->master && help && help->expecting == 0) {
help->helper = __nf_ct_helper_find(newreply); struct nf_conntrack_helper *helper;
helper = __nf_ct_helper_find(newreply);
if (helper)
memset(&help->help, 0, sizeof(help->help));
help->helper = helper;
}
write_unlock_bh(&nf_conntrack_lock); write_unlock_bh(&nf_conntrack_lock);
} }
EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);

View File

@ -830,11 +830,6 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
char *helpname; char *helpname;
int err; int err;
if (!help) {
/* FIXME: we need to reallocate and rehash */
return -EBUSY;
}
/* don't change helper of sibling connections */ /* don't change helper of sibling connections */
if (ct->master) if (ct->master)
return -EINVAL; return -EINVAL;
@ -843,25 +838,34 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
if (err < 0) if (err < 0)
return err; return err;
helper = __nf_conntrack_helper_find_byname(helpname); if (!strcmp(helpname, "")) {
if (!helper) { if (help && help->helper) {
if (!strcmp(helpname, ""))
helper = NULL;
else
return -EINVAL;
}
if (help->helper) {
if (!helper) {
/* we had a helper before ... */ /* we had a helper before ... */
nf_ct_remove_expectations(ct); nf_ct_remove_expectations(ct);
help->helper = NULL; help->helper = NULL;
} else {
/* need to zero data of old helper */
memset(&help->help, 0, sizeof(help->help));
}
} }
return 0;
}
if (!help) {
/* FIXME: we need to reallocate and rehash */
return -EBUSY;
}
helper = __nf_conntrack_helper_find_byname(helpname);
if (helper == NULL)
return -EINVAL;
if (help->helper == helper)
return 0;
if (help->helper)
/* we had a helper before ... */
nf_ct_remove_expectations(ct);
/* need to zero data of old helper */
memset(&help->help, 0, sizeof(help->help));
help->helper = helper; help->helper = helper;
return 0; return 0;

View File

@ -134,12 +134,66 @@ static void destroy(const struct xt_match *match, void *matchinfo)
nf_ct_l3proto_module_put(match->family); nf_ct_l3proto_module_put(match->family);
} }
#ifdef CONFIG_COMPAT
struct compat_xt_conntrack_info
{
compat_uint_t statemask;
compat_uint_t statusmask;
struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX];
struct in_addr sipmsk[IP_CT_DIR_MAX];
struct in_addr dipmsk[IP_CT_DIR_MAX];
compat_ulong_t expires_min;
compat_ulong_t expires_max;
u_int8_t flags;
u_int8_t invflags;
};
static void compat_from_user(void *dst, void *src)
{
struct compat_xt_conntrack_info *cm = src;
struct xt_conntrack_info m = {
.statemask = cm->statemask,
.statusmask = cm->statusmask,
.expires_min = cm->expires_min,
.expires_max = cm->expires_max,
.flags = cm->flags,
.invflags = cm->invflags,
};
memcpy(m.tuple, cm->tuple, sizeof(m.tuple));
memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk));
memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk));
memcpy(dst, &m, sizeof(m));
}
static int compat_to_user(void __user *dst, void *src)
{
struct xt_conntrack_info *m = src;
struct compat_xt_conntrack_info cm = {
.statemask = m->statemask,
.statusmask = m->statusmask,
.expires_min = m->expires_min,
.expires_max = m->expires_max,
.flags = m->flags,
.invflags = m->invflags,
};
memcpy(cm.tuple, m->tuple, sizeof(cm.tuple));
memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk));
memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk));
return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
}
#endif
static struct xt_match conntrack_match = { static struct xt_match conntrack_match = {
.name = "conntrack", .name = "conntrack",
.match = match, .match = match,
.checkentry = checkentry, .checkentry = checkentry,
.destroy = destroy, .destroy = destroy,
.matchsize = sizeof(struct xt_conntrack_info), .matchsize = sizeof(struct xt_conntrack_info),
#ifdef CONFIG_COMPAT
.compatsize = sizeof(struct compat_xt_conntrack_info),
.compat_from_user = compat_from_user,
.compat_to_user = compat_to_user,
#endif
.family = AF_INET, .family = AF_INET,
.me = THIS_MODULE, .me = THIS_MODULE,
}; };

View File

@ -71,12 +71,9 @@ void qdisc_unlock_tree(struct net_device *dev)
/* Kick device. /* Kick device.
Note, that this procedure can be called by a watchdog timer, so that
we do not check dev->tbusy flag here.
Returns: 0 - queue is empty. Returns: 0 - queue is empty or throttled.
>0 - queue is not empty, but throttled. >0 - queue is not empty.
<0 - queue is not empty. Device is throttled, if dev->tbusy != 0.
NOTE: Called under dev->queue_lock with locally disabled BH. NOTE: Called under dev->queue_lock with locally disabled BH.
*/ */
@ -115,7 +112,7 @@ static inline int qdisc_restart(struct net_device *dev)
kfree_skb(skb); kfree_skb(skb);
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name); printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
return -1; goto out;
} }
__get_cpu_var(netdev_rx_stat).cpu_collision++; __get_cpu_var(netdev_rx_stat).cpu_collision++;
goto requeue; goto requeue;
@ -135,10 +132,12 @@ static inline int qdisc_restart(struct net_device *dev)
netif_tx_unlock(dev); netif_tx_unlock(dev);
} }
spin_lock(&dev->queue_lock); spin_lock(&dev->queue_lock);
return -1; q = dev->qdisc;
goto out;
} }
if (ret == NETDEV_TX_LOCKED && nolock) { if (ret == NETDEV_TX_LOCKED && nolock) {
spin_lock(&dev->queue_lock); spin_lock(&dev->queue_lock);
q = dev->qdisc;
goto collision; goto collision;
} }
} }
@ -163,26 +162,28 @@ static inline int qdisc_restart(struct net_device *dev)
*/ */
requeue: requeue:
if (skb->next) if (unlikely(q == &noop_qdisc))
kfree_skb(skb);
else if (skb->next)
dev->gso_skb = skb; dev->gso_skb = skb;
else else
q->ops->requeue(skb, q); q->ops->requeue(skb, q);
netif_schedule(dev); netif_schedule(dev);
return 1; return 0;
} }
out:
BUG_ON((int) q->q.qlen < 0); BUG_ON((int) q->q.qlen < 0);
return q->q.qlen; return q->q.qlen;
} }
void __qdisc_run(struct net_device *dev) void __qdisc_run(struct net_device *dev)
{ {
if (unlikely(dev->qdisc == &noop_qdisc)) do {
goto out; if (!qdisc_restart(dev))
break;
} while (!netif_queue_stopped(dev));
while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
/* NOTHING */;
out:
clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
} }
@ -544,6 +545,7 @@ void dev_activate(struct net_device *dev)
void dev_deactivate(struct net_device *dev) void dev_deactivate(struct net_device *dev)
{ {
struct Qdisc *qdisc; struct Qdisc *qdisc;
struct sk_buff *skb;
spin_lock_bh(&dev->queue_lock); spin_lock_bh(&dev->queue_lock);
qdisc = dev->qdisc; qdisc = dev->qdisc;
@ -551,8 +553,12 @@ void dev_deactivate(struct net_device *dev)
qdisc_reset(qdisc); qdisc_reset(qdisc);
skb = dev->gso_skb;
dev->gso_skb = NULL;
spin_unlock_bh(&dev->queue_lock); spin_unlock_bh(&dev->queue_lock);
kfree_skb(skb);
dev_watchdog_down(dev); dev_watchdog_down(dev);
/* Wait for outstanding dev_queue_xmit calls. */ /* Wait for outstanding dev_queue_xmit calls. */
@ -561,11 +567,6 @@ void dev_deactivate(struct net_device *dev)
/* Wait for outstanding qdisc_run calls. */ /* Wait for outstanding qdisc_run calls. */
while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
yield(); yield();
if (dev->gso_skb) {
kfree_skb(dev->gso_skb);
dev->gso_skb = NULL;
}
} }
void dev_init_scheduler(struct net_device *dev) void dev_init_scheduler(struct net_device *dev)

View File

@ -94,14 +94,13 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
struct net_device *dev = sch->dev; struct net_device *dev = sch->dev;
struct teql_sched_data *q = qdisc_priv(sch); struct teql_sched_data *q = qdisc_priv(sch);
if (q->q.qlen < dev->tx_queue_len) {
__skb_queue_tail(&q->q, skb); __skb_queue_tail(&q->q, skb);
if (q->q.qlen <= dev->tx_queue_len) {
sch->bstats.bytes += skb->len; sch->bstats.bytes += skb->len;
sch->bstats.packets++; sch->bstats.packets++;
return 0; return 0;
} }
__skb_unlink(skb, &q->q);
kfree_skb(skb); kfree_skb(skb);
sch->qstats.drops++; sch->qstats.drops++;
return NET_XMIT_DROP; return NET_XMIT_DROP;

View File

@ -4164,6 +4164,7 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
rwlock_t *addr_lock; rwlock_t *addr_lock;
int err = 0; int err = 0;
void *addrs; void *addrs;
void *buf;
int bytes_copied = 0; int bytes_copied = 0;
if (len != sizeof(struct sctp_getaddrs_old)) if (len != sizeof(struct sctp_getaddrs_old))
@ -4217,13 +4218,14 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
} }
} }
buf = addrs;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
memcpy(&temp, &addr->a, sizeof(temp)); memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
memcpy(addrs, &temp, addrlen); memcpy(buf, &temp, addrlen);
to += addrlen; buf += addrlen;
bytes_copied += addrlen; bytes_copied += addrlen;
cnt ++; cnt ++;
if (cnt >= getaddrs.addr_num) break; if (cnt >= getaddrs.addr_num) break;
@ -4266,6 +4268,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
size_t space_left; size_t space_left;
int bytes_copied = 0; int bytes_copied = 0;
void *addrs; void *addrs;
void *buf;
if (len <= sizeof(struct sctp_getaddrs)) if (len <= sizeof(struct sctp_getaddrs))
return -EINVAL; return -EINVAL;
@ -4316,6 +4319,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
} }
} }
buf = addrs;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
memcpy(&temp, &addr->a, sizeof(temp)); memcpy(&temp, &addr->a, sizeof(temp));
@ -4325,8 +4329,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
err = -ENOMEM; /*fixme: right error?*/ err = -ENOMEM; /*fixme: right error?*/
goto error; goto error;
} }
memcpy(addrs, &temp, addrlen); memcpy(buf, &temp, addrlen);
to += addrlen; buf += addrlen;
bytes_copied += addrlen; bytes_copied += addrlen;
cnt ++; cnt ++;
space_left -= addrlen; space_left -= addrlen;
@ -5227,7 +5231,12 @@ int sctp_inet_listen(struct socket *sock, int backlog)
/* Allocate HMAC for generating cookie. */ /* Allocate HMAC for generating cookie. */
if (sctp_hmac_alg) { if (sctp_hmac_alg) {
tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC); tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
if (!tfm) { if (IS_ERR(tfm)) {
if (net_ratelimit()) {
printk(KERN_INFO
"SCTP: failed to load transform for %s: %ld\n",
sctp_hmac_alg, PTR_ERR(tfm));
}
err = -ENOSYS; err = -ENOSYS;
goto out; goto out;
} }

View File

@ -141,11 +141,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
* an ABORT, so we need to include it in the sac_info. * an ABORT, so we need to include it in the sac_info.
*/ */
if (chunk) { if (chunk) {
/* sctp_inqu_pop() has allready pulled off the chunk
* header. We need to put it back temporarily
*/
skb_push(chunk->skb, sizeof(sctp_chunkhdr_t));
/* Copy the chunk data to a new skb and reserve enough /* Copy the chunk data to a new skb and reserve enough
* head room to use as notification. * head room to use as notification.
*/ */
@ -155,9 +150,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
if (!skb) if (!skb)
goto fail; goto fail;
/* put back the chunk header now that we have a copy */
skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb); event = sctp_skb2event(skb);
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
@ -168,7 +160,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
/* Trim the buffer to the right length. */ /* Trim the buffer to the right length. */
skb_trim(skb, sizeof(struct sctp_assoc_change) + skb_trim(skb, sizeof(struct sctp_assoc_change) +
ntohs(chunk->chunk_hdr->length)); ntohs(chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t));
} else { } else {
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, gfp); MSG_NOTIFICATION, gfp);