From dd981ab091cde09bb9eb23c8d81305ba615ee30c Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 3 Apr 2013 10:14:20 +0200 Subject: batman-adv: use the proper header len when checking the TTVN Unicast packet might be of type either UNICAST or UNICAST4ADDR. In the two cases the header size is different, but the mechanism checking the TTVN field was assuming it to be always of the same type (UNICAST), so failing to access the inner Ethernet header in case of UNICAST4ADDR. Fix this by passing the real header length as argument. Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 319f290..7de0336 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -924,7 +924,7 @@ out: } static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, - struct sk_buff *skb) { + struct sk_buff *skb, int hdr_len) { uint8_t curr_ttvn, old_ttvn; struct batadv_orig_node *orig_node; struct ethhdr *ethhdr; @@ -933,7 +933,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, int is_old_ttvn; /* check if there is enough data before accessing it */ - if (pskb_may_pull(skb, sizeof(*unicast_packet) + ETH_HLEN) < 0) + if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0) return 0; /* create a copy of the skb (in case of for re-routing) to modify it. */ @@ -941,7 +941,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, return 0; unicast_packet = (struct batadv_unicast_packet *)skb->data; - ethhdr = (struct ethhdr *)(skb->data + sizeof(*unicast_packet)); + ethhdr = (struct ethhdr *)(skb->data + hdr_len); /* check if the destination client was served by this node and it is now * roaming. In this case, it means that the node has got a ROAM_ADV @@ -1048,8 +1048,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) return NET_RX_DROP; - - if (!batadv_check_unicast_ttvn(bat_priv, skb)) + if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) return NET_RX_DROP; /* packet for me */ @@ -1093,7 +1092,7 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb, if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) return NET_RX_DROP; - if (!batadv_check_unicast_ttvn(bat_priv, skb)) + if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) return NET_RX_DROP; unicast_packet = (struct batadv_unicast_frag_packet *)skb->data; -- cgit v0.10.2 From 1297f9db4fe8b5c7d77e8da71c2a21ea2d8076ba Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 24 Apr 2013 11:52:28 +0000 Subject: be2net: Remove an incorrect pvid check in Tx To work-around a HW bug that corrupts certain packets while inserting a pvid, the driver needs to invoke a special hack in firmware to avoid the VLAN tagging in the HW. Since this logic is missing from the driver, removing the check for pvid. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2886c9b..a254942 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -626,11 +626,6 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, return vlan_tag; } -static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb) -{ - return vlan_tx_tag_present(skb) || adapter->pvid; -} - static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, struct sk_buff *skb, u32 wrb_cnt, u32 len) { @@ -781,11 +776,10 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; - /* HW has a bug which considers padding bytes as legal - * and modifies the IPv4 hdr's 'tot_len' field + /* For padded packets, BE HW modifies tot_len field in IP header + * incorrecly when VLAN tag is inserted by HW. */ - if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) && - is_ipv4_pkt(skb)) { + if (skb->len <= 60 && vlan_tx_tag_present(skb) && is_ipv4_pkt(skb)) { ip = (struct iphdr *)ip_hdr(skb); pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); } @@ -795,7 +789,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, * Manually insert VLAN in pkt. */ if (skb->ip_summed != CHECKSUM_PARTIAL && - be_vlan_tag_chk(adapter, skb)) { + vlan_tx_tag_present(skb)) { skb = be_insert_vlan_in_pkt(adapter, skb); if (unlikely(!skb)) goto tx_drop; -- cgit v0.10.2 From bc0c3405abbb7d7115df824c0e41422396923c1f Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 24 Apr 2013 11:52:50 +0000 Subject: be2net: fix a Tx stall bug caused by a specific ipv6 packet The ASIC could lockup in the transmit path when it tries to insert VLAN in a specific ipv6 packet. 1) Identify the packet which can cause this. 2) Check if the firmware provides a workaround to prevent this. 3) If workaround is not present, drop the packet. 4) If the firmware provides a workaround, insert the VLAN tag in the packet and inform the firmware to skip further VLAN insertions. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 29aff55..941aa1f 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -328,6 +328,7 @@ enum vf_state { #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 +#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11) struct phy_info { u8 transceiver; @@ -434,6 +435,7 @@ struct be_adapter { u8 wol_cap; bool wol; u32 uc_macs; /* Count of secondary UC MAC programmed */ + u16 qnq_vid; u32 msg_enable; int be_get_temp_freq; u16 max_mcast_mac; @@ -648,6 +650,11 @@ static inline bool be_is_wol_excluded(struct be_adapter *adapter) } } +static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) +{ + return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD; +} + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, u8 link_status); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 3c9b4f1..ce5af9b 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -263,6 +263,27 @@ static void be_async_grp5_evt_process(struct be_adapter *adapter, } } +static void be_async_dbg_evt_process(struct be_adapter *adapter, + u32 trailer, struct be_mcc_compl *cmp) +{ + u8 event_type = 0; + struct be_async_event_qnq *evt = (struct be_async_event_qnq *) cmp; + + event_type = (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) & + ASYNC_TRAILER_EVENT_TYPE_MASK; + + switch (event_type) { + case ASYNC_DEBUG_EVENT_TYPE_QNQ: + if (evt->valid) + adapter->qnq_vid = le16_to_cpu(evt->vlan_tag); + adapter->flags |= BE_FLAGS_QNQ_ASYNC_EVT_RCVD; + break; + default: + dev_warn(&adapter->pdev->dev, "Unknown debug event\n"); + break; + } +} + static inline bool is_link_state_evt(u32 trailer) { return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & @@ -277,6 +298,13 @@ static inline bool is_grp5_evt(u32 trailer) ASYNC_EVENT_CODE_GRP_5); } +static inline bool is_dbg_evt(u32 trailer) +{ + return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_QNQ); +} + static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) { struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; @@ -325,6 +353,9 @@ int be_process_mcc(struct be_adapter *adapter) else if (is_grp5_evt(compl->flags)) be_async_grp5_evt_process(adapter, compl->flags, compl); + else if (is_dbg_evt(compl->flags)) + be_async_dbg_evt_process(adapter, + compl->flags, compl); } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { status = be_mcc_compl_process(adapter, compl); atomic_dec(&mcc_obj->q.used); @@ -1022,6 +1053,7 @@ int be_cmd_mccq_ext_create(struct be_adapter *adapter, /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ req->async_event_bitmap[0] = cpu_to_le32(0x00000022); + req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ); be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 9697086..07fd927 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -84,6 +84,9 @@ struct be_mcc_compl { #define ASYNC_EVENT_QOS_SPEED 0x1 #define ASYNC_EVENT_COS_PRIORITY 0x2 #define ASYNC_EVENT_PVID_STATE 0x3 +#define ASYNC_EVENT_CODE_QNQ 0x6 +#define ASYNC_DEBUG_EVENT_TYPE_QNQ 1 + struct be_async_event_trailer { u32 code; }; @@ -144,6 +147,16 @@ struct be_async_event_grp5_pvid_state { struct be_async_event_trailer trailer; } __packed; +/* async event indicating outer VLAN tag in QnQ */ +struct be_async_event_qnq { + u8 valid; /* Indicates if outer VLAN is valid */ + u8 rsvd0; + u16 vlan_tag; + u32 event_tag; + u8 rsvd1[4]; + struct be_async_event_trailer trailer; +} __packed; + struct be_mcc_mailbox { struct be_mcc_wrb wrb; struct be_mcc_compl compl; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a254942..21109b5 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -627,7 +627,7 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, } static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, - struct sk_buff *skb, u32 wrb_cnt, u32 len) + struct sk_buff *skb, u32 wrb_cnt, u32 len, bool skip_hw_vlan) { u16 vlan_tag; @@ -654,8 +654,9 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); } + /* To skip HW VLAN tagging: evt = 1, compl = 0 */ + AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, !skip_hw_vlan); AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1); - AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, 1); AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt); AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len); } @@ -678,7 +679,8 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, } static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, - struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb) + struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb, + bool skip_hw_vlan) { dma_addr_t busaddr; int i, copied = 0; @@ -727,7 +729,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, queue_head_inc(txq); } - wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied); + wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied, skip_hw_vlan); be_dws_cpu_to_le(hdr, sizeof(*hdr)); return copied; @@ -744,7 +746,8 @@ dma_err: } static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, - struct sk_buff *skb) + struct sk_buff *skb, + bool *skip_hw_vlan) { u16 vlan_tag = 0; @@ -759,9 +762,67 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, skb->vlan_tci = 0; } + if (qnq_async_evt_rcvd(adapter) && adapter->pvid) { + if (!vlan_tag) + vlan_tag = adapter->pvid; + if (skip_hw_vlan) + *skip_hw_vlan = true; + } + + if (vlan_tag) { + skb = __vlan_put_tag(skb, vlan_tag); + if (unlikely(!skb)) + return skb; + + skb->vlan_tci = 0; + } + + /* Insert the outer VLAN, if any */ + if (adapter->qnq_vid) { + vlan_tag = adapter->qnq_vid; + skb = __vlan_put_tag(skb, vlan_tag); + if (unlikely(!skb)) + return skb; + if (skip_hw_vlan) + *skip_hw_vlan = true; + } + return skb; } +static bool be_ipv6_exthdr_check(struct sk_buff *skb) +{ + struct ethhdr *eh = (struct ethhdr *)skb->data; + u16 offset = ETH_HLEN; + + if (eh->h_proto == htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + offset); + + offset += sizeof(struct ipv6hdr); + if (ip6h->nexthdr != NEXTHDR_TCP && + ip6h->nexthdr != NEXTHDR_UDP) { + struct ipv6_opt_hdr *ehdr = + (struct ipv6_opt_hdr *) (skb->data + offset); + + /* offending pkt: 2nd byte following IPv6 hdr is 0xff */ + if (ehdr->hdrlen == 0xff) + return true; + } + } + return false; +} + +static int be_vlan_tag_tx_chk(struct be_adapter *adapter, struct sk_buff *skb) +{ + return vlan_tx_tag_present(skb) || adapter->pvid || adapter->qnq_vid; +} + +static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb) +{ + return BE3_chip(adapter) && + be_ipv6_exthdr_check(skb); +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { @@ -772,6 +833,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, u32 wrb_cnt = 0, copied = 0; u32 start = txq->head, eth_hdr_len; bool dummy_wrb, stopped = false; + bool skip_hw_vlan = false; eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; @@ -790,14 +852,37 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, */ if (skb->ip_summed != CHECKSUM_PARTIAL && vlan_tx_tag_present(skb)) { - skb = be_insert_vlan_in_pkt(adapter, skb); + skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan); + if (unlikely(!skb)) + goto tx_drop; + } + + /* HW may lockup when VLAN HW tagging is requested on + * certain ipv6 packets. Drop such pkts if the HW workaround to + * skip HW tagging is not enabled by FW. + */ + if (unlikely(be_ipv6_tx_stall_chk(adapter, skb) && + (adapter->pvid || adapter->qnq_vid) && + !qnq_async_evt_rcvd(adapter))) + goto tx_drop; + + /* Manual VLAN tag insertion to prevent: + * ASIC lockup when the ASIC inserts VLAN tag into + * certain ipv6 packets. Insert VLAN tags in driver, + * and set event, completion, vlan bits accordingly + * in the Tx WRB. + */ + if (be_ipv6_tx_stall_chk(adapter, skb) && + be_vlan_tag_tx_chk(adapter, skb)) { + skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan); if (unlikely(!skb)) goto tx_drop; } wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); - copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); + copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb, + skip_hw_vlan); if (copied) { int gso_segs = skb_shinfo(skb)->gso_segs; -- cgit v0.10.2 From d2cb6ce7306997c753976b65bf81495e1efe7074 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 24 Apr 2013 11:53:08 +0000 Subject: be2net: Fix PVID tag offload for packets with inline VLAN tag. BE3 HW in UMC mode could wrongly double tag a packet with PVID when the packet already has a inlined VLAN tag. In UMC mode, When HW finds that a packet is already VLAN tagged PVID should not be inserted into the packet. To fix this use the FW hack to instruct the HW to skip PVID tagging. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 21109b5..1232e91 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -834,6 +834,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, u32 start = txq->head, eth_hdr_len; bool dummy_wrb, stopped = false; bool skip_hw_vlan = false; + struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; @@ -846,6 +847,13 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); } + /* If vlan tag is already inlined in the packet, skip HW VLAN + * tagging in UMC mode + */ + if ((adapter->function_mode & UMC_ENABLED) && + veh->h_vlan_proto == htons(ETH_P_8021Q)) + skip_hw_vlan = true; + /* HW has a bug wherein it will calculate CSUM for VLAN * pkts even though it is disabled. * Manually insert VLAN in pkt. -- cgit v0.10.2 From 093162553c33e9479283e107b4431378271c735d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 24 Apr 2013 18:34:55 -0700 Subject: tcp: force a dst refcount when prequeue packet Before escaping RCU protected section and adding packet into prequeue, make sure the dst is refcounted. Reported-by: Mike Galbraith Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index cf0694d..a345480 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1049,6 +1049,7 @@ static inline bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) skb_queue_len(&tp->ucopy.prequeue) == 0) return false; + skb_dst_force(skb); __skb_queue_tail(&tp->ucopy.prequeue, skb); tp->ucopy.memory += skb->truesize; if (tp->ucopy.memory > sk->sk_rcvbuf) { -- cgit v0.10.2 From 89cc80a44b7c320e08599cb86f6aef0ead8986a1 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 22 Apr 2013 22:40:07 +0100 Subject: sfc: Fix naming of MTD partitions for FPGA bitfiles efx_mcdi_get_board_cfg() uses a buffer for the firmware response that is only large enough to hold subtypes for the originally defined set of NVRAM partitions. Longer responses are truncated, and we may read off the end of the buffer when copying out subtypes for additional partitions. In particular, this can result in the MTD partition for an FPGA bitfile being named e.g. 'eth5 sfc_fpga:00' when it should be 'eth5 sfc_fpga:01'. This means the firmware update tool (sfupdate) can't tell which bitfile should be written to the partition. Correct the response buffer size. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 0095ce9..97dd8f18 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -667,7 +667,7 @@ fail: int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, u16 *fw_subtype_list, u32 *capabilities) { - uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMIN]; + uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMAX]; size_t outlen, offset, i; int port_num = efx_port_num(efx); int rc; -- cgit v0.10.2 From cd4baaaa04b4aaa3b0ec4d13a6f3d203b92eadbd Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Mon, 22 Apr 2013 19:42:16 +0000 Subject: gianfar: do not advertise any alarm capability. An early draft of the PHC patch series included an alarm in the gianfar driver. During the review process, the alarm code was dropped, but the capability removal was overlooked. This patch fixes the issue by advertising zero alarms. This patch should be applied to every 3.x stable kernel. Signed-off-by: Richard Cochran Reported-by: Chris LaRocque Cc: Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 2e5daee..a3f8a25 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -127,7 +127,6 @@ struct gianfar_ptp_registers { #define DRIVER "gianfar_ptp" #define DEFAULT_CKSEL 1 -#define N_ALARM 1 /* first alarm is used internally to reset fipers */ #define N_EXT_TS 2 #define REG_SIZE sizeof(struct gianfar_ptp_registers) @@ -410,7 +409,7 @@ static struct ptp_clock_info ptp_gianfar_caps = { .owner = THIS_MODULE, .name = "gianfar clock", .max_adj = 512000, - .n_alarm = N_ALARM, + .n_alarm = 0, .n_ext_ts = N_EXT_TS, .n_per_out = 0, .pps = 1, -- cgit v0.10.2 From fccc9f1fa878d9599aa583f0fec3bca95639667d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Apr 2013 20:22:15 +0000 Subject: appletalk: info leak in ->getname() There is a one byte hole between ->sat_port and ->sat_addr. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 4a141e3..ef12839 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1253,7 +1253,7 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, goto out; *uaddr_len = sizeof(struct sockaddr_at); - memset(&sat.sat_zero, 0, sizeof(sat.sat_zero)); + memset(&sat, 0, sizeof(sat)); if (peer) { err = -ENOTCONN; -- cgit v0.10.2 From 7a3b68434b1b5fb7b9a6184efb26822cd1a54cc8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Apr 2013 20:22:51 +0000 Subject: netrom: info leak in ->getname() The sockaddr_ax25 struct has a 3 byte hole between ->sax25_call and ->sax25_ndigis. I've added a memset to avoid leaking uninitialized stack data to userspace. Signed-off-by: Dan Carpenter Acked-by: Ralf Baechle Signed-off-by: David S. Miller diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 103bd70..ec0c80f 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -834,6 +834,8 @@ static int nr_getname(struct socket *sock, struct sockaddr *uaddr, struct sock *sk = sock->sk; struct nr_sock *nr = nr_sk(sk); + memset(&sax->fsa_ax25, 0, sizeof(struct sockaddr_ax25)); + lock_sock(sk); if (peer != 0) { if (sk->sk_state != TCP_ESTABLISHED) { -- cgit v0.10.2 From d9152097acc5f9fdc0bf1a8e3454634dfae47742 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Apr 2013 20:24:14 +0000 Subject: isdn: mISDN: set ->family in ->getname() The "maddr->family" variable was not set but instead it leaked stack information to userspace. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 8b07f83..e47dcb9 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -578,6 +578,7 @@ data_sock_getname(struct socket *sock, struct sockaddr *addr, lock_sock(sk); *addr_len = sizeof(*maddr); + maddr->family = AF_ISDN; maddr->dev = _pms(sk)->dev->id; maddr->channel = _pms(sk)->ch.nr; maddr->sapi = _pms(sk)->ch.addr & 0xff; -- cgit v0.10.2 From 5ffedc6ed3d066f5c0d2c2106f9081170b3d24fa Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Apr 2013 20:24:52 +0000 Subject: NFC: llcp: two bugs in ->getname() The sockaddr_nfc_llcp struct has as hole between ->sa_family and ->dev_idx so I've added a memset() to clear it and prevent an information leak. Also the ->nfc_protocol element wasn't set so I've added that. "uaddr->sa_family" and "llcp_addr->sa_family" are the same thing but it's less confusing to use llcp_addr consistently throughout. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 6c94447..e163157 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -358,12 +358,13 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, llcp_sock->dsap, llcp_sock->ssap); - uaddr->sa_family = AF_NFC; - + memset(llcp_addr, 0, sizeof(*llcp_addr)); *len = sizeof(struct sockaddr_nfc_llcp); + llcp_addr->sa_family = AF_NFC; llcp_addr->dev_idx = llcp_sock->dev->idx; llcp_addr->target_idx = llcp_sock->target_idx; + llcp_addr->nfc_protocol = llcp_sock->nfc_protocol; llcp_addr->dsap = llcp_sock->dsap; llcp_addr->ssap = llcp_sock->ssap; llcp_addr->service_name_len = llcp_sock->service_name_len; -- cgit v0.10.2 From e8dbad66ef56074eadb41ed5998acd2320447018 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 22 Apr 2013 20:40:39 +0000 Subject: tuntap: correct the return value in tun_set_iff() commit (3be8fbab tuntap: fix error return code in tun_set_iff()) breaks the creation of multiqueue tuntap since it forbids to create more than one queues for a multiqueue tuntap device. We need return 0 instead -EBUSY here since we don't want to re-initialize the device when one or more queues has been already attached. Add a comment and correct the return value to zero. Reported-by: Jerry Chu Cc: Jerry Chu Cc: Wei Yongjun Cc: Eric Dumazet Signed-off-by: Jason Wang Acked-by: Jerry Chu Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 729ed53..0c9df2f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1593,8 +1593,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) return err; if (tun->flags & TUN_TAP_MQ && - (tun->numqueues + tun->numdisabled > 1)) - return -EBUSY; + (tun->numqueues + tun->numdisabled > 1)) { + /* One or more queue has already been attached, no need + * to initialize the device again. + */ + return 0; + } } else { char *name; -- cgit v0.10.2 From e56db277684895184bc74fcf74f7ef993e3a5b6c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 25 Apr 2013 15:15:23 +0800 Subject: caif: spi: missing platform_driver_unregister() on error in cfspi_init_module() Add the missing platform_driver_unregister() before return from cfspi_init_module() in the error handling case. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index b71ce9b..ae7e756 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -864,6 +864,7 @@ static int __init cfspi_init_module(void) driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_up_head_align); err_create_up_head_align: + platform_driver_unregister(&cfspi_spi_driver); err_dev_register: return result; } -- cgit v0.10.2 From ecf01c22be034690b621d92c9ff488d607a9995a Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 22 Apr 2013 02:53:03 +0000 Subject: bnx2x: Prevent NULL pointer dereference in kdump In scenarios in which a previous driver was removed without proper cleanup (e.g., kdump), it is possible for the chip to generate an interrupt without any apparent reason once interrupts are requested. Due to an erroneous initialization of resources, some of the bnx2x structs which are required for interrupt handling are initialized only after an interface's interrupt is requested from the OS. As a result, once such a spurious interrupt occurs, it will cause a NULL pointer dereference - the driver will access those structs in its interrupt handling routine. This patch change the interrupt request scheme so that bnx2x would only request interrupts from the kernel after it has finished initializing all the inner structs required for interrupt handling. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 57619dd..51a6030 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1037,6 +1037,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) DP(NETIF_MSG_INTR, "got an MSI-X interrupt on IDX:SB [fp %d fw_sd %d igusb %d]\n", fp->index, fp->fw_sb_id, fp->igu_sb_id); + bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0); #ifdef BNX2X_STOP_ON_ERROR @@ -1718,7 +1719,7 @@ static int bnx2x_req_irq(struct bnx2x *bp) return request_irq(irq, bnx2x_interrupt, flags, bp->dev->name, bp->dev); } -static int bnx2x_setup_irqs(struct bnx2x *bp) +int bnx2x_setup_irqs(struct bnx2x *bp) { int rc = 0; if (bp->flags & USING_MSIX_FLAG && @@ -2574,6 +2575,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) } } + bnx2x_pre_irq_nic_init(bp); + /* Connect to IRQs */ rc = bnx2x_setup_irqs(bp); if (rc) { @@ -2583,11 +2586,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) LOAD_ERROR_EXIT(bp, load_error2); } - /* Setup NIC internals and enable interrupts */ - bnx2x_nic_init(bp, load_code); - /* Init per-function objects */ if (IS_PF(bp)) { + /* Setup NIC internals and enable interrupts */ + bnx2x_post_irq_nic_init(bp, load_code); + bnx2x_init_bp_objs(bp); bnx2x_iov_nic_init(bp); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index aee7671..c3a65d0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -295,16 +295,29 @@ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw); void bnx2x_nic_init_cnic(struct bnx2x *bp); /** - * bnx2x_nic_init - init driver internals. + * bnx2x_preirq_nic_init - init driver internals. * * @bp: driver handle * * Initializes: - * - rings + * - fastpath object + * - fastpath rings + * etc. + */ +void bnx2x_pre_irq_nic_init(struct bnx2x *bp); + +/** + * bnx2x_postirq_nic_init - init driver internals. + * + * @bp: driver handle + * @load_code: COMMON, PORT or FUNCTION + * + * Initializes: * - status blocks + * - slowpath rings * - etc. */ -void bnx2x_nic_init(struct bnx2x *bp, u32 load_code); +void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code); /** * bnx2x_alloc_mem_cnic - allocate driver's memory for cnic. * diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c50696b..a8f1ee3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -6018,10 +6018,11 @@ void bnx2x_nic_init_cnic(struct bnx2x *bp) mmiowb(); } -void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) +void bnx2x_pre_irq_nic_init(struct bnx2x *bp) { int i; + /* Setup NIC internals and enable interrupts */ for_each_eth_queue(bp, i) bnx2x_init_eth_fp(bp, i); @@ -6030,17 +6031,21 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) bnx2x_init_rx_rings(bp); bnx2x_init_tx_rings(bp); - if (IS_VF(bp)) - return; + if (IS_PF(bp)) { + /* Initialize MOD_ABS interrupts */ + bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id, + bp->common.shmem_base, + bp->common.shmem2_base, BP_PORT(bp)); - /* Initialize MOD_ABS interrupts */ - bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id, - bp->common.shmem_base, bp->common.shmem2_base, - BP_PORT(bp)); + /* initialize the default status block and sp ring */ + bnx2x_init_def_sb(bp); + bnx2x_update_dsb_idx(bp); + bnx2x_init_sp_ring(bp); + } +} - bnx2x_init_def_sb(bp); - bnx2x_update_dsb_idx(bp); - bnx2x_init_sp_ring(bp); +void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code) +{ bnx2x_init_eq_ring(bp); bnx2x_init_internal(bp, load_code); bnx2x_pf_init(bp); @@ -6058,12 +6063,7 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) AEU_INPUTS_ATTN_BITS_SPIO5); } -/* end of nic init */ - -/* - * gzip service functions - */ - +/* gzip service functions */ static int bnx2x_gunzip_init(struct bnx2x *bp) { bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE, -- cgit v0.10.2 From c6cdcf6d82bc8f53e64ad59464e0114fe48e28bb Mon Sep 17 00:00:00 2001 From: "nikolay@redhat.com" Date: Mon, 22 Apr 2013 08:12:22 +0000 Subject: bonding: fix locking in enslave failure path In commit 3c5913b53fefc9d9e15a2d0f93042766658d9f3f ("bonding: primary_slave & curr_active_slave are not cleaned on enslave failure") I didn't account for the use of curr_active_slave without curr_slave_lock and since there are such users, we should hold bond->lock for writing while setting it to NULL (in the NULL case we don't need the curr_slave_lock). Keeping the bond lock as to avoid the extra release/acquire cycle. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index dbbea0e..7db40de1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1915,14 +1915,16 @@ err_detach: bond_detach_slave(bond, new_slave); if (bond->primary_slave == new_slave) bond->primary_slave = NULL; - write_unlock_bh(&bond->lock); if (bond->curr_active_slave == new_slave) { + bond_change_active_slave(bond, NULL); + write_unlock_bh(&bond->lock); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); - bond_change_active_slave(bond, NULL); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + } else { + write_unlock_bh(&bond->lock); } slave_disable_netpoll(new_slave); -- cgit v0.10.2 From 6ad0b2f7fdfd95fe3107367f8aed252e94c3f654 Mon Sep 17 00:00:00 2001 From: Asias He Date: Tue, 23 Apr 2013 20:33:52 +0000 Subject: VSOCK: Fix misc device registration When we call vsock_core_init to init VSOCK the second time, vsock_device.minor still points to the old dynamically allocated minor number. misc_register will allocate it for us successfully as if we were asking for a static one. However, when other user call misc_register to allocate a dynamic minor number, it will give the one used by vsock_core_init(), causing this: [ 405.470687] WARNING: at fs/sysfs/dir.c:536 sysfs_add_one+0xcc/0xf0() [ 405.470689] Hardware name: OptiPlex 790 [ 405.470690] sysfs: cannot create duplicate filename '/dev/char/10:54' Always set vsock_device.minor to MISC_DYNAMIC_MINOR before we register. Cc: "David S. Miller" Cc: Andy King Cc: Dmitry Torokhov Cc: Reilly Grant Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Asias He Acked-by: Dmitry Torokhov Signed-off-by: David S. Miller diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 7f93e2a..4b4db18 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1932,7 +1932,6 @@ static const struct file_operations vsock_device_ops = { static struct miscdevice vsock_device = { .name = "vsock", - .minor = MISC_DYNAMIC_MINOR, .fops = &vsock_device_ops, }; @@ -1942,6 +1941,7 @@ static int __vsock_core_init(void) vsock_init_tables(); + vsock_device.minor = MISC_DYNAMIC_MINOR; err = misc_register(&vsock_device); if (err) { pr_err("Failed to register misc device\n"); -- cgit v0.10.2 From 22ee3b57c3ff71772b0c4178404b04f5df78d501 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Apr 2013 23:40:55 +0000 Subject: VSOCK: Drop bogus __init annotation from vsock_init_tables() If gcc (e.g. 4.1.2) decides not to inline vsock_init_tables(), this will cause a section mismatch: WARNING: net/vmw_vsock/vsock.o(.text+0x1bc): Section mismatch in reference from the function __vsock_core_init() to the function .init.text:vsock_init_tables() The function __vsock_core_init() references the function __init vsock_init_tables(). This is often because __vsock_core_init lacks a __init annotation or the annotation of vsock_init_tables is wrong. This may cause crashes if VSOCKETS=y and VMWARE_VMCI_VSOCKETS=m. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 4b4db18..3f77f42 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -165,7 +165,7 @@ static struct list_head vsock_bind_table[VSOCK_HASH_SIZE + 1]; static struct list_head vsock_connected_table[VSOCK_HASH_SIZE]; static DEFINE_SPINLOCK(vsock_table_lock); -static __init void vsock_init_tables(void) +static void vsock_init_tables(void) { int i; -- cgit v0.10.2 From b9e48de110ec64bdfd4b83358d0e286551bb110c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 24 Apr 2013 02:46:37 +0000 Subject: isdn/sc: Fix incorrect module_param_array types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/isdn/sc/init.c: In function ‘__check_irq’: drivers/isdn/sc/init.c:36: warning: return from incompatible pointer type drivers/isdn/sc/init.c: In function ‘__check_ram’: drivers/isdn/sc/init.c:37: warning: return from incompatible pointer type Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index 6b580b2..ca997bd 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -33,8 +33,8 @@ static unsigned long ram[] = {0, 0, 0, 0}; static bool do_reset = 0; module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(ram, int, NULL, 0); +module_param_array(irq, byte, NULL, 0); +module_param_array(ram, long, NULL, 0); module_param(do_reset, bool, 0); static int identify_board(unsigned long, unsigned int); -- cgit v0.10.2 From 3811ae76bc84e5dc1a670ae10695f046b310bee1 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 24 Apr 2013 21:59:23 +0000 Subject: net: tun: release the reference of tun device in tun_recvmsg We forget to release the reference of tun device in tun_recvmsg. bug introduced in commit 54f968d6efdbf7dec36faa44fc11f01b0e4d1990 (tuntap: move socket to tun_file) Signed-off-by: Gao feng Acked-by: Jason Wang Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 0c9df2f..dcd0c19 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1471,14 +1471,17 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, if (!tun) return -EBADFD; - if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) - return -EINVAL; + if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) { + ret = -EINVAL; + goto out; + } ret = tun_do_read(tun, tfile, iocb, m->msg_iov, total_len, flags & MSG_DONTWAIT); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; } +out: tun_put(tun); return ret; } -- cgit v0.10.2 From f7a1dd6e3ad59f0cfd51da29dfdbfd54122c5916 Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Sat, 27 Apr 2013 20:06:14 +0200 Subject: ipvs: ip_vs_sip_fill_param() BUG: bad check of return value The reason for this patch is crash in kmemdup caused by returning from get_callid with uniialized matchoff and matchlen. Removing Zero check of matchlen since it's done by ct_sip_get_header() BUG: unable to handle kernel paging request at ffff880457b5763f IP: [] kmemdup+0x2e/0x35 PGD 27f6067 PUD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: xt_state xt_helper nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_mangle xt_connmark xt_conntrack ip6_tables nf_conntrack_ftp ip_vs_ftp nf_nat xt_tcpudp iptable_mangle xt_mark ip_tables x_tables ip_vs_rr ip_vs_lblcr ip_vs_pe_sip ip_vs nf_conntrack_sip nf_conntrack bonding igb i2c_algo_bit i2c_core CPU 5 Pid: 0, comm: swapper/5 Not tainted 3.9.0-rc5+ #5 /S1200KP RIP: 0010:[] [] kmemdup+0x2e/0x35 RSP: 0018:ffff8803fea03648 EFLAGS: 00010282 RAX: ffff8803d61063e0 RBX: 0000000000000003 RCX: 0000000000000003 RDX: 0000000000000003 RSI: ffff880457b5763f RDI: ffff8803d61063e0 RBP: ffff8803fea03658 R08: 0000000000000008 R09: 0000000000000011 R10: 0000000000000011 R11: 00ffffffff81a8a3 R12: ffff880457b5763f R13: ffff8803d67f786a R14: ffff8803fea03730 R15: ffffffffa0098e90 FS: 0000000000000000(0000) GS:ffff8803fea00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff880457b5763f CR3: 0000000001a0c000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper/5 (pid: 0, threadinfo ffff8803ee18c000, task ffff8803ee18a480) Stack: ffff8803d822a080 000000000000001c ffff8803fea036c8 ffffffffa000937a ffffffff81f0d8a0 000000038135fdd5 ffff880300000014 ffff880300110000 ffffffff150118ac ffff8803d7e8a000 ffff88031e0118ac 0000000000000000 Call Trace: [] ip_vs_sip_fill_param+0x13a/0x187 [ip_vs_pe_sip] [] ip_vs_sched_persist+0x2c6/0x9c3 [ip_vs] [] ? __lock_acquire+0x677/0x1697 [] ? native_sched_clock+0x3c/0x7d [] ? native_sched_clock+0x3c/0x7d [] ? sched_clock_cpu+0x43/0xcf [] ip_vs_schedule+0x181/0x4ba [ip_vs] ... Signed-off-by: Hans Schillstrom Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: David S. Miller diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c index 12475ef..e5920fb 100644 --- a/net/netfilter/ipvs/ip_vs_pe_sip.c +++ b/net/netfilter/ipvs/ip_vs_pe_sip.c @@ -37,14 +37,10 @@ static int get_callid(const char *dptr, unsigned int dataoff, if (ret > 0) break; if (!ret) - return 0; + return -EINVAL; dataoff += *matchoff; } - /* Empty callid is useless */ - if (!*matchlen) - return -EINVAL; - /* Too large is useless */ if (*matchlen > IP_VS_PEDATA_MAXLEN) return -EINVAL; -- cgit v0.10.2 From 2c1bbbffa0b644fab4f91878cde0c2e8f52e2dcc Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Thu, 25 Apr 2013 00:49:55 +0000 Subject: net: mac802154: comparision issue of type cast, finding by EXTRA_CFLAGS=-W Change MAC802154_CHAN_NONE from ~(u8)0 to 0xff, or the comparison in mac802154_wpan_xmit() for ``chan == MAC802154_CHAN_NONE'' will not succeed. This bug can be boiled down to ``u8 foo = 0xff; if (foo == ~(u8)0) [...] else [...]'' where the condition will always take the else branch. Signed-off-by: Chen Gang Signed-off-by: David S. Miller diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h index a4dcaf1..703c121 100644 --- a/net/mac802154/mac802154.h +++ b/net/mac802154/mac802154.h @@ -90,7 +90,7 @@ struct mac802154_sub_if_data { #define MAC802154_MAX_XMIT_ATTEMPTS 3 -#define MAC802154_CHAN_NONE (~(u8)0) /* No channel is assigned */ +#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */ extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced; extern struct ieee802154_mlme_ops mac802154_mlme_wpan; -- cgit v0.10.2 From d98ef50fd99585e43b77b5ac5943e4450031a18e Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Thu, 25 Apr 2013 00:56:55 +0000 Subject: be2net: Fixed memory leak Signed-off-by: Suresh Reddy Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ce5af9b..24c80d1 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2493,6 +2493,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) struct mgmt_controller_attrib *attribs; struct be_dma_mem attribs_cmd; + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + memset(&attribs_cmd, 0, sizeof(struct be_dma_mem)); attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs); attribs_cmd.va = pci_alloc_consistent(adapter->pdev, attribs_cmd.size, @@ -2500,12 +2503,10 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) if (!attribs_cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); - return -ENOMEM; + status = -ENOMEM; + goto err; } - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; - wrb = wrb_from_mbox(adapter); if (!wrb) { status = -EBUSY; @@ -2525,8 +2526,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) err: mutex_unlock(&adapter->mbox_lock); - pci_free_consistent(adapter->pdev, attribs_cmd.size, attribs_cmd.va, - attribs_cmd.dma); + if (attribs_cmd.va) + pci_free_consistent(adapter->pdev, attribs_cmd.size, + attribs_cmd.va, attribs_cmd.dma); return status; } @@ -2826,6 +2828,9 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) CMD_SUBSYSTEM_ETH)) return -EPERM; + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1); cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, @@ -2833,12 +2838,10 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); - return -ENOMEM; + status = -ENOMEM; + goto err; } - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; - wrb = wrb_from_mbox(adapter); if (!wrb) { status = -EBUSY; @@ -2869,7 +2872,8 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) } err: mutex_unlock(&adapter->mbox_lock); - pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); + if (cmd.va) + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); return status; } @@ -3001,16 +3005,18 @@ int be_cmd_get_func_config(struct be_adapter *adapter) int status; struct be_dma_mem cmd; + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_resp_get_func_config); cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma); if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); - return -ENOMEM; + status = -ENOMEM; + goto err; } - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; wrb = wrb_from_mbox(adapter); if (!wrb) { @@ -3050,8 +3056,8 @@ int be_cmd_get_func_config(struct be_adapter *adapter) } err: mutex_unlock(&adapter->mbox_lock); - pci_free_consistent(adapter->pdev, cmd.size, - cmd.va, cmd.dma); + if (cmd.va) + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); return status; } -- cgit v0.10.2 From b424332d0a812799b83ab6e1d3c8c32a3c5ecfb5 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Thu, 25 Apr 2013 00:56:56 +0000 Subject: be2net: Fix to show wol disabled/enabled state correctly. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 76b302f..1b7233c 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -680,7 +680,8 @@ be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (be_is_wol_supported(adapter)) { wol->supported |= WAKE_MAGIC; - wol->wolopts |= WAKE_MAGIC; + if (adapter->wol) + wol->wolopts |= WAKE_MAGIC; } else wol->wolopts = 0; memset(&wol->sopass, 0, sizeof(wol->sopass)); -- cgit v0.10.2 From e5195c1f31f399289347e043d6abf3ffa80f0005 Mon Sep 17 00:00:00 2001 From: Stefan Bader Date: Fri, 26 Apr 2013 13:49:32 +0000 Subject: r8169: fix 8168evl frame padding. Signed-off-by: Stefan Bader Acked-by: Francois Romieu Cc: hayeswang Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 4ecbe64..15ba8c4 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5787,6 +5787,14 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, goto err_stop_0; } + /* 8168evl does not automatically pad to minimum length. */ + if (unlikely(tp->mac_version == RTL_GIGA_MAC_VER_34 && + skb->len < ETH_ZLEN)) { + if (skb_padto(skb, ETH_ZLEN)) + goto err_update_stats; + skb_put(skb, ETH_ZLEN - skb->len); + } + if (unlikely(le32_to_cpu(txd->opts1) & DescOwn)) goto err_stop_0; @@ -5858,6 +5866,7 @@ err_dma_1: rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); err_dma_0: dev_kfree_skb(skb); +err_update_stats: dev->stats.tx_dropped++; return NETDEV_TX_OK; -- cgit v0.10.2 From add05ad4e9f5c4efee9b98535db5efa32b0d0492 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 29 Apr 2013 11:42:12 +0000 Subject: unix/dgram: peek beyond 0-sized skbs "77c1090 net: fix infinite loop in __skb_recv_datagram()" (v3.8) introduced a regression: After that commit, recv can no longer peek beyond a 0-sized skb in the queue. __skb_recv_datagram() instead stops at the first skb with len == 0 and results in the system call failing with -EFAULT via skb_copy_datagram_iovec(). When peeking at an offset with 0-sized skb(s), each one of those is received only once, in sequence. The offset starts moving forward again after receiving datagrams with len > 0. Signed-off-by: Benjamin Poirier Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/datagram.c b/net/core/datagram.c index 368f9c3..99c4f52 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -187,7 +187,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, skb_queue_walk(queue, skb) { *peeked = skb->peeked; if (flags & MSG_PEEK) { - if (*off >= skb->len && skb->len) { + if (*off >= skb->len && (skb->len || *off || + skb->peeked)) { *off -= skb->len; continue; } -- cgit v0.10.2 From 39cc86130bc045d87f525ce7742da308ff757cec Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 29 Apr 2013 11:42:13 +0000 Subject: unix/dgram: fix peeking with an offset larger than data in queue Currently, peeking on a unix datagram socket with an offset larger than len of the data in the sk receive queue returns immediately with bogus data. That's because *off is not reset between each skb_queue_walk(). This patch fixes this so that the behavior is the same as peeking with no offset on an empty queue: the caller blocks. Signed-off-by: Benjamin Poirier Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/datagram.c b/net/core/datagram.c index 99c4f52..b5d48ac 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -78,9 +78,10 @@ static int receiver_wake_function(wait_queue_t *wait, unsigned int mode, int syn return autoremove_wake_function(wait, mode, sync, key); } /* - * Wait for a packet.. + * Wait for the last received packet to be different from skb */ -static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) +static int wait_for_more_packets(struct sock *sk, int *err, long *timeo_p, + const struct sk_buff *skb) { int error; DEFINE_WAIT_FUNC(wait, receiver_wake_function); @@ -92,7 +93,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) if (error) goto out_err; - if (!skb_queue_empty(&sk->sk_receive_queue)) + if (sk->sk_receive_queue.prev != skb) goto out; /* Socket shut down? */ @@ -131,9 +132,9 @@ out_noerr: * __skb_recv_datagram - Receive a datagram skbuff * @sk: socket * @flags: MSG_ flags + * @peeked: returns non-zero if this packet has been seen before * @off: an offset in bytes to peek skb from. Returns an offset * within an skb where data actually starts - * @peeked: returns non-zero if this packet has been seen before * @err: error code returned * * Get a datagram skbuff, understands the peeking, nonblocking wakeups @@ -161,7 +162,7 @@ out_noerr: struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, int *peeked, int *off, int *err) { - struct sk_buff *skb; + struct sk_buff *skb, *last; long timeo; /* * Caller is allowed not to check sk->sk_err before skb_recv_datagram() @@ -182,14 +183,17 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, */ unsigned long cpu_flags; struct sk_buff_head *queue = &sk->sk_receive_queue; + int _off = *off; + last = (struct sk_buff *)queue; spin_lock_irqsave(&queue->lock, cpu_flags); skb_queue_walk(queue, skb) { + last = skb; *peeked = skb->peeked; if (flags & MSG_PEEK) { - if (*off >= skb->len && (skb->len || *off || + if (_off >= skb->len && (skb->len || _off || skb->peeked)) { - *off -= skb->len; + _off -= skb->len; continue; } skb->peeked = 1; @@ -198,6 +202,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, __skb_unlink(skb, queue); spin_unlock_irqrestore(&queue->lock, cpu_flags); + *off = _off; return skb; } spin_unlock_irqrestore(&queue->lock, cpu_flags); @@ -207,7 +212,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, if (!timeo) goto no_packet; - } while (!wait_for_packet(sk, err, &timeo)); + } while (!wait_for_more_packets(sk, err, &timeo, last)); return NULL; -- cgit v0.10.2 From 79f632c71bea0d0864d84d6a4ce78da5a9430f5b Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 29 Apr 2013 11:42:14 +0000 Subject: unix/stream: fix peeking with an offset larger than data in queue Currently, peeking on a unix stream socket with an offset larger than len of the data in the sk receive queue returns immediately with bogus data. This patch fixes this so that the behavior is the same as peeking with no offset on an empty queue: the caller blocks. Signed-off-by: Benjamin Poirier Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2db702d..1a02af0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1859,10 +1859,10 @@ out: } /* - * Sleep until data has arrive. But check for races.. + * Sleep until more data has arrived. But check for races.. */ - -static long unix_stream_data_wait(struct sock *sk, long timeo) +static long unix_stream_data_wait(struct sock *sk, long timeo, + struct sk_buff *last) { DEFINE_WAIT(wait); @@ -1871,7 +1871,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo) for (;;) { prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - if (!skb_queue_empty(&sk->sk_receive_queue) || + if (skb_peek_tail(&sk->sk_receive_queue) != last || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) || signal_pending(current) || @@ -1890,8 +1890,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo) return timeo; } - - static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) @@ -1936,14 +1934,12 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } - skip = sk_peek_offset(sk, flags); - do { int chunk; - struct sk_buff *skb; + struct sk_buff *skb, *last; unix_state_lock(sk); - skb = skb_peek(&sk->sk_receive_queue); + last = skb = skb_peek(&sk->sk_receive_queue); again: if (skb == NULL) { unix_sk(sk)->recursion_level = 0; @@ -1966,7 +1962,7 @@ again: break; mutex_unlock(&u->readlock); - timeo = unix_stream_data_wait(sk, timeo); + timeo = unix_stream_data_wait(sk, timeo, last); if (signal_pending(current) || mutex_lock_interruptible(&u->readlock)) { @@ -1980,10 +1976,13 @@ again: break; } - if (skip >= skb->len) { + skip = sk_peek_offset(sk, flags); + while (skip >= skb->len) { skip -= skb->len; + last = skb; skb = skb_peek_next(skb, &sk->sk_receive_queue); - goto again; + if (!skb) + goto again; } unix_state_unlock(sk); -- cgit v0.10.2