diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-10 08:46:00 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-10 08:46:00 -0700 |
commit | 460fbf82c0842cad3f3c744c4dcb81978b7829f3 (patch) | |
tree | d19b6d7d18491a8fa423f3ac9f2b422863b8c373 | |
parent | 68491d5892defca59ad4f604cace2b1e30889c14 (diff) | |
parent | b1a7ffcb7a047e99ab02424e651e0492f36095f7 (diff) | |
download | linux-460fbf82c0842cad3f3c744c4dcb81978b7829f3.tar.bz2 |
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: (35 commits)
[IPV6]: Deinline few large functions in inet6 code
[IPV4] ip_fragment: Always compute hash with ipfrag_lock held.
[NETFILTER]: Fix DNAT in LOCAL_OUT
[X25]: Restore skb->dev setting in x25_type_trans().
[NET]: Fix hotplug race during device registration.
[IPV6]: Unexport secure_ipv6_port_ephemeral
[NETFILTER]: Fix build with CONFIG_NETFILTER=y/m on IA64
[NET]: More kzalloc conversions.
[NET] kzalloc: use in alloc_netdev
[PKT_SCHED] act_police: Rename methods.
[TG3]: Speed up SRAM access (2nd version)
[TG3]: Kill some less useful flags
[NETFILTER]: H.323 helper: remove changelog
[NETFILTER]: Convert conntrack/ipt_REJECT to new checksumming functions
[NETFILTER]: Add address family specific checksum helpers
[NETFILTER]: Introduce infrastructure for address family specific operations
[NETFILTER]: Fix IP_NF_CONNTRACK_NETLINK dependency
[NETFILTER]: H.323 helper: add parameter 'default_rrq_ttl'
[NETFILTER]: H.323 helper: make get_h245_addr() static
[NETFILTER]: H.323 helper: change EXPORT_SYMBOL to EXPORT_SYMBOL_GPL
...
71 files changed, 1638 insertions, 1367 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index 86be04b241e1..58f3512c52e1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1584,7 +1584,6 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo return twothirdsMD4Transform(daddr, hash); } -EXPORT_SYMBOL(secure_ipv6_port_ephemeral); #endif #if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6e2ec56cde0b..606243d11793 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: irda-usb.c - * Version: 0.9b + * Version: 0.10 * Description: IrDA-USB Driver * Status: Experimental * Author: Dag Brattli <dag@brattli.net> @@ -9,6 +9,9 @@ * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> * Copyright (C) 2001, Dag Brattli <dag@brattli.net> * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com> + * Copyright (C) 2005, Milan Beno <beno@pobox.sk> + * Copyright (C) 2006, Nick Fedchik <nick@fedchik.org.ua> * * 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 @@ -61,6 +64,7 @@ #include <linux/slab.h> #include <linux/rtnetlink.h> #include <linux/usb.h> +#include <linux/firmware.h> #include "irda-usb.h" @@ -78,8 +82,12 @@ static struct usb_device_id dongles[] = { { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */ + { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, + USB_DEVICE_ID_MATCH_INT_SUBCLASS, .bInterfaceClass = USB_CLASS_APP_SPEC, .bInterfaceSubClass = USB_CLASS_IRDA, .driver_info = IUC_DEFAULT, }, @@ -99,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, dongles); /*------------------------------------------------------------------*/ +static void irda_usb_init_qos(struct irda_usb_cb *self) ; static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); static void irda_usb_disconnect(struct usb_interface *intf); static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); @@ -141,7 +150,24 @@ static void irda_usb_build_header(struct irda_usb_cb *self, __u8 *header, int force) { - /* Set the negotiated link speed */ + /* Here we check if we have an STIR421x chip, + * and if either speed or xbofs (or both) needs + * to be changed. + */ + if (self->capability & IUC_STIR_4210 && + ((self->new_speed != -1) || (self->new_xbofs != -1))) { + + /* With STIR421x, speed and xBOFs must be set at the same + * time, even if only one of them changes. + */ + if (self->new_speed == -1) + self->new_speed = self->speed ; + + if (self->new_xbofs == -1) + self->new_xbofs = self->xbofs ; + } + + /* Set the link speed */ if (self->new_speed != -1) { /* Hum... Ugly hack :-( * Some device are not compliant with the spec and change @@ -191,7 +217,11 @@ static void irda_usb_build_header(struct irda_usb_cb *self, *header = SPEED_4000000; self->new_xbofs = 0; break; - } + case 16000000: + *header = SPEED_16000000; + self->new_xbofs = 0; + break; + } } else /* No change */ *header = 0; @@ -235,6 +265,32 @@ static void irda_usb_build_header(struct irda_usb_cb *self, } } +/* +* calculate turnaround time for SigmaTel header +*/ +static __u8 get_turnaround_time(struct sk_buff *skb) +{ + int turnaround_time = irda_get_mtt(skb); + + if ( turnaround_time == 0 ) + return 0; + else if ( turnaround_time <= 10 ) + return 1; + else if ( turnaround_time <= 50 ) + return 2; + else if ( turnaround_time <= 100 ) + return 3; + else if ( turnaround_time <= 500 ) + return 4; + else if ( turnaround_time <= 1000 ) + return 5; + else if ( turnaround_time <= 5000 ) + return 6; + else + return 7; +} + + /*------------------------------------------------------------------*/ /* * Send a command to change the speed of the dongle @@ -262,12 +318,18 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) /* Set the new speed and xbofs in this fake frame */ irda_usb_build_header(self, frame, 1); + if ( self->capability & IUC_STIR_4210 ) { + if (frame[0] == 0) return ; // do nothing if no change + frame[1] = 0; // other parameters don't change here + frame[2] = 0; + } + /* Submit the 0 length IrDA frame to trigger new speed settings */ usb_fill_bulk_urb(urb, self->usbdev, usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), frame, IRDA_USB_SPEED_MTU, speed_bulk_callback, self); - urb->transfer_buffer_length = USB_IRDA_HEADER; + urb->transfer_buffer_length = self->header_length; urb->transfer_flags = 0; /* Irq disabled -> GFP_ATOMIC */ @@ -383,16 +445,35 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) * allocation will be done lower in skb_push(). * Also, we don't use directly skb_cow(), because it require * headroom >= 16, which force unnecessary copies - Jean II */ - if (skb_headroom(skb) < USB_IRDA_HEADER) { + if (skb_headroom(skb) < self->header_length) { IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__); - if (skb_cow(skb, USB_IRDA_HEADER)) { + if (skb_cow(skb, self->header_length)) { IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__); goto drop; } } /* Change setting for next frame */ - irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0); + + if ( self->capability & IUC_STIR_4210 ) { + __u8 turnaround_time; + __u8* frame; + turnaround_time = get_turnaround_time( skb ); + frame= skb_push(skb, self->header_length); + irda_usb_build_header(self, frame, 0); + frame[2] = turnaround_time; + if ((skb->len != 0) && + ((skb->len % 128) == 0) && + ((skb->len % 512) != 0)) { + /* add extra byte for special SigmaTel feature */ + frame[1] = 1; + skb_put(skb, 1); + } else { + frame[1] = 0; + } + } else { + irda_usb_build_header(self, skb_push(skb, self->header_length), 0); + } /* FIXME: Make macro out of this one */ ((struct irda_skb_cb *)skb->cb)->context = self; @@ -795,7 +876,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) } /* Check for empty frames */ - if (urb->actual_length <= USB_IRDA_HEADER) { + if (urb->actual_length <= self->header_length) { IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__); goto done; } @@ -816,7 +897,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); /* Allocate a new skb */ - newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); + if ( self->capability & IUC_STIR_4210 ) + newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER); + else + newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); + if (!newskb) { self->stats.rx_dropped++; /* We could deliver the current skb, but this would stall @@ -845,7 +930,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) /* Set proper length on skb & remove USB-IrDA header */ skb_put(dataskb, urb->actual_length); - skb_pull(dataskb, USB_IRDA_HEADER); + skb_pull(dataskb, self->header_length); /* Ask the networking layer to queue the packet for the IrDA stack */ dataskb->dev = self->netdev; @@ -937,6 +1022,191 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self) return 0; /* For now */ } + +#define STIR421X_PATCH_PRODUCT_VERSION_STR "Product Version: " +#define STIR421X_PATCH_COMPONENT_VERSION_STR "Component Version: " +#define STIR421X_PATCH_DATA_TAG_STR "STMP" +#define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET 512 /* version info is before here */ +#define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET 512 /* patch image starts before here */ +#define STIR421X_PATCH_FILE_END_OF_HEADER_TAG 0x1A /* marks end of patch file header (PC DOS text file EOF character) */ + +/* + * Known firmware patches for STIR421x dongles + */ +static char * stir421x_patches[] = { + "42101001.sb", + "42101002.sb", +}; + +static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len) +{ + unsigned int version_offset; + unsigned long version_major, version_minor, version_build; + unsigned char * version_start; + int version_found = 0; + + for (version_offset = 0; + version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG; + version_offset++) { + if (!memcmp(patch + version_offset, + STIR421X_PATCH_PRODUCT_VERSION_STR, + sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) { + version_found = 1; + version_start = patch + + version_offset + + sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1; + break; + } + } + + /* We couldn't find a product version on this patch */ + if (!version_found) + return -EINVAL; + + /* Let's check if the product version is dotted */ + if (version_start[3] != '.' || + version_start[7] != '.') + return -EINVAL; + + version_major = simple_strtoul(version_start, NULL, 10); + version_minor = simple_strtoul(version_start + 4, NULL, 10); + version_build = simple_strtoul(version_start + 8, NULL, 10); + + IRDA_DEBUG(2, "%s(), Major: %ld Minor: %ld Build: %ld\n", + __FUNCTION__, + version_major, version_minor, version_build); + + return (((version_major) << 12) + + ((version_minor) << 8) + + ((version_build / 10) << 4) + + (version_build % 10)); + +} + + +static int stir421x_upload_patch (struct irda_usb_cb *self, + unsigned char * patch, + const unsigned int patch_len) +{ + int retval = 0; + int actual_len; + unsigned int i = 0, download_amount = 0; + unsigned char * patch_chunk; + + IRDA_DEBUG (2, "%s(), Uploading STIR421x Patch\n", __FUNCTION__); + + patch_chunk = kzalloc(STIR421X_MAX_PATCH_DOWNLOAD_SIZE, GFP_KERNEL); + if (patch_chunk == NULL) + return -ENOMEM; + + /* break up patch into 1023-byte sections */ + for (i = 0; retval >= 0 && i < patch_len; i += download_amount) { + download_amount = patch_len - i; + if (download_amount > STIR421X_MAX_PATCH_DOWNLOAD_SIZE) + download_amount = STIR421X_MAX_PATCH_DOWNLOAD_SIZE; + + /* download the patch section */ + memcpy(patch_chunk, patch + i, download_amount); + + retval = usb_bulk_msg (self->usbdev, + usb_sndbulkpipe (self->usbdev, + self->bulk_out_ep), + patch_chunk, download_amount, + &actual_len, msecs_to_jiffies (500)); + IRDA_DEBUG (2, "%s(), Sent %u bytes\n", __FUNCTION__, + actual_len); + if (retval == 0) + mdelay(10); + } + + kfree(patch_chunk); + + if (i != patch_len) { + IRDA_ERROR ("%s(), Pushed %d bytes (!= patch_len (%d))\n", + __FUNCTION__, i, patch_len); + retval = -EIO; + } + + if (retval < 0) + /* todo - mark device as not ready */ + IRDA_ERROR ("%s(), STIR421x patch upload failed (%d)\n", + __FUNCTION__, retval); + + return retval; +} + + +static int stir421x_patch_device(struct irda_usb_cb *self) +{ + unsigned int i, patch_found = 0, data_found = 0, data_offset; + int patch_version, ret = 0; + const struct firmware *fw_entry; + + for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) { + if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) { + IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]); + continue; + } + + /* We found a patch from userspace */ + patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size); + + if (patch_version < 0) { + /* Couldn't fetch a version, let's move on to the next file */ + IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__); + ret = patch_version; + release_firmware(fw_entry); + continue; + } + + if (patch_version != self->usbdev->descriptor.bcdDevice) { + /* Patch version and device don't match */ + IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n", + __FUNCTION__, + patch_version, self->usbdev->descriptor.bcdDevice); + ret = -EINVAL; + release_firmware(fw_entry); + continue; + } + + /* If we're here, we've found a correct patch */ + patch_found = 1; + break; + + } + + /* We couldn't find a valid firmware, let's leave */ + if (!patch_found) + return ret; + + /* The actual image starts after the "STMP" keyword */ + for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) { + if (!memcmp(fw_entry->data + data_offset, + STIR421X_PATCH_DATA_TAG_STR, + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) { + IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n", + __FUNCTION__, data_offset); + data_found = 1; + break; + } + } + + /* We couldn't find "STMP" from the header */ + if (!data_found) + return -EINVAL; + + /* Let's upload the patch to the target */ + ret = stir421x_upload_patch(self, + &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)], + fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))); + + release_firmware(fw_entry); + + return ret; + +} + + /********************** IRDA DEVICE CALLBACKS **********************/ /* * Main calls from the IrDA/Network subsystem. @@ -972,6 +1242,11 @@ static int irda_usb_net_open(struct net_device *netdev) return -1; } + if(self->needspatch) { + IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ; + return -EIO ; + } + /* Initialise default speed and xbofs value * (IrLAP will change that soon) */ self->speed = -1; @@ -1050,7 +1325,7 @@ static int irda_usb_net_close(struct net_device *netdev) del_timer(&self->rx_defer_timer); /* Deallocate all the Rx path buffers (URBs and skb) */ - for (i = 0; i < IU_MAX_RX_URBS; i++) { + for (i = 0; i < self->max_rx_urb; i++) { struct urb *urb = self->rx_urb[i]; struct sk_buff *skb = (struct sk_buff *) urb->context; /* Cancel the receive command */ @@ -1426,8 +1701,22 @@ static int irda_usb_probe(struct usb_interface *intf, spin_lock_init(&self->lock); init_timer(&self->rx_defer_timer); + self->capability = id->driver_info; + self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ; + /* Create all of the needed urbs */ - for (i = 0; i < IU_MAX_RX_URBS; i++) { + if (self->capability & IUC_STIR_4210) { + self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS; + self->header_length = USB_IRDA_SIGMATEL_HEADER; + } else { + self->max_rx_urb = IU_MAX_RX_URBS; + self->header_length = USB_IRDA_HEADER; + } + + self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *), + GFP_KERNEL); + + for (i = 0; i < self->max_rx_urb; i++) { self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); if (!self->rx_urb[i]) { goto err_out_1; @@ -1479,17 +1768,28 @@ static int irda_usb_probe(struct usb_interface *intf, goto err_out_3; } + self->usbdev = dev; + /* Find IrDA class descriptor */ irda_desc = irda_usb_find_class_desc(intf); ret = -ENODEV; if (irda_desc == NULL) goto err_out_3; + if (self->needspatch) { + ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), + 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500)); + if (ret < 0) { + IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); + goto err_out_3; + } else { + mdelay(10); + } + } + self->irda_desc = irda_desc; self->present = 1; self->netopen = 0; - self->capability = id->driver_info; - self->usbdev = dev; self->usbintf = intf; /* Allocate the buffer for speed changes */ @@ -1508,6 +1808,28 @@ static int irda_usb_probe(struct usb_interface *intf, IRDA_MESSAGE("IrDA: Registered device %s\n", net->name); usb_set_intfdata(intf, self); + + if (self->needspatch) { + /* Now we fetch and upload the firmware patch */ + ret = stir421x_patch_device(self); + self->needspatch = (ret < 0); + if (ret < 0) { + printk("patch_device failed\n"); + goto err_out_4; + } + + /* replace IrDA class descriptor with what patched device is now reporting */ + irda_desc = irda_usb_find_class_desc (self->usbintf); + if (irda_desc == NULL) { + ret = -ENODEV; + goto err_out_4; + } + if (self->irda_desc) + kfree (self->irda_desc); + self->irda_desc = irda_desc; + irda_usb_init_qos(self); + } + return 0; err_out_4: @@ -1518,7 +1840,7 @@ err_out_3: err_out_2: usb_free_urb(self->tx_urb); err_out_1: - for (i = 0; i < IU_MAX_RX_URBS; i++) { + for (i = 0; i < self->max_rx_urb; i++) { if (self->rx_urb[i]) usb_free_urb(self->rx_urb[i]); } @@ -1571,7 +1893,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) /*netif_device_detach(self->netdev);*/ netif_stop_queue(self->netdev); /* Stop all the receive URBs. Must be synchronous. */ - for (i = 0; i < IU_MAX_RX_URBS; i++) + for (i = 0; i < self->max_rx_urb; i++) usb_kill_urb(self->rx_urb[i]); /* Cancel Tx and speed URB. * Make sure it's synchronous to avoid races. */ @@ -1586,8 +1908,9 @@ static void irda_usb_disconnect(struct usb_interface *intf) self->usbintf = NULL; /* Clean up our urbs */ - for (i = 0; i < IU_MAX_RX_URBS; i++) + for (i = 0; i < self->max_rx_urb; i++) usb_free_urb(self->rx_urb[i]); + kfree(self->rx_urb); /* Clean up Tx and speed URB */ usb_free_urb(self->tx_urb); usb_free_urb(self->speed_urb); @@ -1648,6 +1971,6 @@ module_exit(usb_irda_cleanup); */ module_param(qos_mtt_bits, int, 0); MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); -MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>"); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); +MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>"); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index 4026af42dd47..d833db52cebf 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: irda-usb.h - * Version: 0.9b + * Version: 0.10 * Description: IrDA-USB Driver * Status: Experimental * Author: Dag Brattli <dag@brattli.net> @@ -9,6 +9,9 @@ * Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at> * Copyright (C) 2000, Dag Brattli <dag@brattli.net> * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com> + * Copyright (C) 2005, Milan Beno <beno@pobox.sk> + * Copyright (C) 2006, Nick FEdchik <nick@fedchik.org.ua> * * 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 @@ -31,6 +34,9 @@ #include <net/irda/irda.h> #include <net/irda/irda_device.h> /* struct irlap_cb */ +#define PATCH_FILE_SIZE_MAX 65536 +#define PATCH_FILE_SIZE_MIN 80 + #define RX_COPY_THRESHOLD 200 #define IRDA_USB_MAX_MTU 2051 #define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ @@ -79,15 +85,16 @@ /* Inbound header */ #define MEDIA_BUSY 0x80 -#define SPEED_2400 0x01 -#define SPEED_9600 0x02 -#define SPEED_19200 0x03 -#define SPEED_38400 0x04 -#define SPEED_57600 0x05 -#define SPEED_115200 0x06 -#define SPEED_576000 0x07 -#define SPEED_1152000 0x08 -#define SPEED_4000000 0x09 +#define SPEED_2400 0x01 +#define SPEED_9600 0x02 +#define SPEED_19200 0x03 +#define SPEED_38400 0x04 +#define SPEED_57600 0x05 +#define SPEED_115200 0x06 +#define SPEED_576000 0x07 +#define SPEED_1152000 0x08 +#define SPEED_4000000 0x09 +#define SPEED_16000000 0x0a /* Basic capabilities */ #define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ @@ -100,11 +107,14 @@ #define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ #define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ #define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ +#define IUC_STIR_4210 0x80 /* SigmaTel 4210/4220/4116 VFIR */ /* USB class definitions */ -#define USB_IRDA_HEADER 0x01 -#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ -#define USB_DT_IRDA 0x21 +#define USB_IRDA_HEADER 0x01 +#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ +#define USB_DT_IRDA 0x21 +#define USB_IRDA_SIGMATEL_HEADER 0x03 +#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER) struct irda_class_desc { __u8 bLength; @@ -123,6 +133,7 @@ struct irda_class_desc { * (6.2.5, USB-IrDA class spec 1.0) */ #define IU_REQ_GET_CLASS_DESC 0x06 +#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023 struct irda_usb_cb { struct irda_class_desc *irda_desc; @@ -136,7 +147,8 @@ struct irda_usb_cb { __u16 bulk_out_mtu; /* Max Tx packet size in bytes */ __u8 bulk_int_ep; /* Interrupt Endpoint assignments */ - struct urb *rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */ + __u8 max_rx_urb; + struct urb **rx_urb; /* URBs used to receive data frames */ struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */ struct urb *tx_urb; /* URB used to send data frames */ struct urb *speed_urb; /* URB used to send speed commands */ @@ -157,6 +169,9 @@ struct irda_usb_cb { __u32 speed; /* Current speed */ __s32 new_speed; /* speed we need to set */ + __u8 header_length; /* USB-IrDA frame header size */ + int needspatch; /* device needs firmware patch */ + struct timer_list rx_defer_timer; /* Wait for Rx error to clear */ }; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index ec94ecdb103d..bbcfc8ec35a1 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -11,6 +11,7 @@ * Copyright (c) 2002 Daniele Peri * All Rights Reserved. * Copyright (c) 2002 Jean Tourrilhes + * Copyright (c) 2006 Linus Walleij * * * Based on smc-ircc.c: @@ -61,6 +62,9 @@ #include <linux/spinlock.h> #include <linux/pm.h> +#ifdef CONFIG_PCI +#include <linux/pci.h> +#endif #include <net/irda/wrapper.h> #include <net/irda/irda.h> @@ -100,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); /* Types */ +#ifdef CONFIG_PCI +struct smsc_ircc_subsystem_configuration { + unsigned short vendor; /* PCI vendor ID */ + unsigned short device; /* PCI vendor ID */ + unsigned short subvendor; /* PCI subsystem vendor ID */ + unsigned short subdevice; /* PCI sybsystem device ID */ + unsigned short sir_io; /* I/O port for SIR */ + unsigned short fir_io; /* I/O port for FIR */ + unsigned char fir_irq; /* FIR IRQ */ + unsigned char fir_dma; /* FIR DMA */ + unsigned short cfg_base; /* I/O port for chip configuration */ + int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ + const char *name; /* name shown as info */ +}; +#endif + struct smsc_transceiver { char *name; void (*set_for_speed)(int fir_base, u32 speed); @@ -202,6 +222,16 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); static int __init smsc_superio_fdc(unsigned short cfg_base); static int __init smsc_superio_lpc(unsigned short cfg_base); +#ifdef CONFIG_PCI +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq); +#endif /* Transceivers specific functions */ @@ -353,6 +383,13 @@ static int __init smsc_ircc_init(void) return ret; } +#ifdef CONFIG_PCI + if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { + /* Ignore errors from preconfiguration */ + IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name); + } +#endif + dev_count = 0; if (ircc_fir > 0 && ircc_sir > 0) { @@ -2285,6 +2322,280 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) return ret; } +/* + * Look for some specific subsystem setups that need + * pre-configuration not properly done by the BIOS (especially laptops) + * This code is based in part on smcinit.c, tosh1800-smcinit.c + * and tosh2450-smcinit.c. The table lists the device entries + * for ISA bridges with an LPC (Local Peripheral Configurator) + * that are in turn used to configure the SMSC device with default + * SIR and FIR I/O ports, DMA and IRQ. + */ +#ifdef CONFIG_PCI +#define PCIID_VENDOR_INTEL 0x8086 +#define PCIID_VENDOR_ALI 0x10b9 +static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = { + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x088c, + .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ + .fir_io = 0x0130, + .fir_irq = 0x09, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc8000", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x0890, + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x09, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc6000", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + .device = 0x24c0, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x07, + .fir_dma = 0x01, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba Satellite 2450", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ + .device = 0x248c, /* Some use 24cc? */ + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba Satellite 5100/5200, Tecra 9100", + }, + { + .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + .device = 0x1533, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x02e8, + .fir_io = 0x02f8, + .fir_irq = 0x07, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_ali, + .name = "Toshiba Satellite 1800", + }, + { } // Terminator +}; + + +/* + * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) + * through the chip configuration port. + */ +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) +{ + unsigned short iobase = conf->cfg_base; + unsigned char tmpbyte; + + outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state + outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID + tmpbyte = inb(iobase +1); // Read device ID + IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); + + /* Disable UART1 and set up SIR I/O port */ + outb(0x24, iobase); // select CR24 - UART1 base addr + outb(0x00, iobase + 1); // disable UART1 + outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr + outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->sir_io >> 2) ) { + IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); + return -ENXIO; + } + + /* Set up FIR IRQ channel for UART2 */ + outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select + tmpbyte = inb(iobase + 1); + tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion + tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); + outb(tmpbyte, iobase + 1); + tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; + if (tmpbyte != conf->fir_irq) { + IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n"); + return -ENXIO; + } + + /* Set up FIR I/O port */ + outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr + outb((conf->fir_io >> 3), iobase + 1); + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->fir_io >> 3) ) { + IRDA_WARNING("ERROR: could not configure FIR I/O port.\n"); + return -ENXIO; + } + + /* Set up FIR DMA channel */ + outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select + outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA + tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; + if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { + IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n"); + return -ENXIO; + } + + outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode + tmpbyte = inb(iobase + 1); + tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; + outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed + + outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down + + /* This one was not part of tosh1800 */ + outb(0x0a, iobase); // CR0a - ecp fifo / ir mux + tmpbyte = inb(iobase + 1); + outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port + + outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down + + outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done + + outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration + + return 0; +} + +/* 82801CAM registers */ +#define VID 0x00 +#define DID 0x02 +#define PIRQA_ROUT 0x60 +#define PCI_DMA_C 0x90 +#define COM_DEC 0xe0 +#define LPC_EN 0xe6 +#define GEN2_DEC 0xec +/* + * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or + * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! + */ +static int __init preconfigure_through_82801(struct pci_dev *dev, + struct smsc_ircc_subsystem_configuration *conf) +{ + unsigned short tmpword; + int ret; + + IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); + pci_write_config_byte(dev, COM_DEC, 0x10); + + /* Enable LPC */ + pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ + tmpword &= 0xfffd; /* mask bit 1 */ + tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ + pci_write_config_word(dev, LPC_EN, tmpword); + + /* Setup DMA */ + pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ + pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ + + /* Pre-configure chip */ + ret = preconfigure_smsc_chip(conf); + + /* Disable LPC */ + pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ + tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ + pci_write_config_word(dev, LPC_EN, tmpword); + return ret; +} + +static int __init preconfigure_through_ali(struct pci_dev *dev, + struct smsc_ircc_subsystem_configuration *conf) +{ + /* TODO: put in ALi 1533 configuration here. */ + IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); + return -ENODEV; +} + +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq) +{ + struct pci_dev *dev = NULL; + unsigned short ss_vendor = 0x0000; + unsigned short ss_device = 0x0000; + int ret = 0; + + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + + while (dev != NULL) { + struct smsc_ircc_subsystem_configuration *conf; + + /* + * Cache the subsystem vendor/device: some manufacturers fail to set + * this for all components, so we save it in case there is just + * 0x0000 0x0000 on the device we want to check. + */ + if (dev->subsystem_vendor != 0x0000U) { + ss_vendor = dev->subsystem_vendor; + ss_device = dev->subsystem_device; + } + conf = subsystem_configurations; + for( ; conf->subvendor; conf++) { + if(conf->vendor == dev->vendor && + conf->device == dev->device && + conf->subvendor == ss_vendor && /* Sometimes these are cached values */ + (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { + struct smsc_ircc_subsystem_configuration tmpconf; + + memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); + + /* Override the default values with anything passed in as parameter */ + if (ircc_cfg != 0) + tmpconf.cfg_base = ircc_cfg; + if (ircc_fir != 0) + tmpconf.fir_io = ircc_fir; + if (ircc_sir != 0) + tmpconf.sir_io = ircc_sir; + if (ircc_dma != 0xff) + tmpconf.fir_dma = ircc_dma; + if (ircc_irq != 0xff) + tmpconf.fir_irq = ircc_irq; + + IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name); + if (conf->preconfigure) + ret = conf->preconfigure(dev, &tmpconf); + else + ret = -ENODEV; + } + } + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + } + + return ret; +} +#endif // CONFIG_PCI + /************************************************ * * Transceivers specific functions diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 75b35ad760de..66e74f740261 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -87,6 +87,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) } static struct console netconsole = { + .name = "netcon", .flags = CON_ENABLED | CON_PRINTBUFFER, .write = write_msg }; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0b5358072172..73e271e59c6a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -497,21 +497,20 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); - spin_unlock_irqrestore(&tp->indirect_lock, flags); -} + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + tw32_f(TG3PCI_MEM_WIN_DATA, val); -static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) -{ - /* If no workaround is needed, write to mem space directly */ - if (tp->write32 != tg3_write_indirect_reg32) - tw32(NIC_SRAM_WIN_BASE + off, val); - else - tg3_write_mem(tp, off, val); + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } + spin_unlock_irqrestore(&tp->indirect_lock, flags); } static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) @@ -519,11 +518,19 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + *val = tr32(TG3PCI_MEM_WIN_DATA); + + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } spin_unlock_irqrestore(&tp->indirect_lock, flags); } @@ -1367,12 +1374,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } + tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); + /* Finally, set the new power state. */ pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); udelay(100); /* Delay after power state change */ - tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); - return 0; } @@ -5828,10 +5835,14 @@ static int tg3_reset_hw(struct tg3 *tp) GRC_MODE_NO_TX_PHDR_CSUM | GRC_MODE_NO_RX_PHDR_CSUM); tp->grc_mode |= GRC_MODE_HOST_SENDBDS; - if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM) - tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; - if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM) - tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM; + + /* Pseudo-header checksum is done by hardware logic and not + * the offload processers, so make the chip do the pseudo- + * header checksums on receive. For transmit it is more + * convenient to do the pseudo-header checksum in software + * as Linux does that on transmit for us in all cases. + */ + tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; tw32(GRC_MODE, tp->grc_mode | @@ -6535,11 +6546,11 @@ static void tg3_timer(unsigned long __opaque) if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, - FWCMD_NICDRV_ALIVE2); - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, + FWCMD_NICDRV_ALIVE2); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); /* 5 seconds timeout */ - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); @@ -8034,9 +8045,13 @@ static int tg3_test_nvram(struct tg3 *tp) for (i = 0; i < size; i++) csum8 += buf8[i]; - if (csum8 == 0) - return 0; - return -EIO; + if (csum8 == 0) { + err = 0; + goto out; + } + + err = -EIO; + goto out; } /* Bootstrap checksum at offset 0x10 */ @@ -9531,8 +9546,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->led_ctrl = LED_CTRL_MODE_PHY_1; /* Do not even try poking around in here on Sun parts. */ - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { + /* All SUN chips are built-in LOMs. */ + tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; return; + } tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { @@ -9630,9 +9648,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL) tp->led_ctrl = LED_CTRL_MODE_PHY_2; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) && - (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)) + if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { @@ -10257,6 +10273,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); } + if (tp->write32 == tg3_write_indirect_reg32 || + ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) || + (tp->tg3_flags2 & TG3_FLG2_SUN_570X)) + tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; + /* Get eeprom hw config before calling tg3_set_power_state(). * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be * determined before calling tg3_set_power_state() so that @@ -10299,15 +10322,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - /* Pseudo-header checksum is done by hardware logic and not - * the offload processers, so make the chip do the pseudo- - * header checksums on receive. For transmit it is more - * convenient to do the pseudo-header checksum in software - * as Linux does that on transmit for us in all cases. - */ - tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM; - tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM; - /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index c43cc3264202..8c8b987d1250 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2171,8 +2171,7 @@ struct tg3 { #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 -#define TG3_FLAG_NO_TX_PSEUDO_CSUM 0x00100000 -#define TG3_FLAG_NO_RX_PSEUDO_CSUM 0x00200000 +#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000 #define TG3_FLAG_SERDES_WOL_CAP 0x00400000 #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 412e52ca9720..b31a9bca9361 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -110,6 +110,8 @@ struct nf_info /* Function to register/unregister hook points. */ int nf_register_hook(struct nf_hook_ops *reg); void nf_unregister_hook(struct nf_hook_ops *reg); +int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n); +void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n); /* Functions to register get/setsockopt ranges (non-inclusive). You need to check permissions yourself! */ @@ -281,16 +283,42 @@ extern void nf_invalidate_cache(int pf); Returns true or false. */ extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); -struct nf_queue_rerouter { - void (*save)(const struct sk_buff *skb, struct nf_info *info); - int (*reroute)(struct sk_buff **skb, const struct nf_info *info); - int rer_size; +struct nf_afinfo { + unsigned short family; + unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, u_int8_t protocol); + void (*saveroute)(const struct sk_buff *skb, + struct nf_info *info); + int (*reroute)(struct sk_buff **skb, + const struct nf_info *info); + int route_key_size; }; -#define nf_info_reroute(x) ((void *)x + sizeof(struct nf_info)) +extern struct nf_afinfo *nf_afinfo[]; +static inline struct nf_afinfo *nf_get_afinfo(unsigned short family) +{ + return rcu_dereference(nf_afinfo[family]); +} + +static inline unsigned int +nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, + u_int8_t protocol, unsigned short family) +{ + struct nf_afinfo *afinfo; + unsigned int csum = 0; + + rcu_read_lock(); + afinfo = nf_get_afinfo(family); + if (afinfo) + csum = afinfo->checksum(skb, hook, dataoff, protocol); + rcu_read_unlock(); + return csum; +} -extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer); -extern int nf_unregister_queue_rerouter(int pf); +extern int nf_register_afinfo(struct nf_afinfo *afinfo); +extern void nf_unregister_afinfo(struct nf_afinfo *afinfo); + +#define nf_info_reroute(x) ((void *)x + sizeof(struct nf_info)) #include <net/flow.h> extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 43c09d790b83..85301c5e8d24 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -80,6 +80,8 @@ enum nf_ip_hook_priorities { #ifdef __KERNEL__ extern int ip_route_me_harder(struct sk_buff **pskb); extern int ip_xfrm_me_harder(struct sk_buff **pskb); +extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, u_int8_t protocol); #endif /*__KERNEL__*/ #endif /*__LINUX_IP_NETFILTER_H*/ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h index 0987cea53840..eace86bd2adb 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h @@ -3,6 +3,8 @@ #ifdef __KERNEL__ +#include <linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h> + #define RAS_PORT 1719 #define Q931_PORT 1720 #define H323_RTP_CHANNEL_MAX 4 /* Audio, video, FAX and other */ @@ -25,6 +27,56 @@ struct ip_ct_h323_master { }; }; +struct ip_conntrack_expect; + +extern int get_h225_addr(unsigned char *data, TransportAddress * addr, + u_int32_t * ip, u_int16_t * port); +extern void ip_conntrack_h245_expect(struct ip_conntrack *new, + struct ip_conntrack_expect *this); +extern void ip_conntrack_q931_expect(struct ip_conntrack *new, + struct ip_conntrack_expect *this); +extern int (*set_h245_addr_hook) (struct sk_buff ** pskb, + unsigned char **data, int dataoff, + H245_TransportAddress * addr, + u_int32_t ip, u_int16_t port); +extern int (*set_h225_addr_hook) (struct sk_buff ** pskb, + unsigned char **data, int dataoff, + TransportAddress * addr, + u_int32_t ip, u_int16_t port); +extern int (*set_sig_addr_hook) (struct sk_buff ** pskb, + struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress * addr, int count); +extern int (*set_ras_addr_hook) (struct sk_buff ** pskb, + struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, + TransportAddress * addr, int count); +extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb, + struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress * addr, + u_int16_t port, u_int16_t rtp_port, + struct ip_conntrack_expect * rtp_exp, + struct ip_conntrack_expect * rtcp_exp); +extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + H245_TransportAddress * addr, u_int16_t port, + struct ip_conntrack_expect * exp); +extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, int dataoff, + TransportAddress * addr, u_int16_t port, + struct ip_conntrack_expect * exp); +extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, + enum ip_conntrack_info ctinfo, + unsigned char **data, TransportAddress * addr, + int idx, u_int16_t port, + struct ip_conntrack_expect * exp); + #endif #endif diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h index 0bd828081c0c..0bd828081c0c 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h index cc98f7aa5abe..cc98f7aa5abe 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index 14f2bd010884..52a7b9e76428 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -73,6 +73,9 @@ enum nf_ip6_hook_priorities { }; #ifdef CONFIG_NETFILTER +extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, u_int8_t protocol); + extern int ipv6_netfilter_init(void); extern void ipv6_netfilter_fini(void); #else /* CONFIG_NETFILTER */ diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index 25f708ff020e..59f0c83d55a2 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h @@ -48,31 +48,7 @@ static inline int inet6_sk_ehashfn(const struct sock *sk) return inet6_ehashfn(laddr, lport, faddr, fport); } -static inline void __inet6_hash(struct inet_hashinfo *hashinfo, - struct sock *sk) -{ - struct hlist_head *list; - rwlock_t *lock; - - BUG_TRAP(sk_unhashed(sk)); - - if (sk->sk_state == TCP_LISTEN) { - list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; - lock = &hashinfo->lhash_lock; - inet_listen_wlock(hashinfo); - } else { - unsigned int hash; - sk->sk_hash = hash = inet6_sk_ehashfn(sk); - hash &= (hashinfo->ehash_size - 1); - list = &hashinfo->ehash[hash].chain; - lock = &hashinfo->ehash[hash].lock; - write_lock(lock); - } - - __sk_add_node(sk, list); - sock_prot_inc_use(sk->sk_prot); - write_unlock(lock); -} +extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk); /* * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so @@ -80,52 +56,12 @@ static inline void __inet6_hash(struct inet_hashinfo *hashinfo, * * The sockhash lock must be held as a reader here. */ -static inline struct sock * - __inet6_lookup_established(struct inet_hashinfo *hashinfo, +extern struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, const struct in6_addr *saddr, const u16 sport, const struct in6_addr *daddr, const u16 hnum, - const int dif) -{ - struct sock *sk; - const struct hlist_node *node; - const __u32 ports = INET_COMBINED_PORTS(sport, hnum); - /* Optimize here for direct hit, only listening connections can - * have wildcards anyways. - */ - unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport); - struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); - - prefetch(head->chain.first); - read_lock(&head->lock); - sk_for_each(sk, node, &head->chain) { - /* For IPV6 do the cheaper port and family tests first. */ - if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif)) - goto hit; /* You sunk my battleship! */ - } - /* Must check for a TIME_WAIT'er before going to listener hash. */ - sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { - const struct inet_timewait_sock *tw = inet_twsk(sk); - - if(*((__u32 *)&(tw->tw_dport)) == ports && - sk->sk_family == PF_INET6) { - const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); - - if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && - ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && - (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) - goto hit; - } - } - read_unlock(&head->lock); - return NULL; - -hit: - sock_hold(sk); - read_unlock(&head->lock); - return sk; -} + const int dif); extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, diff --git a/include/net/ip.h b/include/net/ip.h index 8fe6156ca9b0..3d2e5ca62a5a 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -95,6 +95,7 @@ extern int ip_local_deliver(struct sk_buff *skb); extern int ip_mr_input(struct sk_buff *skb); extern int ip_output(struct sk_buff *skb); extern int ip_mc_output(struct sk_buff *skb); +extern int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); extern int ip_do_nat(struct sk_buff *skb); extern void ip_send_check(struct iphdr *ip); extern int ip_queue_xmit(struct sk_buff *skb, int ipfragok); diff --git a/include/net/x25device.h b/include/net/x25device.h index 1a318374faef..1d10c879f7e2 100644 --- a/include/net/x25device.h +++ b/include/net/x25device.h @@ -8,6 +8,7 @@ static inline __be16 x25_type_trans(struct sk_buff *skb, struct net_device *dev) { skb->mac.raw = skb->data; + skb->dev = dev; skb->pkt_type = PACKET_HOST; return htons(ETH_P_X25); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 6b61323ce23c..0c2d13ad69bb 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -255,7 +255,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) } if ((err = hci_send_sco(conn->hcon, skb)) < 0) - goto fail; + return err; return count; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index f29450b788be..3da9264449f7 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -765,6 +765,15 @@ out: return NF_STOLEN; } +static int br_nf_dev_queue_xmit(struct sk_buff *skb) +{ + if (skb->protocol == htons(ETH_P_IP) && + skb->len > skb->dev->mtu && + !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) + return ip_fragment(skb, br_dev_queue_push_xmit); + else + return br_dev_queue_push_xmit(skb); +} /* PF_BRIDGE/POST_ROUTING ********************************************/ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, @@ -824,7 +833,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, realoutdev = nf_bridge->netoutdev; #endif NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, - br_dev_queue_push_xmit); + br_nf_dev_queue_xmit); return NF_STOLEN; @@ -869,7 +878,7 @@ static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb, if ((out->hard_start_xmit == br_dev_xmit && okfn != br_nf_forward_finish && - okfn != br_nf_local_out_finish && okfn != br_dev_queue_push_xmit) + okfn != br_nf_local_out_finish && okfn != br_nf_dev_queue_xmit) #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) || ((out->priv_flags & IFF_802_1Q_VLAN) && VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit) diff --git a/net/core/dev.c b/net/core/dev.c index 434220d093aa..2731570eba5b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3042,11 +3042,11 @@ void netdev_run_todo(void) switch(dev->reg_state) { case NETREG_REGISTERING: + dev->reg_state = NETREG_REGISTERED; err = netdev_register_sysfs(dev); if (err) printk(KERN_ERR "%s: failed sysfs registration (%d)\n", dev->name, err); - dev->reg_state = NETREG_REGISTERED; break; case NETREG_UNREGISTERING: @@ -3100,12 +3100,11 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name, alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; - p = kmalloc(alloc_size, GFP_KERNEL); + p = kzalloc(alloc_size, GFP_KERNEL); if (!p) { printk(KERN_ERR "alloc_dev: Unable to allocate device.\n"); return NULL; } - memset(p, 0, alloc_size); dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); diff --git a/net/core/dv.c b/net/core/dv.c index cf581407538c..29ee77f15932 100644 --- a/net/core/dv.c +++ b/net/core/dv.c @@ -55,15 +55,12 @@ int alloc_divert_blk(struct net_device *dev) dev->divert = NULL; if (dev->type == ARPHRD_ETHER) { - dev->divert = (struct divert_blk *) - kmalloc(alloc_size, GFP_KERNEL); + dev->divert = kzalloc(alloc_size, GFP_KERNEL); if (dev->divert == NULL) { printk(KERN_INFO "divert: unable to allocate divert_blk for %s\n", dev->name); return -ENOMEM; } - - memset(dev->divert, 0, sizeof(struct divert_blk)); dev_hold(dev); } diff --git a/net/core/flow.c b/net/core/flow.c index 55789f832eda..885a2f655db0 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -318,12 +318,10 @@ static void __devinit flow_cache_cpu_prepare(int cpu) /* NOTHING */; flow_table(cpu) = (struct flow_cache_entry **) - __get_free_pages(GFP_KERNEL, order); + __get_free_pages(GFP_KERNEL|__GFP_ZERO, order); if (!flow_table(cpu)) panic("NET: failed to allocate flow cache order %lu\n", order); - memset(flow_table(cpu), 0, PAGE_SIZE << order); - flow_hash_rnd_recalc(cpu) = 1; flow_count(cpu) = 0; diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index b07c029e8219..3cad026764f0 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -159,11 +159,10 @@ int gen_new_estimator(struct gnet_stats_basic *bstats, if (parm->interval < -2 || parm->interval > 3) return -EINVAL; - est = kmalloc(sizeof(*est), GFP_KERNEL); + est = kzalloc(sizeof(*est), GFP_KERNEL); if (est == NULL) return -ENOBUFS; - memset(est, 0, sizeof(*est)); est->interval = parm->interval + 2; est->bstats = bstats; est->rate_est = rate_est; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0c8666872d10..2ec8693fb778 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -284,14 +284,11 @@ static struct neighbour **neigh_hash_alloc(unsigned int entries) struct neighbour **ret; if (size <= PAGE_SIZE) { - ret = kmalloc(size, GFP_ATOMIC); + ret = kzalloc(size, GFP_ATOMIC); } else { ret = (struct neighbour **) - __get_free_pages(GFP_ATOMIC, get_order(size)); + __get_free_pages(GFP_ATOMIC|__GFP_ZERO, get_order(size)); } - if (ret) - memset(ret, 0, size); - return ret; } @@ -1089,8 +1086,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, if (hh->hh_type == protocol) break; - if (!hh && (hh = kmalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { - memset(hh, 0, sizeof(struct hh_cache)); + if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { rwlock_init(&hh->hh_lock); hh->hh_type = protocol; atomic_set(&hh->hh_refcnt, 0); @@ -1366,13 +1362,11 @@ void neigh_table_init(struct neigh_table *tbl) tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1); phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *); - tbl->phash_buckets = kmalloc(phsize, GFP_KERNEL); + tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL); if (!tbl->hash_buckets || !tbl->phash_buckets) panic("cannot allocate neighbour cache hashes"); - memset(tbl->phash_buckets, 0, phsize); - get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); rwlock_init(&tbl->lock); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 21b68464cabb..c12990c9c603 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -165,7 +165,7 @@ static ssize_t show_operstate(struct class_device *dev, char *buf) operstate = IF_OPER_DOWN; read_unlock(&dev_base_lock); - if (operstate >= sizeof(operstates)) + if (operstate >= ARRAY_SIZE(operstates)) return -EINVAL; /* should not happen */ return sprintf(buf, "%s\n", operstates[operstate]); diff --git a/net/core/request_sock.c b/net/core/request_sock.c index 1e44eda1fda9..79ebd75fbe4d 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c @@ -38,13 +38,11 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, { const int lopt_size = sizeof(struct listen_sock) + nr_table_entries * sizeof(struct request_sock *); - struct listen_sock *lopt = kmalloc(lopt_size, GFP_KERNEL); + struct listen_sock *lopt = kzalloc(lopt_size, GFP_KERNEL); if (lopt == NULL) return -ENOMEM; - memset(lopt, 0, lopt_size); - for (lopt->max_qlen_log = 6; (1 << lopt->max_qlen_log) < sysctl_max_syn_backlog; lopt->max_qlen_log++); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index ccd3efc6a173..95a639f2e3db 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -50,7 +50,7 @@ * Patrick McHardy <kaber@trash.net> */ -#define VERSION "0.406" +#define VERSION "0.407" #include <linux/config.h> #include <asm/uaccess.h> @@ -314,11 +314,6 @@ static void __leaf_free_rcu(struct rcu_head *head) kfree(container_of(head, struct leaf, rcu)); } -static inline void free_leaf(struct leaf *leaf) -{ - call_rcu(&leaf->rcu, __leaf_free_rcu); -} - static void __leaf_info_free_rcu(struct rcu_head *head) { kfree(container_of(head, struct leaf_info, rcu)); @@ -357,7 +352,12 @@ static void __tnode_free_rcu(struct rcu_head *head) static inline void tnode_free(struct tnode *tn) { - call_rcu(&tn->rcu, __tnode_free_rcu); + if(IS_LEAF(tn)) { + struct leaf *l = (struct leaf *) tn; + call_rcu_bh(&l->rcu, __leaf_free_rcu); + } + else + call_rcu(&tn->rcu, __tnode_free_rcu); } static struct leaf *leaf_new(void) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 2a8adda15e11..da734c439179 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -304,13 +304,17 @@ out: /* Creation primitives. */ -static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in) +static struct ipq *ip_frag_intern(struct ipq *qp_in) { struct ipq *qp; #ifdef CONFIG_SMP struct hlist_node *n; #endif + unsigned int hash; + write_lock(&ipfrag_lock); + hash = ipqhashfn(qp_in->id, qp_in->saddr, qp_in->daddr, + qp_in->protocol); #ifdef CONFIG_SMP /* With SMP race we have to recheck hash table, because * such entry could be created on other cpu, while we @@ -345,7 +349,7 @@ static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in) } /* Add an entry to the 'ipq' queue for a newly received IP datagram. */ -static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user) +static struct ipq *ip_frag_create(struct iphdr *iph, u32 user) { struct ipq *qp; @@ -371,7 +375,7 @@ static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user) spin_lock_init(&qp->lock); atomic_set(&qp->refcnt, 1); - return ip_frag_intern(hash, qp); + return ip_frag_intern(qp); out_nomem: LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); @@ -387,11 +391,12 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user) __u32 saddr = iph->saddr; __u32 daddr = iph->daddr; __u8 protocol = iph->protocol; - unsigned int hash = ipqhashfn(id, saddr, daddr, protocol); + unsigned int hash; struct ipq *qp; struct hlist_node *n; read_lock(&ipfrag_lock); + hash = ipqhashfn(id, saddr, daddr, protocol); hlist_for_each_entry(qp, n, &ipq_hash[hash], list) { if(qp->id == id && qp->saddr == saddr && @@ -405,7 +410,7 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user) } read_unlock(&ipfrag_lock); - return ip_frag_create(hash, iph, user); + return ip_frag_create(iph, user); } /* Is the fragment too far ahead to be part of ipq? */ diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 9981dcd68f11..ab99bebdcdc8 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -656,7 +656,7 @@ static int ipgre_rcv(struct sk_buff *skb) read_unlock(&ipgre_lock); return(0); } - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); drop: read_unlock(&ipgre_lock); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f75ff1d96551..8dcba3887f04 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -86,8 +86,6 @@ int sysctl_ip_default_ttl = IPDEFTTL; -static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)); - /* Generate a checksum for an outgoing IP datagram. */ __inline__ void ip_send_check(struct iphdr *iph) { @@ -421,7 +419,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) * single device frame, and queue such a frame for sending. */ -static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) +int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) { struct iphdr *iph; int raw = 0; @@ -673,6 +671,8 @@ fail: return err; } +EXPORT_SYMBOL(ip_fragment); + int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) { diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index eef07b0916a3..ea398ee43f28 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -474,9 +474,6 @@ static int ipip_rcv(struct sk_buff *skb) struct iphdr *iph; struct ip_tunnel *tunnel; - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto out; - iph = skb->nh.iph; read_lock(&ipip_lock); @@ -508,7 +505,6 @@ static int ipip_rcv(struct sk_buff *skb) } read_unlock(&ipip_lock); -out: return -1; } diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index b5ad9ac2fbcc..6a9e34b794bc 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -133,7 +133,7 @@ struct ip_rt_info { u_int8_t tos; }; -static void queue_save(const struct sk_buff *skb, struct nf_info *info) +static void nf_ip_saveroute(const struct sk_buff *skb, struct nf_info *info) { struct ip_rt_info *rt_info = nf_info_reroute(info); @@ -146,7 +146,7 @@ static void queue_save(const struct sk_buff *skb, struct nf_info *info) } } -static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info) +static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) { const struct ip_rt_info *rt_info = nf_info_reroute(info); @@ -161,20 +161,54 @@ static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -static struct nf_queue_rerouter ip_reroute = { - .rer_size = sizeof(struct ip_rt_info), - .save = queue_save, - .reroute = queue_reroute, +unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, u_int8_t protocol) +{ + struct iphdr *iph = skb->nh.iph; + unsigned int csum = 0; + + switch (skb->ip_summed) { + case CHECKSUM_HW: + if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN) + break; + if ((protocol == 0 && !(u16)csum_fold(skb->csum)) || + !csum_tcpudp_magic(iph->saddr, iph->daddr, + skb->len - dataoff, protocol, + skb->csum)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + } + /* fall through */ + case CHECKSUM_NONE: + if (protocol == 0) + skb->csum = 0; + else + skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, + skb->len - dataoff, + protocol, 0); + csum = __skb_checksum_complete(skb); + } + return csum; +} + +EXPORT_SYMBOL(nf_ip_checksum); + +static struct nf_afinfo nf_ip_afinfo = { + .family = AF_INET, + .checksum = nf_ip_checksum, + .saveroute = nf_ip_saveroute, + .reroute = nf_ip_reroute, + .route_key_size = sizeof(struct ip_rt_info), }; static int ipv4_netfilter_init(void) { - return nf_register_queue_rerouter(PF_INET, &ip_reroute); + return nf_register_afinfo(&nf_ip_afinfo); } static void ipv4_netfilter_fini(void) { - nf_unregister_queue_rerouter(PF_INET); + nf_unregister_afinfo(&nf_ip_afinfo); } module_init(ipv4_netfilter_init); diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 77855ccd6b43..c60fd5c4ea1e 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -69,6 +69,7 @@ config IP_NF_CONNTRACK_NETLINK tristate 'Connection tracking netlink interface (EXPERIMENTAL)' depends on EXPERIMENTAL && IP_NF_CONNTRACK && NETFILTER_NETLINK depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m + depends on IP_NF_NAT=n || IP_NF_NAT help This option enables support for a netlink-based userspace interface diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index d0d379c7df9a..d7c472faa53b 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -181,33 +181,26 @@ static struct nf_hook_ops arpt_ops[] = { static int __init arptable_filter_init(void) { - int ret, i; + int ret; /* Register table */ ret = arpt_register_table(&packet_filter, &initial_table.repl); if (ret < 0) return ret; - for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) - if ((ret = nf_register_hook(&arpt_ops[i])) < 0) - goto cleanup_hooks; + ret = nf_register_hooks(arpt_ops, ARRAY_SIZE(arpt_ops)); + if (ret < 0) + goto cleanup_table; return ret; -cleanup_hooks: - while (--i >= 0) - nf_unregister_hook(&arpt_ops[i]); - +cleanup_table: arpt_unregister_table(&packet_filter); return ret; } static void __exit arptable_filter_fini(void) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) - nf_unregister_hook(&arpt_ops[i]); - + nf_unregister_hooks(arpt_ops, ARRAY_SIZE(arpt_ops)); arpt_unregister_table(&packet_filter); } diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index daeb1395faa4..2c2fb700d835 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -9,37 +9,6 @@ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * * For more information, please see http://nath323.sourceforge.net/ - * - * Changes: - * 2006-02-01 - initial version 0.1 - * - * 2006-02-20 - version 0.2 - * 1. Changed source format to follow kernel conventions - * 2. Deleted some unnecessary structures - * 3. Minor fixes - * - * 2006-03-10 - version 0.3 - * 1. Added support for multiple TPKTs in one packet (suggested by - * Patrick McHardy) - * 2. Avoid excessive stack usage (based on Patrick McHardy's patch) - * 3. Added support for non-linear skb (based on Patrick McHardy's patch) - * 4. Fixed missing H.245 module owner (Patrick McHardy) - * 5. Avoid long RAS expectation chains (Patrick McHardy) - * 6. Fixed incorrect __exit attribute (Patrick McHardy) - * 7. Eliminated unnecessary return code - * 8. Fixed incorrect use of NAT data from conntrack code (suggested by - * Patrick McHardy) - * 9. Fixed TTL calculation error in RCF - * 10. Added TTL support in RRQ - * 11. Better support for separate TPKT header and data - * - * 2006-03-15 - version 0.4 - * 1. Added support for T.120 channels - * 2. Added parameter gkrouted_only (suggested by Patrick McHardy) - * 3. Splitted ASN.1 code and data (suggested by Patrick McHardy) - * 4. Sort ASN.1 data to avoid forwarding declarations (suggested by - * Patrick McHardy) - * 5. Reset next TPKT data length in get_tpkt_data() */ #include <linux/config.h> @@ -54,8 +23,6 @@ #include <linux/netfilter_ipv4/ip_conntrack_h323.h> #include <linux/moduleparam.h> -#include "ip_conntrack_helper_h323_asn1.h" - #if 0 #define DEBUGP printk #else @@ -63,6 +30,10 @@ #endif /* Parameters */ +static unsigned int default_rrq_ttl = 300; +module_param(default_rrq_ttl, uint, 0600); +MODULE_PARM_DESC(default_rrq_ttl, "use this TTL if it's missing in RRQ"); + static int gkrouted_only = 1; module_param(gkrouted_only, int, 0600); MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper"); @@ -222,8 +193,8 @@ static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct, } /****************************************************************************/ -int get_h245_addr(unsigned char *data, H245_TransportAddress * addr, - u_int32_t * ip, u_int16_t * port) +static int get_h245_addr(unsigned char *data, H245_TransportAddress * addr, + u_int32_t * ip, u_int16_t * port) { unsigned char *p; @@ -1302,7 +1273,7 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct, DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive); info->timeout = rrq->timeToLive; } else - info->timeout = 0; + info->timeout = default_rrq_ttl; return 0; } @@ -1713,18 +1684,17 @@ static int __init init(void) module_init(init); module_exit(fini); -EXPORT_SYMBOL(get_h245_addr); -EXPORT_SYMBOL(get_h225_addr); -EXPORT_SYMBOL(ip_conntrack_h245_expect); -EXPORT_SYMBOL(ip_conntrack_q931_expect); -EXPORT_SYMBOL(set_h245_addr_hook); -EXPORT_SYMBOL(set_h225_addr_hook); -EXPORT_SYMBOL(set_sig_addr_hook); -EXPORT_SYMBOL(set_ras_addr_hook); -EXPORT_SYMBOL(nat_rtp_rtcp_hook); -EXPORT_SYMBOL(nat_t120_hook); -EXPORT_SYMBOL(nat_h245_hook); -EXPORT_SYMBOL(nat_q931_hook); +EXPORT_SYMBOL_GPL(get_h225_addr); +EXPORT_SYMBOL_GPL(ip_conntrack_h245_expect); +EXPORT_SYMBOL_GPL(ip_conntrack_q931_expect); +EXPORT_SYMBOL_GPL(set_h245_addr_hook); +EXPORT_SYMBOL_GPL(set_h225_addr_hook); +EXPORT_SYMBOL_GPL(set_sig_addr_hook); +EXPORT_SYMBOL_GPL(set_ras_addr_hook); +EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook); +EXPORT_SYMBOL_GPL(nat_t120_hook); +EXPORT_SYMBOL_GPL(nat_h245_hook); +EXPORT_SYMBOL_GPL(nat_q931_hook); MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>"); MODULE_DESCRIPTION("H.323 connection tracking helper"); diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c index afa525129b51..48078002e450 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c @@ -15,7 +15,7 @@ #else #include <stdio.h> #endif -#include "ip_conntrack_helper_h323_asn1.h" +#include <linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h> /* Trace Flag */ #ifndef H323_TRACE diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index 3021af0910f1..d8b14a9010a6 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c @@ -224,25 +224,14 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, } /* See ip_conntrack_proto_tcp.c */ - if (hooknum != NF_IP_PRE_ROUTING) - goto checksum_skipped; - - switch (skb->ip_summed) { - case CHECKSUM_HW: - if (!(u16)csum_fold(skb->csum)) - break; - /* fall through */ - case CHECKSUM_NONE: - skb->csum = 0; - if (__skb_checksum_complete(skb)) { - if (LOG_INVALID(IPPROTO_ICMP)) - nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, - "ip_ct_icmp: bad ICMP checksum "); - return -NF_ACCEPT; - } + if (hooknum == NF_IP_PRE_ROUTING && + nf_ip_checksum(skb, hooknum, skb->nh.iph->ihl * 4, 0)) { + if (LOG_INVALID(IPPROTO_ICMP)) + nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, + "ip_ct_icmp: bad ICMP checksum "); + return -NF_ACCEPT; } -checksum_skipped: /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index e0dc37063545..062b252b58ad 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -870,11 +870,8 @@ static int tcp_error(struct sk_buff *skb, * and moreover root might send raw packets. */ /* FIXME: Source route IP option packets --RR */ - if (hooknum == NF_IP_PRE_ROUTING - && skb->ip_summed != CHECKSUM_UNNECESSARY - && csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP, - skb->ip_summed == CHECKSUM_HW ? skb->csum - : skb_checksum(skb, iph->ihl*4, tcplen, 0))) { + if (hooknum == NF_IP_PRE_ROUTING && + nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_TCP)) { if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, "ip_ct_tcp: bad TCP checksum "); diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c index 55b7d3210adf..70899868783b 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c @@ -120,11 +120,8 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, * because the semantic of CHECKSUM_HW is different there * and moreover root might send raw packets. * FIXME: Source route IP option packets --RR */ - if (hooknum == NF_IP_PRE_ROUTING - && skb->ip_summed != CHECKSUM_UNNECESSARY - && csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, - skb->ip_summed == CHECKSUM_HW ? skb->csum - : skb_checksum(skb, iph->ihl*4, udplen, 0))) { + if (hooknum == NF_IP_PRE_ROUTING && + nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_UDP)) { if (LOG_INVALID(IPPROTO_UDP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, "ip_ct_udp: bad UDP checksum "); diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 52076026db36..929d61f7be91 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -469,70 +469,63 @@ static unsigned int ip_conntrack_local(unsigned int hooknum, /* Connection tracking may drop packets, but never alters them, so make it the first hook. */ -static struct nf_hook_ops ip_conntrack_defrag_ops = { - .hook = ip_conntrack_defrag, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ip_conntrack_in_ops = { - .hook = ip_conntrack_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_CONNTRACK, -}; - -static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = { - .hook = ip_conntrack_defrag, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ip_conntrack_local_out_ops = { - .hook = ip_conntrack_local, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_CONNTRACK, -}; - -/* helpers */ -static struct nf_hook_ops ip_conntrack_helper_out_ops = { - .hook = ip_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_HELPER, -}; - -static struct nf_hook_ops ip_conntrack_helper_in_ops = { - .hook = ip_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_CONNTRACK_HELPER, -}; - -/* Refragmenter; last chance. */ -static struct nf_hook_ops ip_conntrack_out_ops = { - .hook = ip_confirm, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_CONFIRM, -}; - -static struct nf_hook_ops ip_conntrack_local_in_ops = { - .hook = ip_confirm, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_CONNTRACK_CONFIRM, +static struct nf_hook_ops ip_conntrack_ops[] = { + { + .hook = ip_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ip_conntrack_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_CONNTRACK, + }, + { + .hook = ip_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ip_conntrack_local, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK, + }, + { + .hook = ip_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_HELPER, + }, + { + .hook = ip_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_CONNTRACK_HELPER, + }, + { + .hook = ip_confirm, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, + }, + { + .hook = ip_confirm, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, + }, }; /* Sysctl support */ @@ -783,18 +776,46 @@ static ctl_table ip_ct_net_table[] = { EXPORT_SYMBOL(ip_ct_log_invalid); #endif /* CONFIG_SYSCTL */ -static int init_or_cleanup(int init) +/* FIXME: Allow NULL functions and sub in pointers to generic for + them. --RR */ +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) +{ + int ret = 0; + + write_lock_bh(&ip_conntrack_lock); + if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) { + ret = -EBUSY; + goto out; + } + ip_ct_protos[proto->proto] = proto; + out: + write_unlock_bh(&ip_conntrack_lock); + return ret; +} + +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) +{ + write_lock_bh(&ip_conntrack_lock); + ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol; + write_unlock_bh(&ip_conntrack_lock); + + /* Somebody could be still looking at the proto in bh. */ + synchronize_net(); + + /* Remove all contrack entries for this protocol */ + ip_ct_iterate_cleanup(kill_proto, &proto->proto); +} + +static int __init ip_conntrack_standalone_init(void) { #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc, *proc_exp, *proc_stat; #endif int ret = 0; - if (!init) goto cleanup; - ret = ip_conntrack_init(); if (ret < 0) - goto cleanup_nothing; + return ret; #ifdef CONFIG_PROC_FS ret = -ENOMEM; @@ -813,78 +834,25 @@ static int init_or_cleanup(int init) proc_stat->owner = THIS_MODULE; #endif - ret = nf_register_hook(&ip_conntrack_defrag_ops); + ret = nf_register_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); if (ret < 0) { - printk("ip_conntrack: can't register pre-routing defrag hook.\n"); + printk("ip_conntrack: can't register hooks.\n"); goto cleanup_proc_stat; } - ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops); - if (ret < 0) { - printk("ip_conntrack: can't register local_out defrag hook.\n"); - goto cleanup_defragops; - } - ret = nf_register_hook(&ip_conntrack_in_ops); - if (ret < 0) { - printk("ip_conntrack: can't register pre-routing hook.\n"); - goto cleanup_defraglocalops; - } - ret = nf_register_hook(&ip_conntrack_local_out_ops); - if (ret < 0) { - printk("ip_conntrack: can't register local out hook.\n"); - goto cleanup_inops; - } - ret = nf_register_hook(&ip_conntrack_helper_in_ops); - if (ret < 0) { - printk("ip_conntrack: can't register local in helper hook.\n"); - goto cleanup_inandlocalops; - } - ret = nf_register_hook(&ip_conntrack_helper_out_ops); - if (ret < 0) { - printk("ip_conntrack: can't register postrouting helper hook.\n"); - goto cleanup_helperinops; - } - ret = nf_register_hook(&ip_conntrack_out_ops); - if (ret < 0) { - printk("ip_conntrack: can't register post-routing hook.\n"); - goto cleanup_helperoutops; - } - ret = nf_register_hook(&ip_conntrack_local_in_ops); - if (ret < 0) { - printk("ip_conntrack: can't register local in hook.\n"); - goto cleanup_inoutandlocalops; - } #ifdef CONFIG_SYSCTL ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0); if (ip_ct_sysctl_header == NULL) { printk("ip_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; - goto cleanup_localinops; + goto cleanup_hooks; } #endif - return ret; - cleanup: - synchronize_net(); #ifdef CONFIG_SYSCTL - unregister_sysctl_table(ip_ct_sysctl_header); - cleanup_localinops: + cleanup_hooks: + nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); #endif - nf_unregister_hook(&ip_conntrack_local_in_ops); - cleanup_inoutandlocalops: - nf_unregister_hook(&ip_conntrack_out_ops); - cleanup_helperoutops: - nf_unregister_hook(&ip_conntrack_helper_out_ops); - cleanup_helperinops: - nf_unregister_hook(&ip_conntrack_helper_in_ops); - cleanup_inandlocalops: - nf_unregister_hook(&ip_conntrack_local_out_ops); - cleanup_inops: - nf_unregister_hook(&ip_conntrack_in_ops); - cleanup_defraglocalops: - nf_unregister_hook(&ip_conntrack_defrag_local_out_ops); - cleanup_defragops: - nf_unregister_hook(&ip_conntrack_defrag_ops); cleanup_proc_stat: #ifdef CONFIG_PROC_FS remove_proc_entry("ip_conntrack", proc_net_stat); @@ -895,48 +863,22 @@ static int init_or_cleanup(int init) cleanup_init: #endif /* CONFIG_PROC_FS */ ip_conntrack_cleanup(); - cleanup_nothing: - return ret; -} - -/* FIXME: Allow NULL functions and sub in pointers to generic for - them. --RR */ -int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) -{ - int ret = 0; - - write_lock_bh(&ip_conntrack_lock); - if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) { - ret = -EBUSY; - goto out; - } - ip_ct_protos[proto->proto] = proto; - out: - write_unlock_bh(&ip_conntrack_lock); return ret; } -void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) -{ - write_lock_bh(&ip_conntrack_lock); - ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol; - write_unlock_bh(&ip_conntrack_lock); - - /* Somebody could be still looking at the proto in bh. */ - synchronize_net(); - - /* Remove all contrack entries for this protocol */ - ip_ct_iterate_cleanup(kill_proto, &proto->proto); -} - -static int __init ip_conntrack_standalone_init(void) -{ - return init_or_cleanup(1); -} - static void __exit ip_conntrack_standalone_fini(void) { - init_or_cleanup(0); + synchronize_net(); +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(ip_ct_sysctl_header); +#endif + nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); +#ifdef CONFIG_PROC_FS + remove_proc_entry("ip_conntrack", proc_net_stat); + proc_net_remove("ip_conntrack_expect"); + proc_net_remove("ip_conntrack"); +#endif /* CONFIG_PROC_FS */ + ip_conntrack_cleanup(); } module_init(ip_conntrack_standalone_init); diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c index a0bc883928c0..d45663d137a7 100644 --- a/net/ipv4/netfilter/ip_nat_helper_h323.c +++ b/net/ipv4/netfilter/ip_nat_helper_h323.c @@ -7,24 +7,6 @@ * * Based on the 'brute force' H.323 NAT module by * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> - * - * Changes: - * 2006-02-01 - initial version 0.1 - * - * 2006-02-20 - version 0.2 - * 1. Changed source format to follow kernel conventions - * 2. Deleted some unnecessary structures - * 3. Minor fixes - * - * 2006-03-10 - version 0.3 - * 1. Added support for multiple TPKTs in one packet (suggested by - * Patrick McHardy) - * 2. Added support for non-linear skb (based on Patrick McHardy's patch) - * 3. Eliminated unnecessary return code - * - * 2006-03-15 - version 0.4 - * 1. Added support for T.120 channels - * 2. Added parameter gkrouted_only (suggested by Patrick McHardy) */ #include <linux/module.h> @@ -41,65 +23,12 @@ #include <linux/netfilter_ipv4/ip_conntrack_h323.h> #include <linux/netfilter_ipv4/ip_conntrack_helper.h> -#include "ip_conntrack_helper_h323_asn1.h" - #if 0 #define DEBUGP printk #else #define DEBUGP(format, args...) #endif -extern int get_h245_addr(unsigned char *data, H245_TransportAddress * addr, - u_int32_t * ip, u_int16_t * port); -extern int get_h225_addr(unsigned char *data, TransportAddress * addr, - u_int32_t * ip, u_int16_t * port); -extern void ip_conntrack_h245_expect(struct ip_conntrack *new, - struct ip_conntrack_expect *this); -extern void ip_conntrack_q931_expect(struct ip_conntrack *new, - struct ip_conntrack_expect *this); -extern int (*set_h245_addr_hook) (struct sk_buff ** pskb, - unsigned char **data, int dataoff, - H245_TransportAddress * addr, - u_int32_t ip, u_int16_t port); -extern int (*set_h225_addr_hook) (struct sk_buff ** pskb, - unsigned char **data, int dataoff, - TransportAddress * addr, - u_int32_t ip, u_int16_t port); -extern int (*set_sig_addr_hook) (struct sk_buff ** pskb, - struct ip_conntrack * ct, - enum ip_conntrack_info ctinfo, - unsigned char **data, - TransportAddress * addr, int count); -extern int (*set_ras_addr_hook) (struct sk_buff ** pskb, - struct ip_conntrack * ct, - enum ip_conntrack_info ctinfo, - unsigned char **data, - TransportAddress * addr, int count); -extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb, - struct ip_conntrack * ct, - enum ip_conntrack_info ctinfo, - unsigned char **data, int dataoff, - H245_TransportAddress * addr, - u_int16_t port, u_int16_t rtp_port, - struct ip_conntrack_expect * rtp_exp, - struct ip_conntrack_expect * rtcp_exp); -extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, - enum ip_conntrack_info ctinfo, - unsigned char **data, int dataoff, - H245_TransportAddress * addr, u_int16_t port, - struct ip_conntrack_expect * exp); -extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, - enum ip_conntrack_info ctinfo, - unsigned char **data, int dataoff, - TransportAddress * addr, u_int16_t port, - struct ip_conntrack_expect * exp); -extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, - enum ip_conntrack_info ctinfo, - unsigned char **data, TransportAddress * addr, - int idx, u_int16_t port, - struct ip_conntrack_expect * exp); - - /****************************************************************************/ static int set_addr(struct sk_buff **pskb, unsigned char **data, int dataoff, diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index efba8c4e42e0..1aba926c1cb0 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c @@ -279,7 +279,7 @@ static struct ipt_target ipt_dnat_reg = { .target = ipt_dnat_target, .targetsize = sizeof(struct ip_nat_multi_range_compat), .table = "nat", - .hooks = 1 << NF_IP_PRE_ROUTING, + .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), .checkentry = ipt_dnat_checkentry, }; diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 3505b0de2e04..8f760b28617e 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -299,69 +299,63 @@ ip_nat_adjust(unsigned int hooknum, /* We must be after connection tracking and before packet filtering. */ -/* Before packet filtering, change destination */ -static struct nf_hook_ops ip_nat_in_ops = { - .hook = ip_nat_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_NAT_DST, +static struct nf_hook_ops ip_nat_ops[] = { + /* Before packet filtering, change destination */ + { + .hook = ip_nat_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = ip_nat_out, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = ip_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, + /* Before packet filtering, change destination */ + { + .hook = ip_nat_local_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_NAT_DST, + }, + /* After packet filtering, change source */ + { + .hook = ip_nat_fn, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SRC, + }, + /* After conntrack, adjust sequence number */ + { + .hook = ip_nat_adjust, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, + }, }; -/* After packet filtering, change source */ -static struct nf_hook_ops ip_nat_out_ops = { - .hook = ip_nat_out, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_NAT_SRC, -}; - -/* After conntrack, adjust sequence number */ -static struct nf_hook_ops ip_nat_adjust_out_ops = { - .hook = ip_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, -}; - -/* Before packet filtering, change destination */ -static struct nf_hook_ops ip_nat_local_out_ops = { - .hook = ip_nat_local_fn, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_NAT_DST, -}; - -/* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */ -static struct nf_hook_ops ip_nat_local_in_ops = { - .hook = ip_nat_fn, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_NAT_SRC, -}; - -/* After conntrack, adjust sequence number */ -static struct nf_hook_ops ip_nat_adjust_in_ops = { - .hook = ip_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, -}; - - -static int init_or_cleanup(int init) +static int __init ip_nat_standalone_init(void) { int ret = 0; need_conntrack(); - if (!init) goto cleanup; - #ifdef CONFIG_XFRM BUG_ON(ip_nat_decode_session != NULL); ip_nat_decode_session = nat_decode_session; @@ -371,50 +365,13 @@ static int init_or_cleanup(int init) printk("ip_nat_init: can't setup rules.\n"); goto cleanup_decode_session; } - ret = nf_register_hook(&ip_nat_in_ops); + ret = nf_register_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops)); if (ret < 0) { - printk("ip_nat_init: can't register in hook.\n"); + printk("ip_nat_init: can't register hooks.\n"); goto cleanup_rule_init; } - ret = nf_register_hook(&ip_nat_out_ops); - if (ret < 0) { - printk("ip_nat_init: can't register out hook.\n"); - goto cleanup_inops; - } - ret = nf_register_hook(&ip_nat_adjust_in_ops); - if (ret < 0) { - printk("ip_nat_init: can't register adjust in hook.\n"); - goto cleanup_outops; - } - ret = nf_register_hook(&ip_nat_adjust_out_ops); - if (ret < 0) { - printk("ip_nat_init: can't register adjust out hook.\n"); - goto cleanup_adjustin_ops; - } - ret = nf_register_hook(&ip_nat_local_out_ops); - if (ret < 0) { - printk("ip_nat_init: can't register local out hook.\n"); - goto cleanup_adjustout_ops; - } - ret = nf_register_hook(&ip_nat_local_in_ops); - if (ret < 0) { - printk("ip_nat_init: can't register local in hook.\n"); - goto cleanup_localoutops; - } return ret; - cleanup: - nf_unregister_hook(&ip_nat_local_in_ops); - cleanup_localoutops: - nf_unregister_hook(&ip_nat_local_out_ops); - cleanup_adjustout_ops: - nf_unregister_hook(&ip_nat_adjust_out_ops); - cleanup_adjustin_ops: - nf_unregister_hook(&ip_nat_adjust_in_ops); - cleanup_outops: - nf_unregister_hook(&ip_nat_out_ops); - cleanup_inops: - nf_unregister_hook(&ip_nat_in_ops); cleanup_rule_init: ip_nat_rule_cleanup(); cleanup_decode_session: @@ -425,14 +382,14 @@ static int init_or_cleanup(int init) return ret; } -static int __init ip_nat_standalone_init(void) -{ - return init_or_cleanup(1); -} - static void __exit ip_nat_standalone_fini(void) { - init_or_cleanup(0); + nf_unregister_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops)); + ip_nat_rule_cleanup(); +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif } module_init(ip_nat_standalone_init); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 896a244f8f91..b93f0494362f 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -662,15 +662,11 @@ static struct nf_queue_handler nfqh = { .outfn = &ipq_enqueue_packet, }; -static int -init_or_cleanup(int init) +static int __init ip_queue_init(void) { int status = -ENOMEM; struct proc_dir_entry *proc; - if (!init) - goto cleanup; - netlink_register_notifier(&ipq_nl_notifier); ipqnl = netlink_kernel_create(NETLINK_FIREWALL, 0, ipq_rcv_sk, THIS_MODULE); @@ -697,11 +693,6 @@ init_or_cleanup(int init) } return status; -cleanup: - nf_unregister_queue_handlers(&nfqh); - synchronize_net(); - ipq_flush(NF_DROP); - cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); @@ -717,15 +708,21 @@ cleanup_netlink_notifier: return status; } -static int __init ip_queue_init(void) -{ - - return init_or_cleanup(1); -} - static void __exit ip_queue_fini(void) { - init_or_cleanup(0); + nf_unregister_queue_handlers(&nfqh); + synchronize_net(); + ipq_flush(NF_DROP); + + unregister_sysctl_table(ipq_sysctl_header); + unregister_netdevice_notifier(&ipq_dev_notifier); + proc_net_remove(IPQ_PROC_FS_NAME); + + sock_release(ipqnl->sk_socket); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); + + netlink_unregister_notifier(&ipq_nl_notifier); } MODULE_DESCRIPTION("IPv4 packet queue handler"); diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index e4768a31718b..aad9d28c8d71 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -725,22 +725,17 @@ static struct file_operations clusterip_proc_fops = { #endif /* CONFIG_PROC_FS */ -static int init_or_cleanup(int fini) +static int __init ipt_clusterip_init(void) { int ret; - if (fini) - goto cleanup; - - if (ipt_register_target(&clusterip_tgt)) { - ret = -EINVAL; - goto cleanup_none; - } + ret = ipt_register_target(&clusterip_tgt); + if (ret < 0) + return ret; - if (nf_register_hook(&cip_arp_ops) < 0) { - ret = -EINVAL; + ret = nf_register_hook(&cip_arp_ops); + if (ret < 0) goto cleanup_target; - } #ifdef CONFIG_PROC_FS clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", proc_net); @@ -753,31 +748,24 @@ static int init_or_cleanup(int fini) printk(KERN_NOTICE "ClusterIP Version %s loaded successfully\n", CLUSTERIP_VERSION); - return 0; -cleanup: - printk(KERN_NOTICE "ClusterIP Version %s unloading\n", - CLUSTERIP_VERSION); -#ifdef CONFIG_PROC_FS - remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent); -#endif cleanup_hook: nf_unregister_hook(&cip_arp_ops); cleanup_target: ipt_unregister_target(&clusterip_tgt); -cleanup_none: - return -EINVAL; -} - -static int __init ipt_clusterip_init(void) -{ - return init_or_cleanup(0); + return ret; } static void __exit ipt_clusterip_fini(void) { - init_or_cleanup(1); + printk(KERN_NOTICE "ClusterIP Version %s unloading\n", + CLUSTERIP_VERSION); +#ifdef CONFIG_PROC_FS + remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent); +#endif + nf_unregister_hook(&cip_arp_ops); + ipt_unregister_target(&clusterip_tgt); } module_init(ipt_clusterip_init); diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 4269a5440d43..0bba3c2bb786 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -106,7 +106,6 @@ static void send_reset(struct sk_buff *oldskb, int hook) struct rtable *rt; u_int16_t tmp_port; u_int32_t tmp_addr; - unsigned int tcplen; int needs_ack; int hh_len; @@ -124,13 +123,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) return; /* Check checksum */ - tcplen = oldskb->len - iph->ihl * 4; - if (((hook != NF_IP_LOCAL_IN && oldskb->ip_summed != CHECKSUM_HW) || - (hook == NF_IP_LOCAL_IN && - oldskb->ip_summed != CHECKSUM_UNNECESSARY)) && - csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP, - oldskb->ip_summed == CHECKSUM_HW ? oldskb->csum : - skb_checksum(oldskb, iph->ihl * 4, tcplen, 0))) + if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) return; if ((rt = route_reverse(oldskb, oth, hook)) == NULL) diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 3d80aefe9cfa..7f417484bfbf 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -157,37 +157,20 @@ static int __init iptable_filter_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ipt_ops[0]); + ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ipt_ops[1]); - if (ret < 0) - goto cleanup_hook0; - - ret = nf_register_hook(&ipt_ops[2]); - if (ret < 0) - goto cleanup_hook1; - return ret; - cleanup_hook1: - nf_unregister_hook(&ipt_ops[1]); - cleanup_hook0: - nf_unregister_hook(&ipt_ops[0]); cleanup_table: ipt_unregister_table(&packet_filter); - return ret; } static void __exit iptable_filter_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ipt_ops[i]); - + nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); ipt_unregister_table(&packet_filter); } diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 412fc96cc896..397b95cc026b 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -211,49 +211,20 @@ static int __init iptable_mangle_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ipt_ops[0]); + ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ipt_ops[1]); - if (ret < 0) - goto cleanup_hook0; - - ret = nf_register_hook(&ipt_ops[2]); - if (ret < 0) - goto cleanup_hook1; - - ret = nf_register_hook(&ipt_ops[3]); - if (ret < 0) - goto cleanup_hook2; - - ret = nf_register_hook(&ipt_ops[4]); - if (ret < 0) - goto cleanup_hook3; - return ret; - cleanup_hook3: - nf_unregister_hook(&ipt_ops[3]); - cleanup_hook2: - nf_unregister_hook(&ipt_ops[2]); - cleanup_hook1: - nf_unregister_hook(&ipt_ops[1]); - cleanup_hook0: - nf_unregister_hook(&ipt_ops[0]); cleanup_table: ipt_unregister_table(&packet_mangler); - return ret; } static void __exit iptable_mangle_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ipt_ops[i]); - + nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); ipt_unregister_table(&packet_mangler); } diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 03cc79a6160a..7912cce1e1b8 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -101,18 +101,18 @@ ipt_hook(unsigned int hook, /* 'raw' is the very first table. */ static struct nf_hook_ops ipt_ops[] = { { - .hook = ipt_hook, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_RAW, - .owner = THIS_MODULE, + .hook = ipt_hook, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_RAW, + .owner = THIS_MODULE, }, { - .hook = ipt_hook, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_RAW, - .owner = THIS_MODULE, + .hook = ipt_hook, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_RAW, + .owner = THIS_MODULE, }, }; @@ -126,31 +126,20 @@ static int __init iptable_raw_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ipt_ops[0]); + ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ipt_ops[1]); - if (ret < 0) - goto cleanup_hook0; - return ret; - cleanup_hook0: - nf_unregister_hook(&ipt_ops[0]); cleanup_table: ipt_unregister_table(&packet_raw); - return ret; } static void __exit iptable_raw_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ipt_ops[i]); - + nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops)); ipt_unregister_table(&packet_raw); } diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 4afbc699d3ba..5bc9f64d7b5b 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -210,71 +210,63 @@ static unsigned int ipv4_conntrack_local(unsigned int hooknum, /* Connection tracking may drop packets, but never alters them, so make it the first hook. */ -static struct nf_hook_ops ipv4_conntrack_defrag_ops = { - .hook = ipv4_conntrack_defrag, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ipv4_conntrack_in_ops = { - .hook = ipv4_conntrack_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_CONNTRACK, -}; - -static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = { - .hook = ipv4_conntrack_defrag, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ipv4_conntrack_local_out_ops = { - .hook = ipv4_conntrack_local, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_CONNTRACK, -}; - -/* helpers */ -static struct nf_hook_ops ipv4_conntrack_helper_out_ops = { - .hook = ipv4_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_HELPER, -}; - -static struct nf_hook_ops ipv4_conntrack_helper_in_ops = { - .hook = ipv4_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_CONNTRACK_HELPER, -}; - - -/* Refragmenter; last chance. */ -static struct nf_hook_ops ipv4_conntrack_out_ops = { - .hook = ipv4_confirm, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_CONFIRM, -}; - -static struct nf_hook_ops ipv4_conntrack_local_in_ops = { - .hook = ipv4_confirm, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_CONNTRACK_CONFIRM, +static struct nf_hook_ops ipv4_conntrack_ops[] = { + { + .hook = ipv4_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ipv4_conntrack_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_CONNTRACK, + }, + { + .hook = ipv4_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ipv4_conntrack_local, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK, + }, + { + .hook = ipv4_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_HELPER, + }, + { + .hook = ipv4_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_CONNTRACK_HELPER, + }, + { + .hook = ipv4_confirm, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, + }, + { + .hook = ipv4_confirm, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, + }, }; #ifdef CONFIG_SYSCTL @@ -440,16 +432,20 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4; extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4; extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp; -static int init_or_cleanup(int init) + +MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); +MODULE_LICENSE("GPL"); + +static int __init nf_conntrack_l3proto_ipv4_init(void) { int ret = 0; - if (!init) goto cleanup; + need_conntrack(); ret = nf_register_sockopt(&so_getorigdst); if (ret < 0) { printk(KERN_ERR "Unable to register netfilter socket option\n"); - goto cleanup_nothing; + return ret; } ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4); @@ -476,84 +472,26 @@ static int init_or_cleanup(int init) goto cleanup_icmp; } - ret = nf_register_hook(&ipv4_conntrack_defrag_ops); + ret = nf_register_hooks(ipv4_conntrack_ops, + ARRAY_SIZE(ipv4_conntrack_ops)); if (ret < 0) { - printk("nf_conntrack_ipv4: can't register pre-routing defrag hook.\n"); + printk("nf_conntrack_ipv4: can't register hooks.\n"); goto cleanup_ipv4; } - ret = nf_register_hook(&ipv4_conntrack_defrag_local_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv4: can't register local_out defrag hook.\n"); - goto cleanup_defragops; - } - - ret = nf_register_hook(&ipv4_conntrack_in_ops); - if (ret < 0) { - printk("nf_conntrack_ipv4: can't register pre-routing hook.\n"); - goto cleanup_defraglocalops; - } - - ret = nf_register_hook(&ipv4_conntrack_local_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv4: can't register local out hook.\n"); - goto cleanup_inops; - } - - ret = nf_register_hook(&ipv4_conntrack_helper_in_ops); - if (ret < 0) { - printk("nf_conntrack_ipv4: can't register local helper hook.\n"); - goto cleanup_inandlocalops; - } - - ret = nf_register_hook(&ipv4_conntrack_helper_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv4: can't register postrouting helper hook.\n"); - goto cleanup_helperinops; - } - - ret = nf_register_hook(&ipv4_conntrack_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv4: can't register post-routing hook.\n"); - goto cleanup_helperoutops; - } - - ret = nf_register_hook(&ipv4_conntrack_local_in_ops); - if (ret < 0) { - printk("nf_conntrack_ipv4: can't register local in hook.\n"); - goto cleanup_inoutandlocalops; - } - #ifdef CONFIG_SYSCTL nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); if (nf_ct_ipv4_sysctl_header == NULL) { printk("nf_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; - goto cleanup_localinops; + goto cleanup_hooks; } #endif return ret; - cleanup: - synchronize_net(); #ifdef CONFIG_SYSCTL - unregister_sysctl_table(nf_ct_ipv4_sysctl_header); - cleanup_localinops: + cleanup_hooks: + nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); #endif - nf_unregister_hook(&ipv4_conntrack_local_in_ops); - cleanup_inoutandlocalops: - nf_unregister_hook(&ipv4_conntrack_out_ops); - cleanup_helperoutops: - nf_unregister_hook(&ipv4_conntrack_helper_out_ops); - cleanup_helperinops: - nf_unregister_hook(&ipv4_conntrack_helper_in_ops); - cleanup_inandlocalops: - nf_unregister_hook(&ipv4_conntrack_local_out_ops); - cleanup_inops: - nf_unregister_hook(&ipv4_conntrack_in_ops); - cleanup_defraglocalops: - nf_unregister_hook(&ipv4_conntrack_defrag_local_out_ops); - cleanup_defragops: - nf_unregister_hook(&ipv4_conntrack_defrag_ops); cleanup_ipv4: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); cleanup_icmp: @@ -564,22 +502,21 @@ static int init_or_cleanup(int init) nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4); cleanup_sockopt: nf_unregister_sockopt(&so_getorigdst); - cleanup_nothing: return ret; } -MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); -MODULE_LICENSE("GPL"); - -static int __init nf_conntrack_l3proto_ipv4_init(void) -{ - need_conntrack(); - return init_or_cleanup(1); -} - static void __exit nf_conntrack_l3proto_ipv4_fini(void) { - init_or_cleanup(0); + synchronize_net(); +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(nf_ct_ipv4_sysctl_header); +#endif + nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); + nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4); + nf_unregister_sockopt(&so_getorigdst); } module_init(nf_conntrack_l3proto_ipv4_init); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 52dc175be39a..4b0d361cc6e6 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -235,30 +235,14 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff, } /* See ip_conntrack_proto_tcp.c */ - if (hooknum != NF_IP_PRE_ROUTING) - goto checksum_skipped; - - switch (skb->ip_summed) { - case CHECKSUM_HW: - if (!(u16)csum_fold(skb->csum)) - break; + if (hooknum == NF_IP_PRE_ROUTING && + nf_ip_checksum(skb, hooknum, dataoff, 0)) { if (LOG_INVALID(IPPROTO_ICMP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, "nf_ct_icmp: bad HW ICMP checksum "); return -NF_ACCEPT; - case CHECKSUM_NONE: - if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) { - if (LOG_INVALID(IPPROTO_ICMP)) - nf_log_packet(PF_INET, 0, skb, NULL, NULL, - NULL, - "nf_ct_icmp: bad ICMP checksum "); - return -NF_ACCEPT; - } - default: - break; } -checksum_skipped: /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index 0d7d386dac22..8d30c48f090e 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -8,6 +8,8 @@ #include <linux/mutex.h> #include <linux/netdevice.h> #include <linux/skbuff.h> +#include <net/icmp.h> +#include <net/ip.h> #include <net/protocol.h> #include <net/xfrm.h> @@ -70,10 +72,16 @@ static int tunnel4_rcv(struct sk_buff *skb) { struct xfrm_tunnel *handler; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto drop; + for (handler = tunnel4_handlers; handler; handler = handler->next) if (!handler->handler(skb)) return 0; + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); + +drop: kfree_skb(skb); return 0; } diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index e1b8f4b90d80..3e174c83bfe7 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -37,8 +37,6 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) { switch (nexthdr) { case IPPROTO_IPIP: - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - return -EINVAL; *spi = skb->nh.iph->saddr; *seq = 0; return 0; @@ -90,7 +88,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) if (unlikely(x->km.state != XFRM_STATE_VALID)) goto drop_unlock; - if (x->encap->encap_type != encap_type) + if ((x->encap ? x->encap->encap_type : 0) != encap_type) goto drop_unlock; if (x->props.replay_window && xfrm_replay_check(x, seq)) diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index bb8ffb8a14c5..2ae84c961678 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -23,6 +23,86 @@ #include <net/inet6_hashtables.h> #include <net/ip.h> +void __inet6_hash(struct inet_hashinfo *hashinfo, + struct sock *sk) +{ + struct hlist_head *list; + rwlock_t *lock; + + BUG_TRAP(sk_unhashed(sk)); + + if (sk->sk_state == TCP_LISTEN) { + list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; + lock = &hashinfo->lhash_lock; + inet_listen_wlock(hashinfo); + } else { + unsigned int hash; + sk->sk_hash = hash = inet6_sk_ehashfn(sk); + hash &= (hashinfo->ehash_size - 1); + list = &hashinfo->ehash[hash].chain; + lock = &hashinfo->ehash[hash].lock; + write_lock(lock); + } + + __sk_add_node(sk, list); + sock_prot_inc_use(sk->sk_prot); + write_unlock(lock); +} +EXPORT_SYMBOL(__inet6_hash); + +/* + * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so + * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM + * + * The sockhash lock must be held as a reader here. + */ +struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, + const struct in6_addr *saddr, + const u16 sport, + const struct in6_addr *daddr, + const u16 hnum, + const int dif) +{ + struct sock *sk; + const struct hlist_node *node; + const __u32 ports = INET_COMBINED_PORTS(sport, hnum); + /* Optimize here for direct hit, only listening connections can + * have wildcards anyways. + */ + unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport); + struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); + + prefetch(head->chain.first); + read_lock(&head->lock); + sk_for_each(sk, node, &head->chain) { + /* For IPV6 do the cheaper port and family tests first. */ + if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif)) + goto hit; /* You sunk my battleship! */ + } + /* Must check for a TIME_WAIT'er before going to listener hash. */ + sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { + const struct inet_timewait_sock *tw = inet_twsk(sk); + + if(*((__u32 *)&(tw->tw_dport)) == ports && + sk->sk_family == PF_INET6) { + const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); + + if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && + ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && + (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) + goto hit; + } + } + read_unlock(&head->lock); + return NULL; + +hit: + sock_hold(sk); + read_unlock(&head->lock); + return sk; +} +EXPORT_SYMBOL(__inet6_lookup_established); + struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, const unsigned short hnum, const int dif) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index ff9040c92556..a995796b5a57 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -519,9 +519,6 @@ ip6ip6_rcv(struct sk_buff *skb) struct ipv6hdr *ipv6h; struct ip6_tnl *t; - if (!pskb_may_pull(skb, sizeof (*ipv6h))) - goto discard; - ipv6h = skb->nh.ipv6h; read_lock(&ip6ip6_lock); @@ -529,8 +526,7 @@ ip6ip6_rcv(struct sk_buff *skb) if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { read_unlock(&ip6ip6_lock); - kfree_skb(skb); - return 0; + goto discard; } if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) { @@ -557,9 +553,11 @@ ip6ip6_rcv(struct sk_buff *skb) return 0; } read_unlock(&ip6ip6_lock); - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); -discard: return 1; + +discard: + kfree_skb(skb); + return 0; } static inline struct ipv6_txoptions *create_tel(__u8 encap_limit) diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index d750cfc019dc..395a417ba955 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -7,6 +7,7 @@ #include <net/ipv6.h> #include <net/ip6_route.h> #include <net/xfrm.h> +#include <net/ip6_checksum.h> int ip6_route_me_harder(struct sk_buff *skb) { @@ -54,7 +55,7 @@ struct ip6_rt_info { struct in6_addr saddr; }; -static void save(const struct sk_buff *skb, struct nf_info *info) +static void nf_ip6_saveroute(const struct sk_buff *skb, struct nf_info *info) { struct ip6_rt_info *rt_info = nf_info_reroute(info); @@ -66,7 +67,7 @@ static void save(const struct sk_buff *skb, struct nf_info *info) } } -static int reroute(struct sk_buff **pskb, const struct nf_info *info) +static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info) { struct ip6_rt_info *rt_info = nf_info_reroute(info); @@ -79,15 +80,50 @@ static int reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -static struct nf_queue_rerouter ip6_reroute = { - .rer_size = sizeof(struct ip6_rt_info), - .save = &save, - .reroute = &reroute, +unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, u_int8_t protocol) +{ + struct ipv6hdr *ip6h = skb->nh.ipv6h; + unsigned int csum = 0; + + switch (skb->ip_summed) { + case CHECKSUM_HW: + if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN) + break; + if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + skb->len - dataoff, protocol, + csum_sub(skb->csum, + skb_checksum(skb, 0, + dataoff, 0)))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + } + /* fall through */ + case CHECKSUM_NONE: + skb->csum = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + skb->len - dataoff, + protocol, + csum_sub(0, + skb_checksum(skb, 0, + dataoff, 0))); + csum = __skb_checksum_complete(skb); + } + return csum; +} + +EXPORT_SYMBOL(nf_ip6_checksum); + +static struct nf_afinfo nf_ip6_afinfo = { + .family = AF_INET6, + .checksum = nf_ip6_checksum, + .saveroute = nf_ip6_saveroute, + .reroute = nf_ip6_reroute, + .route_key_size = sizeof(struct ip6_rt_info), }; int __init ipv6_netfilter_init(void) { - return nf_register_queue_rerouter(PF_INET6, &ip6_reroute); + return nf_register_afinfo(&nf_ip6_afinfo); } /* This can be called from inet6_init() on errors, so it cannot @@ -95,5 +131,5 @@ int __init ipv6_netfilter_init(void) */ void ipv6_netfilter_fini(void) { - nf_unregister_queue_rerouter(PF_INET6); + nf_unregister_afinfo(&nf_ip6_afinfo); } diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e81c6a9dab81..b4b7d441af25 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -658,15 +658,11 @@ static struct nf_queue_handler nfqh = { .outfn = &ipq_enqueue_packet, }; -static int -init_or_cleanup(int init) +static int __init ip6_queue_init(void) { int status = -ENOMEM; struct proc_dir_entry *proc; - if (!init) - goto cleanup; - netlink_register_notifier(&ipq_nl_notifier); ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk, THIS_MODULE); @@ -693,11 +689,6 @@ init_or_cleanup(int init) } return status; -cleanup: - nf_unregister_queue_handlers(&nfqh); - synchronize_net(); - ipq_flush(NF_DROP); - cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); @@ -713,15 +704,21 @@ cleanup_netlink_notifier: return status; } -static int __init ip6_queue_init(void) -{ - - return init_or_cleanup(1); -} - static void __exit ip6_queue_fini(void) { - init_or_cleanup(0); + nf_unregister_queue_handlers(&nfqh); + synchronize_net(); + ipq_flush(NF_DROP); + + unregister_sysctl_table(ipq_sysctl_header); + unregister_netdevice_notifier(&ipq_dev_notifier); + proc_net_remove(IPQ_PROC_FS_NAME); + + sock_release(ipqnl->sk_socket); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); + + netlink_unregister_notifier(&ipq_nl_notifier); } MODULE_DESCRIPTION("IPv6 packet queue handler"); diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index e5e724d9ee60..60976c0c58e8 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -177,37 +177,20 @@ static int __init ip6table_filter_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ip6t_ops[0]); + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ip6t_ops[1]); - if (ret < 0) - goto cleanup_hook0; - - ret = nf_register_hook(&ip6t_ops[2]); - if (ret < 0) - goto cleanup_hook1; - return ret; - cleanup_hook1: - nf_unregister_hook(&ip6t_ops[1]); - cleanup_hook0: - nf_unregister_hook(&ip6t_ops[0]); cleanup_table: ip6t_unregister_table(&packet_filter); - return ret; } static void __exit ip6table_filter_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ip6t_ops[i]); - + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); ip6t_unregister_table(&packet_filter); } diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index e1f0f6ae9841..03a13eab1dae 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -238,49 +238,20 @@ static int __init ip6table_mangle_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ip6t_ops[0]); + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ip6t_ops[1]); - if (ret < 0) - goto cleanup_hook0; - - ret = nf_register_hook(&ip6t_ops[2]); - if (ret < 0) - goto cleanup_hook1; - - ret = nf_register_hook(&ip6t_ops[3]); - if (ret < 0) - goto cleanup_hook2; - - ret = nf_register_hook(&ip6t_ops[4]); - if (ret < 0) - goto cleanup_hook3; - return ret; - cleanup_hook3: - nf_unregister_hook(&ip6t_ops[3]); - cleanup_hook2: - nf_unregister_hook(&ip6t_ops[2]); - cleanup_hook1: - nf_unregister_hook(&ip6t_ops[1]); - cleanup_hook0: - nf_unregister_hook(&ip6t_ops[0]); cleanup_table: ip6t_unregister_table(&packet_mangler); - return ret; } static void __exit ip6table_mangle_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ip6t_ops[i]); - + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); ip6t_unregister_table(&packet_mangler); } diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 54d1fffd62ba..61a7c58e99f8 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -152,31 +152,20 @@ static int __init ip6table_raw_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ip6t_ops[0]); + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ip6t_ops[1]); - if (ret < 0) - goto cleanup_hook0; - return ret; - cleanup_hook0: - nf_unregister_hook(&ip6t_ops[0]); cleanup_table: ip6t_unregister_table(&packet_raw); - return ret; } static void __exit ip6table_raw_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ip6t_ops[i]); - + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); ip6t_unregister_table(&packet_raw); } diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index c8b5a96cbb0f..93bae36f2663 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -286,55 +286,49 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, return ipv6_conntrack_in(hooknum, pskb, in, out, okfn); } -/* Connection tracking may drop packets, but never alters them, so - make it the first hook. */ -static struct nf_hook_ops ipv6_conntrack_defrag_ops = { - .hook = ipv6_defrag, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ipv6_conntrack_in_ops = { - .hook = ipv6_conntrack_in, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_CONNTRACK, -}; - -static struct nf_hook_ops ipv6_conntrack_local_out_ops = { - .hook = ipv6_conntrack_local, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_OUT, - .priority = NF_IP6_PRI_CONNTRACK, -}; - -static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = { - .hook = ipv6_defrag, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_OUT, - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, -}; - -/* Refragmenter; last chance. */ -static struct nf_hook_ops ipv6_conntrack_out_ops = { - .hook = ipv6_confirm, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_POST_ROUTING, - .priority = NF_IP6_PRI_LAST, -}; - -static struct nf_hook_ops ipv6_conntrack_local_in_ops = { - .hook = ipv6_confirm, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_IN, - .priority = NF_IP6_PRI_LAST-1, +static struct nf_hook_ops ipv6_conntrack_ops[] = { + { + .hook = ipv6_defrag, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_PRE_ROUTING, + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ipv6_conntrack_in, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_PRE_ROUTING, + .priority = NF_IP6_PRI_CONNTRACK, + }, + { + .hook = ipv6_conntrack_local, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_OUT, + .priority = NF_IP6_PRI_CONNTRACK, + }, + { + .hook = ipv6_defrag, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_OUT, + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ipv6_confirm, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_POST_ROUTING, + .priority = NF_IP6_PRI_LAST, + }, + { + .hook = ipv6_confirm, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_IN, + .priority = NF_IP6_PRI_LAST-1, + }, }; #ifdef CONFIG_SYSCTL @@ -470,16 +464,21 @@ extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6; extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6; extern int nf_ct_frag6_init(void); extern void nf_ct_frag6_cleanup(void); -static int init_or_cleanup(int init) + +MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); + +static int __init nf_conntrack_l3proto_ipv6_init(void) { int ret = 0; - if (!init) goto cleanup; + need_conntrack(); ret = nf_ct_frag6_init(); if (ret < 0) { printk("nf_conntrack_ipv6: can't initialize frag6.\n"); - goto cleanup_nothing; + return ret; } ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6); if (ret < 0) { @@ -505,71 +504,27 @@ static int init_or_cleanup(int init) goto cleanup_icmpv6; } - ret = nf_register_hook(&ipv6_conntrack_defrag_ops); + ret = nf_register_hooks(ipv6_conntrack_ops, + ARRAY_SIZE(ipv6_conntrack_ops)); if (ret < 0) { printk("nf_conntrack_ipv6: can't register pre-routing defrag " "hook.\n"); goto cleanup_ipv6; } - - ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register local_out defrag " - "hook.\n"); - goto cleanup_defragops; - } - - ret = nf_register_hook(&ipv6_conntrack_in_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register pre-routing hook.\n"); - goto cleanup_defraglocalops; - } - - ret = nf_register_hook(&ipv6_conntrack_local_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register local out hook.\n"); - goto cleanup_inops; - } - - ret = nf_register_hook(&ipv6_conntrack_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register post-routing hook.\n"); - goto cleanup_inandlocalops; - } - - ret = nf_register_hook(&ipv6_conntrack_local_in_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register local in hook.\n"); - goto cleanup_inoutandlocalops; - } - #ifdef CONFIG_SYSCTL nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); if (nf_ct_ipv6_sysctl_header == NULL) { printk("nf_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; - goto cleanup_localinops; + goto cleanup_hooks; } #endif return ret; - cleanup: - synchronize_net(); #ifdef CONFIG_SYSCTL - unregister_sysctl_table(nf_ct_ipv6_sysctl_header); - cleanup_localinops: + cleanup_hooks: + nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); #endif - nf_unregister_hook(&ipv6_conntrack_local_in_ops); - cleanup_inoutandlocalops: - nf_unregister_hook(&ipv6_conntrack_out_ops); - cleanup_inandlocalops: - nf_unregister_hook(&ipv6_conntrack_local_out_ops); - cleanup_inops: - nf_unregister_hook(&ipv6_conntrack_in_ops); - cleanup_defraglocalops: - nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops); - cleanup_defragops: - nf_unregister_hook(&ipv6_conntrack_defrag_ops); cleanup_ipv6: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); cleanup_icmpv6: @@ -580,23 +535,21 @@ static int init_or_cleanup(int init) nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); cleanup_frag6: nf_ct_frag6_cleanup(); - cleanup_nothing: return ret; } -MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); - -static int __init nf_conntrack_l3proto_ipv6_init(void) -{ - need_conntrack(); - return init_or_cleanup(1); -} - static void __exit nf_conntrack_l3proto_ipv6_fini(void) { - init_or_cleanup(0); + synchronize_net(); +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(nf_ct_ipv6_sysctl_header); +#endif + nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); + nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); + nf_ct_frag6_cleanup(); } module_init(nf_conntrack_l3proto_ipv6_init); diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 09945c333055..86c6703265d0 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -233,21 +233,13 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff, return -NF_ACCEPT; } - if (hooknum != NF_IP6_PRE_ROUTING) - goto skipped; - - /* Ignore it if the checksum's bogus. */ - if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, - skb->len - dataoff, IPPROTO_ICMPV6, - skb_checksum(skb, dataoff, - skb->len - dataoff, 0))) { + if (hooknum == NF_IP6_PRE_ROUTING && + nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, "nf_ct_icmpv6: ICMPv6 checksum failed\n"); return -NF_ACCEPT; } -skipped: - /* is not error message ? */ if (icmp6h->icmp6_type >= 128) return NF_ACCEPT; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index c2d3e17beae6..6578c3080f47 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -397,7 +397,7 @@ static int ipip6_rcv(struct sk_buff *skb) return 0; } - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); kfree_skb(skb); read_unlock(&ipip6_lock); out: diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 5659b52284bd..0ef9a35798d1 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -19,11 +19,13 @@ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> */ +#include <linux/icmpv6.h> #include <linux/init.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/netdevice.h> #include <linux/skbuff.h> +#include <net/ipv6.h> #include <net/protocol.h> #include <net/xfrm.h> @@ -87,10 +89,16 @@ static int tunnel6_rcv(struct sk_buff **pskb) struct sk_buff *skb = *pskb; struct xfrm6_tunnel *handler; + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto drop; + for (handler = tunnel6_handlers; handler; handler = handler->next) if (!handler->handler(skb)) return 0; + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); + +drop: kfree_skb(skb); return 0; } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 1ceb1a6c254b..8455a32ea5c4 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -27,6 +27,29 @@ #include "nf_internals.h" +static DEFINE_SPINLOCK(afinfo_lock); + +struct nf_afinfo *nf_afinfo[NPROTO]; +EXPORT_SYMBOL(nf_afinfo); + +int nf_register_afinfo(struct nf_afinfo *afinfo) +{ + spin_lock(&afinfo_lock); + rcu_assign_pointer(nf_afinfo[afinfo->family], afinfo); + spin_unlock(&afinfo_lock); + return 0; +} +EXPORT_SYMBOL_GPL(nf_register_afinfo); + +void nf_unregister_afinfo(struct nf_afinfo *afinfo) +{ + spin_lock(&afinfo_lock); + rcu_assign_pointer(nf_afinfo[afinfo->family], NULL); + spin_unlock(&afinfo_lock); + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(nf_unregister_afinfo); + /* In this code, we can be waiting indefinitely for userspace to * service a packet if a hook returns NF_QUEUE. We could keep a count * of skbuffs queued for userspace, and not deregister a hook unless @@ -63,6 +86,34 @@ void nf_unregister_hook(struct nf_hook_ops *reg) } EXPORT_SYMBOL(nf_unregister_hook); +int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n) +{ + unsigned int i; + int err = 0; + + for (i = 0; i < n; i++) { + err = nf_register_hook(®[i]); + if (err) + goto err; + } + return err; + +err: + if (i > 0) + nf_unregister_hooks(reg, i); + return err; +} +EXPORT_SYMBOL(nf_register_hooks); + +void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; i++) + nf_unregister_hook(®[i]); +} +EXPORT_SYMBOL(nf_unregister_hooks); + unsigned int nf_iterate(struct list_head *head, struct sk_buff **skb, int hook, diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 6492ed66fb3c..69899f27d26a 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -799,8 +799,7 @@ static int tcp_error(struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info *ctinfo, int pf, - unsigned int hooknum, - int(*csum)(const struct sk_buff *,unsigned int)) + unsigned int hooknum) { struct tcphdr _tcph, *th; unsigned int tcplen = skb->len - dataoff; @@ -830,9 +829,8 @@ static int tcp_error(struct sk_buff *skb, */ /* FIXME: Source route IP option packets --RR */ if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || - (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) - && skb->ip_summed != CHECKSUM_UNNECESSARY - && csum(skb, dataoff)) { + (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) && + nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) { if (LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: bad TCP checksum "); @@ -851,44 +849,6 @@ static int tcp_error(struct sk_buff *skb, return NF_ACCEPT; } -static int csum4(const struct sk_buff *skb, unsigned int dataoff) -{ - return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, - skb->len - dataoff, IPPROTO_TCP, - skb->ip_summed == CHECKSUM_HW ? skb->csum - : skb_checksum(skb, dataoff, - skb->len - dataoff, 0)); -} - -static int csum6(const struct sk_buff *skb, unsigned int dataoff) -{ - return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, - skb->len - dataoff, IPPROTO_TCP, - skb->ip_summed == CHECKSUM_HW - ? csum_sub(skb->csum, - skb_checksum(skb, 0, dataoff, 0)) - : skb_checksum(skb, dataoff, skb->len - dataoff, - 0)); -} - -static int tcp_error4(struct sk_buff *skb, - unsigned int dataoff, - enum ip_conntrack_info *ctinfo, - int pf, - unsigned int hooknum) -{ - return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum4); -} - -static int tcp_error6(struct sk_buff *skb, - unsigned int dataoff, - enum ip_conntrack_info *ctinfo, - int pf, - unsigned int hooknum) -{ - return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum6); -} - /* Returns verdict for packet, or -1 for invalid. */ static int tcp_packet(struct nf_conn *conntrack, const struct sk_buff *skb, @@ -1218,7 +1178,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = .print_conntrack = tcp_print_conntrack, .packet = tcp_packet, .new = tcp_new, - .error = tcp_error4, + .error = tcp_error, #if defined(CONFIG_NF_CT_NETLINK) || \ defined(CONFIG_NF_CT_NETLINK_MODULE) .to_nfattr = tcp_to_nfattr, @@ -1239,7 +1199,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = .print_conntrack = tcp_print_conntrack, .packet = tcp_packet, .new = tcp_new, - .error = tcp_error6, + .error = tcp_error, #if defined(CONFIG_NF_CT_NETLINK) || \ defined(CONFIG_NF_CT_NETLINK_MODULE) .to_nfattr = tcp_to_nfattr, diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 831d206344e0..d93edbfde9e3 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -103,8 +103,7 @@ static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb, static int udp_error(struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info *ctinfo, int pf, - unsigned int hooknum, - int (*csum)(const struct sk_buff *, unsigned int)) + unsigned int hooknum) { unsigned int udplen = skb->len - dataoff; struct udphdr _hdr, *hdr; @@ -136,9 +135,8 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff, * and moreover root might send raw packets. * FIXME: Source route IP option packets --RR */ if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || - (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) - && skb->ip_summed != CHECKSUM_UNNECESSARY - && csum(skb, dataoff)) { + (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) && + nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) { if (LOG_INVALID(IPPROTO_UDP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_udp: bad UDP checksum "); @@ -148,44 +146,6 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff, return NF_ACCEPT; } -static int csum4(const struct sk_buff *skb, unsigned int dataoff) -{ - return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, - skb->len - dataoff, IPPROTO_UDP, - skb->ip_summed == CHECKSUM_HW ? skb->csum - : skb_checksum(skb, dataoff, - skb->len - dataoff, 0)); -} - -static int csum6(const struct sk_buff *skb, unsigned int dataoff) -{ - return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, - skb->len - dataoff, IPPROTO_UDP, - skb->ip_summed == CHECKSUM_HW - ? csum_sub(skb->csum, - skb_checksum(skb, 0, dataoff, 0)) - : skb_checksum(skb, dataoff, skb->len - dataoff, - 0)); -} - -static int udp_error4(struct sk_buff *skb, - unsigned int dataoff, - enum ip_conntrack_info *ctinfo, - int pf, - unsigned int hooknum) -{ - return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum4); -} - -static int udp_error6(struct sk_buff *skb, - unsigned int dataoff, - enum ip_conntrack_info *ctinfo, - int pf, - unsigned int hooknum) -{ - return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum6); -} - struct nf_conntrack_protocol nf_conntrack_protocol_udp4 = { .l3proto = PF_INET, @@ -197,7 +157,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp4 = .print_conntrack = udp_print_conntrack, .packet = udp_packet, .new = udp_new, - .error = udp_error4, + .error = udp_error, #if defined(CONFIG_NF_CT_NETLINK) || \ defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, @@ -216,7 +176,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = .print_conntrack = udp_print_conntrack, .packet = udp_packet, .new = udp_new, - .error = udp_error6, + .error = udp_error, #if defined(CONFIG_NF_CT_NETLINK) || \ defined(CONFIG_NF_CT_NETLINK_MODULE) .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index c72aa3cd22e4..408960c6a544 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -649,63 +649,6 @@ static ctl_table nf_ct_net_table[] = { EXPORT_SYMBOL(nf_ct_log_invalid); #endif /* CONFIG_SYSCTL */ -static int init_or_cleanup(int init) -{ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *proc, *proc_exp, *proc_stat; -#endif - int ret = 0; - - if (!init) goto cleanup; - - ret = nf_conntrack_init(); - if (ret < 0) - goto cleanup_nothing; - -#ifdef CONFIG_PROC_FS - proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops); - if (!proc) goto cleanup_init; - - proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440, - &exp_file_ops); - if (!proc_exp) goto cleanup_proc; - - proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat); - if (!proc_stat) - goto cleanup_proc_exp; - - proc_stat->proc_fops = &ct_cpu_seq_fops; - proc_stat->owner = THIS_MODULE; -#endif -#ifdef CONFIG_SYSCTL - nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); - if (nf_ct_sysctl_header == NULL) { - printk("nf_conntrack: can't register to sysctl.\n"); - ret = -ENOMEM; - goto cleanup_proc_stat; - } -#endif - - return ret; - - cleanup: -#ifdef CONFIG_SYSCTL - unregister_sysctl_table(nf_ct_sysctl_header); - cleanup_proc_stat: -#endif -#ifdef CONFIG_PROC_FS - remove_proc_entry("nf_conntrack", proc_net_stat); - cleanup_proc_exp: - proc_net_remove("nf_conntrack_expect"); - cleanup_proc: - proc_net_remove("nf_conntrack"); - cleanup_init: -#endif /* CNFIG_PROC_FS */ - nf_conntrack_cleanup(); - cleanup_nothing: - return ret; -} - int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) { int ret = 0; @@ -808,12 +751,66 @@ void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto) static int __init nf_conntrack_standalone_init(void) { - return init_or_cleanup(1); +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc, *proc_exp, *proc_stat; +#endif + int ret = 0; + + ret = nf_conntrack_init(); + if (ret < 0) + return ret; + +#ifdef CONFIG_PROC_FS + proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops); + if (!proc) goto cleanup_init; + + proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440, + &exp_file_ops); + if (!proc_exp) goto cleanup_proc; + + proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat); + if (!proc_stat) + goto cleanup_proc_exp; + + proc_stat->proc_fops = &ct_cpu_seq_fops; + proc_stat->owner = THIS_MODULE; +#endif +#ifdef CONFIG_SYSCTL + nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); + if (nf_ct_sysctl_header == NULL) { + printk("nf_conntrack: can't register to sysctl.\n"); + ret = -ENOMEM; + goto cleanup_proc_stat; + } +#endif + return ret; + +#ifdef CONFIG_SYSCTL + cleanup_proc_stat: +#endif +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_conntrack", proc_net_stat); + cleanup_proc_exp: + proc_net_remove("nf_conntrack_expect"); + cleanup_proc: + proc_net_remove("nf_conntrack"); + cleanup_init: +#endif /* CNFIG_PROC_FS */ + nf_conntrack_cleanup(); + return ret; } static void __exit nf_conntrack_standalone_fini(void) { - init_or_cleanup(0); +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(nf_ct_sysctl_header); +#endif +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_conntrack", proc_net_stat); + proc_net_remove("nf_conntrack_expect"); + proc_net_remove("nf_conntrack"); +#endif /* CNFIG_PROC_FS */ + nf_conntrack_cleanup(); } module_init(nf_conntrack_standalone_init); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index d9f0d7ef103b..ee8f70889f47 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -17,7 +17,6 @@ * for queueing and must reinject all packets it receives, no matter what. */ static struct nf_queue_handler *queue_handler[NPROTO]; -static struct nf_queue_rerouter *queue_rerouter[NPROTO]; static DEFINE_RWLOCK(queue_handler_lock); @@ -59,32 +58,6 @@ int nf_unregister_queue_handler(int pf) } EXPORT_SYMBOL(nf_unregister_queue_handler); -int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer) -{ - if (pf >= NPROTO) - return -EINVAL; - - write_lock_bh(&queue_handler_lock); - rcu_assign_pointer(queue_rerouter[pf], rer); - write_unlock_bh(&queue_handler_lock); - - return 0; -} -EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); - -int nf_unregister_queue_rerouter(int pf) -{ - if (pf >= NPROTO) - return -EINVAL; - - write_lock_bh(&queue_handler_lock); - rcu_assign_pointer(queue_rerouter[pf], NULL); - write_unlock_bh(&queue_handler_lock); - synchronize_rcu(); - return 0; -} -EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); - void nf_unregister_queue_handlers(struct nf_queue_handler *qh) { int pf; @@ -116,7 +89,7 @@ int nf_queue(struct sk_buff **skb, struct net_device *physindev = NULL; struct net_device *physoutdev = NULL; #endif - struct nf_queue_rerouter *rerouter; + struct nf_afinfo *afinfo; /* QUEUE == DROP if noone is waiting, to be safe. */ read_lock(&queue_handler_lock); @@ -126,7 +99,14 @@ int nf_queue(struct sk_buff **skb, return 1; } - info = kmalloc(sizeof(*info)+queue_rerouter[pf]->rer_size, GFP_ATOMIC); + afinfo = nf_get_afinfo(pf); + if (!afinfo) { + read_unlock(&queue_handler_lock); + kfree_skb(*skb); + return 1; + } + + info = kmalloc(sizeof(*info) + afinfo->route_key_size, GFP_ATOMIC); if (!info) { if (net_ratelimit()) printk(KERN_ERR "OOM queueing packet %p\n", @@ -158,10 +138,7 @@ int nf_queue(struct sk_buff **skb, if (physoutdev) dev_hold(physoutdev); } #endif - rerouter = rcu_dereference(queue_rerouter[pf]); - if (rerouter) - rerouter->save(*skb, info); - + afinfo->saveroute(*skb, info); status = queue_handler[pf]->outfn(*skb, info, queuenum, queue_handler[pf]->data); @@ -190,7 +167,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, { struct list_head *elem = &info->elem->list; struct list_head *i; - struct nf_queue_rerouter *rerouter; + struct nf_afinfo *afinfo; rcu_read_lock(); @@ -228,8 +205,8 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, } if (verdict == NF_ACCEPT) { - rerouter = rcu_dereference(queue_rerouter[info->pf]); - if (rerouter && rerouter->reroute(&skb, info) < 0) + afinfo = nf_get_afinfo(info->pf); + if (!afinfo || afinfo->reroute(&skb, info) < 0) verdict = NF_DROP; } diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 3e3f5448bacb..c60273cad778 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -1033,17 +1033,13 @@ static struct file_operations nful_file_ops = { #endif /* PROC_FS */ -static int -init_or_cleanup(int init) +static int __init nfnetlink_log_init(void) { int i, status = -ENOMEM; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_nful; #endif - if (!init) - goto cleanup; - for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -1066,30 +1062,25 @@ init_or_cleanup(int init) goto cleanup_subsys; proc_nful->proc_fops = &nful_file_ops; #endif - return status; -cleanup: - nf_log_unregister_logger(&nfulnl_logger); #ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_log", proc_net_netfilter); cleanup_subsys: -#endif nfnetlink_subsys_unregister(&nfulnl_subsys); +#endif cleanup_netlink_notifier: netlink_unregister_notifier(&nfulnl_rtnl_notifier); return status; } -static int __init nfnetlink_log_init(void) -{ - - return init_or_cleanup(1); -} - static void __exit nfnetlink_log_fini(void) { - init_or_cleanup(0); + nf_log_unregister_logger(&nfulnl_logger); +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_log", proc_net_netfilter); +#endif + nfnetlink_subsys_unregister(&nfulnl_subsys); + netlink_unregister_notifier(&nfulnl_rtnl_notifier); } MODULE_DESCRIPTION("netfilter userspace logging"); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index d0e62f68139f..86a4ac33de34 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -1071,17 +1071,13 @@ static struct file_operations nfqnl_file_ops = { #endif /* PROC_FS */ -static int -init_or_cleanup(int init) +static int __init nfnetlink_queue_init(void) { int i, status = -ENOMEM; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_nfqueue; #endif - if (!init) - goto cleanup; - for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -1101,31 +1097,26 @@ init_or_cleanup(int init) #endif register_netdevice_notifier(&nfqnl_dev_notifier); - return status; -cleanup: - nf_unregister_queue_handlers(&nfqh); - unregister_netdevice_notifier(&nfqnl_dev_notifier); #ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_queue", proc_net_netfilter); cleanup_subsys: -#endif nfnetlink_subsys_unregister(&nfqnl_subsys); +#endif cleanup_netlink_notifier: netlink_unregister_notifier(&nfqnl_rtnl_notifier); return status; } -static int __init nfnetlink_queue_init(void) -{ - - return init_or_cleanup(1); -} - static void __exit nfnetlink_queue_fini(void) { - init_or_cleanup(0); + nf_unregister_queue_handlers(&nfqh); + unregister_netdevice_notifier(&nfqnl_dev_notifier); +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_queue", proc_net_netfilter); +#endif + nfnetlink_subsys_unregister(&nfqnl_subsys); + netlink_unregister_notifier(&nfqnl_rtnl_notifier); } MODULE_DESCRIPTION("netfilter packet queue handler"); diff --git a/net/sched/act_police.c b/net/sched/act_police.c index fa877f8f652c..24c348fa8922 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -66,7 +66,7 @@ static __inline__ struct tcf_police * tcf_police_lookup(u32 index) } #ifdef CONFIG_NET_CLS_ACT -static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, +static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, int type, struct tc_action *a) { struct tcf_police *p; @@ -113,7 +113,7 @@ rtattr_failure: } static inline int -tcf_hash_search(struct tc_action *a, u32 index) +tcf_act_police_hash_search(struct tc_action *a, u32 index) { struct tcf_police *p = tcf_police_lookup(index); @@ -387,9 +387,9 @@ static struct tc_action_ops act_police_ops = { .act = tcf_act_police, .dump = tcf_act_police_dump, .cleanup = tcf_act_police_cleanup, - .lookup = tcf_hash_search, + .lookup = tcf_act_police_hash_search, .init = tcf_act_police_locate, - .walk = tcf_generic_walker + .walk = tcf_act_police_walker }; static int __init |