From 8c462b6047da80491b8cb6be878e8bf9313ac3e1 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Tue, 24 Aug 2010 15:35:42 -0700 Subject: Bluetooth: Only enable L2CAP FCS for ERTM or streaming This fixes a bug which caused the FCS setting to show L2CAP_FCS_CRC16 with L2CAP modes other than ERTM or streaming. At present, this only affects the FCS value shown with getsockopt() for basic mode. Signed-off-by: Mat Martineau Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index fadf26b4ed7c..c7847035562b 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3071,6 +3071,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd return 0; } +static inline void set_default_fcs(struct l2cap_pinfo *pi) +{ + /* FCS is enabled only in ERTM or streaming mode, if one or both + * sides request it. + */ + if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) + pi->fcs = L2CAP_FCS_NONE; + else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV)) + pi->fcs = L2CAP_FCS_CRC16; +} + static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) { struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; @@ -3135,9 +3146,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto unlock; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) || - l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) - l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; + set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; @@ -3225,9 +3234,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) || - l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) - l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; + set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; l2cap_pi(sk)->next_tx_seq = 0; -- cgit v1.2.3 From 8183b775bc5b79b6b1e250019c9dd930554dfa94 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 1 Sep 2010 15:17:25 +0300 Subject: Bluetooth: fix MTU L2CAP configuration parameter When receiving L2CAP negative configuration response with respect to MTU parameter we modify wrong field. MTU here means proposed value of MTU that the remote device intends to transmit. So for local L2CAP socket it is pi->imtu. Signed-off-by: Andrei Emeltchenko Acked-by: Ville Tervo Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c7847035562b..9fad312e53f2 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2771,10 +2771,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, case L2CAP_CONF_MTU: if (val < L2CAP_DEFAULT_MIN_MTU) { *result = L2CAP_CONF_UNACCEPT; - pi->omtu = L2CAP_DEFAULT_MIN_MTU; + pi->imtu = L2CAP_DEFAULT_MIN_MTU; } else - pi->omtu = val; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); + pi->imtu = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); break; case L2CAP_CONF_FLUSH_TO: -- cgit v1.2.3 From ccbb84af28594e19fd4bf27ff2828c80d03b6081 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 30 Aug 2010 18:44:44 -0300 Subject: Bluetooth: Simplify L2CAP Streaming mode sending As we don't have any error control on the Streaming mode, i.e., we don't need to keep a copy of the skb for later resending we don't need to call skb_clone() on it. Then we can go one further here, and dequeue the skb before sending it, that also means we don't need to look to sk->sk_send_head anymore. The patch saves memory and time when sending Streaming mode data, so it is good to mainline. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 9fad312e53f2..f2062aace406 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1441,33 +1441,23 @@ static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb) static void l2cap_streaming_send(struct sock *sk) { - struct sk_buff *skb, *tx_skb; + struct sk_buff *skb; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; - while ((skb = sk->sk_send_head)) { - tx_skb = skb_clone(skb, GFP_ATOMIC); - - control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + while ((skb = skb_dequeue(TX_QUEUE(sk)))) { + control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE); control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; - put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); if (pi->fcs == L2CAP_FCS_CRC16) { - fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); - put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); + fcs = crc16(0, (u8 *)skb->data, skb->len - 2); + put_unaligned_le16(fcs, skb->data + skb->len - 2); } - l2cap_do_send(sk, tx_skb); + l2cap_do_send(sk, skb); pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; - - if (skb_queue_is_last(TX_QUEUE(sk), skb)) - sk->sk_send_head = NULL; - else - sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); - - skb = skb_dequeue(TX_QUEUE(sk)); - kfree_skb(skb); } } -- cgit v1.2.3 From fad003b6c8e3d944d4453fd569b0702ef1af82b3 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 14 Aug 2010 00:48:07 -0300 Subject: Bluetooth: Fix inconsistent lock state with RFCOMM When receiving a rfcomm connection with the old dund deamon a inconsistent lock state happens. That's because interrupts were already disabled by l2cap_conn_start() when rfcomm_sk_state_change() try to lock the spin_lock. As result we may have a inconsistent lock state for l2cap_conn_start() after rfcomm_sk_state_change() calls bh_lock_sock() and disable interrupts as well. [ 2833.151999] [ 2833.151999] ================================= [ 2833.151999] [ INFO: inconsistent lock state ] [ 2833.151999] 2.6.36-rc3 #2 [ 2833.151999] --------------------------------- [ 2833.151999] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. [ 2833.151999] krfcommd/2306 [HC0[0]:SC0[0]:HE1:SE1] takes: [ 2833.151999] (slock-AF_BLUETOOTH){+.?...}, at: [] rfcomm_sk_state_change+0x46/0x170 [rfcomm] [ 2833.151999] {IN-SOFTIRQ-W} state was registered at: [ 2833.151999] [] __lock_acquire+0x5b6/0x1560 [ 2833.151999] [] lock_acquire+0x5a/0x70 [ 2833.151999] [] _raw_spin_lock+0x2c/0x40 [ 2833.151999] [] l2cap_conn_start+0x92/0x640 [l2cap] [ 2833.151999] [] l2cap_sig_channel+0x6bf/0x1320 [l2cap] [ 2833.151999] [] l2cap_recv_frame+0x133/0x770 [l2cap] [ 2833.151999] [] l2cap_recv_acldata+0x1cb/0x390 [l2cap] [ 2833.151999] [] hci_rx_task+0x2ab/0x450 [bluetooth] [ 2833.151999] [] tasklet_action+0xcb/0xe0 [ 2833.151999] [] __do_softirq+0xae/0x150 [ 2833.151999] [] call_softirq+0x1c/0x30 [ 2833.151999] [] do_softirq+0x75/0xb0 [ 2833.151999] [] irq_exit+0x8d/0xa0 [ 2833.151999] [] smp_apic_timer_interrupt+0x6b/0xa0 [ 2833.151999] [] apic_timer_interrupt+0x13/0x20 [ 2833.151999] [] cpu_idle+0x5a/0xb0 [ 2833.151999] [] rest_init+0xad/0xc0 [ 2833.151999] [] start_kernel+0x2dd/0x2e8 [ 2833.151999] [] x86_64_start_reservations+0xf6/0xfa [ 2833.151999] [] x86_64_start_kernel+0xe4/0xeb [ 2833.151999] irq event stamp: 731 [ 2833.151999] hardirqs last enabled at (731): [] local_bh_enable_ip+0x82/0xe0 [ 2833.151999] hardirqs last disabled at (729): [] __do_softirq+0xce/0x150 [ 2833.151999] softirqs last enabled at (730): [] __do_softirq+0xfe/0x150 [ 2833.151999] softirqs last disabled at (711): [] call_softirq+0x1c/0x30 [ 2833.151999] [ 2833.151999] other info that might help us debug this: [ 2833.151999] 2 locks held by krfcommd/2306: [ 2833.151999] #0: (rfcomm_mutex){+.+.+.}, at: [] rfcomm_run+0x174/0xb20 [rfcomm] [ 2833.151999] #1: (&(&d->lock)->rlock){+.+...}, at: [] rfcomm_dlc_accept+0x53/0x100 [rfcomm] [ 2833.151999] [ 2833.151999] stack backtrace: [ 2833.151999] Pid: 2306, comm: krfcommd Tainted: G W 2.6.36-rc3 #2 [ 2833.151999] Call Trace: [ 2833.151999] [] print_usage_bug+0x171/0x180 [ 2833.151999] [] mark_lock+0x333/0x400 [ 2833.151999] [] __lock_acquire+0x63a/0x1560 [ 2833.151999] [] ? __lock_acquire+0xb25/0x1560 [ 2833.151999] [] lock_acquire+0x5a/0x70 [ 2833.151999] [] ? rfcomm_sk_state_change+0x46/0x170 [rfcomm] [ 2833.151999] [] _raw_spin_lock+0x2c/0x40 [ 2833.151999] [] ? rfcomm_sk_state_change+0x46/0x170 [rfcomm] [ 2833.151999] [] rfcomm_sk_state_change+0x46/0x170 [rfcomm] [ 2833.151999] [] rfcomm_dlc_accept+0x69/0x100 [rfcomm] [ 2833.151999] [] rfcomm_check_accept+0x59/0xd0 [rfcomm] [ 2833.151999] [] rfcomm_recv_frame+0x9fb/0x1320 [rfcomm] [ 2833.151999] [] ? _raw_spin_unlock_irqrestore+0x3b/0x60 [ 2833.151999] [] ? trace_hardirqs_on_caller+0x13d/0x180 [ 2833.151999] [] ? trace_hardirqs_on+0xd/0x10 [ 2833.151999] [] rfcomm_run+0x221/0xb20 [rfcomm] [ 2833.151999] [] ? schedule+0x287/0x780 [ 2833.151999] [] ? rfcomm_run+0x0/0xb20 [rfcomm] [ 2833.151999] [] kthread+0x96/0xa0 [ 2833.151999] [] kernel_thread_helper+0x4/0x10 [ 2833.151999] [] ? restore_args+0x0/0x30 [ 2833.151999] [] ? kthread+0x0/0xa0 [ 2833.151999] [] ? kernel_thread_helper+0x0/0x10 Signed-off-by: Gustavo F. Padovan --- net/bluetooth/rfcomm/sock.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 44a623275951..194b3a04cfd3 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -82,11 +82,14 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb) static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) { struct sock *sk = d->owner, *parent; + unsigned long flags; + if (!sk) return; BT_DBG("dlc %p state %ld err %d", d, d->state, err); + local_irq_save(flags); bh_lock_sock(sk); if (err) @@ -108,6 +111,7 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) } bh_unlock_sock(sk); + local_irq_restore(flags); if (parent && sock_flag(sk, SOCK_ZAPPED)) { /* We have to drop DLC lock here, otherwise -- cgit v1.2.3 From b0239c80fe89d5832a68a0f3121a9d5ec9fb763e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 8 Sep 2010 14:59:44 -0300 Subject: Revert "Bluetooth: Don't accept ConfigReq if we aren't in the BT_CONFIG state" This reverts commit 8cb8e6f1684be13b51f8429b15f39c140326b327. That commit introduced a regression with the Bluetooth Profile Tuning Suite(PTS), Reverting this make sure that L2CAP is in a qualificable state. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f2062aace406..44a8fb0d6c29 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3089,14 +3089,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!sk) return -ENOENT; - if (sk->sk_state != BT_CONFIG) { - struct l2cap_cmd_rej rej; - - rej.reason = cpu_to_le16(0x0002); - l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ, - sizeof(rej), &rej); + if (sk->sk_state == BT_DISCONN) goto unlock; - } /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); -- cgit v1.2.3 From e454c844644683571617896ab2a4ce0109c1943e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 21 Sep 2010 16:31:11 -0300 Subject: Bluetooth: Fix deadlock in the ERTM logic The Enhanced Retransmission Mode(ERTM) is a realiable mode of operation of the Bluetooth L2CAP layer. Think on it like a simplified version of TCP. The problem we were facing here was a deadlock. ERTM uses a backlog queue to queue incomimg packets while the user is helding the lock. At some moment the sk_sndbuf can be exceeded and we can't alloc new skbs then the code sleep with the lock to wait for memory, that stalls the ERTM connection once we can't read the acknowledgements packets in the backlog queue to free memory and make the allocation of outcoming skb successful. This patch actually affect all users of bt_skb_send_alloc(), i.e., all L2CAP modes and SCO. We are safe against socket states changes or channels deletion while the we are sleeping wait memory. Checking for the sk->sk_err and sk->sk_shutdown make the code safe, since any action that can leave the socket or the channel in a not usable state set one of the struct members at least. Then we can check both of them when getting the lock again and return with the proper error if something unexpected happens. Signed-off-by: Gustavo F. Padovan Signed-off-by: Ulisses Furquim --- include/net/bluetooth/bluetooth.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 27a902d9b3a9..30fce0128dd7 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -161,12 +161,30 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, unsigned long l { struct sk_buff *skb; + release_sock(sk); if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) { skb_reserve(skb, BT_SKB_RESERVE); bt_cb(skb)->incoming = 0; } + lock_sock(sk); + + if (!skb && *err) + return NULL; + + *err = sock_error(sk); + if (*err) + goto out; + + if (sk->sk_shutdown) { + *err = -ECONNRESET; + goto out; + } return skb; + +out: + kfree_skb(skb); + return NULL; } int bt_err(__u16 code); -- cgit v1.2.3 From eaa71b318c5ed0cd1ac3182a533471dc5edf372d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Oct 2010 19:28:52 -0300 Subject: Bluetooth: Disallow to change L2CAP_OPTIONS values when connected L2CAP doesn't permit change like MTU, FCS, TxWindow values while the connection is alive, we can only set that before the connection/configuration process. That can lead to bugs in the L2CAP operation. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 44a8fb0d6c29..0b54b7dd8401 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1950,6 +1950,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us switch (optname) { case L2CAP_OPTIONS: + if (sk->sk_state == BT_CONNECTED) { + err = -EINVAL; + break; + } + opts.imtu = l2cap_pi(sk)->imtu; opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; -- cgit v1.2.3 From b530fb69cf54cf22768a3eabc0604d70b5c13fde Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 8 Oct 2010 10:21:22 -0700 Subject: isdn: strcpy() => strlcpy() setup.phone and setup.eazmsn are 32 character buffers. rcvmsg.msg_data.byte_array is a 48 character buffer. sc_adapter[card]->channel[rcvmsg.phy_link_no - 1].dn is 50 chars. The rcvmsg struct comes from the memcpy_fromio() in receivemessage(). I guess that means it's data off the wire. I'm not very familiar with this code but I don't see any reason to assume these strings are NULL terminated. Also it's weird that "dn" in a 50 character buffer but we only seem to use 32 characters. In drivers/isdn/sc/scioc.h, "dn" is only a 49 character buffer. So potentially there is still an issue there. The important thing for now is to prevent the memory corruption. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/isdn/sc/interrupt.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c index 485be8b1e1b3..f0225bc0f267 100644 --- a/drivers/isdn/sc/interrupt.c +++ b/drivers/isdn/sc/interrupt.c @@ -112,11 +112,19 @@ irqreturn_t interrupt_handler(int dummy, void *card_inst) } else if(callid>=0x0000 && callid<=0x7FFF) { + int len; + pr_debug("%s: Got Incoming Call\n", sc_adapter[card]->devicename); - strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4])); - strcpy(setup.eazmsn, - sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn); + len = strlcpy(setup.phone, &(rcvmsg.msg_data.byte_array[4]), + sizeof(setup.phone)); + if (len >= sizeof(setup.phone)) + continue; + len = strlcpy(setup.eazmsn, + sc_adapter[card]->channel[rcvmsg.phy_link_no - 1].dn, + sizeof(setup.eazmsn)); + if (len >= sizeof(setup.eazmsn)) + continue; setup.si1 = 7; setup.si2 = 0; setup.plan = 0; @@ -176,7 +184,9 @@ irqreturn_t interrupt_handler(int dummy, void *card_inst) * Handle a GetMyNumber Rsp */ if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){ - strcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array); + strlcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no - 1].dn, + rcvmsg.msg_data.byte_array, + sizeof(rcvmsg.msg_data.byte_array)); continue; } -- cgit v1.2.3 From ae6df5f96a51818d6376da5307d773baeece4014 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 7 Oct 2010 10:03:48 +0000 Subject: net: clear heap allocation for ETHTOOL_GRXCLSRLALL Calling ETHTOOL_GRXCLSRLALL with a large rule_cnt will allocate kernel heap without clearing it. For the one driver (niu) that implements it, it will leave the unused portion of heap unchanged and copy the full contents back to userspace. Signed-off-by: Kees Cook Acked-by: Ben Hutchings Signed-off-by: David S. Miller --- net/core/ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 7a85367b3c2f..4016ac6bdd5e 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -348,7 +348,7 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, if (info.cmd == ETHTOOL_GRXCLSRLALL) { if (info.rule_cnt > 0) { if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32)) - rule_buf = kmalloc(info.rule_cnt * sizeof(u32), + rule_buf = kzalloc(info.rule_cnt * sizeof(u32), GFP_USER); if (!rule_buf) return -ENOMEM; -- cgit v1.2.3 From aeb19f6052b5e5c8a24aa444fbff73b84341beac Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 8 Oct 2010 04:25:00 +0000 Subject: r8169: allocate with GFP_KERNEL flag when able to sleep We have fedora bug report where driver fail to initialize after suspend/resume because of memory allocation errors: https://bugzilla.redhat.com/show_bug.cgi?id=629158 To fix use GFP_KERNEL allocation where possible. Tested-by: Neal Becker Signed-off-by: Stanislaw Gruszka Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/r8169.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a0da4a17b025..a68ec8fc9f05 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -4000,7 +4000,7 @@ static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping, static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev, struct RxDesc *desc, int rx_buf_sz, - unsigned int align) + unsigned int align, gfp_t gfp) { struct sk_buff *skb; dma_addr_t mapping; @@ -4008,7 +4008,7 @@ static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev, pad = align ? align : NET_IP_ALIGN; - skb = netdev_alloc_skb(dev, rx_buf_sz + pad); + skb = __netdev_alloc_skb(dev, rx_buf_sz + pad, gfp); if (!skb) goto err_out; @@ -4039,7 +4039,7 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp) } static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, - u32 start, u32 end) + u32 start, u32 end, gfp_t gfp) { u32 cur; @@ -4054,7 +4054,7 @@ static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, skb = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->RxDescArray + i, - tp->rx_buf_sz, tp->align); + tp->rx_buf_sz, tp->align, gfp); if (!skb) break; @@ -4082,7 +4082,7 @@ static int rtl8169_init_ring(struct net_device *dev) memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info)); memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); - if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) + if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC, GFP_KERNEL) != NUM_RX_DESC) goto err_out; rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); @@ -4583,7 +4583,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev, count = cur_rx - tp->cur_rx; tp->cur_rx = cur_rx; - delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); + delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx, GFP_ATOMIC); if (!delta && count) netif_info(tp, intr, dev, "no Rx buffer allocated\n"); tp->dirty_rx += delta; -- cgit v1.2.3 From 82553bb6218d2707d2e6446d7b2313dfd60b48a8 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 8 Oct 2010 04:25:01 +0000 Subject: r8169: use device model DMA API Use DMA API as PCI equivalents will be deprecated. This change also allow to allocate with GFP_KERNEL where possible. Tested-by: Neal Becker Signed-off-by: Stanislaw Gruszka Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/r8169.c | 53 +++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a68ec8fc9f05..992db2fa136e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1212,7 +1212,8 @@ static void rtl8169_update_counters(struct net_device *dev) if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0) return; - counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr); + counters = dma_alloc_coherent(&tp->pci_dev->dev, sizeof(*counters), + &paddr, GFP_KERNEL); if (!counters) return; @@ -1233,7 +1234,8 @@ static void rtl8169_update_counters(struct net_device *dev) RTL_W32(CounterAddrLow, 0); RTL_W32(CounterAddrHigh, 0); - pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr); + dma_free_coherent(&tp->pci_dev->dev, sizeof(*counters), counters, + paddr); } static void rtl8169_get_ethtool_stats(struct net_device *dev, @@ -3292,15 +3294,15 @@ static int rtl8169_open(struct net_device *dev) /* * Rx and Tx desscriptors needs 256 bytes alignment. - * pci_alloc_consistent provides more. + * dma_alloc_coherent provides more. */ - tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, - &tp->TxPhyAddr); + tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES, + &tp->TxPhyAddr, GFP_KERNEL); if (!tp->TxDescArray) goto err_pm_runtime_put; - tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, - &tp->RxPhyAddr); + tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES, + &tp->RxPhyAddr, GFP_KERNEL); if (!tp->RxDescArray) goto err_free_tx_0; @@ -3334,12 +3336,12 @@ out: err_release_ring_2: rtl8169_rx_clear(tp); err_free_rx_1: - pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, - tp->RxPhyAddr); + dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); tp->RxDescArray = NULL; err_free_tx_0: - pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, - tp->TxPhyAddr); + dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); tp->TxDescArray = NULL; err_pm_runtime_put: pm_runtime_put_noidle(&pdev->dev); @@ -3975,7 +3977,7 @@ static void rtl8169_free_rx_skb(struct rtl8169_private *tp, { struct pci_dev *pdev = tp->pci_dev; - pci_unmap_single(pdev, le64_to_cpu(desc->addr), tp->rx_buf_sz, + dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), tp->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(*sk_buff); *sk_buff = NULL; @@ -4014,7 +4016,7 @@ static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev, skb_reserve(skb, align ? ((pad - 1) & (unsigned long)skb->data) : pad); - mapping = pci_map_single(pdev, skb->data, rx_buf_sz, + mapping = dma_map_single(&pdev->dev, skb->data, rx_buf_sz, PCI_DMA_FROMDEVICE); rtl8169_map_to_asic(desc, mapping, rx_buf_sz); @@ -4099,7 +4101,8 @@ static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct ring_info *tx_skb, { unsigned int len = tx_skb->len; - pci_unmap_single(pdev, le64_to_cpu(desc->addr), len, PCI_DMA_TODEVICE); + dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), len, + PCI_DMA_TODEVICE); desc->opts1 = 0x00; desc->opts2 = 0x00; desc->addr = 0x00; @@ -4243,7 +4246,8 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, txd = tp->TxDescArray + entry; len = frag->size; addr = ((void *) page_address(frag->page)) + frag->page_offset; - mapping = pci_map_single(tp->pci_dev, addr, len, PCI_DMA_TODEVICE); + mapping = dma_map_single(&tp->pci_dev->dev, addr, len, + PCI_DMA_TODEVICE); /* anti gcc 2.95.3 bugware (sic) */ status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); @@ -4313,7 +4317,8 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->tx_skb[entry].skb = skb; } - mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE); + mapping = dma_map_single(&tp->pci_dev->dev, skb->data, len, + PCI_DMA_TODEVICE); tp->tx_skb[entry].len = len; txd->addr = cpu_to_le64(mapping); @@ -4477,8 +4482,8 @@ static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff, if (!skb) goto out; - pci_dma_sync_single_for_cpu(tp->pci_dev, addr, pkt_size, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&tp->pci_dev->dev, addr, pkt_size, + PCI_DMA_FROMDEVICE); skb_copy_from_linear_data(*sk_buff, skb->data, pkt_size); *sk_buff = skb; done = true; @@ -4549,11 +4554,11 @@ static int rtl8169_rx_interrupt(struct net_device *dev, rtl8169_rx_csum(skb, desc); if (rtl8169_try_rx_copy(&skb, tp, pkt_size, addr)) { - pci_dma_sync_single_for_device(pdev, addr, + dma_sync_single_for_device(&pdev->dev, addr, pkt_size, PCI_DMA_FROMDEVICE); rtl8169_mark_to_asic(desc, tp->rx_buf_sz); } else { - pci_unmap_single(pdev, addr, tp->rx_buf_sz, + dma_unmap_single(&pdev->dev, addr, tp->rx_buf_sz, PCI_DMA_FROMDEVICE); tp->Rx_skbuff[entry] = NULL; } @@ -4769,10 +4774,10 @@ static int rtl8169_close(struct net_device *dev) free_irq(dev->irq, dev); - pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, - tp->RxPhyAddr); - pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, - tp->TxPhyAddr); + dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); + dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); tp->TxDescArray = NULL; tp->RxDescArray = NULL; -- cgit v1.2.3 From 03c698c93fc15d976738a853a7ccb6ea26396003 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Thu, 7 Oct 2010 02:30:30 +0000 Subject: net/fec: carrier off initially to avoid root mount failure with hardware slow in negotiation, the system did freeze while trying to mount root on nfs at boot time. the link state has not been initialised so network stack tried to start transmission right away. this caused instant retries, as the driver solely stated business upon link down, rendering the system unusable. notify carrier off initially to prevent transmission until phylib will report link up. Signed-off-by: Oskar Schirmer Signed-off-by: David S. Miller --- drivers/net/fec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 768b840aeb6b..e83f67d22fe3 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1311,6 +1311,9 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_mii_init; + /* Carrier starts down, phylib will bring it up */ + netif_carrier_off(ndev); + ret = register_netdev(ndev); if (ret) goto failed_register; -- cgit v1.2.3 From f1ee89d5b007620353fb7dec1d34db4baa1a5571 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 10 Oct 2010 21:50:44 +0000 Subject: ATM: solos-pci, remove use after free Stanse found we do in console_show: kfree_skb(skb); return skb->len; which is not good. Fix that by remembering the len and use it in the function instead. Signed-off-by: Jiri Slaby Cc: Chas Williams Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index f916ddf63938..f46138ab38b6 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -444,6 +444,7 @@ static ssize_t console_show(struct device *dev, struct device_attribute *attr, struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); struct solos_card *card = atmdev->dev_data; struct sk_buff *skb; + unsigned int len; spin_lock(&card->cli_queue_lock); skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]); @@ -451,11 +452,12 @@ static ssize_t console_show(struct device *dev, struct device_attribute *attr, if(skb == NULL) return sprintf(buf, "No data.\n"); - memcpy(buf, skb->data, skb->len); - dev_dbg(&card->dev->dev, "len: %d\n", skb->len); + len = skb->len; + memcpy(buf, skb->data, len); + dev_dbg(&card->dev->dev, "len: %d\n", len); kfree_skb(skb); - return skb->len; + return len; } static int send_command(struct solos_card *card, int dev, const char *buf, size_t size) -- cgit v1.2.3 From 5518b29f225dbdf47ded02cf229ff8225a2cdf82 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 10 Oct 2010 22:46:34 +0000 Subject: ATM: mpc, fix use after free Stanse found that mpc_push frees skb and then it dereferences it. It is a typo, new_skb should be dereferenced there. Signed-off-by: Jiri Slaby Cc: Eric Dumazet Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/atm/mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 622b471e14e0..74bcc662c3dd 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -778,7 +778,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) eg->packets_rcvd++; mpc->eg_ops->put(eg); - memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); + memset(ATM_SKB(new_skb), 0, sizeof(struct atm_skb_data)); netif_rx(new_skb); } -- cgit v1.2.3 From ec622ab072e95cf96e78ab4d39d4eea874518c80 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 10 Oct 2010 23:26:57 +0000 Subject: ATM: iphase, remove sleep-inside-atomic Stanse found that ia_init_one locks a spinlock and inside of that it calls ia_start which calls: * request_irq * tx_init which does kmalloc(GFP_KERNEL) Both of them can thus sleep and result in a deadlock. I don't see a reason to have a per-device spinlock there which is used only there and inited right before the lock location. So remove it completely. Signed-off-by: Jiri Slaby Cc: Chas Williams Signed-off-by: David S. Miller --- drivers/atm/iphase.c | 6 ------ drivers/atm/iphase.h | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index ee9ddeb53417..8cb0347dec28 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -3156,7 +3156,6 @@ static int __devinit ia_init_one(struct pci_dev *pdev, { struct atm_dev *dev; IADEV *iadev; - unsigned long flags; int ret; iadev = kzalloc(sizeof(*iadev), GFP_KERNEL); @@ -3188,19 +3187,14 @@ static int __devinit ia_init_one(struct pci_dev *pdev, ia_dev[iadev_count] = iadev; _ia_dev[iadev_count] = dev; iadev_count++; - spin_lock_init(&iadev->misc_lock); - /* First fixes first. I don't want to think about this now. */ - spin_lock_irqsave(&iadev->misc_lock, flags); if (ia_init(dev) || ia_start(dev)) { IF_INIT(printk("IA register failed!\n");) iadev_count--; ia_dev[iadev_count] = NULL; _ia_dev[iadev_count] = NULL; - spin_unlock_irqrestore(&iadev->misc_lock, flags); ret = -EINVAL; goto err_out_deregister_dev; } - spin_unlock_irqrestore(&iadev->misc_lock, flags); IF_EVENT(printk("iadev_count = %d\n", iadev_count);) iadev->next_board = ia_boards; diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h index b2cd20f549cb..077735e0e04b 100644 --- a/drivers/atm/iphase.h +++ b/drivers/atm/iphase.h @@ -1022,7 +1022,7 @@ typedef struct iadev_t { struct dle_q rx_dle_q; struct free_desc_q *rx_free_desc_qhead; struct sk_buff_head rx_dma_q; - spinlock_t rx_lock, misc_lock; + spinlock_t rx_lock; struct atm_vcc **rx_open; /* list of all open VCs */ u16 num_rx_desc, rx_buf_sz, rxing; u32 rx_pkt_ram, rx_tmp_cnt; -- cgit v1.2.3 From 0aa7deadffd8b596983a3abe29a218b4c5f43301 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 10 Oct 2010 23:26:58 +0000 Subject: NET: wimax, fix use after free Stanse found that i2400m_rx frees skb, but still uses skb->len even though it has skb_len defined. So use skb_len properly in the code. And also define it unsinged int rather than size_t to solve compilation warnings. Signed-off-by: Jiri Slaby Cc: Inaky Perez-Gonzalez Cc: linux-wimax@intel.com Acked-by: Inaky Perez-Gonzalez Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/rx.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 8cc9e319f435..1737d1488b35 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -1244,16 +1244,16 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) int i, result; struct device *dev = i2400m_dev(i2400m); const struct i2400m_msg_hdr *msg_hdr; - size_t pl_itr, pl_size, skb_len; + size_t pl_itr, pl_size; unsigned long flags; - unsigned num_pls, single_last; + unsigned num_pls, single_last, skb_len; skb_len = skb->len; - d_fnstart(4, dev, "(i2400m %p skb %p [size %zu])\n", + d_fnstart(4, dev, "(i2400m %p skb %p [size %u])\n", i2400m, skb, skb_len); result = -EIO; msg_hdr = (void *) skb->data; - result = i2400m_rx_msg_hdr_check(i2400m, msg_hdr, skb->len); + result = i2400m_rx_msg_hdr_check(i2400m, msg_hdr, skb_len); if (result < 0) goto error_msg_hdr_check; result = -EIO; @@ -1261,10 +1261,10 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */ num_pls * sizeof(msg_hdr->pld[0]); pl_itr = ALIGN(pl_itr, I2400M_PL_ALIGN); - if (pl_itr > skb->len) { /* got all the payload descriptors? */ + if (pl_itr > skb_len) { /* got all the payload descriptors? */ dev_err(dev, "RX: HW BUG? message too short (%u bytes) for " "%u payload descriptors (%zu each, total %zu)\n", - skb->len, num_pls, sizeof(msg_hdr->pld[0]), pl_itr); + skb_len, num_pls, sizeof(msg_hdr->pld[0]), pl_itr); goto error_pl_descr_short; } /* Walk each payload payload--check we really got it */ @@ -1272,7 +1272,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) /* work around old gcc warnings */ pl_size = i2400m_pld_size(&msg_hdr->pld[i]); result = i2400m_rx_pl_descr_check(i2400m, &msg_hdr->pld[i], - pl_itr, skb->len); + pl_itr, skb_len); if (result < 0) goto error_pl_descr_check; single_last = num_pls == 1 || i == num_pls - 1; @@ -1290,16 +1290,16 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) if (i < i2400m->rx_pl_min) i2400m->rx_pl_min = i; i2400m->rx_num++; - i2400m->rx_size_acc += skb->len; - if (skb->len < i2400m->rx_size_min) - i2400m->rx_size_min = skb->len; - if (skb->len > i2400m->rx_size_max) - i2400m->rx_size_max = skb->len; + i2400m->rx_size_acc += skb_len; + if (skb_len < i2400m->rx_size_min) + i2400m->rx_size_min = skb_len; + if (skb_len > i2400m->rx_size_max) + i2400m->rx_size_max = skb_len; spin_unlock_irqrestore(&i2400m->rx_lock, flags); error_pl_descr_check: error_pl_descr_short: error_msg_hdr_check: - d_fnend(4, dev, "(i2400m %p skb %p [size %zu]) = %d\n", + d_fnend(4, dev, "(i2400m %p skb %p [size %u]) = %d\n", i2400m, skb, skb_len, result); return result; } -- cgit v1.2.3 From b00916b189d13a615ff05c9242201135992fcda3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 11 Oct 2010 12:23:25 -0700 Subject: net: clear heap allocations for privileged ethtool actions Several other ethtool functions leave heap uncleared (potentially) by drivers. Some interfaces appear safe (eeprom, etc), in that the sizes are well controlled. In some situations (e.g. unchecked error conditions), the heap will remain unchanged in areas before copying back to userspace. Note that these are less of an issue since these all require CAP_NET_ADMIN. Cc: stable@kernel.org Signed-off-by: Kees Cook Acked-by: Ben Hutchings Signed-off-by: David S. Miller --- net/core/ethtool.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 4016ac6bdd5e..8451ab481095 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -397,7 +397,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index)) return -ENOMEM; full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size; - indir = kmalloc(full_size, GFP_USER); + indir = kzalloc(full_size, GFP_USER); if (!indir) return -ENOMEM; @@ -538,7 +538,7 @@ static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr) gstrings.len = ret; - data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); + data = kzalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); if (!data) return -ENOMEM; @@ -775,7 +775,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) if (regs.len > reglen) regs.len = reglen; - regbuf = kmalloc(reglen, GFP_USER); + regbuf = kzalloc(reglen, GFP_USER); if (!regbuf) return -ENOMEM; -- cgit v1.2.3