From 183f732c3f3f307d5673e17b69de6894e1dd2918 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 6 Dec 2010 15:56:17 +0200 Subject: [PATCH 01/42] Bluetooth: Fix initial RFCOMM DLC security level Due to commit 63ce0900 connections initiated through TTYs created with "rfcomm bind ..." would have security level BT_SECURITY_SDP instead of BT_SECURITY_LOW. This would cause instant connection failure between any two SSP capable devices due to the L2CAP connect request to RFCOMM being sent before authentication has been performed. This patch fixes the regression by always initializing the DLC security level to BT_SECURITY_LOW. Signed-off-by: Johan Hedberg Acked-by: Luiz Augusto von Dentz Signed-off-by: Gustavo F. Padovan --- net/bluetooth/rfcomm/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index fa642aa652bd..432a9a633e8d 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -311,6 +311,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d) d->state = BT_OPEN; d->flags = 0; d->mscex = 0; + d->sec_level = BT_SECURITY_LOW; d->mtu = RFCOMM_DEFAULT_MTU; d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV; From d9319560b86839506c2011346b1f2e61438a3c73 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 7 Dec 2010 14:03:38 +0800 Subject: [PATCH 02/42] Bluetooth: add NULL pointer check in HCI If we fail to find a hci device pointer in hci_uart, don't try to deref the NULL one we do have. Signed-off-by: Jun Nie Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/hci_ldisc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 720148294e64..3c6cabcb7d84 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -311,8 +311,10 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { hu->proto->close(hu); - hci_unregister_dev(hdev); - hci_free_dev(hdev); + if (hdev) { + hci_unregister_dev(hdev); + hci_free_dev(hdev); + } } } } From cbf68a668d0e41527572c762824a1b6a9225d33f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 30 Nov 2010 11:03:44 -0800 Subject: [PATCH 03/42] iwlagn: rename enhanced txpower fields Some fields we didn't previously use from the enhanced TX power structure will be needed in the next patch, so rename them to their correct names to be able to use them and change code reading them accordingly. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index a650baba0809..96510600b751 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -419,7 +419,8 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) * always check for valid entry before process * the information */ - if (!enhanced_txpower->common || enhanced_txpower->reserved) + if (!(enhanced_txpower->flags || enhanced_txpower->channel) || + enhanced_txpower->delta_20_in_40) continue; for (element = 0; element < eeprom_section_count; element++) { diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d9b590625ae4..310e34568a41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -127,21 +127,23 @@ struct iwl_eeprom_channel { * Enhanced regulatory tx power portion of eeprom image can be broken down * into individual structures; each one is 8 bytes in size and contain the * following information - * @common: (desc + channel) not used by driver, should _NOT_ be "zero" + * @flags: entry flags + * @channel: channel number * @chain_a_max_pwr: chain a max power in 1/2 dBm * @chain_b_max_pwr: chain b max power in 1/2 dBm * @chain_c_max_pwr: chain c max power in 1/2 dBm - * @reserved: not used, should be "zero" + * @delta_20_in_40: 20-in-40 deltas (hi/lo) * @mimo2_max_pwr: mimo2 max power in 1/2 dBm * @mimo3_max_pwr: mimo3 max power in 1/2 dBm * */ struct iwl_eeprom_enhanced_txpwr { - __le16 common; + u8 flags; + u8 channel; s8 chain_a_max; s8 chain_b_max; s8 chain_c_max; - s8 reserved; + u8 delta_20_in_40; s8 mimo2_max; s8 mimo3_max; } __packed; From 6942fec92d3d1b6918425730de31b4c6d0d5c196 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 9 Dec 2010 10:09:14 -0800 Subject: [PATCH 04/42] iwlagn: implement layout-agnostic EEPROM reading From: Johannes Berg The current EEPROM reading code has some layout assumptions that now turned out to be false with some newer versions of the EEPROM. Luckily, we can avoid all such assumptions by using data in the EEPROM itself, so implement using that. However, for risk mitigation purposes, keep the old reading code for current hardware for now. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 + drivers/net/wireless/iwlwifi/iwl-6000.c | 12 +++ drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c | 85 ++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 6 ++ drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-eeprom.h | 15 ++++ 6 files changed, 120 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index db540910b110..0e027f787fbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -315,6 +315,7 @@ struct iwl_cfg iwl100_bgn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, .ht_params = &iwl1000_ht_params, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl100_bg_cfg = { @@ -330,6 +331,7 @@ struct iwl_cfg iwl100_bg_cfg = { .ops = &iwl1000_ops, .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, + .use_new_eeprom_reading = true, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 11e6532fc573..0ceeaac85eda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -561,6 +561,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .ht_params = &iwl6000_ht_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2a_2abg_cfg = { @@ -578,6 +579,7 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .base_params = &iwl6000_base_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2a_2bg_cfg = { @@ -595,6 +597,7 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .base_params = &iwl6000_base_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2agn_cfg = { @@ -616,6 +619,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2abg_cfg = { @@ -636,6 +640,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2bgn_cfg = { @@ -657,6 +662,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2bg_cfg = { @@ -677,6 +683,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_bgn_cfg = { @@ -698,6 +705,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_bg_cfg = { @@ -718,6 +726,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; /* @@ -804,6 +813,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -857,6 +867,7 @@ struct iwl_cfg iwl130_bgn_cfg = { .need_dc_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl130_bg_cfg = { @@ -876,6 +887,7 @@ struct iwl_cfg iwl130_bg_cfg = { .need_dc_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 96510600b751..9eeeda18748d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -392,7 +392,7 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, /** * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info */ -void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +static void iwlcore_eeprom_enhanced_txpower_old(struct iwl_priv *priv) { int eeprom_section_count = 0; int section, element; @@ -453,3 +453,86 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) } } } + +static void +iwlcore_eeprom_enh_txp_read_element(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *txp, + s8 max_txpower_avg) +{ + int ch_idx; + bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ; + enum ieee80211_band band; + + band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ? + IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; + + for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) { + struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx]; + + /* update matching channel or from common data only */ + if (txp->channel != 0 && ch_info->channel != txp->channel) + continue; + + /* update matching band only */ + if (band != ch_info->band) + continue; + + if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) { + ch_info->max_power_avg = max_txpower_avg; + ch_info->curr_txpow = max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + + if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg) + ch_info->ht40_max_power_avg = max_txpower_avg; + } +} + +#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT) +#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr) +#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE) + +static void iwlcore_eeprom_enhanced_txpower_new(struct iwl_priv *priv) +{ + struct iwl_eeprom_enhanced_txpwr *txp_array, *txp; + int idx, entries; + __le16 *txp_len; + s8 max_txp_avg, max_txp_avg_halfdbm; + + BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8); + + /* the length is in 16-bit words, but we want entries */ + txp_len = (__le16 *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS); + entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN; + + txp_array = (void *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_OFFS); + for (idx = 0; idx < entries; idx++) { + txp = &txp_array[idx]; + + /* skip invalid entries */ + if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID)) + continue; + + max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx, + &max_txp_avg_halfdbm); + + /* + * Update the user limit values values to the highest + * power supported by any channel + */ + if (max_txp_avg > priv->tx_power_user_lmt) + priv->tx_power_user_lmt = max_txp_avg; + if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm) + priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm; + + iwlcore_eeprom_enh_txp_read_element(priv, txp, max_txp_avg); + } +} + +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +{ + if (priv->cfg->use_new_eeprom_reading) + iwlcore_eeprom_enhanced_txpower_new(priv); + else + iwlcore_eeprom_enhanced_txpower_old(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index b555edd53354..554afb7d9670 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -569,6 +569,12 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) case INDIRECT_REGULATORY: offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY); break; + case INDIRECT_TXP_LIMIT: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT); + break; + case INDIRECT_TXP_LIMIT_SIZE: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE); + break; case INDIRECT_CALIBRATION: offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION); break; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 64527def059f..954ecc2c34c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -390,6 +390,7 @@ struct iwl_cfg { const bool need_temp_offset_calib; /* if used set to true */ u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; + const bool use_new_eeprom_reading; /* temporary, remove later */ }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 310e34568a41..e3a279d2d0b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -120,6 +120,17 @@ struct iwl_eeprom_channel { s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ } __packed; +enum iwl_eeprom_enhanced_txpwr_flags { + IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0), + IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1), + IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2), + IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3), + IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4), + IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5), + IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6), + IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7), +}; + /** * iwl_eeprom_enhanced_txpwr structure * This structure presents the enhanced regulatory tx power limit layout @@ -188,6 +199,8 @@ struct iwl_eeprom_enhanced_txpwr { #define EEPROM_LINK_CALIBRATION (2*0x67) #define EEPROM_LINK_PROCESS_ADJST (2*0x68) #define EEPROM_LINK_OTHERS (2*0x69) +#define EEPROM_LINK_TXP_LIMIT (2*0x6a) +#define EEPROM_LINK_TXP_LIMIT_SIZE (2*0x6b) /* agn regulatory - indirect access */ #define EEPROM_REG_BAND_1_CHANNELS ((0x08)\ @@ -391,6 +404,8 @@ struct iwl_eeprom_calib_info { #define INDIRECT_CALIBRATION 0x00040000 #define INDIRECT_PROCESS_ADJST 0x00050000 #define INDIRECT_OTHERS 0x00060000 +#define INDIRECT_TXP_LIMIT 0x00070000 +#define INDIRECT_TXP_LIMIT_SIZE 0x00080000 #define INDIRECT_ADDRESS 0x00100000 /* General */ From 4a55d5852adbe66722fb1636c82c7864cd5be441 Mon Sep 17 00:00:00 2001 From: Sven Neumann Date: Thu, 9 Dec 2010 09:38:36 +0100 Subject: [PATCH 05/42] libertas: fix potential NULL-pointer dereference The code wants to check if there's a channel and it is not disabled, but it used to check if channel is not NULL and accessed the channel struct if this check failed. Signed-off-by: Sven Neumann Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 373930afc26b..113f4f204657 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -619,7 +619,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, print_ssid(ssid_buf, ssid, ssid_len), LBS_SCAN_RSSI_TO_MBM(rssi)/100); - if (channel || + if (channel && !(channel->flags & IEEE80211_CHAN_DISABLED)) cfg80211_inform_bss(wiphy, channel, bssid, le64_to_cpu(*(__le64 *)tsfdesc), From c926d006c1514cfb3572893f41f2324e96823661 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 9 Dec 2010 10:43:13 -0800 Subject: [PATCH 06/42] mac80211: Fix NULL-pointer deference on ibss merge when not ready dev_open will eventually call ieee80211_ibss_join which sets up the skb used for beacons/probe-responses however it is possible to receive beacons that attempt to merge before this occurs causing a null pointer dereference. Check ssid_len as that is the last thing set in ieee80211_ibss_join. This occurs quite easily in the presence of adhoc nodes with hidden SSID's revised previous patch to check further up based on irc feedback Signed-off-by: Tim Harvey Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 239c4836a946..077a93dd1671 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -780,6 +780,9 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, mutex_lock(&sdata->u.ibss.mtx); + if (!sdata->u.ibss.ssid_len) + goto mgmt_out; /* not ready to merge yet */ + switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_PROBE_REQ: ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len); @@ -797,6 +800,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, break; } + mgmt_out: mutex_unlock(&sdata->u.ibss.mtx); } From 16cad7fba037b34ca32cc0adac65bc089d969fb8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 11 Dec 2010 12:19:48 +0100 Subject: [PATCH 07/42] p54usb: add 5 more USBIDs This patch adds five more USBIDs to the table. Source: http://www.linuxant.com/pipermail/driverloader/2005q3/002307.html http://wireless.kernel.org/en/users/Drivers/p54/devices (by M. Davis) Cc: Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index d5bc21e5a02c..610aafe207a3 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -43,6 +43,7 @@ MODULE_FIRMWARE("isl3887usb"); static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ + {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */ {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */ @@ -56,9 +57,12 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ + {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */ {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ + {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */ {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */ + {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ @@ -94,6 +98,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ + {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */ {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */ From 8808f64171deec62346888e156e3adb636e2a31a Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 13 Dec 2010 11:43:51 -0200 Subject: [PATCH 08/42] mac80211: avoid calling ieee80211_work_work unconditionally On suspend, there might be usb wireless drivers which wrongly trigger the warning in ieee80211_work_work. If an usb driver doesn't have a suspend hook, the usb stack will disconnect the device. On disconnect, a mac80211 driver calls ieee80211_unregister_hw, which calls dev_close, which calls ieee80211_stop, and in the end calls ieee80211_work_purge-> ieee80211_work_work. The problem is that this call to ieee80211_work_purge comes after mac80211 is suspended, triggering the warning even when we don't have work queued in work_list (the expected case when already suspended), because it always calls ieee80211_work_work. So, just call ieee80211_work_work in ieee80211_work_purge if we really have to abort work. This addresses the warning reported at https://bugzilla.kernel.org/show_bug.cgi?id=24402 Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- net/mac80211/work.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index ae344d1ba056..146097cb43a7 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -1051,11 +1051,13 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_work *wk; + bool cleanup = false; mutex_lock(&local->mtx); list_for_each_entry(wk, &local->work_list, list) { if (wk->sdata != sdata) continue; + cleanup = true; wk->type = IEEE80211_WORK_ABORT; wk->started = true; wk->timeout = jiffies; @@ -1063,7 +1065,8 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->mtx); /* run cleanups etc. */ - ieee80211_work_work(&local->work_work); + if (cleanup) + ieee80211_work_work(&local->work_work); mutex_lock(&local->mtx); list_for_each_entry(wk, &local->work_list, list) { From 56e6417b49132d4f56e9f2241d31942b90b46315 Mon Sep 17 00:00:00 2001 From: Eduardo Costa Date: Tue, 14 Dec 2010 14:37:59 -0600 Subject: [PATCH 09/42] p54usb: New USB ID for Gemtek WUBI-100GW This USB ID is for the WUBI-100GW 802.11g Wireless LAN USB Device that uses p54usb. Signed-off-by: Larry Finger Signed-off-by: Eduardo Costa Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 610aafe207a3..2325e56a9b0b 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -61,6 +61,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */ + {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */ {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */ {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ From af3e5bd5f650163c2e12297f572910a1af1b8236 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Fri, 10 Dec 2010 18:54:11 +0000 Subject: [PATCH 10/42] bonding: Fix slave selection bug. The returned slave is incorrect, if the net device under check is not charged yet by the master. Signed-off-by: Hillf Danton Signed-off-by: David S. Miller --- drivers/net/bonding/bonding.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index c2f081352a03..4feeb2d650a4 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -269,11 +269,11 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct n bond_for_each_slave(bond, slave, i) { if (slave->dev == slave_dev) { - break; + return slave; } } - return slave; + return 0; } static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) From d3052b557a1c94c21f50465702fa886753ce6b43 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Sat, 11 Dec 2010 15:20:11 +0000 Subject: [PATCH 11/42] ipv6: delete expired route in ip6_pmtu_deliver The first big packets sent to a "low-MTU" client correctly triggers the creation of a temporary route containing the reduced MTU. But after the temporary route has expired, new ICMP6 "packet too big" will be sent, rt6_pmtu_discovery will find the previous EXPIRED route check that its mtu isn't bigger then in icmp packet and do nothing before the temporary route will not deleted by gc. I make the simple experiment: while :; do time ( dd if=/dev/zero bs=10K count=1 | ssh hostname dd of=/dev/null ) || break; done The "time" reports real 0m0.197s if a temporary route isn't expired, but it reports real 0m52.837s (!!!!) immediately after a temporare route has expired. Signed-off-by: Andrey Vagin Signed-off-by: David S. Miller --- net/ipv6/route.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 96455ffb76fb..7659d6f16e6b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1565,11 +1565,16 @@ static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, { struct rt6_info *rt, *nrt; int allfrag = 0; - +again: rt = rt6_lookup(net, daddr, saddr, ifindex, 0); if (rt == NULL) return; + if (rt6_check_expired(rt)) { + ip6_del_rt(rt); + goto again; + } + if (pmtu >= dst_mtu(&rt->dst)) goto out; From 42dccd1f757d674a6604077a61d1577d1578c755 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Mon, 13 Dec 2010 02:27:24 +0000 Subject: [PATCH 12/42] axnet_cs: move id (0x1bf, 0x2328) to axnet_cs axnet_cs: Accton EN2328 or compatible (id: 0x01bf, 0x2328) uses Asix chip. So it works better with axnet_cs instead of pcnet_cs. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/axnet_cs.c | 1 + drivers/net/pcmcia/pcnet_cs.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 8a4d19e5de06..f1047dd8a526 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -690,6 +690,7 @@ static void block_output(struct net_device *dev, int count, static struct pcmcia_device_id axnet_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081), PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301), + PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309), diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index d05c44692f08..2c158910f7ea 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1493,7 +1493,6 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530), PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab), PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110), - PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328), PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041), PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300), From 8387451e558853f7b513790c0070e3b6f0c135aa Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 13 Dec 2010 08:19:28 +0000 Subject: [PATCH 13/42] bonding/vlan: Remove redundant VLAN tag insertion logic A bond may have a mixture of slave devices with and without hardware VLAN tag insertion capability. Therefore it always claims this capability and performs software VLAN tag insertion if the slave does not. Since commit 7b9c60903714bf0a19d746b228864bad3497284e, this has also been done by dev_hard_start_xmit(). The result is that VLAN- tagged skbs are now double-tagged when transmitted through slave devices without hardware VLAN tag insertion! Remove the now-redundant logic from bond_dev_queue_xmit(). Signed-off-by: Ben Hutchings Signed-off-by: Jay Vosburgh Reviewed-by: Jesse Gross Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d0ea760ce419..ef370c923341 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -418,36 +418,11 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) * @bond: bond device that got this skb for tx. * @skb: hw accel VLAN tagged skb to transmit * @slave_dev: slave that is supposed to xmit this skbuff - * - * When the bond gets an skb to transmit that is - * already hardware accelerated VLAN tagged, and it - * needs to relay this skb to a slave that is not - * hw accel capable, the skb needs to be "unaccelerated", - * i.e. strip the hwaccel tag and re-insert it as part - * of the payload. */ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev) { - unsigned short uninitialized_var(vlan_id); - - /* Test vlan_list not vlgrp to catch and handle 802.1p tags */ - if (!list_empty(&bond->vlan_list) && - !(slave_dev->features & NETIF_F_HW_VLAN_TX) && - vlan_get_tag(skb, &vlan_id) == 0) { - skb->dev = slave_dev; - skb = vlan_put_tag(skb, vlan_id); - if (!skb) { - /* vlan_put_tag() frees the skb in case of error, - * so return success here so the calling functions - * won't attempt to free is again. - */ - return 0; - } - } else { - skb->dev = slave_dev; - } - + skb->dev = slave_dev; skb->priority = 1; #ifdef CONFIG_NET_POLL_CONTROLLER if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) { From ffa95ed50f9fb2d8faaa6bd73086a7056ea46a06 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 13 Dec 2010 08:19:56 +0000 Subject: [PATCH 14/42] bonding: Change active slave quietly when bond is down bond_change_active_slave() may be called when a slave is added, even if the bond has not been brought up yet. It may then attempt to send packets, and further it may use mcast_work which is uninitialised before the bond is brought up. Add the necessary checks for netif_running(bond->dev). Signed-off-by: Ben Hutchings Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ef370c923341..3b16c34ed86e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1178,11 +1178,13 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_do_fail_over_mac(bond, new_active, old_active); - bond->send_grat_arp = bond->params.num_grat_arp; - bond_send_gratuitous_arp(bond); + if (netif_running(bond->dev)) { + bond->send_grat_arp = bond->params.num_grat_arp; + bond_send_gratuitous_arp(bond); - bond->send_unsol_na = bond->params.num_unsol_na; - bond_send_unsolicited_na(bond); + bond->send_unsol_na = bond->params.num_unsol_na; + bond_send_unsolicited_na(bond); + } write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); @@ -1196,8 +1198,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) /* resend IGMP joins since active slave has changed or * all were sent on curr_active_slave */ - if ((USES_PRIMARY(bond->params.mode) && new_active) || - bond->params.mode == BOND_MODE_ROUNDROBIN) { + if (((USES_PRIMARY(bond->params.mode) && new_active) || + bond->params.mode == BOND_MODE_ROUNDROBIN) && + netif_running(bond->dev)) { bond->igmp_retrans = bond->params.resend_igmp; queue_delayed_work(bond->wq, &bond->mcast_work, 0); } From f88a4a9b65a6f3422b81be995535d0e69df11bb8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 13 Dec 2010 08:20:24 +0000 Subject: [PATCH 15/42] bonding/vlan: Fix mangled NAs on slaves without VLAN tag insertion bond_na_send() attempts to insert a VLAN tag in between building and sending packets of the respective formats. If the slave does not implement hardware VLAN tag insertion then vlan_put_tag() will mangle the network-layer header because the Ethernet header is not present at this point (unlike in bond_arp_send()). Fix this by adding the tag out-of-line and relying on dev_hard_start_xmit() to insert it inline if necessary. Signed-off-by: Ben Hutchings Signed-off-by: Jay Vosburgh Reviewed-by: Jesse Gross Signed-off-by: David S. Miller --- drivers/net/bonding/bond_ipv6.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c index 121b073a6c3f..84fbd4ebd778 100644 --- a/drivers/net/bonding/bond_ipv6.c +++ b/drivers/net/bonding/bond_ipv6.c @@ -88,7 +88,12 @@ static void bond_na_send(struct net_device *slave_dev, } if (vlan_id) { - skb = vlan_put_tag(skb, vlan_id); + /* The Ethernet header is not present yet, so it is + * too early to insert a VLAN tag. Force use of an + * out-of-line tag here and let dev_hard_start_xmit() + * insert it if the slave hardware can't. + */ + skb = __vlan_hwaccel_put_tag(skb, vlan_id); if (!skb) { pr_err("failed to insert VLAN tag\n"); return; From 2984961c388381c1830f95e1c2dc2137301b1009 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Tue, 14 Dec 2010 05:43:19 +0000 Subject: [PATCH 16/42] be2net: use mutex instead of spin lock for mbox_lock Since the mbox polling uses the schedule_timeout, the mbox_lock should be a mutex and not a spin lock. The commit f25b03a replaced udelay() with schedule_timeout() but didn't change mbox_lock to semaphore or mutex. Signed-off-by: Ivan Vecera Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 2 +- drivers/net/benet/be_cmds.c | 75 ++++++++++++++++++++++--------------- drivers/net/benet/be_main.c | 2 +- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 4594a28b1f66..d64313b7090e 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -234,7 +234,7 @@ struct be_adapter { u8 __iomem *db; /* Door Bell */ u8 __iomem *pcicfg; /* PCI config space */ - spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ + struct mutex mbox_lock; /* For serializing mbox cmds to BE card */ struct be_dma_mem mbox_mem; /* Mbox mem is adjusted to align to 16 bytes. The allocated addr * is stored for freeing purpose */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index e4465d222a7d..1c8c79c9d214 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -462,7 +462,8 @@ int be_cmd_fw_init(struct be_adapter *adapter) u8 *wrb; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = (u8 *)wrb_from_mbox(adapter); *wrb++ = 0xFF; @@ -476,7 +477,7 @@ int be_cmd_fw_init(struct be_adapter *adapter) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -491,7 +492,8 @@ int be_cmd_fw_clean(struct be_adapter *adapter) if (adapter->eeh_err) return -EIO; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = (u8 *)wrb_from_mbox(adapter); *wrb++ = 0xFF; @@ -505,7 +507,7 @@ int be_cmd_fw_clean(struct be_adapter *adapter) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } int be_cmd_eq_create(struct be_adapter *adapter, @@ -516,7 +518,8 @@ int be_cmd_eq_create(struct be_adapter *adapter, struct be_dma_mem *q_mem = &eq->dma_mem; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -546,7 +549,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, eq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -558,7 +561,8 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, struct be_cmd_req_mac_query *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -583,7 +587,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, memcpy(mac_addr, resp->mac.addr, ETH_ALEN); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -667,7 +671,8 @@ int be_cmd_cq_create(struct be_adapter *adapter, void *ctxt; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -701,7 +706,7 @@ int be_cmd_cq_create(struct be_adapter *adapter, cq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -724,7 +729,8 @@ int be_cmd_mccq_create(struct be_adapter *adapter, void *ctxt; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -754,7 +760,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, mccq->id = le16_to_cpu(resp->id); mccq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -769,7 +775,8 @@ int be_cmd_txq_create(struct be_adapter *adapter, void *ctxt; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -801,7 +808,7 @@ int be_cmd_txq_create(struct be_adapter *adapter, txq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -816,7 +823,8 @@ int be_cmd_rxq_create(struct be_adapter *adapter, struct be_dma_mem *q_mem = &rxq->dma_mem; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -843,7 +851,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter, *rss_id = resp->rss_id; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -862,7 +870,8 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, if (adapter->eeh_err) return -EIO; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -899,7 +908,7 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -915,7 +924,8 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, struct be_cmd_req_if_create *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -941,7 +951,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -955,7 +965,8 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) if (adapter->eeh_err) return -EIO; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -970,7 +981,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1060,7 +1071,8 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) struct be_cmd_req_get_fw_version *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1077,7 +1089,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1322,7 +1334,8 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, struct be_cmd_req_query_fw_cfg *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1341,7 +1354,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, *caps = le32_to_cpu(resp->function_caps); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1352,7 +1365,8 @@ int be_cmd_reset_function(struct be_adapter *adapter) struct be_cmd_req_hdr *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1365,7 +1379,7 @@ int be_cmd_reset_function(struct be_adapter *adapter) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1376,7 +1390,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) u32 myhash[10]; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1396,7 +1411,7 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 93354eee2cfd..fd251b59b7f9 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2677,7 +2677,7 @@ static int be_ctrl_init(struct be_adapter *adapter) } memset(mc_cmd_mem->va, 0, mc_cmd_mem->size); - spin_lock_init(&adapter->mbox_lock); + mutex_init(&adapter->mbox_lock); spin_lock_init(&adapter->mcc_lock); spin_lock_init(&adapter->mcc_cq_lock); From fcbdf09d9652c8919dcf47072e3ae7dcb4eb98ac Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Thu, 16 Dec 2010 14:26:56 -0800 Subject: [PATCH 17/42] net: fix nulls list corruptions in sk_prot_alloc Special care is taken inside sk_port_alloc to avoid overwriting skc_node/skc_nulls_node. We should also avoid overwriting skc_bind_node/skc_portaddr_node. The patch fixes the following crash: BUG: unable to handle kernel paging request at fffffffffffffff0 IP: [] udp4_lib_lookup2+0xad/0x370 [] __udp4_lib_lookup+0x282/0x360 [] __udp4_lib_rcv+0x31e/0x700 [] ? ip_local_deliver_finish+0x65/0x190 [] ? ip_local_deliver+0x88/0xa0 [] udp_rcv+0x15/0x20 [] ip_local_deliver_finish+0x65/0x190 [] ip_local_deliver+0x88/0xa0 [] ip_rcv_finish+0x32d/0x6f0 [] ? netif_receive_skb+0x99c/0x11c0 [] ip_rcv+0x2bb/0x350 [] netif_receive_skb+0x99c/0x11c0 Signed-off-by: Leonard Crestez Signed-off-by: Octavian Purdila Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 3 +++ net/core/sock.c | 47 ++++++++++++++++++++++++++++++++++------------ net/ipv4/udp.c | 1 + net/ipv4/udplite.c | 1 + net/ipv6/udp.c | 1 + net/ipv6/udplite.c | 1 + 6 files changed, 42 insertions(+), 12 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 659d968d95c5..7d3f7ce239b5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -754,6 +754,7 @@ struct proto { void (*unhash)(struct sock *sk); void (*rehash)(struct sock *sk); int (*get_port)(struct sock *sk, unsigned short snum); + void (*clear_sk)(struct sock *sk, int size); /* Keeping track of sockets in use */ #ifdef CONFIG_PROC_FS @@ -852,6 +853,8 @@ static inline void __sk_prot_rehash(struct sock *sk) sk->sk_prot->hash(sk); } +void sk_prot_clear_portaddr_nulls(struct sock *sk, int size); + /* About 10 seconds */ #define SOCK_DESTROY_TIME (10*HZ) diff --git a/net/core/sock.c b/net/core/sock.c index fb6080111461..e5af8d5d5b50 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1009,6 +1009,36 @@ static void sock_copy(struct sock *nsk, const struct sock *osk) #endif } +/* + * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes + * un-modified. Special care is taken when initializing object to zero. + */ +static inline void sk_prot_clear_nulls(struct sock *sk, int size) +{ + if (offsetof(struct sock, sk_node.next) != 0) + memset(sk, 0, offsetof(struct sock, sk_node.next)); + memset(&sk->sk_node.pprev, 0, + size - offsetof(struct sock, sk_node.pprev)); +} + +void sk_prot_clear_portaddr_nulls(struct sock *sk, int size) +{ + unsigned long nulls1, nulls2; + + nulls1 = offsetof(struct sock, __sk_common.skc_node.next); + nulls2 = offsetof(struct sock, __sk_common.skc_portaddr_node.next); + if (nulls1 > nulls2) + swap(nulls1, nulls2); + + if (nulls1 != 0) + memset((char *)sk, 0, nulls1); + memset((char *)sk + nulls1 + sizeof(void *), 0, + nulls2 - nulls1 - sizeof(void *)); + memset((char *)sk + nulls2 + sizeof(void *), 0, + size - nulls2 - sizeof(void *)); +} +EXPORT_SYMBOL(sk_prot_clear_portaddr_nulls); + static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, int family) { @@ -1021,19 +1051,12 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, if (!sk) return sk; if (priority & __GFP_ZERO) { - /* - * caches using SLAB_DESTROY_BY_RCU should let - * sk_node.next un-modified. Special care is taken - * when initializing object to zero. - */ - if (offsetof(struct sock, sk_node.next) != 0) - memset(sk, 0, offsetof(struct sock, sk_node.next)); - memset(&sk->sk_node.pprev, 0, - prot->obj_size - offsetof(struct sock, - sk_node.pprev)); + if (prot->clear_sk) + prot->clear_sk(sk, prot->obj_size); + else + sk_prot_clear_nulls(sk, prot->obj_size); } - } - else + } else sk = kmalloc(prot->obj_size, priority); if (sk != NULL) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5e0a3a582a59..2d3ded4d0786 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1899,6 +1899,7 @@ struct proto udp_prot = { .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, #endif + .clear_sk = sk_prot_clear_portaddr_nulls, }; EXPORT_SYMBOL(udp_prot); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index ab76aa928fa9..aee9963f7f5a 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -57,6 +57,7 @@ struct proto udplite_prot = { .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, #endif + .clear_sk = sk_prot_clear_portaddr_nulls, }; EXPORT_SYMBOL(udplite_prot); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 91def93bec85..cd6cb7c3e563 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1477,6 +1477,7 @@ struct proto udpv6_prot = { .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, #endif + .clear_sk = sk_prot_clear_portaddr_nulls, }; static struct inet_protosw udpv6_protosw = { diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 5f48fadc27f7..986c4de5292e 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -55,6 +55,7 @@ struct proto udplitev6_prot = { .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, #endif + .clear_sk = sk_prot_clear_portaddr_nulls, }; static struct inet_protosw udplite6_protosw = { From 76d661586c8131453ba75a2e027c1f21511a893a Mon Sep 17 00:00:00 2001 From: David Stevens Date: Tue, 14 Dec 2010 08:42:16 +0000 Subject: [PATCH 18/42] bridge: fix IPv6 queries for bridge multicast snooping This patch fixes a missing ntohs() for bridge IPv6 multicast snooping. Signed-off-by: David L Stevens Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/bridge/br_multicast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index eb5b256ffc88..f19e347f56f6 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -437,7 +437,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, ip6h = ipv6_hdr(skb); *(__force __be32 *)ip6h = htonl(0x60000000); - ip6h->payload_len = 8 + sizeof(*mldq); + ip6h->payload_len = htons(8 + sizeof(*mldq)); ip6h->nexthdr = IPPROTO_HOPOPTS; ip6h->hop_limit = 1; ipv6_addr_set(&ip6h->saddr, 0, 0, 0, 0); From 0b7967503dc97864f283a3a06fbe23e041876138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 14 Dec 2010 12:35:13 +0000 Subject: [PATCH 19/42] net/veth: Fix packet checksumming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't change ip_summed from CHECKSUM_PARTIAL to CHECKSUM_NONE or CHECKSUM_UNNECESSARY because checksum in packet's headers is not valid and will cause invalid checksum when frame is forwarded. Signed-off-by: Michał Mirosław Signed-off-by: David S. Miller --- drivers/net/veth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 0bbc0c323135..cc83fa71c3ff 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -166,7 +166,9 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) if (!(rcv->flags & IFF_UP)) goto tx_drop; - if (dev->features & NETIF_F_NO_CSUM) + /* don't change ip_summed == CHECKSUM_PARTIAL, as that + will cause bad checksum on forwarded packets */ + if (skb->ip_summed == CHECKSUM_NONE) skb->ip_summed = rcv_priv->ip_summed; length = skb->len + ETH_HLEN; From 7d743b7e952261f4d9ee091100b6403f3ce8a2af Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 14 Dec 2010 16:10:41 +0000 Subject: [PATCH 20/42] sctp: fix the return value of getting the sctp partial delivery point Get the sctp partial delivery point using SCTP_PARTIAL_DELIVERY_POINT socket option should return 0 if success, not -ENOTSUPP. Signed-off-by: Wei Yongjun Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0b9ee34ad35c..fff0926b1111 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5053,7 +5053,7 @@ static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len, if (copy_to_user(optval, &val, len)) return -EFAULT; - return -ENOTSUPP; + return 0; } /* From 29ba5fed1bbd09c2cba890798c8f9eaab251401d Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 16 Dec 2010 11:28:12 +0000 Subject: [PATCH 21/42] ipv6: don't flush routes when setting loopback down When loopback device is being brought down, then keep the route table entries because they are special. The entries in the local table for linklocal routes and ::1 address should not be purged. This is a sub optimal solution to the problem and should be replaced by a better fix in future. Signed-off-by: Stephen Hemminger Acked-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 93b7a933a775..848b35591042 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2669,7 +2669,9 @@ static int addrconf_ifdown(struct net_device *dev, int how) ASSERT_RTNL(); - rt6_ifdown(net, dev); + /* Flush routes if device is being removed or it is not loopback */ + if (how || !(dev->flags & IFF_LOOPBACK)) + rt6_ifdown(net, dev); neigh_ifdown(&nd_tbl, dev); idev = __in6_dev_get(dev); From 46814e08d80f87449b5adb3d549a3cae6f9f8148 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 17 Dec 2010 10:16:23 -0800 Subject: [PATCH 22/42] tehuti: Firmware filename is tehuti/bdx.bin My conversion of tehuti to use request_firmware() was confused about the filename of the firmware blob. Change the driver to match the blob. Signed-off-by: Ben Hutchings Signed-off-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/tehuti.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8b3dc1eb4015..296000bf5a25 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -324,7 +324,7 @@ static int bdx_fw_load(struct bdx_priv *priv) ENTER; master = READ_REG(priv, regINIT_SEMAPHORE); if (!READ_REG(priv, regINIT_STATUS) && master) { - rc = request_firmware(&fw, "tehuti/firmware.bin", &priv->pdev->dev); + rc = request_firmware(&fw, "tehuti/bdx.bin", &priv->pdev->dev); if (rc) goto out; bdx_tx_push_desc_safe(priv, (char *)fw->data, fw->size); @@ -2510,4 +2510,4 @@ module_exit(bdx_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(BDX_DRV_DESC); -MODULE_FIRMWARE("tehuti/firmware.bin"); +MODULE_FIRMWARE("tehuti/bdx.bin"); From f4680d3db71f13d2764340a9880745bf54f2469d Mon Sep 17 00:00:00 2001 From: Arnaud Ebalard Date: Wed, 15 Dec 2010 12:16:30 +0000 Subject: [PATCH 23/42] asix: add USB ID for Logitec LAN-GTJ U2A Logitec LAN-GTJ U2A (http://www.pro.logitec.co.jp/pro/g/gLAN-GTJU2A/) USB 2.0 10/10/1000 Ethernet adapter is based on ASIX AX88178 chipset. This patch adds missing USB ID for the device. Signed-off-by: Arnaud Ebalard Signed-off-by: David S. Miller --- drivers/net/usb/asix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index aea4645be7f6..6140b56cce53 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -1507,6 +1507,10 @@ static const struct usb_device_id products [] = { // ASIX AX88178 10/100/1000 USB_DEVICE (0x0b95, 0x1780), .driver_info = (unsigned long) &ax88178_info, +}, { + // Logitec LAN-GTJ/U2A + USB_DEVICE (0x0789, 0x0160), + .driver_info = (unsigned long) &ax88178_info, }, { // Linksys USB200M Rev 2 USB_DEVICE (0x13b1, 0x0018), From 4b8fe66300acb2fba8b16d62606e0d30204022fc Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Fri, 17 Dec 2010 12:03:14 -0800 Subject: [PATCH 24/42] netlink: fix gcc -Wconversion compilation warning $ cat << EOF | gcc -Wconversion -xc -S -o/dev/null - unsigned f(void) {return NLMSG_HDRLEN;} EOF : In function 'f': :3:26: warning: negative integer implicitly converted to unsigned type Signed-off-by: Dmitry V. Levin Signed-off-by: Kirill A. Shutemov Signed-off-by: David S. Miller --- include/linux/netlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 123566912d73..e2b9e63afa68 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -70,7 +70,7 @@ struct nlmsghdr { Check NLM_F_EXCL */ -#define NLMSG_ALIGNTO 4 +#define NLMSG_ALIGNTO 4U #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) From ad0081e43af6de3fecf308b0d098f9611835766b Mon Sep 17 00:00:00 2001 From: David Stevens Date: Fri, 17 Dec 2010 11:42:42 +0000 Subject: [PATCH 25/42] ipv6: Fragment locally generated tunnel-mode IPSec6 packets as needed. This patch modifies IPsec6 to fragment IPv6 packets that are locally generated as needed. This version of the patch only fragments in tunnel mode, so that fragment headers will not be obscured by ESP in transport mode. Signed-off-by: David L Stevens Acked-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/ip6_route.h | 10 ++++++++++ net/ipv6/ip6_output.c | 12 ++---------- net/ipv6/xfrm6_output.c | 16 +++++++++++++++- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 278312c95f96..2ab926860cd8 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -164,5 +164,15 @@ static inline int ipv6_unicast_destination(struct sk_buff *skb) return rt->rt6i_flags & RTF_LOCAL; } +int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); + +static inline int ip6_skb_dst_mtu(struct sk_buff *skb) +{ + struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; + + return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ? + skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); +} + #endif #endif diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 99157b4cd56e..94b5bf132b2e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -56,7 +56,7 @@ #include #include -static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); +int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); int __ip6_local_out(struct sk_buff *skb) { @@ -145,14 +145,6 @@ static int ip6_finish_output2(struct sk_buff *skb) return -EINVAL; } -static inline int ip6_skb_dst_mtu(struct sk_buff *skb) -{ - struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; - - return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ? - skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); -} - static int ip6_finish_output(struct sk_buff *skb) { if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || @@ -601,7 +593,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) return offset; } -static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) +int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { struct sk_buff *frag; struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 6434bd5ce088..8e688b3de9ab 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -17,6 +17,7 @@ #include #include #include +#include #include int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, @@ -88,8 +89,21 @@ static int xfrm6_output_finish(struct sk_buff *skb) return xfrm_output(skb); } +static int __xfrm6_output(struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + struct xfrm_state *x = dst->xfrm; + + if ((x && x->props.mode == XFRM_MODE_TUNNEL) && + ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || + dst_allfrag(skb_dst(skb)))) { + return ip6_fragment(skb, xfrm6_output_finish); + } + return xfrm6_output_finish(skb); +} + int xfrm6_output(struct sk_buff *skb) { return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, - skb_dst(skb)->dev, xfrm6_output_finish); + skb_dst(skb)->dev, __xfrm6_output); } From 173021072e86a0a5b3d2271347493a3e0d5f68e8 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Mon, 20 Dec 2010 04:35:30 +0000 Subject: [PATCH 26/42] net_sched: always clone skbs Pawel reported a panic related to handling shared skbs in ixgbe incorrectly. So we need to revert my previous patch to work around this bug. Instead of reverting the patch completely, I just revert the essential lines, so we can add the previous optimization back more easily in future. commit 3511c9132f8b1e1b5634e41a3331c44b0c13be70 Author: Changli Gao Date: Sat Oct 16 13:04:08 2010 +0000 net_sched: remove the unused parameter of qdisc_create_dflt() Reported-by: Pawel Staszewski Signed-off-by: Changli Gao Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sch_generic.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index ea1f8a83160d..79f34e2b752f 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -610,11 +610,7 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask, { struct sk_buff *n; - if ((action == TC_ACT_STOLEN || action == TC_ACT_QUEUED) && - !skb_shared(skb)) - n = skb_get(skb); - else - n = skb_clone(skb, gfp_mask); + n = skb_clone(skb, gfp_mask); if (n) { n->tc_verd = SET_TC_VERD(n->tc_verd, 0); From bbccc16c8a27d75dabe88326f7074181493a3b69 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Mon, 20 Dec 2010 10:38:47 -0800 Subject: [PATCH 27/42] net: Add USB PID for new MOSCHIP USB ethernet controller MCS7832 variant Due to active notification of the new MCS7832 version by the manufacturer (Mr. Milton; thanks!) -- quote: "functionality same as MCS7830", I'm now submitting this patch (on -rc6), intended for networking.git and -stable. - add MCS7832 USB PID to be able to support this new device variant, too - add related descriptions Signed-off-by: Andreas Mohr Signed-off-by: David S. Miller --- drivers/net/usb/mcs7830.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index a6281e3987b5..b701f593cd59 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -1,5 +1,5 @@ /* - * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices + * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices * * based on usbnet.c, asix.c and the vendor provided mcs7830 driver * @@ -11,6 +11,9 @@ * * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). * + * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"), + * per active notification by manufacturer + * * TODO: * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) * - implement ethtool_ops get_pauseparam/set_pauseparam @@ -60,6 +63,7 @@ #define MCS7830_MAX_MCAST 64 #define MCS7830_VENDOR_ID 0x9710 +#define MCS7832_PRODUCT_ID 0x7832 #define MCS7830_PRODUCT_ID 0x7830 #define MCS7730_PRODUCT_ID 0x7730 @@ -626,7 +630,7 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static const struct driver_info moschip_info = { - .description = "MOSCHIP 7830/7730 usb-NET adapter", + .description = "MOSCHIP 7830/7832/7730 usb-NET adapter", .bind = mcs7830_bind, .rx_fixup = mcs7830_rx_fixup, .flags = FLAG_ETHER, @@ -644,6 +648,10 @@ static const struct driver_info sitecom_info = { }; static const struct usb_device_id products[] = { + { + USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID), + .driver_info = (unsigned long) &moschip_info, + }, { USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), .driver_info = (unsigned long) &moschip_info, From 914e5cea14b2e4651cdb0707e0936b43246deda0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 20 Dec 2010 10:43:02 -0800 Subject: [PATCH 28/42] typhoon: memory corruption in typhoon_get_drvinfo() info->version only has space for 32 characters but my UTS_RELEASE is "2.6.37-rc6-next-20101217-05817-ge935fc8-dirty" so it doesn't fit. This is supposed to be the version of the driver, not the kernel version. This driver doesn't have a version so lets just leave it blank. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/typhoon.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 5b83c3f35f47..a3c46f6a15e7 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1004,7 +1004,6 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) } strcpy(info->driver, KBUILD_MODNAME); - strcpy(info->version, UTS_RELEASE); strcpy(info->bus_info, pci_name(pci_dev)); } From 9f333281a7da4c3a59bccc0cb53f7590eb850d93 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Tue, 30 Nov 2010 16:49:23 +0100 Subject: [PATCH 29/42] mac80211/rt2x00: add ieee80211_tx_status_ni() All rt2x00 drivers except rt2800pci call ieee80211_tx_status() from a workqueue, which causes "NOHZ: local_softirq_pending 08" messages. To fix it, add ieee80211_tx_status_ni() similar to ieee80211_rx_ni() which can be called from process context, and call it from rt2x00lib_txdone(). For the rt2800pci special case a driver flag is introduced. https://bugzilla.kernel.org/show_bug.cgi?id=24892 Signed-off-by: Johannes Stezenbach Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 9 +++++--- include/net/mac80211.h | 28 +++++++++++++++++++++---- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index b26739535986..09a67905c230 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -912,6 +912,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 94fe589acfaa..ab43e7ca2a23 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -664,6 +664,7 @@ enum rt2x00_flags { DRIVER_REQUIRE_COPY_IV, DRIVER_REQUIRE_L2PAD, DRIVER_REQUIRE_TXSTATUS_FIFO, + DRIVER_REQUIRE_TASKLET_CONTEXT, /* * Driver features diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5ba79b935f09..d019830ca840 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -390,9 +390,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, * through a mac80211 library call (RTS/CTS) then we should not * send the status report back. */ - if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) - ieee80211_tx_status(rt2x00dev->hw, entry->skb); - else + if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { + if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags)) + ieee80211_tx_status(rt2x00dev->hw, entry->skb); + else + ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); + } else dev_kfree_skb_any(entry->skb); /* diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9fdf982d1286..365359b24177 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2024,8 +2024,8 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw, * * This function may not be called in IRQ context. Calls to this function * for a single hardware must be synchronized against each other. Calls - * to this function and ieee80211_tx_status_irqsafe() may not be mixed - * for a single hardware. + * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe() + * may not be mixed for a single hardware. * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call @@ -2033,14 +2033,34 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw, void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); +/** + * ieee80211_tx_status_ni - transmit status callback (in process context) + * + * Like ieee80211_tx_status() but can be called in process context. + * + * Calls to this function, ieee80211_tx_status() and + * ieee80211_tx_status_irqsafe() may not be mixed + * for a single hardware. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + */ +static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + local_bh_disable(); + ieee80211_tx_status(hw, skb); + local_bh_enable(); +} + /** * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback * * Like ieee80211_tx_status() but can be called in IRQ context * (internally defers to a tasklet.) * - * Calls to this function and ieee80211_tx_status() may not be mixed for a - * single hardware. + * Calls to this function, ieee80211_tx_status() and + * ieee80211_tx_status_ni() may not be mixed for a single hardware. * * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call From b2b7ab22fa2e619c20917e825c0da7212ca2efc9 Mon Sep 17 00:00:00 2001 From: Meelis Roos Date: Fri, 17 Dec 2010 23:27:50 +0200 Subject: [PATCH 30/42] hostap: remove netif_stop_queue from init Fix runtime warning with backtrace from hostap by removing netif_stop_queue() call before register_netdev. Tested to work fine on hostap_pci Prism 2.5. (This removes a warning about calling netif_stop_queue before register_netdev is called. -- JWL) Signed-off-by: Meelis Roos Acked-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 25a2722c8a98..1d9aed645723 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -891,7 +891,6 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops); - netif_stop_queue(dev); } static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) From aa3e219997e4b949be4199660936099ded0b401f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 20 Dec 2010 13:18:16 -0800 Subject: [PATCH 31/42] net_sched: sch_sfq: fix allot handling When deploying SFQ/IFB here at work, I found the allot management was pretty wrong in sfq, even changing allot from short to int... We should init allot for each new flow, not using a previous value found in slot. Before patch, I saw bursts of several packets per flow, apparently denying the default "quantum 1514" limit I had on my SFQ class. class sfq 11:1 parent 11: (dropped 0, overlimits 0 requeues 0) backlog 0b 7p requeues 0 allot 11546 class sfq 11:46 parent 11: (dropped 0, overlimits 0 requeues 0) backlog 0b 1p requeues 0 allot -23873 class sfq 11:78 parent 11: (dropped 0, overlimits 0 requeues 0) backlog 0b 5p requeues 0 allot 11393 After patch, better fairness among each flow, allot limit being respected, allot is positive : class sfq 11:e parent 11: (dropped 0, overlimits 0 requeues 86) backlog 0b 3p requeues 86 allot 596 class sfq 11:94 parent 11: (dropped 0, overlimits 0 requeues 0) backlog 0b 3p requeues 0 allot 1468 class sfq 11:a4 parent 11: (dropped 0, overlimits 0 requeues 0) backlog 0b 4p requeues 0 allot 650 class sfq 11:bb parent 11: (dropped 0, overlimits 0 requeues 0) backlog 0b 3p requeues 0 allot 596 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_sfq.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 3cf478d012dd..7150705f1d0b 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -270,7 +270,6 @@ static unsigned int sfq_drop(struct Qdisc *sch) /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ d = q->next[q->tail]; q->next[q->tail] = q->next[d]; - q->allot[q->next[d]] += q->quantum; skb = q->qs[d].prev; len = qdisc_pkt_len(skb); __skb_unlink(skb, &q->qs[d]); @@ -321,14 +320,13 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) sfq_inc(q, x); if (q->qs[x].qlen == 1) { /* The flow is new */ if (q->tail == SFQ_DEPTH) { /* It is the first flow */ - q->tail = x; q->next[x] = x; - q->allot[x] = q->quantum; } else { q->next[x] = q->next[q->tail]; q->next[q->tail] = x; - q->tail = x; } + q->tail = x; + q->allot[x] = q->quantum; } if (++sch->q.qlen <= q->limit) { sch->bstats.bytes += qdisc_pkt_len(skb); @@ -359,13 +357,13 @@ sfq_dequeue(struct Qdisc *sch) { struct sfq_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; - sfq_index a, old_a; + sfq_index a, next_a; /* No active slots */ if (q->tail == SFQ_DEPTH) return NULL; - a = old_a = q->next[q->tail]; + a = q->next[q->tail]; /* Grab packet */ skb = __skb_dequeue(&q->qs[a]); @@ -376,17 +374,15 @@ sfq_dequeue(struct Qdisc *sch) /* Is the slot empty? */ if (q->qs[a].qlen == 0) { q->ht[q->hash[a]] = SFQ_DEPTH; - a = q->next[a]; - if (a == old_a) { + next_a = q->next[a]; + if (a == next_a) { q->tail = SFQ_DEPTH; return skb; } - q->next[q->tail] = a; - q->allot[a] += q->quantum; + q->next[q->tail] = next_a; } else if ((q->allot[a] -= qdisc_pkt_len(skb)) <= 0) { - q->tail = a; - a = q->next[a]; q->allot[a] += q->quantum; + q->tail = a; } return skb; } From da521b2c4f046383bc8941604174bc0e8bffb430 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 21 Dec 2010 12:43:16 -0800 Subject: [PATCH 32/42] net: Fix range checks in tcf_valid_offset(). This function has three bugs: 1) The offset should be valid most of the time, this is just a sanity check, therefore we should use "likely" not "unlikely" 2) This is the only place where we can check for arithmetic overflow of the pointer plus the length. 3) The existing range checks are off by one, the valid range is skb->head to skb_tail_pointer(), inclusive. Based almost entirely upon a patch by Ralph Loader. Reported-by: Ralph Loader Signed-off-by: David S. Miller --- include/net/pkt_cls.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index dd3031aed9d5..9fcc680ab6b9 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -323,7 +323,9 @@ static inline unsigned char * tcf_get_base_ptr(struct sk_buff *skb, int layer) static inline int tcf_valid_offset(const struct sk_buff *skb, const unsigned char *ptr, const int len) { - return unlikely((ptr + len) < skb_tail_pointer(skb) && ptr > skb->head); + return likely((ptr + len) <= skb_tail_pointer(skb) && + ptr >= skb->head && + (ptr <= (ptr + len))); } #ifdef CONFIG_NET_CLS_IND From 227fb925d3d3c5e565c1f1323a530564509195f2 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Tue, 21 Dec 2010 19:58:15 -0800 Subject: [PATCH 33/42] MAINTAINERS: email address change My ISP has changed and therefore my email address. Signed-off-by: Don Fry Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index dec390dff141..b0b118a546ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4586,7 +4586,7 @@ F: drivers/pcmcia/ F: include/pcmcia/ PCNET32 NETWORK DRIVER -M: Don Fry +M: Don Fry L: netdev@vger.kernel.org S: Maintained F: drivers/net/pcnet32.c From b51aff057c9d0ef6c529dc25fd9f775faf7b6c63 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Dec 2010 10:15:07 +0100 Subject: [PATCH 34/42] mac80211: fix mesh forwarding Under memory pressure, the mac80211 mesh code may helpfully print a message that it failed to clone a mesh frame and then will proceed to crash trying to use it anyway. Fix that. Cc: stable@kernel.org [2.6.27+] Signed-off-by: Johannes Berg Acked-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/rx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 54fb4a0e76f0..b01e467b76c6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1788,9 +1788,11 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) fwd_skb = skb_copy(skb, GFP_ATOMIC); - if (!fwd_skb && net_ratelimit()) + if (!fwd_skb && net_ratelimit()) { printk(KERN_DEBUG "%s: failed to clone mesh frame\n", sdata->name); + goto out; + } fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); @@ -1828,6 +1830,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } } + out: if (is_multicast_ether_addr(hdr->addr1) || sdata->dev->flags & IFF_PROMISC) return RX_CONTINUE; From 762e30239cce9ff0d82227ade663feed2f6283d8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 22 Dec 2010 03:07:52 +0000 Subject: [PATCH 35/42] atl1c: Do not use legacy PCI power management The atl1c driver uses the legacy PCI power management, so it has to do some PCI-specific things in its ->suspend() and ->resume() callbacks and they are not done correctly. Convert atl1c to the new PCI power management framework and make it let the PCI subsystem handle all of the PCI-specific aspects of device handling during system power transitions. Signed-off-by: Rafael J. Wysocki Signed-off-by: David S. Miller --- drivers/net/atl1c/atl1c_main.c | 39 +++++++++++++--------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 09b099bfab2b..bdf11d89a499 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -702,6 +702,7 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) adapter->wol = 0; + device_set_wakeup_enable(&pdev->dev, false); adapter->link_speed = SPEED_0; adapter->link_duplex = FULL_DUPLEX; adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE; @@ -2444,8 +2445,9 @@ static int atl1c_close(struct net_device *netdev) return 0; } -static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) +static int atl1c_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct atl1c_adapter *adapter = netdev_priv(netdev); struct atl1c_hw *hw = &adapter->hw; @@ -2454,7 +2456,6 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) u32 wol_ctrl_data = 0; u16 mii_intr_status_data = 0; u32 wufc = adapter->wol; - int retval = 0; atl1c_disable_l0s_l1(hw); if (netif_running(netdev)) { @@ -2462,9 +2463,6 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) atl1c_down(adapter); } netif_device_detach(netdev); - retval = pci_save_state(pdev); - if (retval) - return retval; if (wufc) if (atl1c_phy_power_saving(hw) != 0) @@ -2525,12 +2523,8 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data); AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); - /* pcie patch */ - device_set_wakeup_enable(&pdev->dev, 1); - AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET); - pci_prepare_to_sleep(pdev); } else { AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING); master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS; @@ -2540,25 +2534,17 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); AT_WRITE_REG(hw, REG_WOL_CTRL, 0); hw->phy_configured = false; /* re-init PHY when resume */ - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); } - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } -static int atl1c_resume(struct pci_dev *pdev) +static int atl1c_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct atl1c_adapter *adapter = netdev_priv(netdev); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE | ATL1C_PCIE_PHY_RESET); @@ -2582,7 +2568,12 @@ static int atl1c_resume(struct pci_dev *pdev) static void atl1c_shutdown(struct pci_dev *pdev) { - atl1c_suspend(pdev, PMSG_SUSPEND); + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1c_adapter *adapter = netdev_priv(netdev); + + atl1c_suspend(&pdev->dev); + pci_wake_from_d3(pdev, adapter->wol); + pci_set_power_state(pdev, PCI_D3hot); } static const struct net_device_ops atl1c_netdev_ops = { @@ -2886,16 +2877,16 @@ static struct pci_error_handlers atl1c_err_handler = { .resume = atl1c_io_resume, }; +static SIMPLE_DEV_PM_OPS(atl1c_pm_ops, atl1c_suspend, atl1c_resume); + static struct pci_driver atl1c_driver = { .name = atl1c_driver_name, .id_table = atl1c_pci_tbl, .probe = atl1c_probe, .remove = __devexit_p(atl1c_remove), - /* Power Managment Hooks */ - .suspend = atl1c_suspend, - .resume = atl1c_resume, .shutdown = atl1c_shutdown, - .err_handler = &atl1c_err_handler + .err_handler = &atl1c_err_handler, + .driver.pm = &atl1c_pm_ops, }; /* From 1bde5ac49398a064c753bb490535cfad89e99a5f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 23 Dec 2010 09:32:46 -0800 Subject: [PATCH 36/42] tcp: fix listening_get_next() Alexey Vlasov found /proc/net/tcp could sometime loop and display millions of sockets in LISTEN state. In 2.6.29, when we converted TCP hash tables to RCU, we left two sk_next() calls in listening_get_next(). We must instead use sk_nulls_next() to properly detect an end of chain. Reported-by: Alexey Vlasov Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e13da6de1fc7..d978bb2f748b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2030,7 +2030,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) get_req: req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket]; } - sk = sk_next(st->syn_wait_sk); + sk = sk_nulls_next(st->syn_wait_sk); st->state = TCP_SEQ_STATE_LISTENING; read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); } else { @@ -2039,7 +2039,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) if (reqsk_queue_len(&icsk->icsk_accept_queue)) goto start_req; read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); - sk = sk_next(sk); + sk = sk_nulls_next(sk); } get_sk: sk_nulls_for_each_from(sk, node) { From fdac1e0697356ac212259f2147aa60c72e334861 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 22 Dec 2010 13:58:27 +0000 Subject: [PATCH 37/42] irda: prevent integer underflow in IRLMP_ENUMDEVICES If the user-provided len is less than the expected offset, the IRLMP_ENUMDEVICES getsockopt will do a copy_to_user() with a very large size value. While this isn't be a security issue on x86 because it will get caught by the access_ok() check, it may leak large amounts of kernel heap on other architectures. In any event, this patch fixes it. Signed-off-by: Dan Rosenberg Signed-off-by: David S. Miller --- net/irda/af_irda.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 7f097989cde2..5007541b6478 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -2281,6 +2281,16 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, switch (optname) { case IRLMP_ENUMDEVICES: + + /* Offset to first device entry */ + offset = sizeof(struct irda_device_list) - + sizeof(struct irda_device_info); + + if (len < offset) { + err = -EINVAL; + goto out; + } + /* Ask lmp for the current discovery log */ discoveries = irlmp_get_discoveries(&list.len, self->mask.word, self->nslots); @@ -2291,15 +2301,9 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, } /* Write total list length back to client */ - if (copy_to_user(optval, &list, - sizeof(struct irda_device_list) - - sizeof(struct irda_device_info))) + if (copy_to_user(optval, &list, offset)) err = -EFAULT; - /* Offset to first device entry */ - offset = sizeof(struct irda_device_list) - - sizeof(struct irda_device_info); - /* Copy the list itself - watch for overflow */ if (list.len > 2048) { err = -EINVAL; From 0e214ad81545a35c5e62a4c2d6cf7275fd7a545f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 17 Dec 2010 03:25:43 +0000 Subject: [PATCH 38/42] USB: mcs7830: return negative if auto negotiate fails The original code returns 0 on success and 1 on failure. In fact, at this point, "ret" is already either zero or a negative error code so we can just return it directly. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/usb/mcs7830.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index b701f593cd59..2b791392e788 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -355,7 +355,7 @@ static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) if (!ret) ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART ); - return ret < 0 ? : 0; + return ret; } From e058464990c2ef1f3ecd6b83a154913c3c06f02a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 23 Dec 2010 12:03:57 -0800 Subject: [PATCH 39/42] Revert "ipv4: Allow configuring subnets as local addresses" This reverts commit 4465b469008bc03b98a1b8df4e9ae501b6c69d4b. Conflicts: net/ipv4/fib_frontend.c As reported by Ben Greear, this causes regressions: > Change 4465b469008bc03b98a1b8df4e9ae501b6c69d4b caused rules > to stop matching the input device properly because the > FLOWI_FLAG_MATCH_ANY_IIF is always defined in ip_dev_find(). > > This breaks rules such as: > > ip rule add pref 512 lookup local > ip rule del pref 0 lookup local > ip link set eth2 up > ip -4 addr add 172.16.0.102/24 broadcast 172.16.0.255 dev eth2 > ip rule add to 172.16.0.102 iif eth2 lookup local pref 10 > ip rule add iif eth2 lookup 10001 pref 20 > ip route add 172.16.0.0/24 dev eth2 table 10001 > ip route add unreachable 0/0 table 10001 > > If you had a second interface 'eth0' that was on a different > subnet, pinging a system on that interface would fail: > > [root@ct503-60 ~]# ping 192.168.100.1 > connect: Invalid argument Reported-by: Ben Greear Signed-off-by: David S. Miller --- include/net/flow.h | 1 - net/core/fib_rules.c | 3 +-- net/ipv4/fib_frontend.c | 10 ++++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/net/flow.h b/include/net/flow.h index 0ac3fb5e0973..bb08692a20b0 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -49,7 +49,6 @@ struct flowi { __u8 proto; __u8 flags; #define FLOWI_FLAG_ANYSRC 0x01 -#define FLOWI_FLAG_MATCH_ANY_IIF 0x02 union { struct { __be16 sport; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 82a4369ae150..a20e5d3bbfa0 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -181,8 +181,7 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, { int ret = 0; - if (rule->iifindex && (rule->iifindex != fl->iif) && - !(fl->flags & FLOWI_FLAG_MATCH_ANY_IIF)) + if (rule->iifindex && (rule->iifindex != fl->iif)) goto out; if (rule->oifindex && (rule->oifindex != fl->oif)) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index eb6f69a8f27a..c19c1f739fba 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -163,13 +163,19 @@ struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) .daddr = addr } }, - .flags = FLOWI_FLAG_MATCH_ANY_IIF }; struct fib_result res = { 0 }; struct net_device *dev = NULL; + struct fib_table *local_table; + +#ifdef CONFIG_IP_MULTIPLE_TABLES + res.r = NULL; +#endif rcu_read_lock(); - if (fib_lookup(net, &fl, &res)) { + local_table = fib_get_table(net, RT_TABLE_LOCAL); + if (!local_table || + fib_table_lookup(local_table, &fl, &res, FIB_LOOKUP_NOREF)) { rcu_read_unlock(); return NULL; } From 78a36f25478432835f2f1e46202b71ff3ae454ff Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Sat, 25 Dec 2010 05:12:17 +0000 Subject: [PATCH 40/42] sundance: Fix oopses with corrupted skb_shared_info Joel Soete reported oopses at the beginning of pppoe connections since v2.6.35. After debugging the bug was found in sundance skb allocation and dma mapping code, where skb_reserve() bytes aren't taken into account. This is an old bug, only uncovered by some change in 2.6.35. Initial debugging patch by: Eric Dumazet Reported-by: Joel Soete Tested-by: Joel Soete Signed-off-by: Jarek Poplawski Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/sundance.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 3ed2a67bd6d3..b409d7ec4ac1 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1016,7 +1016,7 @@ static void init_ring(struct net_device *dev) /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + 2); np->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1407,7 +1407,7 @@ static void refill_rx (struct net_device *dev) struct sk_buff *skb; entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); + skb = dev_alloc_skb(np->rx_buf_sz + 2); np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ From 7a36df8a857edee8cd8967cbe99a85574d22f482 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Sat, 25 Dec 2010 07:39:59 +0000 Subject: [PATCH 41/42] epic100: hamachi: yellowfin: Fix skb allocation size Joel Soete reported oopses during pppoe over sundance NIC, caused by a bug in skb allocation and dma mapping code, where skb_reserve() bytes weren't taken into account. As a followup to the patch: "sundance: Fix oopses with corrupted skb_shared_info" very similar code is fixed here for three other drivers. Signed-off-by: Jarek Poplawski Cc: Joel Soete Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/epic100.c | 4 ++-- drivers/net/hamachi.c | 4 ++-- drivers/net/yellowfin.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index aa56963ad558..c353bf3113cc 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -935,7 +935,7 @@ static void epic_init_ring(struct net_device *dev) /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz + 2); ep->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1233,7 +1233,7 @@ static int epic_rx(struct net_device *dev, int budget) entry = ep->dirty_rx % RX_RING_SIZE; if (ep->rx_skbuff[entry] == NULL) { struct sk_buff *skb; - skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz); + skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz + 2); if (skb == NULL) break; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 9a6485892b3d..80d25ed53344 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1202,7 +1202,7 @@ static void hamachi_init_ring(struct net_device *dev) } /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2); hmp->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1669,7 +1669,7 @@ static int hamachi_rx(struct net_device *dev) entry = hmp->dirty_rx % RX_RING_SIZE; desc = &(hmp->rx_ring[entry]); if (hmp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2); hmp->rx_skbuff[entry] = skb; if (skb == NULL) diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index cd1b3dcd61db..ec47e22fa186 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -744,7 +744,7 @@ static int yellowfin_init_ring(struct net_device *dev) } for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2); yp->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1157,7 +1157,7 @@ static int yellowfin_rx(struct net_device *dev) for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) { entry = yp->dirty_rx % RX_RING_SIZE; if (yp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2); if (skb == NULL) break; /* Better luck next round. */ yp->rx_skbuff[entry] = skb; From fc75fc8339e7727167443469027540b283daac71 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 22 Dec 2010 04:39:39 +0000 Subject: [PATCH 42/42] ipv4: dont create routes on down devices In ip_route_output_slow(), instead of allowing a route to be created on a not UPed device, report -ENETUNREACH immediately. # ip tunnel add mode ipip remote 10.16.0.164 local 10.16.0.72 dev eth0 # (Note : tunl1 is down) # ping -I tunl1 10.1.2.3 PING 10.1.2.3 (10.1.2.3) from 192.168.18.5 tunl1: 56(84) bytes of data. (nothing) # ./a.out tunl1 # ip tunnel del tunl1 Message from syslogd@shelby at Dec 22 10:12:08 ... kernel: unregister_netdevice: waiting for tunl1 to become free. Usage count = 3 After patch: # ping -I tunl1 10.1.2.3 connect: Network is unreachable Reported-by: Nicolas Dichtel Signed-off-by: Eric Dumazet Reviewed-by: Octavian Purdila Signed-off-by: David S. Miller --- net/ipv4/route.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 987bf9adb318..df948b0f1ac9 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2585,9 +2585,10 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, goto out; /* RACE: Check return value of inet_select_addr instead. */ - if (rcu_dereference(dev_out->ip_ptr) == NULL) - goto out; /* Wrong error code */ - + if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) { + err = -ENETUNREACH; + goto out; + } if (ipv4_is_local_multicast(oldflp->fl4_dst) || ipv4_is_lbcast(oldflp->fl4_dst)) { if (!fl.fl4_src)