From a83d6c0de8811d7bcc4eb67ed199d1120ca6cad8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 17 Feb 2007 23:58:44 +0100 Subject: [Bluetooth] Fix wrong put_user() from HIDP compat ioctl patch The compat ioctl patch copied the parser version field into the report descriptor size field by mistake. Signed-off-by: Marcel Holtmann --- net/bluetooth/hidp/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 8b8a6c1dbd9..0c185257e55 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -194,7 +194,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne if (put_user(ca.ctrl_sock, &uca->ctrl_sock) || put_user(ca.intr_sock, &uca->intr_sock) || put_user(ca.parser, &uca->parser) || - put_user(ca.rd_size, &uca->parser) || + put_user(ca.rd_size, &uca->rd_size) || put_user(compat_ptr(ca.rd_data), &uca->rd_data) || put_user(ca.country, &uca->country) || put_user(ca.subclass, &uca->subclass) || -- cgit From e1aaadd4d8162a2c33e41dd5a72234ea4d3b014f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 17 Feb 2007 23:58:49 +0100 Subject: [Bluetooth] Add support for using the HID subsystem This patch extends the current Bluetooth HID support to use the new HID subsystem and adds full report mode support. Signed-off-by: Marcel Holtmann --- net/bluetooth/hidp/Kconfig | 1 + net/bluetooth/hidp/core.c | 170 ++++++++++++++++++++++++++++++++++++++++++--- net/bluetooth/hidp/hidp.h | 2 + 3 files changed, 164 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig index c6abf2a5a93..98fdfa1fbdd 100644 --- a/net/bluetooth/hidp/Kconfig +++ b/net/bluetooth/hidp/Kconfig @@ -1,6 +1,7 @@ config BT_HIDP tristate "HIDP protocol support" depends on BT && BT_L2CAP && INPUT + select HID help HIDP (Human Interface Device Protocol) is a transport layer for HID reports. HIDP is required for the Bluetooth Human diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 4b99c5e4478..05e23bbcb0a 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -50,7 +51,7 @@ #define BT_DBG(D...) #endif -#define VERSION "1.1" +#define VERSION "1.2" static DECLARE_RWSEM(hidp_session_sem); static LIST_HEAD(hidp_session_list); @@ -124,15 +125,22 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin else strncpy(ci->name, "HID Boot Device", 128); } + + if (session->hid) { + ci->vendor = session->hid->vendor; + ci->product = session->hid->product; + ci->version = session->hid->version; + strncpy(ci->name, session->hid->name, 128); + } } -static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static inline int hidp_queue_event(struct hidp_session *session, struct input_dev *dev, + unsigned int type, unsigned int code, int value) { - struct hidp_session *session = dev->private; - struct sk_buff *skb; unsigned char newleds; + struct sk_buff *skb; - BT_DBG("input %p type %d code %d value %d", dev, type, code, value); + BT_DBG("session %p type %d code %d value %d", session, type, code, value); if (type != EV_LED) return -1; @@ -164,6 +172,21 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned i return 0; } +static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct hid_device *hid = dev->private; + struct hidp_session *session = hid->driver_data; + + return hidp_queue_event(session, dev, type, code, value); +} + +static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct hidp_session *session = dev->private; + + return hidp_queue_event(session, dev, type, code, value); +} + static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb) { struct input_dev *dev = session->input; @@ -219,6 +242,42 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb) input_sync(dev); } +static inline int hidp_queue_report(struct hidp_session *session, unsigned char *data, int size) +{ + struct sk_buff *skb; + + BT_DBG("session %p hid %p data %p size %d", session, device, data, size); + + if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) { + BT_ERR("Can't allocate memory for new frame"); + return -ENOMEM; + } + + *skb_put(skb, 1) = 0xa2; + if (size > 0) + memcpy(skb_put(skb, size), data, size); + + skb_queue_tail(&session->intr_transmit, skb); + + hidp_schedule(session); + + return 0; +} + +static int hidp_send_report(struct hidp_session *session, struct hid_report *report) +{ + unsigned char buf[32]; + int rsize; + + rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0); + if (rsize > sizeof(buf)) + return -EIO; + + hid_output_report(report, buf); + + return hidp_queue_report(session, buf, rsize); +} + static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; @@ -346,6 +405,10 @@ static inline void hidp_process_data(struct hidp_session *session, struct sk_buf if (session->input) hidp_input_report(session, skb); + + if (session->hid) + hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0); + break; case HIDP_DATA_RTYPE_OTHER: @@ -404,8 +467,14 @@ static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_ if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) { hidp_set_timer(session); + if (session->input) hidp_input_report(session, skb); + + if (session->hid) { + hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1); + BT_DBG("report len %d", skb->len); + } } else { BT_DBG("Unsupported protocol header 0x%02x", hdr); } @@ -471,6 +540,11 @@ static int hidp_session(void *arg) product = session->input->id.product; } + if (session->hid) { + vendor = session->hid->vendor; + product = session->hid->product; + } + daemonize("khidpd_%04x%04x", vendor, product); set_user_nice(current, -15); current->flags |= PF_NOFREEZE; @@ -521,6 +595,12 @@ static int hidp_session(void *arg) session->input = NULL; } + if (session->hid) { + if (session->hid->claimed & HID_CLAIMED_INPUT) + hidinput_disconnect(session->hid); + hid_free_device(session->hid); + } + up_write(&hidp_session_sem); kfree(session); @@ -590,6 +670,44 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co input_register_device(input); } +static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_connadd_req *req) +{ + struct hid_device *hid = session->hid; + struct hid_report *report; + bdaddr_t src, dst; + + baswap(&src, &bt_sk(session->ctrl_sock->sk)->src); + baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst); + + hid->driver_data = session; + + hid->country = req->country; + + hid->bus = BUS_BLUETOOTH; + hid->vendor = req->vendor; + hid->product = req->product; + hid->version = req->version; + + strncpy(hid->name, req->name, 128); + strncpy(hid->phys, batostr(&src), 64); + strncpy(hid->uniq, batostr(&dst), 64); + + hid->dev = hidp_get_device(session); + + hid->hidinput_input_event = hidp_hidinput_event; + + list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) + hidp_send_report(session, report); + + list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) + hidp_send_report(session, report); + + if (hidinput_connect(hid) == 0) { + hid->claimed |= HID_CLAIMED_INPUT; + hid_ff_init(hid); + } +} + int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) { struct hidp_session *session, *s; @@ -605,10 +723,38 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, if (!session) return -ENOMEM; - session->input = input_allocate_device(); - if (!session->input) { - kfree(session); - return -ENOMEM; + BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size); + + if (req->rd_size > 0) { + unsigned char *buf = kmalloc(req->rd_size, GFP_KERNEL); + + if (!buf) { + kfree(session); + return -ENOMEM; + } + + if (copy_from_user(buf, req->rd_data, req->rd_size)) { + kfree(buf); + kfree(session); + return -EFAULT; + } + + session->hid = hid_parse_report(buf, req->rd_size); + + kfree(buf); + + if (!session->hid) { + kfree(session); + return -EINVAL; + } + } + + if (!session->hid) { + session->input = input_allocate_device(); + if (!session->input) { + kfree(session); + return -ENOMEM; + } } down_write(&hidp_session_sem); @@ -644,6 +790,9 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, if (session->input) hidp_setup_input(session, req); + if (session->hid) + hidp_setup_hid(session, req); + __hidp_link_session(session); hidp_set_timer(session); @@ -677,6 +826,9 @@ unlink: failed: up_write(&hidp_session_sem); + if (session->hid) + hid_free_device(session->hid); + kfree(session->input); kfree(session); return err; diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index a326601c8f4..343fb0566b3 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -145,6 +145,8 @@ struct hidp_session { struct input_dev *input; + struct hid_device *hid; + struct timer_list timer; struct sk_buff_head ctrl_transmit; -- cgit From f5ffd4620aba9e55656483ae1ef5c79ba81f5403 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 17 Feb 2007 23:58:53 +0100 Subject: [Bluetooth] Add open and close callbacks for HID device The open and close callbacks for the HID device are not optional, but for the Bluetooth HID report mode support it is enough to add empty dummy callbacks. Signed-off-by: Marcel Holtmann --- net/bluetooth/hidp/core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 05e23bbcb0a..4c914df5fd0 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -670,6 +670,15 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co input_register_device(input); } +static int hidp_open(struct hid_device *hid) +{ + return 0; +} + +static void hidp_close(struct hid_device *hid) +{ +} + static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_connadd_req *req) { struct hid_device *hid = session->hid; @@ -694,6 +703,9 @@ static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_conn hid->dev = hidp_get_device(session); + hid->hid_open = hidp_open; + hid->hid_close = hidp_close; + hid->hidinput_input_event = hidp_hidinput_event; list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) -- cgit From c1a3313698895d8ad4760f98642007bf236af2e8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 17 Feb 2007 23:58:57 +0100 Subject: [Bluetooth] Make use of device_move() for RFCOMM TTY devices In the case of bound RFCOMM TTY devices the parent is not available before its usage. So when opening a RFCOMM TTY device, move it to the corresponding ACL device as a child. When closing the device, move it back to the virtual device tree. Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 8cd82dce500..9a7a44fc721 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -74,6 +74,8 @@ struct rfcomm_dev { wait_queue_head_t wait; struct tasklet_struct wakeup_task; + struct device *tty_dev; + atomic_t wmem_alloc; }; @@ -261,7 +263,7 @@ out: return err; } - tty_register_device(rfcomm_tty_driver, dev->id, rfcomm_get_device(dev)); + dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); return dev->id; } @@ -630,6 +632,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) set_current_state(TASK_RUNNING); remove_wait_queue(&dev->wait, &wait); + if (err == 0) + device_move(dev->tty_dev, rfcomm_get_device(dev)); + return err; } @@ -642,6 +647,8 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened); if (--dev->opened == 0) { + device_move(dev->tty_dev, NULL); + /* Close DLC and dettach TTY */ rfcomm_dlc_close(dev->dlc, 0); -- cgit From 2312119afbce0108a72a1e09015a37308f7c7212 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 17 Feb 2007 23:59:02 +0100 Subject: [Bluetooth] Make use of MODULE_FIRMWARE Some Bluetooth drivers need one or more binary firmware images. Export these image names via the MODULE_FIRMWARE tag. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bcm203x.c | 2 ++ drivers/bluetooth/bfusb.c | 1 + drivers/bluetooth/bt3c_cs.c | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 9256985cbe3..8919ccf8274 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -307,3 +307,5 @@ MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("BCM2033-MD.hex"); +MODULE_FIRMWARE("BCM2033-FW.bin"); diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 27cceb6f565..4c766f36d88 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -801,3 +801,4 @@ MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("bfubase.frm"); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 34e5555cb91..18b0f3992c5 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -63,6 +63,7 @@ MODULE_AUTHOR("Marcel Holtmann , Jose Orlando Pereira "); MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("BT3CPCC.bin"); -- cgit From a39a21982c53846acb3bee1a23764a387160a4c8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 20 Feb 2007 01:06:40 -0800 Subject: [IRDA] net/irda/: proper prototypes This patch adds proper prototypes for some functions in include/net/irda/irda.h Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- include/net/irda/irda.h | 16 ++++++++++++++++ net/irda/irmod.c | 13 ------------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h index 1cb0607fcbb..89fe534045f 100644 --- a/include/net/irda/irda.h +++ b/include/net/irda/irda.h @@ -113,4 +113,20 @@ do { if(!(expr)) { \ #define IAS_IRCOMM_ID 0x2343 #define IAS_IRLPT_ID 0x9876 +struct net_device; +struct packet_type; + +extern void irda_proc_register(void); +extern void irda_proc_unregister(void); + +extern int irda_sysctl_register(void); +extern void irda_sysctl_unregister(void); + +extern int irsock_init(void); +extern void irsock_cleanup(void); + +extern int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev); + #endif /* NET_IRDA_H */ diff --git a/net/irda/irmod.c b/net/irda/irmod.c index 826e6c4ca5d..c7fad2c5b9f 100644 --- a/net/irda/irmod.c +++ b/net/irda/irmod.c @@ -42,19 +42,6 @@ #include /* irttp_init */ #include /* irda_device_init */ -/* irproc.c */ -extern void irda_proc_register(void); -extern void irda_proc_unregister(void); -/* irsysctl.c */ -extern int irda_sysctl_register(void); -extern void irda_sysctl_unregister(void); -/* af_irda.c */ -extern int irsock_init(void); -extern void irsock_cleanup(void); -/* irlap_frame.c */ -extern int irlap_driver_rcv(struct sk_buff *, struct net_device *, - struct packet_type *, struct net_device *); - /* * Module parameters */ -- cgit From d3f23dfe8bbb6bf352a208755e4ff2806315067b Mon Sep 17 00:00:00 2001 From: Noriaki TAKAMIYA Date: Tue, 20 Feb 2007 01:08:41 -0800 Subject: [IPSEC]: More fix is needed for __xfrm6_bundle_create(). Fixed to set fl_tunnel.fl6_src correctly in xfrm6_bundle_create(). Signed-off-by: Noriaki TAKAMIYA Acked-by: Masahide NAKAMURA Signed-off-by: David S. Miller --- net/ipv6/xfrm6_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index b1133f27c8a..d8a585bd2cb 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -189,7 +189,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int case AF_INET6: ipv6_addr_copy(&fl_tunnel.fl6_dst, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_dst)); - ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_src)); + ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_local(xfrm[i], &fl->fl6_src)); break; default: BUG_ON(1); -- cgit From ca17c23345308a8692a65a0cca363d9108a665ca Mon Sep 17 00:00:00 2001 From: Joe Jin Date: Tue, 20 Feb 2007 01:30:15 -0800 Subject: [IPV6]: Adjust inet6_exit() cleanup sequence against inet6_init() This patch for adjust inet6_exit() to inverse sequence to inet6_init(). At ipv6_init, it first create proc_root/net/dev_snmp6 entry by call ipv6_misc_proc_init(), then call addrconf_init() to create the corresponding device entry at this directory, but at inet6_exit, ipv6_misc_proc_exit() called first, then call addrconf_init(). Signed-off-by: Joe Jin Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 3585d8fa7f0..5cac14a5c77 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -929,25 +929,28 @@ static void __exit inet6_exit(void) { /* First of all disallow new sockets creation. */ sock_unregister(PF_INET6); + + /* Cleanup code parts. */ + ipv6_packet_cleanup(); +#ifdef CONFIG_IPV6_MIP6 + mip6_fini(); +#endif + addrconf_cleanup(); + ip6_flowlabel_cleanup(); + ip6_route_cleanup(); #ifdef CONFIG_PROC_FS + + /* Cleanup code parts. */ if6_proc_exit(); ac6_proc_exit(); ipv6_misc_proc_exit(); - udp6_proc_exit(); udplite6_proc_exit(); + udp6_proc_exit(); tcp6_proc_exit(); raw6_proc_exit(); #endif -#ifdef CONFIG_IPV6_MIP6 - mip6_fini(); -#endif - /* Cleanup code parts. */ - ip6_flowlabel_cleanup(); - addrconf_cleanup(); - ip6_route_cleanup(); - ipv6_packet_cleanup(); - igmp6_cleanup(); ipv6_netfilter_fini(); + igmp6_cleanup(); ndisc_cleanup(); icmpv6_cleanup(); #ifdef CONFIG_SYSCTL @@ -955,6 +958,7 @@ static void __exit inet6_exit(void) #endif cleanup_ipv6_mibs(); proto_unregister(&rawv6_prot); + proto_unregister(&udplitev6_prot); proto_unregister(&udpv6_prot); proto_unregister(&tcpv6_prot); } -- cgit From ad930650c0e694233971c56e8de8e78b896e2613 Mon Sep 17 00:00:00 2001 From: Jason Lunz Date: Tue, 20 Feb 2007 23:19:54 -0800 Subject: [AF_PACKET]: Remove unnecessary casts. packet_lookup_frame() always returns tpacket_hdr*, so there's no reason to return char* and require casting by callers. Also, remove a cast of void*. Signed-off-by: Jason Lunz Signed-off-by: David S. Miller --- net/packet/af_packet.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index bf269907477..28d47e8f287 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -227,17 +227,14 @@ struct packet_skb_cb { #ifdef CONFIG_PACKET_MMAP -static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) +static inline struct tpacket_hdr *packet_lookup_frame(struct packet_sock *po, unsigned int position) { unsigned int pg_vec_pos, frame_offset; - char *frame; pg_vec_pos = position / po->frames_per_block; frame_offset = position % po->frames_per_block; - frame = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size); - - return frame; + return (struct tpacket_hdr *)(po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size)); } #endif @@ -639,7 +636,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe } spin_lock(&sk->sk_receive_queue.lock); - h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head); + h = packet_lookup_frame(po, po->head); if (h->tp_status) goto ring_is_full; @@ -1473,7 +1470,7 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void { struct sock *sk; struct hlist_node *node; - struct net_device *dev = (struct net_device*)data; + struct net_device *dev = data; read_lock(&packet_sklist_lock); sk_for_each(sk, node, &packet_sklist) { @@ -1588,7 +1585,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, unsigned last = po->head ? po->head-1 : po->frame_max; struct tpacket_hdr *h; - h = (struct tpacket_hdr *)packet_lookup_frame(po, last); + h = packet_lookup_frame(po, last); if (h->tp_status) mask |= POLLIN | POLLRDNORM; -- cgit From 7f62ad5d37f4e43c841e92c6f159c93dcf2d2cdd Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 20 Feb 2007 23:25:40 -0800 Subject: [TG3]: TSO workaround fixes. 1. Add race condition check after netif_stop_queue(). tg3_tx() runs without netif_tx_lock and can race with tg3_start_xmit_dma_bug() -> tg3_tso_bug(). 2. Firmware TSO in 5703/5704/5705 also have the same TSO limitation, i.e. they cannot handle TSO headers bigger than 80 bytes. Rename TG3_FL2_HW_TSO_1_BUG to TG3_FL2_TSO_BUG and set this flag on these chips as well. 3. Update version to 3.74. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 20 +++++++++++--------- drivers/net/tg3.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 81a1c2e1a3f..26c6ac48288 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.73" -#define DRV_MODULE_RELDATE "February 12, 2007" +#define DRV_MODULE_VERSION "3.74" +#define DRV_MODULE_RELDATE "February 20, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3993,7 +3993,10 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) /* Estimate the number of fragments in the worst case */ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) { netif_stop_queue(tp->dev); - return NETDEV_TX_BUSY; + if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3)) + return NETDEV_TX_BUSY; + + netif_wake_queue(tp->dev); } segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO); @@ -4061,7 +4064,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) hdr_len = ip_tcp_len + tcp_opt_len; if (unlikely((ETH_HLEN + hdr_len) > 80) && - (tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG)) + (tp->tg3_flags2 & TG3_FLG2_TSO_BUG)) return (tg3_tso_bug(tp, skb)); base_flags |= (TXD_FLAG_CPU_PRE_DMA | @@ -8137,7 +8140,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || (ering->tx_pending > TG3_TX_RING_SIZE - 1) || (ering->tx_pending <= MAX_SKB_FRAGS) || - ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) && + ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) && (ering->tx_pending <= (MAX_SKB_FRAGS * 3)))) return -EINVAL; @@ -10557,12 +10560,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; } else { - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | - TG3_FLG2_HW_TSO_1_BUG; + tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 && tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2) - tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_1_BUG; + tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG; } } @@ -11867,7 +11869,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; } else { - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG; } /* TSO is on by default on chips that support hardware TSO. diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 45d477e8f37..086892d8c1f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2227,7 +2227,7 @@ struct tg3 { #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; #define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_HW_TSO_1_BUG 0x00000002 +#define TG3_FLG2_TSO_BUG 0x00000002 #define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004 #define TG3_FLG2_IS_5788 0x00000008 #define TG3_FLG2_MAX_RXPEND_64 0x00000010 -- cgit From 2c4f6219aca5939b57596278ea8b014275d4917b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Feb 2007 23:51:47 -0800 Subject: [TCP]: Fix MD5 signature pool locking. The locking calls assumed that these code paths were only invoked in software interrupt context, but that isn't true. Therefore we need to use spin_{lock,unlock}_bh() throughout. Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ac6516c642a..74c4d103ebc 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2266,12 +2266,12 @@ void tcp_free_md5sig_pool(void) { struct tcp_md5sig_pool **pool = NULL; - spin_lock(&tcp_md5sig_pool_lock); + spin_lock_bh(&tcp_md5sig_pool_lock); if (--tcp_md5sig_users == 0) { pool = tcp_md5sig_pool; tcp_md5sig_pool = NULL; } - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); if (pool) __tcp_free_md5sig_pool(pool); } @@ -2314,36 +2314,36 @@ struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void) int alloc = 0; retry: - spin_lock(&tcp_md5sig_pool_lock); + spin_lock_bh(&tcp_md5sig_pool_lock); pool = tcp_md5sig_pool; if (tcp_md5sig_users++ == 0) { alloc = 1; - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); } else if (!pool) { tcp_md5sig_users--; - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); cpu_relax(); goto retry; } else - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); if (alloc) { /* we cannot hold spinlock here because this may sleep. */ struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(); - spin_lock(&tcp_md5sig_pool_lock); + spin_lock_bh(&tcp_md5sig_pool_lock); if (!p) { tcp_md5sig_users--; - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); return NULL; } pool = tcp_md5sig_pool; if (pool) { /* oops, it has already been assigned. */ - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); __tcp_free_md5sig_pool(p); } else { tcp_md5sig_pool = pool = p; - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); } } return pool; @@ -2354,11 +2354,11 @@ EXPORT_SYMBOL(tcp_alloc_md5sig_pool); struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu) { struct tcp_md5sig_pool **p; - spin_lock(&tcp_md5sig_pool_lock); + spin_lock_bh(&tcp_md5sig_pool_lock); p = tcp_md5sig_pool; if (p) tcp_md5sig_users++; - spin_unlock(&tcp_md5sig_pool_lock); + spin_unlock_bh(&tcp_md5sig_pool_lock); return (p ? *per_cpu_ptr(p, cpu) : NULL); } -- cgit From 8c4a2d41a7eb5a8f214f537acca533dcd6430782 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 21 Feb 2007 02:06:04 -0800 Subject: [SCTP]: Fix connection hang/slowdown with PR-SCTP The problem that this patch corrects happens when all of the following conditions are satisfisfied: 1. PR-SCTP is used and the timeout on the chunks is set below RTO.Max. 2. One of the paths on a multihomed associations is brought down. In this scenario, data will expire within the rto of the initial transmission and will never be retransmitted. However this data still fills the send buffer and is counted against the association as outstanding data. This causes any new data not to be sent and retransmission to not happen. The fix is to discount the abandoned data from the outstanding count and peers rwnd estimation. This allows new data to be sent and a retransmission timer restarted. Even though this new data will most likely expire within the rto, the timer still counts as a strike against the transport and forces the FORWARD-TSN chunk to be retransmitted as well. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/outqueue.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 5c2ddd10db0..41abfd17627 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -396,6 +396,19 @@ void sctp_retransmit_mark(struct sctp_outq *q, if (sctp_chunk_abandoned(chunk)) { list_del_init(lchunk); sctp_insert_list(&q->abandoned, lchunk); + + /* If this chunk has not been previousely acked, + * stop considering it 'outstanding'. Our peer + * will most likely never see it since it will + * not be retransmitted + */ + if (!chunk->tsn_gap_acked) { + chunk->transport->flight_size -= + sctp_data_size(chunk); + q->outstanding_bytes -= sctp_data_size(chunk); + q->asoc->peer.rwnd += (sctp_data_size(chunk) + + sizeof(struct sk_buff)); + } continue; } @@ -1244,6 +1257,15 @@ static void sctp_check_transmitted(struct sctp_outq *q, if (sctp_chunk_abandoned(tchunk)) { /* Move the chunk to abandoned list. */ sctp_insert_list(&q->abandoned, lchunk); + + /* If this chunk has not been acked, stop + * considering it as 'outstanding'. + */ + if (!tchunk->tsn_gap_acked) { + tchunk->transport->flight_size -= + sctp_data_size(tchunk); + q->outstanding_bytes -= sctp_data_size(tchunk); + } continue; } @@ -1695,11 +1717,6 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) */ if (TSN_lte(tsn, ctsn)) { list_del_init(lchunk); - if (!chunk->tsn_gap_acked) { - chunk->transport->flight_size -= - sctp_data_size(chunk); - q->outstanding_bytes -= sctp_data_size(chunk); - } sctp_chunk_free(chunk); } else { if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) { -- cgit From 1845a579e0c3084a822fbe610f7cfd1b0e0396ac Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 21 Feb 2007 02:06:19 -0800 Subject: [SCTP]: Strike the transport before updating rto. Once we reach a point where we exceed the max.path.retrans, strike the transport before updating the rto. This will force transport switch at the right time, instead of 1 retransmit too late. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index b3cad8a0373..70c39eac058 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -4605,12 +4605,12 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, * sent as soon as cwnd allows (normally when a SACK arrives). */ - /* NB: Rules E4 and F1 are implicit in R1. */ - sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport)); - /* Do some failure management (Section 8.2). */ sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); + /* NB: Rules E4 and F1 are implicit in R1. */ + sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport)); + return SCTP_DISPOSITION_CONSUME; } -- cgit From f4b9479dc5a1b0e1ca8666053f0d932baddc619d Mon Sep 17 00:00:00 2001 From: Baruch Even Date: Wed, 21 Feb 2007 19:32:37 -0800 Subject: [IPV4]: Correct links in net/ipv4/Kconfig Correct dead/indirect links in net/ipv4/Kconfig Signed-off-by: Baruch Even Signed-off-by: David S. Miller --- net/ipv4/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 91f3a5cdbcf..9e8ef509c51 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -442,7 +442,7 @@ config INET_DIAG ---help--- Support for INET (TCP, DCCP, etc) socket monitoring interface used by native Linux tools such as ss. ss is included in iproute2, currently - downloadable at . + downloadable at . If unsure, say Y. @@ -550,7 +550,7 @@ config TCP_CONG_SCALABLE Scalable TCP is a sender-side only change to TCP which uses a MIMD congestion control algorithm which has some nice scaling properties, though is known to have fairness issues. - See http://www-lce.eng.cam.ac.uk/~ctk21/scalable/ + See http://www.deneholme.net/tom/scalable/ config TCP_CONG_LP tristate "TCP Low Priority" -- cgit From 8c14b7ce22a7ddd9fe1b1c852c4015633ec3efec Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 22 Feb 2007 02:25:42 +0900 Subject: [IPV6] ADDRCONF: Statically link __ipv6_addr_type() for sunrpc subsystem. Link __ipv6_addr_type() statically for sunrpc code even if IPv6 is built as module. Signed-off-by: YOSHIFUJI Hidaki --- net/ipv6/Makefile | 2 +- net/ipv6/addrconf.c | 68 ------------------------------------------- net/ipv6/addrconf_core.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 69 deletions(-) create mode 100644 net/ipv6/addrconf_core.c diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 8bacda109b7..d460017bb35 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -32,6 +32,6 @@ obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_IPV6_SIT) += sit.o obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o -obj-y += exthdrs_core.o +obj-y += addrconf_core.o exthdrs_core.o obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 569a37d698f..524bffe6249 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -211,74 +211,6 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; #endif const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; -#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) - -static inline unsigned ipv6_addr_scope2type(unsigned scope) -{ - switch(scope) { - case IPV6_ADDR_SCOPE_NODELOCAL: - return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) | - IPV6_ADDR_LOOPBACK); - case IPV6_ADDR_SCOPE_LINKLOCAL: - return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) | - IPV6_ADDR_LINKLOCAL); - case IPV6_ADDR_SCOPE_SITELOCAL: - return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) | - IPV6_ADDR_SITELOCAL); - } - return IPV6_ADDR_SCOPE_TYPE(scope); -} - -int __ipv6_addr_type(const struct in6_addr *addr) -{ - __be32 st; - - st = addr->s6_addr32[0]; - - /* Consider all addresses with the first three bits different of - 000 and 111 as unicasts. - */ - if ((st & htonl(0xE0000000)) != htonl(0x00000000) && - (st & htonl(0xE0000000)) != htonl(0xE0000000)) - return (IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); - - if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { - /* multicast */ - /* addr-select 3.1 */ - return (IPV6_ADDR_MULTICAST | - ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr))); - } - - if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) - return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */ - if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) - return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */ - - if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { - if (addr->s6_addr32[2] == 0) { - if (addr->s6_addr32[3] == 0) - return IPV6_ADDR_ANY; - - if (addr->s6_addr32[3] == htonl(0x00000001)) - return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */ - - return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ - } - - if (addr->s6_addr32[2] == htonl(0x0000ffff)) - return (IPV6_ADDR_MAPPED | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ - } - - return (IPV6_ADDR_RESERVED | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ -} - static void addrconf_del_timer(struct inet6_ifaddr *ifp) { if (del_timer(&ifp->timer)) diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c new file mode 100644 index 00000000000..644e0c742f9 --- /dev/null +++ b/net/ipv6/addrconf_core.c @@ -0,0 +1,75 @@ +/* + * IPv6 library code, needed by static components when full IPv6 support is + * not configured or static. + */ + +#include + +#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) + +static inline unsigned ipv6_addr_scope2type(unsigned scope) +{ + switch(scope) { + case IPV6_ADDR_SCOPE_NODELOCAL: + return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) | + IPV6_ADDR_LOOPBACK); + case IPV6_ADDR_SCOPE_LINKLOCAL: + return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) | + IPV6_ADDR_LINKLOCAL); + case IPV6_ADDR_SCOPE_SITELOCAL: + return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) | + IPV6_ADDR_SITELOCAL); + } + return IPV6_ADDR_SCOPE_TYPE(scope); +} + +int __ipv6_addr_type(const struct in6_addr *addr) +{ + __be32 st; + + st = addr->s6_addr32[0]; + + /* Consider all addresses with the first three bits different of + 000 and 111 as unicasts. + */ + if ((st & htonl(0xE0000000)) != htonl(0x00000000) && + (st & htonl(0xE0000000)) != htonl(0xE0000000)) + return (IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); + + if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { + /* multicast */ + /* addr-select 3.1 */ + return (IPV6_ADDR_MULTICAST | + ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr))); + } + + if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) + return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */ + if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) + return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */ + + if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { + if (addr->s6_addr32[2] == 0) { + if (addr->s6_addr32[3] == 0) + return IPV6_ADDR_ANY; + + if (addr->s6_addr32[3] == htonl(0x00000001)) + return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */ + + return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ + } + + if (addr->s6_addr32[2] == htonl(0x0000ffff)) + return (IPV6_ADDR_MAPPED | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ + } + + return (IPV6_ADDR_RESERVED | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ +} + -- cgit From 268920584b57d534a40503a8a3a47eff9e57fbf8 Mon Sep 17 00:00:00 2001 From: Yasuyuki Kozakai Date: Sun, 10 Sep 2006 03:59:17 +0900 Subject: [IPV6] IP6TUNNEL: Use update_pmtu() of dst on xmit. Signed-off-by: Yasuyuki Kozakai Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ip6_tunnel.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 662edb82689..08d944223ec 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -727,11 +727,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) } if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (skb->dst && mtu < dst_mtu(skb->dst)) { - struct rt6_info *rt = (struct rt6_info *) skb->dst; - rt->rt6i_flags |= RTF_MODIFIED; - rt->u.dst.metrics[RTAX_MTU-1] = mtu; - } + if (skb->dst) + skb->dst->ops->update_pmtu(skb->dst, mtu); if (skb->len > mtu) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); goto tx_err_dst_release; -- cgit From 46d480468fd9d165513d96f5e545538425d6472d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 7 Feb 2007 20:36:26 +0900 Subject: [IPV6] ADDRCONF: Manage prefix route corresponding to address manually added. It is more natural to manage prefix routes corresponding to address which is being added manually. With help from Masafumi Aramoto . Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/addrconf.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 524bffe6249..7a2a71536b5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1842,6 +1842,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, struct inet6_dev *idev; struct net_device *dev; int scope; + u32 flags = RTF_EXPIRES; ASSERT_RTNL(); @@ -1857,9 +1858,10 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, scope = ipv6_addr_scope(pfx); - if (valid_lft == INFINITY_LIFE_TIME) + if (valid_lft == INFINITY_LIFE_TIME) { ifa_flags |= IFA_F_PERMANENT; - else if (valid_lft >= 0x7FFFFFFF/HZ) + flags = 0; + } else if (valid_lft >= 0x7FFFFFFF/HZ) valid_lft = 0x7FFFFFFF/HZ; if (prefered_lft == 0) @@ -1877,6 +1879,8 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, ifp->tstamp = jiffies; spin_unlock_bh(&ifp->lock); + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, + jiffies_to_clock_t(valid_lft * HZ), flags); addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); addrconf_verify(0); @@ -2056,6 +2060,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); } @@ -2470,10 +2475,6 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) addrconf_join_solict(dev, &ifp->addr); - if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT)) - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, - flags); - net_srandom(ifp->addr.s6_addr32[3]); read_lock_bh(&idev->lock); @@ -2904,12 +2905,15 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, u32 prefered_lft, u32 valid_lft) { + u32 flags = RTF_EXPIRES; + if (!valid_lft || (prefered_lft > valid_lft)) return -EINVAL; - if (valid_lft == INFINITY_LIFE_TIME) + if (valid_lft == INFINITY_LIFE_TIME) { ifa_flags |= IFA_F_PERMANENT; - else if (valid_lft >= 0x7FFFFFFF/HZ) + flags = 0; + } else if (valid_lft >= 0x7FFFFFFF/HZ) valid_lft = 0x7FFFFFFF/HZ; if (prefered_lft == 0) @@ -2928,6 +2932,8 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, if (!(ifp->flags&IFA_F_TENTATIVE)) ipv6_ifa_notify(0, ifp); + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, + jiffies_to_clock_t(valid_lft * HZ), flags); addrconf_verify(0); return 0; -- cgit From 45ba9dd2007da23da5ac21179451c3c9fee30a96 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 15 Feb 2007 02:07:27 +0900 Subject: [IPV6] ADDRCONF: Register inet6_dev earlier. Allocate inet6_dev earlier to allow users to set up per-interface variables. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/addrconf.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 7a2a71536b5..f6ac65d3655 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2177,6 +2177,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, int run_pending = 0; switch(event) { + case NETDEV_REGISTER: + if (!idev) { + idev = ipv6_add_dev(dev); + if (!idev) + printk(KERN_WARNING "IPv6: add_dev failed for %s\n", + dev->name); + } + break; case NETDEV_UP: case NETDEV_CHANGE: if (event == NETDEV_UP) { -- cgit From 8030f54499925d073a88c09f30d5d844fb1b3190 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 22 Feb 2007 01:53:47 +0900 Subject: [IPV4] devinet: Register inetdev earlier. This patch allocates inetdev at registration for all devices in line with IPv6. This allows sysctl configuration on the devices to occur before they're brought up or addresses are added. Signed-off-by: Herbert Xu Signed-off-by: YOSHIFUJI Hideaki --- net/ipv4/devinet.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 8a0ec10a13a..e10794dc5f6 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1054,12 +1054,14 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, ASSERT_RTNL(); if (!in_dev) { - if (event == NETDEV_REGISTER && dev == &loopback_dev) { + if (event == NETDEV_REGISTER) { in_dev = inetdev_init(dev); if (!in_dev) panic("devinet: Failed to create loopback\n"); - in_dev->cnf.no_xfrm = 1; - in_dev->cnf.no_policy = 1; + if (dev == &loopback_dev) { + in_dev->cnf.no_xfrm = 1; + in_dev->cnf.no_policy = 1; + } } goto out; } -- cgit From 7401055b58e557362dfcaa65a581db1d1e972439 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 21 Feb 2007 23:26:56 -0800 Subject: [IPV6]: Fix __ipv6_addr_type() export in correct place. It needs to be in net/ipv6/addrconf_core.c Signed-off-by: David S. Miller --- net/ipv6/addrconf_core.c | 1 + net/ipv6/ipv6_syms.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index 644e0c742f9..faaefb69229 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -72,4 +72,5 @@ int __ipv6_addr_type(const struct in6_addr *addr) return (IPV6_ADDR_RESERVED | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ } +EXPORT_SYMBOL(__ipv6_addr_type); diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index 0e8e0676a03..e12e3d4fcce 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c @@ -6,7 +6,6 @@ #include #include -EXPORT_SYMBOL(__ipv6_addr_type); EXPORT_SYMBOL(icmpv6_send); EXPORT_SYMBOL(icmpv6_statistics); EXPORT_SYMBOL(icmpv6_err_convert); -- cgit From ac062e84d0c177c43549e7fb608152fec218e7fc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 22 Feb 2007 01:07:53 -0800 Subject: [BRIDGE]: get rid of miscdevice include The bridge hasn't used miscdevice for a long long time. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_private.h | 1 - 1 file changed, 1 deletion(-) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6a0540e0591..16fc47a821e 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -16,7 +16,6 @@ #define _BR_PRIVATE_H #include -#include #include #define BR_HASH_BITS 8 -- cgit From 269def7c505b4d229f9ad49bf88543d1e605533e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 22 Feb 2007 01:10:18 -0800 Subject: [BRIDGE]: eliminate workqueue for carrier check Having a work queue for checking carrier leads to lots of race issues. Simpler to just get the cost when data structure is created and update on change. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 30 +++++------------------------- net/bridge/br_notify.c | 25 +++++++++++-------------- net/bridge/br_private.h | 4 +--- 3 files changed, 17 insertions(+), 42 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index aff6a779c9c..6845a258408 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -77,26 +77,15 @@ static int port_cost(struct net_device *dev) * Called from work queue to allow for calling functions that * might sleep (such as speed check), and to debounce. */ -static void port_carrier_check(struct work_struct *work) +void br_port_carrier_check(struct net_bridge_port *p) { - struct net_bridge_port *p; - struct net_device *dev; - struct net_bridge *br; - - dev = container_of(work, struct net_bridge_port, - carrier_check.work)->dev; - work_release(work); - - rtnl_lock(); - p = dev->br_port; - if (!p) - goto done; - br = p->br; + struct net_device *dev = p->dev; + struct net_bridge *br = p->br; if (netif_carrier_ok(dev)) p->path_cost = port_cost(dev); - if (br->dev->flags & IFF_UP) { + if (netif_running(br->dev)) { spin_lock_bh(&br->lock); if (netif_carrier_ok(dev)) { if (p->state == BR_STATE_DISABLED) @@ -107,9 +96,6 @@ static void port_carrier_check(struct work_struct *work) } spin_unlock_bh(&br->lock); } -done: - dev_put(dev); - rtnl_unlock(); } static void release_nbp(struct kobject *kobj) @@ -162,9 +148,6 @@ static void del_nbp(struct net_bridge_port *p) dev_set_promiscuity(dev, -1); - if (cancel_delayed_work(&p->carrier_check)) - dev_put(dev); - spin_lock_bh(&br->lock); br_stp_disable_port(p); spin_unlock_bh(&br->lock); @@ -282,7 +265,6 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, p->port_no = index; br_init_port(p); p->state = BR_STATE_DISABLED; - INIT_DELAYED_WORK_NAR(&p->carrier_check, port_carrier_check); br_stp_port_timer_init(p); kobject_init(&p->kobj); @@ -446,12 +428,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) spin_lock_bh(&br->lock); br_stp_recalculate_bridge_id(br); br_features_recompute(br); - if (schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE)) - dev_hold(dev); - spin_unlock_bh(&br->lock); dev_set_mtu(br->dev, br_min_mtu(br)); + kobject_uevent(&p->kobj, KOBJ_ADD); return 0; diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 3311c4e3082..37357ed2149 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -42,51 +42,48 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v br = p->br; - spin_lock_bh(&br->lock); switch (event) { case NETDEV_CHANGEMTU: dev_set_mtu(br->dev, br_min_mtu(br)); break; case NETDEV_CHANGEADDR: + spin_lock_bh(&br->lock); br_fdb_changeaddr(p, dev->dev_addr); br_ifinfo_notify(RTM_NEWLINK, p); br_stp_recalculate_bridge_id(br); + spin_unlock_bh(&br->lock); break; case NETDEV_CHANGE: - if (br->dev->flags & IFF_UP) - if (schedule_delayed_work(&p->carrier_check, - BR_PORT_DEBOUNCE)) - dev_hold(dev); + br_port_carrier_check(p); break; case NETDEV_FEAT_CHANGE: - if (br->dev->flags & IFF_UP) + spin_lock_bh(&br->lock); + if (netif_running(br->dev)) br_features_recompute(br); - - /* could do recursive feature change notification - * but who would care?? - */ + spin_unlock_bh(&br->lock); break; case NETDEV_DOWN: + spin_lock_bh(&br->lock); if (br->dev->flags & IFF_UP) br_stp_disable_port(p); + spin_unlock_bh(&br->lock); break; case NETDEV_UP: + spin_lock_bh(&br->lock); if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) br_stp_enable_port(p); + spin_unlock_bh(&br->lock); break; case NETDEV_UNREGISTER: - spin_unlock_bh(&br->lock); br_del_if(br, dev); - goto done; + break; } - spin_unlock_bh(&br->lock); - done: return NOTIFY_DONE; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 16fc47a821e..cc3f1c99261 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -26,8 +26,6 @@ #define BR_PORT_BITS 10 #define BR_MAX_PORTS (1< Date: Thu, 22 Feb 2007 01:26:32 -0800 Subject: [IPV4]: Use random32() in net/ipv4/multipath Removed local random number generator function Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/ipv4/multipath_random.c | 18 ++---------------- net/ipv4/multipath_wrandom.c | 15 ++------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/net/ipv4/multipath_random.c b/net/ipv4/multipath_random.c index 57f481498fb..c312785d14d 100644 --- a/net/ipv4/multipath_random.c +++ b/net/ipv4/multipath_random.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -48,21 +49,6 @@ #define MULTIPATH_MAX_CANDIDATES 40 -/* interface to random number generation */ -static unsigned int RANDOM_SEED = 93186752; - -static inline unsigned int random(unsigned int ubound) -{ - static unsigned int a = 1588635695, - q = 2, - r = 1117695901; - - RANDOM_SEED = a*(RANDOM_SEED % q) - r*(RANDOM_SEED / q); - - return RANDOM_SEED % ubound; -} - - static void random_select_route(const struct flowi *flp, struct rtable *first, struct rtable **rp) @@ -84,7 +70,7 @@ static void random_select_route(const struct flowi *flp, if (candidate_count > 1) { unsigned char i = 0; unsigned char candidate_no = (unsigned char) - random(candidate_count); + (random32() % candidate_count); /* find chosen candidate and adjust GC data for all candidates * to ensure they stay in cache diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c index 2bdbb92b450..57c50369453 100644 --- a/net/ipv4/multipath_wrandom.c +++ b/net/ipv4/multipath_wrandom.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -84,18 +85,6 @@ struct multipath_route { /* state: primarily weight per route information */ static struct multipath_bucket state[MULTIPATH_STATE_SIZE]; -/* interface to random number generation */ -static unsigned int RANDOM_SEED = 93186752; - -static inline unsigned int random(unsigned int ubound) -{ - static unsigned int a = 1588635695, - q = 2, - r = 1117695901; - RANDOM_SEED = a*(RANDOM_SEED % q) - r*(RANDOM_SEED / q); - return RANDOM_SEED % ubound; -} - static unsigned char __multipath_lookup_weight(const struct flowi *fl, const struct rtable *rt) { @@ -193,7 +182,7 @@ static void wrandom_select_route(const struct flowi *flp, /* choose a weighted random candidate */ decision = first; - selector = random(power); + selector = random32() % power; last_power = 0; /* select candidate, adjust GC data and cleanup local state */ -- cgit From e4396b544fa5c85e3c263e0bc92b0743a24ba818 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 24 Feb 2007 18:12:42 -0800 Subject: [XFRM_TUNNEL]: Reload header pointer after pskb_may_pull/pskb_expand_head Please consider applying, this was found on your latest net-2.6 tree while playing around with that ip_hdr() + turn skb->nh/h/mac pointers as offsets on 64 bits idea :-) Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/ipv4/xfrm4_mode_tunnel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index e1cab33fdad..ceb4376f572 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -111,6 +111,7 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) goto out; + iph = skb->nh.iph; if (iph->protocol == IPPROTO_IPIP) { if (x->props.flags & XFRM_STATE_DECAP_DSCP) ipv4_copy_dscp(iph, skb->h.ipiph); -- cgit From aef8811abbc9249a2bd59bd2331bbe523df05d17 Mon Sep 17 00:00:00 2001 From: Bernhard Walle Date: Mon, 26 Feb 2007 12:10:32 -0800 Subject: [XFRM]: Fix oops in xfrm4_dst_destroy() With 2.6.21-rc1, I get an oops when running 'ifdown eth0' and an IPsec connection is active. If I shut down the connection before running 'ifdown eth0', then there's no problem. The critical operation of this script is to kill dhcpd. The problem is probably caused by commit with git identifier 4337226228e1cfc1d70ee975789c6bd070fb597c (Linus tree) "[IPSEC]: IPv4 over IPv6 IPsec tunnel". This patch fixes that oops. I don't know the network code of the Linux kernel in deep, so if that fix is wrong, please change it. But please fix the oops. :) Signed-off-by: Bernhard Walle Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/xfrm4_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index fef19c6bcb9..5d51a2af34c 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -291,7 +291,7 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) if (likely(xdst->u.rt.idev)) in_dev_put(xdst->u.rt.idev); - if (dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer)) + if (dst->xfrm && dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer)) inet_putpeer(xdst->u.rt.peer); xfrm_dst_destroy(xdst); } -- cgit