From 700920eb5ba4de5417b446c9a8bb008df2b973e0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 18 Jan 2012 15:31:45 +0000 Subject: KEYS: Allow special keyrings to be cleared The kernel contains some special internal keyrings, for instance the DNS resolver keyring : 2a93faf1 I----- 1 perm 1f030000 0 0 keyring .dns_resolver: empty It would occasionally be useful to allow the contents of such keyrings to be flushed by root (cache invalidation). Allow a flag to be set on a keyring to mark that someone possessing the sysadmin capability can clear the keyring, even without normal write access to the keyring. Set this flag on the special keyrings created by the DNS resolver, the NFS identity mapper and the CIFS identity mapper. Signed-off-by: David Howells Acked-by: Jeff Layton Acked-by: Steve Dickson Signed-off-by: James Morris --- net/dns_resolver/dns_key.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index fa000d26dc6..c73bba326d7 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -281,6 +281,7 @@ static int __init init_dns_resolver(void) /* instruct request_key() to use this special keyring as a cache for * the results it looks up */ + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; dns_resolver_cache = cred; -- cgit v1.2.3-70-g09d2 From 35b88623692f7ffbfdf16e4c2358784a060c20ed Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 29 Dec 2011 14:41:39 +0200 Subject: mac80211: check sta_apply_parameters() return value Bail out if sta_apply_parameters() returns an error. Signed-off-by: Eliad Peller Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 296620d6ca0..d86730fe75c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1001,6 +1001,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, struct ieee80211_local *local = wiphy_priv(wiphy); struct sta_info *sta; struct ieee80211_sub_if_data *vlansdata; + int err; mutex_lock(&local->sta_mtx); @@ -1040,7 +1041,11 @@ static int ieee80211_change_station(struct wiphy *wiphy, ieee80211_send_layer2_update(sta); } - sta_apply_parameters(local, sta, params); + err = sta_apply_parameters(local, sta, params); + if (err) { + mutex_unlock(&local->sta_mtx); + return err; + } if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates) rate_control_rate_init(sta); -- cgit v1.2.3-70-g09d2 From 39d02a7d90602d4557ee05db2a157a4e0ec3a3d3 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Sat, 7 Jan 2012 21:06:21 +0530 Subject: mac80211: minor cleanup we would have bailed out if 'ifibss->fixed_channel' is valid i.e. we had used 'fixed-freq' parameter in iw ibss join command. this is with the state 'IEEE80211_IBSS_MLME_JOINED' so no need to check for it Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b3d76b756cd..b4c30318e22 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -642,8 +642,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) "IBSS networks with same SSID (merge)\n", sdata->name); ieee80211_request_internal_scan(sdata, - ifibss->ssid, ifibss->ssid_len, - ifibss->fixed_channel ? ifibss->channel : NULL); + ifibss->ssid, ifibss->ssid_len, NULL); } static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) -- cgit v1.2.3-70-g09d2 From bd7e01bc7e7a90b33470173618f6f6805143cd42 Mon Sep 17 00:00:00 2001 From: Ilan Elias Date: Sun, 8 Jan 2012 11:21:53 +0200 Subject: NFC: Complete NCI deactivate in deactivate_ntf If a target was active, complete the NCI deactivate request only in deactivate_ntf. Otherwise, complete it at deactivate_rsp. Deactivate_ntf represents the actual disconnection event (sent from the NCI controller). Signed-off-by: Ilan Elias Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/nci/ntf.c | 2 ++ net/nfc/nci/rsp.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index b16a8dc2afb..10682bf7029 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -280,6 +280,8 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, /* complete the data exchange transaction, if exists */ if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) nci_data_exchange_complete(ndev, NULL, -EIO); + + nci_req_complete(ndev, NCI_STATUS_OK); } void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb) diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 2840ae2f361..3c73e92eb62 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -151,7 +151,10 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, clear_bit(NCI_DISCOVERY, &ndev->flags); - nci_req_complete(ndev, status); + /* If target was active, complete the request only in deactivate_ntf */ + if ((status != NCI_STATUS_OK) || + (!test_bit(NCI_POLL_ACTIVE, &ndev->flags))) + nci_req_complete(ndev, status); } void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From e9980e6d20a5c4d3f52359142ab3569171759a5b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 9 Jan 2012 13:57:36 +0100 Subject: mac80211: refactor __ieee80211_get_channel_mode Use a switch statement instead of a list of if statements. Also include AP_VLAN in the list and skip them since the AP interface will also be looked at. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/chan.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 889c3e93e0f..d1f7abddb18 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -20,23 +20,29 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + switch (sdata->vif.type) { + case NL80211_IFTYPE_MONITOR: continue; - - if (sdata->vif.type == NL80211_IFTYPE_STATION && - !sdata->u.mgd.associated) - continue; - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + case NL80211_IFTYPE_STATION: + if (!sdata->u.mgd.associated) + continue; + break; + case NL80211_IFTYPE_ADHOC: if (!sdata->u.ibss.ssid_len) continue; if (!sdata->u.ibss.fixed_channel) return CHAN_MODE_HOPPING; - } - - if (sdata->vif.type == NL80211_IFTYPE_AP && - !sdata->u.ap.beacon) + break; + case NL80211_IFTYPE_AP_VLAN: + /* will also have _AP interface */ continue; + case NL80211_IFTYPE_AP: + if (!sdata->u.ap.beacon) + continue; + break; + default: + break; + } return CHAN_MODE_FIXED; } -- cgit v1.2.3-70-g09d2 From efa6a09db6d6c27557fb55299b9835b45b968eae Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 9 Jan 2012 19:43:06 +0100 Subject: mac80211: In IBSS the DA field of auth frames is different from BSSID In case of authentication frame exchange between two IBSS STAs, the DA field must contain the destinatioin address (instead of the BSSID). Signed-off-by: Antonio Quartulli Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/util.c | 6 +++--- net/mac80211/work.c | 5 +++-- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b4c30318e22..4345e9449d7 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, * has actually implemented this. */ if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) - ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, + ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2f0642d9e15..ca6486b941b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1396,7 +1396,7 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, u8 *extra, size_t extra_len, const u8 *bssid, - const u8 *key, u8 key_len, u8 key_idx); + const u8 *da, const u8 *key, u8 key_len, u8 key_idx); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len, enum ieee80211_band band, u32 rate_mask, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9919892575f..30d72e2af7c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -862,8 +862,8 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, - u8 *extra, size_t extra_len, const u8 *bssid, - const u8 *key, u8 key_len, u8 key_idx) + u8 *extra, size_t extra_len, const u8 *da, + const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; @@ -881,7 +881,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, memset(mgmt, 0, 24 + 6); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); - memcpy(mgmt->da, bssid, ETH_ALEN); + memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); diff --git a/net/mac80211/work.c b/net/mac80211/work.c index c6dd01a0529..0a1a176fbe9 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -480,7 +480,8 @@ ieee80211_authenticate(struct ieee80211_work *wk) sdata->name, wk->filter_ta, wk->probe_auth.tries); ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie, - wk->ie_len, wk->filter_ta, NULL, 0, 0); + wk->ie_len, wk->filter_ta, wk->filter_ta, NULL, 0, + 0); wk->probe_auth.transaction = 2; wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; @@ -598,7 +599,7 @@ static void ieee80211_auth_challenge(struct ieee80211_work *wk, return; ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm, elems.challenge - 2, elems.challenge_len + 2, - wk->filter_ta, wk->probe_auth.key, + wk->filter_ta, wk->filter_ta, wk->probe_auth.key, wk->probe_auth.key_len, wk->probe_auth.key_idx); wk->probe_auth.transaction = 4; } -- cgit v1.2.3-70-g09d2 From eccc068e8e84c8fe997115629925e0422a98e4de Mon Sep 17 00:00:00 2001 From: Hong Wu Date: Wed, 11 Jan 2012 20:33:39 +0200 Subject: wireless: Save original maximum regulatory transmission power for the calucation of the local maximum transmit power The local maximum transmit power is the maximum power a wireless device allowed to transmit. If Power Constraint is presented, the local maximum power equals to the maximum allowed power defined in regulatory domain minus power constraint. The maximum transmit power is maximum power a wireless device capable of transmitting, and should be used in Power Capability element (7.3.2.16 IEEE802.11 2007). The transmit power from a wireless device should not greater than the local maximum transmit power. The maximum transmit power was not calculated correctly in the current Linux wireless/mac80211 when Power Constraint is presented. Signed-off-by: Hong Wu Signed-off-by: John W. Linville --- include/net/cfg80211.h | 2 ++ net/wireless/reg.c | 19 ++----------------- 2 files changed, 4 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 15f4be7d768..208a7b5f8d4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -120,6 +120,7 @@ enum ieee80211_channel_flags { * @band: band this channel belongs to. * @max_antenna_gain: maximum antenna gain in dBi * @max_power: maximum transmission power (in dBm) + * @max_reg_power: maximum regulatory transmission power (in dBm) * @beacon_found: helper to regulatory code to indicate when a beacon * has been found on this channel. Use regulatory_hint_found_beacon() * to enable this, this is useful only on 5 GHz band. @@ -133,6 +134,7 @@ struct ieee80211_channel { u32 flags; int max_antenna_gain; int max_power; + int max_reg_power; bool beacon_found; u32 orig_flags; int orig_mag, orig_mpwr; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f65feaad155..e9a0ac83b84 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -882,23 +882,8 @@ static void handle_channel(struct wiphy *wiphy, chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); chan->max_antenna_gain = min(chan->orig_mag, (int) MBI_TO_DBI(power_rule->max_antenna_gain)); - if (chan->orig_mpwr) { - /* - * Devices that have their own custom regulatory domain - * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the - * passed country IE power settings. - */ - if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && - wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { - chan->max_power = - MBM_TO_DBM(power_rule->max_eirp); - } else { - chan->max_power = min(chan->orig_mpwr, - (int) MBM_TO_DBM(power_rule->max_eirp)); - } - } else - chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); + chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); + chan->max_power = min(chan->max_power, chan->max_reg_power); } static void handle_band(struct wiphy *wiphy, -- cgit v1.2.3-70-g09d2 From a48b13ac811ee236151d9e0e0dcb5639b2ab4591 Mon Sep 17 00:00:00 2001 From: Hong Wu Date: Wed, 11 Jan 2012 20:34:30 +0200 Subject: mac80211: Fix the maximum transmit power with power constraint The local maximum transmit power for a channel is defined as the maximum regulatory transmission power minus the local power constraint specified for the channel in the Power Constraint element. (7.3.2.15 IEEE80211 2007) Signed-off-by: Hong Wu Signed-off-by: John W. Linville --- net/mac80211/main.c | 3 ++- net/mac80211/mlme.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0a0d94ad9b0..6192caadfab 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -155,7 +155,8 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) power = chan->max_power; else power = local->power_constr_level ? - (chan->max_power - local->power_constr_level) : + min(chan->max_power, + (chan->max_reg_power - local->power_constr_level)) : chan->max_power; if (local->user_power_level >= 0) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ecb4c84c1bb..95d3964fc08 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -547,7 +547,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, if (pwr_constr_elem_len != 1) return; - if ((*pwr_constr_elem <= conf->channel->max_power) && + if ((*pwr_constr_elem <= conf->channel->max_reg_power) && (*pwr_constr_elem != sdata->local->power_constr_level)) { sdata->local->power_constr_level = *pwr_constr_elem; ieee80211_hw_config(sdata->local, 0); -- cgit v1.2.3-70-g09d2 From f1249700f563b5dc541afa7e54a2d93fdffc1fb6 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 13 Jan 2012 13:53:18 +0100 Subject: mac80211: remove useless DA checking in ieee80211_rx_mgmt_probe_resp() Actually the DA field has already been checked along the rx path (in prepare_for_handlers()) and this check is therefore useless at this point. Signed-off-by: Antonio Quartulli Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 4345e9449d7..b253d0adf0a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -853,9 +853,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, size_t baselen; struct ieee802_11_elems elems; - if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) - return; /* ignore ProbeResp to foreign address */ - baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; if (baselen > len) return; -- cgit v1.2.3-70-g09d2 From d5a2ca60e41fec4ede7b82d3608278523cffe77b Mon Sep 17 00:00:00 2001 From: Ilan Elias Date: Tue, 17 Jan 2012 11:06:43 +0200 Subject: NFC: Export new attributes sensb_res and sensf_res Export new attributes sensb_res for tech B and sensf_res for tech F in the target info (returned as a response to NFC_CMD_GET_TARGET). The max size of the attributes nfcid1, sensb_res and sensf_res is exported to user space though include/linux/nfc. Signed-off-by: Ilan Elias Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/linux/nfc.h | 7 ++++ include/net/nfc/nci.h | 19 +++++++++ include/net/nfc/nfc.h | 8 +++- net/nfc/nci/ntf.c | 111 ++++++++++++++++++++++++++++++++++++++++++++------ net/nfc/netlink.c | 6 +++ 5 files changed, 136 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/linux/nfc.h b/include/linux/nfc.h index 01d4e5d6032..b4999abcb2a 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h @@ -89,6 +89,8 @@ enum nfc_commands { * @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the * target is not NFC-Forum compliant) * @NFC_ATTR_TARGET_NFCID1: NFC-A targets identifier, max 10 bytes + * @NFC_ATTR_TARGET_SENSB_RES: NFC-B targets extra information, max 12 bytes + * @NFC_ATTR_TARGET_SENSF_RES: NFC-F targets extra information, max 18 bytes * @NFC_ATTR_COMM_MODE: Passive or active mode * @NFC_ATTR_RF_MODE: Initiator or target */ @@ -101,6 +103,8 @@ enum nfc_attrs { NFC_ATTR_TARGET_SENS_RES, NFC_ATTR_TARGET_SEL_RES, NFC_ATTR_TARGET_NFCID1, + NFC_ATTR_TARGET_SENSB_RES, + NFC_ATTR_TARGET_SENSF_RES, NFC_ATTR_COMM_MODE, NFC_ATTR_RF_MODE, /* private: internal use only */ @@ -109,6 +113,9 @@ enum nfc_attrs { #define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1) #define NFC_DEVICE_NAME_MAXSIZE 8 +#define NFC_NFCID1_MAXSIZE 10 +#define NFC_SENSB_RES_MAXSIZE 12 +#define NFC_SENSF_RES_MAXSIZE 18 /* NFC protocols */ #define NFC_PROTO_JEWEL 1 diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h index 2be95e2626c..34f5ed29c3c 100644 --- a/include/net/nfc/nci.h +++ b/include/net/nfc/nci.h @@ -275,11 +275,27 @@ struct rf_tech_specific_params_nfca_poll { __u8 sel_res; } __packed; +struct rf_tech_specific_params_nfcb_poll { + __u8 sensb_res_len; + __u8 sensb_res[12]; /* 11 or 12 Bytes */ +} __packed; + +struct rf_tech_specific_params_nfcf_poll { + __u8 bit_rate; + __u8 sensf_res_len; + __u8 sensf_res[18]; /* 16 or 18 Bytes */ +} __packed; + struct activation_params_nfca_poll_iso_dep { __u8 rats_res_len; __u8 rats_res[20]; }; +struct activation_params_nfcb_poll_iso_dep { + __u8 attrib_res_len; + __u8 attrib_res[50]; +}; + struct nci_rf_intf_activated_ntf { __u8 rf_discovery_id; __u8 rf_interface; @@ -291,6 +307,8 @@ struct nci_rf_intf_activated_ntf { union { struct rf_tech_specific_params_nfca_poll nfca_poll; + struct rf_tech_specific_params_nfcb_poll nfcb_poll; + struct rf_tech_specific_params_nfcf_poll nfcf_poll; } rf_tech_specific_params; __u8 data_exch_rf_tech_and_mode; @@ -300,6 +318,7 @@ struct nci_rf_intf_activated_ntf { union { struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep; + struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep; } activation_params; } __packed; diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 8696b773a69..819530d0e37 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -24,6 +24,7 @@ #ifndef __NET_NFC_H #define __NET_NFC_H +#include #include #include @@ -65,7 +66,6 @@ struct nfc_ops { #define NFC_TARGET_IDX_ANY -1 #define NFC_MAX_GT_LEN 48 -#define NFC_MAX_NFCID1_LEN 10 struct nfc_target { u32 idx; @@ -73,7 +73,11 @@ struct nfc_target { u16 sens_res; u8 sel_res; u8 nfcid1_len; - u8 nfcid1[NFC_MAX_NFCID1_LEN]; + u8 nfcid1[NFC_NFCID1_MAXSIZE]; + u8 sensb_res_len; + u8 sensb_res[NFC_SENSB_RES_MAXSIZE]; + u8 sensf_res_len; + u8 sensf_res[NFC_SENSF_RES_MAXSIZE]; }; struct nfc_genl_data { diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 10682bf7029..a88be91e973 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -115,15 +115,53 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, return data; } +static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, + struct nci_rf_intf_activated_ntf *ntf, __u8 *data) +{ + struct rf_tech_specific_params_nfcb_poll *nfcb_poll; + + nfcb_poll = &ntf->rf_tech_specific_params.nfcb_poll; + + nfcb_poll->sensb_res_len = *data++; + + pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); + + memcpy(nfcb_poll->sensb_res, data, nfcb_poll->sensb_res_len); + data += nfcb_poll->sensb_res_len; + + return data; +} + +static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, + struct nci_rf_intf_activated_ntf *ntf, __u8 *data) +{ + struct rf_tech_specific_params_nfcf_poll *nfcf_poll; + + nfcf_poll = &ntf->rf_tech_specific_params.nfcf_poll; + + nfcf_poll->bit_rate = *data++; + nfcf_poll->sensf_res_len = *data++; + + pr_debug("bit_rate %d, sensf_res_len %d\n", + nfcf_poll->bit_rate, nfcf_poll->sensf_res_len); + + memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len); + data += nfcf_poll->sensf_res_len; + + return data; +} + static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, struct nci_rf_intf_activated_ntf *ntf, __u8 *data) { struct activation_params_nfca_poll_iso_dep *nfca_poll; + struct activation_params_nfcb_poll_iso_dep *nfcb_poll; switch (ntf->activation_rf_tech_and_mode) { case NCI_NFC_A_PASSIVE_POLL_MODE: nfca_poll = &ntf->activation_params.nfca_poll_iso_dep; nfca_poll->rats_res_len = *data++; + pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len); if (nfca_poll->rats_res_len > 0) { memcpy(nfca_poll->rats_res, data, @@ -131,6 +169,18 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, } break; + case NCI_NFC_B_PASSIVE_POLL_MODE: + nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep; + nfcb_poll->attrib_res_len = *data++; + pr_debug("attrib_res_len %d\n", + nfcb_poll->attrib_res_len); + if (nfcb_poll->attrib_res_len > 0) { + memcpy(nfcb_poll->attrib_res, + data, + nfcb_poll->attrib_res_len); + } + break; + default: pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", ntf->activation_rf_tech_and_mode); @@ -145,21 +195,14 @@ static void nci_target_found(struct nci_dev *ndev, { struct nfc_target nfc_tgt; - if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T) /* T2T MifareUL */ + memset(&nfc_tgt, 0, sizeof(nfc_tgt)); + + if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T) nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK; - else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) /* 4A */ + else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK; - else - nfc_tgt.supported_protocols = 0; - - nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res; - nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res; - nfc_tgt.nfcid1_len = ntf->rf_tech_specific_params.nfca_poll.nfcid1_len; - if (nfc_tgt.nfcid1_len > 0) { - memcpy(nfc_tgt.nfcid1, - ntf->rf_tech_specific_params.nfca_poll.nfcid1, - nfc_tgt.nfcid1_len); - } + else if (ntf->rf_protocol == NCI_RF_PROTOCOL_T3T) + nfc_tgt.supported_protocols = NFC_PROTO_FELICA_MASK; if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) { pr_debug("the target found does not have the desired protocol\n"); @@ -169,6 +212,38 @@ static void nci_target_found(struct nci_dev *ndev, pr_debug("new target found, supported_protocols 0x%x\n", nfc_tgt.supported_protocols); + if (ntf->activation_rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) { + nfc_tgt.sens_res = + ntf->rf_tech_specific_params.nfca_poll.sens_res; + nfc_tgt.sel_res = + ntf->rf_tech_specific_params.nfca_poll.sel_res; + nfc_tgt.nfcid1_len = + ntf->rf_tech_specific_params.nfca_poll.nfcid1_len; + if (nfc_tgt.nfcid1_len > 0) { + memcpy(nfc_tgt.nfcid1, + ntf->rf_tech_specific_params.nfca_poll.nfcid1, + nfc_tgt.nfcid1_len); + } + } else if (ntf->activation_rf_tech_and_mode == + NCI_NFC_B_PASSIVE_POLL_MODE) { + nfc_tgt.sensb_res_len = + ntf->rf_tech_specific_params.nfcb_poll.sensb_res_len; + if (nfc_tgt.sensb_res_len > 0) { + memcpy(nfc_tgt.sensb_res, + ntf->rf_tech_specific_params.nfcb_poll.sensb_res, + nfc_tgt.sensb_res_len); + } + } else if (ntf->activation_rf_tech_and_mode == + NCI_NFC_F_PASSIVE_POLL_MODE) { + nfc_tgt.sensf_res_len = + ntf->rf_tech_specific_params.nfcf_poll.sensf_res_len; + if (nfc_tgt.sensf_res_len > 0) { + memcpy(nfc_tgt.sensf_res, + ntf->rf_tech_specific_params.nfcf_poll.sensf_res, + nfc_tgt.sensf_res_len); + } + } + ndev->target_available_prots = nfc_tgt.supported_protocols; ndev->max_data_pkt_payload_size = ntf->max_data_pkt_payload_size; ndev->initial_num_credits = ntf->initial_num_credits; @@ -215,6 +290,16 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, &ntf, data); break; + case NCI_NFC_B_PASSIVE_POLL_MODE: + data = nci_extract_rf_params_nfcb_passive_poll(ndev, + &ntf, data); + break; + + case NCI_NFC_F_PASSIVE_POLL_MODE: + data = nci_extract_rf_params_nfcf_passive_poll(ndev, + &ntf, data); + break; + default: pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", ntf.activation_rf_tech_and_mode); diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 6989dfa28ee..07f0348aabf 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -70,6 +70,12 @@ static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, if (target->nfcid1_len > 0) NLA_PUT(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len, target->nfcid1); + if (target->sensb_res_len > 0) + NLA_PUT(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len, + target->sensb_res); + if (target->sensf_res_len > 0) + NLA_PUT(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len, + target->sensf_res); return genlmsg_end(msg, hdr); -- cgit v1.2.3-70-g09d2 From 151a02f693b866dd43e147725c818fc1ddb96aa3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Jan 2012 10:30:01 +0100 Subject: mac80211: clean up aggregation destruction Yogesh's patch to destroy aggregation sessions when stations are destroyed was needed, but unnecessarily complex. Clean up this code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ff11f6bf826..a0900043266 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -815,35 +815,20 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) } #endif - /* There could be some memory leaks because of ampdu tx pending queue - * not being freed before destroying the station info. - * - * Make sure that such queues are purged before freeing the station - * info. - * TODO: We have to somehow postpone the full destruction - * until the aggregation stop completes. Refer - * http://thread.gmane.org/gmane.linux.kernel.wireless.general/81936 + /* + * Destroy aggregation state here. It would be nice to wait for the + * driver to finish aggregation stop and then clean up, but for now + * drivers have to handle aggregation stop being requested, followed + * directly by station destruction. */ - - mutex_lock(&sta->ampdu_mlme.mtx); - for (i = 0; i < STA_TID_NUM; i++) { - tid_tx = rcu_dereference_protected_tid_tx(sta, i); + tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); if (!tid_tx) continue; - if (skb_queue_len(&tid_tx->pending)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - wiphy_debug(local->hw.wiphy, "TX A-MPDU purging %d " - "packets for tid=%d\n", - skb_queue_len(&tid_tx->pending), i); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - __skb_queue_purge(&tid_tx->pending); - } - kfree_rcu(tid_tx, rcu_head); + __skb_queue_purge(&tid_tx->pending); + kfree(tid_tx); } - mutex_unlock(&sta->ampdu_mlme.mtx); - sta_info_free(local, sta); return 0; -- cgit v1.2.3-70-g09d2 From 889cbb911a195b832745f77240f547cb2a2885bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Jan 2012 10:33:29 +0100 Subject: mac80211: clean up rate control code It seems exceedingly unlikely that we'll ever support swapping rate control algorithms at runtime, so remove the unused refcounting code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rate.c | 27 ++++----------------------- net/mac80211/rate.h | 4 ---- net/mac80211/sta_info.c | 10 +++------- 3 files changed, 7 insertions(+), 34 deletions(-) (limited to 'net') diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 5a5a7767d54..a21110aecd1 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -159,7 +159,6 @@ static struct rate_control_ref *rate_control_alloc(const char *name, ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); if (!ref) goto fail_ref; - kref_init(&ref->kref); ref->local = local; ref->ops = ieee80211_rate_control_ops_get(name); if (!ref->ops) @@ -184,11 +183,8 @@ fail_ref: return NULL; } -static void rate_control_release(struct kref *kref) +static void rate_control_free(struct rate_control_ref *ctrl_ref) { - struct rate_control_ref *ctrl_ref; - - ctrl_ref = container_of(kref, struct rate_control_ref, kref); ctrl_ref->ops->free(ctrl_ref->priv); #ifdef CONFIG_MAC80211_DEBUGFS @@ -383,21 +379,10 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, BUG_ON(info->control.rates[0].idx < 0); } -struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) -{ - kref_get(&ref->kref); - return ref; -} - -void rate_control_put(struct rate_control_ref *ref) -{ - kref_put(&ref->kref, rate_control_release); -} - int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, const char *name) { - struct rate_control_ref *ref, *old; + struct rate_control_ref *ref; ASSERT_RTNL(); @@ -417,12 +402,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, return -ENOENT; } - old = local->rate_ctrl; + WARN_ON(local->rate_ctrl); local->rate_ctrl = ref; - if (old) { - rate_control_put(old); - sta_info_flush(local, NULL); - } wiphy_debug(local->hw.wiphy, "Selected rate control algorithm '%s'\n", ref->ops->name); @@ -440,6 +421,6 @@ void rate_control_deinitialize(struct ieee80211_local *local) return; local->rate_ctrl = NULL; - rate_control_put(ref); + rate_control_free(ref); } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 168427b0ffd..8268457bd14 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "ieee80211_i.h" #include "sta_info.h" @@ -23,14 +22,11 @@ struct rate_control_ref { struct ieee80211_local *local; struct rate_control_ops *ops; void *priv; - struct kref kref; }; void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_tx_rate_control *txrc); -struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); -void rate_control_put(struct rate_control_ref *ref); static inline void rate_control_tx_status(struct ieee80211_local *local, struct ieee80211_supported_band *sband, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a0900043266..f28fa02b6e5 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -208,10 +208,8 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, */ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { - if (sta->rate_ctrl) { + if (sta->rate_ctrl) rate_control_free_sta(sta); - rate_control_put(sta->rate_ctrl); - } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr); @@ -264,13 +262,11 @@ static int sta_prepare_rate_control(struct ieee80211_local *local, if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) return 0; - sta->rate_ctrl = rate_control_get(local->rate_ctrl); + sta->rate_ctrl = local->rate_ctrl; sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, &sta->sta, gfp); - if (!sta->rate_ctrl_priv) { - rate_control_put(sta->rate_ctrl); + if (!sta->rate_ctrl_priv) return -ENOMEM; - } return 0; } -- cgit v1.2.3-70-g09d2 From c4bf98b220cba7a8618405261d69ee53a265110e Mon Sep 17 00:00:00 2001 From: Ilan Elias Date: Tue, 17 Jan 2012 12:03:50 +0200 Subject: NFC: Add NCI data exchange timer Add NCI data exchange timer to catch timeouts, and call the data exchange callback with an error. Signed-off-by: Ilan Elias Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/nci_core.h | 3 +++ net/nfc/nci/core.c | 24 ++++++++++++++++++++++++ net/nfc/nci/data.c | 4 ++++ 3 files changed, 31 insertions(+) (limited to 'net') diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index f4963ea7794..9154663b606 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -41,6 +41,7 @@ enum { NCI_DISCOVERY, NCI_POLL_ACTIVE, NCI_DATA_EXCHANGE, + NCI_DATA_EXCHANGE_TO, }; /* NCI timeouts */ @@ -49,6 +50,7 @@ enum { #define NCI_RF_DISC_TIMEOUT 5000 #define NCI_RF_DEACTIVATE_TIMEOUT 30000 #define NCI_CMD_TIMEOUT 5000 +#define NCI_DATA_TIMEOUT 700 struct nci_dev; @@ -74,6 +76,7 @@ struct nci_dev { atomic_t credits_cnt; struct timer_list cmd_timer; + struct timer_list data_timer; struct workqueue_struct *cmd_wq; struct work_struct cmd_work; diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 7650139a1a0..815d28a0ed9 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -286,6 +286,7 @@ static int nci_close_device(struct nci_dev *ndev) if (!test_and_clear_bit(NCI_UP, &ndev->flags)) { del_timer_sync(&ndev->cmd_timer); + del_timer_sync(&ndev->data_timer); mutex_unlock(&ndev->req_lock); return 0; } @@ -331,6 +332,15 @@ static void nci_cmd_timer(unsigned long arg) queue_work(ndev->cmd_wq, &ndev->cmd_work); } +/* NCI data exchange timer function */ +static void nci_data_timer(unsigned long arg) +{ + struct nci_dev *ndev = (void *) arg; + + set_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags); + queue_work(ndev->rx_wq, &ndev->rx_work); +} + static int nci_dev_up(struct nfc_dev *nfc_dev) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); @@ -585,6 +595,8 @@ int nci_register_device(struct nci_dev *ndev) setup_timer(&ndev->cmd_timer, nci_cmd_timer, (unsigned long) ndev); + setup_timer(&ndev->data_timer, nci_data_timer, + (unsigned long) ndev); mutex_init(&ndev->req_lock); @@ -722,6 +734,9 @@ static void nci_tx_work(struct work_struct *work) nci_plen(skb->data)); nci_send_frame(skb); + + mod_timer(&ndev->data_timer, + jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT)); } } @@ -753,6 +768,15 @@ static void nci_rx_work(struct work_struct *work) break; } } + + /* check if a data exchange timout has occurred */ + if (test_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags)) { + /* complete the data exchange transaction, if exists */ + if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) + nci_data_exchange_complete(ndev, NULL, -ETIMEDOUT); + + clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags); + } } /* ----- NCI TX CMD worker thread ----- */ diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index e5756b30e60..7880ae924d5 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c @@ -44,6 +44,10 @@ void nci_data_exchange_complete(struct nci_dev *ndev, pr_debug("len %d, err %d\n", skb ? skb->len : 0, err); + /* data exchange is complete, stop the data timer */ + del_timer_sync(&ndev->data_timer); + clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags); + if (cb) { ndev->data_exchange_cb = NULL; ndev->data_exchange_cb_context = 0; -- cgit v1.2.3-70-g09d2 From 24dd0dd74ec8dc4abada132e380dc179459b0f77 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 18 Jan 2012 00:10:43 +0100 Subject: mac80211: add a 2-way Authentication challenge to IBSS mode In IBSS mode, whenever a new station is added a 2-way authentication challenge is performed. Actually this event can be used to recognise a new station joining the cell even if its sta_info entry is already in the list. Signed-off-by: Antonio Quartulli Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b253d0adf0a..a497c03c03d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -298,6 +298,13 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) /* If it fails, maybe we raced another insertion? */ if (sta_info_insert_rcu(sta)) return sta_info_get(sdata, addr); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM" + "(auth_transaction=1)\n", sdata->vif.addr, + sdata->u.ibss.bssid, addr); +#endif + ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, + addr, sdata->u.ibss.bssid, NULL, 0, 0); return sta; } -- cgit v1.2.3-70-g09d2 From 6d810f10325522cfcf498dc6d64b9f96e1f5153f Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 18 Jan 2012 00:10:44 +0100 Subject: mac80211: in IBSS use the Auth frame to trigger STA reinsertion In case of a node re-joining the cell the sta_info structure belonging to it is first destroyed and then reinserted. In this way its internal state is reset. The joining operation is recognised thank the Auth frame being received. This operation is helpful in case of a node being rebooted that is joining the ad-hoc cell again, before its purge timeout on other nodes expires. Signed-off-by: Antonio Quartulli Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 85 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 36 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a497c03c03d..d38baa41cf6 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -36,31 +36,6 @@ #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 -static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - u16 auth_alg, auth_transaction; - - lockdep_assert_held(&sdata->u.ibss.mtx); - - if (len < 24 + 6) - return; - - auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); - auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - - /* - * IEEE 802.11 standard does not require authentication in IBSS - * networks and most implementations do not seem to use it. - * However, try to reply to authentication attempts if someone - * has actually implemented this. - */ - if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) - ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, mgmt->sa, - sdata->u.ibss.bssid, NULL, 0, 0); -} - static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, const u8 *bssid, const int beacon_int, struct ieee80211_channel *chan, @@ -275,7 +250,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, cbss->tsf); } -static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) +static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, + bool auth) __acquires(RCU) { struct ieee80211_sub_if_data *sdata = sta->sdata; @@ -298,20 +274,22 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) /* If it fails, maybe we raced another insertion? */ if (sta_info_insert_rcu(sta)) return sta_info_get(sdata, addr); + if (auth) { #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM" - "(auth_transaction=1)\n", sdata->vif.addr, - sdata->u.ibss.bssid, addr); + printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM" + "(auth_transaction=1)\n", sdata->vif.addr, + sdata->u.ibss.bssid, addr); #endif - ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, - addr, sdata->u.ibss.bssid, NULL, 0, 0); + ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, + addr, sdata->u.ibss.bssid, NULL, 0, 0); + } return sta; } static struct sta_info * ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, const u8 *addr, - u32 supp_rates) + u32 supp_rates, bool auth) __acquires(RCU) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; @@ -353,7 +331,42 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, sta->sta.supp_rates[band] = supp_rates | ieee80211_mandatory_rates(local, band); - return ieee80211_ibss_finish_sta(sta); + return ieee80211_ibss_finish_sta(sta, auth); +} + +static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + u16 auth_alg, auth_transaction; + + lockdep_assert_held(&sdata->u.ibss.mtx); + + if (len < 24 + 6) + return; + + auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); + auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); + + if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) + return; +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM." + "(auth_transaction=%d)\n", + sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); +#endif + sta_info_destroy_addr(sdata, mgmt->sa); + ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); + rcu_read_unlock(); + + /* + * IEEE 802.11 standard does not require authentication in IBSS + * networks and most implementations do not seem to use it. + * However, try to reply to authentication attempts if someone + * has actually implemented this. + */ + ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, + mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); } static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, @@ -418,7 +431,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, } else { rcu_read_unlock(); sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, - mgmt->sa, supp_rates); + mgmt->sa, supp_rates, true); } } @@ -546,7 +559,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ieee80211_sta_join_ibss(sdata, bss); supp_rates = ieee80211_sta_get_rates(local, elems, band); ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, - supp_rates); + supp_rates, true); rcu_read_unlock(); } @@ -947,7 +960,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) list_del(&sta->list); spin_unlock_bh(&ifibss->incomplete_lock); - ieee80211_ibss_finish_sta(sta); + ieee80211_ibss_finish_sta(sta, true); rcu_read_unlock(); spin_lock_bh(&ifibss->incomplete_lock); } -- cgit v1.2.3-70-g09d2 From 8939e47fc953cce6ef53e79e9ff9b53319d1a72d Mon Sep 17 00:00:00 2001 From: Ilan Elias Date: Wed, 18 Jan 2012 13:16:12 +0200 Subject: NFC: Clearly separate NCI states from flags Make a clear separation between NCI states and flags. This is required in order to support more NCI states (e.g. for multiple targets support). Signed-off-by: Ilan Elias Signed-off-by: John W. Linville --- include/net/nfc/nci_core.h | 14 ++++++++++---- net/nfc/nci/core.c | 11 ++++++----- net/nfc/nci/ntf.c | 5 ++--- net/nfc/nci/rsp.c | 8 ++++---- 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 9154663b606..b9c3f8de13d 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -34,16 +34,21 @@ #include #include -/* NCI device state */ -enum { +/* NCI device flags */ +enum nci_flag { NCI_INIT, NCI_UP, - NCI_DISCOVERY, - NCI_POLL_ACTIVE, NCI_DATA_EXCHANGE, NCI_DATA_EXCHANGE_TO, }; +/* NCI device states */ +enum nci_state { + NCI_IDLE, + NCI_DISCOVERY, + NCI_POLL_ACTIVE, +}; + /* NCI timeouts */ #define NCI_RESET_TIMEOUT 5000 #define NCI_INIT_TIMEOUT 5000 @@ -70,6 +75,7 @@ struct nci_dev { int tx_headroom; int tx_tailroom; + atomic_t state; unsigned long flags; atomic_t cmd_cnt; diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 815d28a0ed9..629b7684597 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -264,6 +264,7 @@ static int nci_open_device(struct nci_dev *ndev) if (!rc) { set_bit(NCI_UP, &ndev->flags); + atomic_set(&ndev->state, NCI_IDLE); } else { /* Init failed, cleanup */ skb_queue_purge(&ndev->cmd_q); @@ -360,7 +361,7 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); int rc; - if (test_bit(NCI_DISCOVERY, &ndev->flags)) { + if (atomic_read(&ndev->state) == NCI_DISCOVERY) { pr_err("unable to start poll, since poll is already active\n"); return -EBUSY; } @@ -370,7 +371,7 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) return -EBUSY; } - if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) { + if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { pr_debug("target is active, implicitly deactivate...\n"); rc = nci_request(ndev, nci_rf_deactivate_req, 0, @@ -392,7 +393,7 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); - if (!test_bit(NCI_DISCOVERY, &ndev->flags)) { + if (atomic_read(&ndev->state) != NCI_DISCOVERY) { pr_err("unable to stop poll, since poll is not active\n"); return; } @@ -408,7 +409,7 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); - if (!test_bit(NCI_POLL_ACTIVE, &ndev->flags)) { + if (atomic_read(&ndev->state) != NCI_POLL_ACTIVE) { pr_err("there is no available target to activate\n"); return -EINVAL; } @@ -443,7 +444,7 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) ndev->target_active_prot = 0; - if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) { + if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { nci_request(ndev, nci_rf_deactivate_req, 0, msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); } diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index a88be91e973..8ec39464cea 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -261,8 +261,7 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, __u8 *data = skb->data; int err = 0; - clear_bit(NCI_DISCOVERY, &ndev->flags); - set_bit(NCI_POLL_ACTIVE, &ndev->flags); + atomic_set(&ndev->state, NCI_POLL_ACTIVE); ntf.rf_discovery_id = *data++; ntf.rf_interface = *data++; @@ -350,7 +349,7 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason); - clear_bit(NCI_POLL_ACTIVE, &ndev->flags); + atomic_set(&ndev->state, NCI_IDLE); ndev->target_active_prot = 0; /* drop tx data queue */ diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 3c73e92eb62..cb8bce6899c 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -137,7 +137,7 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) pr_debug("status 0x%x\n", status); if (status == NCI_STATUS_OK) - set_bit(NCI_DISCOVERY, &ndev->flags); + atomic_set(&ndev->state, NCI_DISCOVERY); nci_req_complete(ndev, status); } @@ -149,12 +149,12 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, pr_debug("status 0x%x\n", status); - clear_bit(NCI_DISCOVERY, &ndev->flags); - /* If target was active, complete the request only in deactivate_ntf */ if ((status != NCI_STATUS_OK) || - (!test_bit(NCI_POLL_ACTIVE, &ndev->flags))) + (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { + atomic_set(&ndev->state, NCI_IDLE); nci_req_complete(ndev, status); + } } void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 25a1d9dc850b1bdcc4760eb625f0a67057f54d26 Mon Sep 17 00:00:00 2001 From: Ilan Elias Date: Wed, 18 Jan 2012 13:16:13 +0200 Subject: NFC: NFC core layer should not set the target_idx The NFC core layer should not set the target_idx. Instead, the driver layer (e.g. NCI, PN533) should set the target_idx, so that it will be able to identify the target when its I/F (e.g. activate_target) is called. This is required in order to support multiple targets. Note that currently supported drivers (PN533 and NCI) don't use the target_idx in their implementation. Signed-off-by: Ilan Elias Signed-off-by: John W. Linville --- include/net/nfc/nfc.h | 1 - net/nfc/core.c | 5 ----- net/nfc/rawsock.c | 12 ------------ 3 files changed, 18 deletions(-) (limited to 'net') diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 819530d0e37..d253278e5a9 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -87,7 +87,6 @@ struct nfc_genl_data { struct nfc_dev { unsigned idx; - unsigned target_idx; struct nfc_target *targets; int n_targets; int targets_generation; diff --git a/net/nfc/core.c b/net/nfc/core.c index 3ddf6e698df..6089aca67b1 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -431,15 +431,10 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, int n_targets) { - int i; - pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); dev->polling = false; - for (i = 0; i < n_targets; i++) - targets[i].idx = dev->target_idx++; - spin_lock_bh(&dev->targets_lock); dev->targets_generation++; diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 2e2f8c6a61f..5325439b0c6 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -92,18 +92,6 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr, goto error; } - if (addr->target_idx > dev->target_idx - 1 || - addr->target_idx < dev->target_idx - dev->n_targets) { - rc = -EINVAL; - goto error; - } - - if (addr->target_idx > dev->target_idx - 1 || - addr->target_idx < dev->target_idx - dev->n_targets) { - rc = -EINVAL; - goto error; - } - rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol); if (rc) goto put_dev; -- cgit v1.2.3-70-g09d2 From 019c4fbaa790e2b3f11dab0c8b7d9896d77db3e5 Mon Sep 17 00:00:00 2001 From: Ilan Elias Date: Wed, 18 Jan 2012 13:16:14 +0200 Subject: NFC: Add NCI multiple targets support Add the ability to select between multiple targets in NCI. If only one target is found, it will be auto-activated. If more than one target is found, then DISCOVER_NTF will be generated for each target, and the host should select one by calling DISCOVER_SELECT_CMD. Then, the target will be activated. If the activation fails, GENERIC_ERROR_NTF is generated. Signed-off-by: Ilan Elias Signed-off-by: John W. Linville --- include/net/nfc/nci.h | 34 ++++- include/net/nfc/nci_core.h | 9 +- net/nfc/nci/core.c | 91 +++++++++++-- net/nfc/nci/ntf.c | 323 +++++++++++++++++++++++++++++++++------------ net/nfc/nci/rsp.c | 17 +++ 5 files changed, 378 insertions(+), 96 deletions(-) (limited to 'net') diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h index 34f5ed29c3c..276094b91d7 100644 --- a/include/net/nfc/nci.h +++ b/include/net/nfc/nci.h @@ -116,6 +116,11 @@ #define NCI_DISC_MAP_MODE_POLL 0x01 #define NCI_DISC_MAP_MODE_LISTEN 0x02 +/* NCI Discover Notification Type */ +#define NCI_DISCOVER_NTF_TYPE_LAST 0x00 +#define NCI_DISCOVER_NTF_TYPE_LAST_NFCC 0x01 +#define NCI_DISCOVER_NTF_TYPE_MORE 0x02 + /* NCI Deactivation Type */ #define NCI_DEACTIVATE_TYPE_IDLE_MODE 0x00 #define NCI_DEACTIVATE_TYPE_SLEEP_MODE 0x01 @@ -207,6 +212,13 @@ struct nci_rf_disc_cmd { struct disc_config disc_configs[NCI_MAX_NUM_RF_CONFIGS]; } __packed; +#define NCI_OP_RF_DISCOVER_SELECT_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x04) +struct nci_rf_discover_select_cmd { + __u8 rf_discovery_id; + __u8 rf_protocol; + __u8 rf_interface; +} __packed; + #define NCI_OP_RF_DEACTIVATE_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x06) struct nci_rf_deactivate_cmd { __u8 type; @@ -244,6 +256,8 @@ struct nci_core_init_rsp_2 { #define NCI_OP_RF_DISCOVER_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x03) +#define NCI_OP_RF_DISCOVER_SELECT_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x04) + #define NCI_OP_RF_DEACTIVATE_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x06) /* --------------------------- */ @@ -260,13 +274,15 @@ struct nci_core_conn_credit_ntf { struct conn_credit_entry conn_entries[NCI_MAX_NUM_CONN]; } __packed; +#define NCI_OP_CORE_GENERIC_ERROR_NTF nci_opcode_pack(NCI_GID_CORE, 0x07) + #define NCI_OP_CORE_INTF_ERROR_NTF nci_opcode_pack(NCI_GID_CORE, 0x08) struct nci_core_intf_error_ntf { __u8 status; __u8 conn_id; } __packed; -#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05) +#define NCI_OP_RF_DISCOVER_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x03) struct rf_tech_specific_params_nfca_poll { __u16 sens_res; __u8 nfcid1_len; /* 0, 4, 7, or 10 Bytes */ @@ -286,6 +302,22 @@ struct rf_tech_specific_params_nfcf_poll { __u8 sensf_res[18]; /* 16 or 18 Bytes */ } __packed; +struct nci_rf_discover_ntf { + __u8 rf_discovery_id; + __u8 rf_protocol; + __u8 rf_tech_and_mode; + __u8 rf_tech_specific_params_len; + + union { + struct rf_tech_specific_params_nfca_poll nfca_poll; + struct rf_tech_specific_params_nfcb_poll nfcb_poll; + struct rf_tech_specific_params_nfcf_poll nfcf_poll; + } rf_tech_specific_params; + + __u8 ntf_type; +} __packed; + +#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05) struct activation_params_nfca_poll_iso_dep { __u8 rats_res_len; __u8 rats_res[20]; diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index b9c3f8de13d..86fee8b5c65 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -46,6 +46,8 @@ enum nci_flag { enum nci_state { NCI_IDLE, NCI_DISCOVERY, + NCI_W4_ALL_DISCOVERIES, + NCI_W4_HOST_SELECT, NCI_POLL_ACTIVE, }; @@ -53,6 +55,7 @@ enum nci_state { #define NCI_RESET_TIMEOUT 5000 #define NCI_INIT_TIMEOUT 5000 #define NCI_RF_DISC_TIMEOUT 5000 +#define NCI_RF_DISC_SELECT_TIMEOUT 5000 #define NCI_RF_DEACTIVATE_TIMEOUT 30000 #define NCI_CMD_TIMEOUT 5000 #define NCI_DATA_TIMEOUT 700 @@ -66,6 +69,7 @@ struct nci_ops { }; #define NCI_MAX_SUPPORTED_RF_INTERFACES 4 +#define NCI_MAX_DISCOVERED_TARGETS 10 /* NCI Core structures */ struct nci_dev { @@ -105,9 +109,11 @@ struct nci_dev { void *driver_data; __u32 poll_prots; - __u32 target_available_prots; __u32 target_active_prot; + struct nfc_target targets[NCI_MAX_DISCOVERED_TARGETS]; + int n_targets; + /* received during NCI_OP_CORE_RESET_RSP */ __u8 nci_ver; @@ -178,6 +184,7 @@ int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload); int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb); void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb, int err); +void nci_clear_target_list(struct nci_dev *ndev); /* ----- NCI requests ----- */ #define NCI_REQ_DONE 0 diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 629b7684597..12d1d4d6267 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -216,6 +216,39 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) &cmd); } +struct nci_rf_discover_select_param { + __u8 rf_discovery_id; + __u8 rf_protocol; +}; + +static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt) +{ + struct nci_rf_discover_select_param *param = + (struct nci_rf_discover_select_param *)opt; + struct nci_rf_discover_select_cmd cmd; + + cmd.rf_discovery_id = param->rf_discovery_id; + cmd.rf_protocol = param->rf_protocol; + + switch (cmd.rf_protocol) { + case NCI_RF_PROTOCOL_ISO_DEP: + cmd.rf_interface = NCI_RF_INTERFACE_ISO_DEP; + break; + + case NCI_RF_PROTOCOL_NFC_DEP: + cmd.rf_interface = NCI_RF_INTERFACE_NFC_DEP; + break; + + default: + cmd.rf_interface = NCI_RF_INTERFACE_FRAME; + break; + } + + nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD, + sizeof(struct nci_rf_discover_select_cmd), + &cmd); +} + static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt) { struct nci_rf_deactivate_cmd cmd; @@ -264,6 +297,7 @@ static int nci_open_device(struct nci_dev *ndev) if (!rc) { set_bit(NCI_UP, &ndev->flags); + nci_clear_target_list(ndev); atomic_set(&ndev->state, NCI_IDLE); } else { /* Init failed, cleanup */ @@ -361,7 +395,8 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); int rc; - if (atomic_read(&ndev->state) == NCI_DISCOVERY) { + if ((atomic_read(&ndev->state) == NCI_DISCOVERY) || + (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) { pr_err("unable to start poll, since poll is already active\n"); return -EBUSY; } @@ -371,8 +406,9 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) return -EBUSY; } - if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { - pr_debug("target is active, implicitly deactivate...\n"); + if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) || + (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) { + pr_debug("target active or w4 select, implicitly deactivate\n"); rc = nci_request(ndev, nci_rf_deactivate_req, 0, msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); @@ -393,7 +429,8 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); - if (atomic_read(&ndev->state) != NCI_DISCOVERY) { + if ((atomic_read(&ndev->state) != NCI_DISCOVERY) && + (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) { pr_err("unable to stop poll, since poll is not active\n"); return; } @@ -406,10 +443,15 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, __u32 protocol) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); + struct nci_rf_discover_select_param param; + struct nfc_target *target = 0; + int i; + int rc = 0; pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); - if (atomic_read(&ndev->state) != NCI_POLL_ACTIVE) { + if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) && + (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { pr_err("there is no available target to activate\n"); return -EINVAL; } @@ -419,16 +461,47 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, return -EBUSY; } - if (!(ndev->target_available_prots & (1 << protocol))) { + for (i = 0; i < ndev->n_targets; i++) { + if (ndev->targets[i].idx == target_idx) { + target = &ndev->targets[i]; + break; + } + } + + if (!target) { + pr_err("unable to find the selected target\n"); + return -EINVAL; + } + + if (!(target->supported_protocols & (1 << protocol))) { pr_err("target does not support the requested protocol 0x%x\n", protocol); return -EINVAL; } - ndev->target_active_prot = protocol; - ndev->target_available_prots = 0; + if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { + param.rf_discovery_id = target->idx; - return 0; + if (protocol == NFC_PROTO_JEWEL) + param.rf_protocol = NCI_RF_PROTOCOL_T1T; + else if (protocol == NFC_PROTO_MIFARE) + param.rf_protocol = NCI_RF_PROTOCOL_T2T; + else if (protocol == NFC_PROTO_FELICA) + param.rf_protocol = NCI_RF_PROTOCOL_T3T; + else if (protocol == NFC_PROTO_ISO14443) + param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; + else + param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; + + rc = nci_request(ndev, nci_rf_discover_select_req, + (unsigned long)¶m, + msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT)); + } + + if (!rc) + ndev->target_active_prot = protocol; + + return rc; } static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 8ec39464cea..03e7b4626a3 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -71,6 +71,20 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev, queue_work(ndev->tx_wq, &ndev->tx_work); } +static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev, + struct sk_buff *skb) +{ + __u8 status = skb->data[0]; + + pr_debug("status 0x%x\n", status); + + if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { + /* Activation failed, so complete the request + (the state remains the same) */ + nci_req_complete(ndev, status); + } +} + static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb) { @@ -86,12 +100,9 @@ static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, } static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, - struct nci_rf_intf_activated_ntf *ntf, __u8 *data) + struct rf_tech_specific_params_nfca_poll *nfca_poll, + __u8 *data) { - struct rf_tech_specific_params_nfca_poll *nfca_poll; - - nfca_poll = &ntf->rf_tech_specific_params.nfca_poll; - nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); data += 2; @@ -116,12 +127,9 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, } static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, - struct nci_rf_intf_activated_ntf *ntf, __u8 *data) + struct rf_tech_specific_params_nfcb_poll *nfcb_poll, + __u8 *data) { - struct rf_tech_specific_params_nfcb_poll *nfcb_poll; - - nfcb_poll = &ntf->rf_tech_specific_params.nfcb_poll; - nfcb_poll->sensb_res_len = *data++; pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); @@ -133,12 +141,9 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, } static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, - struct nci_rf_intf_activated_ntf *ntf, __u8 *data) + struct rf_tech_specific_params_nfcf_poll *nfcf_poll, + __u8 *data) { - struct rf_tech_specific_params_nfcf_poll *nfcf_poll; - - nfcf_poll = &ntf->rf_tech_specific_params.nfcf_poll; - nfcf_poll->bit_rate = *data++; nfcf_poll->sensf_res_len = *data++; @@ -151,6 +156,172 @@ static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, return data; } +static int nci_add_new_protocol(struct nci_dev *ndev, + struct nfc_target *target, + __u8 rf_protocol, + __u8 rf_tech_and_mode, + void *params) +{ + struct rf_tech_specific_params_nfca_poll *nfca_poll; + struct rf_tech_specific_params_nfcb_poll *nfcb_poll; + struct rf_tech_specific_params_nfcf_poll *nfcf_poll; + __u32 protocol; + + if (rf_protocol == NCI_RF_PROTOCOL_T2T) + protocol = NFC_PROTO_MIFARE_MASK; + else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) + protocol = NFC_PROTO_ISO14443_MASK; + else if (rf_protocol == NCI_RF_PROTOCOL_T3T) + protocol = NFC_PROTO_FELICA_MASK; + else + protocol = 0; + + if (!(protocol & ndev->poll_prots)) { + pr_err("the target found does not have the desired protocol\n"); + return -EPROTO; + } + + if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) { + nfca_poll = (struct rf_tech_specific_params_nfca_poll *)params; + + target->sens_res = nfca_poll->sens_res; + target->sel_res = nfca_poll->sel_res; + target->nfcid1_len = nfca_poll->nfcid1_len; + if (target->nfcid1_len > 0) { + memcpy(target->nfcid1, nfca_poll->nfcid1, + target->nfcid1_len); + } + } else if (rf_tech_and_mode == NCI_NFC_B_PASSIVE_POLL_MODE) { + nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params; + + target->sensb_res_len = nfcb_poll->sensb_res_len; + if (target->sensb_res_len > 0) { + memcpy(target->sensb_res, nfcb_poll->sensb_res, + target->sensb_res_len); + } + } else if (rf_tech_and_mode == NCI_NFC_F_PASSIVE_POLL_MODE) { + nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params; + + target->sensf_res_len = nfcf_poll->sensf_res_len; + if (target->sensf_res_len > 0) { + memcpy(target->sensf_res, nfcf_poll->sensf_res, + target->sensf_res_len); + } + } else { + pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode); + return -EPROTO; + } + + target->supported_protocols |= protocol; + + pr_debug("protocol 0x%x\n", protocol); + + return 0; +} + +static void nci_add_new_target(struct nci_dev *ndev, + struct nci_rf_discover_ntf *ntf) +{ + struct nfc_target *target; + int i, rc; + + for (i = 0; i < ndev->n_targets; i++) { + target = &ndev->targets[i]; + if (target->idx == ntf->rf_discovery_id) { + /* This target already exists, add the new protocol */ + nci_add_new_protocol(ndev, target, ntf->rf_protocol, + ntf->rf_tech_and_mode, + &ntf->rf_tech_specific_params); + return; + } + } + + /* This is a new target, check if we've enough room */ + if (ndev->n_targets == NCI_MAX_DISCOVERED_TARGETS) { + pr_debug("not enough room, ignoring new target...\n"); + return; + } + + target = &ndev->targets[ndev->n_targets]; + + rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, + ntf->rf_tech_and_mode, + &ntf->rf_tech_specific_params); + if (!rc) { + target->idx = ntf->rf_discovery_id; + ndev->n_targets++; + + pr_debug("target_idx %d, n_targets %d\n", target->idx, + ndev->n_targets); + } +} + +void nci_clear_target_list(struct nci_dev *ndev) +{ + memset(ndev->targets, 0, + (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS)); + + ndev->n_targets = 0; +} + +static void nci_rf_discover_ntf_packet(struct nci_dev *ndev, + struct sk_buff *skb) +{ + struct nci_rf_discover_ntf ntf; + __u8 *data = skb->data; + bool add_target = true; + + ntf.rf_discovery_id = *data++; + ntf.rf_protocol = *data++; + ntf.rf_tech_and_mode = *data++; + ntf.rf_tech_specific_params_len = *data++; + + pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id); + pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol); + pr_debug("rf_tech_and_mode 0x%x\n", ntf.rf_tech_and_mode); + pr_debug("rf_tech_specific_params_len %d\n", + ntf.rf_tech_specific_params_len); + + if (ntf.rf_tech_specific_params_len > 0) { + switch (ntf.rf_tech_and_mode) { + case NCI_NFC_A_PASSIVE_POLL_MODE: + data = nci_extract_rf_params_nfca_passive_poll(ndev, + &(ntf.rf_tech_specific_params.nfca_poll), data); + break; + + case NCI_NFC_B_PASSIVE_POLL_MODE: + data = nci_extract_rf_params_nfcb_passive_poll(ndev, + &(ntf.rf_tech_specific_params.nfcb_poll), data); + break; + + case NCI_NFC_F_PASSIVE_POLL_MODE: + data = nci_extract_rf_params_nfcf_passive_poll(ndev, + &(ntf.rf_tech_specific_params.nfcf_poll), data); + break; + + default: + pr_err("unsupported rf_tech_and_mode 0x%x\n", + ntf.rf_tech_and_mode); + data += ntf.rf_tech_specific_params_len; + add_target = false; + } + } + + ntf.ntf_type = *data++; + pr_debug("ntf_type %d\n", ntf.ntf_type); + + if (add_target == true) + nci_add_new_target(ndev, &ntf); + + if (ntf.ntf_type == NCI_DISCOVER_NTF_TYPE_MORE) { + atomic_set(&ndev->state, NCI_W4_ALL_DISCOVERIES); + } else { + atomic_set(&ndev->state, NCI_W4_HOST_SELECT); + nfc_targets_found(ndev->nfc_dev, ndev->targets, + ndev->n_targets); + } +} + static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, struct nci_rf_intf_activated_ntf *ntf, __u8 *data) { @@ -184,74 +355,32 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, default: pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", ntf->activation_rf_tech_and_mode); - return -EPROTO; + return NCI_STATUS_RF_PROTOCOL_ERROR; } - return 0; + return NCI_STATUS_OK; } -static void nci_target_found(struct nci_dev *ndev, - struct nci_rf_intf_activated_ntf *ntf) +static void nci_target_auto_activated(struct nci_dev *ndev, + struct nci_rf_intf_activated_ntf *ntf) { - struct nfc_target nfc_tgt; + struct nfc_target *target; + int rc; - memset(&nfc_tgt, 0, sizeof(nfc_tgt)); + target = &ndev->targets[ndev->n_targets]; - if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T) - nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK; - else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) - nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK; - else if (ntf->rf_protocol == NCI_RF_PROTOCOL_T3T) - nfc_tgt.supported_protocols = NFC_PROTO_FELICA_MASK; - - if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) { - pr_debug("the target found does not have the desired protocol\n"); + rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, + ntf->activation_rf_tech_and_mode, + &ntf->rf_tech_specific_params); + if (rc) return; - } - pr_debug("new target found, supported_protocols 0x%x\n", - nfc_tgt.supported_protocols); - - if (ntf->activation_rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) { - nfc_tgt.sens_res = - ntf->rf_tech_specific_params.nfca_poll.sens_res; - nfc_tgt.sel_res = - ntf->rf_tech_specific_params.nfca_poll.sel_res; - nfc_tgt.nfcid1_len = - ntf->rf_tech_specific_params.nfca_poll.nfcid1_len; - if (nfc_tgt.nfcid1_len > 0) { - memcpy(nfc_tgt.nfcid1, - ntf->rf_tech_specific_params.nfca_poll.nfcid1, - nfc_tgt.nfcid1_len); - } - } else if (ntf->activation_rf_tech_and_mode == - NCI_NFC_B_PASSIVE_POLL_MODE) { - nfc_tgt.sensb_res_len = - ntf->rf_tech_specific_params.nfcb_poll.sensb_res_len; - if (nfc_tgt.sensb_res_len > 0) { - memcpy(nfc_tgt.sensb_res, - ntf->rf_tech_specific_params.nfcb_poll.sensb_res, - nfc_tgt.sensb_res_len); - } - } else if (ntf->activation_rf_tech_and_mode == - NCI_NFC_F_PASSIVE_POLL_MODE) { - nfc_tgt.sensf_res_len = - ntf->rf_tech_specific_params.nfcf_poll.sensf_res_len; - if (nfc_tgt.sensf_res_len > 0) { - memcpy(nfc_tgt.sensf_res, - ntf->rf_tech_specific_params.nfcf_poll.sensf_res, - nfc_tgt.sensf_res_len); - } - } + target->idx = ntf->rf_discovery_id; + ndev->n_targets++; - ndev->target_available_prots = nfc_tgt.supported_protocols; - ndev->max_data_pkt_payload_size = ntf->max_data_pkt_payload_size; - ndev->initial_num_credits = ntf->initial_num_credits; + pr_debug("target_idx %d, n_targets %d\n", target->idx, ndev->n_targets); - /* set the available credits to initial value */ - atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); - - nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1); + nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets); } static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, @@ -259,9 +388,7 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, { struct nci_rf_intf_activated_ntf ntf; __u8 *data = skb->data; - int err = 0; - - atomic_set(&ndev->state, NCI_POLL_ACTIVE); + int err = NCI_STATUS_OK; ntf.rf_discovery_id = *data++; ntf.rf_interface = *data++; @@ -286,23 +413,24 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, switch (ntf.activation_rf_tech_and_mode) { case NCI_NFC_A_PASSIVE_POLL_MODE: data = nci_extract_rf_params_nfca_passive_poll(ndev, - &ntf, data); + &(ntf.rf_tech_specific_params.nfca_poll), data); break; case NCI_NFC_B_PASSIVE_POLL_MODE: data = nci_extract_rf_params_nfcb_passive_poll(ndev, - &ntf, data); + &(ntf.rf_tech_specific_params.nfcb_poll), data); break; case NCI_NFC_F_PASSIVE_POLL_MODE: data = nci_extract_rf_params_nfcf_passive_poll(ndev, - &ntf, data); + &(ntf.rf_tech_specific_params.nfcf_poll), data); break; default: pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", ntf.activation_rf_tech_and_mode); - return; + err = NCI_STATUS_RF_PROTOCOL_ERROR; + goto exit; } } @@ -334,12 +462,30 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, default: pr_err("unsupported rf_interface 0x%x\n", ntf.rf_interface); - return; + err = NCI_STATUS_RF_PROTOCOL_ERROR; + break; } } - if (!err) - nci_target_found(ndev, &ntf); +exit: + if (err == NCI_STATUS_OK) { + ndev->max_data_pkt_payload_size = ntf.max_data_pkt_payload_size; + ndev->initial_num_credits = ntf.initial_num_credits; + + /* set the available credits to initial value */ + atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); + } + + if (atomic_read(&ndev->state) == NCI_DISCOVERY) { + /* A single target was found and activated automatically */ + atomic_set(&ndev->state, NCI_POLL_ACTIVE); + if (err == NCI_STATUS_OK) + nci_target_auto_activated(ndev, &ntf); + } else { /* ndev->state == NCI_W4_HOST_SELECT */ + /* A selected target was activated, so complete the request */ + atomic_set(&ndev->state, NCI_POLL_ACTIVE); + nci_req_complete(ndev, err); + } } static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, @@ -349,9 +495,6 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason); - atomic_set(&ndev->state, NCI_IDLE); - ndev->target_active_prot = 0; - /* drop tx data queue */ skb_queue_purge(&ndev->tx_q); @@ -365,6 +508,8 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) nci_data_exchange_complete(ndev, NULL, -EIO); + nci_clear_target_list(ndev); + atomic_set(&ndev->state, NCI_IDLE); nci_req_complete(ndev, NCI_STATUS_OK); } @@ -386,10 +531,18 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb) nci_core_conn_credits_ntf_packet(ndev, skb); break; + case NCI_OP_CORE_GENERIC_ERROR_NTF: + nci_core_generic_error_ntf_packet(ndev, skb); + break; + case NCI_OP_CORE_INTF_ERROR_NTF: nci_core_conn_intf_error_ntf_packet(ndev, skb); break; + case NCI_OP_RF_DISCOVER_NTF: + nci_rf_discover_ntf_packet(ndev, skb); + break; + case NCI_OP_RF_INTF_ACTIVATED_NTF: nci_rf_intf_activated_ntf_packet(ndev, skb); break; diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index cb8bce6899c..aa63b1e9918 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -142,6 +142,18 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) nci_req_complete(ndev, status); } +static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev, + struct sk_buff *skb) +{ + __u8 status = skb->data[0]; + + pr_debug("status 0x%x\n", status); + + /* Complete the request on intf_activated_ntf or generic_error_ntf */ + if (status != NCI_STATUS_OK) + nci_req_complete(ndev, status); +} + static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) { @@ -152,6 +164,7 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, /* If target was active, complete the request only in deactivate_ntf */ if ((status != NCI_STATUS_OK) || (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { + nci_clear_target_list(ndev); atomic_set(&ndev->state, NCI_IDLE); nci_req_complete(ndev, status); } @@ -190,6 +203,10 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) nci_rf_disc_rsp_packet(ndev, skb); break; + case NCI_OP_RF_DISCOVER_SELECT_RSP: + nci_rf_disc_select_rsp_packet(ndev, skb); + break; + case NCI_OP_RF_DEACTIVATE_RSP: nci_rf_deactivate_rsp_packet(ndev, skb); break; -- cgit v1.2.3-70-g09d2 From 496053f488fc2d859e41574f3421993826d2d0eb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 11 Jan 2012 16:46:32 -0800 Subject: ipv4: Remove bogus checks of rt_gateway being zero. It can never actually happen. rt_gateway is either the fully resolved flow lookup key's destination address, or the non-zero FIB entry gateway address. Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 8 +++----- net/ipv4/ipip.c | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 2b53a1f7abf..fc213350a6e 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -724,11 +724,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev goto tx_error; } - if (skb->protocol == htons(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) rt = skb_rtable(skb); - if ((dst = rt->rt_gateway) == 0) - goto tx_error_icmp; - } #if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) { struct neighbour *neigh = dst_get_neighbour_noref(skb_dst(skb)); @@ -910,9 +907,10 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev __IPTUNNEL_XMIT(tstats, &dev->stats); return NETDEV_TX_OK; +#if IS_ENABLED(CONFIG_IPV6) tx_error_icmp: dst_link_failure(skb); - +#endif tx_error: dev->stats.tx_errors++; dev_kfree_skb(skb); diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 22a19931530..87c63b67f8c 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -454,8 +454,6 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_fifo_errors++; goto tx_error; } - if ((dst = rt->rt_gateway) == 0) - goto tx_error_icmp; } rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, -- cgit v1.2.3-70-g09d2 From 658c8d964eb3cdb7e4230a59ba09c75a3359ee4a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 24 Jan 2012 18:18:05 -0500 Subject: ipip: Fix bug added to ipip_tunnel_xmit(). We can remove the rt_gateway == 0 check but we shouldn't remove the 'dst' initialization too. Noticed by Eric Dumazet. Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 87c63b67f8c..f84ebff5cdb 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -454,6 +454,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_fifo_errors++; goto tx_error; } + dst = rt->rt_gateway; } rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, -- cgit v1.2.3-70-g09d2 From 61d57f87f3fb04a305f22befabd042ffbec8b852 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 24 Jan 2012 18:23:30 -0500 Subject: ip_gre: Fix bug added to ipgre_tunnel_xmit(). We can remove the rt_gateway == 0 check but we shouldn't remove the 'dst' initialization too. Noticed by Eric Dumazet. Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index fc213350a6e..05f7419ed7c 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -724,8 +724,10 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev goto tx_error; } - if (skb->protocol == htons(ETH_P_IP)) + if (skb->protocol == htons(ETH_P_IP)) { rt = skb_rtable(skb); + dst = rt->rt_gateway; + } #if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) { struct neighbour *neigh = dst_get_neighbour_noref(skb_dst(skb)); -- cgit v1.2.3-70-g09d2 From de4e83bd6b5e16d491ec068cd22801d5d063b07a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 6 Jan 2012 03:34:20 -0800 Subject: sysctl: Register the base sysctl table like any other sysctl table. Simplify the code by treating the base sysctl table like any other sysctl table and register it with register_sysctl_table. To ensure this table is registered early enough to avoid problems call sysctl_init from proc_sys_init. Rename sysctl_net.c:sysctl_init() to net_sysctl_init() to avoid name conflicts now that kernel/sysctl.c:sysctl_init() is no longer static. Signed-off-by: Eric W. Biederman --- fs/proc/proc_sysctl.c | 3 ++- include/linux/sysctl.h | 1 + kernel/sysctl.c | 13 ++++--------- net/sysctl_net.c | 4 ++-- 4 files changed, 9 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index d82f4a8b4b8..9d29d28af57 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -468,5 +468,6 @@ int __init proc_sys_init(void) proc_sys_root->proc_iops = &proc_sys_dir_operations; proc_sys_root->proc_fops = &proc_sys_dir_file_operations; proc_sys_root->nlink = 0; - return 0; + + return sysctl_init(); } diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index cf3ee7f246d..5e3532e9599 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -1095,6 +1095,7 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, void unregister_sysctl_table(struct ctl_table_header * table); int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table); +extern int sysctl_init(void); #else /* CONFIG_SYSCTL */ static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index d5bbddd0de2..ad460248acc 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -192,7 +192,7 @@ static int sysrq_sysctl_handler(ctl_table *table, int write, #endif -static struct ctl_table root_table[]; +static struct ctl_table root_table[1]; static struct ctl_table_root sysctl_table_root; static struct ctl_table_header root_table_header = { {{.count = 1, @@ -222,7 +222,7 @@ int sysctl_legacy_va_layout; /* The default sysctl tables: */ -static struct ctl_table root_table[] = { +static struct ctl_table sysctl_base_table[] = { { .procname = "kernel", .mode = 0555, @@ -1747,17 +1747,12 @@ static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) } } -static __init int sysctl_init(void) +int __init sysctl_init(void) { - sysctl_set_parent(NULL, root_table); -#ifdef CONFIG_SYSCTL_SYSCALL_CHECK - sysctl_check_table(current->nsproxy, root_table); -#endif + register_sysctl_table(sysctl_base_table); return 0; } -core_initcall(sysctl_init); - static struct ctl_table *is_branch_in(struct ctl_table *branch, struct ctl_table *table) { diff --git a/net/sysctl_net.c b/net/sysctl_net.c index e75813904f2..a6bbee2bc71 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -90,7 +90,7 @@ static struct pernet_operations sysctl_pernet_ops = { .exit = sysctl_net_exit, }; -static __init int sysctl_init(void) +static __init int net_sysctl_init(void) { int ret; ret = register_pernet_subsys(&sysctl_pernet_ops); @@ -102,7 +102,7 @@ static __init int sysctl_init(void) out: return ret; } -subsys_initcall(sysctl_init); +subsys_initcall(net_sysctl_init); struct ctl_table_header *register_net_sysctl_table(struct net *net, const struct ctl_path *path, struct ctl_table *table) -- cgit v1.2.3-70-g09d2 From 97324cd804b7b9fb6044e114329335db79810425 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 9 Jan 2012 22:19:13 -0800 Subject: sysctl: Implement retire_sysctl_set This adds a small helper retire_sysctl_set to remove the intimate knowledge about the how a sysctl_set is implemented from net/sysct_net.c Signed-off-by: Eric W. Biederman --- fs/proc/proc_sysctl.c | 4 ++++ include/linux/sysctl.h | 1 + net/sysctl_net.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index f6aa75111b4..9d8223cd365 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1080,6 +1080,10 @@ void setup_sysctl_set(struct ctl_table_set *p, p->is_seen = is_seen; } +void retire_sysctl_set(struct ctl_table_set *set) +{ + WARN_ON(!list_empty(&set->list)); +} int __init proc_sys_init(void) { diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 08cabbfddac..475ff0e35e6 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -1072,6 +1072,7 @@ void proc_sys_poll_notify(struct ctl_table_poll *poll); extern void setup_sysctl_set(struct ctl_table_set *p, struct ctl_table_set *parent, int (*is_seen)(struct ctl_table_set *)); +extern void retire_sysctl_set(struct ctl_table_set *set); void register_sysctl_root(struct ctl_table_root *root); struct ctl_table_header *__register_sysctl_paths( diff --git a/net/sysctl_net.c b/net/sysctl_net.c index a6bbee2bc71..ffd67a6515a 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -82,7 +82,7 @@ static int __net_init sysctl_net_init(struct net *net) static void __net_exit sysctl_net_exit(struct net *net) { - WARN_ON(!list_empty(&net->sysctls.list)); + retire_sysctl_set(&net->sysctls); } static struct pernet_operations sysctl_pernet_ops = { -- cgit v1.2.3-70-g09d2 From bd295b56cfae85f2dd6c2b03951480c91e6d08f3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 22 Jan 2012 21:10:21 -0800 Subject: sysctl: Remove the unnecessary sysctl_set parent concept. In sysctl_net register the two networking roots in the proper order. In register_sysctl walk the sysctl sets in the reverse order of the sysctl roots. Remove parent from ctl_table_set and setup_sysctl_set as it is no longer needed. Signed-off-by: Eric W. Biederman --- fs/proc/proc_sysctl.c | 11 ++++++++--- include/linux/sysctl.h | 3 --- net/sysctl_net.c | 5 ++--- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 9d8223cd365..86d32a318e2 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -995,13 +995,20 @@ struct ctl_table_header *__register_sysctl_paths( header->attached_by = header->ctl_table; header->attached_to = root_table; header->parent = &root_table_header; - for (set = header->set; set; set = set->parent) { + set = header->set; + root = header->root; + for (;;) { struct ctl_table_header *p; list_for_each_entry(p, &set->list, ctl_entry) { if (p->unregistering) continue; try_attach(p, header); } + if (root == &sysctl_table_root) + break; + root = list_entry(root->root_list.prev, + struct ctl_table_root, root_list); + set = lookup_header_set(root, namespaces); } header->parent->count++; list_add_tail(&header->ctl_entry, &header->set->list); @@ -1072,11 +1079,9 @@ void unregister_sysctl_table(struct ctl_table_header * header) EXPORT_SYMBOL(unregister_sysctl_table); void setup_sysctl_set(struct ctl_table_set *p, - struct ctl_table_set *parent, int (*is_seen)(struct ctl_table_set *)) { INIT_LIST_HEAD(&p->list); - p->parent = parent ? parent : &sysctl_table_root.default_set; p->is_seen = is_seen; } diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 475ff0e35e6..43c36acdb62 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -1047,7 +1047,6 @@ struct ctl_table_header struct ctl_table_set { struct list_head list; - struct ctl_table_set *parent; int (*is_seen)(struct ctl_table_set *); }; @@ -1070,7 +1069,6 @@ struct ctl_path { void proc_sys_poll_notify(struct ctl_table_poll *poll); extern void setup_sysctl_set(struct ctl_table_set *p, - struct ctl_table_set *parent, int (*is_seen)(struct ctl_table_set *)); extern void retire_sysctl_set(struct ctl_table_set *set); @@ -1102,7 +1100,6 @@ static inline void unregister_sysctl_table(struct ctl_table_header * table) } static inline void setup_sysctl_set(struct ctl_table_set *p, - struct ctl_table_set *parent, int (*is_seen)(struct ctl_table_set *)) { } diff --git a/net/sysctl_net.c b/net/sysctl_net.c index ffd67a6515a..07c6b879c8b 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -75,7 +75,6 @@ static struct ctl_table_root net_sysctl_ro_root = { static int __net_init sysctl_net_init(struct net *net) { setup_sysctl_set(&net->sysctls, - &net_sysctl_ro_root.default_set, is_seen); return 0; } @@ -96,9 +95,9 @@ static __init int net_sysctl_init(void) ret = register_pernet_subsys(&sysctl_pernet_ops); if (ret) goto out; - register_sysctl_root(&net_sysctl_root); - setup_sysctl_set(&net_sysctl_ro_root.default_set, NULL, NULL); + setup_sysctl_set(&net_sysctl_ro_root.default_set, NULL); register_sysctl_root(&net_sysctl_ro_root); + register_sysctl_root(&net_sysctl_root); out: return ret; } -- cgit v1.2.3-70-g09d2 From 9eb47c26f09e27506d343ef52e634b2a50ee21ef Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 22 Jan 2012 21:26:00 -0800 Subject: sysctl: Add a root pointer to ctl_table_set Add a ctl_table_root pointer to ctl_table set so it is easy to go from a ctl_table_set to a ctl_table_root. Signed-off-by: Eric W. Biederman --- fs/proc/proc_sysctl.c | 3 +++ include/linux/sysctl.h | 3 +++ net/sysctl_net.c | 5 ++--- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index d9c3ae6afe4..65c13dddcea 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -45,6 +45,7 @@ static struct ctl_table_header root_table_header = { static struct ctl_table_root sysctl_table_root = { .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list), .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry), + .default_set.root = &sysctl_table_root, }; static DEFINE_SPINLOCK(sysctl_lock); @@ -1348,9 +1349,11 @@ void unregister_sysctl_table(struct ctl_table_header * header) EXPORT_SYMBOL(unregister_sysctl_table); void setup_sysctl_set(struct ctl_table_set *p, + struct ctl_table_root *root, int (*is_seen)(struct ctl_table_set *)) { INIT_LIST_HEAD(&p->list); + p->root = root; p->is_seen = is_seen; } diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index e40b8f6e5d0..e73ba33cbf0 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -1047,6 +1047,7 @@ struct ctl_table_header struct ctl_table_set { struct list_head list; + struct ctl_table_root *root; int (*is_seen)(struct ctl_table_set *); }; @@ -1069,6 +1070,7 @@ struct ctl_path { void proc_sys_poll_notify(struct ctl_table_poll *poll); extern void setup_sysctl_set(struct ctl_table_set *p, + struct ctl_table_root *root, int (*is_seen)(struct ctl_table_set *)); extern void retire_sysctl_set(struct ctl_table_set *set); @@ -1103,6 +1105,7 @@ static inline void unregister_sysctl_table(struct ctl_table_header * table) } static inline void setup_sysctl_set(struct ctl_table_set *p, + struct ctl_table_root *root, int (*is_seen)(struct ctl_table_set *)) { } diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 07c6b879c8b..e998c644804 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -74,8 +74,7 @@ static struct ctl_table_root net_sysctl_ro_root = { static int __net_init sysctl_net_init(struct net *net) { - setup_sysctl_set(&net->sysctls, - is_seen); + setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen); return 0; } @@ -95,7 +94,7 @@ static __init int net_sysctl_init(void) ret = register_pernet_subsys(&sysctl_pernet_ops); if (ret) goto out; - setup_sysctl_set(&net_sysctl_ro_root.default_set, NULL); + setup_sysctl_set(&net_sysctl_ro_root.default_set, &net_sysctl_ro_root, NULL); register_sysctl_root(&net_sysctl_ro_root); register_sysctl_root(&net_sysctl_root); out: -- cgit v1.2.3-70-g09d2 From 60a47a2e823cbe6b609346bffff61a00c0c76470 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 8 Jan 2012 00:02:37 -0800 Subject: sysctl: Modify __register_sysctl_paths to take a set instead of a root and an nsproxy An nsproxy argument here has always been awkard and now the nsproxy argument is completely unnecessary so remove it, replacing it with the set we want the registered tables to show up in. Signed-off-by: Eric W. Biederman --- fs/proc/proc_sysctl.c | 30 ++++++++++++------------------ include/linux/sysctl.h | 4 ++-- net/sysctl_net.c | 10 +++------- 3 files changed, 17 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index ec54a57c469..e0d3e7e59cb 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1084,8 +1084,7 @@ out: /** * __register_sysctl_table - register a leaf sysctl table - * @root: List of sysctl headers to register on - * @namespaces: Data to compute which lists of sysctl entries are visible + * @set: Sysctl tree to register on * @path: The path to the directory the sysctl table is in. * @table: the top-level table structure * @@ -1126,26 +1125,24 @@ out: * to the table header on success. */ struct ctl_table_header *__register_sysctl_table( - struct ctl_table_root *root, - struct nsproxy *namespaces, + struct ctl_table_set *set, const char *path, struct ctl_table *table) { + struct ctl_table_root *root = set->dir.header.root; struct ctl_table_header *links = NULL; struct ctl_table_header *header; const char *name, *nextname; - struct ctl_table_set *set; struct ctl_dir *dir; header = kzalloc(sizeof(struct ctl_table_header), GFP_KERNEL); if (!header) return NULL; - init_header(header, root, NULL, table); + init_header(header, root, set, table); if (sysctl_check_table(path, table)) goto fail; spin_lock(&sysctl_lock); - header->set = set = lookup_header_set(root, namespaces); dir = &set->dir; dir->header.nreg++; spin_unlock(&sysctl_lock); @@ -1223,8 +1220,7 @@ static int count_subheaders(struct ctl_table *table) } static int register_leaf_sysctl_tables(const char *path, char *pos, - struct ctl_table_header ***subheader, - struct ctl_table_root *root, struct nsproxy *namespaces, + struct ctl_table_header ***subheader, struct ctl_table_set *set, struct ctl_table *table) { struct ctl_table *ctl_table_arg = NULL; @@ -1261,7 +1257,7 @@ static int register_leaf_sysctl_tables(const char *path, char *pos, /* Register everything except a directory full of subdirectories */ if (nr_files || !nr_dirs) { struct ctl_table_header *header; - header = __register_sysctl_table(root, namespaces, path, files); + header = __register_sysctl_table(set, path, files); if (!header) { kfree(ctl_table_arg); goto out; @@ -1286,7 +1282,7 @@ static int register_leaf_sysctl_tables(const char *path, char *pos, goto out; err = register_leaf_sysctl_tables(path, child_pos, subheader, - root, namespaces, entry->child); + set, entry->child); pos[0] = '\0'; if (err) goto out; @@ -1299,8 +1295,7 @@ out: /** * __register_sysctl_paths - register a sysctl table hierarchy - * @root: List of sysctl headers to register on - * @namespaces: Data to compute which lists of sysctl entries are visible + * @set: Sysctl tree to register on * @path: The path to the directory the sysctl table is in. * @table: the top-level table structure * @@ -1310,8 +1305,7 @@ out: * See __register_sysctl_table for more details. */ struct ctl_table_header *__register_sysctl_paths( - struct ctl_table_root *root, - struct nsproxy *namespaces, + struct ctl_table_set *set, const struct ctl_path *path, struct ctl_table *table) { struct ctl_table *ctl_table_arg = table; @@ -1337,7 +1331,7 @@ struct ctl_table_header *__register_sysctl_paths( table = table->child; } if (nr_subheaders == 1) { - header = __register_sysctl_table(root, namespaces, new_path, table); + header = __register_sysctl_table(set, new_path, table); if (header) header->ctl_table_arg = ctl_table_arg; } else { @@ -1351,7 +1345,7 @@ struct ctl_table_header *__register_sysctl_paths( header->ctl_table_arg = ctl_table_arg; if (register_leaf_sysctl_tables(new_path, pos, &subheader, - root, namespaces, table)) + set, table)) goto err_register_leaves; } @@ -1384,7 +1378,7 @@ err_register_leaves: struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, struct ctl_table *table) { - return __register_sysctl_paths(&sysctl_table_root, current->nsproxy, + return __register_sysctl_paths(&sysctl_table_root.default_set, path, table); } EXPORT_SYMBOL(register_sysctl_paths); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 2a1446a9609..cec59415b3c 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -1079,10 +1079,10 @@ extern void retire_sysctl_set(struct ctl_table_set *set); void register_sysctl_root(struct ctl_table_root *root); struct ctl_table_header *__register_sysctl_table( - struct ctl_table_root *root, struct nsproxy *namespaces, + struct ctl_table_set *set, const char *path, struct ctl_table *table); struct ctl_table_header *__register_sysctl_paths( - struct ctl_table_root *root, struct nsproxy *namespaces, + struct ctl_table_set *set, const struct ctl_path *path, struct ctl_table *table); struct ctl_table_header *register_sysctl_table(struct ctl_table * table); struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, diff --git a/net/sysctl_net.c b/net/sysctl_net.c index e998c644804..c3e65aebecc 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -105,19 +105,15 @@ subsys_initcall(net_sysctl_init); struct ctl_table_header *register_net_sysctl_table(struct net *net, const struct ctl_path *path, struct ctl_table *table) { - struct nsproxy namespaces; - namespaces = *current->nsproxy; - namespaces.net_ns = net; - return __register_sysctl_paths(&net_sysctl_root, - &namespaces, path, table); + return __register_sysctl_paths(&net->sysctls, path, table); } EXPORT_SYMBOL_GPL(register_net_sysctl_table); struct ctl_table_header *register_net_sysctl_rotable(const struct ctl_path *path, struct ctl_table *table) { - return __register_sysctl_paths(&net_sysctl_ro_root, - &init_nsproxy, path, table); + return __register_sysctl_paths(&net_sysctl_ro_root.default_set, + path, table); } EXPORT_SYMBOL_GPL(register_net_sysctl_rotable); -- cgit v1.2.3-70-g09d2 From 09e9b813d34d9a09d64a64580a9959d8bae1f4f5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 Jan 2012 04:44:20 +0000 Subject: tcp: add LINUX_MIB_TCPRETRANSFAIL counter It might be useful to get a counter of failed tcp_retransmit_skb() calls. Reported-by: Satoru Moriya Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/snmp.h | 1 + net/ipv4/proc.c | 1 + net/ipv4/tcp_output.c | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/snmp.h b/include/linux/snmp.h index c1241c42817..8ee8af4e6da 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -232,6 +232,7 @@ enum LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */ LINUX_MIB_TCPREQQFULLDOCOOKIES, /* TCPReqQFullDoCookies */ LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */ + LINUX_MIB_TCPRETRANSFAIL, /* TCPRetransFail */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 6afc807ee2a..02d61079f08 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -256,6 +256,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW), SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES), SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP), + SNMP_MIB_ITEM("TCPRetransFail", LINUX_MIB_TCPRETRANSFAIL), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 8c8de2780c7..561550ab3c3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2308,8 +2308,10 @@ begin_fwd: if (sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS)) continue; - if (tcp_retransmit_skb(sk, skb)) + if (tcp_retransmit_skb(sk, skb)) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL); return; + } NET_INC_STATS_BH(sock_net(sk), mib_idx); if (inet_csk(sk)->icsk_ca_state == TCP_CA_Recovery) -- cgit v1.2.3-70-g09d2 From 39232973b779ab0c02cb6dcd8f819b7cb0fcd09a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 26 Jan 2012 15:22:32 -0500 Subject: ipv4/ipv6: Prepare for new route gateway semantics. In the future the ipv4/ipv6 route gateway will take on two types of values: 1) INADDR_ANY/IN6ADDR_ANY, for local network routes, and in this case the neighbour must be obtained using the destination address in ipv4/ipv6 header as the lookup key. 2) Everything else, the actual nexthop route address. So if the gateway is not inaddr-any we use it, otherwise we must use the packet's destination address. Signed-off-by: David S. Miller --- net/ipv4/route.c | 5 +++++ net/ipv6/route.c | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bcacf54e541..4eeb8ce856e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1117,10 +1117,15 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const vo static const __be32 inaddr_any = 0; struct net_device *dev = dst->dev; const __be32 *pkey = daddr; + const struct rtable *rt; struct neighbour *n; + rt = (const struct rtable *) dst; + if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) pkey = &inaddr_any; + else if (rt->rt_gateway) + pkey = (const __be32 *) &rt->rt_gateway; n = __ipv4_neigh_lookup(&arp_tbl, dev, *(__force u32 *)pkey); if (n) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8c2e3ab58f2..7d7f30697ea 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -121,9 +121,23 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) return p; } +static inline const void *choose_neigh_daddr(struct rt6_info *rt, const void *daddr) +{ + struct in6_addr *p = &rt->rt6i_gateway; + + if (p->s6_addr32[0] | p->s6_addr32[1] | + p->s6_addr32[2] | p->s6_addr32[3]) + return (const void *) p; + return daddr; +} + static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, const void *daddr) { - struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr); + struct rt6_info *rt = (struct rt6_info *) dst; + struct neighbour *n; + + daddr = choose_neigh_daddr(rt, daddr); + n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr); if (n) return n; return neigh_create(&nd_tbl, daddr, dst->dev); -- cgit v1.2.3-70-g09d2 From 1e2927b08160a14fff98e88e7a331d916aaa1d56 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 26 Jan 2012 15:23:21 -0500 Subject: ipv6: sit: Convert to dst_neigh_lookup() The only semantic difference is that we now hold a reference to the neighbour and thus have to release it. Signed-off-by: David S. Miller --- net/ipv6/sit.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 133768e5291..c4ffd174352 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -680,9 +680,10 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, /* ISATAP (RFC4214) - must come before 6to4 */ if (dev->priv_flags & IFF_ISATAP) { struct neighbour *neigh = NULL; + bool do_tx_error = false; if (skb_dst(skb)) - neigh = dst_get_neighbour_noref(skb_dst(skb)); + neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); if (neigh == NULL) { if (net_ratelimit()) @@ -697,6 +698,10 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, ipv6_addr_is_isatap(addr6)) dst = addr6->s6_addr32[3]; else + do_tx_error = true; + + neigh_release(neigh); + if (do_tx_error) goto tx_error; } @@ -705,9 +710,10 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, if (!dst) { struct neighbour *neigh = NULL; + bool do_tx_error = false; if (skb_dst(skb)) - neigh = dst_get_neighbour_noref(skb_dst(skb)); + neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); if (neigh == NULL) { if (net_ratelimit()) @@ -723,10 +729,14 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, addr_type = ipv6_addr_type(addr6); } - if ((addr_type & IPV6_ADDR_COMPATv4) == 0) - goto tx_error_icmp; + if ((addr_type & IPV6_ADDR_COMPATv4) != 0) + dst = addr6->s6_addr32[3]; + else + do_tx_error = true; - dst = addr6->s6_addr32[3]; + neigh_release(neigh); + if (do_tx_error) + goto tx_error; } rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, -- cgit v1.2.3-70-g09d2 From a7563f342db6490e66dbf2c8a50577a72a158c9a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 26 Jan 2012 16:29:16 -0500 Subject: ipv6: Use ipv6_addr_any() Suggested by YOSHIFUJI Hideaki. Signed-off-by: David S. Miller --- net/ipv6/route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7d7f30697ea..92be12bb8d2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -125,8 +125,7 @@ static inline const void *choose_neigh_daddr(struct rt6_info *rt, const void *da { struct in6_addr *p = &rt->rt6i_gateway; - if (p->s6_addr32[0] | p->s6_addr32[1] | - p->s6_addr32[2] | p->s6_addr32[3]) + if (!ipv6_addr_any(p)) return (const void *) p; return daddr; } -- cgit v1.2.3-70-g09d2 From c1288b1278d00169e12495eb53ad128e09560b69 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Jan 2012 09:29:57 +0100 Subject: mac80211: make beacon filtering per virtual interface Due to firmware limitations, we may not be able to support beacon filtering on all virtual interfaces. To allow this in mac80211, introduce per-interface driver capability flags that the driver sets when an interface is added. Signed-off-by: Johannes Berg Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/p54/main.c | 3 ++- drivers/net/wireless/rtlwifi/base.c | 1 - drivers/net/wireless/rtlwifi/core.c | 2 ++ drivers/net/wireless/wl1251/main.c | 3 ++- drivers/net/wireless/wl12xx/main.c | 3 ++- include/net/mac80211.h | 29 ++++++++++++++++++++--------- net/mac80211/debugfs.c | 2 -- net/mac80211/mlme.c | 2 +- 8 files changed, 29 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index af2ca1a9c7d..40f4eb7da7b 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -228,6 +228,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mutex_lock(&priv->conf_mutex); if (priv->mode != NL80211_IFTYPE_MONITOR) { mutex_unlock(&priv->conf_mutex); @@ -734,7 +736,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | - IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_REPORTS_TX_ACK_STATUS; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 6f80142580f..ff3e393bc10 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -309,7 +309,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* <5> set hw caps */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_CONNECTION_MONITOR | /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */ diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index d6e37e6a1d5..0ee01ab2e4f 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -112,6 +112,8 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); int err = 0; + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + if (mac->vif) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "vif has been set!! mac->vif = 0x%p\n", mac->vif); diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index ba3268ea81f..86540db6f1a 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -514,6 +514,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, struct wl1251 *wl = hw->priv; int ret = 0; + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", vif->type, vif->addr); @@ -1338,7 +1340,6 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_SUPPORTS_CQM_RSSI; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index d5f55a149de..afc5381f287 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2060,6 +2060,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, u8 role_type; bool booted = false; + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", ieee80211_vif_type_p2p(vif), vif->addr); @@ -4898,7 +4900,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval; wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_HAS_RATE_CONTROL | diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d49928ba5d0..ae8db247bde 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -851,6 +851,16 @@ struct ieee80211_channel_switch { u8 count; }; +/** + * enum ieee80211_vif_flags - virtual interface flags + * + * @IEEE80211_VIF_BEACON_FILTER: the device performs beacon filtering + * on this virtual interface to avoid unnecessary CPU wakeups + */ +enum ieee80211_vif_flags { + IEEE80211_VIF_BEACON_FILTER = BIT(0), +}; + /** * struct ieee80211_vif - per-interface data * @@ -863,6 +873,10 @@ struct ieee80211_channel_switch { * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively + * @driver_flags: flags/capabilities the driver has for this interface, + * these need to be set (or cleared) when the interface is added + * or, if supported by the driver, the interface type is changed + * at runtime, mac80211 will never touch this field * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *). */ @@ -871,6 +885,7 @@ struct ieee80211_vif { struct ieee80211_bss_conf bss_conf; u8 addr[ETH_ALEN]; bool p2p; + u32 driver_flags; /* must be last */ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); }; @@ -1079,10 +1094,6 @@ enum sta_notify_cmd { * @IEEE80211_HW_MFP_CAPABLE: * Hardware supports management frame protection (MFP, IEEE 802.11w). * - * @IEEE80211_HW_BEACON_FILTER: - * Hardware supports dropping of irrelevant beacon frames to - * avoid waking up cpu. - * * @IEEE80211_HW_SUPPORTS_STATIC_SMPS: * Hardware supports static spatial multiplexing powersave, * ie. can turn off all but one chain even on HT connections @@ -1150,7 +1161,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11, IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, IEEE80211_HW_MFP_CAPABLE = 1<<13, - IEEE80211_HW_BEACON_FILTER = 1<<14, + /* reuse bit 14 */ IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, @@ -1446,8 +1457,8 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); * way the host will only receive beacons where some relevant information * (for example ERP protection or WMM settings) have changed. * - * Beacon filter support is advertised with the %IEEE80211_HW_BEACON_FILTER - * hardware capability. The driver needs to enable beacon filter support + * Beacon filter support is advertised with the %IEEE80211_VIF_BEACON_FILTER + * interface capability. The driver needs to enable beacon filter support * whenever power save is enabled, that is %IEEE80211_CONF_PS is set. When * power save is enabled, the stack will not check for beacon loss and the * driver needs to notify about loss of beacons with ieee80211_beacon_loss(). @@ -3316,7 +3327,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, * * @vif: &struct ieee80211_vif pointer from the add_interface callback. * - * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER and + * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER and * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the * hardware is not receiving beacons with this function. */ @@ -3327,7 +3338,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif); * * @vif: &struct ieee80211_vif pointer from the add_interface callback. * - * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER, and + * When beacon filtering is enabled with %IEEE80211_VIF_BEACON_FILTER, and * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver * needs to inform if the connection to the AP has been lost. * diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 90baea53e7c..e8868dae1c0 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -247,8 +247,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); - if (local->hw.flags & IEEE80211_HW_BEACON_FILTER) - sf += snprintf(buf + sf, mxln - sf, "BEACON_FILTER\n"); if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 95d3964fc08..b51eb49d852 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -127,7 +127,7 @@ static void run_again(struct ieee80211_if_managed *ifmgd, void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) { - if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) + if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) return; mod_timer(&sdata->u.mgd.bcn_mon_timer, -- cgit v1.2.3-70-g09d2 From ea086359a63bd0dd85c1d784d0425340649613fa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Jan 2012 09:29:58 +0100 Subject: mac80211: make CQM RSSI support per virtual interface Similar to the previous beacon filtering patch, make CQM RSSI support depend on the flags that the driver set for virtual interfaces. Signed-off-by: Johannes Berg Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl1251/main.c | 6 +++--- drivers/net/wireless/wl12xx/main.c | 4 ++-- include/net/mac80211.h | 14 +++++++------- net/mac80211/cfg.c | 10 ++-------- net/mac80211/debugfs.c | 2 -- net/mac80211/mlme.c | 4 ++-- 6 files changed, 16 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 86540db6f1a..41302c7b1ad 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -514,7 +514,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, struct wl1251 *wl = hw->priv; int ret = 0; - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", vif->type, vif->addr); @@ -1340,8 +1341,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_UAPSD | - IEEE80211_HW_SUPPORTS_CQM_RSSI; + IEEE80211_HW_SUPPORTS_UAPSD; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index afc5381f287..f8748cedbae 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2060,7 +2060,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, u8 role_type; bool booted = false; - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", ieee80211_vif_type_p2p(vif), vif->addr); @@ -4904,7 +4905,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_CONNECTION_MONITOR | - IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_AP_LINK_PS | diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ae8db247bde..65018587684 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -856,9 +856,14 @@ struct ieee80211_channel_switch { * * @IEEE80211_VIF_BEACON_FILTER: the device performs beacon filtering * on this virtual interface to avoid unnecessary CPU wakeups + * @IEEE80211_VIF_SUPPORTS_CQM_RSSI: the device can do connection quality + * monitoring on this virtual interface -- i.e. it can monitor + * connection quality related parameters, such as the RSSI level and + * provide notifications if configured trigger levels are reached. */ enum ieee80211_vif_flags { IEEE80211_VIF_BEACON_FILTER = BIT(0), + IEEE80211_VIF_SUPPORTS_CQM_RSSI = BIT(1), }; /** @@ -1119,11 +1124,6 @@ enum sta_notify_cmd { * When this flag is set, signaling beacon-loss will cause an immediate * change to disassociated state. * - * @IEEE80211_HW_SUPPORTS_CQM_RSSI: - * Hardware can do connection quality monitoring - i.e. it can monitor - * connection quality related parameters, such as the RSSI level and - * provide notifications if configured trigger levels are reached. - * * @IEEE80211_HW_NEED_DTIM_PERIOD: * This device needs to know the DTIM period for the BSS before * associating. @@ -1167,7 +1167,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, IEEE80211_HW_CONNECTION_MONITOR = 1<<19, - IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20, + /* reuse bit 20 */ IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, IEEE80211_HW_AP_LINK_PS = 1<<22, IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, @@ -3408,7 +3408,7 @@ void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif); * @rssi_event: the RSSI trigger event type * @gfp: context flags * - * When the %IEEE80211_HW_SUPPORTS_CQM_RSSI is set, and a connection quality + * When the %IEEE80211_VIF_SUPPORTS_CQM_RSSI is set, and a connection quality * monitoring is configured with an rssi threshold, the driver will inform * whenever the rssi level reaches the threshold. */ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d86730fe75c..74c9301681e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1873,7 +1873,6 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, s32 rssi_thold, u32 rssi_hyst) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_vif *vif = &sdata->vif; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; @@ -1884,14 +1883,9 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, bss_conf->cqm_rssi_thold = rssi_thold; bss_conf->cqm_rssi_hyst = rssi_hyst; - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - return 0; - } - /* tell the driver upon association, unless already associated */ - if (sdata->u.mgd.associated) + if (sdata->u.mgd.associated && + sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); return 0; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e8868dae1c0..affe64be909 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -257,8 +257,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n"); if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); - if (local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) - sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_CQM_RSSI\n"); if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b51eb49d852..de3268c7be1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1043,7 +1043,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= BSS_CHANGED_BSSID; /* Tell the driver to monitor connection quality (if supported) */ - if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) && + if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI && bss_conf->cqm_rssi_thold) bss_info_changed |= BSS_CHANGED_CQM; @@ -1882,7 +1882,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (bss_conf->cqm_rssi_thold && ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && - !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { + !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) { int sig = ifmgd->ave_beacon_signal / 16; int last_event = ifmgd->last_cqm_event_signal; int thold = bss_conf->cqm_rssi_thold; -- cgit v1.2.3-70-g09d2 From 8e7c4e4dc6e98a0d3ee4535c6b94a3ad63adad2a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:52:36 +0100 Subject: mac80211: fix a few -Wshadow warnings It seems that -Wshadow is no longer default in sparse runs, but let's fix the warnings anyway. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 3 --- net/mac80211/status.c | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 75140912076..73d213810a3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2180,9 +2180,6 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) if (rx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_beacon(mgmt->frame_control) && !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { - struct ieee80211_rx_status *status; - - status = IEEE80211_SKB_RXCB(rx->skb); cfg80211_report_obss_beacon(rx->local->hw.wiphy, rx->skb->data, rx->skb->len, status->freq, GFP_ATOMIC); diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 30c265c98f7..d67f0b967f8 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -350,7 +350,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) bool send_to_cooked; bool acked; struct ieee80211_bar *bar; - u16 tid; int rtap_len; for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { @@ -412,7 +411,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } if (!acked && ieee80211_is_back_req(fc)) { - u16 control; + u16 tid, control; /* * BAR failed, store the last SSN and retry sending @@ -516,7 +515,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (ieee80211_is_nullfunc(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) { - bool acked = info->flags & IEEE80211_TX_STAT_ACK; + acked = info->flags & IEEE80211_TX_STAT_ACK; + cfg80211_probe_status(skb->dev, hdr->addr1, cookie, acked, GFP_ATOMIC); } else { -- cgit v1.2.3-70-g09d2 From 2da8f419e78a0ebccc91c095328278fe668a7932 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:52:37 +0100 Subject: cfg80211: fix a few -Wshadow warnings It seems that -Wshadow is no longer default in sparse runs, but let's fix the warnings anyway. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index afeea32e04a..5cefd74ab47 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -427,10 +427,9 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) if (tb[NL80211_KEY_DEFAULT_TYPES]) { struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; - int err = nla_parse_nested(kdt, - NUM_NL80211_KEY_DEFAULT_TYPES - 1, - tb[NL80211_KEY_DEFAULT_TYPES], - nl80211_key_default_policy); + err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1, + tb[NL80211_KEY_DEFAULT_TYPES], + nl80211_key_default_policy); if (err) return err; @@ -4781,7 +4780,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); struct ieee80211_supported_band *sband = wiphy->bands[ibss.channel->band]; - int err; err = ieee80211_get_ratemask(sband, rates, n_rates, &ibss.basic_rates); -- cgit v1.2.3-70-g09d2 From 94f9065648a2645b28187b44ec7778c30cf58758 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Sat, 21 Jan 2012 01:02:16 +0800 Subject: {nl,cfg,mac}80211: Add support of setting non-forwarding entity in Mesh A mesh node that joins the mesh network is by default a forwarding entity. This patch allows the mesh node to set as non-forwarding entity. Whenever dot11MeshForwarding is set to 0, the mesh node can prevent itself from forwarding the traffic which is not destined to him. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++++ include/net/cfg80211.h | 1 + net/mac80211/cfg.c | 2 ++ net/mac80211/debugfs_netdev.c | 1 + net/mac80211/mesh_hwmp.c | 2 +- net/wireless/mesh.c | 1 + net/wireless/nl80211.c | 5 +++++ 7 files changed, 15 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 0f5ff373982..4f98fae1330 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -2104,6 +2104,9 @@ enum nl80211_mntr_flags { * TUs) during which a mesh STA can send only one Action frame containing a * PERR element. * + * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding + * or forwarding entity (default is TRUE - forwarding entity) + * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use @@ -2128,6 +2131,7 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_HWMP_RANN_INTERVAL, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, + NL80211_MESHCONF_FORWARDING, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 208a7b5f8d4..281899167d2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -798,6 +798,7 @@ struct mesh_config { * mesh gate, but not necessarily using the gate announcement protocol. * Still keeping the same nomenclature to be in sync with the spec. */ bool dot11MeshGateAnnouncementProtocol; + bool dot11MeshForwarding; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 74c9301681e..98460783c2d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1346,6 +1346,8 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, conf->dot11MeshHWMPRannInterval = nconf->dot11MeshHWMPRannInterval; } + if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask)) + conf->dot11MeshForwarding = nconf->dot11MeshForwarding; return 0; } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 176c08ffb13..81d12e65a23 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -422,6 +422,7 @@ IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol, u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC); IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); +IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); #endif diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 73abb7524b2..cae407136ae 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -575,7 +575,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, ifmsh->mshstats.dropped_frames_ttl++; } - if (forward) { + if (forward && ifmsh->mshcfg.dot11MeshForwarding) { u32 preq_id; u8 hopcount, flags; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 8c550df1303..9d3e3b6bfcf 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -55,6 +55,7 @@ const struct mesh_config default_mesh_config = { .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL, .dot11MeshGateAnnouncementProtocol = false, + .dot11MeshForwarding = true, }; const struct mesh_setup default_mesh_setup = { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5cefd74ab47..c42173f947e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3258,6 +3258,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, cur_params.dot11MeshHWMPRannInterval); NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, cur_params.dot11MeshGateAnnouncementProtocol); + NLA_PUT_U8(msg, NL80211_MESHCONF_FORWARDING, + cur_params.dot11MeshForwarding); nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); return genlmsg_reply(msg, info); @@ -3289,6 +3291,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 }, [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, + [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, }; static const struct nla_policy @@ -3378,6 +3381,8 @@ do {\ dot11MeshGateAnnouncementProtocol, mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, + mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); if (mask_out) *mask_out = mask; -- cgit v1.2.3-70-g09d2 From 6269cc83e7c444f3050e0d7e640d079bae17aa68 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 26 Jan 2012 09:13:31 +0300 Subject: nfc: NULL vs zero in nci_activate_target() This is a pointer so it should be NULL instead of zero. Sparse complains about this stuff: net/nfc/nci/core.c:447:37: warning: Using plain integer as NULL pointer Signed-off-by: Dan Carpenter Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/nci/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 12d1d4d6267..a47e90c7d9d 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -444,7 +444,7 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); struct nci_rf_discover_select_param param; - struct nfc_target *target = 0; + struct nfc_target *target = NULL; int i; int rc = 0; -- cgit v1.2.3-70-g09d2 From 6e1b1b246096fe04467f928973487fa47afaf2cc Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 26 Jan 2012 13:36:05 +0200 Subject: mac80211: send null packet on active (psm) reconfiguration The sta might be in psm against the ap (e.g. because this was the before a hw restart), so we explicitly send a null packet in order to make sure it'll sync against the ap (and get out of psm). Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- net/mac80211/util.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'net') diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 30d72e2af7c..d82d886d086 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1271,6 +1271,21 @@ int ieee80211_reconfig(struct ieee80211_local *local) ieee80211_recalc_ps(local, -1); + /* + * The sta might be in psm against the ap (e.g. because + * this was the state before a hw restart), so we + * explicitly send a null packet in order to make sure + * it'll sync against the ap (and get out of psm). + */ + if (!(local->hw.conf.flags & IEEE80211_CONF_PS)) { + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type != NL80211_IFTYPE_STATION) + continue; + + ieee80211_send_nullfunc(local, sdata, 0); + } + } + /* * Clear the WLAN_STA_BLOCK_BA flag so new aggregation * sessions can be established after a resume. -- cgit v1.2.3-70-g09d2 From f1e3be1561c43b6bbe2426e34849fb1486dc313b Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Thu, 26 Jan 2012 13:36:34 +0100 Subject: mac80211: Do not scan for IBSS merge with a fixed BSSID. Currently, when we are on an IBSS network with no active station, we would scan for other BSSID, even if fixed_bssid is on, due to a bug in ibss.c, where fixed_channel would be checked instead of fixed_bssid. This would trigger useless scans where scan results would not be used anyway. This patch also reverts commit 39d02a7d90602d4557ee05db2a157a4e0, which assumed that the ifibss->fixed_channel check was legitimate to disable single-channel scans. IBSS single-channel scan should now be fixed. Signed-off-by: Nicolas Cavallari Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index d38baa41cf6..93b3c7298be 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -655,14 +655,15 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) if (ieee80211_sta_active_ibss(sdata)) return; - if (ifibss->fixed_channel) + if (ifibss->fixed_bssid) return; printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " "IBSS networks with same SSID (merge)\n", sdata->name); ieee80211_request_internal_scan(sdata, - ifibss->ssid, ifibss->ssid_len, NULL); + ifibss->ssid, ifibss->ssid_len, + ifibss->fixed_channel ? ifibss->channel : NULL); } static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) -- cgit v1.2.3-70-g09d2 From 0ec88662041e172acf33d7a15a2020841ee82afb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jan 2012 15:01:08 -0800 Subject: ipv4: ip_gre: Convert to dst_neigh_lookup() The conversion is very similar to that made to ipv6's SIT code. Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 05f7419ed7c..bf9541648b9 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -730,10 +730,12 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev } #if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) { - struct neighbour *neigh = dst_get_neighbour_noref(skb_dst(skb)); const struct in6_addr *addr6; + struct neighbour *neigh; + bool do_tx_error_icmp; int addr_type; + neigh = dst_neigh_lookup(skb_dst(skb), &ipv6_hdr(skb)->daddr); if (neigh == NULL) goto tx_error; @@ -746,9 +748,14 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev } if ((addr_type & IPV6_ADDR_COMPATv4) == 0) + do_tx_error_icmp = true; + else { + do_tx_error_icmp = false; + dst = addr6->s6_addr32[3]; + } + neigh_release(neigh); + if (do_tx_error_icmp) goto tx_error_icmp; - - dst = addr6->s6_addr32[3]; } #endif else -- cgit v1.2.3-70-g09d2 From eb857186eb771998fc9ab4bfd398a6fedb5a295c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jan 2012 15:07:56 -0800 Subject: ipv6: ndisc: Convert to dst_neigh_lookup() Now all code paths grab a local reference to the neigh, so if neigh is not NULL we unconditionally release it at the end. The old logic would only release if we didn't have a non-NULL 'rt'. Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d8f02ef88e5..c574ebce3fb 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1223,11 +1223,17 @@ static void ndisc_router_discovery(struct sk_buff *skb) rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); - if (rt) - neigh = dst_get_neighbour_noref(&rt->dst); - + if (rt) { + neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr); + if (!neigh) { + ND_PRINTK0(KERN_ERR + "ICMPv6 RA: %s() got default router without neighbour.\n", + __func__); + dst_release(&rt->dst); + return; + } + } if (rt && lifetime == 0) { - neigh_clone(neigh); ip6_del_rt(rt); rt = NULL; } @@ -1244,7 +1250,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } - neigh = dst_get_neighbour_noref(&rt->dst); + neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr); if (neigh == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 RA: %s() got default router without neighbour.\n", @@ -1411,7 +1417,7 @@ skip_routeinfo: out: if (rt) dst_release(&rt->dst); - else if (neigh) + if (neigh) neigh_release(neigh); } -- cgit v1.2.3-70-g09d2 From 5339ab8b1dd82f14df168fb9bf59449f3e24b03d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jan 2012 15:14:01 -0800 Subject: ipv6: fib: Convert fib6_age() to dst_neigh_lookup(). In this specific situation we know we are dealing with a gatewayed route and therefore rt6i_gateway is not going to be in6addr_any even in future interpretations. Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b82bcde53f7..5b27fbcae34 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1552,11 +1552,20 @@ static int fib6_age(struct rt6_info *rt, void *arg) time_after_eq(now, rt->dst.lastuse + gc_args.timeout)) { RT6_TRACE("aging clone %p\n", rt); return -1; - } else if ((rt->rt6i_flags & RTF_GATEWAY) && - (!(dst_get_neighbour_noref_raw(&rt->dst)->flags & NTF_ROUTER))) { - RT6_TRACE("purging route %p via non-router but gateway\n", - rt); - return -1; + } else if (rt->rt6i_flags & RTF_GATEWAY) { + struct neighbour *neigh; + __u8 neigh_flags = 0; + + neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway); + if (neigh) { + neigh_flags = neigh->flags; + neigh_release(neigh); + } + if (neigh_flags & NTF_ROUTER) { + RT6_TRACE("purging route %p via non-router but gateway\n", + rt); + return -1; + } } gc_args.more++; } -- cgit v1.2.3-70-g09d2 From 4991969a1027826c3db19dd3e600e145603e6928 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jan 2012 15:30:48 -0800 Subject: ipv6: Remove neigh argument from ndisc_send_redirect() Instead, compute it as-needed inside of that function using dst_neigh_lookup(). Signed-off-by: David S. Miller --- include/net/ndisc.h | 1 - net/ipv6/ip6_output.c | 2 +- net/ipv6/ndisc.c | 12 ++++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/ndisc.h b/include/net/ndisc.h index e3133c23980..6f9c25a76cd 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -133,7 +133,6 @@ extern void ndisc_send_rs(struct net_device *dev, const struct in6_addr *daddr); extern void ndisc_send_redirect(struct sk_buff *skb, - struct neighbour *neigh, const struct in6_addr *target); extern int ndisc_mc_map(const struct in6_addr *addr, char *buf, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d97e07183ce..604809b89b6 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -486,7 +486,7 @@ int ip6_forward(struct sk_buff *skb) and by source (inside ndisc_send_redirect) */ if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) - ndisc_send_redirect(skb, n, target); + ndisc_send_redirect(skb, target); } else { int addrtype = ipv6_addr_type(&hdr->saddr); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index c574ebce3fb..8d817018c18 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1512,8 +1512,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) } } -void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, - const struct in6_addr *target) +void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) { struct net_device *dev = skb->dev; struct net *net = dev_net(dev); @@ -1571,6 +1570,13 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, goto release; if (dev->addr_len) { + struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target); + if (!neigh) { + ND_PRINTK2(KERN_WARNING + "ICMPv6 Redirect: no neigh for target address\n"); + goto release; + } + read_lock_bh(&neigh->lock); if (neigh->nud_state & NUD_VALID) { memcpy(ha_buf, neigh->ha, dev->addr_len); @@ -1579,6 +1585,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, len += ndisc_opt_addr_space(dev); } else read_unlock_bh(&neigh->lock); + + neigh_release(neigh); } rd_len = min_t(unsigned int, -- cgit v1.2.3-70-g09d2 From c45a3dfb59c0f17bdbd294dd01efb2d7f99a32c7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jan 2012 15:32:19 -0800 Subject: ipv6: Eliminate dst_get_neighbour_noref() usage in ip6_forward(). It's only used to get at neigh->primary_key, which in this context is always going to be the same as rt->rt6i_gateway. Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 604809b89b6..7a98fc2a5d9 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -388,7 +388,6 @@ int ip6_forward(struct sk_buff *skb) struct ipv6hdr *hdr = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); struct net *net = dev_net(dst->dev); - struct neighbour *n; u32 mtu; if (net->ipv6.devconf_all->forwarding == 0) @@ -463,8 +462,7 @@ int ip6_forward(struct sk_buff *skb) send redirects to source routed frames. We don't send redirects to frames decapsulated from IPsec. */ - n = dst_get_neighbour_noref(dst); - if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) { + if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { struct in6_addr *target = NULL; struct rt6_info *rt; @@ -474,8 +472,8 @@ int ip6_forward(struct sk_buff *skb) */ rt = (struct rt6_info *) dst; - if ((rt->rt6i_flags & RTF_GATEWAY)) - target = (struct in6_addr*)&n->primary_key; + if (rt->rt6i_flags & RTF_GATEWAY) + target = &rt->rt6i_gateway; else target = &hdr->daddr; -- cgit v1.2.3-70-g09d2 From 84920c1420e2b4a4150e5bb45ee5a23ea4641523 Mon Sep 17 00:00:00 2001 From: Tony Zelenoff Date: Thu, 26 Jan 2012 22:28:58 +0000 Subject: net: Allow ipv6 proxies and arp proxies be shown with iproute2 Add ability to return neighbour proxies list to caller if it sent full ndmsg structure and has NTF_PROXY flag set. Before this patch (and before iproute2 patches): $ ip neigh add proxy 2001::1 dev eth0 $ ip -6 neigh show $ After it and with applied iproute2 patches: $ ip neigh add proxy 2001::1 dev eth0 $ ip -6 neigh show 2001::1 dev eth0 proxy $ Compatibility with old versions of iproute2 is not broken, kernel checks for incoming structure size and properly works if old structure is came. [v2] * changed comments style. * removed useless line with continue and curly bracket. * changed incoming message size check from equal to more or equal. CC: davem@davemloft.net CC: kuznet@ms2.inr.ac.ru CC: netdev@vger.kernel.org CC: xemul@parallels.com Signed-off-by: Tony Zelenoff Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/neighbour.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e287346e093..f98ec444133 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2165,6 +2165,35 @@ nla_put_failure: return -EMSGSIZE; } +static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn, + u32 pid, u32 seq, int type, unsigned int flags, + struct neigh_table *tbl) +{ + struct nlmsghdr *nlh; + struct ndmsg *ndm; + + nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); + if (nlh == NULL) + return -EMSGSIZE; + + ndm = nlmsg_data(nlh); + ndm->ndm_family = tbl->family; + ndm->ndm_pad1 = 0; + ndm->ndm_pad2 = 0; + ndm->ndm_flags = pn->flags | NTF_PROXY; + ndm->ndm_type = NDA_DST; + ndm->ndm_ifindex = pn->dev->ifindex; + ndm->ndm_state = NUD_NONE; + + NLA_PUT(skb, NDA_DST, tbl->key_len, pn->key); + + return nlmsg_end(skb, nlh); + +nla_put_failure: + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; +} + static void neigh_update_notify(struct neighbour *neigh) { call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); @@ -2214,23 +2243,78 @@ out: return rc; } +static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct pneigh_entry *n; + struct net *net = sock_net(skb->sk); + int rc, h, s_h = cb->args[3]; + int idx, s_idx = idx = cb->args[4]; + + read_lock_bh(&tbl->lock); + + for (h = 0; h <= PNEIGH_HASHMASK; h++) { + if (h < s_h) + continue; + if (h > s_h) + s_idx = 0; + for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { + if (dev_net(n->dev) != net) + continue; + if (idx < s_idx) + goto next; + if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_NEWNEIGH, + NLM_F_MULTI, tbl) <= 0) { + read_unlock_bh(&tbl->lock); + rc = -1; + goto out; + } + next: + idx++; + } + } + + read_unlock_bh(&tbl->lock); + rc = skb->len; +out: + cb->args[3] = h; + cb->args[4] = idx; + return rc; + +} + static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) { struct neigh_table *tbl; int t, family, s_t; + int proxy = 0; + int err = 0; read_lock(&neigh_tbl_lock); family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; + + /* check for full ndmsg structure presence, family member is + * the same for both structures + */ + if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) && + ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY) + proxy = 1; + s_t = cb->args[0]; - for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) { + for (tbl = neigh_tables, t = 0; tbl && (err >= 0); + tbl = tbl->next, t++) { if (t < s_t || (family && tbl->family != family)) continue; if (t > s_t) memset(&cb->args[1], 0, sizeof(cb->args) - sizeof(cb->args[0])); - if (neigh_dump_table(tbl, skb, cb) < 0) - break; + if (proxy) + err = pneigh_dump_table(tbl, skb, cb); + else + err = neigh_dump_table(tbl, skb, cb); } read_unlock(&neigh_tbl_lock); -- cgit v1.2.3-70-g09d2 From 5de658f878d49e952d7b3f3f26a396132829f513 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 30 Jan 2012 04:29:24 +0000 Subject: ipv6: fix RFC5722 comment RFC5722 Section 4 was amended by Errata 3089 Our implementation did the right thing anyway... Signed-off-by: Eric Dumazet Cc: Nicolas Dichtel Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv6/reassembly.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index b69fae76a6f..9447bd69873 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -336,12 +336,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, } found: - /* RFC5722, Section 4: - * When reassembling an IPv6 datagram, if + /* RFC5722, Section 4, amended by Errata ID : 3089 + * When reassembling an IPv6 datagram, if * one or more its constituent fragments is determined to be an * overlapping fragment, the entire datagram (and any constituent - * fragments, including those not yet received) MUST be silently - * discarded. + * fragments) MUST be silently discarded. */ /* Check for overlap with preceding fragment. */ -- cgit v1.2.3-70-g09d2 From a46621a3a8f24557201a7ef62de151c812f8985c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 30 Jan 2012 15:22:06 -0500 Subject: net: Deinline __nlmsg_put and genlmsg_put. -7k code on i386 defconfig. text data bss dec hex filename 8455963 532732 1810804 10799499 a4c98b vmlinux.o.before 8448899 532732 1810804 10792435 a4adf3 vmlinux.o This change also removes commented-out copy of __nlmsg_put which was last touched in 2005 with "Enable once all users have been converted" comment on top. Changes in v2: rediffed against net-next. Signed-off-by: Denys Vlasenko Signed-off-by: David S. Miller --- include/linux/netlink.h | 18 ++---------------- include/net/genetlink.h | 31 ++----------------------------- include/net/netlink.h | 35 ----------------------------------- net/netlink/af_netlink.c | 18 ++++++++++++++++++ net/netlink/genetlink.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 80 deletions(-) (limited to 'net') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 52e48959cfa..a390e9d5482 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -237,22 +237,8 @@ struct netlink_notify { int protocol; }; -static __inline__ struct nlmsghdr * -__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) -{ - struct nlmsghdr *nlh; - int size = NLMSG_LENGTH(len); - - nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size)); - nlh->nlmsg_type = type; - nlh->nlmsg_len = size; - nlh->nlmsg_flags = flags; - nlh->nlmsg_pid = pid; - nlh->nlmsg_seq = seq; - if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0) - memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size); - return nlh; -} +struct nlmsghdr * +__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags); #define NLMSG_NEW(skb, pid, seq, type, len, flags) \ ({ if (unlikely(skb_tailroom(skb) < (int)NLMSG_SPACE(len))) \ diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 7db32995ccd..ccb68880abf 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -131,35 +131,8 @@ extern void genl_unregister_mc_group(struct genl_family *family, extern void genl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, struct nlmsghdr *nlh, gfp_t flags); -/** - * genlmsg_put - Add generic netlink header to netlink message - * @skb: socket buffer holding the message - * @pid: netlink pid the message is addressed to - * @seq: sequence number (usually the one of the sender) - * @family: generic netlink family - * @flags netlink message flags - * @cmd: generic netlink command - * - * Returns pointer to user specific header - */ -static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, - struct genl_family *family, int flags, u8 cmd) -{ - struct nlmsghdr *nlh; - struct genlmsghdr *hdr; - - nlh = nlmsg_put(skb, pid, seq, family->id, GENL_HDRLEN + - family->hdrsize, flags); - if (nlh == NULL) - return NULL; - - hdr = nlmsg_data(nlh); - hdr->cmd = cmd; - hdr->version = family->version; - hdr->reserved = 0; - - return (char *) hdr + GENL_HDRLEN; -} +void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, + struct genl_family *family, int flags, u8 cmd); /** * genlmsg_nlhdr - Obtain netlink header from user specified header diff --git a/include/net/netlink.h b/include/net/netlink.h index cb1f3504687..f394fe5d764 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -441,41 +441,6 @@ static inline int nlmsg_report(const struct nlmsghdr *nlh) nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \ nlmsg_attrlen(nlh, hdrlen), rem) -#if 0 -/* FIXME: Enable once all users have been converted */ - -/** - * __nlmsg_put - Add a new netlink message to an skb - * @skb: socket buffer to store message in - * @pid: netlink process id - * @seq: sequence number of message - * @type: message type - * @payload: length of message payload - * @flags: message flags - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for both the netlink header and payload. - */ -static inline struct nlmsghdr *__nlmsg_put(struct sk_buff *skb, u32 pid, - u32 seq, int type, int payload, - int flags) -{ - struct nlmsghdr *nlh; - - nlh = (struct nlmsghdr *) skb_put(skb, nlmsg_total_size(payload)); - nlh->nlmsg_type = type; - nlh->nlmsg_len = nlmsg_msg_size(payload); - nlh->nlmsg_flags = flags; - nlh->nlmsg_pid = pid; - nlh->nlmsg_seq = seq; - - memset((unsigned char *) nlmsg_data(nlh) + payload, 0, - nlmsg_padlen(payload)); - - return nlh; -} -#endif - /** * nlmsg_put - Add a new netlink message to an skb * @skb: socket buffer to store message in diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 629b06182f3..4d751e3d4b4 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1645,6 +1645,24 @@ static void netlink_destroy_callback(struct netlink_callback *cb) kfree(cb); } +struct nlmsghdr * +__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) +{ + struct nlmsghdr *nlh; + int size = NLMSG_LENGTH(len); + + nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size)); + nlh->nlmsg_type = type; + nlh->nlmsg_len = size; + nlh->nlmsg_flags = flags; + nlh->nlmsg_pid = pid; + nlh->nlmsg_seq = seq; + if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0) + memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size); + return nlh; +} +EXPORT_SYMBOL(__nlmsg_put); + /* * It looks a bit ugly. * It would be better to create kernel thread. diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index c29d2568c9e..a1154717219 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -498,6 +498,37 @@ int genl_unregister_family(struct genl_family *family) } EXPORT_SYMBOL(genl_unregister_family); +/** + * genlmsg_put - Add generic netlink header to netlink message + * @skb: socket buffer holding the message + * @pid: netlink pid the message is addressed to + * @seq: sequence number (usually the one of the sender) + * @family: generic netlink family + * @flags netlink message flags + * @cmd: generic netlink command + * + * Returns pointer to user specific header + */ +void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, + struct genl_family *family, int flags, u8 cmd) +{ + struct nlmsghdr *nlh; + struct genlmsghdr *hdr; + + nlh = nlmsg_put(skb, pid, seq, family->id, GENL_HDRLEN + + family->hdrsize, flags); + if (nlh == NULL) + return NULL; + + hdr = nlmsg_data(nlh); + hdr->cmd = cmd; + hdr->version = family->version; + hdr->reserved = 0; + + return (char *) hdr + GENL_HDRLEN; +} +EXPORT_SYMBOL(genlmsg_put); + static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { struct genl_ops *ops; -- cgit v1.2.3-70-g09d2 From c037b8367c7e2b775a99d74037f5df014d2fbf06 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 30 Jan 2012 15:28:11 -0500 Subject: Revert "mac80211: Do not scan for IBSS merge with a fixed BSSID." This reverts commit f1e3be1561c43b6bbe2426e34849fb1486dc313b. Johannes Berg thinks that this patch is incorrect. I'll defer to his judgment. Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 93b3c7298be..d38baa41cf6 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -655,15 +655,14 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) if (ieee80211_sta_active_ibss(sdata)) return; - if (ifibss->fixed_bssid) + if (ifibss->fixed_channel) return; printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " "IBSS networks with same SSID (merge)\n", sdata->name); ieee80211_request_internal_scan(sdata, - ifibss->ssid, ifibss->ssid_len, - ifibss->fixed_channel ? ifibss->channel : NULL); + ifibss->ssid, ifibss->ssid_len, NULL); } static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) -- cgit v1.2.3-70-g09d2 From 83d5cc012441531ab0bf6f99881958e964e9cf11 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 Jan 2012 09:31:10 +0100 Subject: mac80211: station state transition error handling In the future, when we start notifying drivers, state transitions could potentially fail. To make it easier to distinguish between programming bugs and driver failures: * rename sta_info_move_state() to sta_info_pre_move_state() which can only be called before the station is inserted (and check this with a new station flag). * rename sta_info_move_state_checked() to just plain sta_info_move_state(), as it will be the regular function that can fail for more than just one reason (bad transition or an error from the driver) This makes the programming model easier -- one of the functions can only be called before insertion and can't fail, the other can fail. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 22 ++++++++-------------- net/mac80211/debugfs_sta.c | 5 +++-- net/mac80211/ibss.c | 6 +++--- net/mac80211/iface.c | 6 +++--- net/mac80211/mesh_plink.c | 6 +++--- net/mac80211/mlme.c | 17 +++++++++++++---- net/mac80211/sta_info.c | 19 ++++++++++++++----- net/mac80211/sta_info.h | 17 ++++++++++++----- 8 files changed, 59 insertions(+), 39 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 98460783c2d..dc742044157 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -776,12 +776,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) && !test_sta_flag(sta, WLAN_STA_AUTH)) { - ret = sta_info_move_state_checked(sta, - IEEE80211_STA_AUTH); + ret = sta_info_move_state(sta, IEEE80211_STA_AUTH); if (ret) return ret; - ret = sta_info_move_state_checked(sta, - IEEE80211_STA_ASSOC); + ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); if (ret) return ret; } @@ -789,11 +787,9 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) - ret = sta_info_move_state_checked(sta, - IEEE80211_STA_AUTHORIZED); + ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) - ret = sta_info_move_state_checked(sta, - IEEE80211_STA_ASSOC); + ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); if (ret) return ret; } @@ -805,12 +801,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) && test_sta_flag(sta, WLAN_STA_AUTH)) { - ret = sta_info_move_state_checked(sta, - IEEE80211_STA_AUTH); + ret = sta_info_move_state(sta, IEEE80211_STA_AUTH); if (ret) return ret; - ret = sta_info_move_state_checked(sta, - IEEE80211_STA_NONE); + ret = sta_info_move_state(sta, IEEE80211_STA_NONE); if (ret) return ret; } @@ -944,8 +938,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, if (!sta) return -ENOMEM; - sta_info_move_state(sta, IEEE80211_STA_AUTH); - sta_info_move_state(sta, IEEE80211_STA_ASSOC); + sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); + sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); err = sta_apply_parameters(local, sta, params); if (err) { diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 2406b3e7393..c8383712fde 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -63,14 +63,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" int res = scnprintf(buf, sizeof(buf), - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", TEST(AUTH), TEST(ASSOC), TEST(PS_STA), TEST(PS_DRIVER), TEST(AUTHORIZED), TEST(SHORT_PREAMBLE), TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), - TEST(TDLS_PEER_AUTH)); + TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), + TEST(INSERTED)); #undef TEST return simple_read_from_buffer(userbuf, count, ppos, buf, res); } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index d38baa41cf6..a98d370b56f 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -265,9 +265,9 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, addr, sdata->name); #endif - sta_info_move_state(sta, IEEE80211_STA_AUTH); - sta_info_move_state(sta, IEEE80211_STA_ASSOC); - sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); + sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); + sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); rate_control_rate_init(sta); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e47768cb8cb..6b0d70e960d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -318,9 +318,9 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) goto err_del_interface; } - sta_info_move_state(sta, IEEE80211_STA_AUTH); - sta_info_move_state(sta, IEEE80211_STA_ASSOC); - sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); + sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); + sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); res = sta_info_insert(sta); if (res) { diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 41ef1b47644..bf92e2878fe 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -96,9 +96,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; - sta_info_move_state(sta, IEEE80211_STA_AUTH); - sta_info_move_state(sta, IEEE80211_STA_ASSOC); - sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); + sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); + sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); set_sta_flag(sta, WLAN_STA_WME); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index de3268c7be1..acc11b5c16f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1587,10 +1587,19 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, return false; } - sta_info_move_state(sta, IEEE80211_STA_AUTH); - sta_info_move_state(sta, IEEE80211_STA_ASSOC); - if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + err = sta_info_move_state(sta, IEEE80211_STA_AUTH); + if (!err) + err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); + if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + if (err) { + printk(KERN_DEBUG + "%s: failed to move station %pM to desired state\n", + sdata->name, sta->sta.addr); + WARN_ON(__sta_info_destroy(sta)); + mutex_unlock(&sdata->local->sta_mtx); + return false; + } rates = 0; basic_rates = 0; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f28fa02b6e5..df8f0a2f0de 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -403,6 +403,8 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) sta_info_hash_add(local, sta); list_add(&sta->list, &local->sta_list); + + set_sta_flag(sta, WLAN_STA_INSERTED); } else { sta->dummy = false; } @@ -707,7 +709,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, return have_buffered; } -static int __must_check __sta_info_destroy(struct sta_info *sta) +int __must_check __sta_info_destroy(struct sta_info *sta) { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; @@ -722,6 +724,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) local = sta->local; sdata = sta->sdata; + lockdep_assert_held(&local->sta_mtx); + /* * Before removing the station from the driver and * rate control, it might still start new aggregation @@ -763,8 +767,13 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); - while (sta->sta_state > IEEE80211_STA_NONE) - sta_info_move_state(sta, sta->sta_state - 1); + while (sta->sta_state > IEEE80211_STA_NONE) { + int err = sta_info_move_state(sta, sta->sta_state - 1); + if (err) { + WARN_ON_ONCE(1); + break; + } + } if (sta->uploaded) { if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) @@ -1391,8 +1400,8 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, } EXPORT_SYMBOL(ieee80211_sta_set_buffered); -int sta_info_move_state_checked(struct sta_info *sta, - enum ieee80211_sta_state new_state) +int sta_info_move_state(struct sta_info *sta, + enum ieee80211_sta_state new_state) { might_sleep(); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6f77f12dc3f..381de37d247 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -52,6 +52,7 @@ * @WLAN_STA_SP: Station is in a service period, so don't try to * reply to other uAPSD trigger frames or PS-Poll. * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. + * @WLAN_STA_INSERTED: This station is inserted into the hash table. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH, @@ -71,6 +72,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_UAPSD, WLAN_STA_SP, WLAN_STA_4ADDR_EVENT, + WLAN_STA_INSERTED, }; enum ieee80211_sta_state { @@ -427,13 +429,17 @@ static inline int test_and_set_sta_flag(struct sta_info *sta, return test_and_set_bit(flag, &sta->_flags); } -int sta_info_move_state_checked(struct sta_info *sta, - enum ieee80211_sta_state new_state); +int sta_info_move_state(struct sta_info *sta, + enum ieee80211_sta_state new_state); -static inline void sta_info_move_state(struct sta_info *sta, - enum ieee80211_sta_state new_state) +static inline void sta_info_pre_move_state(struct sta_info *sta, + enum ieee80211_sta_state new_state) { - int ret = sta_info_move_state_checked(sta, new_state); + int ret; + + WARN_ON_ONCE(test_sta_flag(sta, WLAN_STA_INSERTED)); + + ret = sta_info_move_state(sta, new_state); WARN_ON_ONCE(ret); } @@ -544,6 +550,7 @@ int sta_info_insert(struct sta_info *sta); int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); int sta_info_reinsert(struct sta_info *sta); +int __must_check __sta_info_destroy(struct sta_info *sta); int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr); int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3-70-g09d2 From 2ab694d302b489c5aa49c360dc97149b77c96586 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 27 Jan 2012 11:02:51 +0100 Subject: mac80211: Fix incorrect num_sta_ps decrement in __sta_info_destroy When WLAN_STA_PS_DRIVER is set by ieee80211_sta_block_awake the num_sta_ps counter is not incremented. Hence, we shouldn't decrement it in __sta_info_destroy if only WLAN_STA_PS_DRIVER is set. This could result in an incorrect num_sta_ps counter leading to strange side effects with associated powersaving clients. Fix this by only decrementing num_sta_ps when WLAN_STA_PS_STA was set before. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index df8f0a2f0de..0c79593b1bb 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -750,12 +750,10 @@ int __must_check __sta_info_destroy(struct sta_info *sta) sta->dead = true; - if (test_sta_flag(sta, WLAN_STA_PS_STA) || - test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { + if (test_sta_flag(sta, WLAN_STA_PS_STA)) { BUG_ON(!sdata->bss); clear_sta_flag(sta, WLAN_STA_PS_STA); - clear_sta_flag(sta, WLAN_STA_PS_DRIVER); atomic_dec(&sdata->bss->num_sta_ps); sta_info_recalc_tim(sta); -- cgit v1.2.3-70-g09d2 From 608383bfc04aa222c3e9e896c32f56a5e5deaff0 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 30 Jan 2012 15:18:00 +0100 Subject: mac80211: Fix incorrect num_sta_ps decrement in ap_sta_ps_end If the driver blocked this specific STA with the help of ieee80211_sta_block_awake we won't clear WLAN_STA_PS_STA later but still decrement num_sta_ps. Hence, the next data frame from this STA will trigger ap_sta_ps_end again and also decrement num_sta_ps again leading to an incorrect num_sta_ps counter. This can result in problems with powersaving clients not waking up from PS because the TIM calculation might be skipped due to the incorrect num_sta_ps counter. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/rx.c | 8 ++------ net/mac80211/sta_info.c | 4 +++- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 73d213810a3..ab29253fb4f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1145,19 +1145,15 @@ static void ap_sta_ps_start(struct sta_info *sta) static void ap_sta_ps_end(struct sta_info *sta) { - struct ieee80211_sub_if_data *sdata = sta->sdata; - - atomic_dec(&sdata->bss->num_sta_ps); - #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", - sdata->name, sta->sta.addr, sta->sta.aid); + sta->sdata->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", - sdata->name, sta->sta.addr, sta->sta.aid); + sta->sdata->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ return; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 0c79593b1bb..1fb4770a7d1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -997,9 +997,11 @@ EXPORT_SYMBOL(ieee80211_find_sta); static void clear_sta_ps_flags(void *_sta) { struct sta_info *sta = _sta; + struct ieee80211_sub_if_data *sdata = sta->sdata; clear_sta_flag(sta, WLAN_STA_PS_DRIVER); - clear_sta_flag(sta, WLAN_STA_PS_STA); + if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) + atomic_dec(&sdata->bss->num_sta_ps); } /* powersave support code */ -- cgit v1.2.3-70-g09d2 From 24db78c05b1e3ccb5a78aedd17aa1008c91dab5a Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Sat, 28 Jan 2012 17:25:32 +0100 Subject: nl80211: add support for mcs masks Allow to set mcs masks through nl80211. We also allow to set MCS rates but no legacy rates (and vice versa). Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++++ include/net/cfg80211.h | 3 +-- net/wireless/nl80211.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 4f98fae1330..ad56e21a9f1 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1475,6 +1475,7 @@ enum nl80211_attrs { #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS #define NL80211_MAX_SUPP_RATES 32 +#define NL80211_MAX_SUPP_HT_RATES 77 #define NL80211_MAX_SUPP_REG_RULES 32 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 @@ -2405,12 +2406,15 @@ enum nl80211_key_attributes { * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with * 1 = 500 kbps) but without the IE length restriction (at most * %NL80211_MAX_SUPP_RATES in a single array). + * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * in an array of MCS numbers. * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ enum nl80211_tx_rate_attributes { __NL80211_TXRATE_INVALID, NL80211_TXRATE_LEGACY, + NL80211_TXRATE_MCS, /* keep last */ __NL80211_TXRATE_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5bb3ed4f99f..2964205332f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1232,8 +1232,7 @@ enum wiphy_params_flags { struct cfg80211_bitrate_mask { struct { u32 legacy; - /* TODO: add support for masking MCS rates; e.g.: */ - /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */ + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; } control[IEEE80211_NUM_BANDS]; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c42173f947e..c910b0750dc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5393,9 +5393,39 @@ static u32 rateset_to_mask(struct ieee80211_supported_band *sband, return mask; } +static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, + u8 *rates, u8 rates_len, + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]) +{ + u8 i; + + memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN); + + for (i = 0; i < rates_len; i++) { + int ridx, rbit; + + ridx = rates[i] / 8; + rbit = BIT(rates[i] % 8); + + /* check validity */ + if ((ridx < 0) || (ridx > IEEE80211_HT_MCS_MASK_LEN)) + return false; + + /* check availability */ + if (sband->ht_cap.mcs.rx_mask[ridx] & rbit) + mcs[ridx] |= rbit; + else + return false; + } + + return true; +} + static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, + [NL80211_TXRATE_MCS] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_HT_RATES }, }; static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, @@ -5421,12 +5451,20 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, sband = rdev->wiphy.bands[i]; mask.control[i].legacy = sband ? (1 << sband->n_bitrates) - 1 : 0; + if (sband) + memcpy(mask.control[i].mcs, + sband->ht_cap.mcs.rx_mask, + sizeof(mask.control[i].mcs)); + else + memset(mask.control[i].mcs, 0, + sizeof(mask.control[i].mcs)); } /* * The nested attribute uses enum nl80211_band as the index. This maps * directly to the enum ieee80211_band values used in cfg80211. */ + BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { enum ieee80211_band band = nla_type(tx_rates); @@ -5442,7 +5480,28 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, sband, nla_data(tb[NL80211_TXRATE_LEGACY]), nla_len(tb[NL80211_TXRATE_LEGACY])); - if (mask.control[band].legacy == 0) + } + if (tb[NL80211_TXRATE_MCS]) { + if (!ht_rateset_to_mask( + sband, + nla_data(tb[NL80211_TXRATE_MCS]), + nla_len(tb[NL80211_TXRATE_MCS]), + mask.control[band].mcs)) + return -EINVAL; + } + + if (mask.control[band].legacy == 0) { + /* don't allow empty legacy rates if HT + * is not even supported. */ + if (!rdev->wiphy.bands[band]->ht_cap.ht_supported) + return -EINVAL; + + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) + if (mask.control[band].mcs[i]) + break; + + /* legacy and mcs rates may not be both empty */ + if (i == IEEE80211_HT_MCS_MASK_LEN) return -EINVAL; } } -- cgit v1.2.3-70-g09d2 From 19468413e8d98d44be8daf0acaf8d576dfc53fa2 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Sat, 28 Jan 2012 17:25:33 +0100 Subject: mac80211: add support for mcs masks * Handle MCS masks set by the user. * Match rates provided by the rate control algorithm to the mask set, also in HT mode, and switch back to legacy mode if necessary. * add debugfs files to observate the rate selection Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- include/net/mac80211.h | 1 + net/mac80211/cfg.c | 5 +- net/mac80211/debugfs_netdev.c | 34 ++++++++++++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 7 +++ net/mac80211/rate.c | 124 +++++++++++++++++++++++++++++++++++++++--- net/mac80211/tx.c | 5 ++ 7 files changed, 168 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 65018587684..520eb4c5e5a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3551,6 +3551,7 @@ struct ieee80211_tx_rate_control { bool rts, short_preamble; u8 max_rate_idx; u32 rate_idx_mask; + u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; bool bss; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index dc742044157..d15ba0d0de9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1902,8 +1902,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, return ret; } - for (i = 0; i < IEEE80211_NUM_BANDS; i++) + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { sdata->rc_rateidx_mask[i] = mask->control[i].legacy; + memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs, + sizeof(mask->control[i].mcs)); + } return 0; } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 81d12e65a23..510ed1dab3c 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -87,6 +87,21 @@ static ssize_t ieee80211_if_fmt_##name( \ #define IEEE80211_IF_FMT_SIZE(name, field) \ IEEE80211_IF_FMT(name, field, "%zd\n") +#define IEEE80211_IF_FMT_HEXARRAY(name, field) \ +static ssize_t ieee80211_if_fmt_##name( \ + const struct ieee80211_sub_if_data *sdata, \ + char *buf, int buflen) \ +{ \ + char *p = buf; \ + int i; \ + for (i = 0; i < sizeof(sdata->field); i++) { \ + p += scnprintf(p, buflen + buf - p, "%.2x ", \ + sdata->field[i]); \ + } \ + p += scnprintf(p, buflen + buf - p, "\n"); \ + return p - buf; \ +} + #define IEEE80211_IF_FMT_ATOMIC(name, field) \ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, \ @@ -148,6 +163,11 @@ IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], HEX); IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], HEX); +IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz, + rc_rateidx_mcs_mask[IEEE80211_BAND_2GHZ], HEXARRAY); +IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, + rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY); + IEEE80211_IF_FILE(flags, flags, HEX); IEEE80211_IF_FILE(state, state, LHEX); IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); @@ -442,6 +462,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(channel_type); DEBUGFS_ADD(rc_rateidx_mask_2ghz); DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); DEBUGFS_ADD(bssid); DEBUGFS_ADD(aid); @@ -459,6 +481,8 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(channel_type); DEBUGFS_ADD(rc_rateidx_mask_2ghz); DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); DEBUGFS_ADD(num_sta_authorized); DEBUGFS_ADD(num_sta_ps); @@ -469,6 +493,12 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) static void add_ibss_files(struct ieee80211_sub_if_data *sdata) { + DEBUGFS_ADD(channel_type); + DEBUGFS_ADD(rc_rateidx_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); + DEBUGFS_ADD_MODE(tsf, 0600); } @@ -480,6 +510,8 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(channel_type); DEBUGFS_ADD(rc_rateidx_mask_2ghz); DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); DEBUGFS_ADD(peer); } @@ -492,6 +524,8 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(channel_type); DEBUGFS_ADD(rc_rateidx_mask_2ghz); DEBUGFS_ADD(rc_rateidx_mask_5ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); + DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ca6486b941b..d47e8c110b1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -646,6 +646,7 @@ struct ieee80211_sub_if_data { /* bitmap of allowed (non-MCS) rate indexes for rate control */ u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; + u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN]; union { struct ieee80211_if_ap ap; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6b0d70e960d..c33feede5dc 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1181,6 +1181,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sband = local->hw.wiphy->bands[i]; sdata->rc_rateidx_mask[i] = sband ? (1 << sband->n_bitrates) - 1 : 0; + if (sband) + memcpy(sdata->rc_rateidx_mcs_mask[i], + sband->ht_cap.mcs.rx_mask, + sizeof(sdata->rc_rateidx_mcs_mask[i])); + else + memset(sdata->rc_rateidx_mcs_mask[i], 0, + sizeof(sdata->rc_rateidx_mcs_mask[i])); } /* setup type-dependent data */ diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index a21110aecd1..3fef26d8898 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -289,8 +289,8 @@ bool rate_control_send_low(struct ieee80211_sta *sta, } EXPORT_SYMBOL(rate_control_send_low); -static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, - int n_bitrates, u32 mask) +static bool rate_idx_match_legacy_mask(struct ieee80211_tx_rate *rate, + int n_bitrates, u32 mask) { int j; @@ -299,7 +299,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, if (mask & (1 << j)) { /* Okay, found a suitable rate. Use it. */ rate->idx = j; - return; + return true; } } @@ -308,6 +308,112 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, if (mask & (1 << j)) { /* Okay, found a suitable rate. Use it. */ rate->idx = j; + return true; + } + } + return false; +} + +static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate, + u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +{ + int i, j; + int ridx, rbit; + + ridx = rate->idx / 8; + rbit = rate->idx % 8; + + /* sanity check */ + if (ridx < 0 || ridx > IEEE80211_HT_MCS_MASK_LEN) + return false; + + /* See whether the selected rate or anything below it is allowed. */ + for (i = ridx; i >= 0; i--) { + for (j = rbit; j >= 0; j--) + if (mcs_mask[i] & BIT(j)) { + rate->idx = i * 8 + j; + return true; + } + rbit = 7; + } + + /* Try to find a higher rate that would be allowed */ + ridx = (rate->idx + 1) / 8; + rbit = (rate->idx + 1) % 8; + + for (i = ridx; i < IEEE80211_HT_MCS_MASK_LEN; i++) { + for (j = rbit; j < 8; j++) + if (mcs_mask[i] & BIT(j)) { + rate->idx = i * 8 + j; + return true; + } + rbit = 0; + } + return false; +} + + + +static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, + struct ieee80211_tx_rate_control *txrc, + u32 mask, + u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +{ + struct ieee80211_tx_rate alt_rate; + + /* handle HT rates */ + if (rate->flags & IEEE80211_TX_RC_MCS) { + if (rate_idx_match_mcs_mask(rate, mcs_mask)) + return; + + /* also try the legacy rates. */ + alt_rate.idx = 0; + /* keep protection flags */ + alt_rate.flags = rate->flags & + (IEEE80211_TX_RC_USE_RTS_CTS | + IEEE80211_TX_RC_USE_CTS_PROTECT | + IEEE80211_TX_RC_USE_SHORT_PREAMBLE); + alt_rate.count = rate->count; + if (rate_idx_match_legacy_mask(&alt_rate, + txrc->sband->n_bitrates, + mask)) { + *rate = alt_rate; + return; + } + } else { + struct sk_buff *skb = txrc->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + __le16 fc; + + /* handle legacy rates */ + if (rate_idx_match_legacy_mask(rate, txrc->sband->n_bitrates, + mask)) + return; + + /* if HT BSS, and we handle a data frame, also try HT rates */ + if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT) + return; + + fc = hdr->frame_control; + if (!ieee80211_is_data(fc)) + return; + + alt_rate.idx = 0; + /* keep protection flags */ + alt_rate.flags = rate->flags & + (IEEE80211_TX_RC_USE_RTS_CTS | + IEEE80211_TX_RC_USE_CTS_PROTECT | + IEEE80211_TX_RC_USE_SHORT_PREAMBLE); + alt_rate.count = rate->count; + + alt_rate.flags |= IEEE80211_TX_RC_MCS; + + if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) || + (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS)) + alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + + if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { + *rate = alt_rate; return; } } @@ -331,6 +437,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); int i; u32 mask; + u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; if (sta) { ista = &sta->sta; @@ -354,10 +461,14 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, * the common case. */ mask = sdata->rc_rateidx_mask[info->band]; + memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band], + sizeof(mcs_mask)); if (mask != (1 << txrc->sband->n_bitrates) - 1) { if (sta) { /* Filter out rates that the STA does not support */ mask &= sta->sta.supp_rates[info->band]; + for (i = 0; i < sizeof(mcs_mask); i++) + mcs_mask[i] &= sta->sta.ht_cap.mcs.rx_mask[i]; } /* * Make sure the rate index selected for each TX rate is @@ -368,11 +479,8 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, /* Skip invalid rates */ if (info->control.rates[i].idx < 0) break; - /* Rate masking supports only legacy rates for now */ - if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) - continue; - rate_idx_match_mask(&info->control.rates[i], - txrc->sband->n_bitrates, mask); + rate_idx_match_mask(&info->control.rates[i], txrc, + mask, mcs_mask); } } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e05667cd5e7..1be0ca2b593 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -635,6 +635,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.max_rate_idx = -1; else txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; + memcpy(txrc.rate_idx_mcs_mask, + tx->sdata->rc_rateidx_mcs_mask[tx->channel->band], + sizeof(txrc.rate_idx_mcs_mask)); txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT || tx->sdata->vif.type == NL80211_IFTYPE_ADHOC); @@ -2431,6 +2434,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, txrc.max_rate_idx = -1; else txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; + memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band], + sizeof(txrc.rate_idx_mcs_mask)); txrc.bss = true; rate_control_get_rate(sdata, NULL, &txrc); -- cgit v1.2.3-70-g09d2 From 4f3eb0ba4817e55e1b5b2f63fcf3f266c328fc1a Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 27 Jan 2012 11:02:53 +0100 Subject: mac80211: Move num_sta_ps counter decrement after synchronize_rcu Unted the assumption that the sta struct is still accessible before the synchronize_rcu call we should move the num_sta_ps counter decrement after synchronize_rcu to avoid incorrect decrements if num_sta_ps. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1fb4770a7d1..fa0823892b2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -750,15 +750,6 @@ int __must_check __sta_info_destroy(struct sta_info *sta) sta->dead = true; - if (test_sta_flag(sta, WLAN_STA_PS_STA)) { - BUG_ON(!sdata->bss); - - clear_sta_flag(sta, WLAN_STA_PS_STA); - - atomic_dec(&sdata->bss->num_sta_ps); - sta_info_recalc_tim(sta); - } - local->num_sta--; local->sta_generation++; @@ -790,6 +781,15 @@ int __must_check __sta_info_destroy(struct sta_info *sta) */ synchronize_rcu(); + if (test_sta_flag(sta, WLAN_STA_PS_STA)) { + BUG_ON(!sdata->bss); + + clear_sta_flag(sta, WLAN_STA_PS_STA); + + atomic_dec(&sdata->bss->num_sta_ps); + sta_info_recalc_tim(sta); + } + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); __skb_queue_purge(&sta->ps_tx_buf[ac]); -- cgit v1.2.3-70-g09d2 From a2d91241a80ec9bbc5ab24b9a2c4d730b3fa5730 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 31 Jan 2012 01:04:42 +0000 Subject: tcp: md5: remove obsolete md5_add() method We no longer use md5_add() method from struct tcp_sock_af_ops Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 4 ---- net/ipv4/tcp_ipv4.c | 8 -------- net/ipv6/tcp_ipv6.c | 9 --------- 3 files changed, 21 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 0118ea999f6..3c903462adf 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1462,10 +1462,6 @@ struct tcp_sock_af_ops { const struct sock *sk, const struct request_sock *req, const struct sk_buff *skb); - int (*md5_add) (struct sock *sk, - struct sock *addr_sk, - u8 *newkey, - u8 len); int (*md5_parse) (struct sock *sk, char __user *optval, int optlen); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 337ba4cca05..345e24928fa 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -967,13 +967,6 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, } EXPORT_SYMBOL(tcp_v4_md5_do_add); -static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, - u8 *newkey, u8 newkeylen) -{ - return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->inet_daddr, - newkey, newkeylen); -} - int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) { struct tcp_sock *tp = tcp_sk(sk); @@ -1853,7 +1846,6 @@ EXPORT_SYMBOL(ipv4_specific); static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = { .md5_lookup = tcp_v4_md5_lookup, .calc_md5_hash = tcp_v4_md5_hash_skb, - .md5_add = tcp_v4_md5_add_func, .md5_parse = tcp_v4_parse_md5_keys, }; #endif diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3edd05ae438..f37769ea637 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -626,13 +626,6 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer, return 0; } -static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk, - u8 *newkey, __u8 newkeylen) -{ - return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr, - newkey, newkeylen); -} - static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer) { struct tcp_sock *tp = tcp_sk(sk); @@ -1898,7 +1891,6 @@ static const struct inet_connection_sock_af_ops ipv6_specific = { static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { .md5_lookup = tcp_v6_md5_lookup, .calc_md5_hash = tcp_v6_md5_hash_skb, - .md5_add = tcp_v6_md5_add_func, .md5_parse = tcp_v6_parse_md5_keys, }; #endif @@ -1930,7 +1922,6 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { .md5_lookup = tcp_v4_md5_lookup, .calc_md5_hash = tcp_v4_md5_hash_skb, - .md5_add = tcp_v6_md5_add_func, .md5_parse = tcp_v6_parse_md5_keys, }; #endif -- cgit v1.2.3-70-g09d2 From a915da9b69273815527ccb3789421cb7027b545b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 31 Jan 2012 05:18:33 +0000 Subject: tcp: md5: rcu conversion In order to be able to support proper RST messages for TCP MD5 flows, we need to allow access to MD5 keys without locking listener socket. This conversion is a nice cleanup, and shrinks size of timewait sockets by 80 bytes. IPv6 code reuses generic code found in IPv4 instead of duplicating it. Control path uses GFP_KERNEL allocations instead of GFP_ATOMIC. Signed-off-by: Eric Dumazet Cc: Shawn Lu Signed-off-by: David S. Miller --- include/linux/tcp.h | 3 +- include/net/tcp.h | 61 ++++++------- net/ipv4/tcp_ipv4.c | 227 +++++++++++++++++++---------------------------- net/ipv4/tcp_minisocks.c | 12 +-- net/ipv6/tcp_ipv6.c | 173 +++--------------------------------- 5 files changed, 141 insertions(+), 335 deletions(-) (limited to 'net') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 46a85c9e1f2..c2025f15964 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -486,8 +486,7 @@ struct tcp_timewait_sock { u32 tw_ts_recent; long tw_ts_recent_stamp; #ifdef CONFIG_TCP_MD5SIG - u16 tw_md5_keylen; - u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; + struct tcp_md5sig_key *tw_md5_key; #endif /* Few sockets in timewait have cookies; in that case, then this * object holds a reference to them (tw_cookie_values->kref). diff --git a/include/net/tcp.h b/include/net/tcp.h index 3c903462adf..10ae4c7b6b4 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1130,35 +1130,26 @@ static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) /* MD5 Signature */ struct crypto_hash; +union tcp_md5_addr { + struct in_addr a4; +#if IS_ENABLED(CONFIG_IPV6) + struct in6_addr a6; +#endif +}; + /* - key database */ struct tcp_md5sig_key { - u8 *key; + struct hlist_node node; u8 keylen; -}; - -struct tcp4_md5sig_key { - struct tcp_md5sig_key base; - __be32 addr; -}; - -struct tcp6_md5sig_key { - struct tcp_md5sig_key base; -#if 0 - u32 scope_id; /* XXX */ -#endif - struct in6_addr addr; + u8 family; /* AF_INET or AF_INET6 */ + union tcp_md5_addr addr; + u8 key[TCP_MD5SIG_MAXKEYLEN]; + struct rcu_head rcu; }; /* - sock block */ struct tcp_md5sig_info { - struct tcp4_md5sig_key *keys4; -#if IS_ENABLED(CONFIG_IPV6) - struct tcp6_md5sig_key *keys6; - u32 entries6; - u32 alloced6; -#endif - u32 entries4; - u32 alloced4; + struct hlist_head head; }; /* - pseudo header */ @@ -1195,19 +1186,25 @@ extern int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, const struct sock *sk, const struct request_sock *req, const struct sk_buff *skb); -extern struct tcp_md5sig_key * tcp_v4_md5_lookup(struct sock *sk, - struct sock *addr_sk); -extern int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, u8 *newkey, - u8 newkeylen); -extern int tcp_v4_md5_do_del(struct sock *sk, __be32 addr); +extern int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, + int family, const u8 *newkey, + u8 newkeylen, gfp_t gfp); +extern int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, + int family); +extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, + struct sock *addr_sk); #ifdef CONFIG_TCP_MD5SIG -#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_keylen ? \ - &(struct tcp_md5sig_key) { \ - .key = (twsk)->tw_md5_key, \ - .keylen = (twsk)->tw_md5_keylen, \ - } : NULL) +extern struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk, + const union tcp_md5_addr *addr, int family); +#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_key) #else +static inline struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk, + const union tcp_md5_addr *addr, + int family) +{ + return NULL; +} #define tcp_twsk_md5_key(twsk) NULL #endif diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 345e24928fa..1d5fd82c5c0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -90,16 +90,8 @@ EXPORT_SYMBOL(sysctl_tcp_low_latency); #ifdef CONFIG_TCP_MD5SIG -static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, - __be32 addr); -static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, +static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, __be32 daddr, __be32 saddr, const struct tcphdr *th); -#else -static inline -struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) -{ - return NULL; -} #endif struct inet_hashinfo tcp_hashinfo; @@ -631,7 +623,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; + key = sk ? tcp_md5_do_lookup(sk, + (union tcp_md5_addr *)&ip_hdr(skb)->saddr, + AF_INET) : NULL; if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -759,7 +753,8 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent, 0, - tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr), + tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, + AF_INET), inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, ip_hdr(skb)->tos); } @@ -876,146 +871,124 @@ static struct ip_options_rcu *tcp_v4_save_options(struct sock *sk, */ /* Find the Key structure for an address. */ -static struct tcp_md5sig_key * - tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) +struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk, + const union tcp_md5_addr *addr, + int family) { struct tcp_sock *tp = tcp_sk(sk); - int i; + struct tcp_md5sig_key *key; + struct hlist_node *pos; + unsigned int size = sizeof(struct in_addr); - if (!tp->md5sig_info || !tp->md5sig_info->entries4) + if (!tp->md5sig_info) return NULL; - for (i = 0; i < tp->md5sig_info->entries4; i++) { - if (tp->md5sig_info->keys4[i].addr == addr) - return &tp->md5sig_info->keys4[i].base; +#if IS_ENABLED(CONFIG_IPV6) + if (family == AF_INET6) + size = sizeof(struct in6_addr); +#endif + hlist_for_each_entry_rcu(key, pos, &tp->md5sig_info->head, node) { + if (key->family != family) + continue; + if (!memcmp(&key->addr, addr, size)) + return key; } return NULL; } +EXPORT_SYMBOL(tcp_md5_do_lookup); struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, struct sock *addr_sk) { - return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr); + union tcp_md5_addr *addr; + + addr = (union tcp_md5_addr *)&inet_sk(addr_sk)->inet_daddr; + return tcp_md5_do_lookup(sk, addr, AF_INET); } EXPORT_SYMBOL(tcp_v4_md5_lookup); static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, struct request_sock *req) { - return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); + union tcp_md5_addr *addr; + + addr = (union tcp_md5_addr *)&inet_rsk(req)->rmt_addr; + return tcp_md5_do_lookup(sk, addr, AF_INET); } /* This can be called on a newly created socket, from other files */ -int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, - u8 *newkey, u8 newkeylen) +int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, + int family, const u8 *newkey, u8 newkeylen, gfp_t gfp) { /* Add Key to the list */ struct tcp_md5sig_key *key; struct tcp_sock *tp = tcp_sk(sk); - struct tcp4_md5sig_key *keys; + struct tcp_md5sig_info *md5sig; - key = tcp_v4_md5_do_lookup(sk, addr); + key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET); if (key) { /* Pre-existing entry - just update that one. */ - kfree(key->key); - key->key = newkey; + memcpy(key->key, newkey, newkeylen); key->keylen = newkeylen; - } else { - struct tcp_md5sig_info *md5sig; - - if (!tp->md5sig_info) { - tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), - GFP_ATOMIC); - if (!tp->md5sig_info) { - kfree(newkey); - return -ENOMEM; - } - sk_nocaps_add(sk, NETIF_F_GSO_MASK); - } + return 0; + } - md5sig = tp->md5sig_info; - if (md5sig->entries4 == 0 && - tcp_alloc_md5sig_pool(sk) == NULL) { - kfree(newkey); + md5sig = tp->md5sig_info; + if (!md5sig) { + md5sig = kmalloc(sizeof(*md5sig), gfp); + if (!md5sig) return -ENOMEM; - } - - if (md5sig->alloced4 == md5sig->entries4) { - keys = kmalloc((sizeof(*keys) * - (md5sig->entries4 + 1)), GFP_ATOMIC); - if (!keys) { - kfree(newkey); - if (md5sig->entries4 == 0) - tcp_free_md5sig_pool(); - return -ENOMEM; - } - if (md5sig->entries4) - memcpy(keys, md5sig->keys4, - sizeof(*keys) * md5sig->entries4); + sk_nocaps_add(sk, NETIF_F_GSO_MASK); + INIT_HLIST_HEAD(&md5sig->head); + tp->md5sig_info = md5sig; + } - /* Free old key list, and reference new one */ - kfree(md5sig->keys4); - md5sig->keys4 = keys; - md5sig->alloced4++; - } - md5sig->entries4++; - md5sig->keys4[md5sig->entries4 - 1].addr = addr; - md5sig->keys4[md5sig->entries4 - 1].base.key = newkey; - md5sig->keys4[md5sig->entries4 - 1].base.keylen = newkeylen; + key = kmalloc(sizeof(*key), gfp); + if (!key) + return -ENOMEM; + if (hlist_empty(&md5sig->head) && !tcp_alloc_md5sig_pool(sk)) { + kfree(key); + return -ENOMEM; } + + memcpy(key->key, newkey, newkeylen); + key->keylen = newkeylen; + key->family = family; + memcpy(&key->addr, addr, + (family == AF_INET6) ? sizeof(struct in6_addr) : + sizeof(struct in_addr)); + hlist_add_head_rcu(&key->node, &md5sig->head); return 0; } -EXPORT_SYMBOL(tcp_v4_md5_do_add); +EXPORT_SYMBOL(tcp_md5_do_add); -int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) +int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) { struct tcp_sock *tp = tcp_sk(sk); - int i; - - for (i = 0; i < tp->md5sig_info->entries4; i++) { - if (tp->md5sig_info->keys4[i].addr == addr) { - /* Free the key */ - kfree(tp->md5sig_info->keys4[i].base.key); - tp->md5sig_info->entries4--; - - if (tp->md5sig_info->entries4 == 0) { - kfree(tp->md5sig_info->keys4); - tp->md5sig_info->keys4 = NULL; - tp->md5sig_info->alloced4 = 0; - tcp_free_md5sig_pool(); - } else if (tp->md5sig_info->entries4 != i) { - /* Need to do some manipulation */ - memmove(&tp->md5sig_info->keys4[i], - &tp->md5sig_info->keys4[i+1], - (tp->md5sig_info->entries4 - i) * - sizeof(struct tcp4_md5sig_key)); - } - return 0; - } - } - return -ENOENT; + struct tcp_md5sig_key *key; + + key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET); + if (!key) + return -ENOENT; + hlist_del_rcu(&key->node); + kfree_rcu(key, rcu); + if (hlist_empty(&tp->md5sig_info->head)) + tcp_free_md5sig_pool(); + return 0; } -EXPORT_SYMBOL(tcp_v4_md5_do_del); +EXPORT_SYMBOL(tcp_md5_do_del); -static void tcp_v4_clear_md5_list(struct sock *sk) +void tcp_clear_md5_list(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + struct tcp_md5sig_key *key; + struct hlist_node *pos, *n; - /* Free each key, then the set of key keys, - * the crypto element, and then decrement our - * hold on the last resort crypto. - */ - if (tp->md5sig_info->entries4) { - int i; - for (i = 0; i < tp->md5sig_info->entries4; i++) - kfree(tp->md5sig_info->keys4[i].base.key); - tp->md5sig_info->entries4 = 0; + if (!hlist_empty(&tp->md5sig_info->head)) tcp_free_md5sig_pool(); - } - if (tp->md5sig_info->keys4) { - kfree(tp->md5sig_info->keys4); - tp->md5sig_info->keys4 = NULL; - tp->md5sig_info->alloced4 = 0; + hlist_for_each_entry_safe(key, pos, n, &tp->md5sig_info->head, node) { + hlist_del_rcu(&key->node); + kfree_rcu(key, rcu); } } @@ -1024,7 +997,6 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, { struct tcp_md5sig cmd; struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; - u8 *newkey; if (optlen < sizeof(cmd)) return -EINVAL; @@ -1038,29 +1010,16 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, if (!cmd.tcpm_key || !cmd.tcpm_keylen) { if (!tcp_sk(sk)->md5sig_info) return -ENOENT; - return tcp_v4_md5_do_del(sk, sin->sin_addr.s_addr); + return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, + AF_INET); } if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) return -EINVAL; - if (!tcp_sk(sk)->md5sig_info) { - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_info *p; - - p = kzalloc(sizeof(*p), sk->sk_allocation); - if (!p) - return -EINVAL; - - tp->md5sig_info = p; - sk_nocaps_add(sk, NETIF_F_GSO_MASK); - } - - newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, sk->sk_allocation); - if (!newkey) - return -ENOMEM; - return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, - newkey, cmd.tcpm_keylen); + return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, + AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, + GFP_KERNEL); } static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, @@ -1086,7 +1045,7 @@ static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); } -static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, +static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, __be32 daddr, __be32 saddr, const struct tcphdr *th) { struct tcp_md5sig_pool *hp; @@ -1186,7 +1145,8 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) int genhash; unsigned char newhash[16]; - hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); + hash_expected = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&iph->saddr, + AF_INET); hash_location = tcp_parse_md5sig_option(th); /* We've parsed the options - do we have a hash? */ @@ -1474,7 +1434,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, #ifdef CONFIG_TCP_MD5SIG /* Copy over the MD5 key from the original socket */ - key = tcp_v4_md5_do_lookup(sk, newinet->inet_daddr); + key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&newinet->inet_daddr, + AF_INET); if (key != NULL) { /* * We're using one, so create a matching key @@ -1482,10 +1443,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, * memory, then we end up not copying the key * across. Shucks. */ - char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); - if (newkey != NULL) - tcp_v4_md5_do_add(newsk, newinet->inet_daddr, - newkey, key->keylen); + tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr, + AF_INET, key->key, key->keylen, GFP_ATOMIC); sk_nocaps_add(newsk, NETIF_F_GSO_MASK); } #endif @@ -1934,7 +1893,7 @@ void tcp_v4_destroy_sock(struct sock *sk) #ifdef CONFIG_TCP_MD5SIG /* Clean up the MD5 key list, if any */ if (tp->md5sig_info) { - tcp_v4_clear_md5_list(sk); + tcp_clear_md5_list(sk); kfree(tp->md5sig_info); tp->md5sig_info = NULL; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 550e755747e..3cabafb5cdd 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -359,13 +359,11 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) */ do { struct tcp_md5sig_key *key; - memset(tcptw->tw_md5_key, 0, sizeof(tcptw->tw_md5_key)); - tcptw->tw_md5_keylen = 0; + tcptw->tw_md5_key = NULL; key = tp->af_specific->md5_lookup(sk, sk); if (key != NULL) { - memcpy(&tcptw->tw_md5_key, key->key, key->keylen); - tcptw->tw_md5_keylen = key->keylen; - if (tcp_alloc_md5sig_pool(sk) == NULL) + tcptw->tw_md5_key = kmemdup(key, sizeof(*key), GFP_ATOMIC); + if (tcptw->tw_md5_key && tcp_alloc_md5sig_pool(sk) == NULL) BUG(); } } while (0); @@ -405,8 +403,10 @@ void tcp_twsk_destructor(struct sock *sk) { #ifdef CONFIG_TCP_MD5SIG struct tcp_timewait_sock *twsk = tcp_twsk(sk); - if (twsk->tw_md5_keylen) + if (twsk->tw_md5_key) { tcp_free_md5sig_pool(); + kfree_rcu(twsk->tw_md5_key, rcu); + } #endif } EXPORT_SYMBOL_GPL(tcp_twsk_destructor); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f37769ea637..bec41f9a641 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -540,19 +540,7 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req) static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, const struct in6_addr *addr) { - struct tcp_sock *tp = tcp_sk(sk); - int i; - - BUG_ON(tp == NULL); - - if (!tp->md5sig_info || !tp->md5sig_info->entries6) - return NULL; - - for (i = 0; i < tp->md5sig_info->entries6; i++) { - if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr)) - return &tp->md5sig_info->keys6[i].base; - } - return NULL; + return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6); } static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, @@ -567,129 +555,11 @@ static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); } -static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer, - char *newkey, u8 newkeylen) -{ - /* Add key to the list */ - struct tcp_md5sig_key *key; - struct tcp_sock *tp = tcp_sk(sk); - struct tcp6_md5sig_key *keys; - - key = tcp_v6_md5_do_lookup(sk, peer); - if (key) { - /* modify existing entry - just update that one */ - kfree(key->key); - key->key = newkey; - key->keylen = newkeylen; - } else { - /* reallocate new list if current one is full. */ - if (!tp->md5sig_info) { - tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); - if (!tp->md5sig_info) { - kfree(newkey); - return -ENOMEM; - } - sk_nocaps_add(sk, NETIF_F_GSO_MASK); - } - if (tp->md5sig_info->entries6 == 0 && - tcp_alloc_md5sig_pool(sk) == NULL) { - kfree(newkey); - return -ENOMEM; - } - if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) { - keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) * - (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC); - - if (!keys) { - kfree(newkey); - if (tp->md5sig_info->entries6 == 0) - tcp_free_md5sig_pool(); - return -ENOMEM; - } - - if (tp->md5sig_info->entries6) - memmove(keys, tp->md5sig_info->keys6, - (sizeof (tp->md5sig_info->keys6[0]) * - tp->md5sig_info->entries6)); - - kfree(tp->md5sig_info->keys6); - tp->md5sig_info->keys6 = keys; - tp->md5sig_info->alloced6++; - } - - tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr = *peer; - tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey; - tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen; - - tp->md5sig_info->entries6++; - } - return 0; -} - -static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer) -{ - struct tcp_sock *tp = tcp_sk(sk); - int i; - - for (i = 0; i < tp->md5sig_info->entries6; i++) { - if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) { - /* Free the key */ - kfree(tp->md5sig_info->keys6[i].base.key); - tp->md5sig_info->entries6--; - - if (tp->md5sig_info->entries6 == 0) { - kfree(tp->md5sig_info->keys6); - tp->md5sig_info->keys6 = NULL; - tp->md5sig_info->alloced6 = 0; - tcp_free_md5sig_pool(); - } else { - /* shrink the database */ - if (tp->md5sig_info->entries6 != i) - memmove(&tp->md5sig_info->keys6[i], - &tp->md5sig_info->keys6[i+1], - (tp->md5sig_info->entries6 - i) - * sizeof (tp->md5sig_info->keys6[0])); - } - return 0; - } - } - return -ENOENT; -} - -static void tcp_v6_clear_md5_list (struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - int i; - - if (tp->md5sig_info->entries6) { - for (i = 0; i < tp->md5sig_info->entries6; i++) - kfree(tp->md5sig_info->keys6[i].base.key); - tp->md5sig_info->entries6 = 0; - tcp_free_md5sig_pool(); - } - - kfree(tp->md5sig_info->keys6); - tp->md5sig_info->keys6 = NULL; - tp->md5sig_info->alloced6 = 0; - - if (tp->md5sig_info->entries4) { - for (i = 0; i < tp->md5sig_info->entries4; i++) - kfree(tp->md5sig_info->keys4[i].base.key); - tp->md5sig_info->entries4 = 0; - tcp_free_md5sig_pool(); - } - - kfree(tp->md5sig_info->keys4); - tp->md5sig_info->keys4 = NULL; - tp->md5sig_info->alloced4 = 0; -} - static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, int optlen) { struct tcp_md5sig cmd; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; - u8 *newkey; if (optlen < sizeof(cmd)) return -EINVAL; @@ -704,33 +574,21 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, if (!tcp_sk(sk)->md5sig_info) return -ENOENT; if (ipv6_addr_v4mapped(&sin6->sin6_addr)) - return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]); - return tcp_v6_md5_do_del(sk, &sin6->sin6_addr); + return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], + AF_INET); + return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, + AF_INET6); } if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) return -EINVAL; - if (!tcp_sk(sk)->md5sig_info) { - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_info *p; - - p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); - if (!p) - return -ENOMEM; - - tp->md5sig_info = p; - sk_nocaps_add(sk, NETIF_F_GSO_MASK); - } + if (ipv6_addr_v4mapped(&sin6->sin6_addr)) + return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], + AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); - newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); - if (!newkey) - return -ENOMEM; - if (ipv6_addr_v4mapped(&sin6->sin6_addr)) { - return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3], - newkey, cmd.tcpm_keylen); - } - return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); + return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr, + AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); } static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, @@ -1503,10 +1361,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, * memory, then we end up not copying the key * across. Shucks. */ - char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); - if (newkey != NULL) - tcp_v6_md5_do_add(newsk, &newnp->daddr, - newkey, key->keylen); + tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newnp->daddr, + AF_INET6, key->key, key->keylen, GFP_ATOMIC); } #endif @@ -1995,11 +1851,6 @@ static int tcp_v6_init_sock(struct sock *sk) static void tcp_v6_destroy_sock(struct sock *sk) { -#ifdef CONFIG_TCP_MD5SIG - /* Clean up the MD5 key list */ - if (tcp_sk(sk)->md5sig_info) - tcp_v6_clear_md5_list(sk); -#endif tcp_v4_destroy_sock(sk); inet6_destroy_sock(sk); } -- cgit v1.2.3-70-g09d2 From 5f3d9cb2962967d9d7e03abb4a7ca275a9a3fea5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 31 Jan 2012 10:56:48 +0000 Subject: tcp: md5: use sock_kmalloc() to limit md5 keys There is no limit on number of MD5 keys an application can attach to a tcp socket. This patch adds a per tcp socket limit based on /proc/sys/net/core/optmem_max With current default optmem_max values, this allows about 150 keys on 64bit arches, and 88 keys on 32bit arches. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1d5fd82c5c0..da5d3226771 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -943,11 +943,11 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, tp->md5sig_info = md5sig; } - key = kmalloc(sizeof(*key), gfp); + key = sock_kmalloc(sk, sizeof(*key), gfp); if (!key) return -ENOMEM; if (hlist_empty(&md5sig->head) && !tcp_alloc_md5sig_pool(sk)) { - kfree(key); + sock_kfree_s(sk, key, sizeof(*key)); return -ENOMEM; } @@ -971,6 +971,7 @@ int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) if (!key) return -ENOENT; hlist_del_rcu(&key->node); + atomic_sub(sizeof(*key), &sk->sk_omem_alloc); kfree_rcu(key, rcu); if (hlist_empty(&tp->md5sig_info->head)) tcp_free_md5sig_pool(); @@ -988,6 +989,7 @@ void tcp_clear_md5_list(struct sock *sk) tcp_free_md5sig_pool(); hlist_for_each_entry_safe(key, pos, n, &tp->md5sig_info->head, node) { hlist_del_rcu(&key->node); + atomic_sub(sizeof(*key), &sk->sk_omem_alloc); kfree_rcu(key, rcu); } } -- cgit v1.2.3-70-g09d2 From 5bff0386305461021bbef2d958fa0f0151f56a6f Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 8 Nov 2011 15:09:19 +0300 Subject: SUNRPC: remove non-exclusive pipe creation from RPC pipefs This patch-set was created in context of clone of git branch: git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git. v2: 1) Rebased of current repo state (i.e. all commits were pulled before apply) I feel it is ready for inclusion if no objections will appear. SUNRPC pipefs non-exclusive pipe creation code looks obsolete. IOW, as I see it, all pipes are creating with unique full path and only once. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 1 - net/sunrpc/rpc_pipe.c | 44 ++++++-------------------------------- 2 files changed, 6 insertions(+), 39 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 2bb03d77375..edadc3acf94 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -30,7 +30,6 @@ struct rpc_inode { int pipelen; int nreaders; int nwriters; - int nkern_readwriters; wait_queue_head_t waitq; #define RPC_PIPE_WAIT_FOR_OPEN 1 int flags; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 63a7a7add21..8e3397fc0a7 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -554,7 +554,6 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, if (err) return err; rpci = RPC_I(dentry->d_inode); - rpci->nkern_readwriters = 1; rpci->private = private; rpci->flags = flags; rpci->ops = ops; @@ -587,16 +586,12 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry) static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; - struct rpc_inode *rpci = RPC_I(inode); - rpci->nkern_readwriters--; - if (rpci->nkern_readwriters != 0) - return 0; rpc_close_pipes(inode); return __rpc_unlink(dir, dentry); } -static struct dentry *__rpc_lookup_create(struct dentry *parent, +static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, struct qstr *name) { struct dentry *dentry; @@ -604,27 +599,13 @@ static struct dentry *__rpc_lookup_create(struct dentry *parent, dentry = d_lookup(parent, name); if (!dentry) { dentry = d_alloc(parent, name); - if (!dentry) { - dentry = ERR_PTR(-ENOMEM); - goto out_err; - } + if (!dentry) + return ERR_PTR(-ENOMEM); } - if (!dentry->d_inode) + if (dentry->d_inode == NULL) { d_set_d_op(dentry, &rpc_dentry_operations); -out_err: - return dentry; -} - -static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, - struct qstr *name) -{ - struct dentry *dentry; - - dentry = __rpc_lookup_create(parent, name); - if (IS_ERR(dentry)) - return dentry; - if (dentry->d_inode == NULL) return dentry; + } dput(dentry); return ERR_PTR(-EEXIST); } @@ -812,22 +793,9 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, q.hash = full_name_hash(q.name, q.len), mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); - dentry = __rpc_lookup_create(parent, &q); + dentry = __rpc_lookup_create_exclusive(parent, &q); if (IS_ERR(dentry)) goto out; - if (dentry->d_inode) { - struct rpc_inode *rpci = RPC_I(dentry->d_inode); - if (rpci->private != private || - rpci->ops != ops || - rpci->flags != flags) { - dput (dentry); - err = -EBUSY; - goto out_err; - } - rpci->nkern_readwriters++; - goto out; - } - err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, private, ops, flags); if (err) -- cgit v1.2.3-70-g09d2 From 38b0da7522c086f1dcdeda39a2d1849c6a31f518 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:38:56 +0300 Subject: SUNRPC: create RPC pipefs superblock per network namespace context This is the initial step of RPC pipefs virtualization. It changes nothing to current pipefs behaviour except that mount of pipefs in other than init_net network namespace context will provide only root tree. No other dentries will be visible. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 8e3397fc0a7..e32e6b8c006 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -993,6 +993,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; struct dentry *root; + struct net *net = data; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -1017,7 +1018,7 @@ static struct dentry * rpc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_single(fs_type, flags, data, rpc_fill_super); + return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super); } static struct file_system_type rpc_pipe_fs_type = { -- cgit v1.2.3-70-g09d2 From 021c68dec8c04c44cb82eb5bbee77028fafe22e8 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:39:04 +0300 Subject: SUNRPC: hold current network namespace while pipefs superblock is active We want to be sure that network namespace is still alive while we have pipefs mounted. This will be required later, when RPC pipefs will be mounting only from user-space context. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index e32e6b8c006..f628b0f48a8 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -27,6 +27,9 @@ #include #include #include +#include + +#include "netns.h" static struct vfsmount *rpc_mnt __read_mostly; static int rpc_mount_count; @@ -1011,6 +1014,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) } if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; + sb->s_fs_info = get_net(net); return 0; } @@ -1021,11 +1025,19 @@ rpc_mount(struct file_system_type *fs_type, return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super); } +void rpc_kill_sb(struct super_block *sb) +{ + struct net *net = sb->s_fs_info; + + put_net(net); + kill_litter_super(sb); +} + static struct file_system_type rpc_pipe_fs_type = { .owner = THIS_MODULE, .name = "rpc_pipefs", .mount = rpc_mount, - .kill_sb = kill_litter_super, + .kill_sb = rpc_kill_sb, }; static void -- cgit v1.2.3-70-g09d2 From 2d00131acc641b2cb6f0bdefb8c7bdd8fdf7410b Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:39:13 +0300 Subject: SUNRPC: send notification events on pipefs sb creation and destruction They will be used to notify subscribers about pipefs superblock creation and destruction. Subcribers will have to create their dentries on passed superblock on mount event and destroy otherwise. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 8 ++++++++ net/sunrpc/rpc_pipe.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index edadc3acf94..d39782ce6c6 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -43,6 +43,14 @@ RPC_I(struct inode *inode) return container_of(inode, struct rpc_inode, vfs_inode); } +extern int rpc_pipefs_notifier_register(struct notifier_block *); +extern void rpc_pipefs_notifier_unregister(struct notifier_block *); + +enum { + RPC_PIPEFS_MOUNT, + RPC_PIPEFS_UMOUNT, +}; + extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, char __user *, size_t); extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index f628b0f48a8..58a5062df26 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -28,8 +28,10 @@ #include #include #include +#include #include "netns.h" +#include "sunrpc.h" static struct vfsmount *rpc_mnt __read_mostly; static int rpc_mount_count; @@ -41,6 +43,20 @@ static struct kmem_cache *rpc_inode_cachep __read_mostly; #define RPC_UPCALL_TIMEOUT (30*HZ) +static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list); + +int rpc_pipefs_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_cond_register(&rpc_pipefs_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register); + +void rpc_pipefs_notifier_unregister(struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister); + static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, void (*destroy_msg)(struct rpc_pipe_msg *), int err) { @@ -997,6 +1013,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode; struct dentry *root; struct net *net = data; + int err; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -1014,8 +1031,20 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) } if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; + err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list, + RPC_PIPEFS_MOUNT, + sb); + if (err) + goto err_depopulate; sb->s_fs_info = get_net(net); return 0; + +err_depopulate: + blocking_notifier_call_chain(&rpc_pipefs_notifier_list, + RPC_PIPEFS_UMOUNT, + sb); + __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); + return err; } static struct dentry * @@ -1030,6 +1059,9 @@ void rpc_kill_sb(struct super_block *sb) struct net *net = sb->s_fs_info; put_net(net); + blocking_notifier_call_chain(&rpc_pipefs_notifier_list, + RPC_PIPEFS_UMOUNT, + sb); kill_litter_super(sb); } -- cgit v1.2.3-70-g09d2 From 432eb1a5fb380477ae759041bac2bb305977e436 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:39:22 +0300 Subject: SUNRPC: pipefs dentry lookup helper introduced In all places, where pipefs dentries are created, only directory inode is actually required to create new dentry. And all this directories has root pipefs dentry as their parent. So we actually don't need this pipefs mount point at all if some pipefs lookup method will be provided. IOW, all we really need is just superblock and simple lookup method to find root's child dentry with appropriate name. And this patch introduces this method. Note, that no locking implemented in rpc_d_lookup_sb(). So it can be used only in case of assurance, that pipefs superblock still exist. IOW, we can use this method only in pipefs mount-umount notification subscribers callbacks. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 3 +++ net/sunrpc/rpc_pipe.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index d39782ce6c6..2f338223014 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -51,6 +51,9 @@ enum { RPC_PIPEFS_UMOUNT, }; +extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb, + const unsigned char *dir_name); + extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, char __user *, size_t); extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 58a5062df26..6f295e6c12a 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1007,6 +1007,22 @@ static const struct rpc_filelist files[] = { }, }; +/* + * This call can be used only in RPC pipefs mount notification hooks. + */ +struct dentry *rpc_d_lookup_sb(const struct super_block *sb, + const unsigned char *dir_name) +{ + struct qstr dir = { + .name = dir_name, + .len = strlen(dir_name), + .hash = full_name_hash(dir_name, strlen(dir_name)), + }; + + return d_lookup(sb->s_root, &dir); +} +EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); + static int rpc_fill_super(struct super_block *sb, void *data, int silent) { -- cgit v1.2.3-70-g09d2 From 90c4e82999c517e0cd00d0782c68d186cb18b784 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:39:30 +0300 Subject: SUNRPC: put pipefs superblock link on network namespace We have modules (like, pNFS blocklayout module) which creates pipes on rpc_pipefs. Thus we need per-net operations for them. To make it possible we require appropriate super block. So we have to put sb link on network namespace context. Note, that it's not strongly required to create pipes in per-net operations. IOW, if pipefs wasn't mounted yet, that no sb link reference will present on network namespace and in this case we need just need to pass through pipe creation. Pipe dentry will be created during pipefs mount notification. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/netns.h | 2 ++ net/sunrpc/rpc_pipe.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'net') diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index d013bf211ca..b3842529aec 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -9,6 +9,8 @@ struct cache_detail; struct sunrpc_net { struct proc_dir_entry *proc_net_rpc; struct cache_detail *ip_map_cache; + + struct super_block *pipefs_sb; }; extern int sunrpc_net_id; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 6f295e6c12a..e5e1f357b56 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1029,6 +1029,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode; struct dentry *root; struct net *net = data; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); int err; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -1053,6 +1054,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) if (err) goto err_depopulate; sb->s_fs_info = get_net(net); + sn->pipefs_sb = sb; return 0; err_depopulate: @@ -1073,7 +1075,9 @@ rpc_mount(struct file_system_type *fs_type, void rpc_kill_sb(struct super_block *sb) { struct net *net = sb->s_fs_info; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + sn->pipefs_sb = NULL; put_net(net); blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_UMOUNT, -- cgit v1.2.3-70-g09d2 From c21a588f35b1c50304e505fad542b3aab0814266 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:39:39 +0300 Subject: SUNRPC: pipefs per-net operations helper introduced During per-net pipes creation and destruction we have to make sure, that pipefs sb exists for the whole creation/destruction cycle. This is done by using special mutex which controls pipefs sb reference on network namespace context. Helper consists of two parts: first of them (rpc_get_dentry_net) searches for dentry with specified name and returns with mutex taken on success. When pipe creation or destructions is completed, caller should release this mutex by rpc_put_dentry_net call. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 3 +++ net/sunrpc/netns.h | 1 + net/sunrpc/rpc_pipe.c | 36 ++++++++++++++++++++++++++++++++++++ net/sunrpc/sunrpc_syms.c | 1 + 4 files changed, 41 insertions(+) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 2f338223014..c13fca34dc9 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -53,6 +53,9 @@ enum { extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb, const unsigned char *dir_name); +extern void rpc_pipefs_init_net(struct net *net); +extern struct super_block *rpc_get_sb_net(const struct net *net); +extern void rpc_put_sb_net(const struct net *net); extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, char __user *, size_t); diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index b3842529aec..11d2f486340 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -11,6 +11,7 @@ struct sunrpc_net { struct cache_detail *ip_map_cache; struct super_block *pipefs_sb; + struct mutex pipefs_sb_lock; }; extern int sunrpc_net_id; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index e5e1f357b56..f075f881777 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1023,6 +1023,40 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb, } EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); +void rpc_pipefs_init_net(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + + mutex_init(&sn->pipefs_sb_lock); +} + +/* + * This call will be used for per network namespace operations calls. + * Note: Function will be returned with pipefs_sb_lock taken if superblock was + * found. This lock have to be released by rpc_put_sb_net() when all operations + * will be completed. + */ +struct super_block *rpc_get_sb_net(const struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + + mutex_lock(&sn->pipefs_sb_lock); + if (sn->pipefs_sb) + return sn->pipefs_sb; + mutex_unlock(&sn->pipefs_sb_lock); + return NULL; +} +EXPORT_SYMBOL_GPL(rpc_get_sb_net); + +void rpc_put_sb_net(const struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + + BUG_ON(sn->pipefs_sb == NULL); + mutex_unlock(&sn->pipefs_sb_lock); +} +EXPORT_SYMBOL_GPL(rpc_put_sb_net); + static int rpc_fill_super(struct super_block *sb, void *data, int silent) { @@ -1077,7 +1111,9 @@ void rpc_kill_sb(struct super_block *sb) struct net *net = sb->s_fs_info; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + mutex_lock(&sn->pipefs_sb_lock); sn->pipefs_sb = NULL; + mutex_unlock(&sn->pipefs_sb_lock); put_net(net); blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_UMOUNT, diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 8ec9778c3f4..7086d11589c 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -38,6 +38,7 @@ static __net_init int sunrpc_init_net(struct net *net) if (err) goto err_ipmap; + rpc_pipefs_init_net(net); return 0; err_ipmap: -- cgit v1.2.3-70-g09d2 From efc46bf2b2893132e07628ad8c06e915f3281fdc Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:39:47 +0300 Subject: SUNRPC: added debug messages to RPC pipefs This patch adds debug messages for notification events. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index f075f881777..9a881138fea 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -33,6 +33,10 @@ #include "netns.h" #include "sunrpc.h" +#define RPCDBG_FACILITY RPCDBG_DEBUG + +#define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") + static struct vfsmount *rpc_mnt __read_mostly; static int rpc_mount_count; @@ -1082,6 +1086,8 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) } if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; + dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", net, + NET_NAME(net)); err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_MOUNT, sb); @@ -1115,6 +1121,8 @@ void rpc_kill_sb(struct super_block *sb) sn->pipefs_sb = NULL; mutex_unlock(&sn->pipefs_sb_lock); put_net(net); + dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n", net, + NET_NAME(net)); blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_UMOUNT, sb); -- cgit v1.2.3-70-g09d2 From 766347bec3490111e1c4482af7c7394868c2aed1 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:43:23 +0300 Subject: SUNRPC: replace inode lock with pipe lock for RPC PipeFS operations Currenly, inode i_lock is used to provide concurrent access to SUNPRC PipeFS pipes. It looks redundant, since now other use of inode is present in most of these places and thus can be easely replaced, which will allow to remove most of inode references from PipeFS code. This is a first step towards to removing PipeFS inode references from kernel code other than PipeFS itself. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 1 + net/sunrpc/auth_gss/auth_gss.c | 57 +++++++++++++++++++------------------- net/sunrpc/rpc_pipe.c | 38 ++++++++++++------------- 3 files changed, 48 insertions(+), 48 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index c13fca34dc9..c93ea8689bc 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -35,6 +35,7 @@ struct rpc_inode { int flags; struct delayed_work queue_timeout; const struct rpc_pipe_ops *ops; + spinlock_t lock; }; static inline struct rpc_inode * diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index affa631ac1a..a0844f92a44 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -112,7 +112,7 @@ gss_put_ctx(struct gss_cl_ctx *ctx) /* gss_cred_set_ctx: * called by gss_upcall_callback and gss_create_upcall in order * to set the gss context. The actual exchange of an old context - * and a new one is protected by the inode->i_lock. + * and a new one is protected by the rpci->lock. */ static void gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) @@ -316,17 +316,16 @@ static inline struct gss_upcall_msg * gss_add_msg(struct gss_upcall_msg *gss_msg) { struct rpc_inode *rpci = gss_msg->inode; - struct inode *inode = &rpci->vfs_inode; struct gss_upcall_msg *old; - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); old = __gss_find_upcall(rpci, gss_msg->uid); if (old == NULL) { atomic_inc(&gss_msg->count); list_add(&gss_msg->list, &rpci->in_downcall); } else gss_msg = old; - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); return gss_msg; } @@ -342,14 +341,14 @@ __gss_unhash_msg(struct gss_upcall_msg *gss_msg) static void gss_unhash_msg(struct gss_upcall_msg *gss_msg) { - struct inode *inode = &gss_msg->inode->vfs_inode; + struct rpc_inode *rpci = gss_msg->inode; if (list_empty(&gss_msg->list)) return; - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); if (!list_empty(&gss_msg->list)) __gss_unhash_msg(gss_msg); - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); } static void @@ -376,11 +375,11 @@ gss_upcall_callback(struct rpc_task *task) struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred, struct gss_cred, gc_base); struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; - struct inode *inode = &gss_msg->inode->vfs_inode; + struct rpc_inode *rpci = gss_msg->inode; - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); gss_handle_downcall_result(gss_cred, gss_msg); - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); task->tk_status = gss_msg->msg.errno; gss_release_msg(gss_msg); } @@ -506,7 +505,7 @@ gss_refresh_upcall(struct rpc_task *task) struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_upcall_msg *gss_msg; - struct inode *inode; + struct rpc_inode *rpci; int err = 0; dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, @@ -524,8 +523,8 @@ gss_refresh_upcall(struct rpc_task *task) err = PTR_ERR(gss_msg); goto out; } - inode = &gss_msg->inode->vfs_inode; - spin_lock(&inode->i_lock); + rpci = gss_msg->inode; + spin_lock(&rpci->lock); if (gss_cred->gc_upcall != NULL) rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { @@ -538,7 +537,7 @@ gss_refresh_upcall(struct rpc_task *task) gss_handle_downcall_result(gss_cred, gss_msg); err = gss_msg->msg.errno; } - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); gss_release_msg(gss_msg); out: dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", @@ -549,7 +548,7 @@ out: static inline int gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) { - struct inode *inode; + struct rpc_inode *rpci; struct rpc_cred *cred = &gss_cred->gc_base; struct gss_upcall_msg *gss_msg; DEFINE_WAIT(wait); @@ -573,14 +572,14 @@ retry: err = PTR_ERR(gss_msg); goto out; } - inode = &gss_msg->inode->vfs_inode; + rpci = gss_msg->inode; for (;;) { prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE); - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { break; } - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); if (fatal_signal_pending(current)) { err = -ERESTARTSYS; goto out_intr; @@ -591,7 +590,7 @@ retry: gss_cred_set_ctx(cred, gss_msg->ctx); else err = gss_msg->msg.errno; - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); out_intr: finish_wait(&gss_msg->waitqueue, &wait); gss_release_msg(gss_msg); @@ -609,7 +608,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) const void *p, *end; void *buf; struct gss_upcall_msg *gss_msg; - struct inode *inode = filp->f_path.dentry->d_inode; + struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode); struct gss_cl_ctx *ctx; uid_t uid; ssize_t err = -EFBIG; @@ -639,14 +638,14 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) err = -ENOENT; /* Find a matching upcall */ - spin_lock(&inode->i_lock); - gss_msg = __gss_find_upcall(RPC_I(inode), uid); + spin_lock(&rpci->lock); + gss_msg = __gss_find_upcall(rpci, uid); if (gss_msg == NULL) { - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); goto err_put_ctx; } list_del_init(&gss_msg->list); - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); if (IS_ERR(p)) { @@ -674,9 +673,9 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) err = mlen; err_release_msg: - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); __gss_unhash_msg(gss_msg); - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); gss_release_msg(gss_msg); err_put_ctx: gss_put_ctx(ctx); @@ -726,7 +725,7 @@ gss_pipe_release(struct inode *inode) struct gss_upcall_msg *gss_msg; restart: - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); list_for_each_entry(gss_msg, &rpci->in_downcall, list) { if (!list_empty(&gss_msg->msg.list)) @@ -734,11 +733,11 @@ restart: gss_msg->msg.errno = -EPIPE; atomic_inc(&gss_msg->count); __gss_unhash_msg(gss_msg); - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); gss_release_msg(gss_msg); goto restart; } - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); put_pipe_version(); } diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9a881138fea..16d9b9a701a 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -83,12 +83,11 @@ rpc_timeout_upcall_queue(struct work_struct *work) LIST_HEAD(free_list); struct rpc_inode *rpci = container_of(work, struct rpc_inode, queue_timeout.work); - struct inode *inode = &rpci->vfs_inode; void (*destroy_msg)(struct rpc_pipe_msg *); - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); if (rpci->ops == NULL) { - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); return; } destroy_msg = rpci->ops->destroy_msg; @@ -96,7 +95,7 @@ rpc_timeout_upcall_queue(struct work_struct *work) list_splice_init(&rpci->pipe, &free_list); rpci->pipelen = 0; } - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); } @@ -136,7 +135,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) struct rpc_inode *rpci = RPC_I(inode); int res = -EPIPE; - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); if (rpci->ops == NULL) goto out; if (rpci->nreaders) { @@ -153,7 +152,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) res = 0; } out: - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); wake_up(&rpci->waitq); return res; } @@ -176,14 +175,14 @@ rpc_close_pipes(struct inode *inode) ops = rpci->ops; if (ops != NULL) { LIST_HEAD(free_list); - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); need_release = rpci->nreaders != 0 || rpci->nwriters != 0; rpci->nreaders = 0; list_splice_init(&rpci->in_upcall, &free_list); list_splice_init(&rpci->pipe, &free_list); rpci->pipelen = 0; rpci->ops = NULL; - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); rpci->nwriters = 0; if (need_release && ops->release_pipe) @@ -255,10 +254,10 @@ rpc_pipe_release(struct inode *inode, struct file *filp) goto out; msg = filp->private_data; if (msg != NULL) { - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); msg->errno = -EAGAIN; list_del_init(&msg->list); - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); rpci->ops->destroy_msg(msg); } if (filp->f_mode & FMODE_WRITE) @@ -267,10 +266,10 @@ rpc_pipe_release(struct inode *inode, struct file *filp) rpci->nreaders --; if (rpci->nreaders == 0) { LIST_HEAD(free_list); - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); list_splice_init(&rpci->pipe, &free_list); rpci->pipelen = 0; - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); rpc_purge_list(rpci, &free_list, rpci->ops->destroy_msg, -EAGAIN); } @@ -298,7 +297,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) } msg = filp->private_data; if (msg == NULL) { - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); if (!list_empty(&rpci->pipe)) { msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, @@ -308,7 +307,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) filp->private_data = msg; msg->copied = 0; } - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); if (msg == NULL) goto out_unlock; } @@ -316,9 +315,9 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) res = rpci->ops->upcall(filp, msg, buf, len); if (res < 0 || msg->len == msg->copied) { filp->private_data = NULL; - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); list_del_init(&msg->list); - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); rpci->ops->destroy_msg(msg); } out_unlock: @@ -367,9 +366,9 @@ rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case FIONREAD: - spin_lock(&inode->i_lock); + spin_lock(&rpci->lock); if (rpci->ops == NULL) { - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); return -EPIPE; } len = rpci->pipelen; @@ -378,7 +377,7 @@ rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) msg = filp->private_data; len += msg->len - msg->copied; } - spin_unlock(&inode->i_lock); + spin_unlock(&rpci->lock); return put_user(len, (int __user *)arg); default: return -EINVAL; @@ -1153,6 +1152,7 @@ init_once(void *foo) INIT_DELAYED_WORK(&rpci->queue_timeout, rpc_timeout_upcall_queue); rpci->ops = NULL; + spin_lock_init(&rpci->lock); } int register_rpc_pipefs(void) -- cgit v1.2.3-70-g09d2 From ba9e097593f371ebd102580a0c5b1b2cf55636a0 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:43:32 +0300 Subject: SUNRPC: split SUNPRC PipeFS pipe data and inode creation Generally, pipe data is used only for pipes, and thus allocating space for it on every RPC inode allocation is redundant. This patch splits private SUNRPC PipeFS pipe data and inode, makes pipe data allocated only for pipe inodes. This patch is also is a next step towards to to removing PipeFS inode references from kernel code other than PipeFS itself. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 10 +- net/sunrpc/auth_gss/auth_gss.c | 46 ++++---- net/sunrpc/rpc_pipe.c | 208 ++++++++++++++++++++----------------- 3 files changed, 142 insertions(+), 122 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index c93ea8689bc..57512c23d34 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -21,9 +21,7 @@ struct rpc_pipe_ops { void (*destroy_msg)(struct rpc_pipe_msg *); }; -struct rpc_inode { - struct inode vfs_inode; - void *private; +struct rpc_pipe { struct list_head pipe; struct list_head in_upcall; struct list_head in_downcall; @@ -38,6 +36,12 @@ struct rpc_inode { spinlock_t lock; }; +struct rpc_inode { + struct inode vfs_inode; + void *private; + struct rpc_pipe *pipe; +}; + static inline struct rpc_inode * RPC_I(struct inode *inode) { diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index a0844f92a44..e933484e55e 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -112,7 +112,7 @@ gss_put_ctx(struct gss_cl_ctx *ctx) /* gss_cred_set_ctx: * called by gss_upcall_callback and gss_create_upcall in order * to set the gss context. The actual exchange of an old context - * and a new one is protected by the rpci->lock. + * and a new one is protected by the rpci->pipe->lock. */ static void gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) @@ -297,7 +297,7 @@ static struct gss_upcall_msg * __gss_find_upcall(struct rpc_inode *rpci, uid_t uid) { struct gss_upcall_msg *pos; - list_for_each_entry(pos, &rpci->in_downcall, list) { + list_for_each_entry(pos, &rpci->pipe->in_downcall, list) { if (pos->uid != uid) continue; atomic_inc(&pos->count); @@ -318,14 +318,14 @@ gss_add_msg(struct gss_upcall_msg *gss_msg) struct rpc_inode *rpci = gss_msg->inode; struct gss_upcall_msg *old; - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); old = __gss_find_upcall(rpci, gss_msg->uid); if (old == NULL) { atomic_inc(&gss_msg->count); - list_add(&gss_msg->list, &rpci->in_downcall); + list_add(&gss_msg->list, &rpci->pipe->in_downcall); } else gss_msg = old; - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); return gss_msg; } @@ -345,10 +345,10 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg) if (list_empty(&gss_msg->list)) return; - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); if (!list_empty(&gss_msg->list)) __gss_unhash_msg(gss_msg); - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); } static void @@ -377,9 +377,9 @@ gss_upcall_callback(struct rpc_task *task) struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; struct rpc_inode *rpci = gss_msg->inode; - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); gss_handle_downcall_result(gss_cred, gss_msg); - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); task->tk_status = gss_msg->msg.errno; gss_release_msg(gss_msg); } @@ -524,7 +524,7 @@ gss_refresh_upcall(struct rpc_task *task) goto out; } rpci = gss_msg->inode; - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); if (gss_cred->gc_upcall != NULL) rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { @@ -537,7 +537,7 @@ gss_refresh_upcall(struct rpc_task *task) gss_handle_downcall_result(gss_cred, gss_msg); err = gss_msg->msg.errno; } - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); gss_release_msg(gss_msg); out: dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", @@ -575,11 +575,11 @@ retry: rpci = gss_msg->inode; for (;;) { prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE); - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { break; } - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); if (fatal_signal_pending(current)) { err = -ERESTARTSYS; goto out_intr; @@ -590,7 +590,7 @@ retry: gss_cred_set_ctx(cred, gss_msg->ctx); else err = gss_msg->msg.errno; - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); out_intr: finish_wait(&gss_msg->waitqueue, &wait); gss_release_msg(gss_msg); @@ -638,14 +638,14 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) err = -ENOENT; /* Find a matching upcall */ - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); gss_msg = __gss_find_upcall(rpci, uid); if (gss_msg == NULL) { - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); goto err_put_ctx; } list_del_init(&gss_msg->list); - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); if (IS_ERR(p)) { @@ -673,9 +673,9 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) err = mlen; err_release_msg: - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); __gss_unhash_msg(gss_msg); - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); gss_release_msg(gss_msg); err_put_ctx: gss_put_ctx(ctx); @@ -725,19 +725,19 @@ gss_pipe_release(struct inode *inode) struct gss_upcall_msg *gss_msg; restart: - spin_lock(&rpci->lock); - list_for_each_entry(gss_msg, &rpci->in_downcall, list) { + spin_lock(&rpci->pipe->lock); + list_for_each_entry(gss_msg, &rpci->pipe->in_downcall, list) { if (!list_empty(&gss_msg->msg.list)) continue; gss_msg->msg.errno = -EPIPE; atomic_inc(&gss_msg->count); __gss_unhash_msg(gss_msg); - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); gss_release_msg(gss_msg); goto restart; } - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); put_pipe_version(); } diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 16d9b9a701a..b6f6555128d 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -61,7 +61,7 @@ void rpc_pipefs_notifier_unregister(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister); -static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, +static void rpc_purge_list(struct rpc_pipe *pipe, struct list_head *head, void (*destroy_msg)(struct rpc_pipe_msg *), int err) { struct rpc_pipe_msg *msg; @@ -74,29 +74,29 @@ static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, msg->errno = err; destroy_msg(msg); } while (!list_empty(head)); - wake_up(&rpci->waitq); + wake_up(&pipe->waitq); } static void rpc_timeout_upcall_queue(struct work_struct *work) { LIST_HEAD(free_list); - struct rpc_inode *rpci = - container_of(work, struct rpc_inode, queue_timeout.work); + struct rpc_pipe *pipe = + container_of(work, struct rpc_pipe, queue_timeout.work); void (*destroy_msg)(struct rpc_pipe_msg *); - spin_lock(&rpci->lock); - if (rpci->ops == NULL) { - spin_unlock(&rpci->lock); + spin_lock(&pipe->lock); + if (pipe->ops == NULL) { + spin_unlock(&pipe->lock); return; } - destroy_msg = rpci->ops->destroy_msg; - if (rpci->nreaders == 0) { - list_splice_init(&rpci->pipe, &free_list); - rpci->pipelen = 0; + destroy_msg = pipe->ops->destroy_msg; + if (pipe->nreaders == 0) { + list_splice_init(&pipe->pipe, &free_list); + pipe->pipelen = 0; } - spin_unlock(&rpci->lock); - rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); + spin_unlock(&pipe->lock); + rpc_purge_list(pipe, &free_list, destroy_msg, -ETIMEDOUT); } ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, @@ -135,25 +135,25 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) struct rpc_inode *rpci = RPC_I(inode); int res = -EPIPE; - spin_lock(&rpci->lock); - if (rpci->ops == NULL) + spin_lock(&rpci->pipe->lock); + if (rpci->pipe->ops == NULL) goto out; - if (rpci->nreaders) { - list_add_tail(&msg->list, &rpci->pipe); - rpci->pipelen += msg->len; + if (rpci->pipe->nreaders) { + list_add_tail(&msg->list, &rpci->pipe->pipe); + rpci->pipe->pipelen += msg->len; res = 0; - } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { - if (list_empty(&rpci->pipe)) + } else if (rpci->pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) { + if (list_empty(&rpci->pipe->pipe)) queue_delayed_work(rpciod_workqueue, - &rpci->queue_timeout, + &rpci->pipe->queue_timeout, RPC_UPCALL_TIMEOUT); - list_add_tail(&msg->list, &rpci->pipe); - rpci->pipelen += msg->len; + list_add_tail(&msg->list, &rpci->pipe->pipe); + rpci->pipe->pipelen += msg->len; res = 0; } out: - spin_unlock(&rpci->lock); - wake_up(&rpci->waitq); + spin_unlock(&rpci->pipe->lock); + wake_up(&rpci->pipe->waitq); return res; } EXPORT_SYMBOL_GPL(rpc_queue_upcall); @@ -167,27 +167,27 @@ rpc_inode_setowner(struct inode *inode, void *private) static void rpc_close_pipes(struct inode *inode) { - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; const struct rpc_pipe_ops *ops; int need_release; mutex_lock(&inode->i_mutex); - ops = rpci->ops; + ops = pipe->ops; if (ops != NULL) { LIST_HEAD(free_list); - spin_lock(&rpci->lock); - need_release = rpci->nreaders != 0 || rpci->nwriters != 0; - rpci->nreaders = 0; - list_splice_init(&rpci->in_upcall, &free_list); - list_splice_init(&rpci->pipe, &free_list); - rpci->pipelen = 0; - rpci->ops = NULL; - spin_unlock(&rpci->lock); - rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); - rpci->nwriters = 0; + spin_lock(&pipe->lock); + need_release = pipe->nreaders != 0 || pipe->nwriters != 0; + pipe->nreaders = 0; + list_splice_init(&pipe->in_upcall, &free_list); + list_splice_init(&pipe->pipe, &free_list); + pipe->pipelen = 0; + pipe->ops = NULL; + spin_unlock(&pipe->lock); + rpc_purge_list(pipe, &free_list, ops->destroy_msg, -EPIPE); + pipe->nwriters = 0; if (need_release && ops->release_pipe) ops->release_pipe(inode); - cancel_delayed_work_sync(&rpci->queue_timeout); + cancel_delayed_work_sync(&pipe->queue_timeout); } rpc_inode_setowner(inode, NULL); mutex_unlock(&inode->i_mutex); @@ -207,6 +207,7 @@ static void rpc_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); + kfree(RPC_I(inode)->pipe); kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); } @@ -224,18 +225,18 @@ rpc_pipe_open(struct inode *inode, struct file *filp) int res = -ENXIO; mutex_lock(&inode->i_mutex); - if (rpci->ops == NULL) + if (rpci->pipe->ops == NULL) goto out; - first_open = rpci->nreaders == 0 && rpci->nwriters == 0; - if (first_open && rpci->ops->open_pipe) { - res = rpci->ops->open_pipe(inode); + first_open = rpci->pipe->nreaders == 0 && rpci->pipe->nwriters == 0; + if (first_open && rpci->pipe->ops->open_pipe) { + res = rpci->pipe->ops->open_pipe(inode); if (res) goto out; } if (filp->f_mode & FMODE_READ) - rpci->nreaders++; + rpci->pipe->nreaders++; if (filp->f_mode & FMODE_WRITE) - rpci->nwriters++; + rpci->pipe->nwriters++; res = 0; out: mutex_unlock(&inode->i_mutex); @@ -245,38 +246,38 @@ out: static int rpc_pipe_release(struct inode *inode, struct file *filp) { - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; struct rpc_pipe_msg *msg; int last_close; mutex_lock(&inode->i_mutex); - if (rpci->ops == NULL) + if (pipe->ops == NULL) goto out; msg = filp->private_data; if (msg != NULL) { - spin_lock(&rpci->lock); + spin_lock(&pipe->lock); msg->errno = -EAGAIN; list_del_init(&msg->list); - spin_unlock(&rpci->lock); - rpci->ops->destroy_msg(msg); + spin_unlock(&pipe->lock); + pipe->ops->destroy_msg(msg); } if (filp->f_mode & FMODE_WRITE) - rpci->nwriters --; + pipe->nwriters --; if (filp->f_mode & FMODE_READ) { - rpci->nreaders --; - if (rpci->nreaders == 0) { + pipe->nreaders --; + if (pipe->nreaders == 0) { LIST_HEAD(free_list); - spin_lock(&rpci->lock); - list_splice_init(&rpci->pipe, &free_list); - rpci->pipelen = 0; - spin_unlock(&rpci->lock); - rpc_purge_list(rpci, &free_list, - rpci->ops->destroy_msg, -EAGAIN); + spin_lock(&pipe->lock); + list_splice_init(&pipe->pipe, &free_list); + pipe->pipelen = 0; + spin_unlock(&pipe->lock); + rpc_purge_list(pipe, &free_list, + pipe->ops->destroy_msg, -EAGAIN); } } - last_close = rpci->nwriters == 0 && rpci->nreaders == 0; - if (last_close && rpci->ops->release_pipe) - rpci->ops->release_pipe(inode); + last_close = pipe->nwriters == 0 && pipe->nreaders == 0; + if (last_close && pipe->ops->release_pipe) + pipe->ops->release_pipe(inode); out: mutex_unlock(&inode->i_mutex); return 0; @@ -291,34 +292,34 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) int res = 0; mutex_lock(&inode->i_mutex); - if (rpci->ops == NULL) { + if (rpci->pipe->ops == NULL) { res = -EPIPE; goto out_unlock; } msg = filp->private_data; if (msg == NULL) { - spin_lock(&rpci->lock); - if (!list_empty(&rpci->pipe)) { - msg = list_entry(rpci->pipe.next, + spin_lock(&rpci->pipe->lock); + if (!list_empty(&rpci->pipe->pipe)) { + msg = list_entry(rpci->pipe->pipe.next, struct rpc_pipe_msg, list); - list_move(&msg->list, &rpci->in_upcall); - rpci->pipelen -= msg->len; + list_move(&msg->list, &rpci->pipe->in_upcall); + rpci->pipe->pipelen -= msg->len; filp->private_data = msg; msg->copied = 0; } - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); if (msg == NULL) goto out_unlock; } /* NOTE: it is up to the callback to update msg->copied */ - res = rpci->ops->upcall(filp, msg, buf, len); + res = rpci->pipe->ops->upcall(filp, msg, buf, len); if (res < 0 || msg->len == msg->copied) { filp->private_data = NULL; - spin_lock(&rpci->lock); + spin_lock(&rpci->pipe->lock); list_del_init(&msg->list); - spin_unlock(&rpci->lock); - rpci->ops->destroy_msg(msg); + spin_unlock(&rpci->pipe->lock); + rpci->pipe->ops->destroy_msg(msg); } out_unlock: mutex_unlock(&inode->i_mutex); @@ -334,8 +335,8 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of mutex_lock(&inode->i_mutex); res = -EPIPE; - if (rpci->ops != NULL) - res = rpci->ops->downcall(filp, buf, len); + if (rpci->pipe->ops != NULL) + res = rpci->pipe->ops->downcall(filp, buf, len); mutex_unlock(&inode->i_mutex); return res; } @@ -347,12 +348,12 @@ rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) unsigned int mask = 0; rpci = RPC_I(filp->f_path.dentry->d_inode); - poll_wait(filp, &rpci->waitq, wait); + poll_wait(filp, &rpci->pipe->waitq, wait); mask = POLLOUT | POLLWRNORM; - if (rpci->ops == NULL) + if (rpci->pipe->ops == NULL) mask |= POLLERR | POLLHUP; - if (filp->private_data || !list_empty(&rpci->pipe)) + if (filp->private_data || !list_empty(&rpci->pipe->pipe)) mask |= POLLIN | POLLRDNORM; return mask; } @@ -366,18 +367,18 @@ rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case FIONREAD: - spin_lock(&rpci->lock); - if (rpci->ops == NULL) { - spin_unlock(&rpci->lock); + spin_lock(&rpci->pipe->lock); + if (rpci->pipe->ops == NULL) { + spin_unlock(&rpci->pipe->lock); return -EPIPE; } - len = rpci->pipelen; + len = rpci->pipe->pipelen; if (filp->private_data) { struct rpc_pipe_msg *msg; msg = filp->private_data; len += msg->len - msg->copied; } - spin_unlock(&rpci->lock); + spin_unlock(&rpci->pipe->lock); return put_user(len, (int __user *)arg); default: return -EINVAL; @@ -562,6 +563,23 @@ static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, return 0; } +static void +init_pipe(struct rpc_pipe *pipe) +{ + pipe->nreaders = 0; + pipe->nwriters = 0; + INIT_LIST_HEAD(&pipe->in_upcall); + INIT_LIST_HEAD(&pipe->in_downcall); + INIT_LIST_HEAD(&pipe->pipe); + pipe->pipelen = 0; + init_waitqueue_head(&pipe->waitq); + INIT_DELAYED_WORK(&pipe->queue_timeout, + rpc_timeout_upcall_queue); + pipe->ops = NULL; + spin_lock_init(&pipe->lock); + +} + static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, umode_t mode, const struct file_operations *i_fop, @@ -569,16 +587,24 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, const struct rpc_pipe_ops *ops, int flags) { + struct rpc_pipe *pipe; struct rpc_inode *rpci; int err; + pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL); + if (!pipe) + return -ENOMEM; + init_pipe(pipe); err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); - if (err) + if (err) { + kfree(pipe); return err; + } rpci = RPC_I(dentry->d_inode); rpci->private = private; - rpci->flags = flags; - rpci->ops = ops; + rpci->pipe = pipe; + rpci->pipe->flags = flags; + rpci->pipe->ops = ops; fsnotify_create(dir, dentry); return 0; } @@ -1142,17 +1168,7 @@ init_once(void *foo) inode_init_once(&rpci->vfs_inode); rpci->private = NULL; - rpci->nreaders = 0; - rpci->nwriters = 0; - INIT_LIST_HEAD(&rpci->in_upcall); - INIT_LIST_HEAD(&rpci->in_downcall); - INIT_LIST_HEAD(&rpci->pipe); - rpci->pipelen = 0; - init_waitqueue_head(&rpci->waitq); - INIT_DELAYED_WORK(&rpci->queue_timeout, - rpc_timeout_upcall_queue); - rpci->ops = NULL; - spin_lock_init(&rpci->lock); + rpci->pipe = NULL; } int register_rpc_pipefs(void) -- cgit v1.2.3-70-g09d2 From d0fe13ba9178d3bb78bbd8577bdedc00f76b7a66 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:43:41 +0300 Subject: SUNRPC: cleanup PipeFS redundant RPC inode usage This patch removes redundant RPC inode references from PipeFS. These places are actually where pipes operations are performed. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 93 +++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 47 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index b6f6555128d..299b1a3c3e4 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -132,28 +132,28 @@ EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall); int rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) { - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; int res = -EPIPE; - spin_lock(&rpci->pipe->lock); - if (rpci->pipe->ops == NULL) + spin_lock(&pipe->lock); + if (pipe->ops == NULL) goto out; - if (rpci->pipe->nreaders) { - list_add_tail(&msg->list, &rpci->pipe->pipe); - rpci->pipe->pipelen += msg->len; + if (pipe->nreaders) { + list_add_tail(&msg->list, &pipe->pipe); + pipe->pipelen += msg->len; res = 0; - } else if (rpci->pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) { - if (list_empty(&rpci->pipe->pipe)) + } else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) { + if (list_empty(&pipe->pipe)) queue_delayed_work(rpciod_workqueue, - &rpci->pipe->queue_timeout, + &pipe->queue_timeout, RPC_UPCALL_TIMEOUT); - list_add_tail(&msg->list, &rpci->pipe->pipe); - rpci->pipe->pipelen += msg->len; + list_add_tail(&msg->list, &pipe->pipe); + pipe->pipelen += msg->len; res = 0; } out: - spin_unlock(&rpci->pipe->lock); - wake_up(&rpci->pipe->waitq); + spin_unlock(&pipe->lock); + wake_up(&pipe->waitq); return res; } EXPORT_SYMBOL_GPL(rpc_queue_upcall); @@ -220,23 +220,23 @@ rpc_destroy_inode(struct inode *inode) static int rpc_pipe_open(struct inode *inode, struct file *filp) { - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; int first_open; int res = -ENXIO; mutex_lock(&inode->i_mutex); - if (rpci->pipe->ops == NULL) + if (pipe->ops == NULL) goto out; - first_open = rpci->pipe->nreaders == 0 && rpci->pipe->nwriters == 0; - if (first_open && rpci->pipe->ops->open_pipe) { - res = rpci->pipe->ops->open_pipe(inode); + first_open = pipe->nreaders == 0 && pipe->nwriters == 0; + if (first_open && pipe->ops->open_pipe) { + res = pipe->ops->open_pipe(inode); if (res) goto out; } if (filp->f_mode & FMODE_READ) - rpci->pipe->nreaders++; + pipe->nreaders++; if (filp->f_mode & FMODE_WRITE) - rpci->pipe->nwriters++; + pipe->nwriters++; res = 0; out: mutex_unlock(&inode->i_mutex); @@ -287,39 +287,39 @@ static ssize_t rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) { struct inode *inode = filp->f_path.dentry->d_inode; - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; struct rpc_pipe_msg *msg; int res = 0; mutex_lock(&inode->i_mutex); - if (rpci->pipe->ops == NULL) { + if (pipe->ops == NULL) { res = -EPIPE; goto out_unlock; } msg = filp->private_data; if (msg == NULL) { - spin_lock(&rpci->pipe->lock); - if (!list_empty(&rpci->pipe->pipe)) { - msg = list_entry(rpci->pipe->pipe.next, + spin_lock(&pipe->lock); + if (!list_empty(&pipe->pipe)) { + msg = list_entry(pipe->pipe.next, struct rpc_pipe_msg, list); - list_move(&msg->list, &rpci->pipe->in_upcall); - rpci->pipe->pipelen -= msg->len; + list_move(&msg->list, &pipe->in_upcall); + pipe->pipelen -= msg->len; filp->private_data = msg; msg->copied = 0; } - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); if (msg == NULL) goto out_unlock; } /* NOTE: it is up to the callback to update msg->copied */ - res = rpci->pipe->ops->upcall(filp, msg, buf, len); + res = pipe->ops->upcall(filp, msg, buf, len); if (res < 0 || msg->len == msg->copied) { filp->private_data = NULL; - spin_lock(&rpci->pipe->lock); + spin_lock(&pipe->lock); list_del_init(&msg->list); - spin_unlock(&rpci->pipe->lock); - rpci->pipe->ops->destroy_msg(msg); + spin_unlock(&pipe->lock); + pipe->ops->destroy_msg(msg); } out_unlock: mutex_unlock(&inode->i_mutex); @@ -330,13 +330,13 @@ static ssize_t rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) { struct inode *inode = filp->f_path.dentry->d_inode; - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; int res; mutex_lock(&inode->i_mutex); res = -EPIPE; - if (rpci->pipe->ops != NULL) - res = rpci->pipe->ops->downcall(filp, buf, len); + if (pipe->ops != NULL) + res = pipe->ops->downcall(filp, buf, len); mutex_unlock(&inode->i_mutex); return res; } @@ -344,16 +344,15 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of static unsigned int rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) { - struct rpc_inode *rpci; + struct rpc_pipe *pipe = RPC_I(filp->f_path.dentry->d_inode)->pipe; unsigned int mask = 0; - rpci = RPC_I(filp->f_path.dentry->d_inode); - poll_wait(filp, &rpci->pipe->waitq, wait); + poll_wait(filp, &pipe->waitq, wait); mask = POLLOUT | POLLWRNORM; - if (rpci->pipe->ops == NULL) + if (pipe->ops == NULL) mask |= POLLERR | POLLHUP; - if (filp->private_data || !list_empty(&rpci->pipe->pipe)) + if (filp->private_data || !list_empty(&pipe->pipe)) mask |= POLLIN | POLLRDNORM; return mask; } @@ -362,23 +361,23 @@ static long rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = filp->f_path.dentry->d_inode; - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; int len; switch (cmd) { case FIONREAD: - spin_lock(&rpci->pipe->lock); - if (rpci->pipe->ops == NULL) { - spin_unlock(&rpci->pipe->lock); + spin_lock(&pipe->lock); + if (pipe->ops == NULL) { + spin_unlock(&pipe->lock); return -EPIPE; } - len = rpci->pipe->pipelen; + len = pipe->pipelen; if (filp->private_data) { struct rpc_pipe_msg *msg; msg = filp->private_data; len += msg->len - msg->copied; } - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); return put_user(len, (int __user *)arg); default: return -EINVAL; @@ -808,7 +807,7 @@ static int rpc_rmdir_depopulate(struct dentry *dentry, * @private: private data to associate with the pipe, for the caller's use * @ops: operations defining the behavior of the pipe: upcall, downcall, * release_pipe, open_pipe, and destroy_msg. - * @flags: rpc_inode flags + * @flags: rpc_pipe flags * * Data is made available for userspace to read by calls to * rpc_queue_upcall(). The actual reads will result in calls to -- cgit v1.2.3-70-g09d2 From d706ed1f50d3f7fae61a177183562179abe8e4bb Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:43:49 +0300 Subject: SUNPRC: cleanup RPC PipeFS pipes upcall interface RPC pipe upcall doesn't requires only private pipe data. Thus RPC inode references in this code can be removed. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/blocklayout/blocklayoutdev.c | 2 +- fs/nfs/blocklayout/blocklayoutdm.c | 2 +- fs/nfs/idmap.c | 4 ++-- include/linux/sunrpc/rpc_pipe_fs.h | 2 +- net/sunrpc/auth_gss/auth_gss.c | 3 +-- net/sunrpc/rpc_pipe.c | 3 +-- 6 files changed, 7 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c index d08ba9107fd..81019190e46 100644 --- a/fs/nfs/blocklayout/blocklayoutdev.c +++ b/fs/nfs/blocklayout/blocklayoutdev.c @@ -146,7 +146,7 @@ nfs4_blk_decode_device(struct nfs_server *server, dprintk("%s CALLING USERSPACE DAEMON\n", __func__); add_wait_queue(&bl_wq, &wq); - rc = rpc_queue_upcall(bl_device_pipe->d_inode, &msg); + rc = rpc_queue_upcall(RPC_I(bl_device_pipe->d_inode)->pipe, &msg); if (rc < 0) { remove_wait_queue(&bl_wq, &wq); rv = ERR_PTR(rc); diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index d055c755807..3c38244a872 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -66,7 +66,7 @@ static void dev_remove(dev_t dev) msg.len = sizeof(bl_msg) + bl_msg.totallen; add_wait_queue(&bl_wq, &wq); - if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) { + if (rpc_queue_upcall(RPC_I(bl_device_pipe->d_inode)->pipe, &msg) < 0) { remove_wait_queue(&bl_wq, &wq); goto out; } diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 2c05f1991e1..3c63c47c793 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -589,7 +589,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, msg.len = sizeof(*im); add_wait_queue(&idmap->idmap_wq, &wq); - if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { + if (rpc_queue_upcall(RPC_I(idmap->idmap_dentry->d_inode)->pipe, &msg) < 0) { remove_wait_queue(&idmap->idmap_wq, &wq); goto out; } @@ -650,7 +650,7 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, add_wait_queue(&idmap->idmap_wq, &wq); - if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { + if (rpc_queue_upcall(RPC_I(idmap->idmap_dentry->d_inode)->pipe, &msg) < 0) { remove_wait_queue(&idmap->idmap_wq, &wq); goto out; } diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 57512c23d34..3ebc257e2b4 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -64,7 +64,7 @@ extern void rpc_put_sb_net(const struct net *net); extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, char __user *, size_t); -extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); +extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *); struct rpc_clnt; extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index e933484e55e..4157e315158 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -473,8 +473,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr return gss_new; gss_msg = gss_add_msg(gss_new); if (gss_msg == gss_new) { - struct inode *inode = &gss_new->inode->vfs_inode; - int res = rpc_queue_upcall(inode, &gss_new->msg); + int res = rpc_queue_upcall(gss_new->inode->pipe, &gss_new->msg); if (res) { gss_unhash_msg(gss_new); gss_msg = ERR_PTR(res); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 299b1a3c3e4..4093da79d51 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -130,9 +130,8 @@ EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall); * initialize the fields of @msg (other than @msg->list) appropriately. */ int -rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) +rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) { - struct rpc_pipe *pipe = RPC_I(inode)->pipe; int res = -EPIPE; spin_lock(&pipe->lock); -- cgit v1.2.3-70-g09d2 From 9beae4677de76cfa4ce8899dc8cd1a1cf8cd8332 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:43:57 +0300 Subject: SUNRPC: cleanup GSS pipes usage Currently gss auth holds RPC inode pointer which is now redundant since it requires only pipes operations which takes private pipe data as an argument. Thus this code can be cleaned and all references to RPC inode can be replaced with privtae pipe data references. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/auth_gss.c | 76 +++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 4157e315158..304b8309f21 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -112,7 +112,7 @@ gss_put_ctx(struct gss_cl_ctx *ctx) /* gss_cred_set_ctx: * called by gss_upcall_callback and gss_create_upcall in order * to set the gss context. The actual exchange of an old context - * and a new one is protected by the rpci->pipe->lock. + * and a new one is protected by the pipe->lock. */ static void gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) @@ -251,7 +251,7 @@ struct gss_upcall_msg { struct rpc_pipe_msg msg; struct list_head list; struct gss_auth *auth; - struct rpc_inode *inode; + struct rpc_pipe *pipe; struct rpc_wait_queue rpc_waitqueue; wait_queue_head_t waitqueue; struct gss_cl_ctx *ctx; @@ -294,10 +294,10 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) } static struct gss_upcall_msg * -__gss_find_upcall(struct rpc_inode *rpci, uid_t uid) +__gss_find_upcall(struct rpc_pipe *pipe, uid_t uid) { struct gss_upcall_msg *pos; - list_for_each_entry(pos, &rpci->pipe->in_downcall, list) { + list_for_each_entry(pos, &pipe->in_downcall, list) { if (pos->uid != uid) continue; atomic_inc(&pos->count); @@ -315,17 +315,17 @@ __gss_find_upcall(struct rpc_inode *rpci, uid_t uid) static inline struct gss_upcall_msg * gss_add_msg(struct gss_upcall_msg *gss_msg) { - struct rpc_inode *rpci = gss_msg->inode; + struct rpc_pipe *pipe = gss_msg->pipe; struct gss_upcall_msg *old; - spin_lock(&rpci->pipe->lock); - old = __gss_find_upcall(rpci, gss_msg->uid); + spin_lock(&pipe->lock); + old = __gss_find_upcall(pipe, gss_msg->uid); if (old == NULL) { atomic_inc(&gss_msg->count); - list_add(&gss_msg->list, &rpci->pipe->in_downcall); + list_add(&gss_msg->list, &pipe->in_downcall); } else gss_msg = old; - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); return gss_msg; } @@ -341,14 +341,14 @@ __gss_unhash_msg(struct gss_upcall_msg *gss_msg) static void gss_unhash_msg(struct gss_upcall_msg *gss_msg) { - struct rpc_inode *rpci = gss_msg->inode; + struct rpc_pipe *pipe = gss_msg->pipe; if (list_empty(&gss_msg->list)) return; - spin_lock(&rpci->pipe->lock); + spin_lock(&pipe->lock); if (!list_empty(&gss_msg->list)) __gss_unhash_msg(gss_msg); - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); } static void @@ -375,11 +375,11 @@ gss_upcall_callback(struct rpc_task *task) struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred, struct gss_cred, gc_base); struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; - struct rpc_inode *rpci = gss_msg->inode; + struct rpc_pipe *pipe = gss_msg->pipe; - spin_lock(&rpci->pipe->lock); + spin_lock(&pipe->lock); gss_handle_downcall_result(gss_cred, gss_msg); - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); task->tk_status = gss_msg->msg.errno; gss_release_msg(gss_msg); } @@ -449,7 +449,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, kfree(gss_msg); return ERR_PTR(vers); } - gss_msg->inode = RPC_I(gss_auth->dentry[vers]->d_inode); + gss_msg->pipe = RPC_I(gss_auth->dentry[vers]->d_inode)->pipe; INIT_LIST_HEAD(&gss_msg->list); rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); init_waitqueue_head(&gss_msg->waitqueue); @@ -473,7 +473,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr return gss_new; gss_msg = gss_add_msg(gss_new); if (gss_msg == gss_new) { - int res = rpc_queue_upcall(gss_new->inode->pipe, &gss_new->msg); + int res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg); if (res) { gss_unhash_msg(gss_new); gss_msg = ERR_PTR(res); @@ -504,7 +504,7 @@ gss_refresh_upcall(struct rpc_task *task) struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_upcall_msg *gss_msg; - struct rpc_inode *rpci; + struct rpc_pipe *pipe; int err = 0; dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, @@ -522,8 +522,8 @@ gss_refresh_upcall(struct rpc_task *task) err = PTR_ERR(gss_msg); goto out; } - rpci = gss_msg->inode; - spin_lock(&rpci->pipe->lock); + pipe = gss_msg->pipe; + spin_lock(&pipe->lock); if (gss_cred->gc_upcall != NULL) rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { @@ -536,7 +536,7 @@ gss_refresh_upcall(struct rpc_task *task) gss_handle_downcall_result(gss_cred, gss_msg); err = gss_msg->msg.errno; } - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); gss_release_msg(gss_msg); out: dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", @@ -547,7 +547,7 @@ out: static inline int gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) { - struct rpc_inode *rpci; + struct rpc_pipe *pipe; struct rpc_cred *cred = &gss_cred->gc_base; struct gss_upcall_msg *gss_msg; DEFINE_WAIT(wait); @@ -571,14 +571,14 @@ retry: err = PTR_ERR(gss_msg); goto out; } - rpci = gss_msg->inode; + pipe = gss_msg->pipe; for (;;) { prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE); - spin_lock(&rpci->pipe->lock); + spin_lock(&pipe->lock); if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { break; } - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); if (fatal_signal_pending(current)) { err = -ERESTARTSYS; goto out_intr; @@ -589,7 +589,7 @@ retry: gss_cred_set_ctx(cred, gss_msg->ctx); else err = gss_msg->msg.errno; - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); out_intr: finish_wait(&gss_msg->waitqueue, &wait); gss_release_msg(gss_msg); @@ -607,7 +607,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) const void *p, *end; void *buf; struct gss_upcall_msg *gss_msg; - struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode); + struct rpc_pipe *pipe = RPC_I(filp->f_dentry->d_inode)->pipe; struct gss_cl_ctx *ctx; uid_t uid; ssize_t err = -EFBIG; @@ -637,14 +637,14 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) err = -ENOENT; /* Find a matching upcall */ - spin_lock(&rpci->pipe->lock); - gss_msg = __gss_find_upcall(rpci, uid); + spin_lock(&pipe->lock); + gss_msg = __gss_find_upcall(pipe, uid); if (gss_msg == NULL) { - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); goto err_put_ctx; } list_del_init(&gss_msg->list); - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); if (IS_ERR(p)) { @@ -672,9 +672,9 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) err = mlen; err_release_msg: - spin_lock(&rpci->pipe->lock); + spin_lock(&pipe->lock); __gss_unhash_msg(gss_msg); - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); gss_release_msg(gss_msg); err_put_ctx: gss_put_ctx(ctx); @@ -720,23 +720,23 @@ static int gss_pipe_open_v1(struct inode *inode) static void gss_pipe_release(struct inode *inode) { - struct rpc_inode *rpci = RPC_I(inode); + struct rpc_pipe *pipe = RPC_I(inode)->pipe; struct gss_upcall_msg *gss_msg; restart: - spin_lock(&rpci->pipe->lock); - list_for_each_entry(gss_msg, &rpci->pipe->in_downcall, list) { + spin_lock(&pipe->lock); + list_for_each_entry(gss_msg, &pipe->in_downcall, list) { if (!list_empty(&gss_msg->msg.list)) continue; gss_msg->msg.errno = -EPIPE; atomic_inc(&gss_msg->count); __gss_unhash_msg(gss_msg); - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); gss_release_msg(gss_msg); goto restart; } - spin_unlock(&rpci->pipe->lock); + spin_unlock(&pipe->lock); put_pipe_version(); } -- cgit v1.2.3-70-g09d2 From c239d83b9921b8a8005a3bcd23000cfe18acf5c2 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Dec 2011 15:44:06 +0300 Subject: SUNRPC: split SUNPRC PipeFS dentry and private pipe data creation This patch is a final step towards to removing PipeFS inode references from kernel code other than PipeFS itself. It makes all kernel SUNRPC PipeFS users depends on pipe private data, which state depend on their specific operations, etc. This patch completes SUNRPC PipeFS preparations and allows to create pipe private data and PipeFS dentries independently. Next step will be making SUNPRC PipeFS dentries allocated by SUNRPC PipeFS network namespace aware routines. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/blocklayout/blocklayout.c | 16 ++++++++--- fs/nfs/blocklayout/blocklayout.h | 2 +- fs/nfs/blocklayout/blocklayoutdev.c | 2 +- fs/nfs/blocklayout/blocklayoutdm.c | 2 +- fs/nfs/idmap.c | 28 +++++++++++++------ include/linux/sunrpc/rpc_pipe_fs.h | 7 +++-- net/sunrpc/auth_gss/auth_gss.c | 54 ++++++++++++++++++++++++------------- net/sunrpc/rpc_pipe.c | 54 +++++++++++++++++++++---------------- 8 files changed, 107 insertions(+), 58 deletions(-) (limited to 'net') diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 48cfac31f64..848660fd58c 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -46,7 +46,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andy Adamson "); MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver"); -struct dentry *bl_device_pipe; +struct rpc_pipe *bl_device_pipe; wait_queue_head_t bl_wq; static void print_page(struct page *page) @@ -1051,16 +1051,23 @@ static int __init nfs4blocklayout_init(void) if (ret) goto out_putrpc; - bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL, - &bl_upcall_ops, 0); + bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); path_put(&path); if (IS_ERR(bl_device_pipe)) { ret = PTR_ERR(bl_device_pipe); goto out_putrpc; } + bl_device_pipe->dentry = rpc_mkpipe_dentry(path.dentry, "blocklayout", + NULL, bl_device_pipe); + if (IS_ERR(bl_device_pipe->dentry)) { + ret = PTR_ERR(bl_device_pipe->dentry); + goto out_destroy_pipe; + } out: return ret; +out_destroy_pipe: + rpc_destroy_pipe_data(bl_device_pipe); out_putrpc: rpc_put_mount(); out_remove: @@ -1074,7 +1081,8 @@ static void __exit nfs4blocklayout_exit(void) __func__); pnfs_unregister_layoutdriver(&blocklayout_type); - rpc_unlink(bl_device_pipe); + rpc_unlink(bl_device_pipe->dentry); + rpc_destroy_pipe_data(bl_device_pipe); rpc_put_mount(); } diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index e31a2df28e7..49c670b18a9 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h @@ -161,7 +161,7 @@ struct bl_msg_hdr { u16 totallen; /* length of entire message, including hdr itself */ }; -extern struct dentry *bl_device_pipe; +extern struct rpc_pipe *bl_device_pipe; extern wait_queue_head_t bl_wq; #define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c index 81019190e46..949b6247879 100644 --- a/fs/nfs/blocklayout/blocklayoutdev.c +++ b/fs/nfs/blocklayout/blocklayoutdev.c @@ -146,7 +146,7 @@ nfs4_blk_decode_device(struct nfs_server *server, dprintk("%s CALLING USERSPACE DAEMON\n", __func__); add_wait_queue(&bl_wq, &wq); - rc = rpc_queue_upcall(RPC_I(bl_device_pipe->d_inode)->pipe, &msg); + rc = rpc_queue_upcall(bl_device_pipe, &msg); if (rc < 0) { remove_wait_queue(&bl_wq, &wq); rv = ERR_PTR(rc); diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index 3c38244a872..631f254d12a 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -66,7 +66,7 @@ static void dev_remove(dev_t dev) msg.len = sizeof(bl_msg) + bl_msg.totallen; add_wait_queue(&bl_wq, &wq); - if (rpc_queue_upcall(RPC_I(bl_device_pipe->d_inode)->pipe, &msg) < 0) { + if (rpc_queue_upcall(bl_device_pipe, &msg) < 0) { remove_wait_queue(&bl_wq, &wq); goto out; } diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 3c63c47c793..2992cb854e1 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -410,7 +410,7 @@ struct idmap_hashtable { }; struct idmap { - struct dentry *idmap_dentry; + struct rpc_pipe *idmap_pipe; wait_queue_head_t idmap_wq; struct idmap_msg idmap_im; struct mutex idmap_lock; /* Serializes upcalls */ @@ -435,6 +435,7 @@ int nfs_idmap_new(struct nfs_client *clp) { struct idmap *idmap; + struct rpc_pipe *pipe; int error; BUG_ON(clp->cl_idmap != NULL); @@ -443,14 +444,23 @@ nfs_idmap_new(struct nfs_client *clp) if (idmap == NULL) return -ENOMEM; - idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, - "idmap", idmap, &idmap_upcall_ops, 0); - if (IS_ERR(idmap->idmap_dentry)) { - error = PTR_ERR(idmap->idmap_dentry); + pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0); + if (IS_ERR(pipe)) { + error = PTR_ERR(pipe); kfree(idmap); return error; } + if (clp->cl_rpcclient->cl_path.dentry) + pipe->dentry = rpc_mkpipe_dentry(clp->cl_rpcclient->cl_path.dentry, + "idmap", idmap, pipe); + if (IS_ERR(pipe->dentry)) { + error = PTR_ERR(pipe->dentry); + rpc_destroy_pipe_data(pipe); + kfree(idmap); + return error; + } + idmap->idmap_pipe = pipe; mutex_init(&idmap->idmap_lock); mutex_init(&idmap->idmap_im_lock); init_waitqueue_head(&idmap->idmap_wq); @@ -468,7 +478,9 @@ nfs_idmap_delete(struct nfs_client *clp) if (!idmap) return; - rpc_unlink(idmap->idmap_dentry); + if (idmap->idmap_pipe->dentry) + rpc_unlink(idmap->idmap_pipe->dentry); + rpc_destroy_pipe_data(idmap->idmap_pipe); clp->cl_idmap = NULL; kfree(idmap); } @@ -589,7 +601,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, msg.len = sizeof(*im); add_wait_queue(&idmap->idmap_wq, &wq); - if (rpc_queue_upcall(RPC_I(idmap->idmap_dentry->d_inode)->pipe, &msg) < 0) { + if (rpc_queue_upcall(idmap->idmap_pipe, &msg) < 0) { remove_wait_queue(&idmap->idmap_wq, &wq); goto out; } @@ -650,7 +662,7 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, add_wait_queue(&idmap->idmap_wq, &wq); - if (rpc_queue_upcall(RPC_I(idmap->idmap_dentry->d_inode)->pipe, &msg) < 0) { + if (rpc_queue_upcall(idmap->idmap_pipe, &msg) < 0) { remove_wait_queue(&idmap->idmap_wq, &wq); goto out; } diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 3ebc257e2b4..0d1f748f76d 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -34,6 +34,7 @@ struct rpc_pipe { struct delayed_work queue_timeout; const struct rpc_pipe_ops *ops; spinlock_t lock; + struct dentry *dentry; }; struct rpc_inode { @@ -77,8 +78,10 @@ extern struct dentry *rpc_create_cache_dir(struct dentry *, struct cache_detail *); extern void rpc_remove_cache_dir(struct dentry *); -extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, - const struct rpc_pipe_ops *, int flags); +struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags); +void rpc_destroy_pipe_data(struct rpc_pipe *pipe); +extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *, + struct rpc_pipe *); extern int rpc_unlink(struct dentry *); extern struct vfsmount *rpc_get_mount(void); extern void rpc_put_mount(void); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 304b8309f21..f684ce60666 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -81,7 +81,7 @@ struct gss_auth { * mechanism (for example, "krb5") and exists for * backwards-compatibility with older gssd's. */ - struct dentry *dentry[2]; + struct rpc_pipe *pipe[2]; }; /* pipe_version >= 0 if and only if someone has a pipe open. */ @@ -449,7 +449,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, kfree(gss_msg); return ERR_PTR(vers); } - gss_msg->pipe = RPC_I(gss_auth->dentry[vers]->d_inode)->pipe; + gss_msg->pipe = gss_auth->pipe[vers]; INIT_LIST_HEAD(&gss_msg->list); rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); init_waitqueue_head(&gss_msg->waitqueue); @@ -799,21 +799,33 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) * that we supported only the old pipe. So we instead create * the new pipe first. */ - gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_path.dentry, - "gssd", - clnt, &gss_upcall_ops_v1, - RPC_PIPE_WAIT_FOR_OPEN); - if (IS_ERR(gss_auth->dentry[1])) { - err = PTR_ERR(gss_auth->dentry[1]); + gss_auth->pipe[1] = rpc_mkpipe_data(&gss_upcall_ops_v1, + RPC_PIPE_WAIT_FOR_OPEN); + if (IS_ERR(gss_auth->pipe[1])) { + err = PTR_ERR(gss_auth->pipe[1]); goto err_put_mech; } - gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_path.dentry, - gss_auth->mech->gm_name, - clnt, &gss_upcall_ops_v0, - RPC_PIPE_WAIT_FOR_OPEN); - if (IS_ERR(gss_auth->dentry[0])) { - err = PTR_ERR(gss_auth->dentry[0]); + gss_auth->pipe[0] = rpc_mkpipe_data(&gss_upcall_ops_v0, + RPC_PIPE_WAIT_FOR_OPEN); + if (IS_ERR(gss_auth->pipe[0])) { + err = PTR_ERR(gss_auth->pipe[0]); + goto err_destroy_pipe_1; + } + + gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, + "gssd", + clnt, gss_auth->pipe[1]); + if (IS_ERR(gss_auth->pipe[1]->dentry)) { + err = PTR_ERR(gss_auth->pipe[1]->dentry); + goto err_destroy_pipe_0; + } + + gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, + gss_auth->mech->gm_name, + clnt, gss_auth->pipe[0]); + if (IS_ERR(gss_auth->pipe[0]->dentry)) { + err = PTR_ERR(gss_auth->pipe[0]->dentry); goto err_unlink_pipe_1; } err = rpcauth_init_credcache(auth); @@ -822,9 +834,13 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) return auth; err_unlink_pipe_0: - rpc_unlink(gss_auth->dentry[0]); + rpc_unlink(gss_auth->pipe[0]->dentry); err_unlink_pipe_1: - rpc_unlink(gss_auth->dentry[1]); + rpc_unlink(gss_auth->pipe[1]->dentry); +err_destroy_pipe_0: + rpc_destroy_pipe_data(gss_auth->pipe[0]); +err_destroy_pipe_1: + rpc_destroy_pipe_data(gss_auth->pipe[1]); err_put_mech: gss_mech_put(gss_auth->mech); err_free: @@ -837,8 +853,10 @@ out_dec: static void gss_free(struct gss_auth *gss_auth) { - rpc_unlink(gss_auth->dentry[1]); - rpc_unlink(gss_auth->dentry[0]); + rpc_unlink(gss_auth->pipe[0]->dentry); + rpc_unlink(gss_auth->pipe[1]->dentry); + rpc_destroy_pipe_data(gss_auth->pipe[0]); + rpc_destroy_pipe_data(gss_auth->pipe[1]); gss_mech_put(gss_auth->mech); kfree(gss_auth); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 4093da79d51..6dd8b96e8df 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -206,7 +206,6 @@ static void rpc_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); - kfree(RPC_I(inode)->pipe); kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); } @@ -575,34 +574,44 @@ init_pipe(struct rpc_pipe *pipe) rpc_timeout_upcall_queue); pipe->ops = NULL; spin_lock_init(&pipe->lock); + pipe->dentry = NULL; +} +void rpc_destroy_pipe_data(struct rpc_pipe *pipe) +{ + kfree(pipe); } +EXPORT_SYMBOL_GPL(rpc_destroy_pipe_data); -static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, - umode_t mode, - const struct file_operations *i_fop, - void *private, - const struct rpc_pipe_ops *ops, - int flags) +struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags) { struct rpc_pipe *pipe; - struct rpc_inode *rpci; - int err; pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL); if (!pipe) - return -ENOMEM; + return ERR_PTR(-ENOMEM); init_pipe(pipe); + pipe->ops = ops; + pipe->flags = flags; + return pipe; +} +EXPORT_SYMBOL_GPL(rpc_mkpipe_data); + +static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry, + umode_t mode, + const struct file_operations *i_fop, + void *private, + struct rpc_pipe *pipe) +{ + struct rpc_inode *rpci; + int err; + err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); - if (err) { - kfree(pipe); + if (err) return err; - } rpci = RPC_I(dentry->d_inode); rpci->private = private; rpci->pipe = pipe; - rpci->pipe->flags = flags; - rpci->pipe->ops = ops; fsnotify_create(dir, dentry); return 0; } @@ -819,9 +828,8 @@ static int rpc_rmdir_depopulate(struct dentry *dentry, * The @private argument passed here will be available to all these methods * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. */ -struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, - void *private, const struct rpc_pipe_ops *ops, - int flags) +struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name, + void *private, struct rpc_pipe *pipe) { struct dentry *dentry; struct inode *dir = parent->d_inode; @@ -829,9 +837,9 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, struct qstr q; int err; - if (ops->upcall == NULL) + if (pipe->ops->upcall == NULL) umode &= ~S_IRUGO; - if (ops->downcall == NULL) + if (pipe->ops->downcall == NULL) umode &= ~S_IWUGO; q.name = name; @@ -842,8 +850,8 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, dentry = __rpc_lookup_create_exclusive(parent, &q); if (IS_ERR(dentry)) goto out; - err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, - private, ops, flags); + err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops, + private, pipe); if (err) goto out_err; out: @@ -856,7 +864,7 @@ out_err: err); goto out; } -EXPORT_SYMBOL_GPL(rpc_mkpipe); +EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry); /** * rpc_unlink - remove a pipe -- cgit v1.2.3-70-g09d2 From 0157d021d23a087eecfa830502f81cfe843f0d16 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 11 Jan 2012 19:18:01 +0400 Subject: SUNRPC: handle RPC client pipefs dentries by network namespace aware routines v2: 1) "Over-put" of PipeFS mount point fixed. Fix is ugly, but allows to bisect the patch set. And it will be removed later in the series. This patch makes RPC clients PipeFs dentries allocations in it's owner network namespace context. RPC client pipefs dentries creation logic has been changed: 1) Pipefs dentries creation by sb was moved to separated function, which will be used for handling PipeFS mount notification. 2) Initial value of RPC client PipeFS dir dentry is set no NULL now. RPC client pipefs dentries cleanup logic has been changed: 1) Cleanup is done now in separated rpc_remove_pipedir() function, which takes care about pipefs superblock locking. Also this patch removes slashes from cb_program.pipe_dir_name and from NFS_PIPE_DIRNAME to make rpc_d_lookup_sb() work. This doesn't affect vfs_path_lookup() results in nfs4blocklayout_init() since this slash is cutted off anyway in link_path_walk(). Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfsd/nfs4callback.c | 2 +- include/linux/nfs.h | 2 +- net/sunrpc/clnt.c | 97 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 66 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 6f3ebb48b12..426ccb17165 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -622,7 +622,7 @@ static struct rpc_program cb_program = { .nrvers = ARRAY_SIZE(nfs_cb_version), .version = nfs_cb_version, .stats = &cb_stats, - .pipe_dir_name = "/nfsd4_cb", + .pipe_dir_name = "nfsd4_cb", }; static int max_cb_time(void) diff --git a/include/linux/nfs.h b/include/linux/nfs.h index 8c6ee44914c..6d1fb63f592 100644 --- a/include/linux/nfs.h +++ b/include/linux/nfs.h @@ -29,7 +29,7 @@ #define NFS_MNT_VERSION 1 #define NFS_MNT3_VERSION 3 -#define NFS_PIPE_DIRNAME "/nfs" +#define NFS_PIPE_DIRNAME "nfs" /* * NFS stats. The good thing with these values is that NFSv3 errors are diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f0268ea7e71..5ef192c1a57 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -93,52 +93,89 @@ static void rpc_unregister_client(struct rpc_clnt *clnt) spin_unlock(&rpc_client_lock); } -static int -rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) +static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) +{ + if (clnt->cl_path.dentry) + rpc_remove_client_dir(clnt->cl_path.dentry); + clnt->cl_path.dentry = NULL; +} + +static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) +{ + struct super_block *pipefs_sb; + int put_mnt = 0; + + pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); + if (pipefs_sb) { + if (clnt->cl_path.dentry) + put_mnt = 1; + __rpc_clnt_remove_pipedir(clnt); + rpc_put_sb_net(clnt->cl_xprt->xprt_net); + } + if (put_mnt) + rpc_put_mount(); +} + +static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, + struct rpc_clnt *clnt, char *dir_name) { static uint32_t clntid; - struct path path, dir; char name[15]; struct qstr q = { .name = name, }; + struct dentry *dir, *dentry; int error; - clnt->cl_path.mnt = ERR_PTR(-ENOENT); - clnt->cl_path.dentry = ERR_PTR(-ENOENT); - if (dir_name == NULL) - return 0; - - path.mnt = rpc_get_mount(); - if (IS_ERR(path.mnt)) - return PTR_ERR(path.mnt); - error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir); - if (error) - goto err; - + dir = rpc_d_lookup_sb(sb, dir_name); + if (dir == NULL) + return dir; for (;;) { q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); name[sizeof(name) - 1] = '\0'; q.hash = full_name_hash(q.name, q.len); - path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt); - if (!IS_ERR(path.dentry)) + dentry = rpc_create_client_dir(dir, &q, clnt); + if (!IS_ERR(dentry)) break; - error = PTR_ERR(path.dentry); + error = PTR_ERR(dentry); if (error != -EEXIST) { printk(KERN_INFO "RPC: Couldn't create pipefs entry" " %s/%s, error %d\n", dir_name, name, error); - goto err_path_put; + break; } } - path_put(&dir); + dput(dir); + return dentry; +} + +static int +rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) +{ + struct super_block *pipefs_sb; + struct path path; + + clnt->cl_path.mnt = ERR_PTR(-ENOENT); + clnt->cl_path.dentry = NULL; + if (dir_name == NULL) + return 0; + + path.mnt = rpc_get_mount(); + if (IS_ERR(path.mnt)) + return PTR_ERR(path.mnt); + pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); + if (!pipefs_sb) { + rpc_put_mount(); + return -ENOENT; + } + path.dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); + rpc_put_sb_net(clnt->cl_xprt->xprt_net); + if (IS_ERR(path.dentry)) { + rpc_put_mount(); + return PTR_ERR(path.dentry); + } clnt->cl_path = path; return 0; -err_path_put: - path_put(&dir); -err: - rpc_put_mount(); - return error; } static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) @@ -246,10 +283,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru return clnt; out_no_auth: - if (!IS_ERR(clnt->cl_path.dentry)) { - rpc_remove_client_dir(clnt->cl_path.dentry); - rpc_put_mount(); - } + rpc_clnt_remove_pipedir(clnt); out_no_path: kfree(clnt->cl_principal); out_no_principal: @@ -474,10 +508,7 @@ rpc_free_client(struct rpc_clnt *clnt) { dprintk("RPC: destroying %s client for %s\n", clnt->cl_protname, clnt->cl_server); - if (!IS_ERR(clnt->cl_path.dentry)) { - rpc_remove_client_dir(clnt->cl_path.dentry); - rpc_put_mount(); - } + rpc_clnt_remove_pipedir(clnt); if (clnt->cl_parent != clnt) { rpc_release_client(clnt->cl_parent); goto out_free; -- cgit v1.2.3-70-g09d2 From ccdc28f81c91f7ef2dc6c28d27f50264b19e4dd5 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 11 Jan 2012 19:18:09 +0400 Subject: SUNRPC: handle GSS AUTH pipes by network namespace aware routines This patch makes RPC GSS PipeFs pipes allocated in it's RPC client owner network namespace context. Pipes creation and destruction now done in separated functions, which takes care about PipeFS superblock locking. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/auth_gss.c | 95 ++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index f684ce60666..1a6fa917351 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -757,6 +757,73 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg) } } +static void gss_pipes_dentries_destroy(struct rpc_auth *auth) +{ + struct gss_auth *gss_auth; + + gss_auth = container_of(auth, struct gss_auth, rpc_auth); + rpc_unlink(gss_auth->pipe[0]->dentry); + rpc_unlink(gss_auth->pipe[1]->dentry); +} + +static int gss_pipes_dentries_create(struct rpc_auth *auth) +{ + int err; + struct gss_auth *gss_auth; + struct rpc_clnt *clnt; + + gss_auth = container_of(auth, struct gss_auth, rpc_auth); + clnt = gss_auth->client; + + gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, + "gssd", + clnt, gss_auth->pipe[1]); + if (IS_ERR(gss_auth->pipe[1]->dentry)) + return PTR_ERR(gss_auth->pipe[1]->dentry); + gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, + gss_auth->mech->gm_name, + clnt, gss_auth->pipe[0]); + if (IS_ERR(gss_auth->pipe[0]->dentry)) { + err = PTR_ERR(gss_auth->pipe[0]->dentry); + goto err_unlink_pipe_1; + } + return 0; + +err_unlink_pipe_1: + rpc_unlink(gss_auth->pipe[1]->dentry); + return err; +} + +static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, + struct rpc_auth *auth) +{ + struct net *net = clnt->cl_xprt->xprt_net; + struct super_block *sb; + + sb = rpc_get_sb_net(net); + if (sb) { + if (clnt->cl_path.dentry) + gss_pipes_dentries_destroy(auth); + rpc_put_sb_net(net); + } +} + +static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, + struct rpc_auth *auth) +{ + struct net *net = clnt->cl_xprt->xprt_net; + struct super_block *sb; + int err = 0; + + sb = rpc_get_sb_net(net); + if (sb) { + if (clnt->cl_path.dentry) + err = gss_pipes_dentries_create(auth); + rpc_put_sb_net(net); + } + return err; +} + /* * NOTE: we have the opportunity to use different * parameters based on the input flavor (which must be a pseudoflavor) @@ -812,31 +879,16 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) err = PTR_ERR(gss_auth->pipe[0]); goto err_destroy_pipe_1; } - - gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, - "gssd", - clnt, gss_auth->pipe[1]); - if (IS_ERR(gss_auth->pipe[1]->dentry)) { - err = PTR_ERR(gss_auth->pipe[1]->dentry); + err = gss_pipes_dentries_create_net(clnt, auth); + if (err) goto err_destroy_pipe_0; - } - - gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, - gss_auth->mech->gm_name, - clnt, gss_auth->pipe[0]); - if (IS_ERR(gss_auth->pipe[0]->dentry)) { - err = PTR_ERR(gss_auth->pipe[0]->dentry); - goto err_unlink_pipe_1; - } err = rpcauth_init_credcache(auth); if (err) - goto err_unlink_pipe_0; + goto err_unlink_pipes; return auth; -err_unlink_pipe_0: - rpc_unlink(gss_auth->pipe[0]->dentry); -err_unlink_pipe_1: - rpc_unlink(gss_auth->pipe[1]->dentry); +err_unlink_pipes: + gss_pipes_dentries_destroy_net(clnt, auth); err_destroy_pipe_0: rpc_destroy_pipe_data(gss_auth->pipe[0]); err_destroy_pipe_1: @@ -853,8 +905,7 @@ out_dec: static void gss_free(struct gss_auth *gss_auth) { - rpc_unlink(gss_auth->pipe[0]->dentry); - rpc_unlink(gss_auth->pipe[1]->dentry); + gss_pipes_dentries_destroy_net(gss_auth->client, &gss_auth->rpc_auth); rpc_destroy_pipe_data(gss_auth->pipe[0]); rpc_destroy_pipe_data(gss_auth->pipe[1]); gss_mech_put(gss_auth->mech); -- cgit v1.2.3-70-g09d2 From 70abc49b4f4a4ef04a6bd9852edbd047b480bed7 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 12 Jan 2012 22:07:51 +0400 Subject: SUNRPC: make SUNPRC clients list per network namespace context This patch moves static SUNRPC clients list and it's lock to sunrpc_net structure. Currently this list is used only for debug purposes. But later it will be used also for selecting clients by networks namespace on PipeFS mount/umount events. Per-network namespace lists will make this faster and simplier. Note: client list is taken from "init_net" network namespace context in rpc_show_tasks(). This will be changed some day later with making SUNRPC sysctl's per network namespace context. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 3 ++- net/sunrpc/clnt.c | 26 +++++++++++++++----------- net/sunrpc/netns.h | 3 +++ net/sunrpc/sunrpc_syms.c | 3 +++ net/sunrpc/sysctl.c | 4 +++- 5 files changed, 26 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index e7756896f3c..b16243a35f0 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -244,7 +244,8 @@ int rpciod_up(void); void rpciod_down(void); int __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *)); #ifdef RPC_DEBUG -void rpc_show_tasks(void); +struct net; +void rpc_show_tasks(struct net *); #endif int rpc_init_mempool(void); void rpc_destroy_mempool(void); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5ef192c1a57..90e82c5daeb 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -38,6 +38,7 @@ #include #include "sunrpc.h" +#include "netns.h" #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_CALL @@ -50,8 +51,6 @@ /* * All RPC clients are linked into this list */ -static LIST_HEAD(all_clients); -static DEFINE_SPINLOCK(rpc_client_lock); static DECLARE_WAIT_QUEUE_HEAD(destroy_wait); @@ -81,16 +80,20 @@ static int rpc_ping(struct rpc_clnt *clnt); static void rpc_register_client(struct rpc_clnt *clnt) { - spin_lock(&rpc_client_lock); - list_add(&clnt->cl_clients, &all_clients); - spin_unlock(&rpc_client_lock); + struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); + + spin_lock(&sn->rpc_client_lock); + list_add(&clnt->cl_clients, &sn->all_clients); + spin_unlock(&sn->rpc_client_lock); } static void rpc_unregister_client(struct rpc_clnt *clnt) { - spin_lock(&rpc_client_lock); + struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); + + spin_lock(&sn->rpc_client_lock); list_del(&clnt->cl_clients); - spin_unlock(&rpc_client_lock); + spin_unlock(&sn->rpc_client_lock); } static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) @@ -1883,14 +1886,15 @@ static void rpc_show_task(const struct rpc_clnt *clnt, task->tk_action, rpc_waitq); } -void rpc_show_tasks(void) +void rpc_show_tasks(struct net *net) { struct rpc_clnt *clnt; struct rpc_task *task; int header = 0; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); - spin_lock(&rpc_client_lock); - list_for_each_entry(clnt, &all_clients, cl_clients) { + spin_lock(&sn->rpc_client_lock); + list_for_each_entry(clnt, &sn->all_clients, cl_clients) { spin_lock(&clnt->cl_lock); list_for_each_entry(task, &clnt->cl_tasks, tk_task) { if (!header) { @@ -1901,6 +1905,6 @@ void rpc_show_tasks(void) } spin_unlock(&clnt->cl_lock); } - spin_unlock(&rpc_client_lock); + spin_unlock(&sn->rpc_client_lock); } #endif diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 11d2f486340..0f3af34fa50 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -12,6 +12,9 @@ struct sunrpc_net { struct super_block *pipefs_sb; struct mutex pipefs_sb_lock; + + struct list_head all_clients; + spinlock_t rpc_client_lock; }; extern int sunrpc_net_id; diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 7086d11589c..b4217dc8599 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -29,6 +29,7 @@ int sunrpc_net_id; static __net_init int sunrpc_init_net(struct net *net) { int err; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); err = rpc_proc_init(net); if (err) @@ -39,6 +40,8 @@ static __net_init int sunrpc_init_net(struct net *net) goto err_ipmap; rpc_pipefs_init_net(net); + INIT_LIST_HEAD(&sn->all_clients); + spin_lock_init(&sn->rpc_client_lock); return 0; err_ipmap: diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index e65dcc61333..af7d339add9 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c @@ -20,6 +20,8 @@ #include #include +#include "netns.h" + /* * Declare the debug flags here */ @@ -110,7 +112,7 @@ proc_dodebug(ctl_table *table, int write, *(unsigned int *) table->data = value; /* Display the RPC tasks on writing to rpc_debug */ if (strcmp(table->procname, "rpc_debug") == 0) - rpc_show_tasks(); + rpc_show_tasks(&init_net); } else { if (!access_ok(VERIFY_WRITE, buffer, left)) return -EFAULT; -- cgit v1.2.3-70-g09d2 From 80df9d202255071c8ec610a6a3fdca5cac69f7bd Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 11 Jan 2012 19:18:17 +0400 Subject: SUNRPC: subscribe RPC clients to pipefs notifications This patch subscribes RPC clients to RPC pipefs notifications. RPC clients notifier block is registering with pipefs initialization during SUNRPC module init. This notifier callback is responsible for RPC client PipeFS directory and GSS pipes creation. For pipes creation and destruction two additional callbacks were added to struct rpc_authops. Note that no locking required in notifier callback because PipeFS superblock pointer is passed as an argument from it's creation or destruction routine and thus we can be sure about it's validity. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/auth.h | 2 ++ net/sunrpc/auth_gss/auth_gss.c | 10 ++++-- net/sunrpc/clnt.c | 69 +++++++++++++++++++++++++++++++++++++++++- net/sunrpc/rpc_pipe.c | 19 ++++++++---- net/sunrpc/sunrpc.h | 2 ++ 5 files changed, 92 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 7874a8a5663..492a36d7282 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -99,6 +99,8 @@ struct rpc_authops { struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); + int (*pipes_create)(struct rpc_auth *); + void (*pipes_destroy)(struct rpc_auth *); }; struct rpc_credops { diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 1a6fa917351..9da2d837b51 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -762,8 +762,10 @@ static void gss_pipes_dentries_destroy(struct rpc_auth *auth) struct gss_auth *gss_auth; gss_auth = container_of(auth, struct gss_auth, rpc_auth); - rpc_unlink(gss_auth->pipe[0]->dentry); - rpc_unlink(gss_auth->pipe[1]->dentry); + if (gss_auth->pipe[0]->dentry) + rpc_unlink(gss_auth->pipe[0]->dentry); + if (gss_auth->pipe[1]->dentry) + rpc_unlink(gss_auth->pipe[1]->dentry); } static int gss_pipes_dentries_create(struct rpc_auth *auth) @@ -1614,7 +1616,9 @@ static const struct rpc_authops authgss_ops = { .create = gss_create, .destroy = gss_destroy, .lookup_cred = gss_lookup_cred, - .crcreate = gss_create_cred + .crcreate = gss_create_cred, + .pipes_create = gss_pipes_dentries_create, + .pipes_destroy = gss_pipes_dentries_destroy, }; static const struct rpc_credops gss_credops = { diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 90e82c5daeb..41707450059 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -98,8 +98,11 @@ static void rpc_unregister_client(struct rpc_clnt *clnt) static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) { - if (clnt->cl_path.dentry) + if (clnt->cl_path.dentry) { + if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy) + clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth); rpc_remove_client_dir(clnt->cl_path.dentry); + } clnt->cl_path.dentry = NULL; } @@ -181,6 +184,70 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) return 0; } +static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, + struct super_block *sb) +{ + struct dentry *dentry; + int err = 0; + + switch (event) { + case RPC_PIPEFS_MOUNT: + if (clnt->cl_program->pipe_dir_name == NULL) + break; + dentry = rpc_setup_pipedir_sb(sb, clnt, + clnt->cl_program->pipe_dir_name); + BUG_ON(dentry == NULL); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + clnt->cl_path.dentry = dentry; + if (clnt->cl_auth->au_ops->pipes_create) { + err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth); + if (err) + __rpc_clnt_remove_pipedir(clnt); + } + break; + case RPC_PIPEFS_UMOUNT: + __rpc_clnt_remove_pipedir(clnt); + break; + default: + printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event); + return -ENOTSUPP; + } + return err; +} + +static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct super_block *sb = ptr; + struct rpc_clnt *clnt; + int error = 0; + struct sunrpc_net *sn = net_generic(sb->s_fs_info, sunrpc_net_id); + + spin_lock(&sn->rpc_client_lock); + list_for_each_entry(clnt, &sn->all_clients, cl_clients) { + error = __rpc_pipefs_event(clnt, event, sb); + if (error) + break; + } + spin_unlock(&sn->rpc_client_lock); + return error; +} + +static struct notifier_block rpc_clients_block = { + .notifier_call = rpc_pipefs_event, +}; + +int rpc_clients_notifier_register(void) +{ + return rpc_pipefs_notifier_register(&rpc_clients_block); +} + +void rpc_clients_notifier_unregister(void) +{ + return rpc_pipefs_notifier_unregister(&rpc_clients_block); +} + static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) { struct rpc_program *program = args->program; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 6dd8b96e8df..910de4169a8 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -937,7 +937,7 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry, /** * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() - * @dentry: directory to remove + * @clnt: rpc client */ int rpc_remove_client_dir(struct dentry *dentry) { @@ -1188,17 +1188,24 @@ int register_rpc_pipefs(void) init_once); if (!rpc_inode_cachep) return -ENOMEM; + err = rpc_clients_notifier_register(); + if (err) + goto err_notifier; err = register_filesystem(&rpc_pipe_fs_type); - if (err) { - kmem_cache_destroy(rpc_inode_cachep); - return err; - } - + if (err) + goto err_register; return 0; + +err_register: + rpc_clients_notifier_unregister(); +err_notifier: + kmem_cache_destroy(rpc_inode_cachep); + return err; } void unregister_rpc_pipefs(void) { + rpc_clients_notifier_unregister(); kmem_cache_destroy(rpc_inode_cachep); unregister_filesystem(&rpc_pipe_fs_type); } diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 90c292e2738..14c9f6d1c5f 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h @@ -47,5 +47,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr, struct page *headpage, unsigned long headoffset, struct page *tailpage, unsigned long tailoffset); +int rpc_clients_notifier_register(void); +void rpc_clients_notifier_unregister(void); #endif /* _NET_SUNRPC_SUNRPC_H */ -- cgit v1.2.3-70-g09d2 From f5131257f771ad0e84cf0314a2a86b66318755a9 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 11 Jan 2012 19:18:26 +0400 Subject: SUNRPC: remove RPC client pipefs dentries after unregister Without this patch we have races: rpc_fill_super rpc_free_client rpc_pipefs_event(MOUNT) rpc_remove_pipedir spin_lock(&rpc_client_lock); rpc_setup_pipedir_sb spin_unlock(&rpc_client_lock); spin_lock(&rpc_client_lock); (remove from list) spin_unlock(&rpc_client_lock); MEAMORY LEAKED Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 41707450059..c89ceb80fe8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -578,7 +578,6 @@ rpc_free_client(struct rpc_clnt *clnt) { dprintk("RPC: destroying %s client for %s\n", clnt->cl_protname, clnt->cl_server); - rpc_clnt_remove_pipedir(clnt); if (clnt->cl_parent != clnt) { rpc_release_client(clnt->cl_parent); goto out_free; @@ -587,6 +586,7 @@ rpc_free_client(struct rpc_clnt *clnt) kfree(clnt->cl_server); out_free: rpc_unregister_client(clnt); + rpc_clnt_remove_pipedir(clnt); rpc_free_iostats(clnt->cl_metrics); kfree(clnt->cl_principal); clnt->cl_metrics = NULL; -- cgit v1.2.3-70-g09d2 From 70fe25b6e1a535f09792d1ed7012036c7bd506b2 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 11 Jan 2012 19:18:34 +0400 Subject: SUNRPC: remove RPC pipefs mount point manipulations from RPC clients code v2: 1) Updated due to changes in the first patch of the series. Now, with RPC pipefs mount notifications handling in RPC clients, we can remove mount point creation and destruction. RPC clients dentries will be created on PipeFS mount event and removed on umount event. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index c89ceb80fe8..e3ced306121 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -109,17 +109,12 @@ static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) { struct super_block *pipefs_sb; - int put_mnt = 0; pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); if (pipefs_sb) { - if (clnt->cl_path.dentry) - put_mnt = 1; __rpc_clnt_remove_pipedir(clnt); rpc_put_sb_net(clnt->cl_xprt->xprt_net); } - if (put_mnt) - rpc_put_mount(); } static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, @@ -165,21 +160,13 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) clnt->cl_path.dentry = NULL; if (dir_name == NULL) return 0; - - path.mnt = rpc_get_mount(); - if (IS_ERR(path.mnt)) - return PTR_ERR(path.mnt); pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); - if (!pipefs_sb) { - rpc_put_mount(); - return -ENOENT; - } + if (!pipefs_sb) + return 0; path.dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); rpc_put_sb_net(clnt->cl_xprt->xprt_net); - if (IS_ERR(path.dentry)) { - rpc_put_mount(); + if (IS_ERR(path.dentry)) return PTR_ERR(path.dentry); - } clnt->cl_path = path; return 0; } -- cgit v1.2.3-70-g09d2 From 30507f58ce11e7664512059c708347d7a7d75271 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 11 Jan 2012 19:18:42 +0400 Subject: SUNRPC: remove RPC PipeFS mount point reference from RPC client This is a cleanup patch. We don't need this reference anymore. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/idmap.c | 4 ++-- include/linux/sunrpc/clnt.h | 2 +- net/sunrpc/auth_gss/auth_gss.c | 8 ++++---- net/sunrpc/clnt.c | 21 ++++++++++----------- 4 files changed, 17 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 2992cb854e1..588d7da5b17 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -451,8 +451,8 @@ nfs_idmap_new(struct nfs_client *clp) return error; } - if (clp->cl_rpcclient->cl_path.dentry) - pipe->dentry = rpc_mkpipe_dentry(clp->cl_rpcclient->cl_path.dentry, + if (clp->cl_rpcclient->cl_dentry) + pipe->dentry = rpc_mkpipe_dentry(clp->cl_rpcclient->cl_dentry, "idmap", idmap, pipe); if (IS_ERR(pipe->dentry)) { error = PTR_ERR(pipe->dentry); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 2c5993a17c3..bfd61852b71 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -57,7 +57,7 @@ struct rpc_clnt { int cl_nodelen; /* nodename length */ char cl_nodename[UNX_MAXNODENAME]; - struct path cl_path; + struct dentry * cl_dentry; struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_rtt cl_rtt_default; struct rpc_timeout cl_timeout_default; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 9da2d837b51..5ebb602cabe 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -777,12 +777,12 @@ static int gss_pipes_dentries_create(struct rpc_auth *auth) gss_auth = container_of(auth, struct gss_auth, rpc_auth); clnt = gss_auth->client; - gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, + gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry, "gssd", clnt, gss_auth->pipe[1]); if (IS_ERR(gss_auth->pipe[1]->dentry)) return PTR_ERR(gss_auth->pipe[1]->dentry); - gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_path.dentry, + gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry, gss_auth->mech->gm_name, clnt, gss_auth->pipe[0]); if (IS_ERR(gss_auth->pipe[0]->dentry)) { @@ -804,7 +804,7 @@ static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, sb = rpc_get_sb_net(net); if (sb) { - if (clnt->cl_path.dentry) + if (clnt->cl_dentry) gss_pipes_dentries_destroy(auth); rpc_put_sb_net(net); } @@ -819,7 +819,7 @@ static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, sb = rpc_get_sb_net(net); if (sb) { - if (clnt->cl_path.dentry) + if (clnt->cl_dentry) err = gss_pipes_dentries_create(auth); rpc_put_sb_net(net); } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e3ced306121..ed7c22de931 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -98,12 +98,12 @@ static void rpc_unregister_client(struct rpc_clnt *clnt) static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) { - if (clnt->cl_path.dentry) { + if (clnt->cl_dentry) { if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy) clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth); - rpc_remove_client_dir(clnt->cl_path.dentry); + rpc_remove_client_dir(clnt->cl_dentry); } - clnt->cl_path.dentry = NULL; + clnt->cl_dentry = NULL; } static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) @@ -154,20 +154,19 @@ static int rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) { struct super_block *pipefs_sb; - struct path path; + struct dentry *dentry; - clnt->cl_path.mnt = ERR_PTR(-ENOENT); - clnt->cl_path.dentry = NULL; + clnt->cl_dentry = NULL; if (dir_name == NULL) return 0; pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); if (!pipefs_sb) return 0; - path.dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); + dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); rpc_put_sb_net(clnt->cl_xprt->xprt_net); - if (IS_ERR(path.dentry)) - return PTR_ERR(path.dentry); - clnt->cl_path = path; + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + clnt->cl_dentry = dentry; return 0; } @@ -186,7 +185,7 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, BUG_ON(dentry == NULL); if (IS_ERR(dentry)) return PTR_ERR(dentry); - clnt->cl_path.dentry = dentry; + clnt->cl_dentry = dentry; if (clnt->cl_auth->au_ops->pipes_create) { err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth); if (err) -- cgit v1.2.3-70-g09d2 From 820f9442e711a81749e70c40f149fc54c4ce0ca8 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 25 Nov 2011 17:12:40 +0300 Subject: SUNRPC: split cache creation and PipeFS registration This precursor patch splits SUNRPC cache creation and PipeFS registartion. It's required for latter split of NFS DNS resolver cache creation per network namespace context and PipeFS registration/unregistration on MOUNT/UMOUNT events. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/cache_lib.c | 3 +++ include/linux/sunrpc/cache.h | 2 ++ net/sunrpc/cache.c | 12 +++++------- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c index c98b439332f..d62a8951cb1 100644 --- a/fs/nfs/cache_lib.c +++ b/fs/nfs/cache_lib.c @@ -120,6 +120,7 @@ int nfs_cache_register(struct cache_detail *cd) mnt = rpc_get_mount(); if (IS_ERR(mnt)) return PTR_ERR(mnt); + sunrpc_init_cache_detail(cd); ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &path); if (ret) goto err; @@ -128,6 +129,7 @@ int nfs_cache_register(struct cache_detail *cd) if (!ret) return ret; err: + sunrpc_destroy_cache_detail(cd); rpc_put_mount(); return ret; } @@ -135,6 +137,7 @@ err: void nfs_cache_unregister(struct cache_detail *cd) { sunrpc_cache_unregister_pipefs(cd); + sunrpc_destroy_cache_detail(cd); rpc_put_mount(); } diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 57531f8e595..590a8ab0cec 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -202,6 +202,8 @@ extern int cache_register_net(struct cache_detail *cd, struct net *net); extern void cache_unregister(struct cache_detail *cd); extern void cache_unregister_net(struct cache_detail *cd, struct net *net); +extern void sunrpc_init_cache_detail(struct cache_detail *cd); +extern void sunrpc_destroy_cache_detail(struct cache_detail *cd); extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *, umode_t, struct cache_detail *); extern void sunrpc_cache_unregister_pipefs(struct cache_detail *); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 465df9ae104..fefe06729f9 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -344,7 +344,7 @@ static int current_index; static void do_cache_clean(struct work_struct *work); static struct delayed_work cache_cleaner; -static void sunrpc_init_cache_detail(struct cache_detail *cd) +void sunrpc_init_cache_detail(struct cache_detail *cd) { rwlock_init(&cd->hash_lock); INIT_LIST_HEAD(&cd->queue); @@ -360,8 +360,9 @@ static void sunrpc_init_cache_detail(struct cache_detail *cd) /* start the cleaning process */ schedule_delayed_work(&cache_cleaner, 0); } +EXPORT_SYMBOL_GPL(sunrpc_init_cache_detail); -static void sunrpc_destroy_cache_detail(struct cache_detail *cd) +void sunrpc_destroy_cache_detail(struct cache_detail *cd) { cache_purge(cd); spin_lock(&cache_list_lock); @@ -384,6 +385,7 @@ static void sunrpc_destroy_cache_detail(struct cache_detail *cd) out: printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); } +EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail); /* clean cache tries to find something to clean * and cleans it. @@ -1787,17 +1789,14 @@ int sunrpc_cache_register_pipefs(struct dentry *parent, struct dentry *dir; int ret = 0; - sunrpc_init_cache_detail(cd); q.name = name; q.len = strlen(name); q.hash = full_name_hash(q.name, q.len); dir = rpc_create_cache_dir(parent, &q, umode, cd); if (!IS_ERR(dir)) cd->u.pipefs.dir = dir; - else { - sunrpc_destroy_cache_detail(cd); + else ret = PTR_ERR(dir); - } return ret; } EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs); @@ -1806,7 +1805,6 @@ void sunrpc_cache_unregister_pipefs(struct cache_detail *cd) { rpc_remove_cache_dir(cd->u.pipefs.dir); cd->u.pipefs.dir = NULL; - sunrpc_destroy_cache_detail(cd); } EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs); -- cgit v1.2.3-70-g09d2 From ad6b134008f4e765dd19976552b929273ae523bd Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 10 Jan 2012 16:12:38 +0400 Subject: SUNRPC: fix pipe->ops cleanup on pipe dentry unlink This patch looks late due to GSS AUTH patches sent already. But it fixes a flaw in RPC PipeFS pipes handling. I've added this patch in the series, because this series related to pipes. But it should be a part of previous series named "SUNPRC: cleanup PipeFS for network-namespace-aware users". Pipe dentry can be created and destroyed many times during pipe life cycle. This actually means, that we can't set pipe->ops to NULL in rpc_close_pipes() and use this variable as a flag, indicating, that pipe's dentry is unlinking. To follow this restriction, this patch replaces "pipe->ops = NULL" assignment and checks for NULL with "pipe->dentry = NULL" assignment and checks for NULL respectively. This patch also removes check for non-NULL pipe->ops (or pipe->dentry) in rpc_close_pipes() because it always non-NULL now. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 51 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 910de4169a8..6b417fcabdb 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -86,10 +86,6 @@ rpc_timeout_upcall_queue(struct work_struct *work) void (*destroy_msg)(struct rpc_pipe_msg *); spin_lock(&pipe->lock); - if (pipe->ops == NULL) { - spin_unlock(&pipe->lock); - return; - } destroy_msg = pipe->ops->destroy_msg; if (pipe->nreaders == 0) { list_splice_init(&pipe->pipe, &free_list); @@ -135,8 +131,6 @@ rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) int res = -EPIPE; spin_lock(&pipe->lock); - if (pipe->ops == NULL) - goto out; if (pipe->nreaders) { list_add_tail(&msg->list, &pipe->pipe); pipe->pipelen += msg->len; @@ -150,7 +144,6 @@ rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) pipe->pipelen += msg->len; res = 0; } -out: spin_unlock(&pipe->lock); wake_up(&pipe->waitq); return res; @@ -167,27 +160,23 @@ static void rpc_close_pipes(struct inode *inode) { struct rpc_pipe *pipe = RPC_I(inode)->pipe; - const struct rpc_pipe_ops *ops; int need_release; + LIST_HEAD(free_list); mutex_lock(&inode->i_mutex); - ops = pipe->ops; - if (ops != NULL) { - LIST_HEAD(free_list); - spin_lock(&pipe->lock); - need_release = pipe->nreaders != 0 || pipe->nwriters != 0; - pipe->nreaders = 0; - list_splice_init(&pipe->in_upcall, &free_list); - list_splice_init(&pipe->pipe, &free_list); - pipe->pipelen = 0; - pipe->ops = NULL; - spin_unlock(&pipe->lock); - rpc_purge_list(pipe, &free_list, ops->destroy_msg, -EPIPE); - pipe->nwriters = 0; - if (need_release && ops->release_pipe) - ops->release_pipe(inode); - cancel_delayed_work_sync(&pipe->queue_timeout); - } + spin_lock(&pipe->lock); + need_release = pipe->nreaders != 0 || pipe->nwriters != 0; + pipe->nreaders = 0; + list_splice_init(&pipe->in_upcall, &free_list); + list_splice_init(&pipe->pipe, &free_list); + pipe->pipelen = 0; + pipe->dentry = NULL; + spin_unlock(&pipe->lock); + rpc_purge_list(pipe, &free_list, pipe->ops->destroy_msg, -EPIPE); + pipe->nwriters = 0; + if (need_release && pipe->ops->release_pipe) + pipe->ops->release_pipe(inode); + cancel_delayed_work_sync(&pipe->queue_timeout); rpc_inode_setowner(inode, NULL); mutex_unlock(&inode->i_mutex); } @@ -223,7 +212,7 @@ rpc_pipe_open(struct inode *inode, struct file *filp) int res = -ENXIO; mutex_lock(&inode->i_mutex); - if (pipe->ops == NULL) + if (pipe->dentry == NULL) goto out; first_open = pipe->nreaders == 0 && pipe->nwriters == 0; if (first_open && pipe->ops->open_pipe) { @@ -249,7 +238,7 @@ rpc_pipe_release(struct inode *inode, struct file *filp) int last_close; mutex_lock(&inode->i_mutex); - if (pipe->ops == NULL) + if (pipe->dentry == NULL) goto out; msg = filp->private_data; if (msg != NULL) { @@ -290,7 +279,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) int res = 0; mutex_lock(&inode->i_mutex); - if (pipe->ops == NULL) { + if (pipe->dentry == NULL) { res = -EPIPE; goto out_unlock; } @@ -333,7 +322,7 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of mutex_lock(&inode->i_mutex); res = -EPIPE; - if (pipe->ops != NULL) + if (pipe->dentry != NULL) res = pipe->ops->downcall(filp, buf, len); mutex_unlock(&inode->i_mutex); return res; @@ -348,7 +337,7 @@ rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) poll_wait(filp, &pipe->waitq, wait); mask = POLLOUT | POLLWRNORM; - if (pipe->ops == NULL) + if (pipe->dentry == NULL) mask |= POLLERR | POLLHUP; if (filp->private_data || !list_empty(&pipe->pipe)) mask |= POLLIN | POLLRDNORM; @@ -365,7 +354,7 @@ rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case FIONREAD: spin_lock(&pipe->lock); - if (pipe->ops == NULL) { + if (pipe->dentry == NULL) { spin_unlock(&pipe->lock); return -EPIPE; } -- cgit v1.2.3-70-g09d2 From eee17325f1dfbe004f1475743bab9e3d050d00f5 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 10 Jan 2012 16:13:19 +0400 Subject: NFS: idmap PipeFS notifier introduced v2: 1) Added "nfs_idmap_init" and "nfs_idmap_quit" definitions for kernels built without CONFIG_NFS_V4 option set. This patch subscribes NFS clients to RPC pipefs notifications. Idmap notifier is registering on NFS module load. This notifier callback is responsible for creation/destruction of PipeFS idmap pipe dentry for NFS4 clients. Since ipdmap pipe is created in rpc client pipefs directory, we have make sure, that this directory has been created already. IOW RPC client notifier callback has been called already. To achive this, PipeFS notifier priorities has been introduced (RPC clients notifier priority is greater than NFS idmap one). But this approach gives another problem: unlink for RPC client directory will be called before NFS idmap pipe unlink on UMOUNT event and will fail, because directory is not empty. The solution, introduced in this patch, is to try to remove client directory once again after idmap pipe was unlinked. This looks like ugly hack, so probably it should be replaced in some more elegant way. Note that no locking required in notifier callback because PipeFS superblock pointer is passed as an argument from it's creation or destruction routine and thus we can be sure about it's validity. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 4 +- fs/nfs/idmap.c | 75 ++++++++++++++++++++++++++++++++++++++ fs/nfs/internal.h | 4 ++ include/linux/nfs_idmap.h | 21 ++++++----- include/linux/sunrpc/rpc_pipe_fs.h | 7 ++++ net/sunrpc/clnt.c | 1 + net/sunrpc/rpc_pipe.c | 16 ++++++++ 7 files changed, 116 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 64815b72540..ca9a4aa38df 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -52,8 +52,8 @@ #define NFSDBG_FACILITY NFSDBG_CLIENT -static DEFINE_SPINLOCK(nfs_client_lock); -static LIST_HEAD(nfs_client_list); +DEFINE_SPINLOCK(nfs_client_lock); +LIST_HEAD(nfs_client_list); static LIST_HEAD(nfs_volume_list); static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); #ifdef CONFIG_NFS_V4 diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 769274ed51c..ff084d258c4 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -377,6 +377,7 @@ int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, #include #include "nfs4_fs.h" +#include "internal.h" #define IDMAP_HASH_SZ 128 @@ -530,6 +531,80 @@ nfs_idmap_delete(struct nfs_client *clp) kfree(idmap); } +static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, + struct super_block *sb) +{ + int err = 0; + + switch (event) { + case RPC_PIPEFS_MOUNT: + BUG_ON(clp->cl_rpcclient->cl_dentry == NULL); + err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, + clp->cl_idmap, + clp->cl_idmap->idmap_pipe); + break; + case RPC_PIPEFS_UMOUNT: + if (clp->cl_idmap->idmap_pipe) { + struct dentry *parent; + + parent = clp->cl_idmap->idmap_pipe->dentry->d_parent; + __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe); + /* + * Note: This is a dirty hack. SUNRPC hook has been + * called already but simple_rmdir() call for the + * directory returned with error because of idmap pipe + * inside. Thus now we have to remove this directory + * here. + */ + if (rpc_rmdir(parent)) + printk(KERN_ERR "%s: failed to remove clnt dir!\n", __func__); + } + break; + default: + printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event); + return -ENOTSUPP; + } + return err; +} + +static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct super_block *sb = ptr; + struct nfs_client *clp; + int error = 0; + + spin_lock(&nfs_client_lock); + list_for_each_entry(clp, &nfs_client_list, cl_share_link) { + if (clp->net != sb->s_fs_info) + continue; + if (clp->rpc_ops != &nfs_v4_clientops) + continue; + error = __rpc_pipefs_event(clp, event, sb); + if (error) + break; + } + spin_unlock(&nfs_client_lock); + return error; +} + +#define PIPEFS_NFS_PRIO 1 + +static struct notifier_block nfs_idmap_block = { + .notifier_call = rpc_pipefs_event, + .priority = SUNRPC_PIPEFS_NFS_PRIO, +}; + +int nfs_idmap_init(void) +{ + return rpc_pipefs_notifier_register(&nfs_idmap_block); +} + +void nfs_idmap_quit(void) +{ + rpc_pipefs_notifier_unregister(&nfs_idmap_block); +} + /* * Helper routines for manipulating the hashtable */ diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index d602188f889..2b9836fe443 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -182,6 +182,10 @@ static inline void nfs_fs_proc_exit(void) { } #endif +#ifdef CONFIG_NFS_V4 +extern spinlock_t nfs_client_lock; +extern struct list_head nfs_client_list; +#endif /* nfs4namespace.c */ #ifdef CONFIG_NFS_V4 diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h index 308c1887701..3c9eeb7da64 100644 --- a/include/linux/nfs_idmap.h +++ b/include/linux/nfs_idmap.h @@ -69,31 +69,32 @@ struct nfs_server; struct nfs_fattr; struct nfs4_string; -#ifdef CONFIG_NFS_USE_NEW_IDMAPPER - +#ifdef CONFIG_NFS_V4 int nfs_idmap_init(void); void nfs_idmap_quit(void); - -static inline int nfs_idmap_new(struct nfs_client *clp) +#else +static inline int nfs_idmap_init(void) { return 0; } -static inline void nfs_idmap_delete(struct nfs_client *clp) -{ -} +static inline void nfs_idmap_quit(void) +{} +#endif -#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */ +#ifdef CONFIG_NFS_USE_NEW_IDMAPPER -static inline int nfs_idmap_init(void) +static inline int nfs_idmap_new(struct nfs_client *clp) { return 0; } -static inline void nfs_idmap_quit(void) +static inline void nfs_idmap_delete(struct nfs_client *clp) { } +#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */ + int nfs_idmap_new(struct nfs_client *); void nfs_idmap_delete(struct nfs_client *); diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 0d1f748f76d..ca32ebd14c1 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -49,6 +49,11 @@ RPC_I(struct inode *inode) return container_of(inode, struct rpc_inode, vfs_inode); } +enum { + SUNRPC_PIPEFS_NFS_PRIO, + SUNRPC_PIPEFS_RPC_PRIO, +}; + extern int rpc_pipefs_notifier_register(struct notifier_block *); extern void rpc_pipefs_notifier_unregister(struct notifier_block *); @@ -78,6 +83,8 @@ extern struct dentry *rpc_create_cache_dir(struct dentry *, struct cache_detail *); extern void rpc_remove_cache_dir(struct dentry *); +extern int rpc_rmdir(struct dentry *dentry); + struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags); void rpc_destroy_pipe_data(struct rpc_pipe *pipe); extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *, diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index ed7c22de931..4c684801716 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -222,6 +222,7 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, static struct notifier_block rpc_clients_block = { .notifier_call = rpc_pipefs_event, + .priority = SUNRPC_PIPEFS_RPC_PRIO, }; int rpc_clients_notifier_register(void) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 6b417fcabdb..bae4e71d866 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -616,6 +616,22 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) return ret; } +int rpc_rmdir(struct dentry *dentry) +{ + struct dentry *parent; + struct inode *dir; + int error; + + parent = dget_parent(dentry); + dir = parent->d_inode; + mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); + error = __rpc_rmdir(dir, dentry); + mutex_unlock(&dir->i_mutex); + dput(parent); + return error; +} +EXPORT_SYMBOL_GPL(rpc_rmdir); + static int __rpc_unlink(struct inode *dir, struct dentry *dentry) { int ret; -- cgit v1.2.3-70-g09d2 From 12bc372b96b35a2dc9245ec61369028932b82ea8 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 10 Jan 2012 17:04:48 +0400 Subject: SUNRPC: kernel PipeFS mount point creation routines removed This patch removes static rpc_mnt variable and its creation and destruction routines, because they are not used anymore. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 2 -- net/sunrpc/rpc_pipe.c | 21 --------------------- 2 files changed, 23 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index ca32ebd14c1..426ce6eeee6 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -90,8 +90,6 @@ void rpc_destroy_pipe_data(struct rpc_pipe *pipe); extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *, struct rpc_pipe *); extern int rpc_unlink(struct dentry *); -extern struct vfsmount *rpc_get_mount(void); -extern void rpc_put_mount(void); extern int register_rpc_pipefs(void); extern void unregister_rpc_pipefs(void); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index bae4e71d866..6873c9b51cc 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -37,9 +36,6 @@ #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") -static struct vfsmount *rpc_mnt __read_mostly; -static int rpc_mount_count; - static struct file_system_type rpc_pipe_fs_type; @@ -449,23 +445,6 @@ struct rpc_filelist { umode_t mode; }; -struct vfsmount *rpc_get_mount(void) -{ - int err; - - err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mnt, &rpc_mount_count); - if (err != 0) - return ERR_PTR(err); - return rpc_mnt; -} -EXPORT_SYMBOL_GPL(rpc_get_mount); - -void rpc_put_mount(void) -{ - simple_release_fs(&rpc_mnt, &rpc_mount_count); -} -EXPORT_SYMBOL_GPL(rpc_put_mount); - static int rpc_delete_dentry(const struct dentry *dentry) { return 1; -- cgit v1.2.3-70-g09d2 From 961a828df64979d2a9faeeeee043391670a193b9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Jan 2012 22:57:37 -0500 Subject: SUNRPC: Fix potential races in xprt_lock_write_next() We have to ensure that the wake up from the waitqueue and the assignment of xprt->snd_task are atomic. We can do this by assigning the snd_task while under the waitqueue spinlock. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 13 +++++++----- fs/nfs/nfs4state.c | 17 ++++++++------- include/linux/sunrpc/sched.h | 3 +++ net/sunrpc/sched.c | 42 +++++++++++++++++++++++++++++-------- net/sunrpc/xprt.c | 49 +++++++++++++++++++++++--------------------- 6 files changed, 79 insertions(+), 46 deletions(-) (limited to 'net') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index df3d02c3e8c..c45c21a5470 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -222,6 +222,7 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser return server->nfs_client->cl_session; } +extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy); extern int nfs4_setup_sequence(const struct nfs_server *server, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, struct rpc_task *task); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 360240cc1e9..828a76590af 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -385,17 +385,20 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) free_slotid, tbl->highest_used_slotid); } +bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) +{ + rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); + return true; +} + /* * Signal state manager thread if session fore channel is drained */ static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) { - struct rpc_task *task; - if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { - task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); - if (task) - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); + rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq, + nfs4_set_task_privileged, NULL); return; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a42e60d3ee5..f0e9881c2aa 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -190,23 +190,22 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp) static void nfs4_end_drain_session(struct nfs_client *clp) { struct nfs4_session *ses = clp->cl_session; + struct nfs4_slot_table *tbl; int max_slots; if (ses == NULL) return; + tbl = &ses->fc_slot_table; if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { - spin_lock(&ses->fc_slot_table.slot_tbl_lock); - max_slots = ses->fc_slot_table.max_slots; + spin_lock(&tbl->slot_tbl_lock); + max_slots = tbl->max_slots; while (max_slots--) { - struct rpc_task *task; - - task = rpc_wake_up_next(&ses->fc_slot_table. - slot_tbl_waitq); - if (!task) + if (rpc_wake_up_first(&tbl->slot_tbl_waitq, + nfs4_set_task_privileged, + NULL) == NULL) break; - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); } - spin_unlock(&ses->fc_slot_table.slot_tbl_lock); + spin_unlock(&tbl->slot_tbl_lock); } } diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index b16243a35f0..bd337f990a4 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -235,6 +235,9 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *, struct rpc_task *); void rpc_wake_up(struct rpc_wait_queue *); struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); +struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *, + bool (*)(struct rpc_task *, void *), + void *); void rpc_wake_up_status(struct rpc_wait_queue *, int); int rpc_queue_empty(struct rpc_wait_queue *); void rpc_delay(struct rpc_task *, unsigned long); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 3341d896278..f982dfe5399 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -422,7 +422,7 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); /* * Wake up the next task on a priority queue. */ -static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue) +static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue) { struct list_head *q; struct rpc_task *task; @@ -467,30 +467,54 @@ new_queue: new_owner: rpc_set_waitqueue_owner(queue, task->tk_owner); out: - rpc_wake_up_task_queue_locked(queue, task); return task; } +static struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue) +{ + if (RPC_IS_PRIORITY(queue)) + return __rpc_find_next_queued_priority(queue); + if (!list_empty(&queue->tasks[0])) + return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list); + return NULL; +} + /* - * Wake up the next task on the wait queue. + * Wake up the first task on the wait queue. */ -struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) +struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, + bool (*func)(struct rpc_task *, void *), void *data) { struct rpc_task *task = NULL; - dprintk("RPC: wake_up_next(%p \"%s\")\n", + dprintk("RPC: wake_up_first(%p \"%s\")\n", queue, rpc_qname(queue)); spin_lock_bh(&queue->lock); - if (RPC_IS_PRIORITY(queue)) - task = __rpc_wake_up_next_priority(queue); - else { - task_for_first(task, &queue->tasks[0]) + task = __rpc_find_next_queued(queue); + if (task != NULL) { + if (func(task, data)) rpc_wake_up_task_queue_locked(queue, task); + else + task = NULL; } spin_unlock_bh(&queue->lock); return task; } +EXPORT_SYMBOL_GPL(rpc_wake_up_first); + +static bool rpc_wake_up_next_func(struct rpc_task *task, void *data) +{ + return true; +} + +/* + * Wake up the next task on the wait queue. +*/ +struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue) +{ + return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL); +} EXPORT_SYMBOL_GPL(rpc_wake_up_next); /** diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c64c0ef519b..839f6ef2326 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -292,54 +292,57 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) return retval; } -static void __xprt_lock_write_next(struct rpc_xprt *xprt) +static bool __xprt_lock_write_func(struct rpc_task *task, void *data) { - struct rpc_task *task; + struct rpc_xprt *xprt = data; struct rpc_rqst *req; - if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) - return; - - task = rpc_wake_up_next(&xprt->sending); - if (task == NULL) - goto out_unlock; - req = task->tk_rqstp; xprt->snd_task = task; if (req) { req->rq_bytes_sent = 0; req->rq_ntrans++; } - return; + return true; +} -out_unlock: +static void __xprt_lock_write_next(struct rpc_xprt *xprt) +{ + if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) + return; + + if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_func, xprt)) + return; xprt_clear_locked(xprt); } -static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) +static bool __xprt_lock_write_cong_func(struct rpc_task *task, void *data) { - struct rpc_task *task; + struct rpc_xprt *xprt = data; struct rpc_rqst *req; - if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) - return; - if (RPCXPRT_CONGESTED(xprt)) - goto out_unlock; - task = rpc_wake_up_next(&xprt->sending); - if (task == NULL) - goto out_unlock; - req = task->tk_rqstp; if (req == NULL) { xprt->snd_task = task; - return; + return true; } if (__xprt_get_cong(xprt, task)) { xprt->snd_task = task; req->rq_bytes_sent = 0; req->rq_ntrans++; - return; + return true; } + return false; +} + +static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) +{ + if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) + return; + if (RPCXPRT_CONGESTED(xprt)) + goto out_unlock; + if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_cong_func, xprt)) + return; out_unlock: xprt_clear_locked(xprt); } -- cgit v1.2.3-70-g09d2 From dff02d499c067bdde589b764321b35fe763569f6 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 12:52:10 +0400 Subject: SUNRPC: move rpcbind internals to sunrpc part of network namespace context This patch makes rpcbind logic works in network namespace context. IOW each network namespace will have it's own unique rpcbind internals (clients and friends) required for registering svc services per network namespace. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/netns.h | 5 ++++ net/sunrpc/rpcb_clnt.c | 64 +++++++++++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 0f3af34fa50..1fdeb1ba84b 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -15,6 +15,11 @@ struct sunrpc_net { struct list_head all_clients; spinlock_t rpc_client_lock; + + struct rpc_clnt *rpcb_local_clnt; + struct rpc_clnt *rpcb_local_clnt4; + spinlock_t rpcb_clnt_lock; + unsigned int rpcb_users; }; extern int sunrpc_net_id; diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 8761bf8e36f..7d32f19ba86 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -23,12 +23,15 @@ #include #include #include +#include #include #include #include #include +#include "netns.h" + #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_BIND #endif @@ -111,12 +114,6 @@ static void rpcb_getport_done(struct rpc_task *, void *); static void rpcb_map_release(void *data); static struct rpc_program rpcb_program; -static struct rpc_clnt * rpcb_local_clnt; -static struct rpc_clnt * rpcb_local_clnt4; - -DEFINE_SPINLOCK(rpcb_clnt_lock); -unsigned int rpcb_users; - struct rpcbind_args { struct rpc_xprt * r_xprt; @@ -167,29 +164,31 @@ static void rpcb_map_release(void *data) static int rpcb_get_local(void) { int cnt; + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); - spin_lock(&rpcb_clnt_lock); - if (rpcb_users) - rpcb_users++; - cnt = rpcb_users; - spin_unlock(&rpcb_clnt_lock); + spin_lock(&sn->rpcb_clnt_lock); + if (sn->rpcb_users) + sn->rpcb_users++; + cnt = sn->rpcb_users; + spin_unlock(&sn->rpcb_clnt_lock); return cnt; } void rpcb_put_local(void) { - struct rpc_clnt *clnt = rpcb_local_clnt; - struct rpc_clnt *clnt4 = rpcb_local_clnt4; + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); + struct rpc_clnt *clnt = sn->rpcb_local_clnt; + struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; int shutdown; - spin_lock(&rpcb_clnt_lock); - if (--rpcb_users == 0) { - rpcb_local_clnt = NULL; - rpcb_local_clnt4 = NULL; + spin_lock(&sn->rpcb_clnt_lock); + if (--sn->rpcb_users == 0) { + sn->rpcb_local_clnt = NULL; + sn->rpcb_local_clnt4 = NULL; } - shutdown = !rpcb_users; - spin_unlock(&rpcb_clnt_lock); + shutdown = !sn->rpcb_users; + spin_unlock(&sn->rpcb_clnt_lock); if (shutdown) { /* @@ -204,14 +203,16 @@ void rpcb_put_local(void) static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4) { + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); + /* Protected by rpcb_create_local_mutex */ - rpcb_local_clnt = clnt; - rpcb_local_clnt4 = clnt4; + sn->rpcb_local_clnt = clnt; + sn->rpcb_local_clnt4 = clnt4; smp_wmb(); - rpcb_users = 1; + sn->rpcb_users = 1; dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " - "%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt, - rpcb_local_clnt4); + "%p, rpcb_local_clnt4: %p)\n", sn->rpcb_local_clnt, + sn->rpcb_local_clnt4); } /* @@ -431,6 +432,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) struct rpc_message msg = { .rpc_argp = &map, }; + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " "rpcbind\n", (port ? "" : "un"), @@ -440,7 +442,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) if (port) msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; - return rpcb_register_call(rpcb_local_clnt, &msg); + return rpcb_register_call(sn->rpcb_local_clnt, &msg); } /* @@ -453,6 +455,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap, struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin->sin_port); int result; + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); @@ -465,7 +468,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - result = rpcb_register_call(rpcb_local_clnt4, msg); + result = rpcb_register_call(sn->rpcb_local_clnt4, msg); kfree(map->r_addr); return result; } @@ -480,6 +483,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap, struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin6->sin6_port); int result; + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); @@ -492,7 +496,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - result = rpcb_register_call(rpcb_local_clnt4, msg); + result = rpcb_register_call(sn->rpcb_local_clnt4, msg); kfree(map->r_addr); return result; } @@ -500,6 +504,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap, static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) { struct rpcbind_args *map = msg->rpc_argp; + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); dprintk("RPC: unregistering [%u, %u, '%s'] with " "local rpcbind\n", @@ -508,7 +513,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) map->r_addr = ""; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - return rpcb_register_call(rpcb_local_clnt4, msg); + return rpcb_register_call(sn->rpcb_local_clnt4, msg); } /** @@ -566,8 +571,9 @@ int rpcb_v4_register(const u32 program, const u32 version, struct rpc_message msg = { .rpc_argp = &map, }; + struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); - if (rpcb_local_clnt4 == NULL) + if (sn->rpcb_local_clnt4 == NULL) return -EPROTONOSUPPORT; if (address == NULL) -- cgit v1.2.3-70-g09d2 From 2ea75a10add779b722650aa10836247e7d609fd7 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 12:52:18 +0400 Subject: SUNRPC: optimize net_ns dereferencing in rpcbind creation calls Static rpcbind creation functions can be parametrized by network namespace pointer, calculated only once, instead of using init_net pointer (or taking it from current when virtualization will be comleted) in many places. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpcb_clnt.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 7d32f19ba86..3df276a74d1 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -161,10 +161,10 @@ static void rpcb_map_release(void *data) kfree(map); } -static int rpcb_get_local(void) +static int rpcb_get_local(struct net *net) { int cnt; - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); spin_lock(&sn->rpcb_clnt_lock); if (sn->rpcb_users) @@ -201,9 +201,10 @@ void rpcb_put_local(void) } } -static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4) +static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, + struct rpc_clnt *clnt4) { - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); /* Protected by rpcb_create_local_mutex */ sn->rpcb_local_clnt = clnt; @@ -211,22 +212,23 @@ static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4) smp_wmb(); sn->rpcb_users = 1; dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " - "%p, rpcb_local_clnt4: %p)\n", sn->rpcb_local_clnt, - sn->rpcb_local_clnt4); + "%p, rpcb_local_clnt4: %p) for net %p%s\n", + sn->rpcb_local_clnt, sn->rpcb_local_clnt4, + net, (net == &init_net) ? " (init_net)" : ""); } /* * Returns zero on success, otherwise a negative errno value * is returned. */ -static int rpcb_create_local_unix(void) +static int rpcb_create_local_unix(struct net *net) { static const struct sockaddr_un rpcb_localaddr_rpcbind = { .sun_family = AF_LOCAL, .sun_path = RPCBIND_SOCK_PATHNAME, }; struct rpc_create_args args = { - .net = &init_net, + .net = net, .protocol = XPRT_TRANSPORT_LOCAL, .address = (struct sockaddr *)&rpcb_localaddr_rpcbind, .addrsize = sizeof(rpcb_localaddr_rpcbind), @@ -259,7 +261,7 @@ static int rpcb_create_local_unix(void) clnt4 = NULL; } - rpcb_set_local(clnt, clnt4); + rpcb_set_local(net, clnt, clnt4); out: return result; @@ -269,7 +271,7 @@ out: * Returns zero on success, otherwise a negative errno value * is returned. */ -static int rpcb_create_local_net(void) +static int rpcb_create_local_net(struct net *net) { static const struct sockaddr_in rpcb_inaddr_loopback = { .sin_family = AF_INET, @@ -277,7 +279,7 @@ static int rpcb_create_local_net(void) .sin_port = htons(RPCBIND_PORT), }; struct rpc_create_args args = { - .net = &init_net, + .net = net, .protocol = XPRT_TRANSPORT_TCP, .address = (struct sockaddr *)&rpcb_inaddr_loopback, .addrsize = sizeof(rpcb_inaddr_loopback), @@ -311,7 +313,7 @@ static int rpcb_create_local_net(void) clnt4 = NULL; } - rpcb_set_local(clnt, clnt4); + rpcb_set_local(net, clnt, clnt4); out: return result; @@ -325,16 +327,17 @@ int rpcb_create_local(void) { static DEFINE_MUTEX(rpcb_create_local_mutex); int result = 0; + struct net *net = &init_net; - if (rpcb_get_local()) + if (rpcb_get_local(net)) return result; mutex_lock(&rpcb_create_local_mutex); - if (rpcb_get_local()) + if (rpcb_get_local(net)) goto out; - if (rpcb_create_local_unix() != 0) - result = rpcb_create_local_net(); + if (rpcb_create_local_unix(net) != 0) + result = rpcb_create_local_net(net); out: mutex_unlock(&rpcb_create_local_mutex); -- cgit v1.2.3-70-g09d2 From 1a114a66466ba914a41df438e806fc10e7d9fb3b Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 12:52:26 +0400 Subject: SUNRPC: optimize net_ns dereferencing in rpcbind registering calls Static rpcbind registering functions can be parametrized by network namespace pointer, calculated only once, instead of using init_net pointer (or taking it from current when virtualization will be comleted) in many places. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpcb_clnt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 3df276a74d1..371d2298c9f 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -451,14 +451,14 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) /* * Fill in AF_INET family-specific arguments to register */ -static int rpcb_register_inet4(const struct sockaddr *sap, +static int rpcb_register_inet4(struct sunrpc_net *sn, + const struct sockaddr *sap, struct rpc_message *msg) { const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin->sin_port); int result; - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); @@ -479,14 +479,14 @@ static int rpcb_register_inet4(const struct sockaddr *sap, /* * Fill in AF_INET6 family-specific arguments to register */ -static int rpcb_register_inet6(const struct sockaddr *sap, +static int rpcb_register_inet6(struct sunrpc_net *sn, + const struct sockaddr *sap, struct rpc_message *msg) { const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin6->sin6_port); int result; - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); @@ -504,10 +504,10 @@ static int rpcb_register_inet6(const struct sockaddr *sap, return result; } -static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) +static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, + struct rpc_message *msg) { struct rpcbind_args *map = msg->rpc_argp; - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); dprintk("RPC: unregistering [%u, %u, '%s'] with " "local rpcbind\n", @@ -580,13 +580,13 @@ int rpcb_v4_register(const u32 program, const u32 version, return -EPROTONOSUPPORT; if (address == NULL) - return rpcb_unregister_all_protofamilies(&msg); + return rpcb_unregister_all_protofamilies(sn, &msg); switch (address->sa_family) { case AF_INET: - return rpcb_register_inet4(address, &msg); + return rpcb_register_inet4(sn, address, &msg); case AF_INET6: - return rpcb_register_inet6(address, &msg); + return rpcb_register_inet6(sn, address, &msg); } return -EAFNOSUPPORT; -- cgit v1.2.3-70-g09d2 From c2550e07a61a4528673fb85aaaee16048b7cf6cc Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 12:52:35 +0400 Subject: SUNRPC: create rpcbind client in passed network namespace context Rpcbind clients are per network namespace. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpcb_clnt.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 371d2298c9f..0d76c0f09bb 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -344,11 +344,12 @@ out: return result; } -static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, - size_t salen, int proto, u32 version) +static struct rpc_clnt *rpcb_create(struct net *net, char *hostname, + struct sockaddr *srvaddr, size_t salen, + int proto, u32 version) { struct rpc_create_args args = { - .net = &init_net, + .net = net, .protocol = proto, .address = srvaddr, .addrsize = salen, @@ -708,8 +709,8 @@ void rpcb_getport_async(struct rpc_task *task) dprintk("RPC: %5u %s: trying rpcbind version %u\n", task->tk_pid, __func__, bind_version); - rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, - bind_version); + rpcb_clnt = rpcb_create(xprt->xprt_net, clnt->cl_server, sap, salen, + xprt->prot, bind_version); if (IS_ERR(rpcb_clnt)) { status = PTR_ERR(rpcb_clnt); dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", -- cgit v1.2.3-70-g09d2 From 977ac3157328239a0f4074b13a3d9eb5c832cd6c Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 12:52:43 +0400 Subject: SUNRPC: register rpcbind programs in passed network namespase context Registering rpcbind program requires rpcbind clients, which are per network namespace context. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/clnt.h | 5 +++-- net/sunrpc/rpcb_clnt.c | 8 ++++---- net/sunrpc/svc.c | 10 +++++----- 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index bfd61852b71..b0b3e572a61 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -138,8 +138,9 @@ void rpc_task_release_client(struct rpc_task *); int rpcb_create_local(void); void rpcb_put_local(void); -int rpcb_register(u32, u32, int, unsigned short); -int rpcb_v4_register(const u32 program, const u32 version, +int rpcb_register(struct net *, u32, u32, int, unsigned short); +int rpcb_v4_register(struct net *net, const u32 program, + const u32 version, const struct sockaddr *address, const char *netid); void rpcb_getport_async(struct rpc_task *); diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 0d76c0f09bb..a5aa50d0aae 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -425,7 +425,7 @@ static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 * addresses). */ -int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) +int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port) { struct rpcbind_args map = { .r_prog = prog, @@ -436,7 +436,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) struct rpc_message msg = { .rpc_argp = &map, }; - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " "rpcbind\n", (port ? "" : "un"), @@ -563,7 +563,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, * service on any IPv4 address, but not on IPv6. The latter * advertises the service on all IPv4 and IPv6 addresses. */ -int rpcb_v4_register(const u32 program, const u32 version, +int rpcb_v4_register(struct net *net, const u32 program, const u32 version, const struct sockaddr *address, const char *netid) { struct rpcbind_args map = { @@ -575,7 +575,7 @@ int rpcb_v4_register(const u32 program, const u32 version, struct rpc_message msg = { .rpc_argp = &map, }; - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); if (sn->rpcb_local_clnt4 == NULL) return -EPROTONOSUPPORT; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index e4aabc02368..889d7b11b9a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -818,7 +818,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, return -ENOPROTOOPT; } - error = rpcb_v4_register(program, version, + error = rpcb_v4_register(&init_net, program, version, (const struct sockaddr *)&sin, netid); /* @@ -826,7 +826,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, * registration request with the legacy rpcbind v2 protocol. */ if (error == -EPROTONOSUPPORT) - error = rpcb_register(program, version, protocol, port); + error = rpcb_register(&init_net, program, version, protocol, port); return error; } @@ -865,7 +865,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, return -ENOPROTOOPT; } - error = rpcb_v4_register(program, version, + error = rpcb_v4_register(&init_net, program, version, (const struct sockaddr *)&sin6, netid); /* @@ -968,14 +968,14 @@ static void __svc_unregister(const u32 program, const u32 version, { int error; - error = rpcb_v4_register(program, version, NULL, ""); + error = rpcb_v4_register(&init_net, program, version, NULL, ""); /* * User space didn't support rpcbind v4, so retry this * request with the legacy rpcbind v2 protocol. */ if (error == -EPROTONOSUPPORT) - error = rpcb_register(program, version, 0, 0); + error = rpcb_register(&init_net, program, version, 0, 0); dprintk("svc: %s(%sv%u), error %d\n", __func__, progname, version, error); -- cgit v1.2.3-70-g09d2 From f7a30c18e8d673c996095420a026a28433cb4096 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 12:52:51 +0400 Subject: SUNRPC: parametrize local rpcbind clients creation with net ns These client are per network namespace and thus can be created for different network namespaces. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/clnt.h | 4 ++-- net/sunrpc/rpcb_clnt.c | 7 +++---- net/sunrpc/svc.c | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index b0b3e572a61..e891a8a18cb 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -136,8 +136,8 @@ void rpc_shutdown_client(struct rpc_clnt *); void rpc_release_client(struct rpc_clnt *); void rpc_task_release_client(struct rpc_task *); -int rpcb_create_local(void); -void rpcb_put_local(void); +int rpcb_create_local(struct net *); +void rpcb_put_local(struct net *); int rpcb_register(struct net *, u32, u32, int, unsigned short); int rpcb_v4_register(struct net *net, const u32 program, const u32 version, diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index a5aa50d0aae..6d6a84f6744 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -175,9 +175,9 @@ static int rpcb_get_local(struct net *net) return cnt; } -void rpcb_put_local(void) +void rpcb_put_local(struct net *net) { - struct sunrpc_net *sn = net_generic(&init_net, sunrpc_net_id); + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct rpc_clnt *clnt = sn->rpcb_local_clnt; struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; int shutdown; @@ -323,11 +323,10 @@ out: * Returns zero on success, otherwise a negative errno value * is returned. */ -int rpcb_create_local(void) +int rpcb_create_local(struct net *net) { static DEFINE_MUTEX(rpcb_create_local_mutex); int result = 0; - struct net *net = &init_net; if (rpcb_get_local(net)) return result; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 889d7b11b9a..0aee925fbd7 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -372,7 +372,7 @@ static int svc_rpcb_setup(struct svc_serv *serv) { int err; - err = rpcb_create_local(); + err = rpcb_create_local(&init_net); if (err) return err; @@ -384,7 +384,7 @@ static int svc_rpcb_setup(struct svc_serv *serv) void svc_rpcb_cleanup(struct svc_serv *serv) { svc_unregister(serv); - rpcb_put_local(); + rpcb_put_local(&init_net); } EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); -- cgit v1.2.3-70-g09d2 From 3065f1e29aa2716c8903cfeff368df4b5314040a Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 13:09:03 +0400 Subject: SUNRPC: parametrize rpc_parse_scope_id() by network context Parametrize rpc_parse_scope_id() by network context and thus force it's caller to pass in network context instead of using hard-coded "init_net". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/addr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index ee77742e0ed..cc83de1c222 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c @@ -156,8 +156,9 @@ static size_t rpc_pton4(const char *buf, const size_t buflen, } #if IS_ENABLED(CONFIG_IPV6) -static int rpc_parse_scope_id(const char *buf, const size_t buflen, - const char *delim, struct sockaddr_in6 *sin6) +static int rpc_parse_scope_id(struct net *net, const char *buf, + const size_t buflen, const char *delim, + struct sockaddr_in6 *sin6) { char *p; size_t len; @@ -177,7 +178,7 @@ static int rpc_parse_scope_id(const char *buf, const size_t buflen, unsigned long scope_id = 0; struct net_device *dev; - dev = dev_get_by_name(&init_net, p); + dev = dev_get_by_name(net, p); if (dev != NULL) { scope_id = dev->ifindex; dev_put(dev); @@ -213,7 +214,7 @@ static size_t rpc_pton6(const char *buf, const size_t buflen, if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0) return 0; - if (!rpc_parse_scope_id(buf, buflen, delim, sin6)) + if (!rpc_parse_scope_id(&init_net, buf, buflen, delim, sin6)) return 0; sin6->sin6_family = AF_INET6; -- cgit v1.2.3-70-g09d2 From 8b147f74738d9ab7e76085e5535e0fe8dc8b29f4 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 13:09:11 +0400 Subject: SUNRPC: parametrize rpc_pton6() by network context Parametrize rpc_pton6() by network context and thus force it's caller to pass in network context instead of using hard-coded "init_net". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/addr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index cc83de1c222..18c40a2002f 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c @@ -198,7 +198,7 @@ static int rpc_parse_scope_id(struct net *net, const char *buf, return 0; } -static size_t rpc_pton6(const char *buf, const size_t buflen, +static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, struct sockaddr *sap, const size_t salen) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; @@ -214,14 +214,14 @@ static size_t rpc_pton6(const char *buf, const size_t buflen, if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0) return 0; - if (!rpc_parse_scope_id(&init_net, buf, buflen, delim, sin6)) + if (!rpc_parse_scope_id(net, buf, buflen, delim, sin6)) return 0; sin6->sin6_family = AF_INET6; return sizeof(struct sockaddr_in6); } #else -static size_t rpc_pton6(const char *buf, const size_t buflen, +static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, struct sockaddr *sap, const size_t salen) { return 0; @@ -249,7 +249,7 @@ size_t rpc_pton(const char *buf, const size_t buflen, for (i = 0; i < buflen; i++) if (buf[i] == ':') - return rpc_pton6(buf, buflen, sap, salen); + return rpc_pton6(&init_net, buf, buflen, sap, salen); return rpc_pton4(buf, buflen, sap, salen); } EXPORT_SYMBOL_GPL(rpc_pton); -- cgit v1.2.3-70-g09d2 From 90100b1766c914c820baa78b5be6845fae1159b8 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 13:09:19 +0400 Subject: SUNRPC: parametrize rpc_pton() by network context Parametrize rpc_pton() by network context and thus force it's callers to pass in network context instead of using hard-coded "init_net". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/dns_resolve.c | 4 ++-- fs/nfs/nfs4filelayoutdev.c | 2 +- fs/nfs/nfs4namespace.c | 2 +- fs/nfs/super.c | 4 ++-- fs/nfsd/nfsctl.c | 2 +- include/linux/sunrpc/clnt.h | 2 +- net/sunrpc/addr.c | 7 ++++--- net/sunrpc/svcauth_unix.c | 2 +- 8 files changed, 13 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 200eb67c95d..7edc62a8a64 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c @@ -20,7 +20,7 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen, ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); if (ip_len > 0) - ret = rpc_pton(ip_addr, ip_len, sa, salen); + ret = rpc_pton(&init_net, ip_addr, ip_len, sa, salen); else ret = -ESRCH; kfree(ip_addr); @@ -224,7 +224,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) len = qword_get(&buf, buf1, sizeof(buf1)); if (len <= 0) goto out; - key.addrlen = rpc_pton(buf1, len, + key.addrlen = rpc_pton(&init_net, buf1, len, (struct sockaddr *)&key.addr, sizeof(key.addr)); diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 8ae91908f5a..0d8b9523a3c 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -457,7 +457,7 @@ decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags) INIT_LIST_HEAD(&da->da_node); - if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr, + if (!rpc_pton(&init_net, buf, portstr-buf, (struct sockaddr *)&da->da_addr, sizeof(da->da_addr))) { dprintk("%s: error parsing address %s\n", __func__, buf); goto out_free_da; diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 919a3693592..48a9acdbaeb 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -98,7 +98,7 @@ static size_t nfs_parse_server_name(char *string, size_t len, { ssize_t ret; - ret = rpc_pton(string, len, sa, salen); + ret = rpc_pton(&init_net, string, len, sa, salen); if (ret == 0) { ret = nfs_dns_resolve_name(server->client->cl_xprt->xprt_net, string, len, sa, salen); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e45feb0fee5..b79f2a11c29 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1408,7 +1408,7 @@ static int nfs_parse_mount_options(char *raw, if (string == NULL) goto out_nomem; mnt->nfs_server.addrlen = - rpc_pton(string, strlen(string), + rpc_pton(&init_net, string, strlen(string), (struct sockaddr *) &mnt->nfs_server.address, sizeof(mnt->nfs_server.address)); @@ -1430,7 +1430,7 @@ static int nfs_parse_mount_options(char *raw, if (string == NULL) goto out_nomem; mnt->mount_server.addrlen = - rpc_pton(string, strlen(string), + rpc_pton(&init_net, string, strlen(string), (struct sockaddr *) &mnt->mount_server.address, sizeof(mnt->mount_server.address)); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 748eda93ce5..330352d379b 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -223,7 +223,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) if (qword_get(&buf, fo_path, size) < 0) return -EINVAL; - if (rpc_pton(fo_path, size, sap, salen) == 0) + if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0) return -EINVAL; return nlmsvc_unlock_all_by_ip(sap); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index e891a8a18cb..7bd114fc84e 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -163,7 +163,7 @@ size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); size_t rpc_ntop(const struct sockaddr *, char *, const size_t); -size_t rpc_pton(const char *, const size_t, +size_t rpc_pton(struct net *, const char *, const size_t, struct sockaddr *, const size_t); char * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t); size_t rpc_uaddr2sockaddr(const char *, const size_t, diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index 18c40a2002f..82b06b73c1e 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c @@ -230,6 +230,7 @@ static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, /** * rpc_pton - Construct a sockaddr in @sap + * @net: applicable network namespace * @buf: C string containing presentation format IP address * @buflen: length of presentation address in bytes * @sap: buffer into which to plant socket address @@ -242,14 +243,14 @@ static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, * socket address, if successful. Returns zero if an error * occurred. */ -size_t rpc_pton(const char *buf, const size_t buflen, +size_t rpc_pton(struct net *net, const char *buf, const size_t buflen, struct sockaddr *sap, const size_t salen) { unsigned int i; for (i = 0; i < buflen; i++) if (buf[i] == ':') - return rpc_pton6(&init_net, buf, buflen, sap, salen); + return rpc_pton6(net, buf, buflen, sap, salen); return rpc_pton4(buf, buflen, sap, salen); } EXPORT_SYMBOL_GPL(rpc_pton); @@ -340,7 +341,7 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, port = (unsigned short)((porthi << 8) | portlo); *c = '\0'; - if (rpc_pton(buf, strlen(buf), sap, salen) == 0) + if (rpc_pton(&init_net, buf, strlen(buf), sap, salen) == 0) return 0; switch (sap->sa_family) { diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 01153ead1db..2f8c426c138 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -211,7 +211,7 @@ static int ip_map_parse(struct cache_detail *cd, len = qword_get(&mesg, buf, mlen); if (len <= 0) return -EINVAL; - if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0) + if (rpc_pton(&init_net, buf, len, &address.sa, sizeof(address)) == 0) return -EINVAL; switch (address.sa.sa_family) { case AF_INET: -- cgit v1.2.3-70-g09d2 From f2ac4dc911fdbc9b98a6a48b40efc45aa9161775 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 13:09:27 +0400 Subject: SUNRPC: parametrize rpc_uaddr2sockaddr() by network context Parametrize rpc_uaddr2sockaddr() by network context and thus force it's callers to pass in network context instead of using hard-coded "init_net". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfsd/nfs4state.c | 2 +- include/linux/sunrpc/clnt.h | 2 +- net/sunrpc/addr.c | 8 +++++--- net/sunrpc/rpcb_clnt.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e8c98f00967..c5cddd65942 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1308,7 +1308,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r else goto out_err; - conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, + conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val, se->se_callback_addr_len, (struct sockaddr *)&conn->cb_addr, sizeof(conn->cb_addr)); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 7bd114fc84e..9e754e3458f 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -166,7 +166,7 @@ size_t rpc_ntop(const struct sockaddr *, char *, const size_t); size_t rpc_pton(struct net *, const char *, const size_t, struct sockaddr *, const size_t); char * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t); -size_t rpc_uaddr2sockaddr(const char *, const size_t, +size_t rpc_uaddr2sockaddr(struct net *, const char *, const size_t, struct sockaddr *, const size_t); static inline unsigned short rpc_get_port(const struct sockaddr *sap) diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index 82b06b73c1e..d11418f97f1 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c @@ -297,6 +297,7 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) /** * rpc_uaddr2sockaddr - convert a universal address to a socket address. + * @net: applicable network namespace * @uaddr: C string containing universal address to convert * @uaddr_len: length of universal address string * @sap: buffer into which to plant socket address @@ -308,8 +309,9 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) * Returns the size of the socket address if successful; otherwise * zero is returned. */ -size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, - struct sockaddr *sap, const size_t salen) +size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr, + const size_t uaddr_len, struct sockaddr *sap, + const size_t salen) { char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; unsigned long portlo, porthi; @@ -341,7 +343,7 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, port = (unsigned short)((porthi << 8) | portlo); *c = '\0'; - if (rpc_pton(&init_net, buf, strlen(buf), sap, salen) == 0) + if (rpc_pton(net, buf, strlen(buf), sap, salen) == 0) return 0; switch (sap->sa_family) { diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 6d6a84f6744..7c6fac00444 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -934,7 +934,7 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid, task->tk_msg.rpc_proc->p_name, (char *)p); - if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0) + if (rpc_uaddr2sockaddr(&init_net, (char *)p, len, sap, sizeof(address)) == 0) goto out_fail; rpcb->r_port = rpc_get_port(sap); -- cgit v1.2.3-70-g09d2 From b030fb0bb113316cc6f56779388b8572ab0699da Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 14:02:40 +0400 Subject: SUNRPC: use proper network namespace in rpcbind RPCBPROC_GETADDR procedure Pass request socket network namespace to rpc_uaddr2sockaddr() instead of hardcoded "init_net", when decoding address in RPCBPROC_GETADDR procedure. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpcb_clnt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 7c6fac00444..4ce3a8e0295 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -934,7 +934,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid, task->tk_msg.rpc_proc->p_name, (char *)p); - if (rpc_uaddr2sockaddr(&init_net, (char *)p, len, sap, sizeof(address)) == 0) + if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len, + sap, sizeof(address)) == 0) goto out_fail; rpcb->r_port = rpc_get_port(sap); -- cgit v1.2.3-70-g09d2 From 5247fab5c82779174d50590e0200bf532248a8a1 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 14:02:48 +0400 Subject: SUNRPC: pass network namespace to service registering routines Lockd and NFSd services will handle requests from and to many network nsamespaces. And thus have to be registered and unregistered per network namespace. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/svc.h | 2 +- net/sunrpc/svc.c | 42 +++++++++++++++++++++++------------------- net/sunrpc/svcsock.c | 3 ++- 3 files changed, 26 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 35b37b1e929..d3563c2a580 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -428,7 +428,7 @@ void svc_destroy(struct svc_serv *); int svc_process(struct svc_rqst *); int bc_svc_process(struct svc_serv *, struct rpc_rqst *, struct svc_rqst *); -int svc_register(const struct svc_serv *, const int, +int svc_register(const struct svc_serv *, struct net *, const int, const unsigned short, const unsigned short); void svc_wake_up(struct svc_serv *); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 0aee925fbd7..a2d3330b70d 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -30,7 +30,7 @@ #define RPCDBG_FACILITY RPCDBG_SVCDSP -static void svc_unregister(const struct svc_serv *serv); +static void svc_unregister(const struct svc_serv *serv, struct net *net); #define svc_serv_is_pooled(serv) ((serv)->sv_function) @@ -377,13 +377,13 @@ static int svc_rpcb_setup(struct svc_serv *serv) return err; /* Remove any stale portmap registrations */ - svc_unregister(serv); + svc_unregister(serv, &init_net); return 0; } void svc_rpcb_cleanup(struct svc_serv *serv) { - svc_unregister(serv); + svc_unregister(serv, &init_net); rpcb_put_local(&init_net); } EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); @@ -795,7 +795,8 @@ EXPORT_SYMBOL_GPL(svc_exit_thread); * Returns zero on success; a negative errno value is returned * if any error occurs. */ -static int __svc_rpcb_register4(const u32 program, const u32 version, +static int __svc_rpcb_register4(struct net *net, const u32 program, + const u32 version, const unsigned short protocol, const unsigned short port) { @@ -818,7 +819,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, return -ENOPROTOOPT; } - error = rpcb_v4_register(&init_net, program, version, + error = rpcb_v4_register(net, program, version, (const struct sockaddr *)&sin, netid); /* @@ -826,7 +827,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, * registration request with the legacy rpcbind v2 protocol. */ if (error == -EPROTONOSUPPORT) - error = rpcb_register(&init_net, program, version, protocol, port); + error = rpcb_register(net, program, version, protocol, port); return error; } @@ -842,7 +843,8 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, * Returns zero on success; a negative errno value is returned * if any error occurs. */ -static int __svc_rpcb_register6(const u32 program, const u32 version, +static int __svc_rpcb_register6(struct net *net, const u32 program, + const u32 version, const unsigned short protocol, const unsigned short port) { @@ -865,7 +867,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, return -ENOPROTOOPT; } - error = rpcb_v4_register(&init_net, program, version, + error = rpcb_v4_register(net, program, version, (const struct sockaddr *)&sin6, netid); /* @@ -885,7 +887,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, * Returns zero on success; a negative errno value is returned * if any error occurs. */ -static int __svc_register(const char *progname, +static int __svc_register(struct net *net, const char *progname, const u32 program, const u32 version, const int family, const unsigned short protocol, @@ -895,12 +897,12 @@ static int __svc_register(const char *progname, switch (family) { case PF_INET: - error = __svc_rpcb_register4(program, version, + error = __svc_rpcb_register4(net, program, version, protocol, port); break; #if IS_ENABLED(CONFIG_IPV6) case PF_INET6: - error = __svc_rpcb_register6(program, version, + error = __svc_rpcb_register6(net, program, version, protocol, port); #endif } @@ -914,14 +916,16 @@ static int __svc_register(const char *progname, /** * svc_register - register an RPC service with the local portmapper * @serv: svc_serv struct for the service to register + * @net: net namespace for the service to register * @family: protocol family of service's listener socket * @proto: transport protocol number to advertise * @port: port to advertise * * Service is registered for any address in the passed-in protocol family */ -int svc_register(const struct svc_serv *serv, const int family, - const unsigned short proto, const unsigned short port) +int svc_register(const struct svc_serv *serv, struct net *net, + const int family, const unsigned short proto, + const unsigned short port) { struct svc_program *progp; unsigned int i; @@ -946,7 +950,7 @@ int svc_register(const struct svc_serv *serv, const int family, if (progp->pg_vers[i]->vs_hidden) continue; - error = __svc_register(progp->pg_name, progp->pg_prog, + error = __svc_register(net, progp->pg_name, progp->pg_prog, i, family, proto, port); if (error < 0) break; @@ -963,19 +967,19 @@ int svc_register(const struct svc_serv *serv, const int family, * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient * in this case to clear all existing entries for [program, version]. */ -static void __svc_unregister(const u32 program, const u32 version, +static void __svc_unregister(struct net *net, const u32 program, const u32 version, const char *progname) { int error; - error = rpcb_v4_register(&init_net, program, version, NULL, ""); + error = rpcb_v4_register(net, program, version, NULL, ""); /* * User space didn't support rpcbind v4, so retry this * request with the legacy rpcbind v2 protocol. */ if (error == -EPROTONOSUPPORT) - error = rpcb_register(&init_net, program, version, 0, 0); + error = rpcb_register(net, program, version, 0, 0); dprintk("svc: %s(%sv%u), error %d\n", __func__, progname, version, error); @@ -989,7 +993,7 @@ static void __svc_unregister(const u32 program, const u32 version, * The result of unregistration is reported via dprintk for those who want * verification of the result, but is otherwise not important. */ -static void svc_unregister(const struct svc_serv *serv) +static void svc_unregister(const struct svc_serv *serv, struct net *net) { struct svc_program *progp; unsigned long flags; @@ -1006,7 +1010,7 @@ static void svc_unregister(const struct svc_serv *serv) dprintk("svc: attempting to unregister %sv%u\n", progp->pg_name, i); - __svc_unregister(progp->pg_prog, i, progp->pg_name); + __svc_unregister(net, progp->pg_prog, i, progp->pg_name); } } diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 464570906f8..e8af0c9e436 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1409,7 +1409,8 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, /* Register socket with portmapper */ if (*errp >= 0 && pmap_register) - *errp = svc_register(serv, inet->sk_family, inet->sk_protocol, + *errp = svc_register(serv, sock->sk->sk_net, inet->sk_family, + inet->sk_protocol, ntohs(inet_sk(inet)->inet_sport)); if (*errp < 0) { -- cgit v1.2.3-70-g09d2 From bee42f688c915b510a4aabae4f7a99457137d6f3 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 14:02:56 +0400 Subject: SUNRPC: register service on creation in current network namespace Service, using rpcbind (Lockd, NFSd) are starting from userspace call and thus we can use current network namespace. There could be a problem with NFSd service, because it's creation can be called through NFSd fs from different network namespace. But this is a part of "NFSd per net ns" task and will be fixed in future. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/svc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index a2d3330b70d..cb2caaee2af 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -368,16 +369,16 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu) return &serv->sv_pools[pidx % serv->sv_nrpools]; } -static int svc_rpcb_setup(struct svc_serv *serv) +static int svc_rpcb_setup(struct svc_serv *serv, struct net *net) { int err; - err = rpcb_create_local(&init_net); + err = rpcb_create_local(net); if (err) return err; /* Remove any stale portmap registrations */ - svc_unregister(serv, &init_net); + svc_unregister(serv, net); return 0; } @@ -470,7 +471,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, } if (svc_uses_rpcbind(serv)) { - if (svc_rpcb_setup(serv) < 0) { + if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) { kfree(serv->sv_pools); kfree(serv); return NULL; -- cgit v1.2.3-70-g09d2 From 5ecebb7c7fd737cf387a552994df319c063973db Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 13 Jan 2012 14:03:04 +0400 Subject: SUNRPC: unregister service on creation in current network namespace On service shutdown we can be sure, that no more users of it left except current. Thus it looks like using current network namespace context is safe in this case. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfsd/nfssvc.c | 4 ++-- include/linux/sunrpc/svc.h | 9 +++++---- net/sunrpc/svc.c | 14 +++++++------- 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index eda7d7e55e0..fce472f5f39 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -251,13 +251,13 @@ static void nfsd_shutdown(void) nfsd_up = false; } -static void nfsd_last_thread(struct svc_serv *serv) +static void nfsd_last_thread(struct svc_serv *serv, struct net *net) { /* When last nfsd thread exits we need to do some clean-up */ nfsd_serv = NULL; nfsd_shutdown(); - svc_rpcb_cleanup(serv); + svc_rpcb_cleanup(serv, net); printk(KERN_WARNING "nfsd: last server has exited, flushing export " "cache\n"); diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index d3563c2a580..7b65495aa4e 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -84,7 +84,8 @@ struct svc_serv { unsigned int sv_nrpools; /* number of thread pools */ struct svc_pool * sv_pools; /* array of thread pools */ - void (*sv_shutdown)(struct svc_serv *serv); + void (*sv_shutdown)(struct svc_serv *serv, + struct net *net); /* Callback to use when last thread * exits. */ @@ -413,14 +414,14 @@ struct svc_procedure { /* * Function prototypes. */ -void svc_rpcb_cleanup(struct svc_serv *serv); +void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); struct svc_serv *svc_create(struct svc_program *, unsigned int, - void (*shutdown)(struct svc_serv *)); + void (*shutdown)(struct svc_serv *, struct net *net)); struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node); void svc_exit_thread(struct svc_rqst *); struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, - void (*shutdown)(struct svc_serv *), + void (*shutdown)(struct svc_serv *, struct net *net), svc_thread_fn, struct module *); int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); int svc_pool_stats_open(struct svc_serv *serv, struct file *file); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index cb2caaee2af..a8b49a04461 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -382,10 +382,10 @@ static int svc_rpcb_setup(struct svc_serv *serv, struct net *net) return 0; } -void svc_rpcb_cleanup(struct svc_serv *serv) +void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) { - svc_unregister(serv, &init_net); - rpcb_put_local(&init_net); + svc_unregister(serv, net); + rpcb_put_local(net); } EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); @@ -411,7 +411,7 @@ static int svc_uses_rpcbind(struct svc_serv *serv) */ static struct svc_serv * __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, - void (*shutdown)(struct svc_serv *serv)) + void (*shutdown)(struct svc_serv *serv, struct net *net)) { struct svc_serv *serv; unsigned int vers; @@ -485,7 +485,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, struct svc_serv * svc_create(struct svc_program *prog, unsigned int bufsize, - void (*shutdown)(struct svc_serv *serv)) + void (*shutdown)(struct svc_serv *serv, struct net *net)) { return __svc_create(prog, bufsize, /*npools*/1, shutdown); } @@ -493,7 +493,7 @@ EXPORT_SYMBOL_GPL(svc_create); struct svc_serv * svc_create_pooled(struct svc_program *prog, unsigned int bufsize, - void (*shutdown)(struct svc_serv *serv), + void (*shutdown)(struct svc_serv *serv, struct net *net), svc_thread_fn func, struct module *mod) { struct svc_serv *serv; @@ -542,7 +542,7 @@ svc_destroy(struct svc_serv *serv) svc_close_all(serv); if (serv->sv_shutdown) - serv->sv_shutdown(serv); + serv->sv_shutdown(serv, current->nsproxy->net_ns); cache_clean_deferred(serv); -- cgit v1.2.3-70-g09d2 From 0a402d5a653ee2b613aaba3092a87b1e964622ce Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 19 Jan 2012 21:42:21 +0400 Subject: SUNRPC: cache creation and destruction routines introduced This patch prepares infrastructure for network namespace aware cache detail allocation. One note about adding network namespace link to cache structure. It's going to be used later in NFS DNS cache parsing routine (nfs_dns_parse for rpc_pton() call). Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Acked-by: J. Bruce Fields --- include/linux/sunrpc/cache.h | 4 ++++ net/sunrpc/cache.c | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'net') diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 590a8ab0cec..259381ca811 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -117,6 +117,7 @@ struct cache_detail { struct cache_detail_procfs procfs; struct cache_detail_pipefs pipefs; } u; + struct net *net; }; @@ -202,6 +203,9 @@ extern int cache_register_net(struct cache_detail *cd, struct net *net); extern void cache_unregister(struct cache_detail *cd); extern void cache_unregister_net(struct cache_detail *cd, struct net *net); +extern struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net); +extern void cache_destroy_net(struct cache_detail *cd, struct net *net); + extern void sunrpc_init_cache_detail(struct cache_detail *cd); extern void sunrpc_destroy_cache_detail(struct cache_detail *cd); extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *, diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index fefe06729f9..a450b8ac648 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1664,6 +1664,32 @@ void cache_unregister(struct cache_detail *cd) } EXPORT_SYMBOL_GPL(cache_unregister); +struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net) +{ + struct cache_detail *cd; + + cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL); + if (cd == NULL) + return ERR_PTR(-ENOMEM); + + cd->hash_table = kzalloc(cd->hash_size * sizeof(struct cache_head *), + GFP_KERNEL); + if (cd->hash_table == NULL) { + kfree(cd); + return ERR_PTR(-ENOMEM); + } + cd->net = net; + return cd; +} +EXPORT_SYMBOL_GPL(cache_create_net); + +void cache_destroy_net(struct cache_detail *cd, struct net *net) +{ + kfree(cd->hash_table); + kfree(cd); +} +EXPORT_SYMBOL_GPL(cache_destroy_net); + static ssize_t cache_read_pipefs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { -- cgit v1.2.3-70-g09d2 From 73393232d6a425b6bb4cee590e3e66fc52532a15 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 19 Jan 2012 21:42:29 +0400 Subject: SUNRPC: create unix gid cache per network namespace v2: 1) fixed silly usage of template cache as a real one (this code left from static global cache for all) This patch makes unix_gid_cache cache detail allocated and registered per network namespace context. Thus with this patch unix_gid_cache contents for network namespace "X" are controlled from proc file system mount for the same network namespace "X". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Acked-by: J. Bruce Fields --- net/sunrpc/netns.h | 1 + net/sunrpc/sunrpc_syms.c | 14 ++++++++---- net/sunrpc/svcauth_unix.c | 55 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 1fdeb1ba84b..309f88ddb06 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -9,6 +9,7 @@ struct cache_detail; struct sunrpc_net { struct proc_dir_entry *proc_net_rpc; struct cache_detail *ip_map_cache; + struct cache_detail *unix_gid_cache; struct super_block *pipefs_sb; struct mutex pipefs_sb_lock; diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index b4217dc8599..38a72a1b465 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -26,6 +26,9 @@ int sunrpc_net_id; +extern int unix_gid_cache_create(struct net *net); +extern int unix_gid_cache_destroy(struct net *net); + static __net_init int sunrpc_init_net(struct net *net) { int err; @@ -39,11 +42,17 @@ static __net_init int sunrpc_init_net(struct net *net) if (err) goto err_ipmap; + err = unix_gid_cache_create(net); + if (err) + goto err_unixgid; + rpc_pipefs_init_net(net); INIT_LIST_HEAD(&sn->all_clients); spin_lock_init(&sn->rpc_client_lock); return 0; +err_unixgid: + ip_map_cache_destroy(net); err_ipmap: rpc_proc_exit(net); err_proc: @@ -52,6 +61,7 @@ err_proc: static __net_exit void sunrpc_exit_net(struct net *net) { + unix_gid_cache_destroy(net); ip_map_cache_destroy(net); rpc_proc_exit(net); } @@ -63,8 +73,6 @@ static struct pernet_operations sunrpc_net_ops = { .size = sizeof(struct sunrpc_net), }; -extern struct cache_detail unix_gid_cache; - static int __init init_sunrpc(void) { @@ -86,7 +94,6 @@ init_sunrpc(void) #ifdef RPC_DEBUG rpc_register_sysctl(); #endif - cache_register(&unix_gid_cache); svc_init_xprt_sock(); /* svc sock transport */ init_socket_xprt(); /* clnt sock transport */ return 0; @@ -109,7 +116,6 @@ cleanup_sunrpc(void) svc_cleanup_xprt_sock(); unregister_rpc_pipefs(); rpc_destroy_mempool(); - cache_unregister(&unix_gid_cache); unregister_pernet_subsys(&sunrpc_net_ops); #ifdef RPC_DEBUG rpc_unregister_sysctl(); diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 2f8c426c138..a6eef38fb35 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -436,7 +436,6 @@ struct unix_gid { uid_t uid; struct group_info *gi; }; -static struct cache_head *gid_table[GID_HASHMAX]; static void unix_gid_put(struct kref *kref) { @@ -494,8 +493,7 @@ static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h) return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request); } -static struct unix_gid *unix_gid_lookup(uid_t uid); -extern struct cache_detail unix_gid_cache; +static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid); static int unix_gid_parse(struct cache_detail *cd, char *mesg, int mlen) @@ -539,19 +537,19 @@ static int unix_gid_parse(struct cache_detail *cd, GROUP_AT(ug.gi, i) = gid; } - ugp = unix_gid_lookup(uid); + ugp = unix_gid_lookup(cd, uid); if (ugp) { struct cache_head *ch; ug.h.flags = 0; ug.h.expiry_time = expiry; - ch = sunrpc_cache_update(&unix_gid_cache, + ch = sunrpc_cache_update(cd, &ug.h, &ugp->h, hash_long(uid, GID_HASHBITS)); if (!ch) err = -ENOMEM; else { err = 0; - cache_put(ch, &unix_gid_cache); + cache_put(ch, cd); } } else err = -ENOMEM; @@ -587,10 +585,9 @@ static int unix_gid_show(struct seq_file *m, return 0; } -struct cache_detail unix_gid_cache = { +static struct cache_detail unix_gid_cache_template = { .owner = THIS_MODULE, .hash_size = GID_HASHMAX, - .hash_table = gid_table, .name = "auth.unix.gid", .cache_put = unix_gid_put, .cache_upcall = unix_gid_upcall, @@ -602,14 +599,42 @@ struct cache_detail unix_gid_cache = { .alloc = unix_gid_alloc, }; -static struct unix_gid *unix_gid_lookup(uid_t uid) +int unix_gid_cache_create(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd; + int err; + + cd = cache_create_net(&unix_gid_cache_template, net); + if (IS_ERR(cd)) + return PTR_ERR(cd); + err = cache_register_net(cd, net); + if (err) { + cache_destroy_net(cd, net); + return err; + } + sn->unix_gid_cache = cd; + return 0; +} + +void unix_gid_cache_destroy(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd = sn->unix_gid_cache; + + sn->unix_gid_cache = NULL; + cache_purge(cd); + cache_unregister_net(cd, net); + cache_destroy_net(cd, net); +} + +static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid) { struct unix_gid ug; struct cache_head *ch; ug.uid = uid; - ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h, - hash_long(uid, GID_HASHBITS)); + ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS)); if (ch) return container_of(ch, struct unix_gid, h); else @@ -621,11 +646,13 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) struct unix_gid *ug; struct group_info *gi; int ret; + struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, + sunrpc_net_id); - ug = unix_gid_lookup(uid); + ug = unix_gid_lookup(sn->unix_gid_cache, uid); if (!ug) return ERR_PTR(-EAGAIN); - ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle); + ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle); switch (ret) { case -ENOENT: return ERR_PTR(-ENOENT); @@ -633,7 +660,7 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) return ERR_PTR(-ESHUTDOWN); case 0: gi = get_group_info(ug->gi); - cache_put(&ug->h, &unix_gid_cache); + cache_put(&ug->h, sn->unix_gid_cache); return gi; default: return ERR_PTR(-EAGAIN); -- cgit v1.2.3-70-g09d2 From a1db410d0bbadc49943f0fcddb21702ceb429396 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 19 Jan 2012 21:42:37 +0400 Subject: SUNRPC: create GSS auth cache per network namespace This patch makes GSS auth cache details allocated and registered per network namespace context. Thus with this patch rsi_cache and rsc_cache contents for network namespace "X" are controlled from proc file system mount for the same network namespace "X". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Acked-by: J. Bruce Fields --- include/linux/sunrpc/svcauth_gss.h | 2 + net/sunrpc/auth_gss/auth_gss.c | 21 +++++ net/sunrpc/auth_gss/svcauth_gss.c | 165 ++++++++++++++++++++++++++----------- net/sunrpc/netns.h | 2 + net/sunrpc/sunrpc_syms.c | 1 + 5 files changed, 141 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h index 83bbee3f089..7c32daa025e 100644 --- a/include/linux/sunrpc/svcauth_gss.h +++ b/include/linux/sunrpc/svcauth_gss.h @@ -18,6 +18,8 @@ int gss_svc_init(void); void gss_svc_shutdown(void); +int gss_svc_init_net(struct net *net); +void gss_svc_shutdown_net(struct net *net); int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); u32 svcauth_gss_flavor(struct auth_domain *dom); char *svc_gss_principal(struct svc_rqst *); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 5ebb602cabe..cb2e5645274 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1662,6 +1662,21 @@ static const struct rpc_pipe_ops gss_upcall_ops_v1 = { .release_pipe = gss_pipe_release, }; +static __net_init int rpcsec_gss_init_net(struct net *net) +{ + return gss_svc_init_net(net); +} + +static __net_exit void rpcsec_gss_exit_net(struct net *net) +{ + gss_svc_shutdown_net(net); +} + +static struct pernet_operations rpcsec_gss_net_ops = { + .init = rpcsec_gss_init_net, + .exit = rpcsec_gss_exit_net, +}; + /* * Initialize RPCSEC_GSS module */ @@ -1675,8 +1690,13 @@ static int __init init_rpcsec_gss(void) err = gss_svc_init(); if (err) goto out_unregister; + err = register_pernet_subsys(&rpcsec_gss_net_ops); + if (err) + goto out_svc_exit; rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version"); return 0; +out_svc_exit: + gss_svc_shutdown(); out_unregister: rpcauth_unregister(&authgss_ops); out: @@ -1685,6 +1705,7 @@ out: static void __exit exit_rpcsec_gss(void) { + unregister_pernet_subsys(&rpcsec_gss_net_ops); gss_svc_shutdown(); rpcauth_unregister(&authgss_ops); rcu_barrier(); /* Wait for completion of call_rcu()'s */ diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 8d0f7d3c71c..1600cfb1618 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -48,6 +48,8 @@ #include #include +#include "../netns.h" + #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH #endif @@ -75,10 +77,8 @@ struct rsi { int major_status, minor_status; }; -static struct cache_head *rsi_table[RSI_HASHMAX]; -static struct cache_detail rsi_cache; -static struct rsi *rsi_update(struct rsi *new, struct rsi *old); -static struct rsi *rsi_lookup(struct rsi *item); +static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old); +static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item); static void rsi_free(struct rsi *rsii) { @@ -216,7 +216,7 @@ static int rsi_parse(struct cache_detail *cd, if (dup_to_netobj(&rsii.in_token, buf, len)) goto out; - rsip = rsi_lookup(&rsii); + rsip = rsi_lookup(cd, &rsii); if (!rsip) goto out; @@ -258,21 +258,20 @@ static int rsi_parse(struct cache_detail *cd, if (dup_to_netobj(&rsii.out_token, buf, len)) goto out; rsii.h.expiry_time = expiry; - rsip = rsi_update(&rsii, rsip); + rsip = rsi_update(cd, &rsii, rsip); status = 0; out: rsi_free(&rsii); if (rsip) - cache_put(&rsip->h, &rsi_cache); + cache_put(&rsip->h, cd); else status = -ENOMEM; return status; } -static struct cache_detail rsi_cache = { +static struct cache_detail rsi_cache_template = { .owner = THIS_MODULE, .hash_size = RSI_HASHMAX, - .hash_table = rsi_table, .name = "auth.rpcsec.init", .cache_put = rsi_put, .cache_upcall = rsi_upcall, @@ -283,24 +282,24 @@ static struct cache_detail rsi_cache = { .alloc = rsi_alloc, }; -static struct rsi *rsi_lookup(struct rsi *item) +static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item) { struct cache_head *ch; int hash = rsi_hash(item); - ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash); + ch = sunrpc_cache_lookup(cd, &item->h, hash); if (ch) return container_of(ch, struct rsi, h); else return NULL; } -static struct rsi *rsi_update(struct rsi *new, struct rsi *old) +static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old) { struct cache_head *ch; int hash = rsi_hash(new); - ch = sunrpc_cache_update(&rsi_cache, &new->h, + ch = sunrpc_cache_update(cd, &new->h, &old->h, hash); if (ch) return container_of(ch, struct rsi, h); @@ -339,10 +338,8 @@ struct rsc { char *client_name; }; -static struct cache_head *rsc_table[RSC_HASHMAX]; -static struct cache_detail rsc_cache; -static struct rsc *rsc_update(struct rsc *new, struct rsc *old); -static struct rsc *rsc_lookup(struct rsc *item); +static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old); +static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item); static void rsc_free(struct rsc *rsci) { @@ -444,7 +441,7 @@ static int rsc_parse(struct cache_detail *cd, if (expiry == 0) goto out; - rscp = rsc_lookup(&rsci); + rscp = rsc_lookup(cd, &rsci); if (!rscp) goto out; @@ -506,22 +503,21 @@ static int rsc_parse(struct cache_detail *cd, } rsci.h.expiry_time = expiry; - rscp = rsc_update(&rsci, rscp); + rscp = rsc_update(cd, &rsci, rscp); status = 0; out: gss_mech_put(gm); rsc_free(&rsci); if (rscp) - cache_put(&rscp->h, &rsc_cache); + cache_put(&rscp->h, cd); else status = -ENOMEM; return status; } -static struct cache_detail rsc_cache = { +static struct cache_detail rsc_cache_template = { .owner = THIS_MODULE, .hash_size = RSC_HASHMAX, - .hash_table = rsc_table, .name = "auth.rpcsec.context", .cache_put = rsc_put, .cache_parse = rsc_parse, @@ -531,24 +527,24 @@ static struct cache_detail rsc_cache = { .alloc = rsc_alloc, }; -static struct rsc *rsc_lookup(struct rsc *item) +static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item) { struct cache_head *ch; int hash = rsc_hash(item); - ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash); + ch = sunrpc_cache_lookup(cd, &item->h, hash); if (ch) return container_of(ch, struct rsc, h); else return NULL; } -static struct rsc *rsc_update(struct rsc *new, struct rsc *old) +static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old) { struct cache_head *ch; int hash = rsc_hash(new); - ch = sunrpc_cache_update(&rsc_cache, &new->h, + ch = sunrpc_cache_update(cd, &new->h, &old->h, hash); if (ch) return container_of(ch, struct rsc, h); @@ -558,7 +554,7 @@ static struct rsc *rsc_update(struct rsc *new, struct rsc *old) static struct rsc * -gss_svc_searchbyctx(struct xdr_netobj *handle) +gss_svc_searchbyctx(struct cache_detail *cd, struct xdr_netobj *handle) { struct rsc rsci; struct rsc *found; @@ -566,11 +562,11 @@ gss_svc_searchbyctx(struct xdr_netobj *handle) memset(&rsci, 0, sizeof(rsci)); if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) return NULL; - found = rsc_lookup(&rsci); + found = rsc_lookup(cd, &rsci); rsc_free(&rsci); if (!found) return NULL; - if (cache_check(&rsc_cache, &found->h, NULL)) + if (cache_check(cd, &found->h, NULL)) return NULL; return found; } @@ -968,20 +964,20 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) } static inline int -gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip) +gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip) { struct rsc *rsci; int rc; if (rsip->major_status != GSS_S_COMPLETE) return gss_write_null_verf(rqstp); - rsci = gss_svc_searchbyctx(&rsip->out_handle); + rsci = gss_svc_searchbyctx(cd, &rsip->out_handle); if (rsci == NULL) { rsip->major_status = GSS_S_NO_CONTEXT; return gss_write_null_verf(rqstp); } rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN); - cache_put(&rsci->h, &rsc_cache); + cache_put(&rsci->h, cd); return rc; } @@ -1000,6 +996,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, struct xdr_netobj tmpobj; struct rsi *rsip, rsikey; int ret; + struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); /* Read the verifier; should be NULL: */ *authp = rpc_autherr_badverf; @@ -1028,17 +1025,17 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, } /* Perform upcall, or find upcall result: */ - rsip = rsi_lookup(&rsikey); + rsip = rsi_lookup(sn->rsi_cache, &rsikey); rsi_free(&rsikey); if (!rsip) return SVC_CLOSE; - if (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0) + if (cache_check(sn->rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0) /* No upcall result: */ return SVC_CLOSE; ret = SVC_CLOSE; /* Got an answer to the upcall; use it: */ - if (gss_write_init_verf(rqstp, rsip)) + if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip)) goto out; if (resv->iov_len + 4 > PAGE_SIZE) goto out; @@ -1055,7 +1052,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, ret = SVC_COMPLETE; out: - cache_put(&rsip->h, &rsi_cache); + cache_put(&rsip->h, sn->rsi_cache); return ret; } @@ -1079,6 +1076,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) __be32 *rpcstart; __be32 *reject_stat = resv->iov_base + resv->iov_len; int ret; + struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n", argv->iov_len); @@ -1129,7 +1127,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) case RPC_GSS_PROC_DESTROY: /* Look up the context, and check the verifier: */ *authp = rpcsec_gsserr_credproblem; - rsci = gss_svc_searchbyctx(&gc->gc_ctx); + rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx); if (!rsci) goto auth_err; switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) { @@ -1209,7 +1207,7 @@ drop: ret = SVC_DROP; out: if (rsci) - cache_put(&rsci->h, &rsc_cache); + cache_put(&rsci->h, sn->rsc_cache); return ret; } @@ -1362,6 +1360,7 @@ svcauth_gss_release(struct svc_rqst *rqstp) struct rpc_gss_wire_cred *gc = &gsd->clcred; struct xdr_buf *resbuf = &rqstp->rq_res; int stat = -EINVAL; + struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); if (gc->gc_proc != RPC_GSS_PROC_DATA) goto out; @@ -1404,7 +1403,7 @@ out_err: put_group_info(rqstp->rq_cred.cr_group_info); rqstp->rq_cred.cr_group_info = NULL; if (gsd->rsci) - cache_put(&gsd->rsci->h, &rsc_cache); + cache_put(&gsd->rsci->h, sn->rsc_cache); gsd->rsci = NULL; return stat; @@ -1429,30 +1428,96 @@ static struct auth_ops svcauthops_gss = { .set_client = svcauth_gss_set_client, }; +static int rsi_cache_create_net(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd; + int err; + + cd = cache_create_net(&rsi_cache_template, net); + if (IS_ERR(cd)) + return PTR_ERR(cd); + err = cache_register_net(cd, net); + if (err) { + cache_destroy_net(cd, net); + return err; + } + sn->rsi_cache = cd; + return 0; +} + +static void rsi_cache_destroy_net(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd = sn->rsi_cache; + + sn->rsi_cache = NULL; + cache_purge(cd); + cache_unregister_net(cd, net); + cache_destroy_net(cd, net); +} + +static int rsc_cache_create_net(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd; + int err; + + cd = cache_create_net(&rsc_cache_template, net); + if (IS_ERR(cd)) + return PTR_ERR(cd); + err = cache_register_net(cd, net); + if (err) { + cache_destroy_net(cd, net); + return err; + } + sn->rsc_cache = cd; + return 0; +} + +static void rsc_cache_destroy_net(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd = sn->rsc_cache; + + sn->rsc_cache = NULL; + cache_purge(cd); + cache_unregister_net(cd, net); + cache_destroy_net(cd, net); +} + int -gss_svc_init(void) +gss_svc_init_net(struct net *net) { - int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); + int rv; + + rv = rsc_cache_create_net(net); if (rv) return rv; - rv = cache_register(&rsc_cache); + rv = rsi_cache_create_net(net); if (rv) goto out1; - rv = cache_register(&rsi_cache); - if (rv) - goto out2; return 0; -out2: - cache_unregister(&rsc_cache); out1: - svc_auth_unregister(RPC_AUTH_GSS); + rsc_cache_destroy_net(net); return rv; } +void +gss_svc_shutdown_net(struct net *net) +{ + rsi_cache_destroy_net(net); + rsc_cache_destroy_net(net); +} + +int +gss_svc_init(void) +{ + return svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); +} + void gss_svc_shutdown(void) { - cache_unregister(&rsc_cache); - cache_unregister(&rsi_cache); svc_auth_unregister(RPC_AUTH_GSS); } diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 309f88ddb06..ce7bd449173 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -10,6 +10,8 @@ struct sunrpc_net { struct proc_dir_entry *proc_net_rpc; struct cache_detail *ip_map_cache; struct cache_detail *unix_gid_cache; + struct cache_detail *rsc_cache; + struct cache_detail *rsi_cache; struct super_block *pipefs_sb; struct mutex pipefs_sb_lock; diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 38a72a1b465..d16ac088f6d 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -25,6 +25,7 @@ #include "netns.h" int sunrpc_net_id; +EXPORT_SYMBOL_GPL(sunrpc_net_id); extern int unix_gid_cache_create(struct net *net); extern int unix_gid_cache_destroy(struct net *net); -- cgit v1.2.3-70-g09d2 From d05cc10406893dec65b8e89746e7d4c333935415 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 19 Jan 2012 21:42:45 +0400 Subject: SUNRPC: ip map cache per network namespace cleanup This patch converts ip_map_cache per network namespace implemenetation to the same view, as other caches done in the series. Besides generalization, code becomes shorter with this patch. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Acked-by: J. Bruce Fields --- net/sunrpc/svcauth_unix.c | 71 ++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 41 deletions(-) (limited to 'net') diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index a6eef38fb35..bcd574f2ac5 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -211,7 +211,7 @@ static int ip_map_parse(struct cache_detail *cd, len = qword_get(&mesg, buf, mlen); if (len <= 0) return -EINVAL; - if (rpc_pton(&init_net, buf, len, &address.sa, sizeof(address)) == 0) + if (rpc_pton(cd->net, buf, len, &address.sa, sizeof(address)) == 0) return -EINVAL; switch (address.sa.sa_family) { case AF_INET: @@ -876,56 +876,45 @@ struct auth_ops svcauth_unix = { .set_client = svcauth_unix_set_client, }; +static struct cache_detail ip_map_cache_template = { + .owner = THIS_MODULE, + .hash_size = IP_HASHMAX, + .name = "auth.unix.ip", + .cache_put = ip_map_put, + .cache_upcall = ip_map_upcall, + .cache_parse = ip_map_parse, + .cache_show = ip_map_show, + .match = ip_map_match, + .init = ip_map_init, + .update = update, + .alloc = ip_map_alloc, +}; + int ip_map_cache_create(struct net *net) { - int err = -ENOMEM; - struct cache_detail *cd; - struct cache_head **tbl; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd; + int err; - cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL); - if (cd == NULL) - goto err_cd; - - tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL); - if (tbl == NULL) - goto err_tbl; - - cd->owner = THIS_MODULE, - cd->hash_size = IP_HASHMAX, - cd->hash_table = tbl, - cd->name = "auth.unix.ip", - cd->cache_put = ip_map_put, - cd->cache_upcall = ip_map_upcall, - cd->cache_parse = ip_map_parse, - cd->cache_show = ip_map_show, - cd->match = ip_map_match, - cd->init = ip_map_init, - cd->update = update, - cd->alloc = ip_map_alloc, - + cd = cache_create_net(&ip_map_cache_template, net); + if (IS_ERR(cd)) + return PTR_ERR(cd); err = cache_register_net(cd, net); - if (err) - goto err_reg; - + if (err) { + cache_destroy_net(cd, net); + return err; + } sn->ip_map_cache = cd; return 0; - -err_reg: - kfree(tbl); -err_tbl: - kfree(cd); -err_cd: - return err; } void ip_map_cache_destroy(struct net *net) { - struct sunrpc_net *sn; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct cache_detail *cd = sn->ip_map_cache; - sn = net_generic(net, sunrpc_net_id); - cache_purge(sn->ip_map_cache); - cache_unregister_net(sn->ip_map_cache, net); - kfree(sn->ip_map_cache->hash_table); - kfree(sn->ip_map_cache); + sn->ip_map_cache = NULL; + cache_purge(cd); + cache_unregister_net(cd, net); + cache_destroy_net(cd, net); } -- cgit v1.2.3-70-g09d2 From 2c5f846747526e2b83c5f1b8e69016be0e2e87c0 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 19 Jan 2012 21:42:53 +0400 Subject: SUNRPC: generic cache register routines removed All cache users now uses network-namespace-aware routines, so generic ones are obsolete. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Acked-by: J. Bruce Fields --- include/linux/sunrpc/cache.h | 2 -- net/sunrpc/cache.c | 12 ------------ 2 files changed, 14 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 259381ca811..f5fd6160dbc 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -198,9 +198,7 @@ extern void cache_flush(void); extern void cache_purge(struct cache_detail *detail); #define NEVER (0x7FFFFFFF) extern void __init cache_initialize(void); -extern int cache_register(struct cache_detail *cd); extern int cache_register_net(struct cache_detail *cd, struct net *net); -extern void cache_unregister(struct cache_detail *cd); extern void cache_unregister_net(struct cache_detail *cd, struct net *net); extern struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index a450b8ac648..f21ece08876 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1645,12 +1645,6 @@ int cache_register_net(struct cache_detail *cd, struct net *net) } EXPORT_SYMBOL_GPL(cache_register_net); -int cache_register(struct cache_detail *cd) -{ - return cache_register_net(cd, &init_net); -} -EXPORT_SYMBOL_GPL(cache_register); - void cache_unregister_net(struct cache_detail *cd, struct net *net) { remove_cache_proc_entries(cd, net); @@ -1658,12 +1652,6 @@ void cache_unregister_net(struct cache_detail *cd, struct net *net) } EXPORT_SYMBOL_GPL(cache_unregister_net); -void cache_unregister(struct cache_detail *cd) -{ - cache_unregister_net(cd, &init_net); -} -EXPORT_SYMBOL_GPL(cache_unregister); - struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net) { struct cache_detail *cd; -- cgit v1.2.3-70-g09d2 From ec7652aaf261b7dcb368344369df1e99886c7cd2 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 6 Dec 2011 16:42:40 +0300 Subject: SUNRPC: register RPC stats /proc entries in passed network namespace context This patch makes it possible to create NFS program entry ("/proc/net/rpc/nfs") in passed network namespace context instead of hard-coded "init_net". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 6 +++--- include/linux/sunrpc/stats.h | 8 ++++---- net/sunrpc/stats.c | 15 ++++++++------- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 65486e65294..d2c760e193f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1625,14 +1625,14 @@ static int __init init_nfs_fs(void) goto out0; #ifdef CONFIG_PROC_FS - rpc_proc_register(&nfs_rpcstat); + rpc_proc_register(&init_net, &nfs_rpcstat); #endif if ((err = register_nfs_fs()) != 0) goto out; return 0; out: #ifdef CONFIG_PROC_FS - rpc_proc_unregister("nfs"); + rpc_proc_unregister(&init_net, "nfs"); #endif nfs_destroy_directcache(); out0: @@ -1671,7 +1671,7 @@ static void __exit exit_nfs_fs(void) nfs_dns_resolver_destroy(); nfs_idmap_quit(); #ifdef CONFIG_PROC_FS - rpc_proc_unregister("nfs"); + rpc_proc_unregister(&init_net, "nfs"); #endif nfs_cleanup_cb_ident_idr(); unregister_nfs_fs(); diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h index 680471d1f28..f625b5746bd 100644 --- a/include/linux/sunrpc/stats.h +++ b/include/linux/sunrpc/stats.h @@ -58,8 +58,8 @@ void rpc_modcount(struct inode *, int); #endif #ifdef CONFIG_PROC_FS -struct proc_dir_entry * rpc_proc_register(struct rpc_stat *); -void rpc_proc_unregister(const char *); +struct proc_dir_entry * rpc_proc_register(struct net *,struct rpc_stat *); +void rpc_proc_unregister(struct net *,const char *); void rpc_proc_zero(struct rpc_program *); struct proc_dir_entry * svc_proc_register(struct svc_stat *, const struct file_operations *); @@ -69,8 +69,8 @@ void svc_seq_show(struct seq_file *, const struct svc_stat *); #else -static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; } -static inline void rpc_proc_unregister(const char *p) {} +static inline struct proc_dir_entry *rpc_proc_register(struct net *, struct rpc_stat *s) { return NULL; } +static inline void rpc_proc_unregisterstruct net *, (const char *p) {} static inline void rpc_proc_zero(struct rpc_program *p) {} static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s, diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 80df89d957b..f0f6e7ceadd 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -213,28 +213,29 @@ EXPORT_SYMBOL_GPL(rpc_print_iostats); * Register/unregister RPC proc files */ static inline struct proc_dir_entry * -do_register(const char *name, void *data, const struct file_operations *fops) +do_register(struct net *net, const char *name, void *data, + const struct file_operations *fops) { struct sunrpc_net *sn; dprintk("RPC: registering /proc/net/rpc/%s\n", name); - sn = net_generic(&init_net, sunrpc_net_id); + sn = net_generic(net, sunrpc_net_id); return proc_create_data(name, 0, sn->proc_net_rpc, fops, data); } struct proc_dir_entry * -rpc_proc_register(struct rpc_stat *statp) +rpc_proc_register(struct net *net, struct rpc_stat *statp) { - return do_register(statp->program->name, statp, &rpc_proc_fops); + return do_register(net, statp->program->name, statp, &rpc_proc_fops); } EXPORT_SYMBOL_GPL(rpc_proc_register); void -rpc_proc_unregister(const char *name) +rpc_proc_unregister(struct net *net, const char *name) { struct sunrpc_net *sn; - sn = net_generic(&init_net, sunrpc_net_id); + sn = net_generic(net, sunrpc_net_id); remove_proc_entry(name, sn->proc_net_rpc); } EXPORT_SYMBOL_GPL(rpc_proc_unregister); @@ -242,7 +243,7 @@ EXPORT_SYMBOL_GPL(rpc_proc_unregister); struct proc_dir_entry * svc_proc_register(struct svc_stat *statp, const struct file_operations *fops) { - return do_register(statp->program->pg_name, statp, fops); + return do_register(&init_net, statp->program->pg_name, statp, fops); } EXPORT_SYMBOL_GPL(svc_proc_register); -- cgit v1.2.3-70-g09d2 From 246590f56c9f281d60b7dd7efa0818307e65600d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 6 Dec 2011 16:42:49 +0300 Subject: SUNRPC: register service stats /proc entries in passed network namespace context This patch makes it possible to create NFSd program entry ("/proc/net/rpc/nfsd") in passed network namespace context instead of hard-coded "init_net". Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfsd/stats.c | 5 +++-- include/linux/sunrpc/stats.h | 8 ++++---- net/sunrpc/stats.c | 8 ++++---- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index a2e2402b2af..6d4521feb6e 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "nfsd.h" @@ -94,11 +95,11 @@ static const struct file_operations nfsd_proc_fops = { void nfsd_stat_init(void) { - svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops); + svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops); } void nfsd_stat_shutdown(void) { - svc_proc_unregister("nfsd"); + svc_proc_unregister(&init_net, "nfsd"); } diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h index c5aaf7ddb5c..76f3f7cc6e3 100644 --- a/include/linux/sunrpc/stats.h +++ b/include/linux/sunrpc/stats.h @@ -61,9 +61,9 @@ void rpc_modcount(struct inode *, int); struct proc_dir_entry * rpc_proc_register(struct net *,struct rpc_stat *); void rpc_proc_unregister(struct net *,const char *); void rpc_proc_zero(struct rpc_program *); -struct proc_dir_entry * svc_proc_register(struct svc_stat *, +struct proc_dir_entry * svc_proc_register(struct net *, struct svc_stat *, const struct file_operations *); -void svc_proc_unregister(const char *); +void svc_proc_unregister(struct net *, const char *); void svc_seq_show(struct seq_file *, const struct svc_stat *); @@ -73,9 +73,9 @@ static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct r static inline void rpc_proc_unregister(struct net *net, const char *p) {} static inline void rpc_proc_zero(struct rpc_program *p) {} -static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s, +static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s, const struct file_operations *f) { return NULL; } -static inline void svc_proc_unregister(const char *p) {} +static inline void svc_proc_unregister(struct net *net, const char *p) {} static inline void svc_seq_show(struct seq_file *seq, const struct svc_stat *st) {} diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index f0f6e7ceadd..3c4f6888c89 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -241,18 +241,18 @@ rpc_proc_unregister(struct net *net, const char *name) EXPORT_SYMBOL_GPL(rpc_proc_unregister); struct proc_dir_entry * -svc_proc_register(struct svc_stat *statp, const struct file_operations *fops) +svc_proc_register(struct net *net, struct svc_stat *statp, const struct file_operations *fops) { - return do_register(&init_net, statp->program->pg_name, statp, fops); + return do_register(net, statp->program->pg_name, statp, fops); } EXPORT_SYMBOL_GPL(svc_proc_register); void -svc_proc_unregister(const char *name) +svc_proc_unregister(struct net *net, const char *name) { struct sunrpc_net *sn; - sn = net_generic(&init_net, sunrpc_net_id); + sn = net_generic(net, sunrpc_net_id); remove_proc_entry(name, sn->proc_net_rpc); } EXPORT_SYMBOL_GPL(svc_proc_unregister); -- cgit v1.2.3-70-g09d2 From 4cb54ca2069903121e4c03ec427147c47bed5755 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 20 Jan 2012 16:50:53 +0400 Subject: SUNRPC: search for service transports in network namespace context Service transports are parametrized by network namespace. And thus lookup of transport instance have to take network namespace into account. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust Acked-by: J. Bruce Fields --- fs/lockd/svc.c | 2 +- fs/nfsd/nfsctl.c | 4 ++-- include/linux/sunrpc/svc_xprt.h | 3 ++- net/sunrpc/svc_xprt.c | 6 +++++- 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index c061b9aa7dd..ff379ff7761 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -193,7 +193,7 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name, { struct svc_xprt *xprt; - xprt = svc_find_xprt(serv, name, family, 0); + xprt = svc_find_xprt(serv, name, &init_net, family, 0); if (xprt == NULL) return svc_create_xprt(serv, name, &init_net, family, port, SVC_SOCK_DEFAULTS); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 330352d379b..64c24af8d7e 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -722,7 +722,7 @@ static ssize_t __write_ports_addxprt(char *buf) nfsd_serv->sv_nrthreads--; return 0; out_close: - xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port); + xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); if (xprt != NULL) { svc_close_xprt(xprt); svc_xprt_put(xprt); @@ -748,7 +748,7 @@ static ssize_t __write_ports_delxprt(char *buf) if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) return -EINVAL; - xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); + xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port); if (xprt == NULL) return -ENOTCONN; diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index dfa900948af..b3f64b12f14 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -121,7 +121,8 @@ void svc_close_xprt(struct svc_xprt *xprt); int svc_port_is_privileged(struct sockaddr *sin); int svc_print_xprts(char *buf, int maxlen); struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, - const sa_family_t af, const unsigned short port); + struct net *net, const sa_family_t af, + const unsigned short port); int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); static inline void svc_xprt_get(struct svc_xprt *xprt) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 74cb0d8e9ca..de1e1a8b526 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -1089,6 +1089,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) * svc_find_xprt - find an RPC transport instance * @serv: pointer to svc_serv to search * @xcl_name: C string containing transport's class name + * @net: owner net pointer * @af: Address family of transport's local address * @port: transport's IP port number * @@ -1101,7 +1102,8 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) * service's list that has a matching class name. */ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, - const sa_family_t af, const unsigned short port) + struct net *net, const sa_family_t af, + const unsigned short port) { struct svc_xprt *xprt; struct svc_xprt *found = NULL; @@ -1112,6 +1114,8 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, spin_lock_bh(&serv->sv_lock); list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { + if (xprt->xpt_net != net) + continue; if (strcmp(xprt->xpt_class->xcl_name, xcl_name)) continue; if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family) -- cgit v1.2.3-70-g09d2 From 6eac7d3f45a2519283d38bf670cb6968230124f8 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 20 Jan 2012 13:53:37 -0500 Subject: SUNRPC: constify rpc_clnt fields cl_server and cl_protname ...and get rid of the superfluous cl_inline_name. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/clnt.h | 9 ++++----- net/sunrpc/clnt.c | 29 ++++++++++++----------------- net/sunrpc/rpcb_clnt.c | 2 +- 3 files changed, 17 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 9e754e3458f..db6970ced9b 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -41,8 +41,8 @@ struct rpc_clnt { cl_vers, /* RPC version number */ cl_maxproc; /* max procedure number */ - char * cl_server; /* server machine name */ - char * cl_protname; /* protocol name */ + const char * cl_server; /* server machine name */ + const char * cl_protname; /* protocol name */ struct rpc_auth * cl_auth; /* authenticator */ struct rpc_stat * cl_stats; /* per-program statistics */ struct rpc_iostats * cl_metrics; /* per-client statistics */ @@ -62,7 +62,6 @@ struct rpc_clnt { struct rpc_rtt cl_rtt_default; struct rpc_timeout cl_timeout_default; struct rpc_program * cl_program; - char cl_inline_name[32]; char *cl_principal; /* target to authenticate to */ }; @@ -97,7 +96,7 @@ struct rpc_procinfo { unsigned int p_count; /* call count */ unsigned int p_timer; /* Which RTT timer to use */ u32 p_statidx; /* Which procedure to account */ - char * p_name; /* name of procedure */ + const char * p_name; /* name of procedure */ }; #ifdef __KERNEL__ @@ -109,7 +108,7 @@ struct rpc_create_args { size_t addrsize; struct sockaddr *saddress; const struct rpc_timeout *timeout; - char *servername; + const char *servername; struct rpc_program *program; u32 prognumber; /* overrides program->number */ u32 version; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4c684801716..e9b22e8e16c 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -273,15 +273,9 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru goto out_err; clnt->cl_parent = clnt; - clnt->cl_server = clnt->cl_inline_name; - if (len > sizeof(clnt->cl_inline_name)) { - char *buf = kmalloc(len, GFP_KERNEL); - if (buf != NULL) - clnt->cl_server = buf; - else - len = sizeof(clnt->cl_inline_name); - } - strlcpy(clnt->cl_server, args->servername, len); + clnt->cl_server = kstrdup(args->servername, GFP_KERNEL); + if (clnt->cl_server == NULL) + goto out_no_server; clnt->cl_xprt = xprt; clnt->cl_procinfo = version->procs; @@ -346,8 +340,8 @@ out_no_path: out_no_principal: rpc_free_iostats(clnt->cl_metrics); out_no_stats: - if (clnt->cl_server != clnt->cl_inline_name) - kfree(clnt->cl_server); + kfree(clnt->cl_server); +out_no_server: kfree(clnt); out_err: xprt_put(xprt); @@ -470,6 +464,9 @@ rpc_clone_client(struct rpc_clnt *clnt) new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); if (!new) goto out_no_clnt; + new->cl_server = kstrdup(clnt->cl_server, GFP_KERNEL); + if (new->cl_server == NULL) + goto out_no_server; new->cl_parent = clnt; /* Turn off autobind on clones */ new->cl_autobind = 0; @@ -500,6 +497,8 @@ out_no_path: out_no_principal: rpc_free_iostats(new->cl_metrics); out_no_stats: + kfree(new->cl_server); +out_no_server: kfree(new); out_no_clnt: dprintk("RPC: %s: returned error %d\n", __func__, err); @@ -565,13 +564,9 @@ rpc_free_client(struct rpc_clnt *clnt) { dprintk("RPC: destroying %s client for %s\n", clnt->cl_protname, clnt->cl_server); - if (clnt->cl_parent != clnt) { + if (clnt->cl_parent != clnt) rpc_release_client(clnt->cl_parent); - goto out_free; - } - if (clnt->cl_server != clnt->cl_inline_name) - kfree(clnt->cl_server); -out_free: + kfree(clnt->cl_server); rpc_unregister_client(clnt); rpc_clnt_remove_pipedir(clnt); rpc_free_iostats(clnt->cl_metrics); diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 4ce3a8e0295..d3978017b25 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -343,7 +343,7 @@ out: return result; } -static struct rpc_clnt *rpcb_create(struct net *net, char *hostname, +static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, struct sockaddr *srvaddr, size_t salen, int proto, u32 version) { -- cgit v1.2.3-70-g09d2 From 080b794ce5ad318ce34c52abaedf1bc6788a5abb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 20 Jan 2012 13:53:56 -0500 Subject: SUNRPC: constify rpc_program->name Signed-off-by: Trond Myklebust --- include/linux/sunrpc/clnt.h | 4 ++-- net/sunrpc/clnt.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index db6970ced9b..4a46ffd73a0 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -70,12 +70,12 @@ struct rpc_clnt { */ #define RPC_MAXVERSION 4 struct rpc_program { - char * name; /* protocol name */ + const char * name; /* protocol name */ u32 number; /* program number */ unsigned int nrvers; /* number of versions */ struct rpc_version ** version; /* version array */ struct rpc_stat * stats; /* statistics */ - char * pipe_dir_name; /* path to rpc_pipefs dir */ + const char * pipe_dir_name; /* path to rpc_pipefs dir */ }; struct rpc_version { diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e9b22e8e16c..1b2317fa404 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -118,7 +118,8 @@ static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) } static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, - struct rpc_clnt *clnt, char *dir_name) + struct rpc_clnt *clnt, + const char *dir_name) { static uint32_t clntid; char name[15]; @@ -151,7 +152,7 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, } static int -rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) +rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) { struct super_block *pipefs_sb; struct dentry *dentry; -- cgit v1.2.3-70-g09d2 From a613fa168afc19179a7547fbba45644c5b6912bf Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 20 Jan 2012 13:53:56 -0500 Subject: SUNRPC: constify the rpc_program Signed-off-by: Trond Myklebust --- fs/lockd/clnt4xdr.c | 2 +- fs/lockd/clntxdr.c | 8 ++++---- fs/lockd/mon.c | 8 ++++---- fs/nfs/client.c | 8 ++++---- fs/nfs/internal.h | 2 +- fs/nfs/mount_clnt.c | 10 +++++----- fs/nfs/nfs2xdr.c | 2 +- fs/nfs/nfs3xdr.c | 4 ++-- fs/nfs/nfs4xdr.c | 2 +- fs/nfsd/nfs4callback.c | 6 +++--- include/linux/lockd/lockd.h | 2 +- include/linux/lockd/xdr4.h | 2 +- include/linux/nfs_xdr.h | 10 +++++----- include/linux/sunrpc/clnt.h | 8 ++++---- include/linux/sunrpc/stats.h | 6 +++--- net/sunrpc/clnt.c | 8 ++++---- net/sunrpc/rpcb_clnt.c | 20 ++++++++++---------- 17 files changed, 54 insertions(+), 54 deletions(-) (limited to 'net') diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c index f848b52c67b..3ddcbb1c0a4 100644 --- a/fs/lockd/clnt4xdr.c +++ b/fs/lockd/clnt4xdr.c @@ -598,7 +598,7 @@ static struct rpc_procinfo nlm4_procedures[] = { PROC(GRANTED_RES, res, norep), }; -struct rpc_version nlm_version4 = { +const struct rpc_version nlm_version4 = { .number = 4, .nrprocs = ARRAY_SIZE(nlm4_procedures), .procs = nlm4_procedures, diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c index 180ac34feb9..3d35e3e80c1 100644 --- a/fs/lockd/clntxdr.c +++ b/fs/lockd/clntxdr.c @@ -596,19 +596,19 @@ static struct rpc_procinfo nlm_procedures[] = { PROC(GRANTED_RES, res, norep), }; -static struct rpc_version nlm_version1 = { +static const struct rpc_version nlm_version1 = { .number = 1, .nrprocs = ARRAY_SIZE(nlm_procedures), .procs = nlm_procedures, }; -static struct rpc_version nlm_version3 = { +static const struct rpc_version nlm_version3 = { .number = 3, .nrprocs = ARRAY_SIZE(nlm_procedures), .procs = nlm_procedures, }; -static struct rpc_version *nlm_versions[] = { +static const struct rpc_version *nlm_versions[] = { [1] = &nlm_version1, [3] = &nlm_version3, #ifdef CONFIG_LOCKD_V4 @@ -618,7 +618,7 @@ static struct rpc_version *nlm_versions[] = { static struct rpc_stat nlm_rpc_stats; -struct rpc_program nlm_program = { +const struct rpc_program nlm_program = { .name = "lockd", .number = NLM_PROGRAM, .nrvers = ARRAY_SIZE(nlm_versions), diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 65ba36b80a9..c196030e530 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -47,7 +47,7 @@ struct nsm_res { u32 state; }; -static struct rpc_program nsm_program; +static const struct rpc_program nsm_program; static LIST_HEAD(nsm_handles); static DEFINE_SPINLOCK(nsm_lock); @@ -534,19 +534,19 @@ static struct rpc_procinfo nsm_procedures[] = { }, }; -static struct rpc_version nsm_version1 = { +static const struct rpc_version nsm_version1 = { .number = 1, .nrprocs = ARRAY_SIZE(nsm_procedures), .procs = nsm_procedures }; -static struct rpc_version * nsm_version[] = { +static const struct rpc_version *nsm_version[] = { [1] = &nsm_version1, }; static struct rpc_stat nsm_stats; -static struct rpc_program nsm_program = { +static const struct rpc_program nsm_program = { .name = "statd", .number = NSM_PROGRAM, .nrvers = ARRAY_SIZE(nsm_version), diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 34c8d1cbf06..98af1cb28ee 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -89,7 +89,7 @@ static bool nfs4_disable_idmapping = true; /* * RPC cruft for NFS */ -static struct rpc_version *nfs_version[5] = { +static const struct rpc_version *nfs_version[5] = { [2] = &nfs_version2, #ifdef CONFIG_NFS_V3 [3] = &nfs_version3, @@ -99,7 +99,7 @@ static struct rpc_version *nfs_version[5] = { #endif }; -struct rpc_program nfs_program = { +const struct rpc_program nfs_program = { .name = "nfs", .number = NFS_PROGRAM, .nrvers = ARRAY_SIZE(nfs_version), @@ -115,11 +115,11 @@ struct rpc_stat nfs_rpcstat = { #ifdef CONFIG_NFS_V3_ACL static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; -static struct rpc_version * nfsacl_version[] = { +static const struct rpc_version *nfsacl_version[] = { [3] = &nfsacl_version3, }; -struct rpc_program nfsacl_program = { +const struct rpc_program nfsacl_program = { .name = "nfsacl", .number = NFS_ACL_PROGRAM, .nrvers = ARRAY_SIZE(nfsacl_version), diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index eda4cde40fb..cdb121d3c6f 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -145,7 +145,7 @@ extern int nfs_mount(struct nfs_mount_request *info); extern void nfs_umount(const struct nfs_mount_request *info); /* client.c */ -extern struct rpc_program nfs_program; +extern const struct rpc_program nfs_program; extern void nfs_cleanup_cb_ident_idr(void); extern void nfs_put_client(struct nfs_client *); diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 4fbe3a8e5e6..b37ca34af90 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -67,7 +67,7 @@ enum { MOUNTPROC3_EXPORT = 5, }; -static struct rpc_program mnt_program; +static const struct rpc_program mnt_program; /* * Defined by OpenGroup XNFS Version 3W, chapter 8 @@ -488,19 +488,19 @@ static struct rpc_procinfo mnt3_procedures[] = { }; -static struct rpc_version mnt_version1 = { +static const struct rpc_version mnt_version1 = { .number = 1, .nrprocs = ARRAY_SIZE(mnt_procedures), .procs = mnt_procedures, }; -static struct rpc_version mnt_version3 = { +static const struct rpc_version mnt_version3 = { .number = 3, .nrprocs = ARRAY_SIZE(mnt3_procedures), .procs = mnt3_procedures, }; -static struct rpc_version *mnt_version[] = { +static const struct rpc_version *mnt_version[] = { NULL, &mnt_version1, NULL, @@ -509,7 +509,7 @@ static struct rpc_version *mnt_version[] = { static struct rpc_stat mnt_stats; -static struct rpc_program mnt_program = { +static const struct rpc_program mnt_program = { .name = "mount", .number = NFS_MNT_PROGRAM, .nrvers = ARRAY_SIZE(mnt_version), diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 792cb13a430..1f56000fabb 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -1150,7 +1150,7 @@ struct rpc_procinfo nfs_procedures[] = { PROC(STATFS, fhandle, statfsres, 0), }; -struct rpc_version nfs_version2 = { +const struct rpc_version nfs_version2 = { .number = 2, .nrprocs = ARRAY_SIZE(nfs_procedures), .procs = nfs_procedures diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 183c6b123d0..a77cc9a3ce5 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -2461,7 +2461,7 @@ struct rpc_procinfo nfs3_procedures[] = { PROC(COMMIT, commit, commit, 5), }; -struct rpc_version nfs_version3 = { +const struct rpc_version nfs_version3 = { .number = 3, .nrprocs = ARRAY_SIZE(nfs3_procedures), .procs = nfs3_procedures @@ -2489,7 +2489,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = { }, }; -struct rpc_version nfsacl_version3 = { +const struct rpc_version nfsacl_version3 = { .number = 3, .nrprocs = sizeof(nfs3_acl_procedures)/ sizeof(nfs3_acl_procedures[0]), diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 95e92e43840..4633d405a94 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -7109,7 +7109,7 @@ struct rpc_procinfo nfs4_procedures[] = { #endif /* CONFIG_NFS_V4_1 */ }; -struct rpc_version nfs_version4 = { +const struct rpc_version nfs_version4 = { .number = 4, .nrprocs = ARRAY_SIZE(nfs4_procedures), .procs = nfs4_procedures diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 426ccb17165..0e262f32ac4 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -605,18 +605,18 @@ static struct rpc_version nfs_cb_version4 = { .procs = nfs4_cb_procedures }; -static struct rpc_version *nfs_cb_version[] = { +static const struct rpc_version *nfs_cb_version[] = { &nfs_cb_version4, }; -static struct rpc_program cb_program; +static const struct rpc_program cb_program; static struct rpc_stat cb_stats = { .program = &cb_program }; #define NFS4_CALLBACK 0x40000000 -static struct rpc_program cb_program = { +static const struct rpc_program cb_program = { .name = "nfs4_cb", .number = NFS4_CALLBACK, .nrvers = ARRAY_SIZE(nfs_cb_version), diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 88a114fce47..8949167a148 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -188,7 +188,7 @@ struct nlm_block { /* * Global variables */ -extern struct rpc_program nlm_program; +extern const struct rpc_program nlm_program; extern struct svc_procedure nlmsvc_procedures[]; #ifdef CONFIG_LOCKD_V4 extern struct svc_procedure nlmsvc_procedures4[]; diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h index 7353821341e..e58c88b52ce 100644 --- a/include/linux/lockd/xdr4.h +++ b/include/linux/lockd/xdr4.h @@ -42,6 +42,6 @@ int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); */ -extern struct rpc_version nlm_version4; +extern const struct rpc_version nlm_version4; #endif /* LOCKD_XDR4_H */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index f5188e10ea0..144419a9cbd 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1274,11 +1274,11 @@ struct nfs_rpc_ops { extern const struct nfs_rpc_ops nfs_v2_clientops; extern const struct nfs_rpc_ops nfs_v3_clientops; extern const struct nfs_rpc_ops nfs_v4_clientops; -extern struct rpc_version nfs_version2; -extern struct rpc_version nfs_version3; -extern struct rpc_version nfs_version4; +extern const struct rpc_version nfs_version2; +extern const struct rpc_version nfs_version3; +extern const struct rpc_version nfs_version4; -extern struct rpc_version nfsacl_version3; -extern struct rpc_program nfsacl_program; +extern const struct rpc_version nfsacl_version3; +extern const struct rpc_program nfsacl_program; #endif diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 4a46ffd73a0..a4c62e95c72 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -61,7 +61,7 @@ struct rpc_clnt { struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_rtt cl_rtt_default; struct rpc_timeout cl_timeout_default; - struct rpc_program * cl_program; + const struct rpc_program *cl_program; char *cl_principal; /* target to authenticate to */ }; @@ -73,7 +73,7 @@ struct rpc_program { const char * name; /* protocol name */ u32 number; /* program number */ unsigned int nrvers; /* number of versions */ - struct rpc_version ** version; /* version array */ + const struct rpc_version ** version; /* version array */ struct rpc_stat * stats; /* statistics */ const char * pipe_dir_name; /* path to rpc_pipefs dir */ }; @@ -109,7 +109,7 @@ struct rpc_create_args { struct sockaddr *saddress; const struct rpc_timeout *timeout; const char *servername; - struct rpc_program *program; + const struct rpc_program *program; u32 prognumber; /* overrides program->number */ u32 version; rpc_authflavor_t authflavor; @@ -128,7 +128,7 @@ struct rpc_create_args { struct rpc_clnt *rpc_create(struct rpc_create_args *args); struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, - struct rpc_program *, u32); + const struct rpc_program *, u32); void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt); struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); void rpc_shutdown_client(struct rpc_clnt *); diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h index 76f3f7cc6e3..edc64219f92 100644 --- a/include/linux/sunrpc/stats.h +++ b/include/linux/sunrpc/stats.h @@ -12,7 +12,7 @@ #include struct rpc_stat { - struct rpc_program * program; + const struct rpc_program *program; unsigned int netcnt, netudpcnt, @@ -60,7 +60,7 @@ void rpc_modcount(struct inode *, int); #ifdef CONFIG_PROC_FS struct proc_dir_entry * rpc_proc_register(struct net *,struct rpc_stat *); void rpc_proc_unregister(struct net *,const char *); -void rpc_proc_zero(struct rpc_program *); +void rpc_proc_zero(const struct rpc_program *); struct proc_dir_entry * svc_proc_register(struct net *, struct svc_stat *, const struct file_operations *); void svc_proc_unregister(struct net *, const char *); @@ -71,7 +71,7 @@ void svc_seq_show(struct seq_file *, static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct rpc_stat *s) { return NULL; } static inline void rpc_proc_unregister(struct net *net, const char *p) {} -static inline void rpc_proc_zero(struct rpc_program *p) {} +static inline void rpc_proc_zero(const struct rpc_program *p) {} static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s, const struct file_operations *f) { return NULL; } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 1b2317fa404..db7220d8773 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -238,8 +238,8 @@ void rpc_clients_notifier_unregister(void) static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) { - struct rpc_program *program = args->program; - struct rpc_version *version; + const struct rpc_program *program = args->program; + const struct rpc_version *version; struct rpc_clnt *clnt = NULL; struct rpc_auth *auth; int err; @@ -626,11 +626,11 @@ rpc_release_client(struct rpc_clnt *clnt) * The Sun NFSv2/v3 ACL protocol can do this. */ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, - struct rpc_program *program, + const struct rpc_program *program, u32 vers) { struct rpc_clnt *clnt; - struct rpc_version *version; + const struct rpc_version *version; int err; BUG_ON(vers >= program->nrvers || !program->version[vers]); diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index d3978017b25..b1f08bd6788 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -112,7 +112,7 @@ enum { static void rpcb_getport_done(struct rpc_task *, void *); static void rpcb_map_release(void *data); -static struct rpc_program rpcb_program; +static const struct rpc_program rpcb_program; struct rpcbind_args { struct rpc_xprt * r_xprt; @@ -137,8 +137,8 @@ struct rpcb_info { struct rpc_procinfo * rpc_proc; }; -static struct rpcb_info rpcb_next_version[]; -static struct rpcb_info rpcb_next_version6[]; +static const struct rpcb_info rpcb_next_version[]; +static const struct rpcb_info rpcb_next_version6[]; static const struct rpc_call_ops rpcb_getport_ops = { .rpc_call_done = rpcb_getport_done, @@ -1051,7 +1051,7 @@ static struct rpc_procinfo rpcb_procedures4[] = { }, }; -static struct rpcb_info rpcb_next_version[] = { +static const struct rpcb_info rpcb_next_version[] = { { .rpc_vers = RPCBVERS_2, .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], @@ -1061,7 +1061,7 @@ static struct rpcb_info rpcb_next_version[] = { }, }; -static struct rpcb_info rpcb_next_version6[] = { +static const struct rpcb_info rpcb_next_version6[] = { { .rpc_vers = RPCBVERS_4, .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR], @@ -1075,25 +1075,25 @@ static struct rpcb_info rpcb_next_version6[] = { }, }; -static struct rpc_version rpcb_version2 = { +static const struct rpc_version rpcb_version2 = { .number = RPCBVERS_2, .nrprocs = ARRAY_SIZE(rpcb_procedures2), .procs = rpcb_procedures2 }; -static struct rpc_version rpcb_version3 = { +static const struct rpc_version rpcb_version3 = { .number = RPCBVERS_3, .nrprocs = ARRAY_SIZE(rpcb_procedures3), .procs = rpcb_procedures3 }; -static struct rpc_version rpcb_version4 = { +static const struct rpc_version rpcb_version4 = { .number = RPCBVERS_4, .nrprocs = ARRAY_SIZE(rpcb_procedures4), .procs = rpcb_procedures4 }; -static struct rpc_version *rpcb_version[] = { +static const struct rpc_version *rpcb_version[] = { NULL, NULL, &rpcb_version2, @@ -1103,7 +1103,7 @@ static struct rpc_version *rpcb_version[] = { static struct rpc_stat rpcb_stats; -static struct rpc_program rpcb_program = { +static const struct rpc_program rpcb_program = { .name = "rpcbind", .number = RPCBIND_PROGRAM, .nrvers = ARRAY_SIZE(rpcb_version), -- cgit v1.2.3-70-g09d2 From 82b0a4c3c171b180629696e8d1d5f52516f711e6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 20 Jan 2012 14:52:23 -0500 Subject: SUNRPC: Add trace events to the sunrpc subsystem Add declarations to allow tracing of RPC call creation, running, sleeping, and destruction. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 2 +- include/trace/events/sunrpc.h | 124 ++++++++++++++++++++++++++++++++++++++++++ net/sunrpc/sched.c | 12 ++++ 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 include/trace/events/sunrpc.h (limited to 'net') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index bd337f990a4..f7b2df5252b 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -271,7 +271,7 @@ static inline int rpc_task_has_priority(struct rpc_task *task, unsigned char pri } #ifdef RPC_DEBUG -static inline const char * rpc_qname(struct rpc_wait_queue *q) +static inline const char * rpc_qname(const struct rpc_wait_queue *q) { return ((q && q->name) ? q->name : "unknown"); } diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h new file mode 100644 index 00000000000..51cc9490919 --- /dev/null +++ b/include/trace/events/sunrpc.h @@ -0,0 +1,124 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM sunrpc + +#if !defined(_TRACE_SUNRPC_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SUNRPC_H + +#include +#include +#include + +DECLARE_EVENT_CLASS(rpc_task_running, + + TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), + + TP_ARGS(clnt, task, action), + + TP_STRUCT__entry( + __field(const struct rpc_clnt *, clnt) + __field(const struct rpc_task *, task) + __field(const void *, action) + __field(unsigned long, runstate) + __field(int, status) + __field(unsigned short, flags) + ), + + TP_fast_assign( + __entry->clnt = clnt; + __entry->task = task; + __entry->action = action; + __entry->runstate = task->tk_runstate; + __entry->status = task->tk_status; + __entry->flags = task->tk_flags; + ), + + TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d action=%pf", + __entry->task, + __entry->clnt, + __entry->flags, + __entry->runstate, + __entry->status, + __entry->action + ) +); + +DEFINE_EVENT(rpc_task_running, rpc_task_begin, + + TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), + + TP_ARGS(clnt, task, action) + +); + +DEFINE_EVENT(rpc_task_running, rpc_task_run_action, + + TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), + + TP_ARGS(clnt, task, action) + +); + +DEFINE_EVENT(rpc_task_running, rpc_task_complete, + + TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), + + TP_ARGS(clnt, task, action) + +); + +DECLARE_EVENT_CLASS(rpc_task_queued, + + TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q), + + TP_ARGS(clnt, task, q), + + TP_STRUCT__entry( + __field(const struct rpc_clnt *, clnt) + __field(const struct rpc_task *, task) + __field(const struct rpc_wait_queue *, queue) + __field(unsigned long, timeout) + __field(unsigned long, runstate) + __field(int, status) + __field(unsigned short, flags) + ), + + TP_fast_assign( + __entry->clnt = clnt; + __entry->task = task; + __entry->queue = q; + __entry->timeout = task->tk_timeout; + __entry->runstate = task->tk_runstate; + __entry->status = task->tk_status; + __entry->flags = task->tk_flags; + ), + + TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d timeout=%lu queue=%s", + __entry->task, + __entry->clnt, + __entry->flags, + __entry->runstate, + __entry->status, + __entry->timeout, + rpc_qname(__entry->queue) + ) +); + +DEFINE_EVENT(rpc_task_queued, rpc_task_sleep, + + TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q), + + TP_ARGS(clnt, task, q) + +); + +DEFINE_EVENT(rpc_task_queued, rpc_task_wakeup, + + TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q), + + TP_ARGS(clnt, task, q) + +); + +#endif /* _TRACE_SUNRPC_H */ + +#include diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index f982dfe5399..d79c63df49b 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -28,6 +28,9 @@ #define RPCDBG_FACILITY RPCDBG_SCHED #endif +#define CREATE_TRACE_POINTS +#include + /* * RPC slabs and memory pools */ @@ -251,6 +254,8 @@ static inline void rpc_task_set_debuginfo(struct rpc_task *task) static void rpc_set_active(struct rpc_task *task) { + trace_rpc_task_begin(task->tk_client, task, NULL); + rpc_task_set_debuginfo(task); set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); } @@ -267,6 +272,8 @@ static int rpc_complete_task(struct rpc_task *task) unsigned long flags; int ret; + trace_rpc_task_complete(task->tk_client, task, NULL); + spin_lock_irqsave(&wq->lock, flags); clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); ret = atomic_dec_and_test(&task->tk_count); @@ -324,6 +331,8 @@ static void __rpc_sleep_on_priority(struct rpc_wait_queue *q, dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", task->tk_pid, rpc_qname(q), jiffies); + trace_rpc_task_sleep(task->tk_client, task, q); + __rpc_add_wait_queue(q, task, queue_priority); BUG_ON(task->tk_callback != NULL); @@ -378,6 +387,8 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task return; } + trace_rpc_task_wakeup(task->tk_client, task, queue); + __rpc_remove_wait_queue(queue, task); rpc_make_runnable(task); @@ -701,6 +712,7 @@ static void __rpc_execute(struct rpc_task *task) if (do_action == NULL) break; } + trace_rpc_task_run_action(task->tk_client, task, task->tk_action); do_action(task); /* -- cgit v1.2.3-70-g09d2 From d3b773e4fd80524ac27802fcf11cfd9ed1d5491f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 23 Jan 2012 13:22:45 -0500 Subject: SUNRPC: fixup for namespace changes Fixes this build error when CONFIG_NET_NS is not set: net/sunrpc/svcsock.c: In function 'svc_setup_socket': net/sunrpc/svcsock.c:1412:40: error: 'struct sock_common' has no member named 'skc_net' Reported-by: Stephen Rothwell Signed-off-by: Trond Myklebust --- net/sunrpc/svcsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index e8af0c9e436..e088b1633d3 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1409,7 +1409,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, /* Register socket with portmapper */ if (*errp >= 0 && pmap_register) - *errp = svc_register(serv, sock->sk->sk_net, inet->sk_family, + *errp = svc_register(serv, sock_net(sock->sk), inet->sk_family, inet->sk_protocol, ntohs(inet_sk(inet)->inet_sport)); -- cgit v1.2.3-70-g09d2 From a8afca032998850ec63e83d555cdcf0eb5680cd6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 31 Jan 2012 18:45:40 +0000 Subject: tcp: md5: protects md5sig_info with RCU This patch makes sure we use appropriate memory barriers before publishing tp->md5sig_info, allowing tcp_md5_do_lookup() being used from tcp_v4_send_reset() without holding socket lock (upcoming patch from Shawn Lu) Note we also need to respect rcu grace period before its freeing, since we can free socket without this grace period thanks to SLAB_DESTROY_BY_RCU Signed-off-by: Eric Dumazet Cc: Shawn Lu Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 +- include/net/tcp.h | 1 + net/ipv4/tcp_ipv4.c | 32 ++++++++++++++++++++------------ net/ipv6/tcp_ipv6.c | 2 -- 4 files changed, 22 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index c2025f15964..115389e9b94 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -463,7 +463,7 @@ struct tcp_sock { const struct tcp_sock_af_ops *af_specific; /* TCP MD5 Signature Option information */ - struct tcp_md5sig_info *md5sig_info; + struct tcp_md5sig_info __rcu *md5sig_info; #endif /* When the cookie options are generated and exchanged, then this diff --git a/include/net/tcp.h b/include/net/tcp.h index 10ae4c7b6b4..78880ba0f56 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1150,6 +1150,7 @@ struct tcp_md5sig_key { /* - sock block */ struct tcp_md5sig_info { struct hlist_head head; + struct rcu_head rcu; }; /* - pseudo header */ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index da5d3226771..567cca9b30d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -879,14 +879,18 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk, struct tcp_md5sig_key *key; struct hlist_node *pos; unsigned int size = sizeof(struct in_addr); + struct tcp_md5sig_info *md5sig; - if (!tp->md5sig_info) + /* caller either holds rcu_read_lock() or socket lock */ + md5sig = rcu_dereference_check(tp->md5sig_info, + sock_owned_by_user(sk)); + if (!md5sig) return NULL; #if IS_ENABLED(CONFIG_IPV6) if (family == AF_INET6) size = sizeof(struct in6_addr); #endif - hlist_for_each_entry_rcu(key, pos, &tp->md5sig_info->head, node) { + hlist_for_each_entry_rcu(key, pos, &md5sig->head, node) { if (key->family != family) continue; if (!memcmp(&key->addr, addr, size)) @@ -932,7 +936,8 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, return 0; } - md5sig = tp->md5sig_info; + md5sig = rcu_dereference_protected(tp->md5sig_info, + sock_owned_by_user(sk)); if (!md5sig) { md5sig = kmalloc(sizeof(*md5sig), gfp); if (!md5sig) @@ -940,7 +945,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, sk_nocaps_add(sk, NETIF_F_GSO_MASK); INIT_HLIST_HEAD(&md5sig->head); - tp->md5sig_info = md5sig; + rcu_assign_pointer(tp->md5sig_info, md5sig); } key = sock_kmalloc(sk, sizeof(*key), gfp); @@ -966,6 +971,7 @@ int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) { struct tcp_sock *tp = tcp_sk(sk); struct tcp_md5sig_key *key; + struct tcp_md5sig_info *md5sig; key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET); if (!key) @@ -973,7 +979,9 @@ int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) hlist_del_rcu(&key->node); atomic_sub(sizeof(*key), &sk->sk_omem_alloc); kfree_rcu(key, rcu); - if (hlist_empty(&tp->md5sig_info->head)) + md5sig = rcu_dereference_protected(tp->md5sig_info, + sock_owned_by_user(sk)); + if (hlist_empty(&md5sig->head)) tcp_free_md5sig_pool(); return 0; } @@ -984,10 +992,13 @@ void tcp_clear_md5_list(struct sock *sk) struct tcp_sock *tp = tcp_sk(sk); struct tcp_md5sig_key *key; struct hlist_node *pos, *n; + struct tcp_md5sig_info *md5sig; - if (!hlist_empty(&tp->md5sig_info->head)) + md5sig = rcu_dereference_protected(tp->md5sig_info, 1); + + if (!hlist_empty(&md5sig->head)) tcp_free_md5sig_pool(); - hlist_for_each_entry_safe(key, pos, n, &tp->md5sig_info->head, node) { + hlist_for_each_entry_safe(key, pos, n, &md5sig->head, node) { hlist_del_rcu(&key->node); atomic_sub(sizeof(*key), &sk->sk_omem_alloc); kfree_rcu(key, rcu); @@ -1009,12 +1020,9 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, if (sin->sin_family != AF_INET) return -EINVAL; - if (!cmd.tcpm_key || !cmd.tcpm_keylen) { - if (!tcp_sk(sk)->md5sig_info) - return -ENOENT; + if (!cmd.tcpm_key || !cmd.tcpm_keylen) return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, AF_INET); - } if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) return -EINVAL; @@ -1896,7 +1904,7 @@ void tcp_v4_destroy_sock(struct sock *sk) /* Clean up the MD5 key list, if any */ if (tp->md5sig_info) { tcp_clear_md5_list(sk); - kfree(tp->md5sig_info); + kfree_rcu(tp->md5sig_info, rcu); tp->md5sig_info = NULL; } #endif diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index bec41f9a641..c25018106ef 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -571,8 +571,6 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, return -EINVAL; if (!cmd.tcpm_keylen) { - if (!tcp_sk(sk)->md5sig_info) - return -ENOENT; if (ipv6_addr_v4mapped(&sin6->sin6_addr)) return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], AF_INET); -- cgit v1.2.3-70-g09d2 From 5b11b2e4bdef20e839d90dce96c5bbeafaf9616c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 31 Jan 2012 21:45:26 +0000 Subject: xfrm6: remove unneeded NULL check in __xfrm6_output() We don't check for NULL consistently in __xfrm6_output(). If "x" were NULL here it would lead to an OOPs later. I asked Steffen Klassert about this and he suggested that we remove the NULL check. On 10/29/11, Steffen Klassert wrote: >> net/ipv6/xfrm6_output.c >> 148 >> 149 if ((x && x->props.mode == XFRM_MODE_TUNNEL) && >> ^ > > x can't be null here. It would be a bug if __xfrm6_output() is called > without a xfrm_state attached to the skb. I think we can just remove > this null check. Cc: Steffen Klassert Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/ipv6/xfrm6_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 4eeff89c1aa..8755a3079d0 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -146,7 +146,7 @@ static int __xfrm6_output(struct sk_buff *skb) return -EMSGSIZE; } - if ((x && x->props.mode == XFRM_MODE_TUNNEL) && + if (x->props.mode == XFRM_MODE_TUNNEL && ((skb->len > mtu && !skb_is_gso(skb)) || dst_allfrag(skb_dst(skb)))) { return ip6_fragment(skb, x->outer_mode->afinfo->output_finish); -- cgit v1.2.3-70-g09d2 From 658ddaaf6694adf63f67451dec9ddeb87a7cb2d7 Mon Sep 17 00:00:00 2001 From: Shawn Lu Date: Tue, 31 Jan 2012 22:35:48 +0000 Subject: tcp: md5: RST: getting md5 key from listener TCP RST mechanism is broken in TCP md5(RFC2385). When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp to fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listener on both sides to accept connection from peer. md5 keys for peers are saved in listening socket. There are two cases in finding md5 key when connection is lost: 1.Passive receive RST: The message is send to well known port, tcp will associate it with listner. md5 key is gotten from listener. 2.Active receive RST (no sock): The message is send to ative side, there is no socket associated with the message. In this case, finding listener from source port, then find md5 key from listener. we are not loosing sercuriy here: packet is checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Signed-off-by: Shawn Lu Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- net/ipv6/tcp_ipv6.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 567cca9b30d..90e47931e21 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -593,6 +593,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; + const __u8 *hash_location = NULL; + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; #endif struct net *net; @@ -623,9 +627,36 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_md5_do_lookup(sk, - (union tcp_md5_addr *)&ip_hdr(skb)->saddr, - AF_INET) : NULL; + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, ip_hdr(skb)->daddr, + ntohs(th->source), inet_iif(skb)); + /* don't send rst if it can't find key */ + if (!sk1) + return; + rcu_read_lock(); + key = tcp_md5_do_lookup(sk1, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, AF_INET); + if (!key) + goto release_sk1; + + genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_md5_do_lookup(sk, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, + AF_INET) : NULL; + } + if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -653,6 +684,14 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) { + rcu_read_unlock(); + sock_put(sk1); + } +#endif } /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c25018106ef..d16414cb342 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -923,6 +923,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); u32 seq = 0, ack_seq = 0; struct tcp_md5sig_key *key = NULL; +#ifdef CONFIG_TCP_MD5SIG + const __u8 *hash_location = NULL; + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; +#endif if (th->rst) return; @@ -931,8 +938,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) return; #ifdef CONFIG_TCP_MD5SIG - if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, &ipv6h->daddr, + ntohs(th->source), inet6_iif(skb)); + if (!sk1) + return; + + rcu_read_lock(); + key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr); + if (!key) + goto release_sk1; + + genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; + } #endif if (th->ack) @@ -942,6 +973,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) (th->doff << 2); tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) { + rcu_read_unlock(); + sock_put(sk1); + } +#endif } static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, -- cgit v1.2.3-70-g09d2 From e6ec26935aec629f03e76c67f3bbda68dd0155e2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 29 Jan 2012 15:50:43 +0000 Subject: netpoll: Convert printks to np_ and add pr_fmt Use a more current message logging style. Add pr_fmt to prefix dmesg output with "netpoll: " Add macros to print np->name. Signed-off-by: Joe Perches Reviewed-by: WANG Cong Signed-off-by: David S. Miller --- net/core/netpoll.c | 63 ++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 556b0829866..b5232743d5d 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -9,6 +9,8 @@ * Copyright (C) 2002 Red Hat, Inc. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -55,6 +57,13 @@ static void arp_reply(struct sk_buff *skb); static unsigned int carrier_timeout = 4; module_param(carrier_timeout, uint, 0644); +#define np_info(np, fmt, ...) \ + pr_info("%s: " fmt, np->name, ##__VA_ARGS__) +#define np_err(np, fmt, ...) \ + pr_err("%s: " fmt, np->name, ##__VA_ARGS__) +#define np_notice(np, fmt, ...) \ + pr_notice("%s: " fmt, np->name, ##__VA_ARGS__) + static void queue_process(struct work_struct *work) { struct netpoll_info *npinfo = @@ -627,18 +636,12 @@ out: void netpoll_print_options(struct netpoll *np) { - printk(KERN_INFO "%s: local port %d\n", - np->name, np->local_port); - printk(KERN_INFO "%s: local IP %pI4\n", - np->name, &np->local_ip); - printk(KERN_INFO "%s: interface '%s'\n", - np->name, np->dev_name); - printk(KERN_INFO "%s: remote port %d\n", - np->name, np->remote_port); - printk(KERN_INFO "%s: remote IP %pI4\n", - np->name, &np->remote_ip); - printk(KERN_INFO "%s: remote ethernet address %pM\n", - np->name, np->remote_mac); + np_info(np, "local port %d\n", np->local_port); + np_info(np, "local IP %pI4\n", &np->local_ip); + np_info(np, "interface '%s'\n", np->dev_name); + np_info(np, "remote port %d\n", np->remote_port); + np_info(np, "remote IP %pI4\n", &np->remote_ip); + np_info(np, "remote ethernet address %pM\n", np->remote_mac); } EXPORT_SYMBOL(netpoll_print_options); @@ -680,8 +683,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) goto parse_failed; *delim = 0; if (*cur == ' ' || *cur == '\t') - printk(KERN_INFO "%s: warning: whitespace" - "is not allowed\n", np->name); + np_info(np, "warning: whitespace is not allowed\n"); np->remote_port = simple_strtol(cur, NULL, 10); cur = delim; } @@ -705,8 +707,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) return 0; parse_failed: - printk(KERN_INFO "%s: couldn't parse config at '%s'!\n", - np->name, cur); + np_info(np, "couldn't parse config at '%s'!\n", cur); return -1; } EXPORT_SYMBOL(netpoll_parse_options); @@ -721,8 +722,8 @@ int __netpoll_setup(struct netpoll *np) if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) || !ndev->netdev_ops->ndo_poll_controller) { - printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", - np->name, np->dev_name); + np_err(np, "%s doesn't support polling, aborting\n", + np->dev_name); err = -ENOTSUPP; goto out; } @@ -785,14 +786,12 @@ int netpoll_setup(struct netpoll *np) if (np->dev_name) ndev = dev_get_by_name(&init_net, np->dev_name); if (!ndev) { - printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", - np->name, np->dev_name); + np_err(np, "%s doesn't exist, aborting\n", np->dev_name); return -ENODEV; } if (ndev->master) { - printk(KERN_ERR "%s: %s is a slave device, aborting.\n", - np->name, np->dev_name); + np_err(np, "%s is a slave device, aborting\n", np->dev_name); err = -EBUSY; goto put; } @@ -800,16 +799,14 @@ int netpoll_setup(struct netpoll *np) if (!netif_running(ndev)) { unsigned long atmost, atleast; - printk(KERN_INFO "%s: device %s not up yet, forcing it\n", - np->name, np->dev_name); + np_info(np, "device %s not up yet, forcing it\n", np->dev_name); rtnl_lock(); err = dev_open(ndev); rtnl_unlock(); if (err) { - printk(KERN_ERR "%s: failed to open %s\n", - np->name, ndev->name); + np_err(np, "failed to open %s\n", ndev->name); goto put; } @@ -817,9 +814,7 @@ int netpoll_setup(struct netpoll *np) atmost = jiffies + carrier_timeout * HZ; while (!netif_carrier_ok(ndev)) { if (time_after(jiffies, atmost)) { - printk(KERN_NOTICE - "%s: timeout waiting for carrier\n", - np->name); + np_notice(np, "timeout waiting for carrier\n"); break; } msleep(1); @@ -831,9 +826,7 @@ int netpoll_setup(struct netpoll *np) */ if (time_before(jiffies, atleast)) { - printk(KERN_NOTICE "%s: carrier detect appears" - " untrustworthy, waiting 4 seconds\n", - np->name); + np_notice(np, "carrier detect appears untrustworthy, waiting 4 seconds\n"); msleep(4000); } } @@ -844,15 +837,15 @@ int netpoll_setup(struct netpoll *np) if (!in_dev || !in_dev->ifa_list) { rcu_read_unlock(); - printk(KERN_ERR "%s: no IP address for %s, aborting\n", - np->name, np->dev_name); + np_err(np, "no IP address for %s, aborting\n", + np->dev_name); err = -EDESTADDRREQ; goto put; } np->local_ip = in_dev->ifa_list->ifa_local; rcu_read_unlock(); - printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip); + np_info(np, "local IP %pI4\n", &np->local_ip); } np->dev = ndev; -- cgit v1.2.3-70-g09d2 From 6f7062457fc98e1fa22f74d8f386ed241213dec6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 29 Jan 2012 15:50:44 +0000 Subject: netpoll: Neaten MAX_SKB_SIZE macro Add the types in the packet layout order. Signed-off-by: Joe Perches Reviewed-by: WANG Cong Signed-off-by: David S. Miller --- net/core/netpoll.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/netpoll.c b/net/core/netpoll.c index b5232743d5d..4ce473ea5dc 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -47,9 +47,11 @@ static atomic_t trapped; #define NETPOLL_RX_ENABLED 1 #define NETPOLL_RX_DROP 2 -#define MAX_SKB_SIZE \ - (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ - sizeof(struct iphdr) + sizeof(struct ethhdr)) +#define MAX_SKB_SIZE \ + (sizeof(struct ethhdr) + \ + sizeof(struct iphdr) + \ + sizeof(struct udphdr) + \ + MAX_UDP_CHUNK) static void zap_completion_queue(void); static void arp_reply(struct sk_buff *skb); -- cgit v1.2.3-70-g09d2 From 7b6cd1ce72176e21be15a0ac153bdaa5be1b208a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 1 Feb 2012 10:54:43 +0000 Subject: PATCH V2 net-next] net: dev: Convert printks to pr_ Use the current logging style. Coalesce formats where appropriate. Update grammar where appropriate. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/core/dev.c | 94 ++++++++++++++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 55 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 115dee1d985..f1249472e90 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -446,7 +446,7 @@ void __dev_remove_pack(struct packet_type *pt) } } - printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt); + pr_warn("dev_remove_pack: %p not found\n", pt); out: spin_unlock(&ptype_lock); } @@ -1039,8 +1039,7 @@ rollback: memcpy(dev->name, oldname, IFNAMSIZ); goto rollback; } else { - printk(KERN_ERR - "%s: name change rollback failed: %d.\n", + pr_err("%s: name change rollback failed: %d\n", dev->name, ret); } } @@ -1139,9 +1138,8 @@ void dev_load(struct net *net, const char *name) no_module = request_module("netdev-%s", name); if (no_module && capable(CAP_SYS_MODULE)) { if (!request_module("%s", name)) - pr_err("Loading kernel module for a network device " -"with CAP_SYS_MODULE (deprecated). Use CAP_NET_ADMIN and alias netdev-%s " -"instead\n", name); + pr_err("Loading kernel module for a network device with CAP_SYS_MODULE (deprecated). Use CAP_NET_ADMIN and alias netdev-%s instead.\n", + name); } } EXPORT_SYMBOL(dev_load); @@ -1655,10 +1653,9 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) if (skb_network_header(skb2) < skb2->data || skb2->network_header > skb2->tail) { if (net_ratelimit()) - printk(KERN_CRIT "protocol %04x is " - "buggy, dev %s\n", - ntohs(skb2->protocol), - dev->name); + pr_crit("protocol %04x is buggy, dev %s\n", + ntohs(skb2->protocol), + dev->name); skb_reset_network_header(skb2); } @@ -1691,9 +1688,7 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq) /* If TC0 is invalidated disable TC mapping */ if (tc->offset + tc->count > txq) { - pr_warning("Number of in use tx queues changed " - "invalidating tc mappings. Priority " - "traffic classification disabled!\n"); + pr_warn("Number of in use tx queues changed invalidating tc mappings. Priority traffic classification disabled!\n"); dev->num_tc = 0; return; } @@ -1704,11 +1699,8 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq) tc = &dev->tc_to_txq[q]; if (tc->offset + tc->count > txq) { - pr_warning("Number of in use tx queues " - "changed. Priority %i to tc " - "mapping %i is no longer valid " - "setting map to 0\n", - i, q); + pr_warn("Number of in use tx queues changed. Priority %i to tc mapping %i is no longer valid. Setting map to 0\n", + i, q); netdev_set_prio_tc_map(dev, i, 0); } } @@ -2014,8 +2006,7 @@ EXPORT_SYMBOL(skb_gso_segment); void netdev_rx_csum_fault(struct net_device *dev) { if (net_ratelimit()) { - printk(KERN_ERR "%s: hw csum failure.\n", - dev ? dev->name : ""); + pr_err("%s: hw csum failure\n", dev ? dev->name : ""); dump_stack(); } } @@ -2332,9 +2323,9 @@ static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index) { if (unlikely(queue_index >= dev->real_num_tx_queues)) { if (net_ratelimit()) { - pr_warning("%s selects TX queue %d, but " - "real number of TX queues is %d\n", - dev->name, queue_index, dev->real_num_tx_queues); + pr_warn("%s selects TX queue %d, but real number of TX queues is %d\n", + dev->name, queue_index, + dev->real_num_tx_queues); } return 0; } @@ -2578,16 +2569,16 @@ int dev_queue_xmit(struct sk_buff *skb) } HARD_TX_UNLOCK(dev, txq); if (net_ratelimit()) - printk(KERN_CRIT "Virtual device %s asks to " - "queue packet!\n", dev->name); + pr_crit("Virtual device %s asks to queue packet!\n", + dev->name); } else { /* Recursion is detected! It is possible, * unfortunately */ recursion_alert: if (net_ratelimit()) - printk(KERN_CRIT "Dead loop on virtual device " - "%s, fix it urgently!\n", dev->name); + pr_crit("Dead loop on virtual device %s, fix it urgently!\n", + dev->name); } } @@ -3069,8 +3060,8 @@ static int ing_filter(struct sk_buff *skb, struct netdev_queue *rxq) if (unlikely(MAX_RED_LOOP < ttl++)) { if (net_ratelimit()) - pr_warning( "Redir loop detected Dropping packet (%d->%d)\n", - skb->skb_iif, dev->ifindex); + pr_warn("Redir loop detected Dropping packet (%d->%d)\n", + skb->skb_iif, dev->ifindex); return TC_ACT_SHOT; } @@ -4491,16 +4482,15 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc) dev->flags &= ~IFF_PROMISC; else { dev->promiscuity -= inc; - printk(KERN_WARNING "%s: promiscuity touches roof, " - "set promiscuity failed, promiscuity feature " - "of device might be broken.\n", dev->name); + pr_warn("%s: promiscuity touches roof, set promiscuity failed. promiscuity feature of device might be broken.\n", + dev->name); return -EOVERFLOW; } } if (dev->flags != old_flags) { - printk(KERN_INFO "device %s %s promiscuous mode\n", - dev->name, (dev->flags & IFF_PROMISC) ? "entered" : - "left"); + pr_info("device %s %s promiscuous mode\n", + dev->name, + dev->flags & IFF_PROMISC ? "entered" : "left"); if (audit_enabled) { current_uid_gid(&uid, &gid); audit_log(current->audit_context, GFP_ATOMIC, @@ -4573,9 +4563,8 @@ int dev_set_allmulti(struct net_device *dev, int inc) dev->flags &= ~IFF_ALLMULTI; else { dev->allmulti -= inc; - printk(KERN_WARNING "%s: allmulti touches roof, " - "set allmulti failed, allmulti feature of " - "device might be broken.\n", dev->name); + pr_warn("%s: allmulti touches roof, set allmulti failed. allmulti feature of device might be broken.\n", + dev->name); return -EOVERFLOW; } } @@ -5232,8 +5221,8 @@ static void rollback_registered_many(struct list_head *head) * devices and proceed with the remaining. */ if (dev->reg_state == NETREG_UNINITIALIZED) { - pr_debug("unregister_netdevice: device %s/%p never " - "was registered\n", dev->name, dev); + pr_debug("unregister_netdevice: device %s/%p never was registered\n", + dev->name, dev); WARN_ON(1); list_del(&dev->unreg_list); @@ -5465,7 +5454,7 @@ static int netif_alloc_rx_queues(struct net_device *dev) rx = kcalloc(count, sizeof(struct netdev_rx_queue), GFP_KERNEL); if (!rx) { - pr_err("netdev: Unable to allocate %u rx queues.\n", count); + pr_err("netdev: Unable to allocate %u rx queues\n", count); return -ENOMEM; } dev->_rx = rx; @@ -5499,8 +5488,7 @@ static int netif_alloc_netdev_queues(struct net_device *dev) tx = kcalloc(count, sizeof(struct netdev_queue), GFP_KERNEL); if (!tx) { - pr_err("netdev: Unable to allocate %u tx queues.\n", - count); + pr_err("netdev: Unable to allocate %u tx queues\n", count); return -ENOMEM; } dev->_tx = tx; @@ -5759,10 +5747,8 @@ static void netdev_wait_allrefs(struct net_device *dev) refcnt = netdev_refcnt_read(dev); if (time_after(jiffies, warning_time + 10 * HZ)) { - printk(KERN_EMERG "unregister_netdevice: " - "waiting for %s to become free. Usage " - "count = %d\n", - dev->name, refcnt); + pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n", + dev->name, refcnt); warning_time = jiffies; } } @@ -5813,7 +5799,7 @@ void netdev_run_todo(void) list_del(&dev->todo_list); if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { - printk(KERN_ERR "network todo '%s' but state %d\n", + pr_err("network todo '%s' but state %d\n", dev->name, dev->reg_state); dump_stack(); continue; @@ -5929,15 +5915,13 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, BUG_ON(strlen(name) >= sizeof(dev->name)); if (txqs < 1) { - pr_err("alloc_netdev: Unable to allocate device " - "with zero queues.\n"); + pr_err("alloc_netdev: Unable to allocate device with zero queues\n"); return NULL; } #ifdef CONFIG_RPS if (rxqs < 1) { - pr_err("alloc_netdev: Unable to allocate device " - "with zero RX queues.\n"); + pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n"); return NULL; } #endif @@ -5953,7 +5937,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, p = kzalloc(alloc_size, GFP_KERNEL); if (!p) { - printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n"); + pr_err("alloc_netdev: Unable to allocate device\n"); return NULL; } @@ -6486,8 +6470,8 @@ static void __net_exit default_device_exit(struct net *net) snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex); err = dev_change_net_namespace(dev, &init_net, fb_name); if (err) { - printk(KERN_EMERG "%s: failed to move %s to init_net: %d\n", - __func__, dev->name, err); + pr_emerg("%s: failed to move %s to init_net: %d\n", + __func__, dev->name, err); BUG(); } } -- cgit v1.2.3-70-g09d2 From f79d52c254e4e2cef3da64dc02ade3bc8f10c539 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Feb 2012 16:14:17 -0500 Subject: ipv6: Remove never used function inet6_ac_check(). It went from unused, to commented out, and never changing after that. Just get rid of it, if someone wants it they can unearth it from the history. Signed-off-by: David S. Miller --- include/net/addrconf.h | 1 - net/ipv6/anycast.c | 29 ----------------------------- 2 files changed, 30 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index f68dce2d8d8..757a17638b1 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -160,7 +160,6 @@ extern void addrconf_prefix_rcv(struct net_device *dev, extern int ipv6_sock_ac_join(struct sock *sk,int ifindex, const struct in6_addr *addr); extern int ipv6_sock_ac_drop(struct sock *sk,int ifindex, const struct in6_addr *addr); extern void ipv6_sock_ac_close(struct sock *sk); -extern int inet6_ac_check(struct sock *sk, const struct in6_addr *addr, int ifindex); extern int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr); extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 59402b4637f..db00d27ffb1 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -211,35 +211,6 @@ void ipv6_sock_ac_close(struct sock *sk) rcu_read_unlock(); } -#if 0 -/* The function is not used, which is funny. Apparently, author - * supposed to use it to filter out datagrams inside udp/raw but forgot. - * - * It is OK, anycasts are not special comparing to delivery to unicasts. - */ - -int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex) -{ - struct ipv6_ac_socklist *pac; - struct ipv6_pinfo *np = inet6_sk(sk); - int found; - - found = 0; - read_lock(&ipv6_sk_ac_lock); - for (pac=np->ipv6_ac_list; pac; pac=pac->acl_next) { - if (ifindex && pac->acl_ifindex != ifindex) - continue; - found = ipv6_addr_equal(&pac->acl_addr, addr); - if (found) - break; - } - read_unlock(&ipv6_sk_ac_lock); - - return found; -} - -#endif - static void aca_put(struct ifacaddr6 *ac) { if (atomic_dec_and_test(&ac->aca_refcnt)) { -- cgit v1.2.3-70-g09d2 From 3329bdfc4071840816d6666c6463fdb0bd4c8264 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Feb 2012 16:34:25 -0500 Subject: decnet: Add missing neigh->ha locking to dn_neigh_output_packet() Basically, mirror the logic in neigh_connected_output(). Signed-off-by: David S. Miller --- net/decnet/dn_neigh.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index befe426491b..ee7013f24fc 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -205,17 +205,23 @@ static int dn_neigh_output_packet(struct sk_buff *skb) struct neighbour *neigh = dst_get_neighbour_noref(dst); struct net_device *dev = neigh->dev; char mac_addr[ETH_ALEN]; + unsigned int seq; + int err; dn_dn2eth(mac_addr, rt->rt_local_src); - if (dev_hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, - mac_addr, skb->len) >= 0) - return dev_queue_xmit(skb); - - if (net_ratelimit()) - printk(KERN_DEBUG "dn_neigh_output_packet: oops, can't send packet\n"); - - kfree_skb(skb); - return -EINVAL; + do { + seq = read_seqbegin(&neigh->ha_lock); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + neigh->ha, mac_addr, skb->len); + } while (read_seqretry(&neigh->ha_lock, seq)); + + if (err >= 0) + err = dev_queue_xmit(skb); + else { + kfree_skb(skb); + err = -EINVAL; + } + return err; } static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 7161c76f0def54f5dc7fd9a5534bb3e3e2b2aa60 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Feb 2012 17:23:11 -0500 Subject: atm: clip: Convert over to dst_neigh_lookup(). CLIP only support ipv4, and this is evidenced by the fact that it is a device specific extension of arp_tbl, so this conversion is pretty straightforward. Signed-off-by: David S. Miller --- net/atm/clip.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/atm/clip.c b/net/atm/clip.c index c12c2582457..ef95a30306f 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -328,6 +328,8 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, struct atmarp_entry *entry; struct neighbour *n; struct atm_vcc *vcc; + struct rtable *rt; + __be32 *daddr; int old; unsigned long flags; @@ -338,7 +340,12 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, dev->stats.tx_dropped++; return NETDEV_TX_OK; } - n = dst_get_neighbour_noref(dst); + rt = (struct rtable *) dst; + if (rt->rt_gateway) + daddr = &rt->rt_gateway; + else + daddr = &ip_hdr(skb)->daddr; + n = dst_neigh_lookup(dst, daddr); if (!n) { pr_err("NO NEIGHBOUR !\n"); dev_kfree_skb(skb); @@ -358,7 +365,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, dev_kfree_skb(skb); dev->stats.tx_dropped++; } - return NETDEV_TX_OK; + goto out_release_neigh; } pr_debug("neigh %p, vccs %p\n", entry, entry->vccs); ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; @@ -377,14 +384,14 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */ if (old) { pr_warning("XOFF->XOFF transition\n"); - return NETDEV_TX_OK; + goto out_release_neigh; } dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; vcc->send(vcc, skb); if (atm_may_send(vcc, 0)) { entry->vccs->xoff = 0; - return NETDEV_TX_OK; + goto out_release_neigh; } spin_lock_irqsave(&clip_priv->xoff_lock, flags); netif_stop_queue(dev); /* XOFF -> throttle immediately */ @@ -396,6 +403,8 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, of the brief netif_stop_queue. If this isn't true or if it changes, use netif_wake_queue instead. */ spin_unlock_irqrestore(&clip_priv->xoff_lock, flags); +out_release_neigh: + neigh_release(n); return NETDEV_TX_OK; } -- cgit v1.2.3-70-g09d2 From 761b3ef50e1c2649cffbfa67a4dcb2dcdb7982ed Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Tue, 31 Jan 2012 13:47:36 +0800 Subject: cgroup: remove cgroup_subsys argument from callbacks The argument is not used at all, and it's not necessary, because a specific callback handler of course knows which subsys it belongs to. Now only ->pupulate() takes this argument, because the handlers of this callback always call cgroup_add_file()/cgroup_add_files(). So we reduce a few lines of code, though the shrinking of object size is minimal. 16 files changed, 113 insertions(+), 162 deletions(-) text data bss dec hex filename 5486240 656987 7039960 13183187 c928d3 vmlinux.o.orig 5486170 656987 7039960 13183117 c9288d vmlinux.o Signed-off-by: Li Zefan Signed-off-by: Tejun Heo --- Documentation/cgroups/cgroups.txt | 26 +++++++++------------ block/blk-cgroup.c | 22 +++++++----------- include/linux/cgroup.h | 29 ++++++++++------------- include/net/sock.h | 7 +++--- include/net/tcp_memcontrol.h | 2 +- kernel/cgroup.c | 43 +++++++++++++++++------------------ kernel/cgroup_freezer.c | 11 ++++----- kernel/cpuset.c | 16 ++++--------- kernel/events/core.c | 13 ++++------- kernel/sched/core.c | 20 +++++++--------- mm/memcontrol.c | 48 ++++++++++++++++----------------------- net/core/netprio_cgroup.c | 10 ++++---- net/core/sock.c | 6 ++--- net/ipv4/tcp_memcontrol.c | 2 +- net/sched/cls_cgroup.c | 10 ++++---- security/device_cgroup.c | 10 ++++---- 16 files changed, 113 insertions(+), 162 deletions(-) (limited to 'net') diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index a7c96ae5557..8e74980ab38 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -558,8 +558,7 @@ Each subsystem may export the following methods. The only mandatory methods are create/destroy. Any others that are null are presumed to be successful no-ops. -struct cgroup_subsys_state *create(struct cgroup_subsys *ss, - struct cgroup *cgrp) +struct cgroup_subsys_state *create(struct cgroup *cgrp) (cgroup_mutex held by caller) Called to create a subsystem state object for a cgroup. The @@ -574,7 +573,7 @@ identified by the passed cgroup object having a NULL parent (since it's the root of the hierarchy) and may be an appropriate place for initialization code. -void destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +void destroy(struct cgroup *cgrp) (cgroup_mutex held by caller) The cgroup system is about to destroy the passed cgroup; the subsystem @@ -585,7 +584,7 @@ cgroup->parent is still valid. (Note - can also be called for a newly-created cgroup if an error occurs after this subsystem's create() method has been called for the new cgroup). -int pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +int pre_destroy(struct cgroup *cgrp); Called before checking the reference count on each subsystem. This may be useful for subsystems which have some extra references even if @@ -593,8 +592,7 @@ there are not tasks in the cgroup. If pre_destroy() returns error code, rmdir() will fail with it. From this behavior, pre_destroy() can be called multiple times against a cgroup. -int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) (cgroup_mutex held by caller) Called prior to moving one or more tasks into a cgroup; if the @@ -615,8 +613,7 @@ fork. If this method returns 0 (success) then this should remain valid while the caller holds cgroup_mutex and it is ensured that either attach() or cancel_attach() will be called in future. -void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +void cancel_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) (cgroup_mutex held by caller) Called when a task attach operation has failed after can_attach() has succeeded. @@ -625,23 +622,22 @@ function, so that the subsystem can implement a rollback. If not, not necessary. This will be called only about subsystems whose can_attach() operation have succeeded. The parameters are identical to can_attach(). -void attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +void attach(struct cgroup *cgrp, struct cgroup_taskset *tset) (cgroup_mutex held by caller) Called after the task has been attached to the cgroup, to allow any post-attachment activity that requires memory allocations or blocking. The parameters are identical to can_attach(). -void fork(struct cgroup_subsy *ss, struct task_struct *task) +void fork(struct task_struct *task) Called when a task is forked into a cgroup. -void exit(struct cgroup_subsys *ss, struct task_struct *task) +void exit(struct task_struct *task) Called during task exit. -int populate(struct cgroup_subsys *ss, struct cgroup *cgrp) +int populate(struct cgroup *cgrp) (cgroup_mutex held by caller) Called after creation of a cgroup to allow a subsystem to populate @@ -651,7 +647,7 @@ include/linux/cgroup.h for details). Note that although this method can return an error code, the error code is currently not always handled well. -void post_clone(struct cgroup_subsys *ss, struct cgroup *cgrp) +void post_clone(struct cgroup *cgrp) (cgroup_mutex held by caller) Called during cgroup_create() to do any parameter @@ -659,7 +655,7 @@ initialization which might be required before a task could attach. For example in cpusets, no task may attach before 'cpus' and 'mems' are set up. -void bind(struct cgroup_subsys *ss, struct cgroup *root) +void bind(struct cgroup *root) (cgroup_mutex and ss->hierarchy_mutex held by caller) Called when a cgroup subsystem is rebound to a different hierarchy diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index fa8f2630944..1359d637831 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -28,13 +28,10 @@ static LIST_HEAD(blkio_list); struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT }; EXPORT_SYMBOL_GPL(blkio_root_cgroup); -static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *, - struct cgroup *); -static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *, - struct cgroup_taskset *); -static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *, - struct cgroup_taskset *); -static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *); +static struct cgroup_subsys_state *blkiocg_create(struct cgroup *); +static int blkiocg_can_attach(struct cgroup *, struct cgroup_taskset *); +static void blkiocg_attach(struct cgroup *, struct cgroup_taskset *); +static void blkiocg_destroy(struct cgroup *); static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *); /* for encoding cft->private value on file */ @@ -1548,7 +1545,7 @@ static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup) ARRAY_SIZE(blkio_files)); } -static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup) +static void blkiocg_destroy(struct cgroup *cgroup) { struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup); unsigned long flags; @@ -1598,8 +1595,7 @@ static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup) kfree(blkcg); } -static struct cgroup_subsys_state * -blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup) +static struct cgroup_subsys_state *blkiocg_create(struct cgroup *cgroup) { struct blkio_cgroup *blkcg; struct cgroup *parent = cgroup->parent; @@ -1628,8 +1624,7 @@ done: * of the main cic data structures. For now we allow a task to change * its cgroup only if it's the only owner of its ioc. */ -static int blkiocg_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +static int blkiocg_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { struct task_struct *task; struct io_context *ioc; @@ -1648,8 +1643,7 @@ static int blkiocg_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, return ret; } -static void blkiocg_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +static void blkiocg_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { struct task_struct *task; struct io_context *ioc; diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 7da3e745b74..501adb1b2f4 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -452,23 +452,18 @@ int cgroup_taskset_size(struct cgroup_taskset *tset); */ struct cgroup_subsys { - struct cgroup_subsys_state *(*create)(struct cgroup_subsys *ss, - struct cgroup *cgrp); - int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); - void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); - int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset); - void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset); - void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset); - void (*fork)(struct cgroup_subsys *ss, struct task_struct *task); - void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task); - int (*populate)(struct cgroup_subsys *ss, - struct cgroup *cgrp); - void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cgrp); - void (*bind)(struct cgroup_subsys *ss, struct cgroup *root); + struct cgroup_subsys_state *(*create)(struct cgroup *cgrp); + int (*pre_destroy)(struct cgroup *cgrp); + void (*destroy)(struct cgroup *cgrp); + int (*can_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset); + void (*cancel_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset); + void (*attach)(struct cgroup *cgrp, struct cgroup_taskset *tset); + void (*fork)(struct task_struct *task); + void (*exit)(struct cgroup *cgrp, struct cgroup *old_cgrp, + struct task_struct *task); + int (*populate)(struct cgroup_subsys *ss, struct cgroup *cgrp); + void (*post_clone)(struct cgroup *cgrp); + void (*bind)(struct cgroup *root); int subsys_id; int active; diff --git a/include/net/sock.h b/include/net/sock.h index bb972d254df..705d1add19a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -68,7 +68,7 @@ struct cgroup; struct cgroup_subsys; #ifdef CONFIG_NET int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss); -void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss); +void mem_cgroup_sockets_destroy(struct cgroup *cgrp); #else static inline int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) @@ -76,7 +76,7 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) return 0; } static inline -void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss) +void mem_cgroup_sockets_destroy(struct cgroup *cgrp) { } #endif @@ -869,8 +869,7 @@ struct proto { */ int (*init_cgroup)(struct cgroup *cgrp, struct cgroup_subsys *ss); - void (*destroy_cgroup)(struct cgroup *cgrp, - struct cgroup_subsys *ss); + void (*destroy_cgroup)(struct cgroup *cgrp); struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg); #endif }; diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h index 3512082fa90..48410ff25c9 100644 --- a/include/net/tcp_memcontrol.h +++ b/include/net/tcp_memcontrol.h @@ -13,7 +13,7 @@ struct tcp_memcontrol { struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg); int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss); -void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss); +void tcp_destroy_cgroup(struct cgroup *cgrp); unsigned long long tcp_max_memory(const struct mem_cgroup *memcg); void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx); #endif /* _TCP_MEMCG_H */ diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 43a224f167b..865d89a580c 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -818,7 +818,7 @@ static int cgroup_call_pre_destroy(struct cgroup *cgrp) for_each_subsys(cgrp->root, ss) if (ss->pre_destroy) { - ret = ss->pre_destroy(ss, cgrp); + ret = ss->pre_destroy(cgrp); if (ret) break; } @@ -846,7 +846,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) * Release the subsystem state objects. */ for_each_subsys(cgrp->root, ss) - ss->destroy(ss, cgrp); + ss->destroy(cgrp); cgrp->root->number_of_cgroups--; mutex_unlock(&cgroup_mutex); @@ -1015,7 +1015,7 @@ static int rebind_subsystems(struct cgroupfs_root *root, list_move(&ss->sibling, &root->subsys_list); ss->root = root; if (ss->bind) - ss->bind(ss, cgrp); + ss->bind(cgrp); mutex_unlock(&ss->hierarchy_mutex); /* refcount was already taken, and we're keeping it */ } else if (bit & removed_bits) { @@ -1025,7 +1025,7 @@ static int rebind_subsystems(struct cgroupfs_root *root, BUG_ON(cgrp->subsys[i]->cgroup != cgrp); mutex_lock(&ss->hierarchy_mutex); if (ss->bind) - ss->bind(ss, dummytop); + ss->bind(dummytop); dummytop->subsys[i]->cgroup = dummytop; cgrp->subsys[i] = NULL; subsys[i]->root = &rootnode; @@ -1908,7 +1908,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) for_each_subsys(root, ss) { if (ss->can_attach) { - retval = ss->can_attach(ss, cgrp, &tset); + retval = ss->can_attach(cgrp, &tset); if (retval) { /* * Remember on which subsystem the can_attach() @@ -1932,7 +1932,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) for_each_subsys(root, ss) { if (ss->attach) - ss->attach(ss, cgrp, &tset); + ss->attach(cgrp, &tset); } synchronize_rcu(); @@ -1954,7 +1954,7 @@ out: */ break; if (ss->cancel_attach) - ss->cancel_attach(ss, cgrp, &tset); + ss->cancel_attach(cgrp, &tset); } } return retval; @@ -2067,7 +2067,7 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) */ for_each_subsys(root, ss) { if (ss->can_attach) { - retval = ss->can_attach(ss, cgrp, &tset); + retval = ss->can_attach(cgrp, &tset); if (retval) { failed_ss = ss; goto out_cancel_attach; @@ -2104,7 +2104,7 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) */ for_each_subsys(root, ss) { if (ss->attach) - ss->attach(ss, cgrp, &tset); + ss->attach(cgrp, &tset); } /* @@ -2128,7 +2128,7 @@ out_cancel_attach: if (ss == failed_ss) break; if (ss->cancel_attach) - ss->cancel_attach(ss, cgrp, &tset); + ss->cancel_attach(cgrp, &tset); } } out_free_group_list: @@ -3756,7 +3756,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); for_each_subsys(root, ss) { - struct cgroup_subsys_state *css = ss->create(ss, cgrp); + struct cgroup_subsys_state *css = ss->create(cgrp); if (IS_ERR(css)) { err = PTR_ERR(css); @@ -3770,7 +3770,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, } /* At error, ->destroy() callback has to free assigned ID. */ if (clone_children(parent) && ss->post_clone) - ss->post_clone(ss, cgrp); + ss->post_clone(cgrp); } cgroup_lock_hierarchy(root); @@ -3804,7 +3804,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, for_each_subsys(root, ss) { if (cgrp->subsys[ss->subsys_id]) - ss->destroy(ss, cgrp); + ss->destroy(cgrp); } mutex_unlock(&cgroup_mutex); @@ -4028,7 +4028,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) /* Create the top cgroup state for this subsystem */ list_add(&ss->sibling, &rootnode.subsys_list); ss->root = &rootnode; - css = ss->create(ss, dummytop); + css = ss->create(dummytop); /* We don't handle early failures gracefully */ BUG_ON(IS_ERR(css)); init_cgroup_css(css, ss, dummytop); @@ -4117,7 +4117,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) * no ss->create seems to need anything important in the ss struct, so * this can happen first (i.e. before the rootnode attachment). */ - css = ss->create(ss, dummytop); + css = ss->create(dummytop); if (IS_ERR(css)) { /* failure case - need to deassign the subsys[] slot. */ subsys[i] = NULL; @@ -4135,7 +4135,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) int ret = cgroup_init_idr(ss, css); if (ret) { dummytop->subsys[ss->subsys_id] = NULL; - ss->destroy(ss, dummytop); + ss->destroy(dummytop); subsys[i] = NULL; mutex_unlock(&cgroup_mutex); return ret; @@ -4233,7 +4233,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) * pointer to find their state. note that this also takes care of * freeing the css_id. */ - ss->destroy(ss, dummytop); + ss->destroy(dummytop); dummytop->subsys[ss->subsys_id] = NULL; mutex_unlock(&cgroup_mutex); @@ -4509,7 +4509,7 @@ void cgroup_fork_callbacks(struct task_struct *child) for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) { struct cgroup_subsys *ss = subsys[i]; if (ss->fork) - ss->fork(ss, child); + ss->fork(child); } } } @@ -4611,7 +4611,7 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks) struct cgroup *old_cgrp = rcu_dereference_raw(cg->subsys[i])->cgroup; struct cgroup *cgrp = task_cgroup(tsk, i); - ss->exit(ss, cgrp, old_cgrp, tsk); + ss->exit(cgrp, old_cgrp, tsk); } } } @@ -5066,8 +5066,7 @@ struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id) } #ifdef CONFIG_CGROUP_DEBUG -static struct cgroup_subsys_state *debug_create(struct cgroup_subsys *ss, - struct cgroup *cont) +static struct cgroup_subsys_state *debug_create(struct cgroup *cont) { struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL); @@ -5077,7 +5076,7 @@ static struct cgroup_subsys_state *debug_create(struct cgroup_subsys *ss, return css; } -static void debug_destroy(struct cgroup_subsys *ss, struct cgroup *cont) +static void debug_destroy(struct cgroup *cont) { kfree(cont->subsys[debug_subsys_id]); } diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index fc0646b78a6..f86e93920b6 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -128,8 +128,7 @@ struct cgroup_subsys freezer_subsys; * task->alloc_lock (inside __thaw_task(), prevents race with refrigerator()) * sighand->siglock */ -static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, - struct cgroup *cgroup) +static struct cgroup_subsys_state *freezer_create(struct cgroup *cgroup) { struct freezer *freezer; @@ -142,8 +141,7 @@ static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, return &freezer->css; } -static void freezer_destroy(struct cgroup_subsys *ss, - struct cgroup *cgroup) +static void freezer_destroy(struct cgroup *cgroup) { struct freezer *freezer = cgroup_freezer(cgroup); @@ -164,8 +162,7 @@ static bool is_task_frozen_enough(struct task_struct *task) * a write to that file racing against an attach, and hence the * can_attach() result will remain valid until the attach completes. */ -static int freezer_can_attach(struct cgroup_subsys *ss, - struct cgroup *new_cgroup, +static int freezer_can_attach(struct cgroup *new_cgroup, struct cgroup_taskset *tset) { struct freezer *freezer; @@ -185,7 +182,7 @@ static int freezer_can_attach(struct cgroup_subsys *ss, return 0; } -static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) +static void freezer_fork(struct task_struct *task) { struct freezer *freezer; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index a09ac2b9a66..5d575836dba 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1399,8 +1399,7 @@ static nodemask_t cpuset_attach_nodemask_from; static nodemask_t cpuset_attach_nodemask_to; /* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */ -static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { struct cpuset *cs = cgroup_cs(cgrp); struct task_struct *task; @@ -1436,8 +1435,7 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, return 0; } -static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { struct mm_struct *mm; struct task_struct *task; @@ -1833,8 +1831,7 @@ static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont) * (and likewise for mems) to the new cgroup. Called with cgroup_mutex * held. */ -static void cpuset_post_clone(struct cgroup_subsys *ss, - struct cgroup *cgroup) +static void cpuset_post_clone(struct cgroup *cgroup) { struct cgroup *parent, *child; struct cpuset *cs, *parent_cs; @@ -1857,13 +1854,10 @@ static void cpuset_post_clone(struct cgroup_subsys *ss, /* * cpuset_create - create a cpuset - * ss: cpuset cgroup subsystem * cont: control group that the new cpuset will be part of */ -static struct cgroup_subsys_state *cpuset_create( - struct cgroup_subsys *ss, - struct cgroup *cont) +static struct cgroup_subsys_state *cpuset_create(struct cgroup *cont) { struct cpuset *cs; struct cpuset *parent; @@ -1902,7 +1896,7 @@ static struct cgroup_subsys_state *cpuset_create( * will call async_rebuild_sched_domains(). */ -static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont) +static void cpuset_destroy(struct cgroup *cont) { struct cpuset *cs = cgroup_cs(cont); diff --git a/kernel/events/core.c b/kernel/events/core.c index a8f4ac001a0..a5d1ee92b0d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6906,8 +6906,7 @@ unlock: device_initcall(perf_event_sysfs_init); #ifdef CONFIG_CGROUP_PERF -static struct cgroup_subsys_state *perf_cgroup_create( - struct cgroup_subsys *ss, struct cgroup *cont) +static struct cgroup_subsys_state *perf_cgroup_create(struct cgroup *cont) { struct perf_cgroup *jc; @@ -6924,8 +6923,7 @@ static struct cgroup_subsys_state *perf_cgroup_create( return &jc->css; } -static void perf_cgroup_destroy(struct cgroup_subsys *ss, - struct cgroup *cont) +static void perf_cgroup_destroy(struct cgroup *cont) { struct perf_cgroup *jc; jc = container_of(cgroup_subsys_state(cont, perf_subsys_id), @@ -6941,8 +6939,7 @@ static int __perf_cgroup_move(void *info) return 0; } -static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup_taskset *tset) +static void perf_cgroup_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { struct task_struct *task; @@ -6950,8 +6947,8 @@ static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, task_function_call(task, __perf_cgroup_move, task); } -static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task) +static void perf_cgroup_exit(struct cgroup *cgrp, struct cgroup *old_cgrp, + struct task_struct *task) { /* * cgroup_exit() is called in the copy_process() failure path. diff --git a/kernel/sched/core.c b/kernel/sched/core.c index df00cb09263..ff12f721606 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7530,8 +7530,7 @@ static inline struct task_group *cgroup_tg(struct cgroup *cgrp) struct task_group, css); } -static struct cgroup_subsys_state * -cpu_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cgrp) +static struct cgroup_subsys_state *cpu_cgroup_create(struct cgroup *cgrp) { struct task_group *tg, *parent; @@ -7548,15 +7547,14 @@ cpu_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cgrp) return &tg->css; } -static void -cpu_cgroup_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +static void cpu_cgroup_destroy(struct cgroup *cgrp) { struct task_group *tg = cgroup_tg(cgrp); sched_destroy_group(tg); } -static int cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, +static int cpu_cgroup_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { struct task_struct *task; @@ -7574,7 +7572,7 @@ static int cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, return 0; } -static void cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, +static void cpu_cgroup_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { struct task_struct *task; @@ -7584,8 +7582,8 @@ static void cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, } static void -cpu_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task) +cpu_cgroup_exit(struct cgroup *cgrp, struct cgroup *old_cgrp, + struct task_struct *task) { /* * cgroup_exit() is called in the copy_process() failure path. @@ -7935,8 +7933,7 @@ struct cgroup_subsys cpu_cgroup_subsys = { */ /* create a new cpu accounting group */ -static struct cgroup_subsys_state *cpuacct_create( - struct cgroup_subsys *ss, struct cgroup *cgrp) +static struct cgroup_subsys_state *cpuacct_create(struct cgroup *cgrp) { struct cpuacct *ca; @@ -7966,8 +7963,7 @@ out: } /* destroy an existing cpu accounting group */ -static void -cpuacct_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +static void cpuacct_destroy(struct cgroup *cgrp) { struct cpuacct *ca = cgroup_ca(cgrp); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3dbff4dcde3..ae2f0a8ab76 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4580,10 +4580,9 @@ static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) return mem_cgroup_sockets_init(cont, ss); }; -static void kmem_cgroup_destroy(struct cgroup_subsys *ss, - struct cgroup *cont) +static void kmem_cgroup_destroy(struct cgroup *cont) { - mem_cgroup_sockets_destroy(cont, ss); + mem_cgroup_sockets_destroy(cont); } #else static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) @@ -4591,8 +4590,7 @@ static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) return 0; } -static void kmem_cgroup_destroy(struct cgroup_subsys *ss, - struct cgroup *cont) +static void kmem_cgroup_destroy(struct cgroup *cont) { } #endif @@ -4884,7 +4882,7 @@ err_cleanup: } static struct cgroup_subsys_state * __ref -mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) +mem_cgroup_create(struct cgroup *cont) { struct mem_cgroup *memcg, *parent; long error = -ENOMEM; @@ -4946,20 +4944,18 @@ free_out: return ERR_PTR(error); } -static int mem_cgroup_pre_destroy(struct cgroup_subsys *ss, - struct cgroup *cont) +static int mem_cgroup_pre_destroy(struct cgroup *cont) { struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); return mem_cgroup_force_empty(memcg, false); } -static void mem_cgroup_destroy(struct cgroup_subsys *ss, - struct cgroup *cont) +static void mem_cgroup_destroy(struct cgroup *cont) { struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); - kmem_cgroup_destroy(ss, cont); + kmem_cgroup_destroy(cont); mem_cgroup_put(memcg); } @@ -5296,9 +5292,8 @@ static void mem_cgroup_clear_mc(void) mem_cgroup_end_move(from); } -static int mem_cgroup_can_attach(struct cgroup_subsys *ss, - struct cgroup *cgroup, - struct cgroup_taskset *tset) +static int mem_cgroup_can_attach(struct cgroup *cgroup, + struct cgroup_taskset *tset) { struct task_struct *p = cgroup_taskset_first(tset); int ret = 0; @@ -5336,9 +5331,8 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss, return ret; } -static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss, - struct cgroup *cgroup, - struct cgroup_taskset *tset) +static void mem_cgroup_cancel_attach(struct cgroup *cgroup, + struct cgroup_taskset *tset) { mem_cgroup_clear_mc(); } @@ -5453,9 +5447,8 @@ retry: up_read(&mm->mmap_sem); } -static void mem_cgroup_move_task(struct cgroup_subsys *ss, - struct cgroup *cont, - struct cgroup_taskset *tset) +static void mem_cgroup_move_task(struct cgroup *cont, + struct cgroup_taskset *tset) { struct task_struct *p = cgroup_taskset_first(tset); struct mm_struct *mm = get_task_mm(p); @@ -5470,20 +5463,17 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss, mem_cgroup_clear_mc(); } #else /* !CONFIG_MMU */ -static int mem_cgroup_can_attach(struct cgroup_subsys *ss, - struct cgroup *cgroup, - struct cgroup_taskset *tset) +static int mem_cgroup_can_attach(struct cgroup *cgroup, + struct cgroup_taskset *tset) { return 0; } -static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss, - struct cgroup *cgroup, - struct cgroup_taskset *tset) +static void mem_cgroup_cancel_attach(struct cgroup *cgroup, + struct cgroup_taskset *tset) { } -static void mem_cgroup_move_task(struct cgroup_subsys *ss, - struct cgroup *cont, - struct cgroup_taskset *tset) +static void mem_cgroup_move_task(struct cgroup *cont, + struct cgroup_taskset *tset) { } #endif diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 3a9fd4826b7..22036ab732c 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -23,9 +23,8 @@ #include #include -static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, - struct cgroup *cgrp); -static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp); +static void cgrp_destroy(struct cgroup *cgrp); static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp); struct cgroup_subsys net_prio_subsys = { @@ -120,8 +119,7 @@ static void update_netdev_tables(void) rtnl_unlock(); } -static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, - struct cgroup *cgrp) +static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp) { struct cgroup_netprio_state *cs; int ret; @@ -145,7 +143,7 @@ static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, return &cs->css; } -static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +static void cgrp_destroy(struct cgroup *cgrp) { struct cgroup_netprio_state *cs; struct net_device *dev; diff --git a/net/core/sock.c b/net/core/sock.c index 5c5af9988f9..688037cb3b6 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -160,19 +160,19 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) out: list_for_each_entry_continue_reverse(proto, &proto_list, node) if (proto->destroy_cgroup) - proto->destroy_cgroup(cgrp, ss); + proto->destroy_cgroup(cgrp); mutex_unlock(&proto_list_mutex); return ret; } -void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss) +void mem_cgroup_sockets_destroy(struct cgroup *cgrp) { struct proto *proto; mutex_lock(&proto_list_mutex); list_for_each_entry_reverse(proto, &proto_list, node) if (proto->destroy_cgroup) - proto->destroy_cgroup(cgrp, ss); + proto->destroy_cgroup(cgrp); mutex_unlock(&proto_list_mutex); } #endif diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index 49978788a9d..e714c6834c9 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c @@ -94,7 +94,7 @@ create_files: } EXPORT_SYMBOL(tcp_init_cgroup); -void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) +void tcp_destroy_cgroup(struct cgroup *cgrp) { struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); struct cg_proto *cg_proto; diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index f84fdc3a7f2..1afaa284fcd 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -22,9 +22,8 @@ #include #include -static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, - struct cgroup *cgrp); -static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp); +static void cgrp_destroy(struct cgroup *cgrp); static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp); struct cgroup_subsys net_cls_subsys = { @@ -51,8 +50,7 @@ static inline struct cgroup_cls_state *task_cls_state(struct task_struct *p) struct cgroup_cls_state, css); } -static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, - struct cgroup *cgrp) +static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp) { struct cgroup_cls_state *cs; @@ -66,7 +64,7 @@ static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, return &cs->css; } -static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +static void cgrp_destroy(struct cgroup *cgrp) { kfree(cgrp_cls_state(cgrp)); } diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 8b5b5d8612c..c43a3323fee 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -61,8 +61,8 @@ static inline struct dev_cgroup *task_devcgroup(struct task_struct *task) struct cgroup_subsys devices_subsys; -static int devcgroup_can_attach(struct cgroup_subsys *ss, - struct cgroup *new_cgrp, struct cgroup_taskset *set) +static int devcgroup_can_attach(struct cgroup *new_cgrp, + struct cgroup_taskset *set) { struct task_struct *task = cgroup_taskset_first(set); @@ -156,8 +156,7 @@ remove: /* * called from kernel/cgroup.c with cgroup_lock() held. */ -static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss, - struct cgroup *cgroup) +static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup) { struct dev_cgroup *dev_cgroup, *parent_dev_cgroup; struct cgroup *parent_cgroup; @@ -195,8 +194,7 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss, return &dev_cgroup->css; } -static void devcgroup_destroy(struct cgroup_subsys *ss, - struct cgroup *cgroup) +static void devcgroup_destroy(struct cgroup *cgroup) { struct dev_cgroup *dev_cgroup; struct dev_whitelist_item *wh, *tmp; -- cgit v1.2.3-70-g09d2 From 6d8d17499810479eabd10731179c04b2ca22152f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Jan 2012 12:56:02 +0300 Subject: nfsd: don't allow zero length strings in cache_parse() There is no point in passing a zero length string here and quite a few of that cache_parse() implementations will Oops if count is zero. Signed-off-by: Dan Carpenter Cc: stable@kernel.org Signed-off-by: J. Bruce Fields --- net/sunrpc/cache.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 465df9ae104..8c6598e0334 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -828,6 +828,8 @@ static ssize_t cache_do_downcall(char *kaddr, const char __user *buf, { ssize_t ret; + if (count == 0) + return -EINVAL; if (copy_from_user(kaddr, buf, count)) return -EFAULT; kaddr[count] = '\0'; -- cgit v1.2.3-70-g09d2 From 3476964dba98641716173445aade77d40cc6f27a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 20 Jan 2012 10:48:18 +0300 Subject: nfsd: remove some unneeded checks We check for zero length strings in the caller now, so these aren't needed. Signed-off-by: Dan Carpenter Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 2 +- net/sunrpc/svcauth_unix.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index cf8a6bd062f..8e9689abbc0 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -87,7 +87,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) struct svc_expkey key; struct svc_expkey *ek = NULL; - if (mlen < 1 || mesg[mlen-1] != '\n') + if (mesg[mlen - 1] != '\n') return -EINVAL; mesg[mlen-1] = 0; diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 01153ead1db..6ab35736d88 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -509,7 +509,7 @@ static int unix_gid_parse(struct cache_detail *cd, time_t expiry; struct unix_gid ug, *ugp; - if (mlen <= 0 || mesg[mlen-1] != '\n') + if (mesg[mlen - 1] != '\n') return -EINVAL; mesg[mlen-1] = 0; -- cgit v1.2.3-70-g09d2 From 9f912ceb7ed1df1ed98ad2c28995dd66529a690a Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 20 Jan 2012 16:55:39 +0400 Subject: SUNPRC: remove marking service temporary sockets with XPT_CHNGBUF This is a cleanup patch. Service temporary sockets can be TCP or RDMA only. But XPT_CHNGBUF service socket flag is checked only for UDP sockets on receive. Thus (if I don't miss something non-obvious) this bit raising for temporary sockets can be removed. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields --- net/sunrpc/svcsock.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 464570906f8..b3bb18ba350 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1381,8 +1381,6 @@ void svc_sock_update_bufs(struct svc_serv *serv) spin_lock_bh(&serv->sv_lock); list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); - list_for_each_entry(svsk, &serv->sv_tempsocks, sk_xprt.xpt_list) - set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); spin_unlock_bh(&serv->sv_lock); } EXPORT_SYMBOL_GPL(svc_sock_update_bufs); -- cgit v1.2.3-70-g09d2 From 4a695823b580124c3ab750d8d528f7c6522628c3 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 3 Feb 2012 04:36:19 +0000 Subject: caif: Kill debugfs vars for caif socket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kill off the debug-fs exposed varaibles from caif_socket. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller --- net/caif/caif_socket.c | 113 +------------------------------------------------ 1 file changed, 1 insertion(+), 112 deletions(-) (limited to 'net') diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index a9862808645..0d113186463 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -43,34 +43,9 @@ enum caif_states { #define TX_FLOW_ON_BIT 1 #define RX_FLOW_ON_BIT 2 -static struct dentry *debugfsdir; - -#ifdef CONFIG_DEBUG_FS -struct debug_fs_counter { - atomic_t caif_nr_socks; - atomic_t caif_sock_create; - atomic_t num_connect_req; - atomic_t num_connect_resp; - atomic_t num_connect_fail_resp; - atomic_t num_disconnect; - atomic_t num_remote_shutdown_ind; - atomic_t num_tx_flow_off_ind; - atomic_t num_tx_flow_on_ind; - atomic_t num_rx_flow_off; - atomic_t num_rx_flow_on; -}; -static struct debug_fs_counter cnt; -#define dbfs_atomic_inc(v) atomic_inc_return(v) -#define dbfs_atomic_dec(v) atomic_dec_return(v) -#else -#define dbfs_atomic_inc(v) 0 -#define dbfs_atomic_dec(v) 0 -#endif - struct caifsock { struct sock sk; /* must be first member */ struct cflayer layer; - char name[CAIF_LAYER_NAME_SZ]; /* Used for debugging */ u32 flow_state; struct caif_connect_request conn_req; struct mutex readlock; @@ -161,7 +136,6 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) atomic_read(&cf_sk->sk.sk_rmem_alloc), sk_rcvbuf_lowwater(cf_sk)); set_rx_flow_off(cf_sk); - dbfs_atomic_inc(&cnt.num_rx_flow_off); caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); } @@ -172,7 +146,6 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) set_rx_flow_off(cf_sk); if (net_ratelimit()) pr_debug("sending flow OFF due to rmem_schedule\n"); - dbfs_atomic_inc(&cnt.num_rx_flow_off); caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); } skb->dev = NULL; @@ -233,14 +206,12 @@ static void caif_ctrl_cb(struct cflayer *layr, switch (flow) { case CAIF_CTRLCMD_FLOW_ON_IND: /* OK from modem to start sending again */ - dbfs_atomic_inc(&cnt.num_tx_flow_on_ind); set_tx_flow_on(cf_sk); cf_sk->sk.sk_state_change(&cf_sk->sk); break; case CAIF_CTRLCMD_FLOW_OFF_IND: /* Modem asks us to shut up */ - dbfs_atomic_inc(&cnt.num_tx_flow_off_ind); set_tx_flow_off(cf_sk); cf_sk->sk.sk_state_change(&cf_sk->sk); break; @@ -249,7 +220,6 @@ static void caif_ctrl_cb(struct cflayer *layr, /* We're now connected */ caif_client_register_refcnt(&cf_sk->layer, cfsk_hold, cfsk_put); - dbfs_atomic_inc(&cnt.num_connect_resp); cf_sk->sk.sk_state = CAIF_CONNECTED; set_tx_flow_on(cf_sk); cf_sk->sk.sk_state_change(&cf_sk->sk); @@ -263,7 +233,6 @@ static void caif_ctrl_cb(struct cflayer *layr, case CAIF_CTRLCMD_INIT_FAIL_RSP: /* Connect request failed */ - dbfs_atomic_inc(&cnt.num_connect_fail_resp); cf_sk->sk.sk_err = ECONNREFUSED; cf_sk->sk.sk_state = CAIF_DISCONNECTED; cf_sk->sk.sk_shutdown = SHUTDOWN_MASK; @@ -277,7 +246,6 @@ static void caif_ctrl_cb(struct cflayer *layr, case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND: /* Modem has closed this connection, or device is down. */ - dbfs_atomic_inc(&cnt.num_remote_shutdown_ind); cf_sk->sk.sk_shutdown = SHUTDOWN_MASK; cf_sk->sk.sk_err = ECONNRESET; set_rx_flow_on(cf_sk); @@ -297,7 +265,6 @@ static void caif_check_flow_release(struct sock *sk) return; if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) { - dbfs_atomic_inc(&cnt.num_rx_flow_on); set_rx_flow_on(cf_sk); caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ); } @@ -854,7 +821,6 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, /*ifindex = id of the interface.*/ cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if; - dbfs_atomic_inc(&cnt.num_connect_req); cf_sk->layer.receive = caif_sktrecv_cb; err = caif_connect_client(sock_net(sk), &cf_sk->conn_req, @@ -943,8 +909,6 @@ static int caif_release(struct socket *sock) spin_unlock_bh(&sk->sk_receive_queue.lock); sock->sk = NULL; - dbfs_atomic_inc(&cnt.num_disconnect); - WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir)); if (cf_sk->debugfs_socket_dir != NULL) debugfs_remove_recursive(cf_sk->debugfs_socket_dir); @@ -1052,14 +1016,12 @@ static void caif_sock_destructor(struct sock *sk) return; } sk_stream_kill_queues(&cf_sk->sk); - dbfs_atomic_dec(&cnt.caif_nr_socks); caif_free_client(&cf_sk->layer); } static int caif_create(struct net *net, struct socket *sock, int protocol, int kern) { - int num; struct sock *sk = NULL; struct caifsock *cf_sk = NULL; static struct proto prot = {.name = "PF_CAIF", @@ -1120,34 +1082,6 @@ static int caif_create(struct net *net, struct socket *sock, int protocol, cf_sk->sk.sk_priority = CAIF_PRIO_NORMAL; cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY; cf_sk->conn_req.protocol = protocol; - /* Increase the number of sockets created. */ - dbfs_atomic_inc(&cnt.caif_nr_socks); - num = dbfs_atomic_inc(&cnt.caif_sock_create); -#ifdef CONFIG_DEBUG_FS - if (!IS_ERR(debugfsdir)) { - - /* Fill in some information concerning the misc socket. */ - snprintf(cf_sk->name, sizeof(cf_sk->name), "cfsk%d", num); - - cf_sk->debugfs_socket_dir = - debugfs_create_dir(cf_sk->name, debugfsdir); - - debugfs_create_u32("sk_state", S_IRUSR | S_IWUSR, - cf_sk->debugfs_socket_dir, - (u32 *) &cf_sk->sk.sk_state); - debugfs_create_u32("flow_state", S_IRUSR | S_IWUSR, - cf_sk->debugfs_socket_dir, &cf_sk->flow_state); - debugfs_create_u32("sk_rmem_alloc", S_IRUSR | S_IWUSR, - cf_sk->debugfs_socket_dir, - (u32 *) &cf_sk->sk.sk_rmem_alloc); - debugfs_create_u32("sk_wmem_alloc", S_IRUSR | S_IWUSR, - cf_sk->debugfs_socket_dir, - (u32 *) &cf_sk->sk.sk_wmem_alloc); - debugfs_create_u32("identity", S_IRUSR | S_IWUSR, - cf_sk->debugfs_socket_dir, - (u32 *) &cf_sk->layer.id); - } -#endif release_sock(&cf_sk->sk); return 0; } @@ -1159,7 +1093,7 @@ static struct net_proto_family caif_family_ops = { .owner = THIS_MODULE, }; -static int af_caif_init(void) +static int __init caif_sktinit_module(void) { int err = sock_register(&caif_family_ops); if (!err) @@ -1167,54 +1101,9 @@ static int af_caif_init(void) return 0; } -static int __init caif_sktinit_module(void) -{ -#ifdef CONFIG_DEBUG_FS - debugfsdir = debugfs_create_dir("caif_sk", NULL); - if (!IS_ERR(debugfsdir)) { - debugfs_create_u32("num_sockets", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.caif_nr_socks); - debugfs_create_u32("num_create", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.caif_sock_create); - debugfs_create_u32("num_connect_req", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_connect_req); - debugfs_create_u32("num_connect_resp", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_connect_resp); - debugfs_create_u32("num_connect_fail_resp", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_connect_fail_resp); - debugfs_create_u32("num_disconnect", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_disconnect); - debugfs_create_u32("num_remote_shutdown_ind", - S_IRUSR | S_IWUSR, debugfsdir, - (u32 *) &cnt.num_remote_shutdown_ind); - debugfs_create_u32("num_tx_flow_off_ind", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_tx_flow_off_ind); - debugfs_create_u32("num_tx_flow_on_ind", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_tx_flow_on_ind); - debugfs_create_u32("num_rx_flow_off", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_rx_flow_off); - debugfs_create_u32("num_rx_flow_on", S_IRUSR | S_IWUSR, - debugfsdir, - (u32 *) &cnt.num_rx_flow_on); - } -#endif - return af_caif_init(); -} - static void __exit caif_sktexit_module(void) { sock_unregister(PF_CAIF); - if (debugfsdir != NULL) - debugfs_remove_recursive(debugfsdir); } module_init(caif_sktinit_module); module_exit(caif_sktexit_module); -- cgit v1.2.3-70-g09d2 From 576f3cc7fb94a22df2ced8dcba7d48ff42f8e745 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 3 Feb 2012 04:36:20 +0000 Subject: caif: Add drop count for caif_net device. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Count dropped packets in CAIF Netdevice. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller --- net/caif/chnl_net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 865690948bb..a751d9b263e 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -74,7 +74,6 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) struct sk_buff *skb; struct chnl_net *priv = container_of(layr, struct chnl_net, chnl); int pktlen; - int err = 0; const u8 *ip_version; u8 buf; @@ -95,8 +94,7 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) /* check the version of IP */ ip_version = skb_header_pointer(skb, 0, 1, &buf); - if (!ip_version) - return -EINVAL; + switch (*ip_version >> 4) { case 4: skb->protocol = htons(ETH_P_IP); @@ -105,6 +103,7 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) skb->protocol = htons(ETH_P_IPV6); break; default: + priv->netdev->stats.rx_errors++; return -EINVAL; } @@ -123,7 +122,7 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) priv->netdev->stats.rx_packets++; priv->netdev->stats.rx_bytes += pktlen; - return err; + return 0; } static int delete_device(struct chnl_net *dev) @@ -221,11 +220,13 @@ static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len > priv->netdev->mtu) { pr_warn("Size of skb exceeded MTU\n"); + dev->stats.tx_errors++; return -ENOSPC; } if (!priv->flowenabled) { pr_debug("dropping packets flow off\n"); + dev->stats.tx_dropped++; return NETDEV_TX_BUSY; } @@ -240,8 +241,7 @@ static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send the packet down the stack. */ result = priv->chnl.dn->transmit(priv->chnl.dn, pkt); if (result) { - if (result == -EAGAIN) - result = NETDEV_TX_BUSY; + dev->stats.tx_dropped++; return result; } -- cgit v1.2.3-70-g09d2 From 22b6a2eb902985961e6b41b923988a92a4523267 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 5 Feb 2012 12:28:57 +0000 Subject: decnet: remove unused variable from dn_output() The variable 'neigh' is assigned to, but otherwise completely unused. So let's remove it. Signed-off-by: Jesper Juhl Signed-off-by: David S. Miller --- net/decnet/dn_route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index f31ce72dca6..80a3de4906d 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -724,11 +724,10 @@ static int dn_output(struct sk_buff *skb) struct dn_route *rt = (struct dn_route *)dst; struct net_device *dev = dst->dev; struct dn_skb_cb *cb = DN_SKB_CB(skb); - struct neighbour *neigh; int err = -EINVAL; - if ((neigh = dst_get_neighbour_noref(dst)) == NULL) + if (dst_get_neighbour_noref(dst) == NULL) goto error; skb->dev = dev; -- cgit v1.2.3-70-g09d2 From 1f0b6702b5d0c10b8a1637f05baf0d597c9c0cc1 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 5 Feb 2012 12:50:46 +0000 Subject: caif: caifdev is never used in net/caif/caif_dev.c::transmit() - remove it. Signed-off-by: Jesper Juhl Signed-off-by: David S. Miller --- net/caif/caif_dev.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 82c57069415..aa6f716524f 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -162,7 +162,6 @@ void caif_flow_cb(struct sk_buff *skb) static int transmit(struct cflayer *layer, struct cfpkt *pkt) { int err, high = 0, qlen = 0; - struct caif_dev_common *caifdev; struct caif_device_entry *caifd = container_of(layer, struct caif_device_entry, layer); struct sk_buff *skb; @@ -174,7 +173,6 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt) skb->dev = caifd->netdev; skb_reset_network_header(skb); skb->protocol = htons(ETH_P_CAIF); - caifdev = netdev_priv(caifd->netdev); /* Check if we need to handle xoff */ if (likely(caifd->netdev->tx_queue_len == 0)) -- cgit v1.2.3-70-g09d2 From 5753cba17611af108995672c4e2d978014e17a56 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Mon, 6 Feb 2012 10:08:08 -0500 Subject: SUNRPC: Adding status trace points This patch adds three trace points to the status routines in the sunrpc state machine. The goal of these trace points is to give an Admin the ability to check on binding status or connection status to see if there is a potential problem. Signed-off-by: Steve Dickson Signed-off-by: Trond Myklebust --- include/trace/events/sunrpc.h | 53 +++++++++++++++++++++++++++++++++++++++++++ net/sunrpc/clnt.c | 4 ++++ 2 files changed, 57 insertions(+) (limited to 'net') diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index ec8668d978d..43be87d5dd5 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -8,6 +8,59 @@ #include #include +DECLARE_EVENT_CLASS(rpc_task_status, + + TP_PROTO(struct rpc_task *task), + + TP_ARGS(task), + + TP_STRUCT__entry( + __field(const struct rpc_task *, task) + __field(const struct rpc_clnt *, clnt) + __field(int, status) + ), + + TP_fast_assign( + __entry->task = task; + __entry->clnt = task->tk_client; + __entry->status = task->tk_status; + ), + + TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status) +); + +DEFINE_EVENT(rpc_task_status, rpc_call_status, + TP_PROTO(struct rpc_task *task), + + TP_ARGS(task) +); + +DEFINE_EVENT(rpc_task_status, rpc_bind_status, + TP_PROTO(struct rpc_task *task), + + TP_ARGS(task) +); + +TRACE_EVENT(rpc_connect_status, + TP_PROTO(struct rpc_task *task, int status), + + TP_ARGS(task, status), + + TP_STRUCT__entry( + __field(const struct rpc_task *, task) + __field(const struct rpc_clnt *, clnt) + __field(int, status) + ), + + TP_fast_assign( + __entry->task = task; + __entry->clnt = task->tk_client; + __entry->status = status; + ), + + TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status) +); + DECLARE_EVENT_CLASS(rpc_task_running, TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index db7220d8773..bb7ed2f3aee 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "sunrpc.h" #include "netns.h" @@ -1247,6 +1248,7 @@ call_bind_status(struct rpc_task *task) return; } + trace_rpc_bind_status(task); switch (task->tk_status) { case -ENOMEM: dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid); @@ -1346,6 +1348,7 @@ call_connect_status(struct rpc_task *task) return; } + trace_rpc_connect_status(task, status); switch (status) { /* if soft mounted, test if we've timed out */ case -ETIMEDOUT: @@ -1534,6 +1537,7 @@ call_status(struct rpc_task *task) return; } + trace_rpc_call_status(task); task->tk_status = 0; switch(status) { case -EHOSTDOWN: -- cgit v1.2.3-70-g09d2 From c8987876e9bf9b7b83e75b325586bc77ea8ac825 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:17 +0100 Subject: mac80211: move managed mode station state modification Move the station state modification right before insert, this just makes the current code more readable (you can tell that it's before insertion looking at a single screenful of code) right now, but some upcoming changes will require this. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 49fd1acd5d1..40b929d57a9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1587,20 +1587,6 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, return false; } - err = sta_info_move_state(sta, IEEE80211_STA_AUTH); - if (!err) - err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); - if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); - if (err) { - printk(KERN_DEBUG - "%s: failed to move station %pM to desired state\n", - sdata->name, sta->sta.addr); - WARN_ON(__sta_info_destroy(sta)); - mutex_unlock(&sdata->local->sta_mtx); - return false; - } - rates = 0; basic_rates = 0; sband = local->hw.wiphy->bands[wk->chan->band]; @@ -1648,6 +1634,20 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, if (elems.wmm_param) set_sta_flag(sta, WLAN_STA_WME); + err = sta_info_move_state(sta, IEEE80211_STA_AUTH); + if (!err) + err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); + if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); + if (err) { + printk(KERN_DEBUG + "%s: failed to move station %pM to desired state\n", + sdata->name, sta->sta.addr); + WARN_ON(__sta_info_destroy(sta)); + mutex_unlock(&sdata->local->sta_mtx); + return false; + } + /* sta_info_reinsert will also unlock the mutex lock */ err = sta_info_reinsert(sta); sta = NULL; -- cgit v1.2.3-70-g09d2 From 077f49392819608084c6d8d20e3dcca230afe07d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:18 +0100 Subject: mac80211: simplify AP_VLAN handling Setting keys and updating TKIP keys must use the BSS sdata (not AP_VLAN), so we translate. Move the translation into driver-ops wrappers instead of having it inline in the code to simplify the normal code flow. The same can be done for sta_add/remove which already does the translation in the wrapper. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/driver-ops.h | 2 ++ net/mac80211/key.c | 8 -------- net/mac80211/pm.c | 11 ++--------- net/mac80211/sta_info.c | 8 +------- net/mac80211/util.c | 11 ++--------- 5 files changed, 7 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index e8960ae3986..b8673f6100d 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -253,6 +253,7 @@ static inline int drv_set_key(struct ieee80211_local *local, might_sleep(); + sdata = get_bss_sdata(sdata); check_sdata_in_driver(sdata); trace_drv_set_key(local, cmd, sdata, sta, key); @@ -272,6 +273,7 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, if (sta) ista = &sta->sta; + sdata = get_bss_sdata(sdata); check_sdata_in_driver(sdata); trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 87a89741432..94f02b577d4 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -123,9 +123,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) */ if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) goto out_unsupported; - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); } ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); @@ -187,11 +184,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))) increment_tailroom_need_count(sdata); - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - ret = drv_set_key(key->local, DISABLE_KEY, sdata, sta, &key->conf); diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 596efaf50e0..c65ff471acc 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -97,15 +97,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) /* tear down aggregation sessions and remove STAs */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (sta->uploaded) { - sdata = sta->sdata; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - - drv_sta_remove(local, sdata, &sta->sta); - } + if (sta->uploaded) + drv_sta_remove(local, sta->sdata, &sta->sta); mesh_plink_quiesce(sta); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fa0823892b2..8e1e361c223 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -764,14 +764,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta) } } - if (sta->uploaded) { - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); + if (sta->uploaded) drv_sta_remove(local, sdata, &sta->sta); - sdata = sta->sdata; - } /* * At this point, after we wait for an RCU grace period, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d82d886d086..d4966e88aa4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1184,15 +1184,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* add STAs back */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (sta->uploaded) { - sdata = sta->sdata; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - - WARN_ON(drv_sta_add(local, sdata, &sta->sta)); - } + if (sta->uploaded) + WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta)); } mutex_unlock(&local->sta_mtx); -- cgit v1.2.3-70-g09d2 From 89c91caeccf45bbeb86104445125fe1eaec12079 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:19 +0100 Subject: mac80211: dont program keys for stations not uploaded If a station couldn't be uploaded to the driver but is still kept (only in IBSS mode) we still shouldn't try to program the keys for it into hardware; fix this bug by skipping the key upload in this case. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/key.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 94f02b577d4..e8616b3ff63 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -54,14 +54,6 @@ static void assert_key_lock(struct ieee80211_local *local) lockdep_assert_held(&local->key_mtx); } -static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) -{ - if (key->sta) - return &key->sta->sta; - - return NULL; -} - static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) { /* @@ -95,7 +87,7 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_sta *sta; + struct sta_info *sta; int ret; might_sleep(); @@ -105,7 +97,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) assert_key_lock(key->local); - sta = get_sta_for_key(key); + sta = key->sta; /* * If this is a per-STA GTK, check if it @@ -115,6 +107,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) goto out_unsupported; + if (sta && !sta->uploaded) + goto out_unsupported; + sdata = key->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { /* @@ -125,7 +120,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) goto out_unsupported; } - ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); + ret = drv_set_key(key->local, SET_KEY, sdata, + sta ? &sta->sta : NULL, &key->conf); if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; @@ -144,7 +140,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (ret != -ENOSPC && ret != -EOPNOTSUPP) wiphy_err(key->local->hw.wiphy, "failed to set key (%d, %pM) to hardware (%d)\n", - key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); + key->conf.keyidx, + sta ? sta->sta.addr : bcast_addr, ret); out_unsupported: switch (key->conf.cipher) { @@ -163,7 +160,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_sta *sta; + struct sta_info *sta; int ret; might_sleep(); @@ -176,7 +173,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) return; - sta = get_sta_for_key(key); + sta = key->sta; sdata = key->sdata; if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || @@ -185,12 +182,13 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) increment_tailroom_need_count(sdata); ret = drv_set_key(key->local, DISABLE_KEY, sdata, - sta, &key->conf); + sta ? &sta->sta : NULL, &key->conf); if (ret) wiphy_err(key->local->hw.wiphy, "failed to remove key (%d, %pM) from hardware (%d)\n", - key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); + key->conf.keyidx, + sta ? sta->sta.addr : bcast_addr, ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } -- cgit v1.2.3-70-g09d2 From 71ec375c75095002f36f083ceb32bbb8725734ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:20 +0100 Subject: mac80211: add NOTEXIST station state This will be used by drivers later if they need to have stations inserted all the time, in mac80211 has no purpose, is never used and sta_state starts out in NONE. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 2 ++ net/mac80211/sta_info.h | 1 + 2 files changed, 3 insertions(+) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 8e1e361c223..464bc691644 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -293,6 +293,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->sdata = sdata; sta->last_rx = jiffies; + sta->sta_state = IEEE80211_STA_NONE; + do_posix_clock_monotonic_gettime(&uptime); sta->last_connected = uptime.tv_sec; ewma_init(&sta->avg_signal, 1024, 8); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 381de37d247..da4b03c1c3b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -77,6 +77,7 @@ enum ieee80211_sta_info_flags { enum ieee80211_sta_state { /* NOTE: These need to be ordered correctly! */ + IEEE80211_STA_NOTEXIST, IEEE80211_STA_NONE, IEEE80211_STA_AUTH, IEEE80211_STA_ASSOC, -- cgit v1.2.3-70-g09d2 From f09603a259ffef69ad4516a04eb06cd65ac522fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:21 +0100 Subject: mac80211: add sta_state callback (based on Eliad's patch) Add a callback to notify the low-level driver whenever the state of a station changes. The driver is only notified when the station is actually in the mac80211 hash table, not for pre-insert state transitions. To allow the driver to replace sta_add/remove calls with this, call extra transitions with the NOTEXIST state. This callback can fail, so we need to be careful in handling it when a station is inserted, particularly in the IBSS case where we still keep the station entry around for mac80211 purposes. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 30 +++++++++++++ net/mac80211/driver-ops.h | 22 +++++++++ net/mac80211/driver-trace.h | 32 +++++++++++++ net/mac80211/main.c | 3 ++ net/mac80211/pm.c | 10 ++++- net/mac80211/sta_info.c | 106 +++++++++++++++++++++++++++++++++++++------- net/mac80211/sta_info.h | 9 ---- net/mac80211/util.c | 10 ++++- 8 files changed, 194 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 520eb4c5e5a..922313f0b39 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -981,6 +981,25 @@ enum set_key_cmd { SET_KEY, DISABLE_KEY, }; +/** + * enum ieee80211_sta_state - station state + * + * @IEEE80211_STA_NOTEXIST: station doesn't exist at all, + * this is a special state for add/remove transitions + * @IEEE80211_STA_NONE: station exists without special state + * @IEEE80211_STA_AUTH: station is authenticated + * @IEEE80211_STA_ASSOC: station is associated + * @IEEE80211_STA_AUTHORIZED: station is authorized (802.1X) + */ +enum ieee80211_sta_state { + /* NOTE: These need to be ordered correctly! */ + IEEE80211_STA_NOTEXIST, + IEEE80211_STA_NONE, + IEEE80211_STA_AUTH, + IEEE80211_STA_ASSOC, + IEEE80211_STA_AUTHORIZED, +}; + /** * struct ieee80211_sta - station table entry * @@ -1974,6 +1993,13 @@ enum ieee80211_frame_release_type { * in AP mode, this callback will not be called when the flag * %IEEE80211_HW_AP_LINK_PS is set. Must be atomic. * + * @sta_state: Notifies low level driver about state transition of a + * station (which can be the AP, a client, IBSS/WDS/mesh peer etc.) + * This callback is mutually exclusive with @sta_add/@sta_remove. + * It must not fail for down transitions but may fail for transitions + * up the list of states. + * The callback can sleep. + * * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), * bursting) for a hardware TX queue. * Returns a negative error code on failure. @@ -2193,6 +2219,10 @@ struct ieee80211_ops { struct ieee80211_sta *sta); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, struct ieee80211_sta *sta); + int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state); int (*conf_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b8673f6100d..4bd266ec533 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -478,6 +478,28 @@ static inline void drv_sta_remove(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline __must_check +int drv_sta_state(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + int ret = 0; + + might_sleep(); + + sdata = get_bss_sdata(sdata); + check_sdata_in_driver(sdata); + + trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); + if (local->ops->sta_state) + ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, + old_state, new_state); + trace_drv_return_int(local, ret); + return ret; +} + static inline int drv_conf_tx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, u16 queue, const struct ieee80211_tx_queue_params *params) diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 6e9df8fd8fb..384e2f08c18 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -635,6 +635,38 @@ TRACE_EVENT(drv_sta_notify, ) ); +TRACE_EVENT(drv_sta_state, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state), + + TP_ARGS(local, sdata, sta, old_state, new_state), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(u32, old_state) + __field(u32, new_state) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->old_state = old_state; + __entry->new_state = new_state; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " state: %d->%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, + __entry->old_state, __entry->new_state + ) +); + TRACE_EVENT(drv_sta_add, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6192caadfab..f4fc540aac1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -535,6 +535,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, int priv_size, i; struct wiphy *wiphy; + if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) + return NULL; + /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for * the driver's private data diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index c65ff471acc..af49ac4f082 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -97,9 +97,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) /* tear down aggregation sessions and remove STAs */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (sta->uploaded) + if (sta->uploaded) { + enum ieee80211_sta_state state; + drv_sta_remove(local, sta->sdata, &sta->sta); + state = sta->sta_state; + for (; state > IEEE80211_STA_NOTEXIST; state--) + WARN_ON(drv_sta_state(local, sdata, sta, + state, state - 1)); + } + mesh_plink_quiesce(sta); } mutex_unlock(&local->sta_mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 464bc691644..fcd9027c669 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -351,6 +351,38 @@ static int sta_info_insert_check(struct sta_info *sta) return 0; } +static int sta_info_insert_drv_state(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) +{ + enum ieee80211_sta_state state; + int err = 0; + + for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state; state++) { + err = drv_sta_state(local, sdata, sta, state, state + 1); + if (err) + break; + } + + if (!err) { + sta->uploaded = true; + return 0; + } + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + printk(KERN_DEBUG + "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n", + sdata->name, sta->sta.addr, state + 1, err); + err = 0; + } + + /* unwind on error */ + for (; state > IEEE80211_STA_NOTEXIST; state--) + WARN_ON(drv_sta_state(local, sdata, sta, state, state - 1)); + + return err; +} + /* * should be called with sta_mtx locked * this function replaces the mutex lock @@ -392,8 +424,11 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " "driver (%d) - keeping it anyway.\n", sdata->name, sta->sta.addr, err); - } else - sta->uploaded = true; + } else { + err = sta_info_insert_drv_state(local, sdata, sta); + if (err) + goto out_err; + } } if (!dummy_reinsert) { @@ -759,15 +794,19 @@ int __must_check __sta_info_destroy(struct sta_info *sta) RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); while (sta->sta_state > IEEE80211_STA_NONE) { - int err = sta_info_move_state(sta, sta->sta_state - 1); - if (err) { + ret = sta_info_move_state(sta, sta->sta_state - 1); + if (ret) { WARN_ON_ONCE(1); break; } } - if (sta->uploaded) + if (sta->uploaded) { drv_sta_remove(local, sdata, &sta->sta); + ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE, + IEEE80211_STA_NOTEXIST); + WARN_ON_ONCE(ret != 0); + } /* * At this point, after we wait for an RCU grace period, @@ -1404,20 +1443,58 @@ int sta_info_move_state(struct sta_info *sta, if (sta->sta_state == new_state) return 0; + /* check allowed transitions first */ + + switch (new_state) { + case IEEE80211_STA_NONE: + if (sta->sta_state != IEEE80211_STA_AUTH) + return -EINVAL; + break; + case IEEE80211_STA_AUTH: + if (sta->sta_state != IEEE80211_STA_NONE && + sta->sta_state != IEEE80211_STA_ASSOC) + return -EINVAL; + break; + case IEEE80211_STA_ASSOC: + if (sta->sta_state != IEEE80211_STA_AUTH && + sta->sta_state != IEEE80211_STA_AUTHORIZED) + return -EINVAL; + break; + case IEEE80211_STA_AUTHORIZED: + if (sta->sta_state != IEEE80211_STA_ASSOC) + return -EINVAL; + break; + default: + WARN(1, "invalid state %d", new_state); + return -EINVAL; + } + + printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", + sta->sdata->name, sta->sta.addr, new_state); + + /* + * notify the driver before the actual changes so it can + * fail the transition + */ + if (test_sta_flag(sta, WLAN_STA_INSERTED)) { + int err = drv_sta_state(sta->local, sta->sdata, sta, + sta->sta_state, new_state); + if (err) + return err; + } + + /* reflect the change in all state variables */ + switch (new_state) { case IEEE80211_STA_NONE: if (sta->sta_state == IEEE80211_STA_AUTH) clear_bit(WLAN_STA_AUTH, &sta->_flags); - else - return -EINVAL; break; case IEEE80211_STA_AUTH: if (sta->sta_state == IEEE80211_STA_NONE) set_bit(WLAN_STA_AUTH, &sta->_flags); else if (sta->sta_state == IEEE80211_STA_ASSOC) clear_bit(WLAN_STA_ASSOC, &sta->_flags); - else - return -EINVAL; break; case IEEE80211_STA_ASSOC: if (sta->sta_state == IEEE80211_STA_AUTH) { @@ -1426,24 +1503,19 @@ int sta_info_move_state(struct sta_info *sta, if (sta->sdata->vif.type == NL80211_IFTYPE_AP) atomic_dec(&sta->sdata->u.ap.num_sta_authorized); clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); - } else - return -EINVAL; + } break; case IEEE80211_STA_AUTHORIZED: if (sta->sta_state == IEEE80211_STA_ASSOC) { if (sta->sdata->vif.type == NL80211_IFTYPE_AP) atomic_inc(&sta->sdata->u.ap.num_sta_authorized); set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); - } else - return -EINVAL; + } break; default: - WARN(1, "invalid state %d", new_state); - return -EINVAL; + break; } - printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", - sta->sdata->name, sta->sta.addr, new_state); sta->sta_state = new_state; return 0; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index da4b03c1c3b..2ee80886000 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -75,15 +75,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_INSERTED, }; -enum ieee80211_sta_state { - /* NOTE: These need to be ordered correctly! */ - IEEE80211_STA_NOTEXIST, - IEEE80211_STA_NONE, - IEEE80211_STA_AUTH, - IEEE80211_STA_ASSOC, - IEEE80211_STA_AUTHORIZED, -}; - #define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ #define HT_AGG_MAX_RETRIES 15 diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d4966e88aa4..8f8b4ecc776 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1184,8 +1184,16 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* add STAs back */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (sta->uploaded) + if (sta->uploaded) { + enum ieee80211_sta_state state; + WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta)); + + for (state = IEEE80211_STA_NOTEXIST; + state < sta->sta_state - 1; state++) + WARN_ON(drv_sta_state(local, sta->sdata, sta, + state, state + 1)); + } } mutex_unlock(&local->sta_mtx); -- cgit v1.2.3-70-g09d2 From a4ec45a421b80bc36fd37578accf081f32527a7f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:22 +0100 Subject: mac80211: implement sta_add/sta_remove in sta_state Instead of maintaining separate sta_add/sta_remove callsites, implement it in sta_state when the driver has no sta_state implementation. The only behavioural change this should cause is in secure mesh mode: with this the station entries will only be created after the stations are set to AUTH. Given which drivers support mesh, this seems to not be a problem. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/driver-ops.h | 11 ++++++++++- net/mac80211/pm.c | 2 -- net/mac80211/sta_info.c | 23 +++++++++-------------- net/mac80211/util.c | 2 -- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4bd266ec533..70dfb6415c2 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -493,9 +493,18 @@ int drv_sta_state(struct ieee80211_local *local, check_sdata_in_driver(sdata); trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); - if (local->ops->sta_state) + if (local->ops->sta_state) { ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, old_state, new_state); + } else if (old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC) { + ret = drv_sta_add(local, sdata, &sta->sta); + if (ret == 0) + sta->uploaded = true; + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { + drv_sta_remove(local, sdata, &sta->sta); + } trace_drv_return_int(local, ret); return ret; } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index af49ac4f082..2b53a5348ac 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -100,8 +100,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) if (sta->uploaded) { enum ieee80211_sta_state state; - drv_sta_remove(local, sta->sdata, &sta->sta); - state = sta->sta_state; for (; state > IEEE80211_STA_NOTEXIST; state--) WARN_ON(drv_sta_state(local, sdata, sta, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fcd9027c669..5e577bd0e6a 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -365,7 +365,12 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local, } if (!err) { - sta->uploaded = true; + /* + * Drivers using legacy sta_add/sta_remove callbacks only + * get uploaded set to true after sta_add is called. + */ + if (!local->ops->sta_add) + sta->uploaded = true; return 0; } @@ -417,18 +422,9 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) if (!sta->dummy || dummy_reinsert) { /* notify driver */ - err = drv_sta_add(local, sdata, &sta->sta); - if (err) { - if (sdata->vif.type != NL80211_IFTYPE_ADHOC) - goto out_err; - printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " - "driver (%d) - keeping it anyway.\n", - sdata->name, sta->sta.addr, err); - } else { - err = sta_info_insert_drv_state(local, sdata, sta); - if (err) - goto out_err; - } + err = sta_info_insert_drv_state(local, sdata, sta); + if (err) + goto out_err; } if (!dummy_reinsert) { @@ -802,7 +798,6 @@ int __must_check __sta_info_destroy(struct sta_info *sta) } if (sta->uploaded) { - drv_sta_remove(local, sdata, &sta->sta); ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE, IEEE80211_STA_NOTEXIST); WARN_ON_ONCE(ret != 0); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8f8b4ecc776..264397aee81 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1187,8 +1187,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (sta->uploaded) { enum ieee80211_sta_state state; - WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta)); - for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state - 1; state++) WARN_ON(drv_sta_state(local, sta->sdata, sta, -- cgit v1.2.3-70-g09d2 From 7852e36186d2a1983c215836d7e3d7b8927c930d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:24 +0100 Subject: mac80211: remove dummy STA support The dummy STA support was added because I didn't want to change the driver API at the time. Now that we have state transitions triggering station add/remove in the driver, we only call add once a station reaches ASSOCIATED, so we can remove the dummy station stuff again. While at it, tighten the RX check and accept only port control (EAP) frames from the AP station if it's not associated yet -- in other cases there's no race. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 15 ++---- net/mac80211/rx.c | 13 +++-- net/mac80211/sta_info.c | 135 +++++++++--------------------------------------- net/mac80211/sta_info.h | 30 +---------- 4 files changed, 38 insertions(+), 155 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 40b929d57a9..d04811a29cd 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1581,7 +1581,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, * station info was already allocated and inserted before * the association and should be available to us */ - sta = sta_info_get_rx(sdata, cbss->bssid); + sta = sta_info_get(sdata, cbss->bssid); if (WARN_ON(!sta)) { mutex_unlock(&sdata->local->sta_mtx); return false; @@ -1648,14 +1648,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, return false; } - /* sta_info_reinsert will also unlock the mutex lock */ - err = sta_info_reinsert(sta); - sta = NULL; - if (err) { - printk(KERN_DEBUG "%s: failed to insert STA entry for" - " the AP (error %d)\n", sdata->name, err); - return false; - } + mutex_unlock(&sdata->local->sta_mtx); /* * Always handle WMM once after association regardless @@ -2536,12 +2529,10 @@ static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata, if (!sta) return -ENOMEM; - sta->dummy = true; - err = sta_info_insert(sta); sta = NULL; if (err) { - printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for" + printk(KERN_DEBUG "%s: failed to insert STA entry for" " the AP (error %d)\n", sdata->name, err); return err; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ab29253fb4f..8d6fa674f53 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -859,7 +859,12 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && rx->sdata->vif.type != NL80211_IFTYPE_WDS && (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { - if (rx->sta && rx->sta->dummy && + /* + * accept port control frames from the AP even when it's not + * yet marked ASSOC to prevent a race where we don't set the + * assoc bit quickly enough before it sends the first frame + */ + if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION && ieee80211_is_data_present(hdr->frame_control)) { u16 ethertype; u8 *payload; @@ -2949,7 +2954,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (ieee80211_is_data(fc)) { prev_sta = NULL; - for_each_sta_info_rx(local, hdr->addr2, sta, tmp) { + for_each_sta_info(local, hdr->addr2, sta, tmp) { if (!prev_sta) { prev_sta = sta; continue; @@ -2993,7 +2998,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; } - rx.sta = sta_info_get_bss_rx(prev, hdr->addr2); + rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; ieee80211_prepare_and_rx_handle(&rx, skb, false); @@ -3001,7 +3006,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, } if (prev) { - rx.sta = sta_info_get_bss_rx(prev, hdr->addr2); + rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 5e577bd0e6a..31cd6d92531 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -97,25 +97,6 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta; - sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], - lockdep_is_held(&local->sta_mtx)); - while (sta) { - if (sta->sdata == sdata && !sta->dummy && - memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) - break; - sta = rcu_dereference_check(sta->hnext, - lockdep_is_held(&local->sta_mtx)); - } - return sta; -} - -/* get a station info entry even if it is a dummy station*/ -struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, - const u8 *addr) -{ - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], lockdep_is_held(&local->sta_mtx)); while (sta) { @@ -138,30 +119,6 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta; - sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], - lockdep_is_held(&local->sta_mtx)); - while (sta) { - if ((sta->sdata == sdata || - (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && - !sta->dummy && - memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) - break; - sta = rcu_dereference_check(sta->hnext, - lockdep_is_held(&local->sta_mtx)); - } - return sta; -} - -/* - * Get sta info either from the specified interface - * or from one of its vlans (including dummy stations) - */ -struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, - const u8 *addr) -{ - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], lockdep_is_held(&local->sta_mtx)); while (sta) { @@ -397,66 +354,43 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) { struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; - struct sta_info *exist_sta; - bool dummy_reinsert = false; + struct station_info sinfo; int err = 0; lockdep_assert_held(&local->sta_mtx); - /* - * check if STA exists already. - * only accept a scenario of a second call to sta_info_insert_finish - * with a dummy station entry that was inserted earlier - * in that case - assume that the dummy station flag should - * be removed. - */ - exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr); - if (exist_sta) { - if (exist_sta == sta && sta->dummy) { - dummy_reinsert = true; - } else { - err = -EEXIST; - goto out_err; - } - } - - if (!sta->dummy || dummy_reinsert) { - /* notify driver */ - err = sta_info_insert_drv_state(local, sdata, sta); - if (err) - goto out_err; + /* check if STA exists already */ + if (sta_info_get_bss(sdata, sta->sta.addr)) { + err = -EEXIST; + goto out_err; } - if (!dummy_reinsert) { - local->num_sta++; - local->sta_generation++; - smp_mb(); + /* notify driver */ + err = sta_info_insert_drv_state(local, sdata, sta); + if (err) + goto out_err; - /* make the station visible */ - sta_info_hash_add(local, sta); + local->num_sta++; + local->sta_generation++; + smp_mb(); - list_add(&sta->list, &local->sta_list); + /* make the station visible */ + sta_info_hash_add(local, sta); - set_sta_flag(sta, WLAN_STA_INSERTED); - } else { - sta->dummy = false; - } + list_add(&sta->list, &local->sta_list); - if (!sta->dummy) { - struct station_info sinfo; + set_sta_flag(sta, WLAN_STA_INSERTED); - ieee80211_sta_debugfs_add(sta); - rate_control_add_sta_debugfs(sta); + ieee80211_sta_debugfs_add(sta); + rate_control_add_sta_debugfs(sta); - memset(&sinfo, 0, sizeof(sinfo)); - sinfo.filled = 0; - sinfo.generation = local->sta_generation; - cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); - } + memset(&sinfo, 0, sizeof(sinfo)); + sinfo.filled = 0; + sinfo.generation = local->sta_generation; + cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n", - sta->dummy ? "dummy " : "", sta->sta.addr); + wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ /* move reference to rcu-protected */ @@ -508,25 +442,6 @@ int sta_info_insert(struct sta_info *sta) return err; } -/* Caller must hold sta->local->sta_mtx */ -int sta_info_reinsert(struct sta_info *sta) -{ - struct ieee80211_local *local = sta->local; - int err = 0; - - err = sta_info_insert_check(sta); - if (err) { - mutex_unlock(&local->sta_mtx); - return err; - } - - might_sleep(); - - err = sta_info_insert_finish(sta); - rcu_read_unlock(); - return err; -} - static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) { /* @@ -873,7 +788,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) int ret; mutex_lock(&sdata->local->sta_mtx); - sta = sta_info_get_rx(sdata, addr); + sta = sta_info_get(sdata, addr); ret = __sta_info_destroy(sta); mutex_unlock(&sdata->local->sta_mtx); @@ -887,7 +802,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, int ret; mutex_lock(&sdata->local->sta_mtx); - sta = sta_info_get_bss_rx(sdata, addr); + sta = sta_info_get_bss(sdata, addr); ret = __sta_info_destroy(sta); mutex_unlock(&sdata->local->sta_mtx); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 2ee80886000..03f249bc276 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -265,8 +265,6 @@ struct sta_ampdu_mlme { * @dead: set to true when sta is unlinked * @uploaded: set to true when sta is uploaded to the driver * @lost_packets: number of consecutive lost packets - * @dummy: indicate a dummy station created for receiving - * EAP frames before association * @sta: station information we share with the driver * @sta_state: duplicates information about station state (for debug) * @beacon_loss_count: number of times beacon loss has triggered @@ -364,9 +362,6 @@ struct sta_info { unsigned int lost_packets; unsigned int beacon_loss_count; - /* should be right in front of sta to be in the same cache line */ - bool dummy; - /* keep last! */ struct ieee80211_sta sta; }; @@ -468,15 +463,9 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, const u8 *addr); -struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, - const u8 *addr); - struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, const u8 *addr); -struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, - const u8 *addr); - static inline void for_each_sta_info_type_check(struct ieee80211_local *local, const u8 *addr, @@ -485,23 +474,7 @@ void for_each_sta_info_type_check(struct ieee80211_local *local, { } -#define for_each_sta_info(local, _addr, _sta, nxt) \ - for ( /* initialise loop */ \ - _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ - nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ - /* typecheck */ \ - for_each_sta_info_type_check(local, (_addr), _sta, nxt),\ - /* continue condition */ \ - _sta; \ - /* advance loop */ \ - _sta = nxt, \ - nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ - ) \ - /* run code only if address matches and it's not a dummy sta */ \ - if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 && \ - !_sta->dummy) - -#define for_each_sta_info_rx(local, _addr, _sta, nxt) \ +#define for_each_sta_info(local, _addr, _sta, nxt) \ for ( /* initialise loop */ \ _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ @@ -540,7 +513,6 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta); */ int sta_info_insert(struct sta_info *sta); int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); -int sta_info_reinsert(struct sta_info *sta); int __must_check __sta_info_destroy(struct sta_info *sta); int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3-70-g09d2 From 95de817b9034d50860319f6033ec85d25024694c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:25 +0100 Subject: cfg80211: stop tracking authenticated state To track authenticated state seems to have been a design mistake in cfg80211. It is possible to have out of band authentication (FT), tracking multiple authentications caused more problems than it ever helped, and the implementation in mac80211 is too complex. Remove all this complexity, and let userspace do whatever it wants to, mac80211 can deal with that just fine. Association is still tracked of course, but authentication no longer is. Local auth state changes are thus no longer of value, so ignore them completely. This will also help implement SAE -- asking the driver to do an authentication is now almost equivalent to sending an authentication frame, with the exception of shared key authentication which is still handled completely. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- Documentation/DocBook/80211.tmpl | 1 - include/net/cfg80211.h | 39 ++--- net/mac80211/mlme.c | 23 +-- net/wireless/core.h | 9 +- net/wireless/mlme.c | 322 +++++++-------------------------------- net/wireless/nl80211.c | 18 +-- net/wireless/sme.c | 41 +---- 7 files changed, 91 insertions(+), 362 deletions(-) (limited to 'net') diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 2014155c899..c5ac6929c41 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -129,7 +129,6 @@ !Finclude/net/cfg80211.h cfg80211_pmksa !Finclude/net/cfg80211.h cfg80211_send_rx_auth !Finclude/net/cfg80211.h cfg80211_send_auth_timeout -!Finclude/net/cfg80211.h __cfg80211_auth_canceled !Finclude/net/cfg80211.h cfg80211_send_rx_assoc !Finclude/net/cfg80211.h cfg80211_send_assoc_timeout !Finclude/net/cfg80211.h cfg80211_send_deauth diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2964205332f..6cfecb02a34 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1039,10 +1039,6 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); * @key_len: length of WEP key for shared key authentication * @key_idx: index of WEP key for shared key authentication * @key: WEP key for shared key authentication - * @local_state_change: This is a request for a local state only, i.e., no - * Authentication frame is to be transmitted and authentication state is - * to be changed without having to wait for a response from the peer STA - * (AP). */ struct cfg80211_auth_request { struct cfg80211_bss *bss; @@ -1051,7 +1047,6 @@ struct cfg80211_auth_request { enum nl80211_auth_type auth_type; const u8 *key; u8 key_len, key_idx; - bool local_state_change; }; /** @@ -1068,7 +1063,11 @@ enum cfg80211_assoc_req_flags { * * This structure provides information needed to complete IEEE 802.11 * (re)association. - * @bss: The BSS to associate with. + * @bss: The BSS to associate with. If the call is successful the driver + * is given a reference that it must release, normally via a call to + * cfg80211_send_rx_assoc(), or, if association timed out, with a + * call to cfg80211_put_bss() (in addition to calling + * cfg80211_send_assoc_timeout()) * @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie_len: Length of ie buffer in octets * @use_mfp: Use management frame protection (IEEE 802.11w) in this association @@ -1096,19 +1095,16 @@ struct cfg80211_assoc_request { * This structure provides information needed to complete IEEE 802.11 * deauthentication. * - * @bss: the BSS to deauthenticate from + * @bssid: the BSSID of the BSS to deauthenticate from * @ie: Extra IEs to add to Deauthentication frame or %NULL * @ie_len: Length of ie buffer in octets * @reason_code: The reason code for the deauthentication - * @local_state_change: This is a request for a local state only, i.e., no - * Deauthentication frame is to be transmitted. */ struct cfg80211_deauth_request { - struct cfg80211_bss *bss; + const u8 *bssid; const u8 *ie; size_t ie_len; u16 reason_code; - bool local_state_change; }; /** @@ -2206,8 +2202,6 @@ struct cfg80211_conn; struct cfg80211_internal_bss; struct cfg80211_cached_keys; -#define MAX_AUTH_BSSES 4 - /** * struct wireless_dev - wireless per-netdev state * @@ -2271,8 +2265,6 @@ struct wireless_dev { struct list_head event_list; spinlock_t event_lock; - struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; - struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; struct cfg80211_internal_bss *current_bss; /* associated / joined */ struct ieee80211_channel *channel; @@ -2763,21 +2755,11 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); */ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); -/** - * __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled - * @dev: network device - * @addr: The MAC address of the device with which the authentication timed out - * - * When a pending authentication had no action yet, the driver may decide - * to not send a deauth frame, but in that case must calls this function - * to tell cfg80211 about this decision. It is only valid to call this - * function within the deauth() callback. - */ -void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr); - /** * cfg80211_send_rx_assoc - notification of processed association * @dev: network device + * @bss: the BSS struct association was requested for, the struct reference + * is owned by cfg80211 after this call * @buf: (re)association response frame (header + body) * @len: length of the frame data * @@ -2786,7 +2768,8 @@ void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr); * function or cfg80211_send_assoc_timeout() to indicate the result of * cfg80211_ops::assoc() call. This function may sleep. */ -void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, + const u8 *buf, size_t len); /** * cfg80211_send_assoc_timeout - notification of timed out association diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d04811a29cd..082fcda5778 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2459,9 +2459,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_work *wk; u16 auth_alg; - if (req->local_state_change) - return 0; /* no need to update mac80211 state */ - switch (req->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: auth_alg = WLAN_AUTH_OPEN; @@ -2593,7 +2590,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, sta_info_destroy_addr(wk->sdata, cbss->bssid); } - cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); + cfg80211_send_rx_assoc(wk->sdata->dev, cbss, skb->data, skb->len); destroy: if (wk->assoc.synced) drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, @@ -2750,13 +2747,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u8 bssid[ETH_ALEN]; bool assoc_bss = false; mutex_lock(&ifmgd->mtx); - memcpy(bssid, req->bss->bssid, ETH_ALEN); - if (ifmgd->associated == req->bss) { + if (ifmgd->associated && + memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) { ieee80211_set_disassoc(sdata, false, true); mutex_unlock(&ifmgd->mtx); assoc_bss = true; @@ -2777,7 +2773,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, tmp->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) continue; - if (memcmp(req->bss->bssid, tmp->filter_ta, ETH_ALEN)) + if (memcmp(req->bssid, tmp->filter_ta, ETH_ALEN)) continue; not_auth_yet = tmp->type == IEEE80211_WORK_DIRECT_PROBE; @@ -2811,18 +2807,15 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, * frame, and if it's IDLE we have completed the auth * process already. */ - if (not_auth_yet) { - __cfg80211_auth_canceled(sdata->dev, bssid); + if (not_auth_yet) return 0; - } } printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", - sdata->name, bssid, req->reason_code); + sdata->name, req->bssid, req->reason_code); - ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, - req->reason_code, cookie, - !req->local_state_change); + ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, + req->reason_code, cookie, true); if (assoc_bss) sta_info_flush(sdata->local, sdata); diff --git a/net/wireless/core.h b/net/wireless/core.h index 43ad9c81efc..2b454caf439 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -325,15 +325,13 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx, - bool local_state_change); + const u8 *key, int key_len, int key_idx); int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx, - bool local_state_change); + const u8 *key, int key_len, int key_idx); int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, @@ -421,7 +419,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap); void cfg80211_sme_scan_done(struct net_device *dev); void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); -void cfg80211_sme_disassoc(struct net_device *dev, int idx); +void cfg80211_sme_disassoc(struct net_device *dev, + struct cfg80211_internal_bss *bss); void __cfg80211_scan_done(struct work_struct *wk); void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); void __cfg80211_sched_scan_results(struct work_struct *wk); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 438dfc105b4..d553d365e75 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -20,40 +20,18 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; - u8 *bssid = mgmt->bssid; - int i; - u16 status = le16_to_cpu(mgmt->u.auth.status_code); - bool done = false; wdev_lock(wdev); - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (wdev->authtry_bsses[i] && - memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, - ETH_ALEN) == 0) { - if (status == WLAN_STATUS_SUCCESS) { - wdev->auth_bsses[i] = wdev->authtry_bsses[i]; - } else { - cfg80211_unhold_bss(wdev->authtry_bsses[i]); - cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); - } - wdev->authtry_bsses[i] = NULL; - done = true; - break; - } - } - - if (done) { - nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); - cfg80211_sme_rx_auth(dev, buf, len); - } + nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); + cfg80211_sme_rx_auth(dev, buf, len); wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_rx_auth); -void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, + const u8 *buf, size_t len) { u16 status_code; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -61,8 +39,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; u8 *ie = mgmt->u.assoc_resp.variable; - int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); - struct cfg80211_internal_bss *bss = NULL; + int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); wdev_lock(wdev); @@ -75,43 +52,20 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) * frame instead of reassoc. */ if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && - cfg80211_sme_failed_reassoc(wdev)) + cfg80211_sme_failed_reassoc(wdev)) { + cfg80211_put_bss(bss); goto out; + } nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); - if (status_code == WLAN_STATUS_SUCCESS) { - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (!wdev->auth_bsses[i]) - continue; - if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid, - ETH_ALEN) == 0) { - bss = wdev->auth_bsses[i]; - wdev->auth_bsses[i] = NULL; - /* additional reference to drop hold */ - cfg80211_ref_bss(bss); - break; - } - } - - /* - * We might be coming here because the driver reported - * a successful association at the same time as the - * user requested a deauth. In that case, we will have - * removed the BSS from the auth_bsses list due to the - * deauth request when the assoc response makes it. If - * the two code paths acquire the lock the other way - * around, that's just the standard situation of a - * deauth being requested while connected. - */ - if (!bss) - goto out; - } else if (wdev->conn) { + if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) { cfg80211_sme_failed_assoc(wdev); /* * do not call connect_result() now because the * sme will schedule work that does it later. */ + cfg80211_put_bss(bss); goto out; } @@ -124,17 +78,10 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) wdev->sme_state = CFG80211_SME_CONNECTING; } - /* this consumes one bss reference (unless bss is NULL) */ + /* this consumes the bss reference */ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, status_code, - status_code == WLAN_STATUS_SUCCESS, - bss ? &bss->pub : NULL); - /* drop hold now, and also reference acquired above */ - if (bss) { - cfg80211_unhold_bss(bss); - cfg80211_put_bss(&bss->pub); - } - + status_code == WLAN_STATUS_SUCCESS, bss); out: wdev_unlock(wdev); } @@ -148,8 +95,7 @@ void __cfg80211_send_deauth(struct net_device *dev, struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; - int i; - bool found = false, was_current = false; + bool was_current = false; ASSERT_WDEV_LOCK(wdev); @@ -158,32 +104,9 @@ void __cfg80211_send_deauth(struct net_device *dev, cfg80211_unhold_bss(wdev->current_bss); cfg80211_put_bss(&wdev->current_bss->pub); wdev->current_bss = NULL; - found = true; was_current = true; - } else for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (wdev->auth_bsses[i] && - memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { - cfg80211_unhold_bss(wdev->auth_bsses[i]); - cfg80211_put_bss(&wdev->auth_bsses[i]->pub); - wdev->auth_bsses[i] = NULL; - found = true; - break; - } - if (wdev->authtry_bsses[i] && - memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, - ETH_ALEN) == 0 && - memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) == 0) { - cfg80211_unhold_bss(wdev->authtry_bsses[i]); - cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); - wdev->authtry_bsses[i] = NULL; - found = true; - break; - } } - if (!found) - return; - nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { @@ -220,10 +143,8 @@ void __cfg80211_send_disassoc(struct net_device *dev, struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; - int i; u16 reason_code; bool from_ap; - bool done = false; ASSERT_WDEV_LOCK(wdev); @@ -234,16 +155,10 @@ void __cfg80211_send_disassoc(struct net_device *dev, if (wdev->current_bss && memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) - continue; - wdev->auth_bsses[i] = wdev->current_bss; - wdev->current_bss = NULL; - done = true; - cfg80211_sme_disassoc(dev, i); - break; - } - WARN_ON(!done); + cfg80211_sme_disassoc(dev, wdev->current_bss); + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; } else WARN_ON(1); @@ -287,34 +202,6 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, } EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); -static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr) -{ - int i; - bool done = false; - - ASSERT_WDEV_LOCK(wdev); - - for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { - if (wdev->authtry_bsses[i] && - memcmp(wdev->authtry_bsses[i]->pub.bssid, - addr, ETH_ALEN) == 0) { - cfg80211_unhold_bss(wdev->authtry_bsses[i]); - cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); - wdev->authtry_bsses[i] = NULL; - done = true; - break; - } - } - - WARN_ON(!done); -} - -void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr) -{ - __cfg80211_auth_remove(dev->ieee80211_ptr, addr); -} -EXPORT_SYMBOL(__cfg80211_auth_canceled); - void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -329,8 +216,6 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) WLAN_STATUS_UNSPECIFIED_FAILURE, false, NULL); - __cfg80211_auth_remove(wdev, addr); - wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_auth_timeout); @@ -340,8 +225,6 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - int i; - bool done = false; wdev_lock(wdev); @@ -351,20 +234,6 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) WLAN_STATUS_UNSPECIFIED_FAILURE, false, NULL); - for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { - if (wdev->auth_bsses[i] && - memcmp(wdev->auth_bsses[i]->pub.bssid, - addr, ETH_ALEN) == 0) { - cfg80211_unhold_bss(wdev->auth_bsses[i]); - cfg80211_put_bss(&wdev->auth_bsses[i]->pub); - wdev->auth_bsses[i] = NULL; - done = true; - break; - } - } - - WARN_ON(!done); - wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_assoc_timeout); @@ -403,13 +272,11 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx, - bool local_state_change) + const u8 *key, int key_len, int key_idx) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_auth_request req; - struct cfg80211_internal_bss *bss; - int i, err, slot = -1, nfree = 0; + int err; ASSERT_WDEV_LOCK(wdev); @@ -421,20 +288,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) return -EALREADY; - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (wdev->authtry_bsses[i] && - memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, - ETH_ALEN) == 0) - return -EALREADY; - if (wdev->auth_bsses[i] && - memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, - ETH_ALEN) == 0) - return -EALREADY; - } - memset(&req, 0, sizeof(req)); - req.local_state_change = local_state_change; req.ie = ie; req.ie_len = ie_len; req.auth_type = auth_type; @@ -446,39 +301,9 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (!req.bss) return -ENOENT; - bss = bss_from_pub(req.bss); - - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) { - slot = i; - nfree++; - } - } - - /* we need one free slot for disassoc and one for this auth */ - if (nfree < 2) { - err = -ENOSPC; - goto out; - } - - if (local_state_change) - wdev->auth_bsses[slot] = bss; - else - wdev->authtry_bsses[slot] = bss; - cfg80211_hold_bss(bss); - err = rdev->ops->auth(&rdev->wiphy, dev, &req); - if (err) { - if (local_state_change) - wdev->auth_bsses[slot] = NULL; - else - wdev->authtry_bsses[slot] = NULL; - cfg80211_unhold_bss(bss); - } - out: - if (err) - cfg80211_put_bss(req.bss); + cfg80211_put_bss(req.bss); return err; } @@ -487,15 +312,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx, - bool local_state_change) + const u8 *key, int key_len, int key_idx) { int err; wdev_lock(dev->ieee80211_ptr); err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, - key, key_len, key_idx, local_state_change); + key, key_len, key_idx); wdev_unlock(dev->ieee80211_ptr); return err; @@ -530,8 +354,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_assoc_request req; - struct cfg80211_internal_bss *bss; - int i, err, slot = -1; + int err; bool was_connected = false; ASSERT_WDEV_LOCK(wdev); @@ -573,26 +396,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, return -ENOENT; } - bss = bss_from_pub(req.bss); - - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (bss == wdev->auth_bsses[i]) { - slot = i; - break; - } - } + err = rdev->ops->assoc(&rdev->wiphy, dev, &req); - if (slot < 0) { - err = -ENOTCONN; - goto out; + if (err) { + if (was_connected) + wdev->sme_state = CFG80211_SME_CONNECTED; + cfg80211_put_bss(req.bss); } - err = rdev->ops->assoc(&rdev->wiphy, dev, &req); - out: - if (err && was_connected) - wdev->sme_state = CFG80211_SME_CONNECTED; - /* still a reference in wdev->auth_bsses[slot] */ - cfg80211_put_bss(req.bss); return err; } @@ -624,34 +435,25 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, bool local_state_change) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_deauth_request req; - int i; + struct cfg80211_deauth_request req = { + .bssid = bssid, + .reason_code = reason, + .ie = ie, + .ie_len = ie_len, + }; ASSERT_WDEV_LOCK(wdev); - memset(&req, 0, sizeof(req)); - req.reason_code = reason; - req.local_state_change = local_state_change; - req.ie = ie; - req.ie_len = ie_len; - if (wdev->current_bss && - memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { - req.bss = &wdev->current_bss->pub; - } else for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (wdev->auth_bsses[i] && - memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) { - req.bss = &wdev->auth_bsses[i]->pub; - break; - } - if (wdev->authtry_bsses[i] && - memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) { - req.bss = &wdev->authtry_bsses[i]->pub; - break; + if (local_state_change) { + if (wdev->current_bss && + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; } - } - if (!req.bss) - return -ENOTCONN; + return 0; + } return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); } @@ -722,7 +524,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_deauth_request req; - int i; + u8 bssid[ETH_ALEN]; ASSERT_WDEV_LOCK(wdev); @@ -734,35 +536,17 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, req.ie = NULL; req.ie_len = 0; - if (wdev->current_bss) { - req.bss = &wdev->current_bss->pub; - rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(&wdev->current_bss->pub); - wdev->current_bss = NULL; - } - } + if (!wdev->current_bss) + return; - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (wdev->auth_bsses[i]) { - req.bss = &wdev->auth_bsses[i]->pub; - rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); - if (wdev->auth_bsses[i]) { - cfg80211_unhold_bss(wdev->auth_bsses[i]); - cfg80211_put_bss(&wdev->auth_bsses[i]->pub); - wdev->auth_bsses[i] = NULL; - } - } - if (wdev->authtry_bsses[i]) { - req.bss = &wdev->authtry_bsses[i]->pub; - rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); - if (wdev->authtry_bsses[i]) { - cfg80211_unhold_bss(wdev->authtry_bsses[i]); - cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); - wdev->authtry_bsses[i] = NULL; - } - } + memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); + req.bssid = bssid; + rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; } } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c910b0750dc..e1fd1bf9072 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4083,7 +4083,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, struct cfg80211_bss *res = &intbss->pub; void *hdr; struct nlattr *bss; - int i; ASSERT_WDEV_LOCK(wdev); @@ -4136,13 +4135,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, if (intbss == wdev->current_bss) NLA_PUT_U32(msg, NL80211_BSS_STATUS, NL80211_BSS_STATUS_ASSOCIATED); - else for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (intbss != wdev->auth_bsses[i]) - continue; - NLA_PUT_U32(msg, NL80211_BSS_STATUS, - NL80211_BSS_STATUS_AUTHENTICATED); - break; - } break; case NL80211_IFTYPE_ADHOC: if (intbss == wdev->current_bss) @@ -4410,10 +4402,16 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; + /* + * Since we no longer track auth state, ignore + * requests to only change local state. + */ + if (local_state_change) + return 0; + return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, - key.p.key, key.p.key_len, key.idx, - local_state_change); + key.p.key, key.p.key_len, key.idx); } static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 7b9ecaed96b..f7e937ff897 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -179,7 +179,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) params->ssid, params->ssid_len, NULL, 0, params->key, params->key_len, - params->key_idx, false); + params->key_idx); case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!rdev->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; @@ -477,6 +477,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, kfree(wdev->connect_keys); wdev->connect_keys = NULL; wdev->ssid_len = 0; + cfg80211_put_bss(bss); return; } @@ -701,31 +702,10 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->ssid_len = 0; if (wdev->conn) { - const u8 *bssid; - int ret; - kfree(wdev->conn->ie); wdev->conn->ie = NULL; kfree(wdev->conn); wdev->conn = NULL; - - /* - * If this disconnect was due to a disassoc, we - * we might still have an auth BSS around. For - * the userspace SME that's currently expected, - * but for the kernel SME (nl80211 CONNECT or - * wireless extensions) we want to clear up all - * state. - */ - for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (!wdev->auth_bsses[i]) - continue; - bssid = wdev->auth_bsses[i]->pub.bssid; - ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, - WLAN_REASON_DEAUTH_LEAVING, - false); - WARN(ret, "deauth failed: %d\n", ret); - } } nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); @@ -1012,7 +992,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, return err; } -void cfg80211_sme_disassoc(struct net_device *dev, int idx) +void cfg80211_sme_disassoc(struct net_device *dev, + struct cfg80211_internal_bss *bss) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); @@ -1031,16 +1012,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx) * want it any more so deauthenticate too. */ - if (!wdev->auth_bsses[idx]) - return; + memcpy(bssid, bss->pub.bssid, ETH_ALEN); - memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); - if (__cfg80211_mlme_deauth(rdev, dev, bssid, - NULL, 0, WLAN_REASON_DEAUTH_LEAVING, - false)) { - /* whatever -- assume gone anyway */ - cfg80211_unhold_bss(wdev->auth_bsses[idx]); - cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); - wdev->auth_bsses[idx] = NULL; - } + __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, + WLAN_REASON_DEAUTH_LEAVING, false); } -- cgit v1.2.3-70-g09d2 From 4c0c0b75e0c35ddb8f61c06bcbffede63ab4f4a2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:26 +0100 Subject: cfg80211: export cfg80211_ref_bss This is needed by mac80211 to keep a reference to a BSS alive for the auth process. Remove the old version of cfg80211_ref_bss() since it's not actually used. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 14 ++++++++++++++ net/wireless/core.h | 5 ----- net/wireless/scan.c | 12 ++++++++++++ 3 files changed, 26 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6cfecb02a34..229edc526cf 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2719,6 +2719,20 @@ struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *meshid, size_t meshidlen, const u8 *meshcfg); +/** + * cfg80211_ref_bss - reference BSS struct + * @bss: the BSS struct to reference + * + * Increments the refcount of the given BSS struct. + */ +void cfg80211_ref_bss(struct cfg80211_bss *bss); + +/** + * cfg80211_put_bss - unref BSS struct + * @bss: the BSS struct + * + * Decrements the refcount of the given BSS struct. + */ void cfg80211_put_bss(struct cfg80211_bss *bss); /** diff --git a/net/wireless/core.h b/net/wireless/core.h index 2b454caf439..3ac2dd00d71 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -144,11 +144,6 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu return container_of(pub, struct cfg80211_internal_bss, pub); } -static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss) -{ - kref_get(&bss->ref); -} - static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) { atomic_inc(&bss->hold); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 31119e32e09..afde7e5f001 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -861,6 +861,18 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_inform_bss_frame); +void cfg80211_ref_bss(struct cfg80211_bss *pub) +{ + struct cfg80211_internal_bss *bss; + + if (!pub) + return; + + bss = container_of(pub, struct cfg80211_internal_bss, pub); + kref_get(&bss->ref); +} +EXPORT_SYMBOL(cfg80211_ref_bss); + void cfg80211_put_bss(struct cfg80211_bss *pub) { struct cfg80211_internal_bss *bss; -- cgit v1.2.3-70-g09d2 From 66e67e418908442389d3a9e6509985f01cbaf9b0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:27 +0100 Subject: mac80211: redesign auth/assoc This is the second part of the auth/assoc redesign, the mac80211 part. This moves the auth/assoc code out of the work abstraction and into the MLME, so that we don't flip channels all the time etc. The only downside is that when we are associated, we need to drop the association in order to create a connection to another AP, but for most drivers this is actually desirable and the ability to do was never used by any applications. If we want to implement resource reservation with FT-OTA, we'd probably best do it with explicit R-O-C in wpa_s. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Makefile | 4 +- net/mac80211/cfg.c | 6 +- net/mac80211/ieee80211_i.h | 77 +-- net/mac80211/iface.c | 4 +- net/mac80211/main.c | 10 +- net/mac80211/mlme.c | 1340 ++++++++++++++++++++++++++++++++------------ net/mac80211/rx.c | 9 +- net/mac80211/work.c | 815 --------------------------- 8 files changed, 1038 insertions(+), 1227 deletions(-) (limited to 'net') diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index d540c3b160f..1be7a454aa7 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -9,7 +9,7 @@ mac80211-y := \ scan.o offchannel.o \ ht.o agg-tx.o agg-rx.o \ ibss.o \ - mlme.o work.o \ + work.o \ iface.o \ rate.o \ michael.o \ @@ -25,7 +25,7 @@ mac80211-y := \ wme.o \ event.o \ chan.o \ - driver-trace.o + driver-trace.o mlme.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d15ba0d0de9..c3de921c8cf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2028,7 +2028,7 @@ ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) if (wk->offchan_tx.wait && !wk->offchan_tx.status) cfg80211_mgmt_tx_status(wk->sdata->dev, (unsigned long) wk->offchan_tx.frame, - wk->ie, wk->ie_len, false, GFP_KERNEL); + wk->data, wk->data_len, false, GFP_KERNEL); return WORK_DONE_DESTROY; } @@ -2179,8 +2179,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, wk->done = ieee80211_offchan_tx_done; wk->offchan_tx.frame = skb; wk->offchan_tx.wait = wait; - wk->ie_len = len; - memcpy(wk->ie, buf, len); + wk->data_len = len; + memcpy(wk->data, buf, len); ieee80211_add_work(wk); return 0; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d47e8c110b1..a146b1177cb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -280,10 +280,6 @@ struct mesh_preq_queue { enum ieee80211_work_type { IEEE80211_WORK_ABORT, - IEEE80211_WORK_DIRECT_PROBE, - IEEE80211_WORK_AUTH, - IEEE80211_WORK_ASSOC_BEACON_WAIT, - IEEE80211_WORK_ASSOC, IEEE80211_WORK_REMAIN_ON_CHANNEL, IEEE80211_WORK_OFFCHANNEL_TX, }; @@ -316,35 +312,9 @@ struct ieee80211_work { unsigned long timeout; enum ieee80211_work_type type; - u8 filter_ta[ETH_ALEN]; - bool started; union { - struct { - int tries; - u16 algorithm, transaction; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - u8 key[WLAN_KEY_LEN_WEP104]; - u8 key_len, key_idx; - bool privacy; - bool synced; - } probe_auth; - struct { - struct cfg80211_bss *bss; - const u8 *supp_rates; - const u8 *ht_information_ie; - enum ieee80211_smps_mode smps; - int tries; - u16 capability; - u8 prev_bssid[ETH_ALEN]; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; - u8 supp_rates_len; - bool wmm_used, use_11n, uapsd_used; - bool synced; - } assoc; struct { u32 duration; } remain; @@ -355,9 +325,8 @@ struct ieee80211_work { } offchan_tx; }; - int ie_len; - /* must be last */ - u8 ie[0]; + size_t data_len; + u8 data[]; }; /* flags used in struct ieee80211_if_managed.flags */ @@ -373,6 +342,43 @@ enum ieee80211_sta_flags { IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), }; +struct ieee80211_mgd_auth_data { + struct cfg80211_bss *bss; + unsigned long timeout; + int tries; + u16 algorithm, expected_transaction; + + u8 key[WLAN_KEY_LEN_WEP104]; + u8 key_len, key_idx; + bool synced; + bool done; + + size_t ie_len; + u8 ie[]; +}; + +struct ieee80211_mgd_assoc_data { + struct cfg80211_bss *bss; + const u8 *supp_rates; + const u8 *ht_information_ie; + + unsigned long timeout; + int tries; + + u16 capability; + u8 prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + u8 supp_rates_len; + bool wmm_used, uapsd_used; + bool have_beacon; + bool sent_assoc; + bool synced; + + size_t ie_len; + u8 ie[]; +}; + struct ieee80211_if_managed { struct timer_list timer; struct timer_list conn_mon_timer; @@ -389,6 +395,8 @@ struct ieee80211_if_managed { struct mutex mtx; struct cfg80211_bss *associated; + struct ieee80211_mgd_auth_data *auth_data; + struct ieee80211_mgd_assoc_data *assoc_data; u8 bssid[ETH_ALEN]; @@ -770,7 +778,6 @@ struct ieee80211_local { struct list_head work_list; struct timer_list work_timer; struct work_struct work_work; - struct sk_buff_head work_skb_queue; /* * private workqueue to mac80211. mac80211 makes this accessible @@ -1437,8 +1444,6 @@ void ieee80211_work_init(struct ieee80211_local *local); void ieee80211_add_work(struct ieee80211_work *wk); void free_work(struct ieee80211_work *wk); void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); -ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb); int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2efd595b2f7..19f0818eba7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1310,7 +1310,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) /* do not count disabled managed interfaces */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - !sdata->u.mgd.associated) { + !sdata->u.mgd.associated && + !sdata->u.mgd.auth_data && + !sdata->u.mgd.assoc_data) { sdata->vif.bss_conf.idle = true; continue; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f4fc540aac1..362e89d6d46 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -199,15 +199,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, return; if (sdata->vif.type == NL80211_IFTYPE_STATION) { - /* - * While not associated, claim a BSSID of all-zeroes - * so that drivers don't do any weird things with the - * BSSID at that time. - */ - if (sdata->vif.bss_conf.assoc) - sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; - else - sdata->vif.bss_conf.bssid = zero; + sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; else if (sdata->vif.type == NL80211_IFTYPE_AP) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 082fcda5778..52133dab929 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -30,6 +30,12 @@ #include "rate.h" #include "led.h" +#define IEEE80211_AUTH_TIMEOUT (HZ / 5) +#define IEEE80211_AUTH_MAX_TRIES 3 +#define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) +#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) +#define IEEE80211_ASSOC_MAX_TRIES 3 + static int max_nullfunc_tries = 2; module_param(max_nullfunc_tries, int, 0644); MODULE_PARM_DESC(max_nullfunc_tries, @@ -97,6 +103,15 @@ enum rx_mgmt_action { /* caller must call cfg80211_send_disassoc() */ RX_MGMT_CFG80211_DISASSOC, + + /* caller must call cfg80211_send_rx_auth() */ + RX_MGMT_CFG80211_RX_AUTH, + + /* caller must call cfg80211_send_rx_assoc() */ + RX_MGMT_CFG80211_RX_ASSOC, + + /* caller must call cfg80211_send_assoc_timeout() */ + RX_MGMT_CFG80211_ASSOC_TIMEOUT, }; /* utils */ @@ -115,8 +130,7 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) * has happened -- the work that runs from this timer will * do that. */ -static void run_again(struct ieee80211_if_managed *ifmgd, - unsigned long timeout) +static void run_again(struct ieee80211_if_managed *ifmgd, unsigned long timeout) { ASSERT_MGD_MTX(ifmgd); @@ -284,6 +298,319 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* frame sending functions */ +static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, + struct ieee80211_supported_band *sband, + u32 *rates) +{ + int i, j, count; + *rates = 0; + count = 0; + for (i = 0; i < supp_rates_len; i++) { + int rate = (supp_rates[i] & 0x7F) * 5; + + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == rate) { + *rates |= BIT(j); + count++; + break; + } + } + + return count; +} + +static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, const u8 *ht_info_ie, + struct ieee80211_supported_band *sband, + struct ieee80211_channel *channel, + enum ieee80211_smps_mode smps) +{ + struct ieee80211_ht_info *ht_info; + u8 *pos; + u32 flags = channel->flags; + u16 cap; + struct ieee80211_sta_ht_cap ht_cap; + + BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); + + if (!sband->ht_cap.ht_supported) + return; + + if (!ht_info_ie) + return; + + if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) + return; + + memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); + ieee80211_apply_htcap_overrides(sdata, &ht_cap); + + ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); + + /* determine capability flags */ + cap = ht_cap.cap; + + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (flags & IEEE80211_CHAN_NO_HT40PLUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (flags & IEEE80211_CHAN_NO_HT40MINUS) { + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cap &= ~IEEE80211_HT_CAP_SGI_40; + } + break; + } + + /* set SM PS mode properly */ + cap &= ~IEEE80211_HT_CAP_SM_PS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC: + case IEEE80211_SMPS_NUM_MODES: + WARN_ON(1); + case IEEE80211_SMPS_OFF: + cap |= WLAN_HT_CAP_SM_PS_DISABLED << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_STATIC: + cap |= WLAN_HT_CAP_SM_PS_STATIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + case IEEE80211_SMPS_DYNAMIC: + cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << + IEEE80211_HT_CAP_SM_PS_SHIFT; + break; + } + + /* reserve and fill IE */ + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); +} + +static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u8 *pos, qos_info; + size_t offset = 0, noffset; + int i, count, rates_len, supp_rates_len; + u16 capab; + struct ieee80211_supported_band *sband; + u32 rates = 0; + struct ieee80211_bss *bss = (void *)assoc_data->bss->priv; + + lockdep_assert_held(&ifmgd->mtx); + + sband = local->hw.wiphy->bands[local->oper_channel->band]; + + if (assoc_data->supp_rates_len) { + /* + * Get all rates supported by the device and the AP as + * some APs don't like getting a superset of their rates + * in the association request (e.g. D-Link DAP 1353 in + * b-only mode)... + */ + rates_len = ieee80211_compatible_rates(assoc_data->supp_rates, + assoc_data->supp_rates_len, + sband, &rates); + } else { + /* + * In case AP not provide any supported rates information + * before association, we send information element(s) with + * all rates that we support. + */ + rates = ~0; + rates_len = sband->n_bitrates; + } + + skb = alloc_skb(local->hw.extra_tx_headroom + + sizeof(*mgmt) + /* bit too much but doesn't matter */ + 2 + assoc_data->ssid_len + /* SSID */ + 4 + rates_len + /* (extended) rates */ + 4 + /* power capability */ + 2 + 2 * sband->n_channels + /* supported channels */ + 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ + assoc_data->ie_len + /* extra IEs */ + 9, /* WMM */ + GFP_KERNEL); + if (!skb) + return; + + skb_reserve(skb, local->hw.extra_tx_headroom); + + capab = WLAN_CAPABILITY_ESS; + + if (sband->band == IEEE80211_BAND_2GHZ) { + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; + } + + if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + + if ((assoc_data->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN); + + if (!is_zero_ether_addr(assoc_data->prev_bssid)) { + skb_put(skb, 10); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_REASSOC_REQ); + mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.reassoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); + memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid, + ETH_ALEN); + } else { + skb_put(skb, 4); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ASSOC_REQ); + mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.assoc_req.listen_interval = + cpu_to_le16(local->hw.conf.listen_interval); + } + + /* SSID */ + pos = skb_put(skb, 2 + assoc_data->ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = assoc_data->ssid_len; + memcpy(pos, assoc_data->ssid, assoc_data->ssid_len); + + /* add all rates which were marked to be used above */ + supp_rates_len = rates_len; + if (supp_rates_len > 8) + supp_rates_len = 8; + + pos = skb_put(skb, supp_rates_len + 2); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = supp_rates_len; + + count = 0; + for (i = 0; i < sband->n_bitrates; i++) { + if (BIT(i) & rates) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + if (++count == 8) + break; + } + } + + if (rates_len > count) { + pos = skb_put(skb, rates_len - count + 2); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = rates_len - count; + + for (i++; i < sband->n_bitrates; i++) { + if (BIT(i) & rates) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + } + } + + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { + /* 1. power capabilities */ + pos = skb_put(skb, 4); + *pos++ = WLAN_EID_PWR_CAPABILITY; + *pos++ = 2; + *pos++ = 0; /* min tx power */ + *pos++ = local->oper_channel->max_power; /* max tx power */ + + /* 2. supported channels */ + /* TODO: get this in reg domain format */ + pos = skb_put(skb, 2 * sband->n_channels + 2); + *pos++ = WLAN_EID_SUPPORTED_CHANNELS; + *pos++ = 2 * sband->n_channels; + for (i = 0; i < sband->n_channels; i++) { + *pos++ = ieee80211_frequency_to_channel( + sband->channels[i].center_freq); + *pos++ = 1; /* one channel in the subband*/ + } + } + + /* if present, add any custom IEs that go before HT */ + if (assoc_data->ie_len && assoc_data->ie) { + static const u8 before_ht[] = { + WLAN_EID_SSID, + WLAN_EID_SUPP_RATES, + WLAN_EID_EXT_SUPP_RATES, + WLAN_EID_PWR_CAPABILITY, + WLAN_EID_SUPPORTED_CHANNELS, + WLAN_EID_RSN, + WLAN_EID_QOS_CAPA, + WLAN_EID_RRM_ENABLED_CAPABILITIES, + WLAN_EID_MOBILITY_DOMAIN, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES, + }; + noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, + before_ht, ARRAY_SIZE(before_ht), + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, assoc_data->ie + offset, noffset - offset); + offset = noffset; + } + + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N) && + bss->wmm_used && local->hw.queues >= 4) + ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie, + sband, local->oper_channel, ifmgd->ap_smps); + + /* if present, add any custom non-vendor IEs that go after HT */ + if (assoc_data->ie_len && assoc_data->ie) { + noffset = ieee80211_ie_split_vendor(assoc_data->ie, + assoc_data->ie_len, + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, assoc_data->ie + offset, noffset - offset); + offset = noffset; + } + + if (assoc_data->wmm_used && local->hw.queues >= 4) { + if (assoc_data->uapsd_used) { + qos_info = local->uapsd_queues; + qos_info |= (local->uapsd_max_sp_len << + IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); + } else { + qos_info = 0; + } + + pos = skb_put(skb, 9); + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 7; /* len */ + *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ + *pos++ = 0x50; + *pos++ = 0xf2; + *pos++ = 2; /* WME */ + *pos++ = 0; /* WME info */ + *pos++ = 1; /* WME ver */ + *pos++ = qos_info; + } + + /* add any remaining custom (i.e. vendor specific here) IEs */ + if (assoc_data->ie_len && assoc_data->ie) { + noffset = assoc_data->ie_len; + pos = skb_put(skb, noffset - offset); + memcpy(pos, assoc_data->ie + offset, noffset - offset); + } + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); +} + static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *bssid, u16 stype, u16 reason, void *cookie, bool send_frame) @@ -1423,6 +1750,135 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) EXPORT_SYMBOL(ieee80211_connection_loss); +static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, + bool assoc) +{ + struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; + + lockdep_assert_held(&sdata->u.mgd.mtx); + + if (auth_data->synced) + drv_finish_tx_sync(sdata->local, sdata, + auth_data->bss->bssid, + IEEE80211_TX_SYNC_AUTH); + + if (!assoc) { + sta_info_destroy_addr(sdata, auth_data->bss->bssid); + + memset(sdata->u.mgd.bssid, 0, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + } + + cfg80211_put_bss(auth_data->bss); + kfree(auth_data); + sdata->u.mgd.auth_data = NULL; +} + +static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) +{ + struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; + u8 *pos; + struct ieee802_11_elems elems; + + pos = mgmt->u.auth.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + if (!elems.challenge) + return; + auth_data->expected_transaction = 4; + ieee80211_send_auth(sdata, 3, auth_data->algorithm, + elems.challenge - 2, elems.challenge_len + 2, + auth_data->bss->bssid, auth_data->bss->bssid, + auth_data->key, auth_data->key_len, + auth_data->key_idx); +} + +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + u8 bssid[ETH_ALEN]; + u16 auth_alg, auth_transaction, status_code; + struct sta_info *sta; + + lockdep_assert_held(&ifmgd->mtx); + + if (len < 24 + 6) + return RX_MGMT_NONE; + + if (!ifmgd->auth_data || ifmgd->auth_data->done) + return RX_MGMT_NONE; + + memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); + + if (memcmp(bssid, mgmt->bssid, ETH_ALEN)) + return RX_MGMT_NONE; + + auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); + auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); + status_code = le16_to_cpu(mgmt->u.auth.status_code); + + if (auth_alg != ifmgd->auth_data->algorithm || + auth_transaction != ifmgd->auth_data->expected_transaction) + return RX_MGMT_NONE; + + if (status_code != WLAN_STATUS_SUCCESS) { + printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", + sdata->name, mgmt->sa, status_code); + goto out; + } + + switch (ifmgd->auth_data->algorithm) { + case WLAN_AUTH_OPEN: + case WLAN_AUTH_LEAP: + case WLAN_AUTH_FT: + break; + case WLAN_AUTH_SHARED_KEY: + if (ifmgd->auth_data->expected_transaction != 4) { + ieee80211_auth_challenge(sdata, mgmt, len); + /* need another frame */ + return RX_MGMT_NONE; + } + break; + default: + WARN_ONCE(1, "invalid auth alg %d", + ifmgd->auth_data->algorithm); + return RX_MGMT_NONE; + } + + printk(KERN_DEBUG "%s: authenticated\n", sdata->name); + out: + if (ifmgd->auth_data->synced) + drv_finish_tx_sync(sdata->local, sdata, bssid, + IEEE80211_TX_SYNC_AUTH); + ifmgd->auth_data->synced = false; + ifmgd->auth_data->done = true; + ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; + run_again(ifmgd, ifmgd->auth_data->timeout); + + /* move station state to auth */ + mutex_lock(&sdata->local->sta_mtx); + sta = sta_info_get(sdata, bssid); + if (!sta) { + WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); + goto out_err; + } + if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { + printk(KERN_DEBUG "%s: failed moving %pM to auth\n", + sdata->name, bssid); + goto out_err; + } + mutex_unlock(&sdata->local->sta_mtx); + + return RX_MGMT_CFG80211_RX_AUTH; + out_err: + mutex_unlock(&sdata->local->sta_mtx); + /* ignore frame -- wait for timeout */ + return RX_MGMT_NONE; +} + + static enum rx_mgmt_action __must_check ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) @@ -1431,10 +1887,14 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, const u8 *bssid = NULL; u16 reason_code; + lockdep_assert_held(&ifmgd->mtx); + if (len < 24 + 2) return RX_MGMT_NONE; - ASSERT_MGD_MTX(ifmgd); + if (!ifmgd->associated || + memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) + return RX_MGMT_NONE; bssid = ifmgd->associated->bssid; @@ -1459,15 +1919,13 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u16 reason_code; - if (len < 24 + 2) - return RX_MGMT_NONE; - - ASSERT_MGD_MTX(ifmgd); + lockdep_assert_held(&ifmgd->mtx); - if (WARN_ON(!ifmgd->associated)) + if (len < 24 + 2) return RX_MGMT_NONE; - if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN))) + if (!ifmgd->associated || + memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) return RX_MGMT_NONE; reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); @@ -1524,15 +1982,37 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, } } -static bool ieee80211_assoc_success(struct ieee80211_work *wk, +static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, + bool assoc) +{ + struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; + + lockdep_assert_held(&sdata->u.mgd.mtx); + + if (assoc_data->synced) + drv_finish_tx_sync(sdata->local, sdata, + assoc_data->bss->bssid, + IEEE80211_TX_SYNC_ASSOC); + + if (!assoc) { + sta_info_destroy_addr(sdata, assoc_data->bss->bssid); + + memset(sdata->u.mgd.bssid, 0, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + } + + kfree(assoc_data); + sdata->u.mgd.assoc_data = NULL; +} + +static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *cbss, struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_sub_if_data *sdata = wk->sdata; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct sta_info *sta; - struct cfg80211_bss *cbss = wk->assoc.bss; u8 *pos; u32 rates, basic_rates; u16 capab_info, aid; @@ -1589,7 +2069,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, rates = 0; basic_rates = 0; - sband = local->hw.wiphy->bands[wk->chan->band]; + sband = local->hw.wiphy->bands[local->oper_channel->band]; ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, &rates, &basic_rates, &have_higher_than_11mbit, @@ -1610,11 +2090,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, basic_rates = BIT(min_rate_index); } - sta->sta.supp_rates[wk->chan->band] = rates; + sta->sta.supp_rates[local->oper_channel->band] = rates; sdata->vif.bss_conf.basic_rates = basic_rates; /* cf. IEEE 802.11 9.2.12 */ - if (wk->chan->band == IEEE80211_BAND_2GHZ && + if (local->oper_channel->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; else @@ -1664,8 +2144,6 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, else ieee80211_set_wmm_default(sdata); - local->oper_channel = wk->chan; - if (elems.ht_info_elem && elems.wmm_param && (sdata->local->hw.queues >= 4) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) @@ -1696,7 +2174,82 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, return true; } +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len, + struct cfg80211_bss **bss) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + u16 capab_info, status_code, aid; + struct ieee802_11_elems elems; + u8 *pos; + bool reassoc; + + lockdep_assert_held(&ifmgd->mtx); + + if (!assoc_data) + return RX_MGMT_NONE; + if (memcmp(assoc_data->bss->bssid, mgmt->bssid, ETH_ALEN)) + return RX_MGMT_NONE; + + /* + * AssocResp and ReassocResp have identical structure, so process both + * of them in this function. + */ + + if (len < 24 + 6) + return RX_MGMT_NONE; + + reassoc = ieee80211_is_reassoc_req(mgmt->frame_control); + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + aid = le16_to_cpu(mgmt->u.assoc_resp.aid); + + printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " + "status=%d aid=%d)\n", + sdata->name, reassoc ? "Rea" : "A", mgmt->sa, + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); + + pos = mgmt->u.assoc_resp.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && + elems.timeout_int && elems.timeout_int_len == 5 && + elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { + u32 tu, ms; + tu = get_unaligned_le32(elems.timeout_int + 1); + ms = tu * 1024 / 1000; + printk(KERN_DEBUG "%s: %pM rejected association temporarily; " + "comeback duration %u TU (%u ms)\n", + sdata->name, mgmt->sa, tu, ms); + assoc_data->timeout = jiffies + msecs_to_jiffies(ms); + if (ms > IEEE80211_ASSOC_TIMEOUT) + run_again(ifmgd, assoc_data->timeout); + return RX_MGMT_NONE; + } + + *bss = assoc_data->bss; + + if (status_code != WLAN_STATUS_SUCCESS) { + printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", + sdata->name, mgmt->sa, status_code); + ieee80211_destroy_assoc_data(sdata, false); + } else { + printk(KERN_DEBUG "%s: associated\n", sdata->name); + + ieee80211_destroy_assoc_data(sdata, true); + if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { + /* oops -- internal error -- send timeout for now */ + sta_info_destroy_addr(sdata, mgmt->bssid); + cfg80211_put_bss(*bss); + return RX_MGMT_CFG80211_ASSOC_TIMEOUT; + } + } + + return RX_MGMT_CFG80211_RX_ASSOC; +} static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, @@ -1710,7 +2263,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *channel; bool need_ps = false; - if (sdata->u.mgd.associated) { + if (sdata->u.mgd.associated && + memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, + ETH_ALEN) == 0) { bss = (void *)sdata->u.mgd.associated->priv; /* not previously set so we may need to recalc */ need_ps = !bss->dtim_period; @@ -1780,6 +2335,15 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) ieee80211_reset_ap_probe(sdata); + + if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies && + memcmp(mgmt->bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN) == 0) { + /* got probe response, continue with auth */ + printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); + ifmgd->auth_data->tries = 0; + ifmgd->auth_data->timeout = jiffies; + run_again(ifmgd, ifmgd->auth_data->timeout); + } } /* @@ -1819,7 +2383,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, u32 ncrc; u8 *bssid; - ASSERT_MGD_MTX(ifmgd); + lockdep_assert_held(&ifmgd->mtx); /* Process beacon from the current BSS */ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1829,21 +2393,25 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (rx_status->freq != local->hw.conf.channel->center_freq) return; - /* - * We might have received a number of frames, among them a - * disassoc frame and a beacon... - */ - if (!ifmgd->associated) - return; + if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && + memcmp(mgmt->bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN) == 0) { + ieee802_11_parse_elems(mgmt->u.beacon.variable, + len - baselen, &elems); - bssid = ifmgd->associated->bssid; + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, + false); + ifmgd->assoc_data->have_beacon = true; + ifmgd->assoc_data->sent_assoc = false; + /* continue assoc process */ + ifmgd->assoc_data->timeout = jiffies; + run_again(ifmgd, ifmgd->assoc_data->timeout); + return; + } - /* - * And in theory even frames from a different AP we were just - * associated to a split-second ago! - */ - if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) + if (!ifmgd->associated || + memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) return; + bssid = ifmgd->associated->bssid; /* Track average RSSI from the Beacon frames of the current AP */ ifmgd->last_beacon_signal = rx_status->signal; @@ -2027,6 +2595,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_rx_status *rx_status; struct ieee80211_mgmt *mgmt; + struct cfg80211_bss *bss = NULL; enum rx_mgmt_action rma = RX_MGMT_NONE; u16 fc; @@ -2036,92 +2605,59 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); - if (ifmgd->associated && - memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) { - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_BEACON: - ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(sdata, skb); - break; - case IEEE80211_STYPE_DEAUTH: - rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_DISASSOC: - rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_ACTION: - switch (mgmt->u.action.category) { - case WLAN_CATEGORY_SPECTRUM_MGMT: - ieee80211_sta_process_chanswitch(sdata, - &mgmt->u.action.u.chan_switch.sw_elem, - (void *)ifmgd->associated->priv, - rx_status->mactime); - break; - } - } - mutex_unlock(&ifmgd->mtx); - - switch (rma) { - case RX_MGMT_NONE: - /* no action */ - break; - case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); - break; - case RX_MGMT_CFG80211_DISASSOC: - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_BEACON: + ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); + break; + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(sdata, skb); + break; + case IEEE80211_STYPE_AUTH: + rma = ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_DEAUTH: + rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_DISASSOC: + rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); + break; + case IEEE80211_STYPE_ACTION: + switch (mgmt->u.action.category) { + case WLAN_CATEGORY_SPECTRUM_MGMT: + ieee80211_sta_process_chanswitch(sdata, + &mgmt->u.action.u.chan_switch.sw_elem, + (void *)ifmgd->associated->priv, + rx_status->mactime); break; - default: - WARN(1, "unexpected: %d", rma); } - return; } - mutex_unlock(&ifmgd->mtx); - if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { - struct ieee80211_local *local = sdata->local; - struct ieee80211_work *wk; - - mutex_lock(&local->mtx); - list_for_each_entry(wk, &local->work_list, list) { - if (wk->sdata != sdata) - continue; - - if (wk->type != IEEE80211_WORK_ASSOC && - wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) - continue; - - if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) - continue; - if (memcmp(mgmt->sa, wk->filter_ta, ETH_ALEN)) - continue; - - /* - * Printing the message only here means we can't - * spuriously print it, but it also means that it - * won't be printed when the frame comes in before - * we even tried to associate or in similar cases. - * - * Ultimately, I suspect cfg80211 should print the - * messages instead. - */ - printk(KERN_DEBUG - "%s: deauthenticated from %pM (Reason: %u)\n", - sdata->name, mgmt->bssid, - le16_to_cpu(mgmt->u.deauth.reason_code)); - - list_del_rcu(&wk->list); - free_work(wk); - break; - } - mutex_unlock(&local->mtx); - + switch (rma) { + case RX_MGMT_NONE: + /* no action */ + break; + case RX_MGMT_CFG80211_DEAUTH: cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + break; + case RX_MGMT_CFG80211_DISASSOC: + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); + break; + case RX_MGMT_CFG80211_RX_AUTH: + cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, skb->len); + break; + case RX_MGMT_CFG80211_RX_ASSOC: + cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, skb->len); + break; + case RX_MGMT_CFG80211_ASSOC_TIMEOUT: + cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); + break; + default: + WARN(1, "unexpected: %d", rma); } } @@ -2166,14 +2702,160 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); } +static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; + + lockdep_assert_held(&ifmgd->mtx); + + if (WARN_ON_ONCE(!auth_data)) + return -EINVAL; + + if (!auth_data->synced) { + int ret = drv_tx_sync(local, sdata, auth_data->bss->bssid, + IEEE80211_TX_SYNC_AUTH); + if (ret) + return ret; + } + auth_data->synced = true; + + auth_data->tries++; + + if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { + printk(KERN_DEBUG "%s: authentication with %pM timed out\n", + sdata->name, auth_data->bss->bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, auth_data->bss); + + return -ETIMEDOUT; + } + + if (auth_data->bss->proberesp_ies) { + printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n", + sdata->name, auth_data->bss->bssid, auth_data->tries, + IEEE80211_AUTH_MAX_TRIES); + + auth_data->expected_transaction = 2; + ieee80211_send_auth(sdata, 1, auth_data->algorithm, + auth_data->ie, auth_data->ie_len, + auth_data->bss->bssid, + auth_data->bss->bssid, NULL, 0, 0); + } else { + const u8 *ssidie; + + printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", + sdata->name, auth_data->bss->bssid, auth_data->tries, + IEEE80211_AUTH_MAX_TRIES); + + ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); + if (!ssidie) + return -EINVAL; + /* + * Direct probe is sent to broadcast address as some APs + * will not answer to direct packet in unassociated state. + */ + ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], + NULL, 0, (u32) -1, true, false); + } + + auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + run_again(ifmgd, auth_data->timeout); + + return 0; +} + +static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; + struct ieee80211_local *local = sdata->local; + + lockdep_assert_held(&sdata->u.mgd.mtx); + + if (!assoc_data->synced) { + int ret = drv_tx_sync(local, sdata, assoc_data->bss->bssid, + IEEE80211_TX_SYNC_ASSOC); + if (ret) + return ret; + } + assoc_data->synced = true; + + assoc_data->tries++; + if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { + printk(KERN_DEBUG "%s: association with %pM timed out\n", + sdata->name, assoc_data->bss->bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss); + + return -ETIMEDOUT; + } + + printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n", + sdata->name, assoc_data->bss->bssid, assoc_data->tries, + IEEE80211_ASSOC_MAX_TRIES); + ieee80211_send_assoc(sdata); + + assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; + run_again(&sdata->u.mgd, assoc_data->timeout); + + return 0; +} + void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - /* then process the rest of the work */ mutex_lock(&ifmgd->mtx); + if (ifmgd->auth_data && + time_after(jiffies, ifmgd->auth_data->timeout)) { + if (ifmgd->auth_data->done) { + /* + * ok ... we waited for assoc but userspace didn't, + * so let's just kill the auth data + */ + ieee80211_destroy_auth_data(sdata, false); + } else if (ieee80211_probe_auth(sdata)) { + u8 bssid[ETH_ALEN]; + + memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); + + ieee80211_destroy_auth_data(sdata, false); + + mutex_unlock(&ifmgd->mtx); + cfg80211_send_auth_timeout(sdata->dev, bssid); + mutex_lock(&ifmgd->mtx); + } + } else if (ifmgd->auth_data) + run_again(ifmgd, ifmgd->auth_data->timeout); + + if (ifmgd->assoc_data && + time_after(jiffies, ifmgd->assoc_data->timeout)) { + if (!ifmgd->assoc_data->have_beacon || + ieee80211_do_assoc(sdata)) { + u8 bssid[ETH_ALEN]; + + memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN); + + ieee80211_destroy_assoc_data(sdata, false); + + mutex_unlock(&ifmgd->mtx); + cfg80211_send_assoc_timeout(sdata->dev, bssid); + mutex_lock(&ifmgd->mtx); + } + } else if (ifmgd->assoc_data) + run_again(ifmgd, ifmgd->assoc_data->timeout); + if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL) && ifmgd->associated) { @@ -2249,6 +2931,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) } mutex_unlock(&ifmgd->mtx); + + mutex_lock(&local->mtx); + ieee80211_recalc_idle(local); + mutex_unlock(&local->mtx); } static void ieee80211_sta_bcn_mon_timer(unsigned long data) @@ -2421,50 +3107,24 @@ int ieee80211_max_network_latency(struct notifier_block *nb, } /* config hooks */ -static enum work_done_result -ieee80211_probe_auth_done(struct ieee80211_work *wk, - struct sk_buff *skb) -{ - struct ieee80211_local *local = wk->sdata->local; - - if (!skb) { - cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); - goto destroy; - } - - if (wk->type == IEEE80211_WORK_AUTH) { - cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); - goto destroy; - } - - mutex_lock(&wk->sdata->u.mgd.mtx); - ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); - mutex_unlock(&wk->sdata->u.mgd.mtx); - - wk->type = IEEE80211_WORK_AUTH; - wk->probe_auth.tries = 0; - return WORK_DONE_REQUEUE; - destroy: - if (wk->probe_auth.synced) - drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, - IEEE80211_TX_SYNC_AUTH); - - return WORK_DONE_DESTROY; -} - int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct cfg80211_auth_request *req) { - const u8 *ssid; - struct ieee80211_work *wk; + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_auth_data *auth_data; + struct sta_info *sta; u16 auth_alg; + int err; + + /* prepare auth data structure */ switch (req->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: auth_alg = WLAN_AUTH_OPEN; break; case NL80211_AUTHTYPE_SHARED_KEY: - if (IS_ERR(sdata->local->wep_tx_tfm)) + if (IS_ERR(local->wep_tx_tfm)) return -EOPNOTSUPP; auth_alg = WLAN_AUTH_SHARED_KEY; break; @@ -2478,169 +3138,142 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return -EOPNOTSUPP; } - wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); - if (!wk) + auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL); + if (!auth_data) return -ENOMEM; - memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); + auth_data->bss = req->bss; if (req->ie && req->ie_len) { - memcpy(wk->ie, req->ie, req->ie_len); - wk->ie_len = req->ie_len; + memcpy(auth_data->ie, req->ie, req->ie_len); + auth_data->ie_len = req->ie_len; } if (req->key && req->key_len) { - wk->probe_auth.key_len = req->key_len; - wk->probe_auth.key_idx = req->key_idx; - memcpy(wk->probe_auth.key, req->key, req->key_len); + auth_data->key_len = req->key_len; + auth_data->key_idx = req->key_idx; + memcpy(auth_data->key, req->key, req->key_len); } - ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); - wk->probe_auth.ssid_len = ssid[1]; - - wk->probe_auth.algorithm = auth_alg; - wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; - - /* if we already have a probe, don't probe again */ - if (req->bss->proberesp_ies) - wk->type = IEEE80211_WORK_AUTH; - else - wk->type = IEEE80211_WORK_DIRECT_PROBE; - wk->chan = req->bss->channel; - wk->chan_type = NL80211_CHAN_NO_HT; - wk->sdata = sdata; - wk->done = ieee80211_probe_auth_done; - - ieee80211_add_work(wk); - return 0; -} + auth_data->algorithm = auth_alg; -/* create and insert a dummy station entry */ -static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata, - u8 *bssid) { - struct sta_info *sta; - int err; + /* try to authenticate/probe */ - sta = sta_info_alloc(sdata, bssid, GFP_KERNEL); - if (!sta) - return -ENOMEM; + mutex_lock(&ifmgd->mtx); - err = sta_info_insert(sta); - sta = NULL; - if (err) { - printk(KERN_DEBUG "%s: failed to insert STA entry for" - " the AP (error %d)\n", sdata->name, err); - return err; + if ((ifmgd->auth_data && !ifmgd->auth_data->done) || + ifmgd->assoc_data) { + err = -EBUSY; + goto err_free; } - return 0; -} + if (ifmgd->auth_data) + ieee80211_destroy_auth_data(sdata, false); -static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, - struct sk_buff *skb) -{ - struct ieee80211_local *local = wk->sdata->local; - struct ieee80211_mgmt *mgmt; - struct ieee80211_rx_status *rx_status; - struct ieee802_11_elems elems; - struct cfg80211_bss *cbss = wk->assoc.bss; - u16 status; + /* prep auth_data so we don't go into idle on disassoc */ + ifmgd->auth_data = auth_data; - if (!skb) { - sta_info_destroy_addr(wk->sdata, cbss->bssid); - cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); - goto destroy; - } + if (ifmgd->associated) + ieee80211_set_disassoc(sdata, true, false); - if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { - mutex_lock(&wk->sdata->u.mgd.mtx); - rx_status = (void *) skb->cb; - ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems); - ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status, - &elems, true); - mutex_unlock(&wk->sdata->u.mgd.mtx); + printk(KERN_DEBUG "%s: authenticate with %pM\n", + sdata->name, req->bss->bssid); - wk->type = IEEE80211_WORK_ASSOC; - /* not really done yet */ - return WORK_DONE_REQUEUE; - } + mutex_lock(&local->mtx); + ieee80211_recalc_idle(sdata->local); + mutex_unlock(&local->mtx); - mgmt = (void *)skb->data; - status = le16_to_cpu(mgmt->u.assoc_resp.status_code); + /* switch to the right channel */ + local->oper_channel = req->bss->channel; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - if (status == WLAN_STATUS_SUCCESS) { - if (wk->assoc.synced) - drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, - IEEE80211_TX_SYNC_ASSOC); + /* set BSSID */ + memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); - mutex_lock(&wk->sdata->u.mgd.mtx); - if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { - mutex_unlock(&wk->sdata->u.mgd.mtx); - /* oops -- internal error -- send timeout for now */ - sta_info_destroy_addr(wk->sdata, cbss->bssid); - cfg80211_send_assoc_timeout(wk->sdata->dev, - wk->filter_ta); - return WORK_DONE_DESTROY; - } + /* add station entry */ + sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); + if (!sta) { + err = -ENOMEM; + goto err_clear; + } - mutex_unlock(&wk->sdata->u.mgd.mtx); - } else { - /* assoc failed - destroy the dummy station entry */ - sta_info_destroy_addr(wk->sdata, cbss->bssid); + err = sta_info_insert(sta); + if (err) { + printk(KERN_DEBUG + "%s: failed to insert STA entry for the AP %pM (error %d)\n", + sdata->name, req->bss->bssid, err); + goto err_clear; } - cfg80211_send_rx_assoc(wk->sdata->dev, cbss, skb->data, skb->len); - destroy: - if (wk->assoc.synced) - drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, - IEEE80211_TX_SYNC_ASSOC); + err = ieee80211_probe_auth(sdata); + if (err) { + if (auth_data->synced) + drv_finish_tx_sync(local, sdata, req->bss->bssid, + IEEE80211_TX_SYNC_AUTH); + sta_info_destroy_addr(sdata, req->bss->bssid); + goto err_clear; + } + + /* hold our own reference */ + cfg80211_ref_bss(auth_data->bss); + err = 0; + goto out_unlock; + + err_clear: + ifmgd->auth_data = NULL; + err_free: + kfree(auth_data); + out_unlock: + mutex_unlock(&ifmgd->mtx); - return WORK_DONE_DESTROY; + return err; } int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req) { + struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)req->bss->priv; - struct ieee80211_work *wk; - const u8 *ssid; + struct ieee80211_mgd_assoc_data *assoc_data; + struct sta_info *sta; + const u8 *ssidie; int i, err; + ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + if (!ssidie) + return -EINVAL; + + assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); + if (!assoc_data) + return -ENOMEM; + mutex_lock(&ifmgd->mtx); - if (ifmgd->associated) { - if (!req->prev_bssid || - memcmp(req->prev_bssid, ifmgd->associated->bssid, - ETH_ALEN)) { - /* - * We are already associated and the request was not a - * reassociation request from the current BSS, so - * reject it. - */ - mutex_unlock(&ifmgd->mtx); - return -EALREADY; - } - /* Trying to reassociate - clear previous association state */ + if (ifmgd->associated) ieee80211_set_disassoc(sdata, true, false); + + if (ifmgd->auth_data && !ifmgd->auth_data->done) { + err = -EBUSY; + goto err_free; } - mutex_unlock(&ifmgd->mtx); - wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); - if (!wk) - return -ENOMEM; + if (ifmgd->assoc_data) { + err = -EBUSY; + goto err_free; + } - /* - * create a dummy station info entry in order - * to start accepting incoming EAPOL packets from the station - */ - err = ieee80211_pre_assoc(sdata, req->bss->bssid); - if (err) { - kfree(wk); - return err; + if (ifmgd->auth_data) { + bool match; + + /* keep sta info, bssid if matching */ + match = memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN) == 0; + ieee80211_destroy_auth_data(sdata, match); } + /* prepare assoc data */ + ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; @@ -2652,7 +3285,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) ifmgd->flags |= IEEE80211_STA_DISABLE_11N; - if (req->flags & ASSOC_REQ_DISABLE_HT) ifmgd->flags |= IEEE80211_STA_DISABLE_11N; @@ -2661,16 +3293,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sizeof(ifmgd->ht_capa_mask)); if (req->ie && req->ie_len) { - memcpy(wk->ie, req->ie, req->ie_len); - wk->ie_len = req->ie_len; - } else - wk->ie_len = 0; - - wk->assoc.bss = req->bss; + memcpy(assoc_data->ie, req->ie, req->ie_len); + assoc_data->ie_len = req->ie_len; + } - memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); + assoc_data->bss = req->bss; - /* new association always uses requested smps mode */ if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { if (ifmgd->powersave) ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; @@ -2679,7 +3307,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } else ifmgd->ap_smps = ifmgd->req_smps; - wk->assoc.smps = ifmgd->ap_smps; /* * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. * We still associate in non-HT mode (11a/b/g) if any one of these @@ -2687,39 +3314,27 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, * We can set this to true for non-11n hardware, that'll be checked * separately along with the peer capabilities. */ - wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); - wk->assoc.capability = req->bss->capability; - wk->assoc.wmm_used = bss->wmm_used; - wk->assoc.supp_rates = bss->supp_rates; - wk->assoc.supp_rates_len = bss->supp_rates_len; - wk->assoc.ht_information_ie = + assoc_data->capability = req->bss->capability; + assoc_data->wmm_used = bss->wmm_used; + assoc_data->supp_rates = bss->supp_rates; + assoc_data->supp_rates_len = bss->supp_rates_len; + assoc_data->ht_information_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); if (bss->wmm_used && bss->uapsd_supported && (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { - wk->assoc.uapsd_used = true; + assoc_data->uapsd_used = true; ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; } else { - wk->assoc.uapsd_used = false; + assoc_data->uapsd_used = false; ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; } - ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); - wk->assoc.ssid_len = ssid[1]; + memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); + assoc_data->ssid_len = ssidie[1]; if (req->prev_bssid) - memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); - - wk->chan = req->bss->channel; - wk->chan_type = NL80211_CHAN_NO_HT; - wk->sdata = sdata; - wk->done = ieee80211_assoc_done; - if (!bss->dtim_period && - sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) - wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT; - else - wk->type = IEEE80211_WORK_ASSOC; + memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; @@ -2737,15 +3352,79 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.control_port_ethertype; sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; - ieee80211_add_work(wk); - return 0; + /* kick off associate process */ + + ifmgd->assoc_data = assoc_data; + + mutex_lock(&local->mtx); + ieee80211_recalc_idle(sdata->local); + mutex_unlock(&local->mtx); + + /* switch to the right channel */ + local->oper_channel = req->bss->channel; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + rcu_read_lock(); + sta = sta_info_get(sdata, req->bss->bssid); + rcu_read_unlock(); + + if (!sta) { + /* set BSSID */ + memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + + sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); + if (!sta) { + err = -ENOMEM; + goto err_clear; + } + + sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); + + err = sta_info_insert(sta); + sta = NULL; + if (err) { + printk(KERN_DEBUG + "%s: failed to insert STA entry for the AP (error %d)\n", + sdata->name, err); + goto err_clear; + } + } else + WARN_ON_ONCE(memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN)); + + if (!bss->dtim_period && + sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { + /* + * Wait up to one beacon interval ... + * should this be more if we miss one? + */ + printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", + sdata->name, ifmgd->bssid); + assoc_data->timeout = jiffies + + TU_TO_EXP_TIME(req->bss->beacon_interval); + } else { + assoc_data->have_beacon = true; + assoc_data->sent_assoc = false; + assoc_data->timeout = jiffies; + } + run_again(ifmgd, assoc_data->timeout); + + err = 0; + goto out; + err_clear: + ifmgd->assoc_data = NULL; + err_free: + kfree(assoc_data); + out: + mutex_unlock(&ifmgd->mtx); + + return err; } int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct cfg80211_deauth_request *req, void *cookie) { - struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; bool assoc_bss = false; @@ -2754,62 +3433,13 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) { ieee80211_set_disassoc(sdata, false, true); - mutex_unlock(&ifmgd->mtx); assoc_bss = true; - } else { - bool not_auth_yet = false; - struct ieee80211_work *tmp, *wk = NULL; - + } else if (ifmgd->auth_data) { + ieee80211_destroy_auth_data(sdata, false); mutex_unlock(&ifmgd->mtx); - - mutex_lock(&local->mtx); - list_for_each_entry(tmp, &local->work_list, list) { - if (tmp->sdata != sdata) - continue; - - if (tmp->type != IEEE80211_WORK_DIRECT_PROBE && - tmp->type != IEEE80211_WORK_AUTH && - tmp->type != IEEE80211_WORK_ASSOC && - tmp->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) - continue; - - if (memcmp(req->bssid, tmp->filter_ta, ETH_ALEN)) - continue; - - not_auth_yet = tmp->type == IEEE80211_WORK_DIRECT_PROBE; - list_del_rcu(&tmp->list); - synchronize_rcu(); - wk = tmp; - break; - } - mutex_unlock(&local->mtx); - - if (wk && wk->type == IEEE80211_WORK_ASSOC) { - /* clean up dummy sta & TX sync */ - sta_info_destroy_addr(wk->sdata, wk->filter_ta); - if (wk->assoc.synced) - drv_finish_tx_sync(local, wk->sdata, - wk->filter_ta, - IEEE80211_TX_SYNC_ASSOC); - } else if (wk && wk->type == IEEE80211_WORK_AUTH) { - if (wk->probe_auth.synced) - drv_finish_tx_sync(local, wk->sdata, - wk->filter_ta, - IEEE80211_TX_SYNC_AUTH); - } - kfree(wk); - - /* - * If somebody requests authentication and we haven't - * sent out an auth frame yet there's no need to send - * out a deauth frame either. If the state was PROBE, - * then this is the case. If it's AUTH we have sent a - * frame, and if it's IDLE we have completed the auth - * process already. - */ - if (not_auth_yet) - return 0; + return 0; } + mutex_unlock(&ifmgd->mtx); printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", sdata->name, req->bssid, req->reason_code); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8d6fa674f53..2b5b1194dfc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2484,14 +2484,9 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; - ieee80211_rx_result rxs; struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; __le16 stype; - rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); - if (rxs != RX_CONTINUE) - return rxs; - stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE); if (!ieee80211_vif_is_mesh(&sdata->vif) && @@ -2500,10 +2495,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; switch (stype) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): case cpu_to_le16(IEEE80211_STYPE_BEACON): case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): /* process for all: mesh, mlme, ibss */ break; + case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_DEAUTH): case cpu_to_le16(IEEE80211_STYPE_DISASSOC): if (is_multicast_ether_addr(mgmt->da) && @@ -2515,7 +2513,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; break; case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): - case cpu_to_le16(IEEE80211_STYPE_AUTH): /* process only for ibss */ if (sdata->vif.type != NL80211_IFTYPE_ADHOC) return RX_DROP_MONITOR; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 0a1a176fbe9..c6e230efa04 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -27,16 +27,9 @@ #include "rate.h" #include "driver-ops.h" -#define IEEE80211_AUTH_TIMEOUT (HZ / 5) -#define IEEE80211_AUTH_MAX_TRIES 3 -#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) -#define IEEE80211_ASSOC_MAX_TRIES 3 - enum work_action { - WORK_ACT_MISMATCH, WORK_ACT_NONE, WORK_ACT_TIMEOUT, - WORK_ACT_DONE, }; @@ -71,465 +64,6 @@ void free_work(struct ieee80211_work *wk) kfree_rcu(wk, rcu_head); } -static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, - struct ieee80211_supported_band *sband, - u32 *rates) -{ - int i, j, count; - *rates = 0; - count = 0; - for (i = 0; i < supp_rates_len; i++) { - int rate = (supp_rates[i] & 0x7F) * 5; - - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == rate) { - *rates |= BIT(j); - count++; - break; - } - } - - return count; -} - -/* frame sending functions */ - -static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, const u8 *ht_info_ie, - struct ieee80211_supported_band *sband, - struct ieee80211_channel *channel, - enum ieee80211_smps_mode smps) -{ - struct ieee80211_ht_info *ht_info; - u8 *pos; - u32 flags = channel->flags; - u16 cap; - struct ieee80211_sta_ht_cap ht_cap; - - BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); - - if (!sband->ht_cap.ht_supported) - return; - - if (!ht_info_ie) - return; - - if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) - return; - - memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); - ieee80211_apply_htcap_overrides(sdata, &ht_cap); - - ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); - - /* determine capability flags */ - cap = ht_cap.cap; - - switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (flags & IEEE80211_CHAN_NO_HT40PLUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (flags & IEEE80211_CHAN_NO_HT40MINUS) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - cap &= ~IEEE80211_HT_CAP_SGI_40; - } - break; - } - - /* set SM PS mode properly */ - cap &= ~IEEE80211_HT_CAP_SM_PS; - switch (smps) { - case IEEE80211_SMPS_AUTOMATIC: - case IEEE80211_SMPS_NUM_MODES: - WARN_ON(1); - case IEEE80211_SMPS_OFF: - cap |= WLAN_HT_CAP_SM_PS_DISABLED << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_STATIC: - cap |= WLAN_HT_CAP_SM_PS_STATIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - case IEEE80211_SMPS_DYNAMIC: - cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << - IEEE80211_HT_CAP_SM_PS_SHIFT; - break; - } - - /* reserve and fill IE */ - pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); - ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); -} - -static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, - struct ieee80211_work *wk) -{ - struct ieee80211_local *local = sdata->local; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u8 *pos, qos_info; - size_t offset = 0, noffset; - int i, count, rates_len, supp_rates_len; - u16 capab; - struct ieee80211_supported_band *sband; - u32 rates = 0; - - sband = local->hw.wiphy->bands[wk->chan->band]; - - if (wk->assoc.supp_rates_len) { - /* - * Get all rates supported by the device and the AP as - * some APs don't like getting a superset of their rates - * in the association request (e.g. D-Link DAP 1353 in - * b-only mode)... - */ - rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, - wk->assoc.supp_rates_len, - sband, &rates); - } else { - /* - * In case AP not provide any supported rates information - * before association, we send information element(s) with - * all rates that we support. - */ - rates = ~0; - rates_len = sband->n_bitrates; - } - - skb = alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + /* bit too much but doesn't matter */ - 2 + wk->assoc.ssid_len + /* SSID */ - 4 + rates_len + /* (extended) rates */ - 4 + /* power capability */ - 2 + 2 * sband->n_channels + /* supported channels */ - 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ - wk->ie_len + /* extra IEs */ - 9, /* WMM */ - GFP_KERNEL); - if (!skb) - return; - - skb_reserve(skb, local->hw.extra_tx_headroom); - - capab = WLAN_CAPABILITY_ESS; - - if (sband->band == IEEE80211_BAND_2GHZ) { - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; - } - - if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - - if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && - (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) - capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, wk->filter_ta, ETH_ALEN); - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN); - - if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { - skb_put(skb, 10); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_REASSOC_REQ); - mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.reassoc_req.listen_interval = - cpu_to_le16(local->hw.conf.listen_interval); - memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, - ETH_ALEN); - } else { - skb_put(skb, 4); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ASSOC_REQ); - mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.assoc_req.listen_interval = - cpu_to_le16(local->hw.conf.listen_interval); - } - - /* SSID */ - pos = skb_put(skb, 2 + wk->assoc.ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = wk->assoc.ssid_len; - memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); - - /* add all rates which were marked to be used above */ - supp_rates_len = rates_len; - if (supp_rates_len > 8) - supp_rates_len = 8; - - pos = skb_put(skb, supp_rates_len + 2); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = supp_rates_len; - - count = 0; - for (i = 0; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - if (++count == 8) - break; - } - } - - if (rates_len > count) { - pos = skb_put(skb, rates_len - count + 2); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates_len - count; - - for (i++; i < sband->n_bitrates; i++) { - if (BIT(i) & rates) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - } - } - - if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { - /* 1. power capabilities */ - pos = skb_put(skb, 4); - *pos++ = WLAN_EID_PWR_CAPABILITY; - *pos++ = 2; - *pos++ = 0; /* min tx power */ - *pos++ = wk->chan->max_power; /* max tx power */ - - /* 2. supported channels */ - /* TODO: get this in reg domain format */ - pos = skb_put(skb, 2 * sband->n_channels + 2); - *pos++ = WLAN_EID_SUPPORTED_CHANNELS; - *pos++ = 2 * sband->n_channels; - for (i = 0; i < sband->n_channels; i++) { - *pos++ = ieee80211_frequency_to_channel( - sband->channels[i].center_freq); - *pos++ = 1; /* one channel in the subband*/ - } - } - - /* if present, add any custom IEs that go before HT */ - if (wk->ie_len && wk->ie) { - static const u8 before_ht[] = { - WLAN_EID_SSID, - WLAN_EID_SUPP_RATES, - WLAN_EID_EXT_SUPP_RATES, - WLAN_EID_PWR_CAPABILITY, - WLAN_EID_SUPPORTED_CHANNELS, - WLAN_EID_RSN, - WLAN_EID_QOS_CAPA, - WLAN_EID_RRM_ENABLED_CAPABILITIES, - WLAN_EID_MOBILITY_DOMAIN, - WLAN_EID_SUPPORTED_REGULATORY_CLASSES, - }; - noffset = ieee80211_ie_split(wk->ie, wk->ie_len, - before_ht, ARRAY_SIZE(before_ht), - offset); - pos = skb_put(skb, noffset - offset); - memcpy(pos, wk->ie + offset, noffset - offset); - offset = noffset; - } - - if (wk->assoc.use_11n && wk->assoc.wmm_used && - local->hw.queues >= 4) - ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie, - sband, wk->chan, wk->assoc.smps); - - /* if present, add any custom non-vendor IEs that go after HT */ - if (wk->ie_len && wk->ie) { - noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len, - offset); - pos = skb_put(skb, noffset - offset); - memcpy(pos, wk->ie + offset, noffset - offset); - offset = noffset; - } - - if (wk->assoc.wmm_used && local->hw.queues >= 4) { - if (wk->assoc.uapsd_used) { - qos_info = local->uapsd_queues; - qos_info |= (local->uapsd_max_sp_len << - IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); - } else { - qos_info = 0; - } - - pos = skb_put(skb, 9); - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = qos_info; - } - - /* add any remaining custom (i.e. vendor specific here) IEs */ - if (wk->ie_len && wk->ie) { - noffset = wk->ie_len; - pos = skb_put(skb, noffset - offset); - memcpy(pos, wk->ie + offset, noffset - offset); - } - - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - ieee80211_tx_skb(sdata, skb); -} - -static void ieee80211_remove_auth_bss(struct ieee80211_local *local, - struct ieee80211_work *wk) -{ - struct cfg80211_bss *cbss; - u16 capa_val = WLAN_CAPABILITY_ESS; - - if (wk->probe_auth.privacy) - capa_val |= WLAN_CAPABILITY_PRIVACY; - - cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta, - wk->probe_auth.ssid, wk->probe_auth.ssid_len, - WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, - capa_val); - if (!cbss) - return; - - cfg80211_unlink_bss(local->hw.wiphy, cbss); - cfg80211_put_bss(cbss); -} - -static enum work_action __must_check -ieee80211_direct_probe(struct ieee80211_work *wk) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - - if (!wk->probe_auth.synced) { - int ret = drv_tx_sync(local, sdata, wk->filter_ta, - IEEE80211_TX_SYNC_AUTH); - if (ret) - return WORK_ACT_TIMEOUT; - } - wk->probe_auth.synced = true; - - wk->probe_auth.tries++; - if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", - sdata->name, wk->filter_ta); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - ieee80211_remove_auth_bss(local, wk); - - return WORK_ACT_TIMEOUT; - } - - printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", - sdata->name, wk->filter_ta, wk->probe_auth.tries, - IEEE80211_AUTH_MAX_TRIES); - - /* - * Direct probe is sent to broadcast address as some APs - * will not answer to direct packet in unassociated state. - */ - ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, - wk->probe_auth.ssid_len, NULL, 0, - (u32) -1, true, false); - - wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - run_again(local, wk->timeout); - - return WORK_ACT_NONE; -} - - -static enum work_action __must_check -ieee80211_authenticate(struct ieee80211_work *wk) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - - if (!wk->probe_auth.synced) { - int ret = drv_tx_sync(local, sdata, wk->filter_ta, - IEEE80211_TX_SYNC_AUTH); - if (ret) - return WORK_ACT_TIMEOUT; - } - wk->probe_auth.synced = true; - - wk->probe_auth.tries++; - if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with %pM" - " timed out\n", sdata->name, wk->filter_ta); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - ieee80211_remove_auth_bss(local, wk); - - return WORK_ACT_TIMEOUT; - } - - printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n", - sdata->name, wk->filter_ta, wk->probe_auth.tries); - - ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie, - wk->ie_len, wk->filter_ta, wk->filter_ta, NULL, 0, - 0); - wk->probe_auth.transaction = 2; - - wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - run_again(local, wk->timeout); - - return WORK_ACT_NONE; -} - -static enum work_action __must_check -ieee80211_associate(struct ieee80211_work *wk) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - - if (!wk->assoc.synced) { - int ret = drv_tx_sync(local, sdata, wk->filter_ta, - IEEE80211_TX_SYNC_ASSOC); - if (ret) - return WORK_ACT_TIMEOUT; - } - wk->assoc.synced = true; - - wk->assoc.tries++; - if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with %pM" - " timed out\n", - sdata->name, wk->filter_ta); - - /* - * Most likely AP is not in the range so remove the - * bss struct for that AP. - */ - if (wk->assoc.bss) - cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss); - - return WORK_ACT_TIMEOUT; - } - - printk(KERN_DEBUG "%s: associate with %pM (try %d)\n", - sdata->name, wk->filter_ta, wk->assoc.tries); - ieee80211_send_assoc(sdata, wk); - - wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; - run_again(local, wk->timeout); - - return WORK_ACT_NONE; -} - static enum work_action __must_check ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) { @@ -569,300 +103,6 @@ ieee80211_offchannel_tx(struct ieee80211_work *wk) return WORK_ACT_TIMEOUT; } -static enum work_action __must_check -ieee80211_assoc_beacon_wait(struct ieee80211_work *wk) -{ - if (wk->started) - return WORK_ACT_TIMEOUT; - - /* - * Wait up to one beacon interval ... - * should this be more if we miss one? - */ - printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", - wk->sdata->name, wk->filter_ta); - wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval); - return WORK_ACT_NONE; -} - -static void ieee80211_auth_challenge(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - u8 *pos; - struct ieee802_11_elems elems; - - pos = mgmt->u.auth.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - if (!elems.challenge) - return; - ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm, - elems.challenge - 2, elems.challenge_len + 2, - wk->filter_ta, wk->filter_ta, wk->probe_auth.key, - wk->probe_auth.key_len, wk->probe_auth.key_idx); - wk->probe_auth.transaction = 4; -} - -static enum work_action __must_check -ieee80211_rx_mgmt_auth(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len) -{ - u16 auth_alg, auth_transaction, status_code; - - if (wk->type != IEEE80211_WORK_AUTH) - return WORK_ACT_MISMATCH; - - if (len < 24 + 6) - return WORK_ACT_NONE; - - auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); - auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - status_code = le16_to_cpu(mgmt->u.auth.status_code); - - if (auth_alg != wk->probe_auth.algorithm || - auth_transaction != wk->probe_auth.transaction) - return WORK_ACT_NONE; - - if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", - wk->sdata->name, mgmt->sa, status_code); - return WORK_ACT_DONE; - } - - switch (wk->probe_auth.algorithm) { - case WLAN_AUTH_OPEN: - case WLAN_AUTH_LEAP: - case WLAN_AUTH_FT: - break; - case WLAN_AUTH_SHARED_KEY: - if (wk->probe_auth.transaction != 4) { - ieee80211_auth_challenge(wk, mgmt, len); - /* need another frame */ - return WORK_ACT_NONE; - } - break; - default: - WARN_ON(1); - return WORK_ACT_NONE; - } - - printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name); - return WORK_ACT_DONE; -} - -static enum work_action __must_check -ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len, - bool reassoc) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - u16 capab_info, status_code, aid; - struct ieee802_11_elems elems; - u8 *pos; - - if (wk->type != IEEE80211_WORK_ASSOC) - return WORK_ACT_MISMATCH; - - /* - * AssocResp and ReassocResp have identical structure, so process both - * of them in this function. - */ - - if (len < 24 + 6) - return WORK_ACT_NONE; - - capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); - status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); - aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - - printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " - "status=%d aid=%d)\n", - sdata->name, reassoc ? "Rea" : "A", mgmt->sa, - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); - - pos = mgmt->u.assoc_resp.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - - if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && - elems.timeout_int && elems.timeout_int_len == 5 && - elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { - u32 tu, ms; - tu = get_unaligned_le32(elems.timeout_int + 1); - ms = tu * 1024 / 1000; - printk(KERN_DEBUG "%s: %pM rejected association temporarily; " - "comeback duration %u TU (%u ms)\n", - sdata->name, mgmt->sa, tu, ms); - wk->timeout = jiffies + msecs_to_jiffies(ms); - if (ms > IEEE80211_ASSOC_TIMEOUT) - run_again(local, wk->timeout); - return WORK_ACT_NONE; - } - - if (status_code != WLAN_STATUS_SUCCESS) - printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", - sdata->name, mgmt->sa, status_code); - else - printk(KERN_DEBUG "%s: associated\n", sdata->name); - - return WORK_ACT_DONE; -} - -static enum work_action __must_check -ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - size_t baselen; - - ASSERT_WORK_MTX(local); - - if (wk->type != IEEE80211_WORK_DIRECT_PROBE) - return WORK_ACT_MISMATCH; - - if (len < 24 + 12) - return WORK_ACT_NONE; - - baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; - if (baselen > len) - return WORK_ACT_NONE; - - printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); - return WORK_ACT_DONE; -} - -static enum work_action __must_check -ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk, - struct ieee80211_mgmt *mgmt, size_t len) -{ - struct ieee80211_sub_if_data *sdata = wk->sdata; - struct ieee80211_local *local = sdata->local; - - ASSERT_WORK_MTX(local); - - if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) - return WORK_ACT_MISMATCH; - - if (len < 24 + 12) - return WORK_ACT_NONE; - - printk(KERN_DEBUG "%s: beacon received\n", sdata->name); - return WORK_ACT_DONE; -} - -static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, - struct sk_buff *skb) -{ - struct ieee80211_rx_status *rx_status; - struct ieee80211_mgmt *mgmt; - struct ieee80211_work *wk; - enum work_action rma = WORK_ACT_NONE; - u16 fc; - - rx_status = (struct ieee80211_rx_status *) skb->cb; - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); - - mutex_lock(&local->mtx); - - list_for_each_entry(wk, &local->work_list, list) { - const u8 *bssid = NULL; - - switch (wk->type) { - case IEEE80211_WORK_DIRECT_PROBE: - case IEEE80211_WORK_AUTH: - case IEEE80211_WORK_ASSOC: - case IEEE80211_WORK_ASSOC_BEACON_WAIT: - bssid = wk->filter_ta; - break; - default: - continue; - } - - /* - * Before queuing, we already verified mgmt->sa, - * so this is needed just for matching. - */ - if (compare_ether_addr(bssid, mgmt->bssid)) - continue; - - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_BEACON: - rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len); - break; - case IEEE80211_STYPE_PROBE_RESP: - rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_AUTH: - rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len); - break; - case IEEE80211_STYPE_ASSOC_RESP: - rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, - skb->len, false); - break; - case IEEE80211_STYPE_REASSOC_RESP: - rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, - skb->len, true); - break; - default: - WARN_ON(1); - rma = WORK_ACT_NONE; - } - - /* - * We've either received an unexpected frame, or we have - * multiple work items and need to match the frame to the - * right one. - */ - if (rma == WORK_ACT_MISMATCH) - continue; - - /* - * We've processed this frame for that work, so it can't - * belong to another work struct. - * NB: this is also required for correctness for 'rma'! - */ - break; - } - - switch (rma) { - case WORK_ACT_MISMATCH: - /* ignore this unmatched frame */ - break; - case WORK_ACT_NONE: - break; - case WORK_ACT_DONE: - list_del_rcu(&wk->list); - break; - default: - WARN(1, "unexpected: %d", rma); - } - - mutex_unlock(&local->mtx); - - if (rma != WORK_ACT_DONE) - goto out; - - switch (wk->done(wk, skb)) { - case WORK_DONE_DESTROY: - free_work(wk); - break; - case WORK_DONE_REQUEUE: - synchronize_rcu(); - wk->started = false; /* restart */ - mutex_lock(&local->mtx); - list_add_tail(&wk->list, &local->work_list); - mutex_unlock(&local->mtx); - } - - out: - kfree_skb(skb); -} - static void ieee80211_work_timer(unsigned long data) { struct ieee80211_local *local = (void *) data; @@ -877,7 +117,6 @@ static void ieee80211_work_work(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, work_work); - struct sk_buff *skb; struct ieee80211_work *wk, *tmp; LIST_HEAD(free_work); enum work_action rma; @@ -893,10 +132,6 @@ static void ieee80211_work_work(struct work_struct *work) if (WARN(local->suspended, "work scheduled while going to suspend\n")) return; - /* first process frames to avoid timing out while a frame is pending */ - while ((skb = skb_dequeue(&local->work_skb_queue))) - ieee80211_work_rx_queued_mgmt(local, skb); - mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -947,24 +182,12 @@ static void ieee80211_work_work(struct work_struct *work) case IEEE80211_WORK_ABORT: rma = WORK_ACT_TIMEOUT; break; - case IEEE80211_WORK_DIRECT_PROBE: - rma = ieee80211_direct_probe(wk); - break; - case IEEE80211_WORK_AUTH: - rma = ieee80211_authenticate(wk); - break; - case IEEE80211_WORK_ASSOC: - rma = ieee80211_associate(wk); - break; case IEEE80211_WORK_REMAIN_ON_CHANNEL: rma = ieee80211_remain_on_channel_timeout(wk); break; case IEEE80211_WORK_OFFCHANNEL_TX: rma = ieee80211_offchannel_tx(wk); break; - case IEEE80211_WORK_ASSOC_BEACON_WAIT: - rma = ieee80211_assoc_beacon_wait(wk); - break; } wk->started = started; @@ -1052,7 +275,6 @@ void ieee80211_work_init(struct ieee80211_local *local) setup_timer(&local->work_timer, ieee80211_work_timer, (unsigned long)local); INIT_WORK(&local->work_work, ieee80211_work_work); - skb_queue_head_init(&local->work_skb_queue); } void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) @@ -1086,43 +308,6 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->mtx); } -ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_mgmt *mgmt; - struct ieee80211_work *wk; - u16 fc; - - if (skb->len < 24) - return RX_DROP_MONITOR; - - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); - - list_for_each_entry_rcu(wk, &local->work_list, list) { - if (sdata != wk->sdata) - continue; - if (compare_ether_addr(wk->filter_ta, mgmt->sa)) - continue; - if (compare_ether_addr(wk->filter_ta, mgmt->bssid)) - continue; - - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - case IEEE80211_STYPE_BEACON: - skb_queue_tail(&local->work_skb_queue, skb); - ieee80211_queue_work(&local->hw, &local->work_work); - return RX_QUEUED; - } - } - - return RX_CONTINUE; -} - static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, struct sk_buff *skb) { -- cgit v1.2.3-70-g09d2 From 267335d63b808dc861f3a4dc81a605489a8a13ac Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 31 Jan 2012 20:25:47 +0100 Subject: cfg80211/mac80211: userspace peer authorization in IBSS If the IBSS network is RSN-protected, let userspace authorize the stations instead of adding them as AUTHORIZED by default. Signed-off-by: Antonio Quartulli Signed-off-by: John W. Linville --- include/net/cfg80211.h | 5 +++++ net/mac80211/ibss.c | 6 +++++- net/mac80211/ieee80211_i.h | 2 ++ net/wireless/nl80211.c | 20 ++++++++++++-------- 4 files changed, 24 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 229edc526cf..e0c9ff3a197 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1147,6 +1147,10 @@ struct cfg80211_disassoc_request { * @beacon_interval: beacon interval to use * @privacy: this is a protected network, keys will be configured * after joining + * @control_port: whether user space controls IEEE 802.1X port, i.e., + * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is + * required to assume that the port is unauthorized until authorized by + * user space. Otherwise, port is marked authorized by default. * @basic_rates: bitmap of basic rates to use when creating the IBSS * @mcast_rate: per-band multicast rate index + 1 (0: disabled) */ @@ -1161,6 +1165,7 @@ struct cfg80211_ibss_params { u32 basic_rates; bool channel_fixed; bool privacy; + bool control_port; int mcast_rate[IEEE80211_NUM_BANDS]; }; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 7b3a0b0aa24..8361da4b36a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -268,7 +268,10 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); - sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); + /* authorize the station only if the network is not RSN protected. If + * not wait for the userspace to authorize it */ + if (!sta->sdata->u.ibss.control_port) + sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); rate_control_rate_init(sta); @@ -1075,6 +1078,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.fixed_bssid = false; sdata->u.ibss.privacy = params->privacy; + sdata->u.ibss.control_port = params->control_port; sdata->u.ibss.basic_rates = params->basic_rates; memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, sizeof(params->mcast_rate)); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a146b1177cb..74594f012cd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -478,6 +478,8 @@ struct ieee80211_if_ibss { bool fixed_channel; bool privacy; + bool control_port; + u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len, ie_len; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e1fd1bf9072..f1681e2c594 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2654,13 +2654,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - /* disallow things sta doesn't support */ - if (params.plink_action) - return -EINVAL; - if (params.ht_capa) - return -EINVAL; - if (params.listen_interval >= 0) - return -EINVAL; /* * Don't allow userspace to change the TDLS_PEER flag, * but silently ignore attempts to change it since we @@ -2668,7 +2661,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) * to change the flag. */ params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); - + /* fall through */ + case NL80211_IFTYPE_ADHOC: + /* disallow things sta doesn't support */ + if (params.plink_action) + return -EINVAL; + if (params.ht_capa) + return -EINVAL; + if (params.listen_interval >= 0) + return -EINVAL; /* reject any changes other than AUTHORIZED */ if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) return -EINVAL; @@ -4802,6 +4803,9 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) return PTR_ERR(connkeys); } + ibss.control_port = + nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]); + err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); if (err) kfree(connkeys); -- cgit v1.2.3-70-g09d2 From 910570b5f4dbf75b73389010704ca6442a767a41 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 1 Feb 2012 10:42:11 +0300 Subject: mac80211: off by one in mcs mask handling "ridx" is used as an index into the mcs_mask[] array which has IEEE80211_HT_MCS_MASK_LEN elements. Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- net/mac80211/rate.c | 2 +- net/wireless/nl80211.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 3fef26d8898..22fc28e9026 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -324,7 +324,7 @@ static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate, rbit = rate->idx % 8; /* sanity check */ - if (ridx < 0 || ridx > IEEE80211_HT_MCS_MASK_LEN) + if (ridx < 0 || ridx >= IEEE80211_HT_MCS_MASK_LEN) return false; /* See whether the selected rate or anything below it is allowed. */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f1681e2c594..fe274765356 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5410,7 +5410,7 @@ static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, rbit = BIT(rates[i] % 8); /* check validity */ - if ((ridx < 0) || (ridx > IEEE80211_HT_MCS_MASK_LEN)) + if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN)) return false; /* check availability */ -- cgit v1.2.3-70-g09d2 From 885bd8eca6ac172e299750d99bd5c9fddbed89b9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 2 Feb 2012 17:44:55 +0200 Subject: mac80211: support hw scan while idle Currently, mac80211 goes to idle-off before starting a scan. However, some devices that implement hw scan might not need going idle-off in order to perform a hw scan, and thus saving some energy and simplifying their state machine. (Note that this is also the case for sched scan - it currently doesn't make mac80211 go idle-off) Add a new flag to indicate support for hw scan while idle. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- include/net/mac80211.h | 5 +++++ net/mac80211/debugfs.c | 2 ++ net/mac80211/iface.c | 3 ++- net/mac80211/main.c | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 922313f0b39..cbff4f94a20 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1164,6 +1164,10 @@ enum sta_notify_cmd { * @IEEE80211_HW_TX_AMPDU_SETUP_IN_HW: The device handles TX A-MPDU session * setup strictly in HW. mac80211 should not attempt to do this in * software. + * + * @IEEE80211_HW_SCAN_WHILE_IDLE: The device can do hw scan while + * being idle (i.e. mac80211 doesn't have to go idle-off during the + * the scan). */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -1190,6 +1194,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, IEEE80211_HW_AP_LINK_PS = 1<<22, IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23, + IEEE80211_HW_SCAN_WHILE_IDLE = 1<<24, }; /** diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index affe64be909..483e96ed95c 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -263,6 +263,8 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); + if (local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE) + sf += snprintf(buf + sf, mxln - sf, "SCAN_WHILE_IDLE\n"); rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); kfree(buf); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 19f0818eba7..6b3cd65d1e0 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1332,7 +1332,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) wk->sdata->vif.bss_conf.idle = false; } - if (local->scan_sdata) { + if (local->scan_sdata && + !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { scanning = true; local->scan_sdata->vif.bss_conf.idle = false; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 362e89d6d46..831a5bd44fd 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -697,6 +697,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ) return -EINVAL; + if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) + return -EINVAL; + if (hw->max_report_rates == 0) hw->max_report_rates = hw->max_rates; -- cgit v1.2.3-70-g09d2 From a0417fa3a18a14be1f4d9cffcf378a7c42d92a91 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 6 Feb 2012 15:14:37 -0500 Subject: net: Make qdisc_skb_cb upper size bound explicit. Just like skb->cb[], so that qdisc_skb_cb can be encapsulated inside of other data structures. This is intended to be used by IPoIB so that it can remember addressing information stored at hard_header_ops->create() time that it can fetch when the packet gets to the transmit routine. Signed-off-by: David S. Miller --- include/net/sch_generic.h | 9 ++++++++- net/sched/sch_choke.c | 3 +-- net/sched/sch_netem.c | 3 +-- net/sched/sch_sfb.c | 3 +-- net/sched/sch_sfq.c | 5 ++--- 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index f6bb08b73ca..55ce96b53b0 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -220,9 +220,16 @@ struct tcf_proto { struct qdisc_skb_cb { unsigned int pkt_len; - long data[]; + unsigned char data[24]; }; +static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) +{ + struct qdisc_skb_cb *qcb; + BUILD_BUG_ON(sizeof(skb->cb) < sizeof(unsigned int) + sz); + BUILD_BUG_ON(sizeof(qcb->data) < sz); +} + static inline int qdisc_qlen(const struct Qdisc *q) { return q->q.qlen; diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index e465064d39a..7e267d7b9c7 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -148,8 +148,7 @@ struct choke_skb_cb { static inline struct choke_skb_cb *choke_skb_cb(const struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < - sizeof(struct qdisc_skb_cb) + sizeof(struct choke_skb_cb)); + qdisc_cb_private_validate(skb, sizeof(struct choke_skb_cb)); return (struct choke_skb_cb *)qdisc_skb_cb(skb)->data; } diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 2776012132e..e83d61ca78c 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -130,8 +130,7 @@ struct netem_skb_cb { static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < - sizeof(struct qdisc_skb_cb) + sizeof(struct netem_skb_cb)); + qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb)); return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data; } diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 96e42cae4c7..d7eea99333e 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -94,8 +94,7 @@ struct sfb_skb_cb { static inline struct sfb_skb_cb *sfb_skb_cb(const struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < - sizeof(struct qdisc_skb_cb) + sizeof(struct sfb_skb_cb)); + qdisc_cb_private_validate(skb, sizeof(struct sfb_skb_cb)); return (struct sfb_skb_cb *)qdisc_skb_cb(skb)->data; } diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 67494aef9ac..60d47180f04 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -166,9 +166,8 @@ struct sfq_skb_cb { static inline struct sfq_skb_cb *sfq_skb_cb(const struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < - sizeof(struct qdisc_skb_cb) + sizeof(struct sfq_skb_cb)); - return (struct sfq_skb_cb *)qdisc_skb_cb(skb)->data; + qdisc_cb_private_validate(skb, sizeof(struct sfq_skb_cb)); + return (struct sfq_skb_cb *)qdisc_skb_cb(skb)->data; } static unsigned int sfq_hash(const struct sfq_sched_data *q, -- cgit v1.2.3-70-g09d2 From e1936e9407138b483e6d1332dd944afec8131f30 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Jan 2012 13:55:23 +0100 Subject: mac80211: call rate control only after init There are situations where we don't have the necessary rate control information yet for station entries, e.g. when associating. This currently doesn't really happen due to the dummy station handling; explicitly disabling rate control when it's not initialised will allow us to remove dummy stations. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 4 ++-- net/mac80211/rate.c | 2 +- net/mac80211/rate.h | 1 + net/mac80211/sta_info.h | 2 ++ 4 files changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c8383712fde..6d45804d09b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -63,7 +63,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" int res = scnprintf(buf, sizeof(buf), - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", TEST(AUTH), TEST(ASSOC), TEST(PS_STA), TEST(PS_DRIVER), TEST(AUTHORIZED), TEST(SHORT_PREAMBLE), @@ -71,7 +71,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), - TEST(INSERTED)); + TEST(INSERTED), TEST(RATE_CONTROL)); #undef TEST return simple_read_from_buffer(userbuf, count, ppos, buf, res); } diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 22fc28e9026..111fba38be8 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -439,7 +439,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, u32 mask; u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; - if (sta) { + if (sta && test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) { ista = &sta->sta; priv_sta = sta->rate_ctrl_priv; } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 8268457bd14..5fc3135a6b4 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -58,6 +58,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; ref->ops->rate_init(ref->priv, sband, ista, priv_sta); + set_sta_flag(sta, WLAN_STA_RATE_CONTROL); } static inline void rate_control_rate_update(struct ieee80211_local *local, diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 03f249bc276..23a97c9dc04 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -53,6 +53,7 @@ * reply to other uAPSD trigger frames or PS-Poll. * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. * @WLAN_STA_INSERTED: This station is inserted into the hash table. + * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH, @@ -73,6 +74,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_SP, WLAN_STA_4ADDR_EVENT, WLAN_STA_INSERTED, + WLAN_STA_RATE_CONTROL, }; #define STA_TID_NUM 16 -- cgit v1.2.3-70-g09d2 From 8809b255a9fca8c3179491d3bc9268c42e23ba97 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 25 Oct 2011 10:44:35 -0400 Subject: tipc: improve the link deferred queue insertion algorithm Re-code the algorithm for inserting an out-of-sequence message into a unicast or broadcast link's deferred message queue. It remains functionally equivalent but should be easier to understand/maintain. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index ac1832a66f8..c317abf74a7 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1853,17 +1853,16 @@ cont: } /* - * link_defer_buf(): Sort a received out-of-sequence packet - * into the deferred reception queue. - * Returns the increase of the queue length,i.e. 0 or 1 + * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue + * + * Returns increase in queue length (i.e. 0 or 1) */ -u32 tipc_link_defer_pkt(struct sk_buff **head, - struct sk_buff **tail, +u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail, struct sk_buff *buf) { - struct sk_buff *prev = NULL; - struct sk_buff *crs = *head; + struct sk_buff *queue_buf; + struct sk_buff **prev; u32 seq_no = buf_seqno(buf); buf->next = NULL; @@ -1881,31 +1880,30 @@ u32 tipc_link_defer_pkt(struct sk_buff **head, return 1; } - /* Scan through queue and sort it in */ - do { - struct tipc_msg *msg = buf_msg(crs); + /* Locate insertion point in queue, then insert; discard if duplicate */ + prev = head; + queue_buf = *head; + for (;;) { + u32 curr_seqno = buf_seqno(queue_buf); - if (less(seq_no, msg_seqno(msg))) { - buf->next = crs; - if (prev) - prev->next = buf; - else - *head = buf; - return 1; + if (seq_no == curr_seqno) { + buf_discard(buf); + return 0; } - if (seq_no == msg_seqno(msg)) + + if (less(seq_no, curr_seqno)) break; - prev = crs; - crs = crs->next; - } while (crs); - /* Message is a duplicate of an existing message */ + prev = &queue_buf->next; + queue_buf = queue_buf->next; + } - buf_discard(buf); - return 0; + buf->next = queue_buf; + *prev = buf; + return 1; } -/** +/* * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet */ -- cgit v1.2.3-70-g09d2 From 92d2c905b404d8d056ce35a0ce645e23529742c2 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 25 Oct 2011 11:20:26 -0400 Subject: tipc: Prevent transmission of outdated link protocol messages Ensures that a link endpoint discards any previously deferred link protocol message whenever it attempts to send a new one. Previously, it was possible for a link protocol message that was unsent due to congestion to be transmitted after newer protocol messages had been sent. The stale link protocol message might then cause the receiving link endpoint to malfunction because of its outdated conent. Thanks to Osamu Kaminuma [okaminum@avaya.com] for diagnosing the problem and contributing a prototype patch. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 53 +++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index c317abf74a7..bee316ce387 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1954,6 +1954,13 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, u32 msg_size = sizeof(l_ptr->proto_msg); int r_flag; + /* Discard any previous message that was deferred due to congestion */ + + if (l_ptr->proto_msg_queue) { + buf_discard(l_ptr->proto_msg_queue); + l_ptr->proto_msg_queue = NULL; + } + if (link_blocked(l_ptr)) return; @@ -1962,6 +1969,8 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG)) return; + /* Create protocol message with "out-of-sequence" sequence number */ + msg_set_type(msg, msg_typ); msg_set_net_plane(msg, l_ptr->b_ptr->net_plane); msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in)); @@ -2018,44 +2027,36 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, r_flag = (l_ptr->owner->working_links > tipc_link_is_up(l_ptr)); msg_set_redundant_link(msg, r_flag); msg_set_linkprio(msg, l_ptr->priority); - - /* Ensure sequence number will not fit : */ + msg_set_size(msg, msg_size); msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2))); - /* Congestion? */ - - if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) { - if (!l_ptr->proto_msg_queue) { - l_ptr->proto_msg_queue = - tipc_buf_acquire(sizeof(l_ptr->proto_msg)); - } - buf = l_ptr->proto_msg_queue; - if (!buf) - return; - skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); - return; - } - - /* Message can be sent */ - buf = tipc_buf_acquire(msg_size); if (!buf) return; skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); - msg_set_size(buf_msg(buf), msg_size); - if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { - l_ptr->unacked_window = 0; - buf_discard(buf); + /* Defer message if bearer is already congested */ + + if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) { + l_ptr->proto_msg_queue = buf; + return; + } + + /* Defer message if attempting to send results in bearer congestion */ + + if (!tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { + tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); + l_ptr->proto_msg_queue = buf; + l_ptr->stats.bearer_congs++; return; } - /* New congestion */ - tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); - l_ptr->proto_msg_queue = buf; - l_ptr->stats.bearer_congs++; + /* Discard message if it was sent successfully */ + + l_ptr->unacked_window = 0; + buf_discard(buf); } /* -- cgit v1.2.3-70-g09d2 From 4d75313ce9b832efc4efb487f080b5ed72beae2c Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 25 Oct 2011 12:19:05 -0400 Subject: tipc: Prevent broadcast link stalling in dual LAN environments Ensure that sequence number information about incoming broadcast link messages is initialized only by the activation of the first link to a given cluster node. Previously, a race condition allowed reset and/or activation messages for a second link to re-initialize this sequence number information with obsolete values. This could trigger TIPC to request the retransmission of previously acknowledged broadcast link messages from that node, resulting in broadcast link processing becoming stalled if the node had already released one or more of those messages and was unable to perform the required retransmission. Thanks to Laser for identifying this problem and assisting in the development of this fix. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index bee316ce387..4ea6cad1174 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -2128,14 +2128,15 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) } l_ptr->owner->bclink.supported = (max_pkt_info != 0); + /* Synchronize broadcast link info, if not done previously */ + + if (!tipc_node_is_up(l_ptr->owner)) + l_ptr->owner->bclink.last_in = msg_last_bcast(msg); + link_state_event(l_ptr, msg_type(msg)); l_ptr->peer_session = msg_session(msg); l_ptr->peer_bearer_id = msg_bearer_id(msg); - - /* Synchronize broadcast sequence numbers */ - if (!tipc_node_redundant_links(l_ptr->owner)) - l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg)); break; case STATE_MSG: -- cgit v1.2.3-70-g09d2 From 934993137199ffb56fef50664f87e71cdb3471b0 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 25 Oct 2011 15:14:46 -0400 Subject: tipc: Ensure broadcast link re-acquires node after link failure Fix a bug that can prevent TIPC from sending broadcast messages to a node if contact with the node is lost and then regained. The problem occurs if the broadcast link first clears the flag indicating the node is part of the link's distribution set (when it loses contact with the node), and later fails to restore the flag (when contact is regained); restoration fails if contact with the node is regained by implicit unicast link activation triggered by the arrival of a data message, rather than explicitly by the arrival of a link activation message. The broadcast link now uses separate fields to track whether a node is theoretically capable of receiving broadcast messages versus whether it is actually part of the link's distribution set. The former member is updated by the receipt of link protocol messages, which can occur at any time; the latter member is updated only when contact with the node is gained or lost. This change also permits the simplification of several conditional expressions since the broadcast link's "supported" field can now only be set if there are working links to the associated node. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 5 +++-- net/tipc/node.c | 3 ++- net/tipc/node.h | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index 4ea6cad1174..3405f560a84 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1502,6 +1502,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr, tipc_addr_string_fill(addr_string, n_ptr->addr); info("Multicast link info for %s\n", addr_string); + info("Supportable: %d, ", n_ptr->bclink.supportable); info("Supported: %d, ", n_ptr->bclink.supported); info("Acked: %u\n", n_ptr->bclink.acked); info("Last in: %u, ", n_ptr->bclink.last_in); @@ -1736,7 +1737,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) /* Release acked messages */ - if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported) + if (n_ptr->bclink.supported) tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg)); crs = l_ptr->first_out; @@ -2126,7 +2127,7 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) } else { l_ptr->max_pkt = l_ptr->max_pkt_target; } - l_ptr->owner->bclink.supported = (max_pkt_info != 0); + l_ptr->owner->bclink.supportable = (max_pkt_info != 0); /* Synchronize broadcast link info, if not done previously */ diff --git a/net/tipc/node.c b/net/tipc/node.c index 6b226faad89..9196f943b83 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -306,8 +306,9 @@ static void node_established_contact(struct tipc_node *n_ptr) /* Syncronize broadcast acks */ n_ptr->bclink.acked = tipc_bclink_get_last_sent(); - if (n_ptr->bclink.supported) { + if (n_ptr->bclink.supportable) { tipc_bclink_add_node(n_ptr->addr); + n_ptr->bclink.supported = 1; if (n_ptr->addr < tipc_own_addr) tipc_own_tag++; } diff --git a/net/tipc/node.h b/net/tipc/node.h index 0b1c5f8b699..90689f48761 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -62,6 +62,7 @@ * @link_cnt: number of links to node * @permit_changeover: non-zero if node has redundant links to this system * @bclink: broadcast-related info + * @supportable: non-zero if node supports TIPC b'cast link capability * @supported: non-zero if node supports TIPC b'cast capability * @acked: sequence # of last outbound b'cast message acknowledged by node * @last_in: sequence # of last in-sequence b'cast message received from node @@ -86,7 +87,8 @@ struct tipc_node { int block_setup; int permit_changeover; struct { - int supported; + u8 supportable; + u8 supported; u32 acked; u32 last_in; u32 gap_after; -- cgit v1.2.3-70-g09d2 From 47361c87c504d89f1ba50b4230d56ef67792c258 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 26 Oct 2011 10:55:16 -0400 Subject: tipc: Fix problem with broadcast link synchronization between nodes Corrects a problem in which a link endpoint that activates as the result of receiving a RESET/STATE sequence of link protocol messages fails to properly record the broadcast link status information about the node to which it is now communicating with. (The problem does not occur with the more common RESET/ACTIVATE sequence of messages.) The fix ensures that the broadcast link status info is updated after the RESET message resets the link endpoint, rather than before, thereby preventing new information from being overwritten by the reset operation. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index 3405f560a84..1150ba5a648 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -2105,6 +2105,8 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) l_ptr->owner->block_setup = WAIT_NODE_DOWN; } + link_state_event(l_ptr, RESET_MSG); + /* fall thru' */ case ACTIVATE_MSG: /* Update link settings according other endpoint's values */ @@ -2134,10 +2136,11 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) if (!tipc_node_is_up(l_ptr->owner)) l_ptr->owner->bclink.last_in = msg_last_bcast(msg); - link_state_event(l_ptr, msg_type(msg)); - l_ptr->peer_session = msg_session(msg); l_ptr->peer_bearer_id = msg_bearer_id(msg); + + if (msg_type(msg) == ACTIVATE_MSG) + link_state_event(l_ptr, ACTIVATE_MSG); break; case STATE_MSG: -- cgit v1.2.3-70-g09d2 From 57732560d1aa7d454d10e557f8959d19d1454174 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 26 Oct 2011 11:41:45 -0400 Subject: tipc: Add missing broadcast link lock when sending NACK Ensures that any attempt to send a NACK message over TIPC's broadcast link has exclusive access to the link's main data structures, to prevent interference with a simultaneous attempt to send other broadcast link traffic (such as application-generated multicast messages). Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 8eb87b11d10..7342abc2cfa 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -340,8 +340,10 @@ static void bclink_send_nack(struct tipc_node *n_ptr) msg_set_bcgap_to(msg, n_ptr->bclink.gap_to); msg_set_bcast_tag(msg, tipc_own_tag); + spin_lock_bh(&bc_lock); tipc_bearer_send(&bcbearer->bearer, buf, NULL); bcl->stats.sent_nacks++; + spin_unlock_bh(&bc_lock); buf_discard(buf); /* -- cgit v1.2.3-70-g09d2 From 8a275a6a30ba871eb34ea41c1fbb507039f4c0dc Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 26 Oct 2011 15:33:44 -0400 Subject: tipc: Fix node lock reclamation issues in broadcast link reception Fixes a pair of problems in broadcast link message reception code relating to the reclamation of the node lock after consuming an in-sequence message. 1) Now retests to see if the sending node is still up after reclaiming the node lock, and bails out if it is non-operational. 2) Now manipulates the node's deferred message queue only after reclaiming the node lock, rather than using queue head pointer information that was cached previously. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 58 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 7342abc2cfa..e7df313020c 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -474,7 +474,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) struct tipc_node *node; u32 next_in; u32 seqno; - struct sk_buff *deferred; + int deferred; /* Screen out unwanted broadcast messages */ @@ -489,6 +489,8 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) if (unlikely(!node->bclink.supported)) goto unlock; + /* Handle broadcast protocol message */ + if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { if (msg_type(msg) != STATE_MSG) goto unlock; @@ -513,11 +515,11 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) /* Handle in-sequence broadcast message */ -receive: - next_in = mod(node->bclink.last_in + 1); seqno = msg_seqno(msg); + next_in = mod(node->bclink.last_in + 1); if (likely(seqno == next_in)) { +receive: bcl->stats.recv_info++; node->bclink.last_in++; bclink_set_gap(node); @@ -551,23 +553,40 @@ receive: buf_discard(buf); } buf = NULL; + + /* Determine new synchronization state */ + tipc_node_lock(node); - deferred = node->bclink.deferred_head; - if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) { - buf = deferred; - msg = buf_msg(buf); - node->bclink.deferred_head = deferred->next; - goto receive; - } - } else if (less(next_in, seqno)) { + if (unlikely(!tipc_node_is_up(node))) + goto unlock; + + if (!node->bclink.deferred_head) + goto unlock; + + msg = buf_msg(node->bclink.deferred_head); + seqno = msg_seqno(msg); + next_in = mod(next_in + 1); + if (seqno != next_in) + goto unlock; + + /* Take in-sequence message from deferred queue & deliver it */ + + buf = node->bclink.deferred_head; + node->bclink.deferred_head = buf->next; + goto receive; + } + + /* Handle out-of-sequence broadcast message */ + + if (less(next_in, seqno)) { u32 gap_after = node->bclink.gap_after; u32 gap_to = node->bclink.gap_to; - if (tipc_link_defer_pkt(&node->bclink.deferred_head, - &node->bclink.deferred_tail, - buf)) { + deferred = tipc_link_defer_pkt(&node->bclink.deferred_head, + &node->bclink.deferred_tail, + buf); + if (deferred) { node->bclink.nack_sync++; - bcl->stats.deferred_recv++; if (seqno == mod(gap_after + 1)) node->bclink.gap_after = seqno; else if (less(gap_after, seqno) && less(seqno, gap_to)) @@ -579,9 +598,12 @@ receive: bclink_send_nack(node); bclink_set_gap(node); } - } else { - bcl->stats.duplicates++; - } + } else + deferred = 0; + + if (deferred) + bcl->stats.deferred_recv++; + unlock: tipc_node_unlock(node); exit: -- cgit v1.2.3-70-g09d2 From 0232c5a566ff52d5c9fc1dda70253c942628ca66 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 26 Oct 2011 15:57:26 -0400 Subject: tipc: Fix bug in broadcast link duplicate message statistics Modifies broadcast link so that it increments the "received duplicate message" count if an incoming message cannot be added to the deferred message queue because it is already present in the queue. (The aligns broadcast link behavior with that of TIPC's unicast links.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index e7df313020c..035b350be5c 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -603,6 +603,8 @@ receive: if (deferred) bcl->stats.deferred_recv++; + else + bcl->stats.duplicates++; unlock: tipc_node_unlock(node); -- cgit v1.2.3-70-g09d2 From b98158e3b36645305363a598d91c544fa31446f1 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 26 Oct 2011 16:13:35 -0400 Subject: tipc: Add missing locks in broadcast link statistics accumulation Ensures that all attempts to update broadcast link statistics are done only while holding the lock that protects the link's main data structures, to prevent interference by simultaneous updates caused by messages arriving on other interfaces. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 035b350be5c..facc216c6a9 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -520,6 +520,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) if (likely(seqno == next_in)) { receive: + spin_lock_bh(&bc_lock); bcl->stats.recv_info++; node->bclink.last_in++; bclink_set_gap(node); @@ -527,7 +528,9 @@ receive: bclink_send_ack(node); bcl->stats.sent_acks++; } + if (likely(msg_isdata(msg))) { + spin_unlock_bh(&bc_lock); tipc_node_unlock(node); if (likely(msg_mcast(msg))) tipc_port_recv_mcast(buf, NULL); @@ -536,6 +539,7 @@ receive: } else if (msg_user(msg) == MSG_BUNDLER) { bcl->stats.recv_bundles++; bcl->stats.recv_bundled += msg_msgcnt(msg); + spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_link_recv_bundle(buf); } else if (msg_user(msg) == MSG_FRAGMENTER) { @@ -543,12 +547,15 @@ receive: if (tipc_link_recv_fragment(&node->bclink.defragm, &buf, &msg)) bcl->stats.recv_fragmented++; + spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_net_route_msg(buf); } else if (msg_user(msg) == NAME_DISTRIBUTOR) { + spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_named_recv(buf); } else { + spin_unlock_bh(&bc_lock); tipc_node_unlock(node); buf_discard(buf); } @@ -601,11 +608,15 @@ receive: } else deferred = 0; + spin_lock_bh(&bc_lock); + if (deferred) bcl->stats.deferred_recv++; else bcl->stats.duplicates++; + spin_unlock_bh(&bc_lock); + unlock: tipc_node_unlock(node); exit: -- cgit v1.2.3-70-g09d2 From 7a54d4a99dcbbfdf1d4550faa19b615091137953 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 27 Oct 2011 14:17:53 -0400 Subject: tipc: Major redesign of broadcast link ACK/NACK algorithms Completely redesigns broadcast link ACK and NACK mechanisms to prevent spurious retransmit requests in dual LAN networks, and to prevent the broadcast link from stalling due to the failure of a receiving node to acknowledge receiving a broadcast message or request its retransmission. Note: These changes only impact the timing of when ACK and NACK messages are sent, and not the basic broadcast link protocol itself, so inter- operability with nodes using the "classic" algorithms is maintained. The revised algorithms are as follows: 1) An explicit ACK message is still sent after receiving 16 in-sequence messages, and implicit ACK information continues to be carried in other unicast link message headers (including link state messages). However, the timing of explicit ACKs is now based on the receiving node's absolute network address rather than its relative network address to ensure that the failure of another node does not delay the ACK beyond its 16 message target. 2) A NACK message is now typically sent only when a message gap persists for two consecutive incoming link state messages; this ensures that a suspected gap is not confirmed until both LANs in a dual LAN network have had an opportunity to deliver the message, thereby preventing spurious NACKs. A NACK message can also be generated by the arrival of a single link state message, if the deferred queue is so big that the current message gap cannot be the result of "normal" mis-ordering due to the use of dual LANs (or one LAN using a bonded interface). Since link state messages typically arrive at different nodes at different times the problem of multiple nodes issuing identical NACKs simultaneously is inherently avoided. 3) Nodes continue to "peek" at NACK messages sent by other nodes. If another node requests retransmission of a message gap suspected (but not yet confirmed) by the peeking node, the peeking node forgets about the gap and does not generate a duplicate retransmit request. (If the peeking node subsequently fails to receive the lost message, later link state messages will cause it to rediscover and confirm the gap and send another NACK.) 4) Message gap "equality" is now determined by the start of the gap only. This is sufficient to deal with the most common cases of message loss, and eliminates the need for complex end of gap computations. 5) A peeking node no longer tries to determine whether it should send a complementary NACK, since the most common cases of message loss don't require it to be sent. Consequently, the node no longer examines the "broadcast tag" field of a NACK message when peeking. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 226 +++++++++++++++++++------------------------------------ net/tipc/bcast.h | 2 +- net/tipc/link.c | 21 ++++-- net/tipc/node.c | 4 +- net/tipc/node.h | 12 +-- 5 files changed, 100 insertions(+), 165 deletions(-) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index facc216c6a9..1f3b1607d9d 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -157,39 +157,14 @@ u32 tipc_bclink_get_last_sent(void) return bcl->fsm_msg_cnt; } -/** - * bclink_set_gap - set gap according to contents of current deferred pkt queue - * - * Called with 'node' locked, bc_lock unlocked - */ - -static void bclink_set_gap(struct tipc_node *n_ptr) -{ - struct sk_buff *buf = n_ptr->bclink.deferred_head; - - n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = - mod(n_ptr->bclink.last_in); - if (unlikely(buf != NULL)) - n_ptr->bclink.gap_to = mod(buf_seqno(buf) - 1); -} - -/** - * bclink_ack_allowed - test if ACK or NACK message can be sent at this moment - * - * This mechanism endeavours to prevent all nodes in network from trying - * to ACK or NACK at the same time. - * - * Note: TIPC uses a different trigger to distribute ACKs than it does to - * distribute NACKs, but tries to use the same spacing (divide by 16). - */ - -static int bclink_ack_allowed(u32 n) +static void bclink_update_last_sent(struct tipc_node *node, u32 seqno) { - return (n % TIPC_MIN_LINK_WIN) == tipc_own_tag; + node->bclink.last_sent = less_eq(node->bclink.last_sent, seqno) ? + seqno : node->bclink.last_sent; } -/** +/* * tipc_bclink_retransmit_to - get most recent node to request retransmission * * Called with bc_lock locked @@ -300,44 +275,56 @@ exit: spin_unlock_bh(&bc_lock); } -/** - * bclink_send_ack - unicast an ACK msg +/* + * tipc_bclink_update_link_state - update broadcast link state * * tipc_net_lock and node lock set */ -static void bclink_send_ack(struct tipc_node *n_ptr) +void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent) { - struct tipc_link *l_ptr = n_ptr->active_links[n_ptr->addr & 1]; + struct sk_buff *buf; - if (l_ptr != NULL) - tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); -} + /* Ignore "stale" link state info */ -/** - * bclink_send_nack- broadcast a NACK msg - * - * tipc_net_lock and node lock set - */ + if (less_eq(last_sent, n_ptr->bclink.last_in)) + return; -static void bclink_send_nack(struct tipc_node *n_ptr) -{ - struct sk_buff *buf; - struct tipc_msg *msg; + /* Update link synchronization state; quit if in sync */ + + bclink_update_last_sent(n_ptr, last_sent); + + if (n_ptr->bclink.last_sent == n_ptr->bclink.last_in) + return; + + /* Update out-of-sync state; quit if loss is still unconfirmed */ - if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to)) + if ((++n_ptr->bclink.oos_state) == 1) { + if (n_ptr->bclink.deferred_size < (TIPC_MIN_LINK_WIN / 2)) + return; + n_ptr->bclink.oos_state++; + } + + /* Don't NACK if one has been recently sent (or seen) */ + + if (n_ptr->bclink.oos_state & 0x1) return; + /* Send NACK */ + buf = tipc_buf_acquire(INT_H_SIZE); if (buf) { - msg = buf_msg(buf); + struct tipc_msg *msg = buf_msg(buf); + tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, - INT_H_SIZE, n_ptr->addr); + INT_H_SIZE, n_ptr->addr); msg_set_non_seq(msg, 1); msg_set_mc_netid(msg, tipc_net_id); - msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in)); - msg_set_bcgap_after(msg, n_ptr->bclink.gap_after); - msg_set_bcgap_to(msg, n_ptr->bclink.gap_to); + msg_set_bcast_ack(msg, n_ptr->bclink.last_in); + msg_set_bcgap_after(msg, n_ptr->bclink.last_in); + msg_set_bcgap_to(msg, n_ptr->bclink.deferred_head + ? buf_seqno(n_ptr->bclink.deferred_head) - 1 + : n_ptr->bclink.last_sent); msg_set_bcast_tag(msg, tipc_own_tag); spin_lock_bh(&bc_lock); @@ -346,96 +333,37 @@ static void bclink_send_nack(struct tipc_node *n_ptr) spin_unlock_bh(&bc_lock); buf_discard(buf); - /* - * Ensure we doesn't send another NACK msg to the node - * until 16 more deferred messages arrive from it - * (i.e. helps prevent all nodes from NACK'ing at same time) - */ - - n_ptr->bclink.nack_sync = tipc_own_tag; + n_ptr->bclink.oos_state++; } } -/** - * tipc_bclink_check_gap - send a NACK if a sequence gap exists +/* + * bclink_peek_nack - monitor retransmission requests sent by other nodes * - * tipc_net_lock and node lock set - */ - -void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 last_sent) -{ - if (!n_ptr->bclink.supported || - less_eq(last_sent, mod(n_ptr->bclink.last_in))) - return; - - bclink_set_gap(n_ptr); - if (n_ptr->bclink.gap_after == n_ptr->bclink.gap_to) - n_ptr->bclink.gap_to = last_sent; - bclink_send_nack(n_ptr); -} - -/** - * tipc_bclink_peek_nack - process a NACK msg meant for another node + * Delay any upcoming NACK by this node if another node has already + * requested the first message this node is going to ask for. * * Only tipc_net_lock set. */ -static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to) +static void bclink_peek_nack(struct tipc_msg *msg) { - struct tipc_node *n_ptr = tipc_node_find(dest); - u32 my_after, my_to; + struct tipc_node *n_ptr = tipc_node_find(msg_destnode(msg)); - if (unlikely(!n_ptr || !tipc_node_is_up(n_ptr))) + if (unlikely(!n_ptr)) return; + tipc_node_lock(n_ptr); - /* - * Modify gap to suppress unnecessary NACKs from this node - */ - my_after = n_ptr->bclink.gap_after; - my_to = n_ptr->bclink.gap_to; - - if (less_eq(gap_after, my_after)) { - if (less(my_after, gap_to) && less(gap_to, my_to)) - n_ptr->bclink.gap_after = gap_to; - else if (less_eq(my_to, gap_to)) - n_ptr->bclink.gap_to = n_ptr->bclink.gap_after; - } else if (less_eq(gap_after, my_to)) { - if (less_eq(my_to, gap_to)) - n_ptr->bclink.gap_to = gap_after; - } else { - /* - * Expand gap if missing bufs not in deferred queue: - */ - struct sk_buff *buf = n_ptr->bclink.deferred_head; - u32 prev = n_ptr->bclink.gap_to; - for (; buf; buf = buf->next) { - u32 seqno = buf_seqno(buf); + if (n_ptr->bclink.supported && + (n_ptr->bclink.last_in != n_ptr->bclink.last_sent) && + (n_ptr->bclink.last_in == msg_bcgap_after(msg))) + n_ptr->bclink.oos_state = 2; - if (mod(seqno - prev) != 1) { - buf = NULL; - break; - } - if (seqno == gap_after) - break; - prev = seqno; - } - if (buf == NULL) - n_ptr->bclink.gap_to = gap_after; - } - /* - * Some nodes may send a complementary NACK now: - */ - if (bclink_ack_allowed(sender_tag + 1)) { - if (n_ptr->bclink.gap_to != n_ptr->bclink.gap_after) { - bclink_send_nack(n_ptr); - bclink_set_gap(n_ptr); - } - } tipc_node_unlock(n_ptr); } -/** +/* * tipc_bclink_send_msg - broadcast a packet to all nodes in cluster */ @@ -505,10 +433,7 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) spin_unlock_bh(&bc_lock); } else { tipc_node_unlock(node); - tipc_bclink_peek_nack(msg_destnode(msg), - msg_bcast_tag(msg), - msg_bcgap_after(msg), - msg_bcgap_to(msg)); + bclink_peek_nack(msg); } goto exit; } @@ -519,16 +444,28 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) next_in = mod(node->bclink.last_in + 1); if (likely(seqno == next_in)) { + bclink_update_last_sent(node, seqno); receive: + node->bclink.last_in = seqno; + node->bclink.oos_state = 0; + spin_lock_bh(&bc_lock); bcl->stats.recv_info++; - node->bclink.last_in++; - bclink_set_gap(node); - if (unlikely(bclink_ack_allowed(seqno))) { - bclink_send_ack(node); + + /* + * Unicast an ACK periodically, ensuring that + * all nodes in the cluster don't ACK at the same time + */ + + if (((seqno - tipc_own_addr) % TIPC_MIN_LINK_WIN) == 0) { + tipc_link_send_proto_msg( + node->active_links[node->addr & 1], + STATE_MSG, 0, 0, 0, 0, 0); bcl->stats.sent_acks++; } + /* Deliver message to destination */ + if (likely(msg_isdata(msg))) { spin_unlock_bh(&bc_lock); tipc_node_unlock(node); @@ -567,9 +504,14 @@ receive: if (unlikely(!tipc_node_is_up(node))) goto unlock; - if (!node->bclink.deferred_head) + if (node->bclink.last_in == node->bclink.last_sent) goto unlock; + if (!node->bclink.deferred_head) { + node->bclink.oos_state = 1; + goto unlock; + } + msg = buf_msg(node->bclink.deferred_head); seqno = msg_seqno(msg); next_in = mod(next_in + 1); @@ -580,31 +522,19 @@ receive: buf = node->bclink.deferred_head; node->bclink.deferred_head = buf->next; + node->bclink.deferred_size--; goto receive; } /* Handle out-of-sequence broadcast message */ if (less(next_in, seqno)) { - u32 gap_after = node->bclink.gap_after; - u32 gap_to = node->bclink.gap_to; - deferred = tipc_link_defer_pkt(&node->bclink.deferred_head, &node->bclink.deferred_tail, buf); - if (deferred) { - node->bclink.nack_sync++; - if (seqno == mod(gap_after + 1)) - node->bclink.gap_after = seqno; - else if (less(gap_after, seqno) && less(seqno, gap_to)) - node->bclink.gap_to = seqno; - } + node->bclink.deferred_size += deferred; + bclink_update_last_sent(node, seqno); buf = NULL; - if (bclink_ack_allowed(node->bclink.nack_sync)) { - if (gap_to != gap_after) - bclink_send_nack(node); - bclink_set_gap(node); - } } else deferred = 0; diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index b009666c60b..5571394098f 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -96,7 +96,7 @@ int tipc_bclink_send_msg(struct sk_buff *buf); void tipc_bclink_recv_pkt(struct sk_buff *buf); u32 tipc_bclink_get_last_sent(void); u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); -void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 seqno); +void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent); int tipc_bclink_stats(char *stats_buf, const u32 buf_size); int tipc_bclink_reset_stats(void); int tipc_bclink_set_queue_limits(u32 limit); diff --git a/net/tipc/link.c b/net/tipc/link.c index 1150ba5a648..cce953723dd 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1501,14 +1501,13 @@ static void link_retransmit_failure(struct tipc_link *l_ptr, tipc_node_lock(n_ptr); tipc_addr_string_fill(addr_string, n_ptr->addr); - info("Multicast link info for %s\n", addr_string); + info("Broadcast link info for %s\n", addr_string); info("Supportable: %d, ", n_ptr->bclink.supportable); info("Supported: %d, ", n_ptr->bclink.supported); info("Acked: %u\n", n_ptr->bclink.acked); info("Last in: %u, ", n_ptr->bclink.last_in); - info("Gap after: %u, ", n_ptr->bclink.gap_after); - info("Gap to: %u\n", n_ptr->bclink.gap_to); - info("Nack sync: %u\n\n", n_ptr->bclink.nack_sync); + info("Oos state: %u, ", n_ptr->bclink.oos_state); + info("Last sent: %u\n", n_ptr->bclink.last_sent); tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr); @@ -1974,7 +1973,7 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, msg_set_type(msg, msg_typ); msg_set_net_plane(msg, l_ptr->b_ptr->net_plane); - msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in)); + msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); msg_set_last_bcast(msg, tipc_bclink_get_last_sent()); if (msg_typ == STATE_MSG) { @@ -2133,8 +2132,12 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) /* Synchronize broadcast link info, if not done previously */ - if (!tipc_node_is_up(l_ptr->owner)) - l_ptr->owner->bclink.last_in = msg_last_bcast(msg); + if (!tipc_node_is_up(l_ptr->owner)) { + l_ptr->owner->bclink.last_sent = + l_ptr->owner->bclink.last_in = + msg_last_bcast(msg); + l_ptr->owner->bclink.oos_state = 0; + } l_ptr->peer_session = msg_session(msg); l_ptr->peer_bearer_id = msg_bearer_id(msg); @@ -2181,7 +2184,9 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) /* Protocol message before retransmits, reduce loss risk */ - tipc_bclink_check_gap(l_ptr->owner, msg_last_bcast(msg)); + if (l_ptr->owner->bclink.supported) + tipc_bclink_update_link_state(l_ptr->owner, + msg_last_bcast(msg)); if (rec_gap || (msg_probe(msg))) { tipc_link_send_proto_msg(l_ptr, STATE_MSG, diff --git a/net/tipc/node.c b/net/tipc/node.c index 9196f943b83..6d8bdfd95cd 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -339,12 +339,12 @@ static void node_lost_contact(struct tipc_node *n_ptr) /* Flush broadcast link info associated with lost node */ if (n_ptr->bclink.supported) { - n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0; while (n_ptr->bclink.deferred_head) { struct sk_buff *buf = n_ptr->bclink.deferred_head; n_ptr->bclink.deferred_head = buf->next; buf_discard(buf); } + n_ptr->bclink.deferred_size = 0; if (n_ptr->bclink.defragm) { buf_discard(n_ptr->bclink.defragm); @@ -450,7 +450,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) read_lock_bh(&tipc_net_lock); - /* Get space for all unicast links + multicast link */ + /* Get space for all unicast links + broadcast link */ payload_size = TLV_SPACE(sizeof(link_info)) * (atomic_read(&tipc_num_links) + 1); diff --git a/net/tipc/node.h b/net/tipc/node.h index 90689f48761..c88ce64f8a3 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -66,9 +66,9 @@ * @supported: non-zero if node supports TIPC b'cast capability * @acked: sequence # of last outbound b'cast message acknowledged by node * @last_in: sequence # of last in-sequence b'cast message received from node - * @gap_after: sequence # of last message not requiring a NAK request - * @gap_to: sequence # of last message requiring a NAK request - * @nack_sync: counter that determines when NAK requests should be sent + * @last_sent: sequence # of last b'cast message sent by node + * @oos_state: state tracker for handling OOS b'cast messages + * @deferred_size: number of OOS b'cast messages in deferred queue * @deferred_head: oldest OOS b'cast message received from node * @deferred_tail: newest OOS b'cast message received from node * @defragm: list of partially reassembled b'cast message fragments from node @@ -91,9 +91,9 @@ struct tipc_node { u8 supported; u32 acked; u32 last_in; - u32 gap_after; - u32 gap_to; - u32 nack_sync; + u32 last_sent; + u32 oos_state; + u32 deferred_size; struct sk_buff *deferred_head; struct sk_buff *deferred_tail; struct sk_buff *defragm; -- cgit v1.2.3-70-g09d2 From 1ec2bb08407b377e5954b3f9479c2bf67fc925a9 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 27 Oct 2011 15:03:24 -0400 Subject: tipc: Remove obsolete broadcast tag capability Eliminates support for the broadcast tag field, which is no longer used by broadcast link NACK messages. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 1 - net/tipc/node.c | 7 +------ net/tipc/node.h | 2 -- 3 files changed, 1 insertion(+), 9 deletions(-) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 1f3b1607d9d..a9b7132d34f 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -325,7 +325,6 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent) msg_set_bcgap_to(msg, n_ptr->bclink.deferred_head ? buf_seqno(n_ptr->bclink.deferred_head) - 1 : n_ptr->bclink.last_sent); - msg_set_bcast_tag(msg, tipc_own_tag); spin_lock_bh(&bc_lock); tipc_bearer_send(&bcbearer->bearer, buf, NULL); diff --git a/net/tipc/node.c b/net/tipc/node.c index 6d8bdfd95cd..7bc45e135fb 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -49,9 +49,8 @@ LIST_HEAD(tipc_node_list); static u32 tipc_num_nodes; static atomic_t tipc_num_links = ATOMIC_INIT(0); -u32 tipc_own_tag; -/** +/* * tipc_node_find - locate specified node object, if it exists */ @@ -309,8 +308,6 @@ static void node_established_contact(struct tipc_node *n_ptr) if (n_ptr->bclink.supportable) { tipc_bclink_add_node(n_ptr->addr); n_ptr->bclink.supported = 1; - if (n_ptr->addr < tipc_own_addr) - tipc_own_tag++; } } @@ -353,8 +350,6 @@ static void node_lost_contact(struct tipc_node *n_ptr) tipc_bclink_remove_node(n_ptr->addr); tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ); - if (n_ptr->addr < tipc_own_addr) - tipc_own_tag--; n_ptr->bclink.supported = 0; } diff --git a/net/tipc/node.h b/net/tipc/node.h index c88ce64f8a3..e1b78a2199c 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -114,8 +114,6 @@ static inline unsigned int tipc_hashfn(u32 addr) return addr & (NODE_HTABLE_SIZE - 1); } -extern u32 tipc_own_tag; - struct tipc_node *tipc_node_find(u32 addr); struct tipc_node *tipc_node_create(u32 addr); void tipc_node_delete(struct tipc_node *n_ptr); -- cgit v1.2.3-70-g09d2 From b76b27cad5ade1d483d4b94df6b35976bccf1055 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 27 Oct 2011 16:31:26 -0400 Subject: tipc: Prevent loss of fragmented messages over unicast links Modifies unicast link endpoint logic so an incoming fragmented message is not lost if reassembly cannot begin because there is no buffer big enough to hold the entire reassembled message. The link endpoint now ignores the first fragment completely, which causes the sending node to retransmit the first fragment so that reassembly can be re-attempted. Previously, the sender would have had no reason to retransmit the 1st fragment, so we would never have a chance to re-try the allocation. Signed-off-by: Allan Stephens --- net/tipc/link.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index cce953723dd..d8b0a22367b 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1774,6 +1774,7 @@ protocol_check: head = link_insert_deferred_queue(l_ptr, head); if (likely(msg_is_dest(msg, tipc_own_addr))) { + int ret; deliver: if (likely(msg_isdata(msg))) { tipc_node_unlock(n_ptr); @@ -1798,11 +1799,15 @@ deliver: continue; case MSG_FRAGMENTER: l_ptr->stats.recv_fragments++; - if (tipc_link_recv_fragment(&l_ptr->defragm_buf, - &buf, &msg)) { + ret = tipc_link_recv_fragment( + &l_ptr->defragm_buf, + &buf, &msg); + if (ret == 1) { l_ptr->stats.recv_fragmented++; goto deliver; } + if (ret == -1) + l_ptr->next_in_no--; break; case CHANGEOVER_PROTOCOL: type = msg_type(msg); @@ -2632,7 +2637,9 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, set_fragm_size(pbuf, fragm_sz); set_expected_frags(pbuf, exp_fragm_cnt - 1); } else { - warn("Link unable to reassemble fragmented message\n"); + dbg("Link unable to reassemble fragmented message\n"); + buf_discard(fbuf); + return -1; } buf_discard(fbuf); return 0; -- cgit v1.2.3-70-g09d2 From 63e7f1ac2855ba56f15d8189694ca9bd16ae4107 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 27 Oct 2011 16:43:09 -0400 Subject: tipc: Prevent loss of fragmented messages over broadcast link Modifies broadcast link so that an incoming fragmented message is not lost if reassembly cannot begin because there currently is no buffer big enough to hold the entire reassembled message. The broadcast link now ignores the first fragment completely, which causes the sending node to retransmit the first fragment so that reassembly can be re-attempted. Previously, the sender would have had no reason to retransmit the 1st fragment, so we would never have a chance to re-try the allocation. To do this cleanly without duplicaton, a new bclink_accept_pkt() function is introduced. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 64 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index a9b7132d34f..41ecf313073 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -389,7 +389,33 @@ exit: return res; } -/** +/* + * bclink_accept_pkt - accept an incoming, in-sequence broadcast packet + * + * Called with both sending node's lock and bc_lock taken. + */ + +static void bclink_accept_pkt(struct tipc_node *node, u32 seqno) +{ + bclink_update_last_sent(node, seqno); + node->bclink.last_in = seqno; + node->bclink.oos_state = 0; + bcl->stats.recv_info++; + + /* + * Unicast an ACK periodically, ensuring that + * all nodes in the cluster don't ACK at the same time + */ + + if (((seqno - tipc_own_addr) % TIPC_MIN_LINK_WIN) == 0) { + tipc_link_send_proto_msg( + node->active_links[node->addr & 1], + STATE_MSG, 0, 0, 0, 0, 0); + bcl->stats.sent_acks++; + } +} + +/* * tipc_bclink_recv_pkt - receive a broadcast packet, and deliver upwards * * tipc_net_lock is read_locked, no other locks set @@ -443,29 +469,12 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) next_in = mod(node->bclink.last_in + 1); if (likely(seqno == next_in)) { - bclink_update_last_sent(node, seqno); receive: - node->bclink.last_in = seqno; - node->bclink.oos_state = 0; - - spin_lock_bh(&bc_lock); - bcl->stats.recv_info++; - - /* - * Unicast an ACK periodically, ensuring that - * all nodes in the cluster don't ACK at the same time - */ - - if (((seqno - tipc_own_addr) % TIPC_MIN_LINK_WIN) == 0) { - tipc_link_send_proto_msg( - node->active_links[node->addr & 1], - STATE_MSG, 0, 0, 0, 0, 0); - bcl->stats.sent_acks++; - } - /* Deliver message to destination */ if (likely(msg_isdata(msg))) { + spin_lock_bh(&bc_lock); + bclink_accept_pkt(node, seqno); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); if (likely(msg_mcast(msg))) @@ -473,24 +482,35 @@ receive: else buf_discard(buf); } else if (msg_user(msg) == MSG_BUNDLER) { + spin_lock_bh(&bc_lock); + bclink_accept_pkt(node, seqno); bcl->stats.recv_bundles++; bcl->stats.recv_bundled += msg_msgcnt(msg); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_link_recv_bundle(buf); } else if (msg_user(msg) == MSG_FRAGMENTER) { + int ret = tipc_link_recv_fragment(&node->bclink.defragm, + &buf, &msg); + if (ret < 0) + goto unlock; + spin_lock_bh(&bc_lock); + bclink_accept_pkt(node, seqno); bcl->stats.recv_fragments++; - if (tipc_link_recv_fragment(&node->bclink.defragm, - &buf, &msg)) + if (ret > 0) bcl->stats.recv_fragmented++; spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_net_route_msg(buf); } else if (msg_user(msg) == NAME_DISTRIBUTOR) { + spin_lock_bh(&bc_lock); + bclink_accept_pkt(node, seqno); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_named_recv(buf); } else { + spin_lock_bh(&bc_lock); + bclink_accept_pkt(node, seqno); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); buf_discard(buf); -- cgit v1.2.3-70-g09d2 From 3175bd9add570f3b5c06877369897b334556a2ff Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 28 Oct 2011 12:03:00 -0400 Subject: tipc: Eliminate alteration of publication key during name table purging Removes code that alters the publication key of a name table entry that is being forcibly purged from TIPC's name table after contact with the publishing node has been lost. Current TIPC ensures that all defunct names are purged before re-establishing contact with a failed node. There used to be a risk that the publication might be accidentally deleted because it might be re-added to the name table before the purge operation was completed. But now there is no longer a need to ensure that the new key is different than the old one. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/name_distr.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net') diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 98ebb37f180..acecfda82f3 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -239,9 +239,6 @@ exit: * * Invoked for each publication issued by a newly failed node. * Removes publication structure from name table & deletes it. - * In rare cases the link may have come back up again when this - * function is called, and we have two items representing the same - * publication. Nudge this item's key to distinguish it from the other. */ static void named_purge_publ(struct publication *publ) @@ -249,7 +246,6 @@ static void named_purge_publ(struct publication *publ) struct publication *p; write_lock_bh(&tipc_nametbl_lock); - publ->key += 1222345; p = tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node, publ->ref, publ->key); if (p) -- cgit v1.2.3-70-g09d2 From dff10e9e637663c8c5dd0bae1a8f0e899cbb4a36 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 2 Nov 2011 10:32:14 -0400 Subject: tipc: Minor optimization to rejection of connection-based messages Modifies message rejection logic so that TIPC doesn't attempt to send a FIN message to the rejecting port if it is known in advance that there is no such message because the rejecting port doesn't exist. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/port.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/tipc/port.c b/net/tipc/port.c index d91efc69e6f..ba3268b8da4 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -400,15 +400,16 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) /* send self-abort message when rejecting on a connected port */ if (msg_connected(msg)) { - struct sk_buff *abuf = NULL; struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg)); if (p_ptr) { + struct sk_buff *abuf = NULL; + if (p_ptr->connected) abuf = port_build_self_abort_msg(p_ptr, err); tipc_port_unlock(p_ptr); + tipc_net_route_msg(abuf); } - tipc_net_route_msg(abuf); } /* send returned message & dispose of rejected message */ -- cgit v1.2.3-70-g09d2 From 87e3c0553fcbea79bf9f17fc5694484ecf3ae5e8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 1 Feb 2012 10:46:20 +0300 Subject: SUNRPC: remove an unneeded NULL check in xprt_connect() We check "task->tk_rqstp" and then we dereference it without checking on the next line. The only caller is call_connect() and that has a check which prevents it from calling xprt_connect() with a NULL. if (task->tk_status < 0) return; If "task->tk_rqstp" were NULL then "tk_status" would be -EAGAIN. Signed-off-by: Dan Carpenter Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 839f6ef2326..efe5495ecf6 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -715,9 +715,7 @@ void xprt_connect(struct rpc_task *task) if (xprt_connected(xprt)) xprt_release_write(xprt, task); else { - if (task->tk_rqstp) - task->tk_rqstp->rq_bytes_sent = 0; - + task->tk_rqstp->rq_bytes_sent = 0; task->tk_timeout = task->tk_rqstp->rq_timeout; rpc_sleep_on(&xprt->pending, task, xprt_connect_status); -- cgit v1.2.3-70-g09d2 From c3059be16c9ef29c05f0876a9df5fea21f29724f Mon Sep 17 00:00:00 2001 From: Shriram Rajagopalan Date: Sun, 5 Feb 2012 13:51:32 +0000 Subject: net/sched: sch_plug - Queue traffic until an explicit release command The qdisc supports two operations - plug and unplug. When the qdisc receives a plug command via netlink request, packets arriving henceforth are buffered until a corresponding unplug command is received. Depending on the type of unplug command, the queue can be unplugged indefinitely or selectively. This qdisc can be used to implement output buffering, an essential functionality required for consistent recovery in checkpoint based fault-tolerance systems. Output buffering enables speculative execution by allowing generated network traffic to be rolled back. It is used to provide network protection for Xen Guests in the Remus high availability project, available as part of Xen. This module is generic enough to be used by any other system that wishes to add speculative execution and output buffering to its applications. This module was originally available in the linux 2.6.32 PV-OPS tree, used as dom0 for Xen. For more information, please refer to http://nss.cs.ubc.ca/remus/ and http://wiki.xensource.com/xenwiki/Remus Changes in V3: * Removed debug output (printk) on queue overflow * Added TCQ_PLUG_RELEASE_INDEFINITE - that allows the user to use this qdisc, for simple plug/unplug operations. * Use of packet counts instead of pointers to keep track of the buffers in the queue. Signed-off-by: Shriram Rajagopalan Signed-off-by: Brendan Cully [author of the code in the linux 2.6.32 pvops tree] Signed-off-by: David S. Miller --- include/linux/pkt_sched.h | 21 +++++ net/sched/Kconfig | 26 ++++++ net/sched/Makefile | 1 + net/sched/sch_plug.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+) create mode 100644 net/sched/sch_plug.c (limited to 'net') diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 0d5b79365d0..410b33d014d 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -127,6 +127,27 @@ struct tc_multiq_qopt { __u16 max_bands; /* Maximum number of queues */ }; +/* PLUG section */ + +#define TCQ_PLUG_BUFFER 0 +#define TCQ_PLUG_RELEASE_ONE 1 +#define TCQ_PLUG_RELEASE_INDEFINITE 2 +#define TCQ_PLUG_LIMIT 3 + +struct tc_plug_qopt { + /* TCQ_PLUG_BUFFER: Inset a plug into the queue and + * buffer any incoming packets + * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head + * to beginning of the next plug. + * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue. + * Stop buffering packets until the next TCQ_PLUG_BUFFER + * command is received (just act as a pass-thru queue). + * TCQ_PLUG_LIMIT: Increase/decrease queue size + */ + int action; + __u32 limit; +}; + /* TBF section */ struct tc_tbf_qopt { diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 2590e91b328..75b58f81d53 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -260,6 +260,32 @@ config NET_SCH_INGRESS To compile this code as a module, choose M here: the module will be called sch_ingress. +config NET_SCH_PLUG + tristate "Plug network traffic until release (PLUG)" + ---help--- + + This queuing discipline allows userspace to plug/unplug a network + output queue, using the netlink interface. When it receives an + enqueue command it inserts a plug into the outbound queue that + causes following packets to enqueue until a dequeue command arrives + over netlink, causing the plug to be removed and resuming the normal + packet flow. + + This module also provides a generic "network output buffering" + functionality (aka output commit), wherein upon arrival of a dequeue + command, only packets up to the first plug are released for delivery. + The Remus HA project uses this module to enable speculative execution + of virtual machines by allowing the generated network output to be rolled + back if needed. + + For more information, please refer to http://wiki.xensource.com/xenwiki/Remus + + Say Y here if you are using this kernel for Xen dom0 and + want to protect Xen guests with Remus. + + To compile this code as a module, choose M here: the + module will be called sch_plug. + comment "Classification" config NET_CLS diff --git a/net/sched/Makefile b/net/sched/Makefile index dc5889c0a15..8cdf4e2b51d 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_NET_SCH_MULTIQ) += sch_multiq.o obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o obj-$(CONFIG_NET_SCH_DRR) += sch_drr.o +obj-$(CONFIG_NET_SCH_PLUG) += sch_plug.o obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o diff --git a/net/sched/sch_plug.c b/net/sched/sch_plug.c new file mode 100644 index 00000000000..ba7b737e405 --- /dev/null +++ b/net/sched/sch_plug.c @@ -0,0 +1,233 @@ +/* + * sch_plug.c Queue traffic until an explicit release command + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * There are two ways to use this qdisc: + * 1. A simple "instantaneous" plug/unplug operation, by issuing an alternating + * sequence of TCQ_PLUG_BUFFER & TCQ_PLUG_RELEASE_INDEFINITE commands. + * + * 2. For network output buffering (a.k.a output commit) functionality. + * Output commit property is commonly used by applications using checkpoint + * based fault-tolerance to ensure that the checkpoint from which a system + * is being restored is consistent w.r.t outside world. + * + * Consider for e.g. Remus - a Virtual Machine checkpointing system, + * wherein a VM is checkpointed, say every 50ms. The checkpoint is replicated + * asynchronously to the backup host, while the VM continues executing the + * next epoch speculatively. + * + * The following is a typical sequence of output buffer operations: + * 1.At epoch i, start_buffer(i) + * 2. At end of epoch i (i.e. after 50ms): + * 2.1 Stop VM and take checkpoint(i). + * 2.2 start_buffer(i+1) and Resume VM + * 3. While speculatively executing epoch(i+1), asynchronously replicate + * checkpoint(i) to backup host. + * 4. When checkpoint_ack(i) is received from backup, release_buffer(i) + * Thus, this Qdisc would receive the following sequence of commands: + * TCQ_PLUG_BUFFER (epoch i) + * .. TCQ_PLUG_BUFFER (epoch i+1) + * ....TCQ_PLUG_RELEASE_ONE (epoch i) + * ......TCQ_PLUG_BUFFER (epoch i+2) + * ........ + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * State of the queue, when used for network output buffering: + * + * plug(i+1) plug(i) head + * ------------------+--------------------+----------------> + * | | + * | | + * pkts_current_epoch| pkts_last_epoch |pkts_to_release + * ----------------->|<--------+--------->|+---------------> + * v v + * + */ + +struct plug_sched_data { + /* If true, the dequeue function releases all packets + * from head to end of the queue. The queue turns into + * a pass-through queue for newly arriving packets. + */ + bool unplug_indefinite; + + /* Queue Limit in bytes */ + u32 limit; + + /* Number of packets (output) from the current speculatively + * executing epoch. + */ + u32 pkts_current_epoch; + + /* Number of packets corresponding to the recently finished + * epoch. These will be released when we receive a + * TCQ_PLUG_RELEASE_ONE command. This command is typically + * issued after committing a checkpoint at the target. + */ + u32 pkts_last_epoch; + + /* + * Number of packets from the head of the queue, that can + * be released (committed checkpoint). + */ + u32 pkts_to_release; +}; + +static int plug_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct plug_sched_data *q = qdisc_priv(sch); + + if (likely(sch->qstats.backlog + skb->len <= q->limit)) { + if (!q->unplug_indefinite) + q->pkts_current_epoch++; + return qdisc_enqueue_tail(skb, sch); + } + + return qdisc_reshape_fail(skb, sch); +} + +static struct sk_buff *plug_dequeue(struct Qdisc *sch) +{ + struct plug_sched_data *q = qdisc_priv(sch); + + if (qdisc_is_throttled(sch)) + return NULL; + + if (!q->unplug_indefinite) { + if (!q->pkts_to_release) { + /* No more packets to dequeue. Block the queue + * and wait for the next release command. + */ + qdisc_throttled(sch); + return NULL; + } + q->pkts_to_release--; + } + + return qdisc_dequeue_head(sch); +} + +static int plug_init(struct Qdisc *sch, struct nlattr *opt) +{ + struct plug_sched_data *q = qdisc_priv(sch); + + q->pkts_current_epoch = 0; + q->pkts_last_epoch = 0; + q->pkts_to_release = 0; + q->unplug_indefinite = false; + + if (opt == NULL) { + /* We will set a default limit of 100 pkts (~150kB) + * in case tx_queue_len is not available. The + * default value is completely arbitrary. + */ + u32 pkt_limit = qdisc_dev(sch)->tx_queue_len ? : 100; + q->limit = pkt_limit * psched_mtu(qdisc_dev(sch)); + } else { + struct tc_plug_qopt *ctl = nla_data(opt); + + if (nla_len(opt) < sizeof(*ctl)) + return -EINVAL; + + q->limit = ctl->limit; + } + + qdisc_throttled(sch); + return 0; +} + +/* Receives 4 types of messages: + * TCQ_PLUG_BUFFER: Inset a plug into the queue and + * buffer any incoming packets + * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head + * to beginning of the next plug. + * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue. + * Stop buffering packets until the next TCQ_PLUG_BUFFER + * command is received (just act as a pass-thru queue). + * TCQ_PLUG_LIMIT: Increase/decrease queue size + */ +static int plug_change(struct Qdisc *sch, struct nlattr *opt) +{ + struct plug_sched_data *q = qdisc_priv(sch); + struct tc_plug_qopt *msg; + + if (opt == NULL) + return -EINVAL; + + msg = nla_data(opt); + if (nla_len(opt) < sizeof(*msg)) + return -EINVAL; + + switch (msg->action) { + case TCQ_PLUG_BUFFER: + /* Save size of the current buffer */ + q->pkts_last_epoch = q->pkts_current_epoch; + q->pkts_current_epoch = 0; + if (q->unplug_indefinite) + qdisc_throttled(sch); + q->unplug_indefinite = false; + break; + case TCQ_PLUG_RELEASE_ONE: + /* Add packets from the last complete buffer to the + * packets to be released set. + */ + q->pkts_to_release += q->pkts_last_epoch; + q->pkts_last_epoch = 0; + qdisc_unthrottled(sch); + netif_schedule_queue(sch->dev_queue); + break; + case TCQ_PLUG_RELEASE_INDEFINITE: + q->unplug_indefinite = true; + q->pkts_to_release = 0; + q->pkts_last_epoch = 0; + q->pkts_current_epoch = 0; + qdisc_unthrottled(sch); + netif_schedule_queue(sch->dev_queue); + break; + case TCQ_PLUG_LIMIT: + /* Limit is supplied in bytes */ + q->limit = msg->limit; + break; + default: + return -EINVAL; + } + + return 0; +} + +struct Qdisc_ops plug_qdisc_ops = { + .id = "plug", + .priv_size = sizeof(struct plug_sched_data), + .enqueue = plug_enqueue, + .dequeue = plug_dequeue, + .peek = qdisc_peek_head, + .init = plug_init, + .change = plug_change, + .owner = THIS_MODULE, +}; + +static int __init plug_module_init(void) +{ + return register_qdisc(&plug_qdisc_ops); +} + +static void __exit plug_module_exit(void) +{ + unregister_qdisc(&plug_qdisc_ops); +} +module_init(plug_module_init) +module_exit(plug_module_exit) +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From af2ce213f6e6b28497c5c932f43b94026b5a0363 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Feb 2012 21:20:15 +0000 Subject: caif: remove duplicate initialization "priv" is initialized twice. I kept the second one, because it is next to the check for NULL. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/caif/chnl_net.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index a751d9b263e..e866234d0e5 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -72,13 +72,12 @@ static void robust_list_del(struct list_head *delete_node) static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) { struct sk_buff *skb; - struct chnl_net *priv = container_of(layr, struct chnl_net, chnl); + struct chnl_net *priv; int pktlen; const u8 *ip_version; u8 buf; priv = container_of(layr, struct chnl_net, chnl); - if (!priv) return -EINVAL; -- cgit v1.2.3-70-g09d2 From 79027596ff710f9662ccae5f5e85de43961420ed Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 7 Feb 2012 12:45:44 +0100 Subject: mac80211: add #ifdef CONFIG_MAC80211_VERBOSE_DEBUG for a debug printk When not debugging mac80211 code, station state transitions do not need to show up in the kernel log. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 31cd6d92531..4034ee61602 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1379,8 +1379,10 @@ int sta_info_move_state(struct sta_info *sta, return -EINVAL; } +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", sta->sdata->name, sta->sta.addr, new_state); +#endif /* * notify the driver before the actual changes so it can -- cgit v1.2.3-70-g09d2 From 5ad20dd1480dc557afcec19ac7fae5581264dd59 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 7 Feb 2012 21:09:25 -0800 Subject: mac80211: rename mesh static path_lookup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you want to use mesh support from mac80211 on a recent kernel on 2.6.24 you'll run into a name clash when compiling against include/linux/namei.h, so rename this routine. /home/mcgrof/tmp/compat-wireless-3.2.5-1/net/mac80211/mesh_pathtbl.c: At top level: /home/mcgrof/tmp/compat-wireless-3.2.5-1/net/mac80211/mesh_pathtbl.c:342:26: error: conflicting types for ‘path_lookup’ include/linux/namei.h:71:12: note: previous declaration of ‘path_lookup’ was here Although this could sit as a separate patch in compat-wireless it seems best to just merge upstream. Cc: Javier Cardona Signed-off-by: Luis R. Rodriguez Acked-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index edf167e3b8f..dc51669e67d 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -336,7 +336,7 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, } -static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst, +static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst, struct ieee80211_sub_if_data *sdata) { struct mesh_path *mpath; @@ -371,12 +371,12 @@ static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst, */ struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) { - return path_lookup(rcu_dereference(mesh_paths), dst, sdata); + return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); } struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) { - return path_lookup(rcu_dereference(mpp_paths), dst, sdata); + return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata); } -- cgit v1.2.3-70-g09d2 From 43480aecb1f538d4f6dd8b2c5d2b71fb98659072 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Feb 2012 08:51:50 +0000 Subject: gro: more generic L2 header check Shlomo Pongratz reported GRO L2 header check was suited for Ethernet only, and failed on IB/ipoib traffic. He provided a patch faking a zeroed header to let GRO aggregates frames. Roland Dreier, Herbert Xu, and others suggested we change GRO L2 header check to be more generic, ie not assuming L2 header is 14 bytes, but taking into account hard_header_len. __napi_gro_receive() has special handling for the common case (Ethernet) to avoid a memcmp() call and use an inline optimized function instead. Signed-off-by: Eric Dumazet Reported-by: Shlomo Pongratz Cc: Roland Dreier Cc: Or Gerlitz Cc: Herbert Xu Tested-by: Sean Hefty Signed-off-by: David S. Miller --- net/core/dev.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index f1249472e90..763a0eda715 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3491,14 +3491,20 @@ static inline gro_result_t __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff *p; + unsigned int maclen = skb->dev->hard_header_len; for (p = napi->gro_list; p; p = p->next) { unsigned long diffs; diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; diffs |= p->vlan_tci ^ skb->vlan_tci; - diffs |= compare_ether_header(skb_mac_header(p), - skb_gro_mac_header(skb)); + if (maclen == ETH_HLEN) + diffs |= compare_ether_header(skb_mac_header(p), + skb_gro_mac_header(skb)); + else if (!diffs) + diffs = memcmp(skb_mac_header(p), + skb_gro_mac_header(skb), + maclen); NAPI_GRO_CB(p)->same_flow = !diffs; NAPI_GRO_CB(p)->flush = 0; } -- cgit v1.2.3-70-g09d2 From 76e21053b5bf33a07c76f99d27a74238310e3c71 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Wed, 8 Feb 2012 09:11:07 +0000 Subject: ipv4: Implement IP_UNICAST_IF socket option. The IP_UNICAST_IF feature is needed by the Wine project. This patch implements the feature by setting the outgoing interface in a similar fashion to that of IP_MULTICAST_IF. A separate option is needed to handle this feature since the existing options do not provide all of the characteristics required by IP_UNICAST_IF, a summary is provided below. SO_BINDTODEVICE: * SO_BINDTODEVICE requires administrative privileges, IP_UNICAST_IF does not. From reading some old mailing list articles my understanding is that SO_BINDTODEVICE requires administrative privileges because it can override the administrator's routing settings. * The SO_BINDTODEVICE option restricts both outbound and inbound traffic, IP_UNICAST_IF only impacts outbound traffic. IP_PKTINFO: * Since IP_PKTINFO and IP_UNICAST_IF are independent options, implementing IP_UNICAST_IF with IP_PKTINFO will likely break some applications. * Implementing IP_UNICAST_IF on top of IP_PKTINFO significantly complicates the Wine codebase and reduces the socket performance (doing this requires a lot of extra communication between the "server" and "user" layers). bind(): * bind() does not work on broadcast packets, IP_UNICAST_IF is specifically intended to work with broadcast packets. * Like SO_BINDTODEVICE, bind() restricts both outbound and inbound traffic. Signed-off-by: Erich E. Hoover Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/in.h | 1 + include/net/inet_sock.h | 2 ++ net/ipv4/ip_sockglue.c | 33 +++++++++++++++++++++++++++++++++ net/ipv4/ping.c | 3 ++- net/ipv4/raw.c | 3 ++- net/ipv4/udp.c | 3 ++- 6 files changed, 42 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/linux/in.h b/include/linux/in.h index 01129c0ea87..e0337f11d92 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -111,6 +111,7 @@ struct in_addr { #define MCAST_LEAVE_SOURCE_GROUP 47 #define MCAST_MSFILTER 48 #define IP_MULTICAST_ALL 49 +#define IP_UNICAST_IF 50 #define MCAST_EXCLUDE 0 #define MCAST_INCLUDE 1 diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index e3e405106af..022f772c0eb 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -132,6 +132,7 @@ struct rtable; * @tos - TOS * @mc_ttl - Multicasting TTL * @is_icsk - is this an inet_connection_sock? + * @uc_index - Unicast outgoing device index * @mc_index - Multicast device index * @mc_list - Group array * @cork - info to build ip hdr on each ip frag while socket is corked @@ -167,6 +168,7 @@ struct inet_sock { transparent:1, mc_all:1, nodefrag:1; + int uc_index; int mc_index; __be32 mc_addr; struct ip_mc_socklist __rcu *mc_list; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 8aa87c19fa0..9125529dab9 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -469,6 +469,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, (1<mc_loop = !!val; break; + case IP_UNICAST_IF: + { + struct net_device *dev = NULL; + int ifindex; + + if (optlen != sizeof(int)) + goto e_inval; + + ifindex = (__force int)ntohl((__force __be32)val); + if (ifindex == 0) { + inet->uc_index = 0; + err = 0; + break; + } + + dev = dev_get_by_index(sock_net(sk), ifindex); + err = -EADDRNOTAVAIL; + if (!dev) + break; + dev_put(dev); + + err = -EINVAL; + if (sk->sk_bound_dev_if) + break; + + inet->uc_index = ifindex; + err = 0; + break; + } case IP_MULTICAST_IF: { struct ip_mreqn mreq; @@ -1178,6 +1208,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_MULTICAST_LOOP: val = inet->mc_loop; break; + case IP_UNICAST_IF: + val = (__force int)htonl((__u32) inet->uc_index); + break; case IP_MULTICAST_IF: { struct in_addr addr; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index aea5a199c37..cfc82cf339f 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -556,7 +556,8 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = inet->mc_index; if (!saddr) saddr = inet->mc_addr; - } + } else if (!ipc.oif) + ipc.oif = inet->uc_index; flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 3ccda5ae8a2..ab466305b62 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -563,7 +563,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = inet->mc_index; if (!saddr) saddr = inet->mc_addr; - } + } else if (!ipc.oif) + ipc.oif = inet->uc_index; flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5d075b5f70f..cd99f1a0f59 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -917,7 +917,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (!saddr) saddr = inet->mc_addr; connected = 0; - } + } else if (!ipc.oif) + ipc.oif = inet->uc_index; if (connected) rt = (struct rtable *)sk_dst_check(sk, 0); -- cgit v1.2.3-70-g09d2 From c4062dfc425e94290ac427a98d6b4721dd2bc91f Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Wed, 8 Feb 2012 09:11:08 +0000 Subject: ipv6: Implement IPV6_UNICAST_IF socket option. The IPV6_UNICAST_IF feature is the IPv6 compliment to IP_UNICAST_IF. Signed-off-by: Erich E. Hoover Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/in6.h | 1 + include/linux/ipv6.h | 1 + net/ipv6/icmp.c | 4 ++++ net/ipv6/ipv6_sockglue.c | 34 ++++++++++++++++++++++++++++++++++ net/ipv6/raw.c | 2 ++ net/ipv6/udp.c | 3 ++- 6 files changed, 44 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/in6.h b/include/linux/in6.h index 097a34b5556..5c83d9e3eb8 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -271,6 +271,7 @@ struct in6_flowlabel_req { #define IPV6_ORIGDSTADDR 74 #define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR #define IPV6_TRANSPARENT 75 +#define IPV6_UNICAST_IF 76 /* * Multicast Routing: diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 6318268dcaf..743a16a4104 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -324,6 +324,7 @@ struct ipv6_pinfo { __unused_2:6; __s16 mcast_hops:9; #endif + int ucast_oif; int mcast_oif; /* pktoption flags */ diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 01d46bff63c..af88934e4d7 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -468,6 +468,8 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) fl6.flowi6_oif = np->mcast_oif; + else if (!fl6.flowi6_oif) + fl6.flowi6_oif = np->ucast_oif; dst = icmpv6_route_lookup(net, skb, sk, &fl6); if (IS_ERR(dst)) @@ -553,6 +555,8 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) fl6.flowi6_oif = np->mcast_oif; + else if (!fl6.flowi6_oif) + fl6.flowi6_oif = np->ucast_oif; err = ip6_dst_lookup(sk, &dst, &fl6); if (err) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 18a2719003c..6d6b65fdaa1 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -516,6 +516,36 @@ done: retv = 0; break; + case IPV6_UNICAST_IF: + { + struct net_device *dev = NULL; + int ifindex; + + if (optlen != sizeof(int)) + goto e_inval; + + ifindex = (__force int)ntohl((__force __be32)val); + if (ifindex == 0) { + np->ucast_oif = 0; + retv = 0; + break; + } + + dev = dev_get_by_index(net, ifindex); + retv = -EADDRNOTAVAIL; + if (!dev) + break; + dev_put(dev); + + retv = -EINVAL; + if (sk->sk_bound_dev_if) + break; + + np->ucast_oif = ifindex; + retv = 0; + break; + } + case IPV6_MULTICAST_IF: if (sk->sk_type == SOCK_STREAM) break; @@ -1160,6 +1190,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, val = np->mcast_oif; break; + case IPV6_UNICAST_IF: + val = (__force int)htonl((__u32) np->ucast_oif); + break; + case IPV6_MTU_DISCOVER: val = np->pmtudisc; break; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d02f7e4dd61..5bddea77884 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -856,6 +856,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) fl6.flowi6_oif = np->mcast_oif; + else if (!fl6.flowi6_oif) + fl6.flowi6_oif = np->ucast_oif; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 4f96b5c6368..8aebf8f9043 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1130,7 +1130,8 @@ do_udp_sendmsg: if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) { fl6.flowi6_oif = np->mcast_oif; connected = 0; - } + } else if (!fl6.flowi6_oif) + fl6.flowi6_oif = np->ucast_oif; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); -- cgit v1.2.3-70-g09d2 From 2cfc6fc584a65db87935ca4e4d5e1ad89d5192ee Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 8 Feb 2012 19:17:11 +0100 Subject: mac80211: do not call rate control .tx_status before .rate_init Most rate control implementations assume .get_rate and .tx_status are only called once the per-station data has been fully initialized. minstrel_ht crashes if this assumption is violated. Signed-off-by: Felix Fietkau Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- net/mac80211/rate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 5fc3135a6b4..fbb1efdc4d0 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -37,7 +37,7 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; - if (!ref) + if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) return; ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); -- cgit v1.2.3-70-g09d2 From 7d316b9453523498246e9e19a659c423d4c5081e Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 8 Feb 2012 00:19:45 +0000 Subject: af_iucv: remove IUCV-pathes completely A SEVER is missing in the callback of a receiving SEVERED. This may inhibit z/VM to remove the corresponding IUCV-path completely. This patch adds a SEVER in iucv_callback_connrej (together with additional locking. Signed-off-by: Ursula Braun Signed-off-by: Martin Schwidefsky Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 71 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'net') diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index d5c5b8fd1d0..3ce0259499e 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -90,6 +90,7 @@ do { \ static void iucv_sock_kill(struct sock *sk); static void iucv_sock_close(struct sock *sk); +static void iucv_sever_path(struct sock *, int); static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); @@ -181,11 +182,7 @@ static int afiucv_pm_freeze(struct device *dev) case IUCV_DISCONN: case IUCV_CLOSING: case IUCV_CONNECTED: - if (iucv->path) { - err = pr_iucv->path_sever(iucv->path, NULL); - iucv_path_free(iucv->path); - iucv->path = NULL; - } + iucv_sever_path(sk, 0); break; case IUCV_OPEN: case IUCV_BOUND: @@ -194,6 +191,8 @@ static int afiucv_pm_freeze(struct device *dev) default: break; } + skb_queue_purge(&iucv->send_skb_q); + skb_queue_purge(&iucv->backlog_skb_q); } read_unlock(&iucv_sk_list.lock); return err; @@ -447,10 +446,29 @@ static void iucv_sock_kill(struct sock *sk) sock_put(sk); } +/* Terminate an IUCV path */ +static void iucv_sever_path(struct sock *sk, int with_user_data) +{ + unsigned char user_data[16]; + struct iucv_sock *iucv = iucv_sk(sk); + struct iucv_path *path = iucv->path; + + if (iucv->path) { + iucv->path = NULL; + if (with_user_data) { + low_nmcpy(user_data, iucv->src_name); + high_nmcpy(user_data, iucv->dst_name); + ASCEBC(user_data, sizeof(user_data)); + pr_iucv->path_sever(path, user_data); + } else + pr_iucv->path_sever(path, NULL); + iucv_path_free(path); + } +} + /* Close an IUCV socket */ static void iucv_sock_close(struct sock *sk) { - unsigned char user_data[16]; struct iucv_sock *iucv = iucv_sk(sk); unsigned long timeo; int err, blen; @@ -494,25 +512,14 @@ static void iucv_sock_close(struct sock *sk) sk->sk_state = IUCV_CLOSED; sk->sk_state_change(sk); - if (iucv->path) { - low_nmcpy(user_data, iucv->src_name); - high_nmcpy(user_data, iucv->dst_name); - ASCEBC(user_data, sizeof(user_data)); - pr_iucv->path_sever(iucv->path, user_data); - iucv_path_free(iucv->path); - iucv->path = NULL; - } - sk->sk_err = ECONNRESET; sk->sk_state_change(sk); iucv_skb_queue_purge(&iucv->send_skb_q); skb_queue_purge(&iucv->backlog_skb_q); - break; - default: - /* nothing to do here */ - break; + default: /* fall through */ + iucv_sever_path(sk, 1); } /* mark socket for deletion by iucv_sock_kill() */ @@ -894,11 +901,8 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_CLOSED) err = -ECONNREFUSED; - if (err && iucv->transport == AF_IUCV_TRANS_IUCV) { - pr_iucv->path_sever(iucv->path, NULL); - iucv_path_free(iucv->path); - iucv->path = NULL; - } + if (err && iucv->transport == AF_IUCV_TRANS_IUCV) + iucv_sever_path(sk, 0); done: release_sock(sk); @@ -1565,13 +1569,6 @@ static int iucv_sock_release(struct socket *sock) iucv_sock_close(sk); - /* Unregister with IUCV base support */ - if (iucv_sk(sk)->path) { - pr_iucv->path_sever(iucv_sk(sk)->path, NULL); - iucv_path_free(iucv_sk(sk)->path); - iucv_sk(sk)->path = NULL; - } - sock_orphan(sk); iucv_sock_kill(sk); return err; @@ -1750,8 +1747,7 @@ static int iucv_callback_connreq(struct iucv_path *path, path->msglim = iucv->msglimit; err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk); if (err) { - err = pr_iucv->path_sever(path, user_data); - iucv_path_free(path); + iucv_sever_path(nsk, 1); iucv_sock_kill(nsk); goto fail; } @@ -1828,6 +1824,7 @@ static void iucv_callback_txdone(struct iucv_path *path, struct sk_buff *list_skb = list->next; unsigned long flags; + bh_lock_sock(sk); if (!skb_queue_empty(list)) { spin_lock_irqsave(&list->lock, flags); @@ -1849,7 +1846,6 @@ static void iucv_callback_txdone(struct iucv_path *path, iucv_sock_wake_msglim(sk); } } - BUG_ON(!this); if (sk->sk_state == IUCV_CLOSING) { if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { @@ -1857,6 +1853,7 @@ static void iucv_callback_txdone(struct iucv_path *path, sk->sk_state_change(sk); } } + bh_unlock_sock(sk); } @@ -1864,9 +1861,15 @@ static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) { struct sock *sk = path->private; + if (sk->sk_state == IUCV_CLOSED) + return; + + bh_lock_sock(sk); + iucv_sever_path(sk, 1); sk->sk_state = IUCV_DISCONN; sk->sk_state_change(sk); + bh_unlock_sock(sk); } /* called if the other communication side shuts down its RECV direction; -- cgit v1.2.3-70-g09d2 From 7f1b0ea42a800713a3d56e1e8ca1a845e0461ca2 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 8 Feb 2012 00:19:46 +0000 Subject: af_iucv: block writing if msg limit is exceeded When polling on an AF_IUCV socket, writing should be blocked if the number of pending messages exceeds a defined limit. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 3ce0259499e..ef6ab71921f 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1490,7 +1490,7 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock, if (sk->sk_state == IUCV_DISCONN) mask |= POLLIN; - if (sock_writeable(sk)) + if (sock_writeable(sk) && iucv_below_msglim(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); -- cgit v1.2.3-70-g09d2 From 800c5eb7b5eba6cb2a32738d763fd59f0fbcdde4 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 8 Feb 2012 00:19:47 +0000 Subject: af_iucv: change net_device handling for HS transport This patch saves the net_device in the iucv_sock structure during bind in order to fasten skb sending. In addition some other small improvements are made for HS transport: - error checking when sending skbs - locking changes in afiucv_hs_callback_txnotify - skb freeing in afiucv_hs_callback_txnotify And finally it contains code cleanup to get rid of iucv_skb_queue_purge. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- include/net/iucv/af_iucv.h | 1 + net/iucv/af_iucv.c | 119 +++++++++++++++++++++++---------------------- 2 files changed, 63 insertions(+), 57 deletions(-) (limited to 'net') diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index 0954ec95915..a1517887aea 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -113,6 +113,7 @@ struct iucv_sock { spinlock_t accept_q_lock; struct sock *parent; struct iucv_path *path; + struct net_device *hs_dev; struct sk_buff_head send_skb_q; struct sk_buff_head backlog_skb_q; struct sock_msg_q message_q; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index ef6ab71921f..fbce4a3126d 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -131,17 +131,6 @@ static inline void low_nmcpy(unsigned char *dst, char *src) memcpy(&dst[8], src, 8); } -static void iucv_skb_queue_purge(struct sk_buff_head *list) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(list)) != NULL) { - if (skb->dev) - dev_put(skb->dev); - kfree_skb(skb); - } -} - static int afiucv_pm_prepare(struct device *dev) { #ifdef CONFIG_PM_DEBUG @@ -176,7 +165,7 @@ static int afiucv_pm_freeze(struct device *dev) read_lock(&iucv_sk_list.lock); sk_for_each(sk, node, &iucv_sk_list.head) { iucv = iucv_sk(sk); - iucv_skb_queue_purge(&iucv->send_skb_q); + skb_queue_purge(&iucv->send_skb_q); skb_queue_purge(&iucv->backlog_skb_q); switch (sk->sk_state) { case IUCV_DISCONN: @@ -337,7 +326,6 @@ static void iucv_sock_wake_msglim(struct sock *sk) static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, struct sk_buff *skb, u8 flags) { - struct net *net = sock_net(sock); struct iucv_sock *iucv = iucv_sk(sock); struct af_iucv_trans_hdr *phs_hdr; struct sk_buff *nskb; @@ -374,10 +362,10 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, if (imsg) memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message)); - skb->dev = dev_get_by_index(net, sock->sk_bound_dev_if); + skb->dev = iucv->hs_dev; if (!skb->dev) return -ENODEV; - if (!(skb->dev->flags & IFF_UP)) + if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) return -ENETDOWN; if (skb->len > skb->dev->mtu) { if (sock->sk_type == SOCK_SEQPACKET) @@ -392,15 +380,14 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, return -ENOMEM; skb_queue_tail(&iucv->send_skb_q, nskb); err = dev_queue_xmit(skb); - if (err) { + if (net_xmit_eval(err)) { skb_unlink(nskb, &iucv->send_skb_q); - dev_put(nskb->dev); kfree_skb(nskb); } else { atomic_sub(confirm_recv, &iucv->msg_recv); WARN_ON(atomic_read(&iucv->msg_recv) < 0); } - return err; + return net_xmit_eval(err); } static struct sock *__iucv_get_sock_by_name(char *nm) @@ -471,7 +458,8 @@ static void iucv_sock_close(struct sock *sk) { struct iucv_sock *iucv = iucv_sk(sk); unsigned long timeo; - int err, blen; + int err = 0; + int blen; struct sk_buff *skb; lock_sock(sk); @@ -498,7 +486,7 @@ static void iucv_sock_close(struct sock *sk) sk->sk_state = IUCV_CLOSING; sk->sk_state_change(sk); - if (!skb_queue_empty(&iucv->send_skb_q)) { + if (!err && !skb_queue_empty(&iucv->send_skb_q)) { if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) timeo = sk->sk_lingertime; else @@ -515,13 +503,19 @@ static void iucv_sock_close(struct sock *sk) sk->sk_err = ECONNRESET; sk->sk_state_change(sk); - iucv_skb_queue_purge(&iucv->send_skb_q); + skb_queue_purge(&iucv->send_skb_q); skb_queue_purge(&iucv->backlog_skb_q); default: /* fall through */ iucv_sever_path(sk, 1); } + if (iucv->hs_dev) { + dev_put(iucv->hs_dev); + iucv->hs_dev = NULL; + sk->sk_bound_dev_if = 0; + } + /* mark socket for deletion by iucv_sock_kill() */ sock_set_flag(sk, SOCK_ZAPPED); @@ -713,7 +707,6 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, goto done_unlock; /* Bind the socket */ - if (pr_iucv) if (!memcmp(sa->siucv_user_id, iucv_userid, 8)) goto vm_bind; /* VM IUCV transport */ @@ -727,6 +720,8 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, memcpy(iucv->src_name, sa->siucv_name, 8); memcpy(iucv->src_user_id, sa->siucv_user_id, 8); sk->sk_bound_dev_if = dev->ifindex; + iucv->hs_dev = dev; + dev_hold(dev); sk->sk_state = IUCV_BOUND; iucv->transport = AF_IUCV_TRANS_HIPER; if (!iucv->msglimit) @@ -1128,8 +1123,10 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, noblock, &err); else skb = sock_alloc_send_skb(sk, len, noblock, &err); - if (!skb) + if (!skb) { + err = -ENOMEM; goto out; + } if (iucv->transport == AF_IUCV_TRANS_HIPER) skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN); if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { @@ -1152,6 +1149,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, /* increment and save iucv message tag for msg_completion cbk */ txmsg.tag = iucv->send_tag++; memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN); + if (iucv->transport == AF_IUCV_TRANS_HIPER) { atomic_inc(&iucv->msg_sent); err = afiucv_hs_send(&txmsg, sk, skb, 0); @@ -1206,8 +1204,6 @@ release: return len; fail: - if (skb->dev) - dev_put(skb->dev); kfree_skb(skb); out: release_sock(sk); @@ -1400,7 +1396,14 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, } kfree_skb(skb); - atomic_inc(&iucv->msg_recv); + if (iucv->transport == AF_IUCV_TRANS_HIPER) { + atomic_inc(&iucv->msg_recv); + if (atomic_read(&iucv->msg_recv) > iucv->msglimit) { + WARN_ON(1); + iucv_sock_close(sk); + return -EFAULT; + } + } /* Queue backlog skbs */ spin_lock_bh(&iucv->message_q.lock); @@ -1957,6 +1960,8 @@ static int afiucv_hs_callback_syn(struct sock *sk, struct sk_buff *skb) memcpy(niucv->src_name, iucv->src_name, 8); memcpy(niucv->src_user_id, iucv->src_user_id, 8); nsk->sk_bound_dev_if = sk->sk_bound_dev_if; + niucv->hs_dev = iucv->hs_dev; + dev_hold(niucv->hs_dev); afiucv_swap_src_dest(skb); trans_hdr->flags = AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_ACK; trans_hdr->window = niucv->msglimit; @@ -2025,12 +2030,15 @@ static int afiucv_hs_callback_fin(struct sock *sk, struct sk_buff *skb) struct iucv_sock *iucv = iucv_sk(sk); /* other end of connection closed */ - if (iucv) { - bh_lock_sock(sk); + if (!iucv) + goto out; + bh_lock_sock(sk); + if (sk->sk_state == IUCV_CONNECTED) { sk->sk_state = IUCV_DISCONN; sk->sk_state_change(sk); - bh_unlock_sock(sk); } + bh_unlock_sock(sk); +out: kfree_skb(skb); return NET_RX_SUCCESS; } @@ -2175,11 +2183,11 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev, break; case (AF_IUCV_FLAG_WIN): err = afiucv_hs_callback_win(sk, skb); - if (skb->len > sizeof(struct af_iucv_trans_hdr)) - err = afiucv_hs_callback_rx(sk, skb); - else - kfree(skb); - break; + if (skb->len == sizeof(struct af_iucv_trans_hdr)) { + kfree_skb(skb); + break; + } + /* fall through */ case 0: /* plain data frame */ memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class, @@ -2205,65 +2213,64 @@ static void afiucv_hs_callback_txnotify(struct sk_buff *skb, struct iucv_sock *iucv = NULL; struct sk_buff_head *list; struct sk_buff *list_skb; - struct sk_buff *this = NULL; + struct sk_buff *nskb; unsigned long flags; struct hlist_node *node; - read_lock(&iucv_sk_list.lock); + read_lock_irqsave(&iucv_sk_list.lock, flags); sk_for_each(sk, node, &iucv_sk_list.head) if (sk == isk) { iucv = iucv_sk(sk); break; } - read_unlock(&iucv_sk_list.lock); + read_unlock_irqrestore(&iucv_sk_list.lock, flags); - if (!iucv) + if (!iucv || sock_flag(sk, SOCK_ZAPPED)) return; - bh_lock_sock(sk); list = &iucv->send_skb_q; - list_skb = list->next; + spin_lock_irqsave(&list->lock, flags); if (skb_queue_empty(list)) goto out_unlock; - - spin_lock_irqsave(&list->lock, flags); + list_skb = list->next; + nskb = list_skb->next; while (list_skb != (struct sk_buff *)list) { if (skb_shinfo(list_skb) == skb_shinfo(skb)) { - this = list_skb; switch (n) { case TX_NOTIFY_OK: - __skb_unlink(this, list); + __skb_unlink(list_skb, list); + kfree_skb(list_skb); iucv_sock_wake_msglim(sk); - dev_put(this->dev); - kfree_skb(this); break; case TX_NOTIFY_PENDING: atomic_inc(&iucv->pendings); break; case TX_NOTIFY_DELAYED_OK: - __skb_unlink(this, list); + __skb_unlink(list_skb, list); atomic_dec(&iucv->pendings); if (atomic_read(&iucv->pendings) <= 0) iucv_sock_wake_msglim(sk); - dev_put(this->dev); - kfree_skb(this); + kfree_skb(list_skb); break; case TX_NOTIFY_UNREACHABLE: case TX_NOTIFY_DELAYED_UNREACHABLE: case TX_NOTIFY_TPQFULL: /* not yet used */ case TX_NOTIFY_GENERALERROR: case TX_NOTIFY_DELAYED_GENERALERROR: - __skb_unlink(this, list); - dev_put(this->dev); - kfree_skb(this); - sk->sk_state = IUCV_DISCONN; - sk->sk_state_change(sk); + __skb_unlink(list_skb, list); + kfree_skb(list_skb); + if (sk->sk_state == IUCV_CONNECTED) { + sk->sk_state = IUCV_DISCONN; + sk->sk_state_change(sk); + } break; } break; } - list_skb = list_skb->next; + list_skb = nskb; + nskb = nskb->next; } +out_unlock: spin_unlock_irqrestore(&list->lock, flags); if (sk->sk_state == IUCV_CLOSING) { @@ -2273,8 +2280,6 @@ static void afiucv_hs_callback_txnotify(struct sk_buff *skb, } } -out_unlock: - bh_unlock_sock(sk); } static const struct proto_ops iucv_sock_ops = { .family = PF_IUCV, -- cgit v1.2.3-70-g09d2 From 51363b8751a673a00ad48eea895266396d53fa52 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 8 Feb 2012 00:19:48 +0000 Subject: af_iucv: allow retrieval of maximum message size For HS transport the maximum message size depends on the MTU-size of the HS-device bound to the AF_IUCV socket. This patch adds a getsockopt option MSGSIZE returning the maximum message size that can be handled for this AF_IUCV socket. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- include/net/iucv/af_iucv.h | 1 + net/iucv/af_iucv.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index a1517887aea..2e1d5ecc2d1 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -132,6 +132,7 @@ struct iucv_sock { /* iucv socket options (SOL_IUCV) */ #define SO_IPRMDATA_MSG 0x0080 /* send/recv IPRM_DATA msgs */ #define SO_MSGLIMIT 0x1000 /* get/set IUCV MSGLIMIT */ +#define SO_MSGSIZE 0x0800 /* get maximum msgsize */ /* iucv related control messages (scm) */ #define SCM_IUCV_TRGCLS 0x0001 /* target class control message */ diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index fbce4a3126d..98d1f0ba7fe 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1633,7 +1633,8 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, { struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk); - int val, len; + unsigned int val; + int len; if (level != SOL_IUCV) return -ENOPROTOOPT; @@ -1656,6 +1657,13 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, : iucv->msglimit; /* default */ release_sock(sk); break; + case SO_MSGSIZE: + if (sk->sk_state == IUCV_OPEN) + return -EBADFD; + val = (iucv->hs_dev) ? iucv->hs_dev->mtu - + sizeof(struct af_iucv_trans_hdr) - ETH_HLEN : + 0x7fffffff; + break; default: return -ENOPROTOOPT; } -- cgit v1.2.3-70-g09d2 From 5fd5c44d3f27c93685d4a036565245f3cdb8c033 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Thu, 9 Feb 2012 23:17:15 +0900 Subject: rds: Fix typo in iw_recv.c and ib_recv.c Correct spelling "inclue" to "include" in net/rds/iw_recv.c and net/rds/ib_recv.c Signed-off-by: Masanari Iida Signed-off-by: Jiri Kosina --- net/rds/ib_recv.c | 2 +- net/rds/iw_recv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index e29e0ca32f7..8d6d9702d1e 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -826,7 +826,7 @@ static void rds_ib_process_recv(struct rds_connection *conn, if (data_len < sizeof(struct rds_header)) { rds_ib_conn_error(conn, "incoming message " - "from %pI4 didn't inclue a " + "from %pI4 didn't include a " "header, disconnecting and " "reconnecting\n", &conn->c_faddr); diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 5e57347f49f..3c871700501 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -661,7 +661,7 @@ static void rds_iw_process_recv(struct rds_connection *conn, if (byte_len < sizeof(struct rds_header)) { rds_iw_conn_error(conn, "incoming message " - "from %pI4 didn't inclue a " + "from %pI4 didn't include a " "header, disconnecting and " "reconnecting\n", &conn->c_faddr); -- cgit v1.2.3-70-g09d2 From 7a3198a89722ad9521d22b05938d357eac7460fa Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 9 Feb 2012 09:34:41 +0000 Subject: ipv6: helper function to get tclass Implement helper inline function to get traffic class from IPv6 header. Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- include/linux/ipv6.h | 5 +++++ net/ipv6/datagram.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 743a16a4104..4847a64d3c0 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -233,6 +233,11 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb) return (struct ipv6hdr *)skb_transport_header(skb); } +static inline __u8 ipv6_tclass(const struct ipv6hdr *iph) +{ + return (ntohl(*(__be32 *)iph) >> 20) & 0xff; +} + /* This structure contains results of exthdrs parsing as offsets from skb->nh. diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 251e7cd75e8..76832c8dc89 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -485,7 +485,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) } if (np->rxopt.bits.rxtclass) { - int tclass = (ntohl(*(__be32 *)ipv6_hdr(skb)) >> 20) & 0xff; + int tclass = ipv6_tclass(ipv6_hdr(skb)); put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); } -- cgit v1.2.3-70-g09d2 From 4c507d2897bd9be810b3403ade73b04cf6fdfd4a Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 9 Feb 2012 09:35:49 +0000 Subject: net: implement IP_RECVTOS for IP_PKTOPTIONS Currently, it is not easily possible to get TOS/DSCP value of packets from an incoming TCP stream. The mechanism is there, IP_PKTOPTIONS getsockopt with IP_RECVTOS set, the same way as incoming TTL can be queried. This is not actually implemented for TOS, though. This patch adds this functionality, both for IPv4 (IP_PKTOPTIONS) and IPv6 (IPV6_2292PKTOPTIONS). For IPv4, like in the IP_RECVTTL case, the value of the TOS field is stored from the other party's ACK. This is needed for proxies which require DSCP transparency. One such example is at http://zph.bratcheda.org/. Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- include/linux/ipv6.h | 2 +- include/net/inet_sock.h | 1 + net/ipv4/af_inet.c | 1 + net/ipv4/ip_sockglue.c | 4 ++++ net/ipv4/tcp_ipv4.c | 1 + net/ipv6/af_inet6.c | 1 + net/ipv6/ipv6_sockglue.c | 4 ++++ net/ipv6/tcp_ipv6.c | 4 ++++ 8 files changed, 17 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4847a64d3c0..8260ef77976 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -366,7 +366,7 @@ struct ipv6_pinfo { dontfrag:1; __u8 min_hopcount; __u8 tclass; - __u8 padding; + __u8 rcv_tclass; __u32 dst_cookie; diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 022f772c0eb..ae17e1352d7 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -168,6 +168,7 @@ struct inet_sock { transparent:1, mc_all:1, nodefrag:1; + __u8 rcv_tos; int uc_index; int mc_index; __be32 mc_addr; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index f7b5670744f..e588a34e85c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -381,6 +381,7 @@ lookup_protocol: inet->mc_all = 1; inet->mc_index = 0; inet->mc_list = NULL; + inet->rcv_tos = 0; sk_refcnt_debug_inc(sk); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 9125529dab9..ca50d9f9f8c 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1289,6 +1289,10 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, int hlim = inet->mc_ttl; put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim); } + if (inet->cmsg_flags & IP_CMSG_TOS) { + int tos = inet->rcv_tos; + put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos); + } len -= msg.msg_controllen; return put_user(len, optlen); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4d6f81c818d..94abee8cf56 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1463,6 +1463,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ireq->opt = NULL; newinet->mc_index = inet_iif(skb); newinet->mc_ttl = ip_hdr(skb)->ttl; + newinet->rcv_tos = ip_hdr(skb)->tos; inet_csk(newsk)->icsk_ext_hdr_len = 0; if (inet_opt) inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 273f48d1df2..5605f9dca87 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -214,6 +214,7 @@ lookup_protocol: inet->mc_ttl = 1; inet->mc_index = 0; inet->mc_list = NULL; + inet->rcv_tos = 0; if (ipv4_config.no_pmtu_disc) inet->pmtudisc = IP_PMTUDISC_DONT; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 6d6b65fdaa1..63dd1f89ed7 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1017,6 +1017,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, int hlim = np->mcast_hops; put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); } + if (np->rxopt.bits.rxtclass) { + int tclass = np->rcv_tclass; + put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); + } if (np->rxopt.bits.rxoinfo) { struct in6_pktinfo src_info; src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d16414cb342..12c6ece67f3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1282,6 +1282,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; + newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); /* * No need to charge this sock to the relevant IPv6 refcnt debug socks count @@ -1360,6 +1361,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; + newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); /* Clone native IPv6 options from listening socket (if any) @@ -1562,6 +1564,8 @@ ipv6_pktoptions: np->mcast_oif = inet6_iif(opt_skb); if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; + if (np->rxopt.bits.rxtclass) + np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); if (ipv6_opt_accepted(sk, opt_skb)) { skb_set_owner_r(opt_skb, sk); opt_skb = xchg(&np->pktoptions, opt_skb); -- cgit v1.2.3-70-g09d2 From c8585bd89e2e3c87eab6ca711e09b3af20fd469b Mon Sep 17 00:00:00 2001 From: Danny Kukawka Date: Thu, 9 Feb 2012 09:48:53 +0000 Subject: eth: reset addr_assign_type if eth_mac_addr() called If eth_mac_addr() get called, usually if SIOCSIFHWADDR was used to change the MAC of a ethernet device, reset the addr_assign_type to NET_ADDR_PERM if the state was NET_ADDR_RANDOM before. Reset the state since the MAC is no longer random at least not from the kernel side. v2: changed to bitops, removed if() Signed-off-by: Danny Kukawka Signed-off-by: David S. Miller --- net/ethernet/eth.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index a2468363978..a93af86b847 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -288,6 +288,8 @@ int eth_mac_addr(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + /* if device marked as NET_ADDR_RANDOM, reset it */ + dev->addr_assign_type &= ~NET_ADDR_RANDOM; return 0; } EXPORT_SYMBOL(eth_mac_addr); -- cgit v1.2.3-70-g09d2 From b57c1a5646739bfc273245dc738f2f12a2d4d3ec Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 3 Jan 2012 16:03:00 +0200 Subject: Bluetooth: Convert inquiry cache to use standard list types This makes it possible to use the convenience functions provided for standard kernel list types and it also makes it easier to extend the use of the cache for the management interface where e.g. name resolving control will be needed. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 10 ++++------ net/bluetooth/hci_core.c | 31 +++++++++++++++++-------------- net/bluetooth/hci_sysfs.c | 2 +- 3 files changed, 22 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ea9231f4935..91d1baf0507 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -44,14 +44,14 @@ struct inquiry_data { }; struct inquiry_entry { - struct inquiry_entry *next; + struct list_head list; __u32 timestamp; struct inquiry_data data; }; struct inquiry_cache { + struct list_head list; __u32 timestamp; - struct inquiry_entry *list; }; struct hci_conn_hash { @@ -350,14 +350,12 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); static inline void inquiry_cache_init(struct hci_dev *hdev) { - struct inquiry_cache *c = &hdev->inq_cache; - c->list = NULL; + INIT_LIST_HEAD(&hdev->inq_cache.list); } static inline int inquiry_cache_empty(struct hci_dev *hdev) { - struct inquiry_cache *c = &hdev->inq_cache; - return c->list == NULL; + return list_empty(&hdev->inq_cache.list); } static inline long inquiry_cache_age(struct hci_dev *hdev) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 845da3ee56a..feeea4df252 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -357,15 +357,11 @@ struct hci_dev *hci_dev_get(int index) /* ---- Inquiry support ---- */ static void inquiry_cache_flush(struct hci_dev *hdev) { - struct inquiry_cache *cache = &hdev->inq_cache; - struct inquiry_entry *next = cache->list, *e; - - BT_DBG("cache %p", cache); + struct inquiry_entry *p, *n; - cache->list = NULL; - while ((e = next)) { - next = e->next; - kfree(e); + list_for_each_entry_safe(p, n, &hdev->inq_cache.list, list) { + list_del(&p->list); + kfree(p); } } @@ -376,10 +372,12 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b BT_DBG("cache %p, %s", cache, batostr(bdaddr)); - for (e = cache->list; e; e = e->next) + list_for_each_entry(e, &cache->list, list) { if (!bacmp(&e->data.bdaddr, bdaddr)) - break; - return e; + return e; + } + + return NULL; } void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) @@ -396,8 +394,7 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) if (!ie) return; - ie->next = cache->list; - cache->list = ie; + list_add(&ie->list, &cache->list); } memcpy(&ie->data, data, sizeof(*data)); @@ -412,15 +409,21 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) struct inquiry_entry *e; int copied = 0; - for (e = cache->list; e && copied < num; e = e->next, copied++) { + list_for_each_entry(e, &cache->list, list) { struct inquiry_data *data = &e->data; + + if (copied >= num) + break; + bacpy(&info->bdaddr, &data->bdaddr); info->pscan_rep_mode = data->pscan_rep_mode; info->pscan_period_mode = data->pscan_period_mode; info->pscan_mode = data->pscan_mode; memcpy(info->dev_class, data->dev_class, 3); info->clock_offset = data->clock_offset; + info++; + copied++; } BT_DBG("cache %p, copied %d", cache, copied); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 52109561423..ed9cceeec7b 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -388,7 +388,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) hci_dev_lock(hdev); - for (e = cache->list; e; e = e->next) { + list_for_each_entry(e, &cache->list, list) { struct inquiry_data *data = &e->data; seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", batostr(&data->bdaddr), -- cgit v1.2.3-70-g09d2 From 32748db00228b67a5315a91e1a6dd2c54864d87b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 30 Dec 2011 14:57:23 +0200 Subject: Bluetooth: Move Extended Inquiry Response defines to hci.h The EIR defines are needed also outside of mgmt.c (e.g. in hci_event.c to check if EIR data has the complete name) so it's better to have them in a single public place, i.e. hci.h. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 13 +++++++++++++ net/bluetooth/mgmt.c | 12 ------------ 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5b2fed5eebf..ce5133b2244 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -284,6 +284,19 @@ enum { #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00 #define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01 +/* Extended Inquiry Response field types */ +#define EIR_FLAGS 0x01 /* flags */ +#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define EIR_NAME_SHORT 0x08 /* shortened local name */ +#define EIR_NAME_COMPLETE 0x09 /* complete local name */ +#define EIR_TX_POWER 0x0A /* transmit power level */ +#define EIR_DEVICE_ID 0x10 /* device ID */ + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bc8e59dda78..851cb19c55b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -303,18 +303,6 @@ static u32 get_current_settings(struct hci_dev *hdev) return settings; } -#define EIR_FLAGS 0x01 /* flags */ -#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ -#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ -#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ -#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ -#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ -#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ -#define EIR_NAME_SHORT 0x08 /* shortened local name */ -#define EIR_NAME_COMPLETE 0x09 /* complete local name */ -#define EIR_TX_POWER 0x0A /* transmit power level */ -#define EIR_DEVICE_ID 0x10 /* device ID */ - #define PNP_INFO_SVCLASS_ID 0x1200 static u8 bluetooth_base_uuid[] = { -- cgit v1.2.3-70-g09d2 From 561aafbcb2e3f8fee11d3781f866c7b4c4f93a28 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 13:31:59 +0200 Subject: Bluetooth: Add initial mgmt_confirm_name support This patch adds initial support for mgmt_confirm_name. It adds the necessary tracking of the name state by extending the inquiry cache. The actual name resolving operation (to be done once inquiry is finished) is not yet part of this patch. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 29 +++++++++++++++----- net/bluetooth/hci_core.c | 58 ++++++++++++++++++++++++++++++++-------- net/bluetooth/hci_event.c | 51 +++++++++++++++++++++++++++++------ net/bluetooth/hci_sysfs.c | 2 +- net/bluetooth/mgmt.c | 51 ++++++++++++++++++++++++++++++++++- 5 files changed, 163 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 91d1baf0507..2999b6e2c3f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -44,14 +44,23 @@ struct inquiry_data { }; struct inquiry_entry { - struct list_head list; + struct list_head all; /* inq_cache.all */ + struct list_head list; /* unknown or resolve */ + enum { + NAME_NOT_KNOWN, + NAME_NEEDED, + NAME_PENDING, + NAME_KNOWN, + } name_state; __u32 timestamp; struct inquiry_data data; }; struct inquiry_cache { - struct list_head list; - __u32 timestamp; + struct list_head all; /* All devices found during inquiry */ + struct list_head unknown; /* Name state not known */ + struct list_head resolve; /* Name needs to be resolved */ + __u32 timestamp; }; struct hci_conn_hash { @@ -350,12 +359,14 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); static inline void inquiry_cache_init(struct hci_dev *hdev) { - INIT_LIST_HEAD(&hdev->inq_cache.list); + INIT_LIST_HEAD(&hdev->inq_cache.all); + INIT_LIST_HEAD(&hdev->inq_cache.unknown); + INIT_LIST_HEAD(&hdev->inq_cache.resolve); } static inline int inquiry_cache_empty(struct hci_dev *hdev) { - return list_empty(&hdev->inq_cache.list); + return list_empty(&hdev->inq_cache.all); } static inline long inquiry_cache_age(struct hci_dev *hdev) @@ -371,7 +382,10 @@ static inline long inquiry_entry_age(struct inquiry_entry *e) struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data); +struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, + bdaddr_t *bdaddr); +void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, + bool name_known); /* ----- HCI Connections ----- */ enum { @@ -913,7 +927,8 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir); + u8 addr_type, u8 *dev_class, s8 rssi, + u8 cfm_name, u8 *eir); int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index feeea4df252..fc09a3cbe20 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -357,12 +357,16 @@ struct hci_dev *hci_dev_get(int index) /* ---- Inquiry support ---- */ static void inquiry_cache_flush(struct hci_dev *hdev) { + struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_entry *p, *n; - list_for_each_entry_safe(p, n, &hdev->inq_cache.list, list) { - list_del(&p->list); + list_for_each_entry_safe(p, n, &cache->all, all) { + list_del(&p->all); kfree(p); } + + INIT_LIST_HEAD(&cache->unknown); + INIT_LIST_HEAD(&cache->resolve); } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) @@ -372,7 +376,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b BT_DBG("cache %p, %s", cache, batostr(bdaddr)); - list_for_each_entry(e, &cache->list, list) { + list_for_each_entry(e, &cache->all, all) { if (!bacmp(&e->data.bdaddr, bdaddr)) return e; } @@ -380,7 +384,24 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b return NULL; } -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) +struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, + bdaddr_t *bdaddr) +{ + struct inquiry_cache *cache = &hdev->inq_cache; + struct inquiry_entry *e; + + BT_DBG("cache %p, %s", cache, batostr(bdaddr)); + + list_for_each_entry(e, &cache->unknown, list) { + if (!bacmp(&e->data.bdaddr, bdaddr)) + return e; + } + + return NULL; +} + +void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, + bool name_known) { struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_entry *ie; @@ -388,13 +409,28 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); - if (!ie) { - /* Entry not in the cache. Add new one. */ - ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); - if (!ie) - return; + if (ie) + goto update; + + /* Entry not in the cache. Add new one. */ + ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); + if (!ie) + return; + + list_add(&ie->all, &cache->all); + + if (name_known) { + ie->name_state = NAME_KNOWN; + } else { + ie->name_state = NAME_NOT_KNOWN; + list_add(&ie->list, &cache->unknown); + } - list_add(&ie->list, &cache->list); +update: + if (name_known && ie->name_state != NAME_KNOWN && + ie->name_state != NAME_PENDING) { + ie->name_state = NAME_KNOWN; + list_del(&ie->list); } memcpy(&ie->data, data, sizeof(*data)); @@ -409,7 +445,7 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) struct inquiry_entry *e; int copied = 0; - list_for_each_entry(e, &cache->list, list) { + list_for_each_entry(e, &cache->all, all) { struct inquiry_data *data = &e->data; if (copied >= num) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 001307f8105..9302c3c2556 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1533,9 +1533,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * data.clock_offset = info->clock_offset; data.rssi = 0x00; data.ssp_mode = 0x00; - hci_inquiry_cache_update(hdev, &data); + hci_inquiry_cache_update(hdev, &data, false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, NULL); + info->dev_class, 0, 1, NULL); } hci_dev_unlock(hdev); @@ -2572,10 +2572,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - hci_inquiry_cache_update(hdev, &data); + hci_inquiry_cache_update(hdev, &data, false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - NULL); + 1, NULL); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2589,10 +2589,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - hci_inquiry_cache_update(hdev, &data); + hci_inquiry_cache_update(hdev, &data, false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - NULL); + 1, NULL); } } @@ -2710,6 +2710,31 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s BT_DBG("%s status %d", hdev->name, ev->status); } +static inline bool eir_has_complete_name(u8 *data, size_t data_len) +{ + u8 field_len; + size_t parsed; + + for (parsed = 0; parsed < data_len - 1; parsed += field_len) { + field_len = data[0]; + + if (field_len == 0) + break; + + parsed += field_len + 1; + + if (parsed > data_len) + break; + + if (data[1] == EIR_NAME_COMPLETE) + return true; + + data += field_len + 1; + } + + return false; +} + static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct inquiry_data data; @@ -2724,6 +2749,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { + bool name_known; + bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2732,9 +2759,17 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x01; - hci_inquiry_cache_update(hdev, &data); + + if (test_bit(HCI_MGMT, &hdev->flags)) + name_known = eir_has_complete_name(info->data, + sizeof(info->data)); + else + name_known = true; + + hci_inquiry_cache_update(hdev, &data, name_known); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, info->data); + info->dev_class, info->rssi, + !name_known, info->data); } hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index ed9cceeec7b..3600d78c2f2 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -388,7 +388,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) hci_dev_lock(hdev); - list_for_each_entry(e, &cache->list, list) { + list_for_each_entry(e, &cache->all, all) { struct inquiry_data *data = &e->data; seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", batostr(&data->bdaddr), diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 851cb19c55b..39775119585 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1967,6 +1967,50 @@ failed: return err; } +static int confirm_name(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct mgmt_cp_confirm_name *cp = (void *) data; + struct inquiry_entry *e; + struct hci_dev *hdev; + int err; + + BT_DBG("hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr); + if (!e) { + err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS); + goto failed; + } + + if (cp->name_known) { + e->name_state = NAME_KNOWN; + list_del(&e->list); + } else { + e->name_state = NAME_NEEDED; + list_move(&e->list, &hdev->inq_cache.resolve); + } + + err = 0; + +failed: + hci_dev_unlock(hdev); + + return err; +} + static int block_device(struct sock *sk, u16 index, unsigned char *data, u16 len) { @@ -2215,6 +2259,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_STOP_DISCOVERY: err = stop_discovery(sk, index); break; + case MGMT_OP_CONFIRM_NAME: + err = confirm_name(sk, index, buf + sizeof(*hdr), len); + break; case MGMT_OP_BLOCK_DEVICE: err = block_device(sk, index, buf + sizeof(*hdr), len); break; @@ -2689,7 +2736,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, } int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir) + u8 addr_type, u8 *dev_class, s8 rssi, + u8 cfm_name, u8 *eir) { struct mgmt_ev_device_found ev; @@ -2698,6 +2746,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_mgmt(link_type, addr_type); ev.rssi = rssi; + ev.confirm_name = cfm_name; if (eir) memcpy(ev.eir, eir, sizeof(ev.eir)); -- cgit v1.2.3-70-g09d2 From 3175405b906a85ed2bad21e09c444266e4a05a8e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 13:39:52 +0200 Subject: Bluetooth: Return updated name state with hci_inquiry_cache_update If user-space has already confirmed the name for a remote device we shouldn't request confirmation again. The simplest way to do this is to return the name state from hci_inquiry_cache_update (if it is anything else than unknown then we do not need confirmation from user-space). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 9 +++++++-- net/bluetooth/hci_event.c | 21 ++++++++++++++------- 3 files changed, 22 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2999b6e2c3f..236f7f0e596 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -384,7 +384,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, bdaddr_t *bdaddr); -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, +bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); /* ----- HCI Connections ----- */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fc09a3cbe20..162176151db 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -400,7 +400,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, return NULL; } -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, +bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { struct inquiry_cache *cache = &hdev->inq_cache; @@ -415,7 +415,7 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, /* Entry not in the cache. Add new one. */ ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); if (!ie) - return; + return false; list_add(&ie->all, &cache->all); @@ -436,6 +436,11 @@ update: memcpy(&ie->data, data, sizeof(*data)); ie->timestamp = jiffies; cache->timestamp = jiffies; + + if (ie->name_state == NAME_NOT_KNOWN) + return false; + + return true; } static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9302c3c2556..d4d20df9fbb 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1525,6 +1525,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { + bool name_known; + bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -1533,9 +1535,10 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * data.clock_offset = info->clock_offset; data.rssi = 0x00; data.ssp_mode = 0x00; - hci_inquiry_cache_update(hdev, &data, false); + + name_known = hci_inquiry_cache_update(hdev, &data, false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, 1, NULL); + info->dev_class, 0, !name_known, NULL); } hci_dev_unlock(hdev); @@ -2551,6 +2554,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct { struct inquiry_data data; int num_rsp = *((__u8 *) skb->data); + bool name_known; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); @@ -2572,10 +2576,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - hci_inquiry_cache_update(hdev, &data, false); + + name_known = hci_inquiry_cache_update(hdev, &data, + false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - 1, NULL); + !name_known, NULL); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2589,10 +2595,11 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - hci_inquiry_cache_update(hdev, &data, false); + name_known = hci_inquiry_cache_update(hdev, &data, + false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - 1, NULL); + !name_known, NULL); } } @@ -2766,7 +2773,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct else name_known = true; - hci_inquiry_cache_update(hdev, &data, name_known); + name_known = hci_inquiry_cache_update(hdev, &data, name_known); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, !name_known, info->data); -- cgit v1.2.3-70-g09d2 From 4663262c294c71aa1139616ae7f24dd345a69c15 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Jan 2012 16:06:08 +0200 Subject: Bluetooth: Flush inquiry cache when starting mgmt triggered inquiry For the remote name state tracking for the management interface to work the cache needs to be flushed whenever inquiry is started. The hci_do_inquiry function is only used by the management interface so by having the flushing done from it ensures that old ioctl based functionality isn't affected. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 162176151db..5dbfb276edf 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2611,6 +2611,8 @@ int hci_do_inquiry(struct hci_dev *hdev, u8 length) if (test_bit(HCI_INQUIRY, &hdev->flags)) return -EINPROGRESS; + inquiry_cache_flush(hdev); + memset(&cp, 0, sizeof(cp)); memcpy(&cp.lap, lap, sizeof(cp.lap)); cp.length = length; -- cgit v1.2.3-70-g09d2 From 30883512be0839349d29c7b0bc31016e0498cf8c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 14:16:21 +0200 Subject: Bluetooth: Rename hdev->inq_cache to hdev->discovery This struct is used for not just inquiry caching but also for general device discovery state tracking so it's better to rename it to something more appropriate. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 16 ++++++++-------- net/bluetooth/hci_core.c | 12 ++++++------ net/bluetooth/hci_sysfs.c | 2 +- net/bluetooth/mgmt.c | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 236f7f0e596..5a566fd5e2a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -56,7 +56,7 @@ struct inquiry_entry { struct inquiry_data data; }; -struct inquiry_cache { +struct discovery_state { struct list_head all; /* All devices found during inquiry */ struct list_head unknown; /* Name state not known */ struct list_head resolve; /* Name needs to be resolved */ @@ -226,7 +226,7 @@ struct hci_dev { struct list_head mgmt_pending; - struct inquiry_cache inq_cache; + struct discovery_state discovery; struct hci_conn_hash conn_hash; struct list_head blacklist; @@ -357,21 +357,21 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); #define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ #define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */ -static inline void inquiry_cache_init(struct hci_dev *hdev) +static inline void discovery_init(struct hci_dev *hdev) { - INIT_LIST_HEAD(&hdev->inq_cache.all); - INIT_LIST_HEAD(&hdev->inq_cache.unknown); - INIT_LIST_HEAD(&hdev->inq_cache.resolve); + INIT_LIST_HEAD(&hdev->discovery.all); + INIT_LIST_HEAD(&hdev->discovery.unknown); + INIT_LIST_HEAD(&hdev->discovery.resolve); } static inline int inquiry_cache_empty(struct hci_dev *hdev) { - return list_empty(&hdev->inq_cache.all); + return list_empty(&hdev->discovery.all); } static inline long inquiry_cache_age(struct hci_dev *hdev) { - struct inquiry_cache *c = &hdev->inq_cache; + struct discovery_state *c = &hdev->discovery; return jiffies - c->timestamp; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5dbfb276edf..55509b0a810 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -357,7 +357,7 @@ struct hci_dev *hci_dev_get(int index) /* ---- Inquiry support ---- */ static void inquiry_cache_flush(struct hci_dev *hdev) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *p, *n; list_for_each_entry_safe(p, n, &cache->all, all) { @@ -371,7 +371,7 @@ static void inquiry_cache_flush(struct hci_dev *hdev) struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; BT_DBG("cache %p, %s", cache, batostr(bdaddr)); @@ -387,7 +387,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, bdaddr_t *bdaddr) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; BT_DBG("cache %p, %s", cache, batostr(bdaddr)); @@ -403,7 +403,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); @@ -445,7 +445,7 @@ update: static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_info *info = (struct inquiry_info *) buf; struct inquiry_entry *e; int copied = 0; @@ -1546,7 +1546,7 @@ int hci_register_dev(struct hci_dev *hdev) init_waitqueue_head(&hdev->req_wait_q); mutex_init(&hdev->req_lock); - inquiry_cache_init(hdev); + discovery_init(hdev); hci_conn_hash_init(hdev); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3600d78c2f2..74b49e330a1 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -383,7 +383,7 @@ static struct device_type bt_host = { static int inquiry_cache_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; hci_dev_lock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 39775119585..894f11bc571 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2000,7 +2000,7 @@ static int confirm_name(struct sock *sk, u16 index, unsigned char *data, list_del(&e->list); } else { e->name_state = NAME_NEEDED; - list_move(&e->list, &hdev->inq_cache.resolve); + list_move(&e->list, &hdev->discovery.resolve); } err = 0; -- cgit v1.2.3-70-g09d2 From ff9ef5787046c3fd20cf9f7ca1cd70260c1eedb9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 14:23:45 +0200 Subject: Bluetooth: Add discovery state tracking This patch adds proper state tracking to the device discovery process. This makes it possible to return appropriate errors when trying to stop a non-active discovery or start discovery when it is already ongoing. Once name resolving is implemented this also makes it possible to know what the right action to do is when a remote name lookup is cancelled. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 +++++++++ net/bluetooth/hci_core.c | 25 +++++++++++++++++++++++++ net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5a566fd5e2a..2f19de4770b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -57,6 +57,12 @@ struct inquiry_entry { }; struct discovery_state { + enum { + DISCOVERY_STOPPED, + DISCOVERY_STARTING, + DISCOVERY_ACTIVE, + DISCOVERY_STOPPING, + } state; struct list_head all; /* All devices found during inquiry */ struct list_head unknown; /* Name state not known */ struct list_head resolve; /* Name needs to be resolved */ @@ -359,11 +365,14 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); static inline void discovery_init(struct hci_dev *hdev) { + hdev->discovery.state = DISCOVERY_STOPPED; INIT_LIST_HEAD(&hdev->discovery.all); INIT_LIST_HEAD(&hdev->discovery.unknown); INIT_LIST_HEAD(&hdev->discovery.resolve); } +void hci_discovery_set_state(struct hci_dev *hdev, int state); + static inline int inquiry_cache_empty(struct hci_dev *hdev) { return list_empty(&hdev->discovery.all); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 55509b0a810..b6871923060 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -355,6 +355,30 @@ struct hci_dev *hci_dev_get(int index) } /* ---- Inquiry support ---- */ + +void hci_discovery_set_state(struct hci_dev *hdev, int state) +{ + BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); + + if (hdev->discovery.state == state) + return; + + switch (state) { + case DISCOVERY_STOPPED: + mgmt_discovering(hdev, 0); + break; + case DISCOVERY_STARTING: + break; + case DISCOVERY_ACTIVE: + mgmt_discovering(hdev, 1); + break; + case DISCOVERY_STOPPING: + break; + } + + hdev->discovery.state = state; +} + static void inquiry_cache_flush(struct hci_dev *hdev) { struct discovery_state *cache = &hdev->discovery; @@ -367,6 +391,7 @@ static void inquiry_cache_flush(struct hci_dev *hdev) INIT_LIST_HEAD(&cache->unknown); INIT_LIST_HEAD(&cache->resolve); + cache->state = DISCOVERY_STOPPED; } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d4d20df9fbb..43d69569a0d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -65,7 +65,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - mgmt_discovering(hdev, 0); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_dev_unlock(hdev); hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); @@ -1119,7 +1119,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) set_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - mgmt_discovering(hdev, 1); + hci_discovery_set_state(hdev, DISCOVERY_ACTIVE); hci_dev_unlock(hdev); } @@ -1507,7 +1507,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff return; hci_dev_lock(hdev); - mgmt_discovering(hdev, 0); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 894f11bc571..590966ddfa6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1918,6 +1918,12 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } + if (hdev->discovery.state != DISCOVERY_STOPPED) { + err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, + MGMT_STATUS_BUSY); + goto failed; + } + cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0); if (!cmd) { err = -ENOMEM; @@ -1927,6 +1933,8 @@ static int start_discovery(struct sock *sk, u16 index, err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); if (err < 0) mgmt_pending_remove(cmd); + else + hci_discovery_set_state(hdev, DISCOVERY_STARTING); failed: hci_dev_unlock(hdev); @@ -1950,6 +1958,12 @@ static int stop_discovery(struct sock *sk, u16 index) hci_dev_lock(hdev); + if (hdev->discovery.state != DISCOVERY_ACTIVE) { + err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_REJECTED); + goto failed; + } + cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); if (!cmd) { err = -ENOMEM; @@ -1959,6 +1973,8 @@ static int stop_discovery(struct sock *sk, u16 index) err = hci_cancel_inquiry(hdev); if (err < 0) mgmt_pending_remove(cmd); + else + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); failed: hci_dev_unlock(hdev); -- cgit v1.2.3-70-g09d2 From 30dc78e1a2bcbe2a0fca7aa44dfded4bb0db6148 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 15:44:20 +0200 Subject: Bluetooth: Add name resolving support for mgmt based discovery This patch adds the necessary logic to perform name lookups after inquiry completes. This is done by checking for entries in the resolve list after each inquiry complete and remote name complete HCI event. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 8 +++- net/bluetooth/hci_core.c | 34 ++++++++++++++++- net/bluetooth/hci_event.c | 81 ++++++++++++++++++++++++++++++++++++++-- net/bluetooth/mgmt.c | 37 +++++++++++++++--- 4 files changed, 149 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2f19de4770b..a8680da7f40 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -60,7 +60,8 @@ struct discovery_state { enum { DISCOVERY_STOPPED, DISCOVERY_STARTING, - DISCOVERY_ACTIVE, + DISCOVERY_INQUIRY, + DISCOVERY_RESOLVING, DISCOVERY_STOPPING, } state; struct list_head all; /* All devices found during inquiry */ @@ -371,6 +372,8 @@ static inline void discovery_init(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->discovery.resolve); } +bool hci_discovery_active(struct hci_dev *hdev); + void hci_discovery_set_state(struct hci_dev *hdev, int state); static inline int inquiry_cache_empty(struct hci_dev *hdev) @@ -393,6 +396,9 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, bdaddr_t *bdaddr); +struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, + bdaddr_t *bdaddr, + int state); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b6871923060..546a4294147 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -356,6 +356,17 @@ struct hci_dev *hci_dev_get(int index) /* ---- Inquiry support ---- */ +bool hci_discovery_active(struct hci_dev *hdev) +{ + struct discovery_state *discov = &hdev->discovery; + + if (discov->state == DISCOVERY_INQUIRY || + discov->state == DISCOVERY_RESOLVING) + return true; + + return false; +} + void hci_discovery_set_state(struct hci_dev *hdev, int state) { BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); @@ -369,9 +380,11 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) break; case DISCOVERY_STARTING: break; - case DISCOVERY_ACTIVE: + case DISCOVERY_INQUIRY: mgmt_discovering(hdev, 1); break; + case DISCOVERY_RESOLVING: + break; case DISCOVERY_STOPPING: break; } @@ -425,6 +438,25 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, return NULL; } +struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, + bdaddr_t *bdaddr, + int state) +{ + struct discovery_state *cache = &hdev->discovery; + struct inquiry_entry *e; + + BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state); + + list_for_each_entry(e, &cache->resolve, list) { + if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state) + return e; + if (!bacmp(&e->data.bdaddr, bdaddr)) + return e; + } + + return NULL; +} + bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 43d69569a0d..089dff80ccb 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1119,7 +1119,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) set_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_ACTIVE); + hci_discovery_set_state(hdev, DISCOVERY_INQUIRY); hci_dev_unlock(hdev); } @@ -1271,6 +1271,50 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, return 1; } +static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e) +{ + struct hci_cp_remote_name_req cp; + + memset(&cp, 0, sizeof(cp)); + + bacpy(&cp.bdaddr, &e->data.bdaddr); + cp.pscan_rep_mode = e->data.pscan_rep_mode; + cp.pscan_mode = e->data.pscan_mode; + cp.clock_offset = e->data.clock_offset; + + return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); +} + +static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct discovery_state *discov = &hdev->discovery; + struct inquiry_entry *e; + + if (discov->state == DISCOVERY_STOPPING) + goto discov_complete; + + if (discov->state != DISCOVERY_RESOLVING) + return; + + e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING); + if (e) { + e->name_state = NAME_KNOWN; + list_del(&e->list); + } + + if (list_empty(&discov->resolve)) + goto discov_complete; + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); + if (hci_resolve_name(hdev, e) == 0) { + e->name_state = NAME_PENDING; + return; + } + +discov_complete: + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); +} + static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) { struct hci_cp_remote_name_req *cp; @@ -1289,6 +1333,9 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); + if (test_bit(HCI_MGMT, &hdev->flags)) + hci_resolve_next_name(hdev, &cp->bdaddr); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); if (!conn) goto unlock; @@ -1496,6 +1543,8 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); + struct discovery_state *discov = &hdev->discovery; + struct inquiry_entry *e; BT_DBG("%s status %d", hdev->name, status); @@ -1506,8 +1555,28 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) return; + if (!test_bit(HCI_MGMT, &hdev->flags)) + return; + hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + + if (discov->state != DISCOVERY_INQUIRY) + goto unlock; + + if (list_empty(&discov->resolve)) { + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + goto unlock; + } + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); + if (e && hci_resolve_name(hdev, e) == 0) { + e->name_state = NAME_PENDING; + hci_discovery_set_state(hdev, DISCOVERY_RESOLVING); + } else { + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + } + +unlock: hci_dev_unlock(hdev); } @@ -1807,8 +1876,12 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); - if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags)) - mgmt_remote_name(hdev, &ev->bdaddr, ev->name); + if (test_bit(HCI_MGMT, &hdev->flags)) { + if (ev->status == 0) + mgmt_remote_name(hdev, &ev->bdaddr, ev->name); + + hci_resolve_next_name(hdev, &ev->bdaddr); + } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (!conn) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 590966ddfa6..295cfc8a307 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1947,6 +1947,8 @@ static int stop_discovery(struct sock *sk, u16 index) { struct hci_dev *hdev; struct pending_cmd *cmd; + struct hci_cp_remote_name_req_cancel cp; + struct inquiry_entry *e; int err; BT_DBG("hci%u", index); @@ -1958,25 +1960,44 @@ static int stop_discovery(struct sock *sk, u16 index) hci_dev_lock(hdev); - if (hdev->discovery.state != DISCOVERY_ACTIVE) { + if (!hci_discovery_active(hdev)) { err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_REJECTED); - goto failed; + goto unlock; } cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); if (!cmd) { err = -ENOMEM; - goto failed; + goto unlock; + } + + if (hdev->discovery.state == DISCOVERY_INQUIRY) { + err = hci_cancel_inquiry(hdev); + if (err < 0) + mgmt_pending_remove(cmd); + else + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); + goto unlock; + } + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); + if (!e) { + mgmt_pending_remove(cmd); + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + goto unlock; } - err = hci_cancel_inquiry(hdev); + bacpy(&cp.bdaddr, &e->data.bdaddr); + err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, + sizeof(cp), &cp); if (err < 0) mgmt_pending_remove(cmd); else hci_discovery_set_state(hdev, DISCOVERY_STOPPING); -failed: +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2004,6 +2025,12 @@ static int confirm_name(struct sock *sk, u16 index, unsigned char *data, hci_dev_lock(hdev); + if (!hci_discovery_active(hdev)) { + err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_FAILED); + goto failed; + } + e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr); if (!e) { err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, -- cgit v1.2.3-70-g09d2 From 25e89e99b4a54a2cb6e27b4675cd71a3d8a9b3fc Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 4 Jan 2012 12:41:58 +0200 Subject: Bluetooth: Process num completed data blocks event Adds support for Number Of Completed Data Blocks Event. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 13 +++++++++++ net/bluetooth/hci_event.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ce5133b2244..6a9d316fb97 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1168,6 +1168,19 @@ struct hci_ev_le_meta { __u8 subevent; } __packed; +#define HCI_EV_NUM_COMP_BLOCKS 0x48 +struct hci_comp_blocks_info { + __le16 handle; + __le16 pkts; + __le16 blocks; +} __packed; + +struct hci_ev_num_comp_blocks { + __le16 num_blocks; + __u8 num_hndl; + struct hci_comp_blocks_info handles[0]; +} __packed; + /* Low energy meta events */ #define HCI_EV_LE_CONN_COMPLETE 0x01 struct hci_ev_le_conn_complete { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 089dff80ccb..0466ed9c1b4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2408,6 +2408,56 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s queue_work(hdev->workqueue, &hdev->tx_work); } +static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_num_comp_blocks *ev = (void *) skb->data; + int i; + + if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) { + BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode); + return; + } + + if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) + + ev->num_hndl * sizeof(struct hci_comp_blocks_info)) { + BT_DBG("%s bad parameters", hdev->name); + return; + } + + BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks, + ev->num_hndl); + + for (i = 0; i < ev->num_hndl; i++) { + struct hci_comp_blocks_info *info = &ev->handles[i]; + struct hci_conn *conn; + __u16 handle, block_count; + + handle = __le16_to_cpu(info->handle); + block_count = __le16_to_cpu(info->blocks); + + conn = hci_conn_hash_lookup_handle(hdev, handle); + if (!conn) + continue; + + conn->sent -= block_count; + + switch (conn->type) { + case ACL_LINK: + hdev->block_cnt += block_count; + if (hdev->block_cnt > hdev->num_blocks) + hdev->block_cnt = hdev->num_blocks; + break; + + default: + BT_ERR("Unknown type %d conn %p", conn->type, conn); + break; + } + } + + queue_work(hdev->workqueue, &hdev->tx_work); +} + static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_mode_change *ev = (void *) skb->data; @@ -3386,6 +3436,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_remote_oob_data_request_evt(hdev, skb); break; + case HCI_EV_NUM_COMP_BLOCKS: + hci_num_comp_blocks_evt(hdev, skb); + break; + default: BT_DBG("%s event 0x%x", hdev->name, event); break; -- cgit v1.2.3-70-g09d2 From 6423cf3a1862d5b162aaa13543bf69216a9f6ac0 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 4 Jan 2012 12:10:41 +0100 Subject: Bluetooth: Fix sk_sndtimeo initialization for L2CAP socket sk_sndtime value should be specified in jiffies thus initial value needs to be converted from miliseconds. Otherwise this timeout is unreliable when CONFIG_HZ is not set to 1000. Signed-off-by: Andrzej Kaczmarek Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c61d967012b..c57027f7606 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1002,7 +1002,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p INIT_LIST_HEAD(&bt_sk(sk)->accept_q); sk->sk_destruct = l2cap_sock_destruct; - sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; + sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); sock_reset_flag(sk, SOCK_ZAPPED); -- cgit v1.2.3-70-g09d2 From b83ddfe2ac670392c27a799371bb1a7e14a7e3d3 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 4 Jan 2012 12:10:42 +0100 Subject: Bluetooth: l2cap_set_timer needs jiffies as timeout value After moving L2CAP timers to workqueues l2cap_set_timer expects timeout value to be specified in jiffies but constants defined in miliseconds are used. This makes timeouts unreliable when CONFIG_HZ is not set to 1000. __set_chan_timer macro still uses jiffies as input to avoid multiple conversions from/to jiffies for sk_sndtimeo value which is already specified in jiffies. Signed-off-by: Andrzej Kaczmarek Ackec-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 6 +++--- net/bluetooth/l2cap_core.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 68f58915069..ab8f7d83079 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -626,13 +626,13 @@ static inline void l2cap_clear_timer(struct l2cap_chan *chan, #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ - L2CAP_DEFAULT_RETRANS_TO); + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ - L2CAP_DEFAULT_MONITOR_TO); + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ - L2CAP_DEFAULT_ACK_TO); + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index faf0b11ac1d..e35ff4cd33c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2970,7 +2970,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_err = ECONNRESET; - __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -4478,7 +4479,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_ENC_TIMEOUT)); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); } else { @@ -4546,7 +4548,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) L2CAP_CONN_REQ, sizeof(req), &req); } else { __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); } } else if (chan->state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -4566,7 +4569,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } } else { l2cap_state_change(chan, BT_DISCONN); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); res = L2CAP_CR_SEC_BLOCK; stat = L2CAP_CS_NO_INFO; } -- cgit v1.2.3-70-g09d2 From cc48dc0a996af6ae20e91c551d71e7f72768860f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 4 Jan 2012 16:42:26 +0200 Subject: Bluetooth: Remove magic number from ACL TO Adds HCI_ACL_TX_TIMEOUT and clear conversion from msec to jiffies Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6a9d316fb97..4202c9cb497 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -130,6 +130,7 @@ enum { #define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ #define HCI_CMD_TIMEOUT (1000) /* 1 seconds */ +#define HCI_ACL_TX_TIMEOUT (45000) /* 45 seconds */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 546a4294147..f84935e5cba 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2350,7 +2350,8 @@ static inline void hci_sched_acl(struct hci_dev *hdev) if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ - if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45)) + if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + + msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) hci_link_tx_to(hdev, ACL_LINK); } -- cgit v1.2.3-70-g09d2 From 010666a126fce7b9ecdda7209c558db21d771c56 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:07 +0100 Subject: Bluetooth: Make hci-destruct callback optional Several drivers already provide an empty callback so we can actually make this optional and then remove all those empty callbacks in the drivers. This callback isn't needed at all by most drivers as they can remove their allocated structures on device disconnect and not on hci destruction. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 6 ++++-- net/bluetooth/hci_core.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 25a6c3fd7d1..86c74cc563f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -595,8 +595,10 @@ static inline void hci_conn_put(struct hci_conn *conn) /* ----- HCI Devices ----- */ static inline void __hci_dev_put(struct hci_dev *d) { - if (atomic_dec_and_test(&d->refcnt)) - d->destruct(d); + if (atomic_dec_and_test(&d->refcnt)) { + if (d->destruct) + d->destruct(d); + } } /* diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f84935e5cba..f23e32a645c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1551,7 +1551,7 @@ int hci_register_dev(struct hci_dev *hdev) BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name, hdev->bus, hdev->owner); - if (!hdev->open || !hdev->close || !hdev->destruct) + if (!hdev->open || !hdev->close) return -EINVAL; /* Do not allow HCI_AMP devices to register at index 0, -- cgit v1.2.3-70-g09d2 From 46e06531a5ae13c66f774d3cb1ad78385618a5a2 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:21 +0100 Subject: Bluetooth: Correctly acquire module ref We provide a device-object to other subsystems and we provide our own release-function. Therefore, the device-object must own a reference to our module, otherwise the release-function may get deleted before the device-object does. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 74b49e330a1..ec03ee2b301 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -372,6 +372,7 @@ static void bt_host_release(struct device *dev) { void *data = dev_get_drvdata(dev); kfree(data); + module_put(THIS_MODULE); } static struct device_type bt_host = { @@ -523,6 +524,7 @@ void hci_init_sysfs(struct hci_dev *hdev) dev->type = &bt_host; dev->class = bt_class; + __module_get(THIS_MODULE); dev_set_drvdata(dev, hdev); device_initialize(dev); } -- cgit v1.2.3-70-g09d2 From e9b9cfa1575e37cb2dbb5534aeaaa16814228887 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:22 +0100 Subject: Bluetooth: Remove HCI-owner field After unregistering an hci_dev object a bluetooth driver does not have any callbacks in the hci_dev structure left over. Therefore, there is no need to keep a reference to the module. Previously, we needed this to protect the hci-destruct callback. However, this callback is no longer available so we do not need this owner field, anymore. Drivers now call hci_unregister_dev() and they are done with the object. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/bfusb.c | 2 -- drivers/bluetooth/bluecard_cs.c | 2 -- drivers/bluetooth/bpa10x.c | 2 -- drivers/bluetooth/bt3c_cs.c | 2 -- drivers/bluetooth/btmrvl_main.c | 1 - drivers/bluetooth/btsdio.c | 2 -- drivers/bluetooth/btuart_cs.c | 2 -- drivers/bluetooth/btusb.c | 2 -- drivers/bluetooth/btwilink.c | 1 - drivers/bluetooth/dtl1_cs.c | 2 -- drivers/bluetooth/hci_ldisc.c | 2 -- drivers/bluetooth/hci_vhci.c | 2 -- include/net/bluetooth/hci_core.h | 13 ++----------- net/bluetooth/hci_core.c | 3 +-- 14 files changed, 3 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index e99ce89e1ca..c7d6ff0ffcf 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -705,8 +705,6 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i hdev->send = bfusb_send_frame; hdev->ioctl = bfusb_ioctl; - hdev->owner = THIS_MODULE; - if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 5cb325a1374..6b1261f9deb 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -738,8 +738,6 @@ static int bluecard_open(bluecard_info_t *info) hdev->send = bluecard_hci_send_frame; hdev->ioctl = bluecard_hci_ioctl; - hdev->owner = THIS_MODULE; - id = inb(iobase + 0x30); if ((id & 0x0f) == 0x02) diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 29cd11d401e..9d635148104 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -470,8 +470,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * hdev->flush = bpa10x_flush; hdev->send = bpa10x_send_frame; - hdev->owner = THIS_MODULE; - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); err = hci_register_dev(hdev); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index e74334dfc77..0e304cb4bde 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -584,8 +584,6 @@ static int bt3c_open(bt3c_info_t *info) hdev->send = bt3c_hci_send_frame; hdev->ioctl = bt3c_hci_ioctl; - hdev->owner = THIS_MODULE; - /* Load firmware */ err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev); if (err < 0) { diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 995cf43f4bd..66b58fd09fb 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -550,7 +550,6 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) hdev->flush = btmrvl_flush; hdev->send = btmrvl_send_frame; hdev->ioctl = btmrvl_ioctl; - hdev->owner = THIS_MODULE; btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index d38945cc9f0..2d6e4ed1637 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -337,8 +337,6 @@ static int btsdio_probe(struct sdio_func *func, hdev->flush = btsdio_flush; hdev->send = btsdio_send_frame; - hdev->owner = THIS_MODULE; - err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 84e02f1a45b..80ad2b9b352 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -502,8 +502,6 @@ static int btuart_open(btuart_info_t *info) hdev->send = btuart_hci_send_frame; hdev->ioctl = btuart_hci_ioctl; - hdev->owner = THIS_MODULE; - spin_lock_irqsave(&(info->lock), flags); /* Reset UART */ diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 44b5e736ddc..a36888a9c20 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -997,8 +997,6 @@ static int btusb_probe(struct usb_interface *intf, hdev->send = btusb_send_frame; hdev->notify = btusb_notify; - hdev->owner = THIS_MODULE; - /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index da9cf6a6e8a..b81b32e4fa1 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -317,7 +317,6 @@ static int bt_ti_probe(struct platform_device *pdev) hdev->close = ti_st_close; hdev->flush = NULL; hdev->send = ti_st_send_frame; - hdev->owner = THIS_MODULE; err = hci_register_dev(hdev); if (err < 0) { diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index aae40caaa18..295cf1b4a05 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -484,8 +484,6 @@ static int dtl1_open(dtl1_info_t *info) hdev->send = dtl1_hci_send_frame; hdev->ioctl = dtl1_hci_ioctl; - hdev->owner = THIS_MODULE; - spin_lock_irqsave(&(info->lock), flags); /* Reset UART */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 5ea49df3462..459ff0ba5a4 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -392,8 +392,6 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->send = hci_uart_send_frame; hdev->parent = hu->tty->dev; - hdev->owner = THIS_MODULE; - if (!reset) set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 44a801292d6..5f305c131a0 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -244,8 +244,6 @@ static int vhci_open(struct inode *inode, struct file *file) hdev->flush = vhci_flush; hdev->send = vhci_send_frame; - hdev->owner = THIS_MODULE; - if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); kfree(data); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 935aca8783c..99984688ccd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -262,8 +262,6 @@ struct hci_dev { struct rfkill *rfkill; - struct module *owner; - unsigned long dev_flags; int (*open)(struct hci_dev *hdev); @@ -601,11 +599,7 @@ static inline void __hci_dev_put(struct hci_dev *d) * hci_dev_put and hci_dev_hold are macros to avoid dragging all the * overhead of all the modular infrastructure into this header. */ -#define hci_dev_put(d) \ -do { \ - __hci_dev_put(d); \ - module_put(d->owner); \ -} while (0) +#define hci_dev_put(d) __hci_dev_put(d) static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) { @@ -613,10 +607,7 @@ static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) return d; } -#define hci_dev_hold(d) \ -({ \ - try_module_get(d->owner) ? __hci_dev_hold(d) : NULL; \ -}) +#define hci_dev_hold(d) __hci_dev_hold(d) #define hci_dev_lock(d) mutex_lock(&d->lock) #define hci_dev_unlock(d) mutex_unlock(&d->lock) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f23e32a645c..58392a6b48b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1548,8 +1548,7 @@ int hci_register_dev(struct hci_dev *hdev) struct list_head *head = &hci_dev_list, *p; int i, id, error; - BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name, - hdev->bus, hdev->owner); + BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); if (!hdev->open || !hdev->close) return -EINVAL; -- cgit v1.2.3-70-g09d2 From 4c724c7135ca2b407bd318b4267456a7b5723825 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:23 +0100 Subject: Bluetooth: Correctly take hci_dev->dev refcount The hci_dev->dev device structure has an internal refcount. This refcount is used to protect the whole hci_dev object. However, we currently do not use it. Therefore, if someone calls hci_free_dev() we currently immediately destroy the hci_dev object because we never took the device refcount. This even happens if the hci_dev->refcnt is not 0. In fact, the hci_dev->refcnt is totally useless in its current state. Therefore, we simply remove hci_dev->refcnt and instead use hci_dev->dev refcnt. This fixes all the symptoms and also correctly integrates the device structure into our bluetooth bus system. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 5 ++--- net/bluetooth/hci_core.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 99984688ccd..4ccf3749a9a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -129,7 +129,6 @@ struct adv_entry { struct hci_dev { struct list_head list; struct mutex lock; - atomic_t refcnt; char name[8]; unsigned long flags; @@ -592,7 +591,7 @@ static inline void hci_conn_put(struct hci_conn *conn) /* ----- HCI Devices ----- */ static inline void __hci_dev_put(struct hci_dev *d) { - atomic_dec(&d->refcnt); + put_device(&d->dev); } /* @@ -603,7 +602,7 @@ static inline void __hci_dev_put(struct hci_dev *d) static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) { - atomic_inc(&d->refcnt); + get_device(&d->dev); return d; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 58392a6b48b..f5fba65a9e5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1571,7 +1571,6 @@ int hci_register_dev(struct hci_dev *hdev) hdev->id = id; list_add_tail(&hdev->list, head); - atomic_set(&hdev->refcnt, 1); mutex_init(&hdev->lock); hdev->flags = 0; @@ -1655,6 +1654,7 @@ int hci_register_dev(struct hci_dev *hdev) schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); + __hci_dev_hold(hdev); return id; -- cgit v1.2.3-70-g09d2 From dc946bd86f725c42c3ab1caf9966d29f5b364fea Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:24 +0100 Subject: Bluetooth: Remove __hci_dev_put/hold Since we remove the owner field of hci_dev hci_dev_put and __hci_dev_put do the same so we can merge them into one function. Same for hci_dev_hold and __hci_dev_hold. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 4 ++-- include/net/bluetooth/hci_core.h | 12 ++---------- net/bluetooth/hci_core.c | 4 ++-- 3 files changed, 6 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a36888a9c20..d7664ffc518 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1079,7 +1079,7 @@ static void btusb_disconnect(struct usb_interface *intf) hdev = data->hdev; - __hci_dev_hold(hdev); + hci_dev_hold(hdev); usb_set_intfdata(data->intf, NULL); @@ -1093,7 +1093,7 @@ static void btusb_disconnect(struct usb_interface *intf) else if (data->isoc) usb_driver_release_interface(&btusb_driver, data->isoc); - __hci_dev_put(hdev); + hci_dev_put(hdev); hci_free_dev(hdev); kfree(data); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4ccf3749a9a..f9c88251fe1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -589,25 +589,17 @@ static inline void hci_conn_put(struct hci_conn *conn) } /* ----- HCI Devices ----- */ -static inline void __hci_dev_put(struct hci_dev *d) +static inline void hci_dev_put(struct hci_dev *d) { put_device(&d->dev); } -/* - * hci_dev_put and hci_dev_hold are macros to avoid dragging all the - * overhead of all the modular infrastructure into this header. - */ -#define hci_dev_put(d) __hci_dev_put(d) - -static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) +static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) { get_device(&d->dev); return d; } -#define hci_dev_hold(d) __hci_dev_hold(d) - #define hci_dev_lock(d) mutex_lock(&d->lock) #define hci_dev_unlock(d) mutex_unlock(&d->lock) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f5fba65a9e5..a3113f8c1f9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1654,7 +1654,7 @@ int hci_register_dev(struct hci_dev *hdev) schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); - __hci_dev_hold(hdev); + hci_dev_hold(hdev); return id; @@ -1717,7 +1717,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); - __hci_dev_put(hdev); + hci_dev_put(hdev); } EXPORT_SYMBOL(hci_unregister_dev); -- cgit v1.2.3-70-g09d2 From cbe8fed490601862310f035b9973509b8634998e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 8 Jan 2012 22:51:16 +0200 Subject: Bluetooth: Remove bogus inline declaration from l2cap_chan_connect As reported by Dan Carpenter this function causes a Sparse warning and shouldn't be declared inline: include/net/bluetooth/l2cap.h:837:30 error: marked inline, but without a definition" Reported-by: Dan Carpenter Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ab8f7d83079..26486e182f5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -834,7 +834,7 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); -inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e35ff4cd33c..dcccae04ae0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1120,7 +1120,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; -- cgit v1.2.3-70-g09d2 From a8b2d5c2cfe1c6398e3fdd4372c4ae7f74fb4493 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 8 Jan 2012 23:11:15 +0200 Subject: Bluetooth: Move mgmt related flags from hdev->flags to hdev->dev_flags There's no point in exposing these to user-space (which is what happens to everything in hdev->flags) so move them to dev_flags instead. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 16 ++++++++-------- net/bluetooth/hci_core.c | 30 +++++++++++++++--------------- net/bluetooth/hci_event.c | 44 ++++++++++++++++++++++---------------------- net/bluetooth/mgmt.c | 30 +++++++++++++++--------------- net/bluetooth/smp.c | 2 +- 5 files changed, 61 insertions(+), 61 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4202c9cb497..3ee39ed9c29 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -77,14 +77,6 @@ enum { HCI_RAW, - HCI_SETUP, - HCI_AUTO_OFF, - HCI_MGMT, - HCI_PAIRABLE, - HCI_SERVICE_CACHE, - HCI_LINK_KEYS, - HCI_DEBUG_KEYS, - HCI_RESET, }; @@ -93,6 +85,14 @@ enum { * states from the controller. */ enum { + HCI_SETUP, + HCI_AUTO_OFF, + HCI_MGMT, + HCI_PAIRABLE, + HCI_SERVICE_CACHE, + HCI_LINK_KEYS, + HCI_DEBUG_KEYS, + HCI_LE_SCAN, }; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a3113f8c1f9..3acb23cf6ee 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -668,7 +668,7 @@ int hci_dev_open(__u16 dev) hci_dev_hold(hdev); set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); - if (!test_bit(HCI_SETUP, &hdev->flags)) { + if (!test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_powered(hdev, 1); hci_dev_unlock(hdev); @@ -722,10 +722,10 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->discov_timeout = 0; } - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work(&hdev->power_off); - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) cancel_delayed_work(&hdev->service_cache); hci_dev_lock(hdev); @@ -947,11 +947,11 @@ int hci_get_dev_list(void __user *arg) read_lock(&hci_dev_list_lock); list_for_each_entry(hdev, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work(&hdev->power_off); - if (!test_bit(HCI_MGMT, &hdev->flags)) - set_bit(HCI_PAIRABLE, &hdev->flags); + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); (dr + n)->dev_id = hdev->id; (dr + n)->dev_opt = hdev->flags; @@ -983,11 +983,11 @@ int hci_get_dev_info(void __user *arg) if (!hdev) return -ENODEV; - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work_sync(&hdev->power_off); - if (!test_bit(HCI_MGMT, &hdev->flags)) - set_bit(HCI_PAIRABLE, &hdev->flags); + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; @@ -1067,11 +1067,11 @@ static void hci_power_on(struct work_struct *work) if (hci_dev_open(hdev->id) < 0) return; - if (test_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) schedule_delayed_work(&hdev->power_off, msecs_to_jiffies(AUTO_OFF_TIMEOUT)); - if (test_and_clear_bit(HCI_SETUP, &hdev->flags)) + if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) mgmt_index_added(hdev); } @@ -1082,7 +1082,7 @@ static void hci_power_off(struct work_struct *work) BT_DBG("%s", hdev->name); - clear_bit(HCI_AUTO_OFF, &hdev->flags); + clear_bit(HCI_AUTO_OFF, &hdev->dev_flags); hci_dev_close(hdev->id); } @@ -1649,8 +1649,8 @@ int hci_register_dev(struct hci_dev *hdev) } } - set_bit(HCI_AUTO_OFF, &hdev->flags); - set_bit(HCI_SETUP, &hdev->flags); + set_bit(HCI_AUTO_OFF, &hdev->dev_flags); + set_bit(HCI_SETUP, &hdev->dev_flags); schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); @@ -1686,7 +1686,7 @@ void hci_unregister_dev(struct hci_dev *hdev) kfree_skb(hdev->reassembly[i]); if (!test_bit(HCI_INIT, &hdev->flags) && - !test_bit(HCI_SETUP, &hdev->flags)) { + !test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_index_removed(hdev); hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0466ed9c1b4..2d39ede1f20 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -211,7 +211,7 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_set_local_name_complete(hdev, sent, status); if (status == 0) @@ -890,7 +890,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status); if (rp->status != 0) @@ -916,7 +916,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -951,7 +951,7 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -967,7 +967,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -982,7 +982,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -998,7 +998,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -1110,7 +1110,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) hci_req_complete(hdev, HCI_OP_INQUIRY, status); hci_conn_check_pending(hdev); hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_start_discovery_failed(hdev, status); hci_dev_unlock(hdev); return; @@ -1333,7 +1333,7 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) hci_resolve_next_name(hdev, &cp->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); @@ -1555,7 +1555,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) return; - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) return; hci_dev_lock(hdev); @@ -1876,7 +1876,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) { + if (test_bit(HCI_MGMT, &hdev->dev_flags)) { if (ev->status == 0) mgmt_remote_name(hdev, &ev->bdaddr, ev->name); @@ -2505,10 +2505,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff hci_conn_put(conn); } - if (!test_bit(HCI_PAIRABLE, &hdev->flags)) + if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags)) hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - else if (test_bit(HCI_MGMT, &hdev->flags)) { + else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { u8 secure; if (conn->pending_sec_level == BT_SECURITY_HIGH) @@ -2532,7 +2532,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s", hdev->name); - if (!test_bit(HCI_LINK_KEYS, &hdev->flags)) + if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags)) return; hci_dev_lock(hdev); @@ -2547,7 +2547,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s found key type %u for %s", hdev->name, key->type, batostr(&ev->bdaddr)); - if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && + if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) && key->type == HCI_LK_DEBUG_COMBINATION) { BT_DBG("%s ignoring debug key", hdev->name); goto not_found; @@ -2609,7 +2609,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff hci_conn_put(conn); } - if (test_bit(HCI_LINK_KEYS, &hdev->flags)) + if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags)) hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, ev->key_type, pin_len); @@ -2890,7 +2890,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.rssi = info->rssi; data.ssp_mode = 0x01; - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) name_known = eir_has_complete_name(info->data, sizeof(info->data)); else @@ -2939,10 +2939,10 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff hci_conn_hold(conn); - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; - if (test_bit(HCI_PAIRABLE, &hdev->flags) || + if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; @@ -3005,7 +3005,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); @@ -3071,7 +3071,7 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_request(hdev, &ev->bdaddr); hci_dev_unlock(hdev); @@ -3130,7 +3130,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; data = hci_find_remote_oob_data(hdev, &ev->bdaddr); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 295cfc8a307..3de1e909471 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -226,10 +226,10 @@ static int read_index_list(struct sock *sk) i = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags)) cancel_delayed_work(&d->power_off); - if (test_bit(HCI_SETUP, &d->flags)) + if (test_bit(HCI_SETUP, &d->dev_flags)) continue; put_unaligned_le16(d->id, &rp->index[i++]); @@ -285,7 +285,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_ISCAN, &hdev->flags)) settings |= MGMT_SETTING_DISCOVERABLE; - if (test_bit(HCI_PAIRABLE, &hdev->flags)) + if (test_bit(HCI_PAIRABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_PAIRABLE; if (!(hdev->features[4] & LMP_NO_BREDR)) @@ -419,7 +419,7 @@ static int update_eir(struct hci_dev *hdev) if (hdev->ssp_mode == 0) return 0; - if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return 0; memset(&cp, 0, sizeof(cp)); @@ -451,7 +451,7 @@ static int update_class(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return 0; cod[0] = hdev->minor_class; @@ -469,7 +469,7 @@ static void service_cache_off(struct work_struct *work) struct hci_dev *hdev = container_of(work, struct hci_dev, service_cache.work); - if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return; hci_dev_lock(hdev); @@ -482,10 +482,10 @@ static void service_cache_off(struct work_struct *work) static void mgmt_init_hdev(struct hci_dev *hdev) { - if (!test_and_set_bit(HCI_MGMT, &hdev->flags)) + if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); - if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) schedule_delayed_work(&hdev->service_cache, msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); } @@ -502,7 +502,7 @@ static int read_controller_info(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_INFO, MGMT_STATUS_INVALID_PARAMS); - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work_sync(&hdev->power_off); hci_dev_lock(hdev); @@ -851,9 +851,9 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, hci_dev_lock(hdev); if (cp->val) - set_bit(HCI_PAIRABLE, &hdev->flags); + set_bit(HCI_PAIRABLE, &hdev->dev_flags); else - clear_bit(HCI_PAIRABLE, &hdev->flags); + clear_bit(HCI_PAIRABLE, &hdev->dev_flags); err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); if (err < 0) @@ -1008,7 +1008,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, hdev->major_class = cp->major; hdev->minor_class = cp->minor; - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) { + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { hci_dev_unlock(hdev); cancel_delayed_work_sync(&hdev->service_cache); hci_dev_lock(hdev); @@ -1063,12 +1063,12 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, hci_link_keys_clear(hdev); - set_bit(HCI_LINK_KEYS, &hdev->flags); + set_bit(HCI_LINK_KEYS, &hdev->dev_flags); if (cp->debug_keys) - set_bit(HCI_DEBUG_KEYS, &hdev->flags); + set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); else - clear_bit(HCI_DEBUG_KEYS, &hdev->flags); + clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 32c47de3034..65a90242d99 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -217,7 +217,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, { u8 dist_keys = 0; - if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) { + if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { dist_keys = SMP_DIST_ENC_KEY; authreq |= SMP_AUTH_BONDING; } else { -- cgit v1.2.3-70-g09d2 From 44b5f7d0cb1939497a0858d9f43d89f039f85887 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 8 Jan 2012 23:39:40 +0200 Subject: Bluetooth: Fix resetting HCI_MGMT flag The HCI_MGMT flag should not be cleared when resetting a HCI device. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2d39ede1f20..f3dafae6e1d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -195,7 +195,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); - hdev->dev_flags = 0; + /* Reset all flags, except persistent ones like HCI_MGMT */ + hdev->dev_flags &= BIT(HCI_MGMT); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From a3d4e20a88f54571d794cca365f232bfed0669bb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 9 Jan 2012 00:53:02 +0200 Subject: Bluetooth: Sort to-be-resolved devices by RSSI during discovery This patch makes sure that devices with stronger signal (RSSI closer to 0) are sorted first in the resolve list and will therefore get their names resolved first during device discovery. Since it's more likely that the device the user is trying to discover has a strong signal due to its proximity this ensures that the user gets the "device found" event for it more quickly. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 28 +++++++++++++++++++++++++++- net/bluetooth/mgmt.c | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f9c88251fe1..59e3541e9fc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -395,6 +395,8 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, bdaddr_t *bdaddr, int state); +void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, + struct inquiry_entry *ie); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3acb23cf6ee..9963121028e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -457,6 +457,25 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, return NULL; } +void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, + struct inquiry_entry *ie) +{ + struct discovery_state *cache = &hdev->discovery; + struct list_head *pos = &cache->resolve; + struct inquiry_entry *p; + + list_del(&ie->list); + + list_for_each_entry(p, &cache->resolve, list) { + if (p->name_state != NAME_PENDING && + abs(p->data.rssi) >= abs(ie->data.rssi)) + break; + pos = &p->list; + } + + list_add(&ie->list, pos); +} + bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { @@ -466,8 +485,15 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); - if (ie) + if (ie) { + if (ie->name_state == NAME_NEEDED && + data->rssi != ie->data.rssi) { + ie->data.rssi = data->rssi; + hci_inquiry_cache_update_resolve(hdev, ie); + } + goto update; + } /* Entry not in the cache. Add new one. */ ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3de1e909471..2dae2e8f623 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2043,7 +2043,7 @@ static int confirm_name(struct sock *sk, u16 index, unsigned char *data, list_del(&e->list); } else { e->name_state = NAME_NEEDED; - list_move(&e->list, &hdev->discovery.resolve); + hci_inquiry_cache_update_resolve(hdev, e); } err = 0; -- cgit v1.2.3-70-g09d2 From 8b281b9c7820b054d15cf471c418fd884cbbec78 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 10 Jan 2012 18:33:50 -0200 Subject: Bluetooth: Fix 'enable_hs' type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following build warning: CC [M] net/bluetooth/hci_core.o net/bluetooth/hci_core.c: In function ‘__check_enable_hs’: net/bluetooth/hci_core.c:2587: warning: return from incompatible pointer type module_param in hci_core.c passes 'enable_hs' as bool format, so fix this variable definition type. Signed-off-by: Fabio Estevam Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 2 +- net/bluetooth/hci_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3ee39ed9c29..84993073c2f 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1415,6 +1415,6 @@ struct hci_inquiry_req { }; #define IREQ_CACHE_FLUSH 0x0001 -extern int enable_hs; +extern bool enable_hs; #endif /* __HCI_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9963121028e..91166dbbe35 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -55,7 +55,7 @@ #define AUTO_OFF_TIMEOUT 2000 -int enable_hs; +bool enable_hs; static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); -- cgit v1.2.3-70-g09d2 From 0ef3ef0f676e3c7aaab4a936635f503770fd38b2 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:46 +0100 Subject: Bluetooth: Set P-bit for SREJ frame only if there are I-frames to ack SREJ frame with P-bit set acknowledges I-frames numbered up to (ReqSeq - 1). With this patch P-bit in SREJ is set only when there are some I-frames to ack. This fixes ambiguous situation when lost of I-frame with TxSeq=0 would result in sending SREJ acking all previous I-frames. Consider following scenario: TxWindow=3 HostA: sent I-frame TxSeq=0 HostA: sent I-frame TxSeq=1 HostA: sent I-frame TxSeq=2 HostB: missed I-frame TxSeq=0 HostB: received I-frame TxSeq=1 HostB: sent SREJ ReqSeq=0 Pbit=1 HostA: received SREJ ReqSeq=0 Pbit=1 <- All I-frames acked or not? ... Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index dcccae04ae0..0d5bb45e7be 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3927,15 +3927,15 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont __skb_queue_head_init(&chan->srej_q); l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); - set_bit(CONN_SEND_PBIT, &chan->conn_state); + /* Set P-bit only if there are some I-frames to ack. */ + if (__clear_ack_timer(chan)) + set_bit(CONN_SEND_PBIT, &chan->conn_state); err = l2cap_send_srejframe(chan, tx_seq); if (err < 0) { l2cap_send_disconn_req(chan->conn, chan, -err); return err; } - - __clear_ack_timer(chan); } return 0; -- cgit v1.2.3-70-g09d2 From b17e73bb4269f47e1ea2d64a834f1cfc8644fabb Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:47 +0100 Subject: Bluetooth: Clear ack_timer when sending ack ack_timer should be cleared when sending ACK to avoid acking I-frames twice. This commit introduces helper function (only send ack, not clearing timer) which is used by l2cap_send_ack and l2cap_ack_timeout. This is to avoid clearing ack timer in timer function. Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0d5bb45e7be..3b9e2813f1f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1478,7 +1478,7 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan) return ret; } -static void l2cap_send_ack(struct l2cap_chan *chan) +static void __l2cap_send_ack(struct l2cap_chan *chan) { u32 control = 0; @@ -1498,6 +1498,12 @@ static void l2cap_send_ack(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } +static void l2cap_send_ack(struct l2cap_chan *chan) +{ + __clear_ack_timer(chan); + __l2cap_send_ack(chan); +} + static void l2cap_send_srejtail(struct l2cap_chan *chan) { struct srej_list *tail; @@ -1988,7 +1994,7 @@ static void l2cap_ack_timeout(struct work_struct *work) BT_DBG("chan %p", chan); lock_sock(chan->sk); - l2cap_send_ack(chan); + __l2cap_send_ack(chan); release_sock(chan->sk); } -- cgit v1.2.3-70-g09d2 From 77f918bc7babb8473933ca0a6deefc64fe24b06c Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:48 +0100 Subject: Bluetooth: Don't send RNR immediately when entering local busy There is no need to send RNR immediately when entring local busy. Also upper layer might clear local busy condition before ack timer expires saving few cycles for sending RNR. This also prevents sending two RNRs in some cases where sending one would be enough i.e received N I-frame can trigger local busy (sending RNR acking up to N-1 I-frame) and later sending ack (RNR acking up to N I-frame). This was affecting TC_ERM_BV_07_C and TC_ERM_BV_22_C with some non default channel parameters (tx window and receiving buffer sizes). Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3b9e2813f1f..778ceb2b840 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3719,19 +3719,11 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) { - u32 control; - BT_DBG("chan %p, Enter local busy", chan); set_bit(CONN_LOCAL_BUSY, &chan->conn_state); - control = __set_reqseq(chan, chan->buffer_seq); - control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); - l2cap_send_sframe(chan, control); - - set_bit(CONN_RNR_SENT, &chan->conn_state); - - __clear_ack_timer(chan); + __set_ack_timer(chan); } static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan) @@ -3871,8 +3863,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont goto drop; } - if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { + if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) + l2cap_send_ack(chan); goto drop; + } if (tx_seq == chan->expected_tx_seq) goto expected; -- cgit v1.2.3-70-g09d2 From 09bfb2ee52a66845bbefad0b6eaeae1b5adea949 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:49 +0100 Subject: Bluetooth: Drop L2CAP chan reference if ERTM ack_timer fired Reference counter was incremented when starting ack timer but decremented only when clearing timer, not when timer fired. Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 778ceb2b840..6773453927e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1996,6 +1996,8 @@ static void l2cap_ack_timeout(struct work_struct *work) lock_sock(chan->sk); __l2cap_send_ack(chan); release_sock(chan->sk); + + l2cap_chan_put(chan); } static inline void l2cap_ertm_init(struct l2cap_chan *chan) -- cgit v1.2.3-70-g09d2 From 5ef8cb9e5b5012a373f48e1e336339864b4c1303 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 13 Jan 2012 17:21:42 +0200 Subject: Bluetooth: Use chan instead of sk Remove unneeded conversion from sk to chan. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6773453927e..22319377eb2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -73,7 +73,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); -static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); +static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb); /* ---- L2CAP channels ---- */ @@ -4138,9 +4138,8 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont return 0; } -static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) +int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; u32 control; u16 req_seq; int len, next_tx_seq_offset, req_seq_offset; @@ -4241,7 +4240,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk break; case L2CAP_MODE_ERTM: - l2cap_ertm_data_rcv(sk, skb); + l2cap_ertm_data_rcv(chan, skb); goto done; -- cgit v1.2.3-70-g09d2 From 0952a57a25ee9854e1bf21e333b9fd3de211760e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 13 Jan 2012 17:21:43 +0200 Subject: Bluetooth: Change sk to l2cap_chan Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 22319377eb2..a66e5ec9ade 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1518,9 +1518,10 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } -static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) +static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb) { - struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; int err, sent = 0; @@ -1578,7 +1579,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); put_unaligned_le16(chan->psm, skb_put(skb, 2)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); @@ -1611,7 +1612,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); @@ -1661,7 +1662,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, if (sdulen) put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); -- cgit v1.2.3-70-g09d2 From 7d262f86f6b73efb500be9d9242ef0673221493d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 10 Jan 2012 18:20:49 -0300 Subject: Bluetooth: Add 'eir_len' param to mgmt_device_found() This patch adds a new parameter to mgmt_device_found() to inform the length of 'eir' pointer. EIR data from LE advertising report event doesn't have a fixed length as EIR data from extended inquiry result event does. We needed to change mgmt_device_found() so it copies 'eir_len' bytes instead of HCI_MAX_EIR_LENGTH. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_event.c | 10 ++++++---- net/bluetooth/mgmt.c | 7 +++++-- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 59e3541e9fc..393acd071cb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -925,7 +925,7 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 *eir); + u8 cfm_name, u8 *eir, u8 eir_len); int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f3dafae6e1d..3323dc6c986 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1608,7 +1608,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * name_known = hci_inquiry_cache_update(hdev, &data, false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, !name_known, NULL); + info->dev_class, 0, !name_known, + NULL, 0); } hci_dev_unlock(hdev); @@ -2705,7 +2706,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL); + !name_known, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2723,7 +2724,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL); + !name_known, NULL, 0); } } @@ -2900,7 +2901,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct name_known = hci_inquiry_cache_update(hdev, &data, name_known); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, info->data); + !name_known, info->data, + sizeof(info->data)); } hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2dae2e8f623..e7bbad80fa7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2780,10 +2780,13 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 *eir) + u8 cfm_name, u8 *eir, u8 eir_len) { struct mgmt_ev_device_found ev; + if (eir_len > sizeof(ev.eir)) + return -EINVAL; + memset(&ev, 0, sizeof(ev)); bacpy(&ev.addr.bdaddr, bdaddr); @@ -2792,7 +2795,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev.confirm_name = cfm_name; if (eir) - memcpy(ev.eir, eir, sizeof(ev.eir)); + memcpy(ev.eir, eir, eir_len); if (dev_class) memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); -- cgit v1.2.3-70-g09d2 From 3c9e919511f87f10491628c6b44bc4675822f307 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 10 Jan 2012 18:20:50 -0300 Subject: Bluetooth: Report LE devices Devices found during LE scan should be reported to userspace through mgmt_device_found events. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3323dc6c986..42d63522270 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3208,6 +3208,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, { u8 num_reports = skb->data[0]; void *ptr = &skb->data[1]; + s8 rssi; hci_dev_lock(hdev); @@ -3216,6 +3217,10 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, hci_add_adv_entry(hdev, ev); + rssi = ev->data[ev->length]; + mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, + NULL, rssi, 0, ev->data, ev->length); + ptr += sizeof(*ev) + ev->length + 1; } -- cgit v1.2.3-70-g09d2 From 7005ff1780ca7ad5ed2ec710ad35affc48362ebf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Jan 2012 16:14:43 +0200 Subject: Bluetooth: Fix clearing persistent flags There are several other dev_flags besided HCI_MGMT that should not be cleared upon reset. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 42d63522270..54132a909ea 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -195,8 +195,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); - /* Reset all flags, except persistent ones like HCI_MGMT */ - hdev->dev_flags &= BIT(HCI_MGMT); + /* Reset all flags, except persistent ones */ + hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From afc747a600ff2e3a4eef8f312fc766608a1360e2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 18:11:07 +0200 Subject: Bluetooth: Rename mgmt connected events to match user space User space uses device_(dis)connected instead of just (dis)connected so rename the defines and functions to match this. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 12 +++++++----- 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 393acd071cb..f3fbfd6f6c3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -896,10 +896,10 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable); int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent); -int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type); -int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, +int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); +int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index be65d341788..d1d13dc0cca 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -328,9 +328,9 @@ struct mgmt_ev_new_link_key { struct mgmt_link_key_info key; } __packed; -#define MGMT_EV_CONNECTED 0x000A +#define MGMT_EV_DEVICE_CONNECTED 0x000A -#define MGMT_EV_DISCONNECTED 0x000B +#define MGMT_EV_DEVICE_DISCONNECTED 0x000B #define MGMT_EV_CONNECT_FAILED 0x000C struct mgmt_ev_connect_failed { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 54132a909ea..e13ce945afc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1643,7 +1643,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->state = BT_CONFIG; hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; - mgmt_connected(hdev, &ev->bdaddr, conn->type, + mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); } else conn->state = BT_CONNECTED; @@ -1789,7 +1789,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (ev->status != 0) mgmt_disconnect_failed(hdev, &conn->dst, ev->status); else - mgmt_disconnected(hdev, &conn->dst, conn->type, + mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type); } @@ -3188,7 +3188,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff goto unlock; } - mgmt_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); + mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e7bbad80fa7..c8042c6e2b4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2464,7 +2464,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } -int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, +int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type) { struct mgmt_addr_info ev; @@ -2472,7 +2472,8 @@ int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev.bdaddr, bdaddr); ev.type = link_to_mgmt(link_type, addr_type); - return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, &ev, sizeof(ev), + NULL); } static void disconnect_rsp(struct pending_cmd *cmd, void *data) @@ -2509,8 +2510,8 @@ static void remove_keys_rsp(struct pending_cmd *cmd, void *data) mgmt_pending_remove(cmd); } -int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type) +int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type) { struct mgmt_addr_info ev; struct sock *sk = NULL; @@ -2521,7 +2522,8 @@ int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev.bdaddr, bdaddr); ev.type = link_to_mgmt(link_type, addr_type); - err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk); + err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), + sk); if (sk) sock_put(sk); -- cgit v1.2.3-70-g09d2 From e319d2e74378660c5e09a1b8703663ba97f0f62a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 19:51:59 +0200 Subject: Bluetooth: Add eir_len parameter to mgmt_ev_device_found This patch add a two byte eir_len parameter mgmt_ev_device_found. Since it's unlikely that the data will in the short term be much bigger than conventional EIR lengths just use a small stack based buffer for now to avoid dynamic memory allocation & freeing. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- include/net/bluetooth/mgmt.h | 3 ++- net/bluetooth/mgmt.c | 28 +++++++++++++++------------- 3 files changed, 18 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f3fbfd6f6c3..33dff8ef2e0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -925,7 +925,7 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 *eir, u8 eir_len); + u8 cfm_name, u8 *eir, u16 eir_len); int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index d1d13dc0cca..4f166c834dd 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -368,7 +368,8 @@ struct mgmt_ev_device_found { __u8 dev_class[3]; __s8 rssi; __u8 confirm_name; - __u8 eir[HCI_MAX_EIR_LENGTH]; + __le16 eir_len; + __u8 eir[0]; } __packed; #define MGMT_EV_REMOTE_NAME 0x0012 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c8042c6e2b4..b7e7fdfaee3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2782,27 +2782,29 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 *eir, u8 eir_len) + u8 cfm_name, u8 *eir, u16 eir_len) { - struct mgmt_ev_device_found ev; + char buf[512]; + struct mgmt_ev_device_found *ev = (void *) buf; + size_t ev_size = sizeof(*ev) + eir_len; - if (eir_len > sizeof(ev.eir)) + if (ev_size > sizeof(buf)) return -EINVAL; - memset(&ev, 0, sizeof(ev)); + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->rssi = rssi; + ev->confirm_name = cfm_name; - bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); - ev.rssi = rssi; - ev.confirm_name = cfm_name; - - if (eir) - memcpy(ev.eir, eir, eir_len); + if (eir_len > 0) { + put_unaligned_le16(eir_len, &ev->eir_len); + memcpy(ev->eir, eir, eir_len); + } if (dev_class) - memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); + memcpy(ev->dev_class, dev_class, sizeof(ev->dev_class)); - return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); } int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name) -- cgit v1.2.3-70-g09d2 From 4ddb1930f91b7395a760cd4a8cf1b2a87011571c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 20:04:43 +0200 Subject: Bluetooth: Rename eir_has_complete_name to eir_has_data_type This allows for other uses such as checking for an embedded class of device value in order to decide whether to append the class or not. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e13ce945afc..d256042a83c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2842,7 +2842,7 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s BT_DBG("%s status %d", hdev->name, ev->status); } -static inline bool eir_has_complete_name(u8 *data, size_t data_len) +static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) { u8 field_len; size_t parsed; @@ -2858,7 +2858,7 @@ static inline bool eir_has_complete_name(u8 *data, size_t data_len) if (parsed > data_len) break; - if (data[1] == EIR_NAME_COMPLETE) + if (data[1] == type) return true; data += field_len + 1; @@ -2893,8 +2893,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.ssp_mode = 0x01; if (test_bit(HCI_MGMT, &hdev->dev_flags)) - name_known = eir_has_complete_name(info->data, - sizeof(info->data)); + name_known = eir_has_data_type(info->data, + sizeof(info->data), + EIR_NAME_COMPLETE); else name_known = true; -- cgit v1.2.3-70-g09d2 From 6759a67579a927f2a92f398cf67555e6cc92d0ff Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 20:51:14 +0200 Subject: Bluetooth: Move eir_has_data_field to hci_core.h This makes the function accessible from all places it's needed (e.g. mgmt.c and hci_event.c). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 25 +++++++++++++++++++++++++ net/bluetooth/hci_event.c | 25 ------------------------- 2 files changed, 25 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 33dff8ef2e0..393bb73fc99 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -868,6 +868,31 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, read_unlock(&hci_cb_list_lock); } +static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) +{ + u8 field_len; + size_t parsed; + + for (parsed = 0; parsed < data_len - 1; parsed += field_len) { + field_len = data[0]; + + if (field_len == 0) + break; + + parsed += field_len + 1; + + if (parsed > data_len) + break; + + if (data[1] == type) + return true; + + data += field_len + 1; + } + + return false; +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d256042a83c..e93afebdcf8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2842,31 +2842,6 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s BT_DBG("%s status %d", hdev->name, ev->status); } -static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) -{ - u8 field_len; - size_t parsed; - - for (parsed = 0; parsed < data_len - 1; parsed += field_len) { - field_len = data[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > data_len) - break; - - if (data[1] == type) - return true; - - data += field_len + 1; - } - - return false; -} - static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct inquiry_data data; -- cgit v1.2.3-70-g09d2 From 1dc06093a9f353ef19b7b5180602884d0ce065c5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 21:01:23 +0200 Subject: Bluetooth: Merge device class into the EIR data in mgmt_ev_device_found There's no need to have a separate device class field since the same information can be encoded into the EIR data. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 11 +++++++++++ include/net/bluetooth/mgmt.h | 1 - net/bluetooth/mgmt.c | 20 +++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 393bb73fc99..a0311018a4d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -893,6 +893,17 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) return false; } +static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, + u8 data_len) +{ + eir[eir_len++] = sizeof(type) + data_len; + eir[eir_len++] = type; + memcpy(&eir[eir_len], data, data_len); + eir_len += data_len; + + return eir_len; +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4f166c834dd..bdace523b91 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -365,7 +365,6 @@ struct mgmt_ev_auth_failed { #define MGMT_EV_DEVICE_FOUND 0x0011 struct mgmt_ev_device_found { struct mgmt_addr_info addr; - __u8 dev_class[3]; __s8 rssi; __u8 confirm_name; __le16 eir_len; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b7e7fdfaee3..bec64c98b6a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2786,23 +2786,29 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; - size_t ev_size = sizeof(*ev) + eir_len; + size_t ev_size; - if (ev_size > sizeof(buf)) + /* Leave 5 bytes for a potential CoD field */ + if (sizeof(*ev) + eir_len + 5 > sizeof(buf)) return -EINVAL; + memset(buf, 0, sizeof(buf)); + bacpy(&ev->addr.bdaddr, bdaddr); ev->addr.type = link_to_mgmt(link_type, addr_type); ev->rssi = rssi; ev->confirm_name = cfm_name; - if (eir_len > 0) { - put_unaligned_le16(eir_len, &ev->eir_len); + if (eir_len > 0) memcpy(ev->eir, eir, eir_len); - } - if (dev_class) - memcpy(ev->dev_class, dev_class, sizeof(ev->dev_class)); + if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV)) + eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, + dev_class, 3); + + put_unaligned_le16(eir_len, &ev->eir_len); + + ev_size = sizeof(*ev) + eir_len; return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); } -- cgit v1.2.3-70-g09d2 From 51a8efd7d02c13cb1c6fdd1cd66788792a3fcc7c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jan 2012 06:10:31 +0200 Subject: Bluetooth: Rename conn->pend to conn->flags These flags can and will be used for more general purpose values than just pending state transitions so the more common name "flags" makes more sense than "pend". Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- net/bluetooth/hci_conn.c | 20 ++++++++++---------- net/bluetooth/hci_event.c | 36 ++++++++++++++++++------------------ net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/smp.c | 19 +++++++++---------- 5 files changed, 41 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a0311018a4d..0938168ce60 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -300,7 +300,7 @@ struct hci_conn { __u8 io_capability; __u8 power_save; __u16 disc_timeout; - unsigned long pend; + unsigned long flags; __u8 remote_cap; __u8 remote_oob; @@ -764,7 +764,7 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) if (conn->type != ACL_LINK && conn->type != LE_LINK) return; - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return; encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; @@ -805,7 +805,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) hci_proto_auth_cfm(conn, status); - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return; encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3db432473ad..8a4678a2c98 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -337,7 +337,7 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn) hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); } - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { struct hci_cp_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); @@ -589,9 +589,9 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 acl->power_save = 1; hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); - if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) { + if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) { /* defer SCO setup until mode change completed */ - set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend); + set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags); return sco; } @@ -633,13 +633,13 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) conn->auth_type = auth_type; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); if (conn->key_type != 0xff) - set_bit(HCI_CONN_REAUTH_PEND, &conn->pend); + set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); } return 0; @@ -650,7 +650,7 @@ static void hci_conn_encrypt(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 0x01; @@ -700,7 +700,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) goto encrypt; auth: - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return 0; if (!hci_conn_auth(conn, sec_level, auth_type)) @@ -735,7 +735,7 @@ int hci_conn_change_link_key(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_change_conn_link_key cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, @@ -754,7 +754,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) if (!role && conn->link_mode & HCI_LM_MASTER) return 1; - if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { struct hci_cp_switch_role cp; bacpy(&cp.bdaddr, &conn->dst); cp.role = role; @@ -781,7 +781,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) if (!conn->power_save && !force_active) goto timer; - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { struct hci_cp_exit_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e93afebdcf8..d9a8618ae15 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1344,7 +1344,7 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); @@ -1461,9 +1461,9 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) hci_sco_setup(conn, status); } @@ -1488,9 +1488,9 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) hci_sco_setup(conn, status); } @@ -1817,7 +1817,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (!ev->status) { if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) && - test_bit(HCI_CONN_REAUTH_PEND, &conn->pend)) { + test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { conn->link_mode |= HCI_LM_AUTH; @@ -1827,8 +1827,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s mgmt_auth_failed(hdev, &conn->dst, ev->status); } - clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); - clear_bit(HCI_CONN_REAUTH_PEND, &conn->pend); + clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); + clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) { @@ -1850,7 +1850,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s hci_conn_put(conn); } - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { if (!ev->status) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; @@ -1858,7 +1858,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); hci_encrypt_cfm(conn, ev->status, 0x00); } } @@ -1892,7 +1892,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); @@ -1923,7 +1923,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * conn->link_mode &= ~HCI_LM_ENCRYPT; } - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); if (conn->state == BT_CONFIG) { if (!ev->status) @@ -1952,7 +1952,7 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct if (!ev->status) conn->link_mode |= HCI_LM_SECURE; - clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); + clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); hci_key_change_cfm(conn, ev->status); } @@ -2336,7 +2336,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb conn->link_mode |= HCI_LM_MASTER; } - clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend); + clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); hci_role_switch_cfm(conn, ev->status, ev->role); } @@ -2474,14 +2474,14 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb conn->mode = ev->mode; conn->interval = __le16_to_cpu(ev->interval); - if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { if (conn->mode == HCI_CM_ACTIVE) conn->power_save = 1; else conn->power_save = 0; } - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) hci_sco_setup(conn, ev->status); } @@ -3013,7 +3013,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If we're not the initiators request authorization to * proceed from user space (mgmt_user_confirm with * confirm_hint set to 1). */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { BT_DBG("Confirming auto-accept as acceptor"); confirm_hint = 1; goto confirm; @@ -3074,7 +3074,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_ * initiated the authentication. A traditional auth_complete * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0) + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) mgmt_auth_failed(hdev, &conn->dst, ev->status); hci_conn_put(conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a66e5ec9ade..27b72d95443 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1020,7 +1020,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) __cancel_delayed_work(&conn->info_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { __cancel_delayed_work(&conn->security_timer); smp_chan_destroy(conn); } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 65a90242d99..e08fe6c9c9c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -261,7 +261,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend); + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); @@ -449,7 +449,7 @@ static void random_work(struct work_struct *work) memset(stk + smp->smp_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) { + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; goto error; } @@ -506,7 +506,7 @@ void smp_chan_destroy(struct l2cap_conn *conn) { struct smp_chan *smp = conn->smp_chan; - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); if (smp->tfm) crypto_free_blkcipher(smp->tfm); @@ -571,7 +571,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->link_mode & HCI_LM_MASTER) return SMP_CMD_NOTSUPP; - if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) + if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp = smp_chan_create(conn); smp = conn->smp_chan; @@ -707,8 +707,7 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn) if (!key) return 0; - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, - &hcon->pend)) + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return 1; master = (void *) key->data; @@ -733,7 +732,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (smp_ltk_encrypt(conn)) return 0; - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) + if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); @@ -772,7 +771,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) if (smp_ltk_encrypt(conn)) goto done; - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) + if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); @@ -908,7 +907,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) BT_DBG("conn %p force %d", conn, force); - if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) + if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) return 0; rsp = (void *) &smp->prsp[1]; @@ -982,7 +981,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) } if (conn->hcon->out || force) { - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } -- cgit v1.2.3-70-g09d2 From a0c808b373e89aecc3ecae4cbdcdeff68aa12e3e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jan 2012 09:49:58 +0200 Subject: Bluetooth: Convert hdev->out to a bool type The hdev->out variable is essentially a boolean so the type 'bool' makes more sense than u8. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 8 ++++---- net/bluetooth/hci_event.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0938168ce60..520da44940e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -282,7 +282,7 @@ struct hci_conn { __u16 state; __u8 mode; __u8 type; - __u8 out; + bool out; __u8 attempt; __u8 dev_class[3]; __u8 features[8]; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8a4678a2c98..a707d19ee44 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -51,7 +51,7 @@ static void hci_le_connect(struct hci_conn *conn) struct hci_cp_le_create_conn cp; conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->link_mode |= HCI_LM_MASTER; conn->sec_level = BT_SECURITY_LOW; @@ -83,7 +83,7 @@ void hci_acl_connect(struct hci_conn *conn) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->link_mode = HCI_LM_MASTER; @@ -151,7 +151,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->attempt++; @@ -169,7 +169,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->attempt++; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d9a8618ae15..f6c13153a5e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1154,7 +1154,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (!conn) { conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); if (conn) { - conn->out = 1; + conn->out = true; conn->link_mode |= HCI_LM_MASTER; } else BT_ERR("No memory for new connection"); @@ -1526,7 +1526,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr); if (conn) { conn->dst_type = cp->peer_addr_type; - conn->out = 1; + conn->out = true; } else { BT_ERR("No memory for new connection"); } -- cgit v1.2.3-70-g09d2 From b644ba33699711630099efc58a4efc225560aceb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 17 Jan 2012 21:48:47 +0200 Subject: Bluetooth: Update device_connected and device_found events to latest API This patch updates mgmt_ev_device_connected and mgmt_ev_device found to include an EIR-encoded remote name and class whenever possible. With this addition the mgmt_ev_remote_name event becomes unnecessary and can be removed. Since the connected event doesn't map to hci_conn_complete anymore a HCI_CONN_MGMT_CONNECTED flag is added to track when mgmt has been notified about a connection. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 ++-- include/net/bluetooth/mgmt.h | 17 +++++---- net/bluetooth/hci_event.c | 78 ++++++++++++++++++++++++++++------------ net/bluetooth/mgmt.c | 56 +++++++++++++++++++++-------- 4 files changed, 110 insertions(+), 48 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 520da44940e..18af5427fd0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -409,6 +409,7 @@ enum { HCI_CONN_MODE_CHANGE_PEND, HCI_CONN_SCO_SETUP_PEND, HCI_CONN_LE_SMP_PEND, + HCI_CONN_MGMT_CONNECTED, }; static inline void hci_conn_hash_init(struct hci_dev *hdev) @@ -933,7 +934,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent); int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type); + u8 addr_type, u8 *name, u8 name_len, + u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); @@ -962,7 +964,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 *eir, u16 eir_len); -int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name); +int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, s8 rssi, u8 *name, u8 name_len); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index bdace523b91..6f37983c877 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -329,6 +329,11 @@ struct mgmt_ev_new_link_key { } __packed; #define MGMT_EV_DEVICE_CONNECTED 0x000A +struct mgmt_ev_device_connected { + struct mgmt_addr_info addr; + __le16 eir_len; + __u8 eir[0]; +} __packed; #define MGMT_EV_DEVICE_DISCONNECTED 0x000B @@ -371,20 +376,14 @@ struct mgmt_ev_device_found { __u8 eir[0]; } __packed; -#define MGMT_EV_REMOTE_NAME 0x0012 -struct mgmt_ev_remote_name { - bdaddr_t bdaddr; - __u8 name[MGMT_MAX_NAME_LENGTH]; -} __packed; - -#define MGMT_EV_DISCOVERING 0x0013 +#define MGMT_EV_DISCOVERING 0x0012 -#define MGMT_EV_DEVICE_BLOCKED 0x0014 +#define MGMT_EV_DEVICE_BLOCKED 0x0013 struct mgmt_ev_device_blocked { bdaddr_t bdaddr; } __packed; -#define MGMT_EV_DEVICE_UNBLOCKED 0x0015 +#define MGMT_EV_DEVICE_UNBLOCKED 0x0014 struct mgmt_ev_device_unblocked { bdaddr_t bdaddr; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f6c13153a5e..f0b08ab734d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1286,11 +1286,36 @@ static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } -static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) +static bool hci_resolve_next_name(struct hci_dev *hdev) { struct discovery_state *discov = &hdev->discovery; struct inquiry_entry *e; + if (list_empty(&discov->resolve)) + return false; + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); + if (hci_resolve_name(hdev, e) == 0) { + e->name_state = NAME_PENDING; + return true; + } + + return false; +} + +static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, + bdaddr_t *bdaddr, u8 *name, u8 name_len) +{ + struct discovery_state *discov = &hdev->discovery; + struct inquiry_entry *e; + + if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, + name, name_len, conn->dev_class); + + if (discov->state == DISCOVERY_STOPPED) + return; + if (discov->state == DISCOVERY_STOPPING) goto discov_complete; @@ -1301,16 +1326,13 @@ static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) if (e) { e->name_state = NAME_KNOWN; list_del(&e->list); + if (name) + mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, + e->data.rssi, name, name_len); } - if (list_empty(&discov->resolve)) - goto discov_complete; - - e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); - if (hci_resolve_name(hdev, e) == 0) { - e->name_state = NAME_PENDING; + if (hci_resolve_next_name(hdev)) return; - } discov_complete: hci_discovery_set_state(hdev, DISCOVERY_STOPPED); @@ -1334,10 +1356,11 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + if (test_bit(HCI_MGMT, &hdev->dev_flags)) - hci_resolve_next_name(hdev, &cp->bdaddr); + hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0); - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); if (!conn) goto unlock; @@ -1643,8 +1666,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->state = BT_CONFIG; hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; - mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type); } else conn->state = BT_CONNECTED; @@ -1785,7 +1806,8 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (ev->status == 0) conn->state = BT_CLOSED; - if (conn->type == ACL_LINK || conn->type == LE_LINK) { + if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && + (conn->type == ACL_LINK || conn->type == LE_LINK)) { if (ev->status != 0) mgmt_disconnect_failed(hdev, &conn->dst, ev->status); else @@ -1878,14 +1900,18 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->dev_flags)) { - if (ev->status == 0) - mgmt_remote_name(hdev, &ev->bdaddr, ev->name); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - hci_resolve_next_name(hdev, &ev->bdaddr); - } + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + goto check_auth; - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (ev->status == 0) + hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name, + strnlen(ev->name, HCI_MAX_NAME_LENGTH)); + else + hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0); + +check_auth: if (!conn) goto unlock; @@ -1994,7 +2020,10 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); - } + } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, &conn->dst, conn->type, + conn->dst_type, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -2763,7 +2792,10 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); - } + } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, &conn->dst, conn->type, + conn->dst_type, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -3164,7 +3196,9 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff goto unlock; } - mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); + if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, &ev->bdaddr, conn->type, + conn->dst_type, NULL, 0, 0); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bec64c98b6a..ae9283d47e6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1244,7 +1244,6 @@ static int get_connections(struct sock *sk, u16 index) struct mgmt_rp_get_connections *rp; struct hci_dev *hdev; struct hci_conn *c; - struct list_head *p; size_t rp_len; u16 count; int i, err; @@ -1259,8 +1258,9 @@ static int get_connections(struct sock *sk, u16 index) hci_dev_lock(hdev); count = 0; - list_for_each(p, &hdev->conn_hash.list) { - count++; + list_for_each_entry(c, &hdev->conn_hash.list, list) { + if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + count++; } rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info)); @@ -1274,6 +1274,8 @@ static int get_connections(struct sock *sk, u16 index) i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { + if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + continue; bacpy(&rp->addr[i].bdaddr, &c->dst); rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); if (rp->addr[i].type == MGMT_ADDR_INVALID) @@ -2465,15 +2467,28 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, } int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type) + u8 addr_type, u8 *name, u8 name_len, + u8 *dev_class) { - struct mgmt_addr_info ev; + char buf[512]; + struct mgmt_ev_device_connected *ev = (void *) buf; + u16 eir_len = 0; - bacpy(&ev.bdaddr, bdaddr); - ev.type = link_to_mgmt(link_type, addr_type); + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_mgmt(link_type, addr_type); - return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, &ev, sizeof(ev), - NULL); + if (name_len > 0) + eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, + name, name_len); + + if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0) + eir_len = eir_append_data(&ev->eir[eir_len], eir_len, + EIR_CLASS_OF_DEV, dev_class, 3); + + put_unaligned_le16(eir_len, &ev->eir_len); + + return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, + sizeof(*ev) + eir_len, NULL); } static void disconnect_rsp(struct pending_cmd *cmd, void *data) @@ -2813,16 +2828,27 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); } -int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name) +int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, s8 rssi, u8 *name, u8 name_len) { - struct mgmt_ev_remote_name ev; + struct mgmt_ev_device_found *ev; + char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2]; + u16 eir_len; - memset(&ev, 0, sizeof(ev)); + ev = (struct mgmt_ev_device_found *) buf; - bacpy(&ev.bdaddr, bdaddr); - memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + memset(buf, 0, sizeof(buf)); + + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->rssi = rssi; + + eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, + name_len); + + put_unaligned_le16(eir_len, &ev->eir_len); - return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); } int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) -- cgit v1.2.3-70-g09d2 From 58a681ef1455aef9caad1d41073868fb399373f6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jan 2012 06:47:28 +0200 Subject: Bluetooth: Merge boolean members of struct hci_conn into flags Now that the flags member of struct hci_conn is supposed to accommodate any boolean type values we can easily merge all boolean members into it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- net/bluetooth/hci_conn.c | 15 +++++++++------ net/bluetooth/hci_event.c | 21 +++++++++++++-------- 3 files changed, 25 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 18af5427fd0..7a033111c98 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -286,7 +286,6 @@ struct hci_conn { __u8 attempt; __u8 dev_class[3]; __u8 features[8]; - __u8 ssp_mode; __u16 interval; __u16 pkt_type; __u16 link_policy; @@ -298,12 +297,10 @@ struct hci_conn { __u8 pin_length; __u8 enc_key_size; __u8 io_capability; - __u8 power_save; __u16 disc_timeout; unsigned long flags; __u8 remote_cap; - __u8 remote_oob; __u8 remote_auth; unsigned int sent; @@ -410,6 +407,9 @@ enum { HCI_CONN_SCO_SETUP_PEND, HCI_CONN_LE_SMP_PEND, HCI_CONN_MGMT_CONNECTED, + HCI_CONN_SSP_ENABLED, + HCI_CONN_POWER_SAVE, + HCI_CONN_REMOTE_OOB, }; static inline void hci_conn_hash_init(struct hci_dev *hdev) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a707d19ee44..8288e303621 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -105,7 +105,8 @@ void hci_acl_connect(struct hci_conn *conn) } memcpy(conn->dev_class, ie->data.dev_class, 3); - conn->ssp_mode = ie->data.ssp_mode; + if (ie->data.ssp_mode > 0) + set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } cp.pkt_type = cpu_to_le16(conn->pkt_type); @@ -386,7 +387,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->remote_auth = 0xff; conn->key_type = 0xff; - conn->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; switch (type) { @@ -586,7 +587,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 if (acl->state == BT_CONNECTED && (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { - acl->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &acl->flags); hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) { @@ -607,7 +608,8 @@ int hci_conn_check_link_mode(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 && + if (test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && + conn->hdev->ssp_mode > 0 && !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; @@ -671,7 +673,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* For non 2.1 devices and low security level we don't need the link key. */ if (sec_level == BT_SECURITY_LOW && - (!conn->ssp_mode || !conn->hdev->ssp_mode)) + (!test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) || + !conn->hdev->ssp_mode)) return 1; /* For other security levels we need the link key. */ @@ -778,7 +781,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) if (conn->mode != HCI_CM_SNIFF) goto timer; - if (!conn->power_save && !force_active) + if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active) goto timer; if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f0b08ab734d..02ad5380173 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1264,7 +1264,8 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, /* Only request authentication for SSP connections or non-SSP * devices with sec_level HIGH or if MITM protection is requested */ - if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) && + if (!(hdev->ssp_mode > 0 && + test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) && conn->pending_sec_level != BT_SECURITY_HIGH && !(conn->auth_type & 0x01)) return 0; @@ -1838,7 +1839,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s goto unlock; if (!ev->status) { - if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) && + if (!(test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && + hdev->ssp_mode > 0) && test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { @@ -1853,7 +1855,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { - if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) { + if (!ev->status && hdev->ssp_mode > 0 && + test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; @@ -2505,9 +2508,9 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { if (conn->mode == HCI_CM_ACTIVE) - conn->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &conn->flags); else - conn->power_save = 0; + clear_bit(HCI_CONN_POWER_SAVE, &conn->flags); } if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) @@ -2780,7 +2783,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b if (ie) ie->data.ssp_mode = (ev->features[0] & 0x01); - conn->ssp_mode = (ev->features[0] & 0x01); + if (ev->features[0] & 0x01) + set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } if (conn->state != BT_CONFIG) @@ -2962,7 +2966,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; - if ((conn->out == 0x01 || conn->remote_oob == 0x01) && + if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) && hci_find_remote_oob_data(hdev, &conn->dst)) cp.oob_data = 0x01; else @@ -2998,8 +3002,9 @@ static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *s goto unlock; conn->remote_cap = ev->capability; - conn->remote_oob = ev->oob_data; conn->remote_auth = ev->authentication; + if (ev->oob_data) + set_bit(HCI_CONN_REMOTE_OOB, &conn->flags); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3-70-g09d2 From 84bde9d6c0e6830f4a8685a5d237965053118bf9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 25 Jan 2012 14:21:06 +0200 Subject: Bluetooth: Convert hdev->ssp_mode to a flag The ssp_mode is essentially just a boolean so it's more appropriate to have it simply as a flag in hdev->dev_flags. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_conn.c | 6 +++--- net/bluetooth/hci_event.c | 17 ++++++++++++----- net/bluetooth/mgmt.c | 4 ++-- 5 files changed, 18 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index dd2cc6cb35b..cb9097acbf4 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -94,6 +94,7 @@ enum { HCI_DEBUG_KEYS, HCI_LE_SCAN, + HCI_SSP_ENABLED, }; /* HCI ioctl defines */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7a033111c98..94ba8693e9d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -144,7 +144,6 @@ struct hci_dev { __u8 features[8]; __u8 host_features[8]; __u8 commands[64]; - __u8 ssp_mode; __u8 hci_ver; __u16 hci_rev; __u8 lmp_ver; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8288e303621..6ec259e84b9 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -609,8 +609,8 @@ int hci_conn_check_link_mode(struct hci_conn *conn) BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - conn->hdev->ssp_mode > 0 && - !(conn->link_mode & HCI_LM_ENCRYPT)) + test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags) && + !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; return 1; @@ -674,7 +674,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) key. */ if (sec_level == BT_SECURITY_LOW && (!test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) || - !conn->hdev->ssp_mode)) + !test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags))) return 1; /* For other security levels we need the link key. */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 02ad5380173..eb198ccbc10 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -429,7 +429,10 @@ static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - hdev->ssp_mode = rp->mode; + if (rp->mode) + set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); } static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) @@ -446,7 +449,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) if (!sent) return; - hdev->ssp_mode = *((__u8 *) sent); + if (*((u8 *) sent)) + set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); } static u8 hci_get_inquiry_mode(struct hci_dev *hdev) @@ -1264,7 +1270,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, /* Only request authentication for SSP connections or non-SSP * devices with sec_level HIGH or if MITM protection is requested */ - if (!(hdev->ssp_mode > 0 && + if (!(test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) && conn->pending_sec_level != BT_SECURITY_HIGH && !(conn->auth_type & 0x01)) @@ -1840,7 +1846,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (!ev->status) { if (!(test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - hdev->ssp_mode > 0) && + test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) && test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { @@ -1855,7 +1861,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { - if (!ev->status && hdev->ssp_mode > 0 && + if (!ev->status && + test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ae9283d47e6..89707996d35 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -297,7 +297,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_AUTH, &hdev->flags)) settings |= MGMT_SETTING_LINK_SECURITY; - if (hdev->ssp_mode > 0) + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_SSP; return settings; @@ -416,7 +416,7 @@ static int update_eir(struct hci_dev *hdev) if (!(hdev->features[6] & LMP_EXT_INQ)) return 0; - if (hdev->ssp_mode == 0) + if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) return 0; if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) -- cgit v1.2.3-70-g09d2 From aa64a8b500e61c33c17f1d5e7de0cc154489c59e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Jan 2012 21:33:12 +0200 Subject: Bluetooth: Add a convenience function to check for SSP enabled It's a very common test to see if both the local and the remote device have SSP enabled. By creating a simple function to test this we can shorten many if-statements in the code. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 +++++++ net/bluetooth/hci_conn.c | 8 ++------ net/bluetooth/hci_event.c | 12 ++++-------- 3 files changed, 13 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 94ba8693e9d..25f449fcd69 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -411,6 +411,13 @@ enum { HCI_CONN_REMOTE_OOB, }; +static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + return (test_bit(HCI_SSP_ENABLED, &hdev->flags) && + test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)); +} + static inline void hci_conn_hash_init(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6ec259e84b9..eae7a53467e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -608,9 +608,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags) && - !(conn->link_mode & HCI_LM_ENCRYPT)) + if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; return 1; @@ -672,9 +670,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* For non 2.1 devices and low security level we don't need the link key. */ - if (sec_level == BT_SECURITY_LOW && - (!test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) || - !test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags))) + if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn)) return 1; /* For other security levels we need the link key. */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index eb198ccbc10..6fb9016652b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1270,8 +1270,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, /* Only request authentication for SSP connections or non-SSP * devices with sec_level HIGH or if MITM protection is requested */ - if (!(test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && - test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) && + if (!hci_conn_ssp_enabled(conn) && conn->pending_sec_level != BT_SECURITY_HIGH && !(conn->auth_type & 0x01)) return 0; @@ -1845,9 +1844,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s goto unlock; if (!ev->status) { - if (!(test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) && - test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { + if (!hci_conn_ssp_enabled(conn) && + test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { conn->link_mode |= HCI_LM_AUTH; @@ -1861,9 +1859,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { - if (!ev->status && - test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && - test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) { + if (!ev->status && hci_conn_ssp_enabled(conn)) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; -- cgit v1.2.3-70-g09d2 From 61e1b4b7de5c7e3b671e069f8bf7ee94dedbfde0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 19 Jan 2012 11:19:50 +0200 Subject: Bluetooth: trivial: space correction Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 27b72d95443..cba1f683b64 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4720,7 +4720,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) c->state, __le16_to_cpu(c->psm), c->scid, c->dcid, c->imtu, c->omtu, c->sec_level, c->mode); -} + } read_unlock(&chan_list_lock); -- cgit v1.2.3-70-g09d2 From d22015aad40b4316f0f74c8e410debca44c3e6e2 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sun, 22 Jan 2012 00:28:34 +0200 Subject: Bluetooth: silence lockdep warning Since bluetooth uses multiple protocols types, to avoid lockdep warnings, we need to use different lockdep classes (one for each protocol type). This is already done in bt_sock_create but it misses a couple of cases when new connections are created. This patch corrects that to fix the following warning: <4>[ 1864.732366] ======================================================= <4>[ 1864.733030] [ INFO: possible circular locking dependency detected ] <4>[ 1864.733544] 3.0.16-mid3-00007-gc9a0f62 #3 <4>[ 1864.733883] ------------------------------------------------------- <4>[ 1864.734408] t.android.btclc/4204 is trying to acquire lock: <4>[ 1864.734869] (rfcomm_mutex){+.+.+.}, at: [] rfcomm_dlc_close+0x15/0x30 <4>[ 1864.735541] <4>[ 1864.735549] but task is already holding lock: <4>[ 1864.736045] (sk_lock-AF_BLUETOOTH){+.+.+.}, at: [] lock_sock+0xa/0xc <4>[ 1864.736732] <4>[ 1864.736740] which lock already depends on the new lock. <4>[ 1864.736750] <4>[ 1864.737428] <4>[ 1864.737437] the existing dependency chain (in reverse order) is: <4>[ 1864.738016] <4>[ 1864.738023] -> #1 (sk_lock-AF_BLUETOOTH){+.+.+.}: <4>[ 1864.738549] [] lock_acquire+0x104/0x140 <4>[ 1864.738977] [] lock_sock_nested+0x58/0x68 <4>[ 1864.739411] [] l2cap_sock_sendmsg+0x3e/0x76 <4>[ 1864.739858] [] __sock_sendmsg+0x50/0x59 <4>[ 1864.740279] [] sock_sendmsg+0x94/0xa8 <4>[ 1864.740687] [] kernel_sendmsg+0x28/0x37 <4>[ 1864.741106] [] rfcomm_send_frame+0x30/0x38 <4>[ 1864.741542] [] rfcomm_send_ua+0x58/0x5a <4>[ 1864.741959] [] rfcomm_run+0x441/0xb52 <4>[ 1864.742365] [] kthread+0x63/0x68 <4>[ 1864.742742] [] kernel_thread_helper+0x6/0xd <4>[ 1864.743187] <4>[ 1864.743193] -> #0 (rfcomm_mutex){+.+.+.}: <4>[ 1864.743667] [] __lock_acquire+0x988/0xc00 <4>[ 1864.744100] [] lock_acquire+0x104/0x140 <4>[ 1864.744519] [] __mutex_lock_common+0x3b/0x33f <4>[ 1864.744975] [] mutex_lock_nested+0x2d/0x36 <4>[ 1864.745412] [] rfcomm_dlc_close+0x15/0x30 <4>[ 1864.745842] [] __rfcomm_sock_close+0x5f/0x6b <4>[ 1864.746288] [] rfcomm_sock_shutdown+0x2f/0x62 <4>[ 1864.746737] [] sys_socketcall+0x1db/0x422 <4>[ 1864.747165] [] syscall_call+0x7/0xb Signed-off-by: Octavian Purdila Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 2 ++ net/bluetooth/af_bluetooth.c | 12 +++++------- net/bluetooth/l2cap_sock.c | 2 ++ net/bluetooth/rfcomm/sock.c | 2 ++ 4 files changed, 11 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index abaad6ed9b8..4a82ca0bb0b 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -256,4 +256,6 @@ void l2cap_exit(void); int sco_init(void); void sco_exit(void); +void bt_sock_reclassify_lock(struct sock *sk, int proto); + #endif /* __BLUETOOTH_H */ diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index ef92864ac62..72eb187a5f6 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -71,19 +71,16 @@ static const char *const bt_slock_key_strings[BT_MAX_PROTO] = { "slock-AF_BLUETOOTH-BTPROTO_AVDTP", }; -static inline void bt_sock_reclassify_lock(struct socket *sock, int proto) +void bt_sock_reclassify_lock(struct sock *sk, int proto) { - struct sock *sk = sock->sk; - - if (!sk) - return; - + BUG_ON(!sk); BUG_ON(sock_owned_by_user(sk)); sock_lock_init_class_and_name(sk, bt_slock_key_strings[proto], &bt_slock_key[proto], bt_key_strings[proto], &bt_lock_key[proto]); } +EXPORT_SYMBOL(bt_sock_reclassify_lock); int bt_sock_register(int proto, const struct net_proto_family *ops) { @@ -145,7 +142,8 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto, if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { err = bt_proto[proto]->create(net, sock, proto, kern); - bt_sock_reclassify_lock(sock, proto); + if (!err) + bt_sock_reclassify_lock(sock->sk, proto); module_put(bt_proto[proto]->owner); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c57027f7606..401d9428ae4 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -849,6 +849,8 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) if (!sk) return NULL; + bt_sock_reclassify_lock(sk, BTPROTO_L2CAP); + l2cap_sock_init(sk, parent); return l2cap_pi(sk)->chan; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index f066678faee..22169c3f148 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -956,6 +956,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * if (!sk) goto done; + bt_sock_reclassify_lock(sk, BTPROTO_RFCOMM); + rfcomm_sock_init(sk, parent); bacpy(&bt_sk(sk)->src, &src); bacpy(&bt_sk(sk)->dst, &dst); -- cgit v1.2.3-70-g09d2 From 2f7719ce54bf6e877987f6ef578b580a51d8c2e3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 20 Jan 2012 14:08:03 +0200 Subject: Bluetooth: Add alloc_skb chan operator Add channel-specific skb allocation method Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 3 +++ net/bluetooth/l2cap_core.c | 23 +++++++++++++++-------- net/bluetooth/l2cap_sock.c | 9 +++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 238daf84184..e7a8cc7d07f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -506,6 +506,9 @@ struct l2cap_ops { int (*recv) (void *data, struct sk_buff *skb); void (*close) (void *data); void (*state_change) (void *data, int state); + struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, + unsigned long len, int nb, int *err); + }; struct l2cap_conn { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cba1f683b64..b2f52f87b98 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1520,7 +1520,6 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; int err, sent = 0; @@ -1536,7 +1535,9 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr while (len) { count = min_t(unsigned int, conn->mtu, len); - *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); + *frag = chan->ops->alloc_skb(chan, count, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!*frag) return err; if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) @@ -1566,8 +1567,10 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, BT_DBG("sk %p len %d priority %u", sk, (int)len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) return ERR_PTR(err); @@ -1600,8 +1603,10 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, BT_DBG("sk %p len %d", sk, (int)len); count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) return ERR_PTR(err); @@ -1647,8 +1652,10 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, hlen += L2CAP_FCS_SIZE; count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) return ERR_PTR(err); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 401d9428ae4..16360298590 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -899,12 +899,21 @@ static void l2cap_sock_state_change_cb(void *data, int state) sk->sk_state = state; } +static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long len, int nb, int *err) +{ + struct sock *sk = chan->sk; + + return bt_skb_send_alloc(sk, len, nb, err); +} + static struct l2cap_ops l2cap_chan_ops = { .name = "L2CAP Socket Interface", .new_connection = l2cap_sock_new_connection_cb, .recv = l2cap_sock_recv_cb, .close = l2cap_sock_close_cb, .state_change = l2cap_sock_state_change_cb, + .alloc_skb = l2cap_sock_alloc_skb_cb, }; static void l2cap_sock_destruct(struct sock *sk) -- cgit v1.2.3-70-g09d2 From cad8f1d072375a550ca81419799ba381118c14bb Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 23 Jan 2012 10:06:05 +0100 Subject: Bluetooth: Make l2cap_ertm_data_rcv static It is not used outside of l2cap_core.c. Also l2cap_ertm_data_rcv is only used after it is defined so there is no need for forward declaration. Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b2f52f87b98..942ba1d1a38 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -73,8 +73,6 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); -static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb); - /* ---- L2CAP channels ---- */ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) @@ -4146,7 +4144,7 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont return 0; } -int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) +static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { u32 control; u16 req_seq; -- cgit v1.2.3-70-g09d2 From cb601d7e65f497a2a172d65b2ef1d738ac6fe4f4 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 30 Jan 2012 09:22:09 -0300 Subject: Bluetooth: Use GFP_KERNEL in hci_conn_add() This function is called in process context only, so it should use GFP_KERNEL to allocate memory. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index eae7a53467e..9ec7b8efae5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -373,7 +373,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) BT_DBG("%s dst %s", hdev->name, batostr(dst)); - conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); + conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); if (!conn) return NULL; -- cgit v1.2.3-70-g09d2 From 75d7735c7a3ddc3842473219460285748d10db11 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 30 Jan 2012 09:22:10 -0300 Subject: Bluetooth: Use GFP_KERNEL in hci_chan_create() This function is called in process context only, so it should use GFP_KERNEL to allocate memory. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 9ec7b8efae5..7b38a0ba876 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -945,7 +945,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s conn %p", hdev->name, conn); - chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC); + chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); if (!chan) return NULL; -- cgit v1.2.3-70-g09d2 From e72acc13c770a82b4ce4a07e9716f29320eae0f8 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 27 Jan 2012 19:42:03 -0300 Subject: Bluetooth: Remove unneeded locking We don't need locking hdev in hci_conn_timeout() since it doesn't access any hdev's shared resources, it basically queues HCI commands. Signed-off-by: Andre Guedes Signed-off-by: Vinicius Costa Gomes Reviewed-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7b38a0ba876..67c94c4dfc3 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -280,7 +280,6 @@ static void hci_conn_timeout(struct work_struct *work) { struct hci_conn *conn = container_of(work, struct hci_conn, disc_work.work); - struct hci_dev *hdev = conn->hdev; __u8 reason; BT_DBG("conn %p state %d", conn, conn->state); @@ -288,8 +287,6 @@ static void hci_conn_timeout(struct work_struct *work) if (atomic_read(&conn->refcnt)) return; - hci_dev_lock(hdev); - switch (conn->state) { case BT_CONNECT: case BT_CONNECT2: @@ -309,8 +306,6 @@ static void hci_conn_timeout(struct work_struct *work) conn->state = BT_CLOSED; break; } - - hci_dev_unlock(hdev); } /* Enter sniff mode */ -- cgit v1.2.3-70-g09d2 From 17cd3f374be6648bd46c86ff8f2a2511d3f416ee Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Mon, 30 Jan 2012 18:26:28 -0200 Subject: Bluetooth: Remove usage of __cancel_delayed_work() __cancel_delayed_work() is being used in some paths where we cannot sleep waiting for the delayed work to finish. However, that function might return while the timer is running and the work will be queued again. Replace the calls with safer cancel_delayed_work() version which spins until the timer handler finishes on other CPUs and cancels the delayed work. Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 4 ++-- net/bluetooth/l2cap_core.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e7a8cc7d07f..42fdbb83325 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -614,7 +614,7 @@ static inline void l2cap_set_timer(struct l2cap_chan *chan, { BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); - if (!__cancel_delayed_work(work)) + if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); schedule_delayed_work(work, timeout); } @@ -624,7 +624,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan, { bool ret; - ret = __cancel_delayed_work(work); + ret = cancel_delayed_work(work); if (ret) l2cap_chan_put(chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 942ba1d1a38..ae7fb27525d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2588,7 +2588,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && cmd->ident == conn->info_ident) { - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work(&conn->info_timer); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -3135,7 +3135,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) return 0; - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; @@ -4509,7 +4509,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (hcon->type == LE_LINK) { smp_distribute_keys(conn, 0); - __cancel_delayed_work(&conn->security_timer); + cancel_delayed_work(&conn->security_timer); } rcu_read_lock(); -- cgit v1.2.3-70-g09d2 From 127074bfa3c11c12e0160437e31b08c6b27412a4 Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Mon, 30 Jan 2012 18:26:29 -0200 Subject: Bluetooth: Fix possible use after free in delete path We need to use the _sync() version for cancelling the info and security timer in the L2CAP connection delete path. Otherwise the delayed work handler might run after the connection object is freed. Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ae7fb27525d..09cd8601ea8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1016,10 +1016,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { - __cancel_delayed_work(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } -- cgit v1.2.3-70-g09d2 From f7aa611a0ecf1d22f21e26279e1a3baf1db6b973 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Mon, 30 Jan 2012 19:29:12 -0300 Subject: Bluetooth: Rename smp_key_size to enc_key_size This makes clear that this is the size of the key used to encrypt the link. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/smp.h | 2 +- net/bluetooth/smp.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index aeaf5fa2b9f..7b3acdd2913 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -127,7 +127,7 @@ struct smp_chan { u8 rrnd[16]; /* SMP Pairing Random (remote) */ u8 pcnf[16]; /* SMP Pairing Confirm */ u8 tk[16]; /* SMP Temporary Key */ - u8 smp_key_size; + u8 enc_key_size; unsigned long smp_flags; struct crypto_blkcipher *tfm; struct work_struct confirm; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e08fe6c9c9c..581833436af 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -250,7 +250,7 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) (max_key_size < SMP_MIN_ENC_KEY_SIZE)) return SMP_ENC_KEY_SIZE; - smp->smp_key_size = max_key_size; + smp->enc_key_size = max_key_size; return 0; } @@ -446,8 +446,8 @@ static void random_work(struct work_struct *work) smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); swap128(key, stk); - memset(stk + smp->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); + memset(stk + smp->enc_key_size, 0, + SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; @@ -455,7 +455,7 @@ static void random_work(struct work_struct *work) } hci_le_start_enc(hcon, ediv, rand, stk); - hcon->enc_key_size = smp->smp_key_size; + hcon->enc_key_size = smp->enc_key_size; } else { u8 stk[16], r[16], rand[8]; __le16 ediv; @@ -469,10 +469,10 @@ static void random_work(struct work_struct *work) smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key); swap128(key, stk); - memset(stk + smp->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); + memset(stk + smp->enc_key_size, 0, + SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); - hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size, + hci_add_ltk(hcon->hdev, 0, conn->dst, smp->enc_key_size, ediv, rand, stk); } @@ -819,7 +819,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(*rp)); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size, + hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, rp->ediv, rp->rand, smp->tk); smp_distribute_keys(conn, 1); @@ -940,7 +940,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size, + hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, ediv, ident.rand, enc.ltk); ident.ediv = cpu_to_le16(ediv); -- cgit v1.2.3-70-g09d2 From 4777bfdebbddc1f58d9148de5a3e00375d063768 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 30 Jan 2012 23:31:28 -0300 Subject: Bluetooth: Use GFP_KERNEL in hci_add_adv_entry() This function is not called in interrupt context anymore, so it should use GFP_KERNEL to allocate memory. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 91166dbbe35..45e2d2a72b1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1553,7 +1553,7 @@ int hci_add_adv_entry(struct hci_dev *hdev, if (hci_find_adv_entry(hdev, &ev->bdaddr)) return 0; - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 66f01296962dfebf032c18ffe61c53a199b4a7bd Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 27 Jan 2012 19:32:39 +0200 Subject: Bluetooth: Fix RFCOMM session reference counting issue There is an imbalance in the rfcomm_session_hold / rfcomm_session_put operations which causes the following crash: [ 685.010159] BUG: unable to handle kernel paging request at 6b6b6b6b [ 685.010169] IP: [] rfcomm_process_dlcs+0x1b/0x15e [ 685.010181] *pdpt = 000000002d665001 *pde = 0000000000000000 [ 685.010191] Oops: 0000 [#1] PREEMPT SMP [ 685.010247] [ 685.010255] Pid: 947, comm: krfcommd Tainted: G C 3.0.16-mid8-dirty #44 [ 685.010266] EIP: 0060:[] EFLAGS: 00010246 CPU: 1 [ 685.010274] EIP is at rfcomm_process_dlcs+0x1b/0x15e [ 685.010281] EAX: e79f551c EBX: 6b6b6b6b ECX: 00000007 EDX: e79f40b4 [ 685.010288] ESI: e79f4060 EDI: ed4e1f70 EBP: ed4e1f68 ESP: ed4e1f50 [ 685.010295] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 685.010303] Process krfcommd (pid: 947, ti=ed4e0000 task=ed43e5e0 task.ti=ed4e0000) [ 685.010308] Stack: [ 685.010312] ed4e1f68 c149eb53 e5925150 e79f4060 ed500000 ed4e1f70 ed4e1f80 c149ec10 [ 685.010331] 00000000 ed43e5e0 00000000 ed4e1f90 ed4e1f9c c149ec87 0000bf54 00000000 [ 685.010348] 00000000 ee03bf54 c149ec37 ed4e1fe4 c104fe01 00000000 00000000 00000000 [ 685.010367] Call Trace: [ 685.010376] [] ? rfcomm_process_rx+0x6e/0x74 [ 685.010387] [] rfcomm_process_sessions+0xb7/0xde [ 685.010398] [] rfcomm_run+0x50/0x6d [ 685.010409] [] ? rfcomm_process_sessions+0xde/0xde [ 685.010419] [] kthread+0x63/0x68 [ 685.010431] [] ? __init_kthread_worker+0x42/0x42 [ 685.010442] [] kernel_thread_helper+0x6/0xd This issue has been brought up earlier here: https://lkml.org/lkml/2011/5/21/127 The issue appears to be the rfcomm_session_put in rfcomm_recv_ua. This operation doesn't seem be to required as for the non-initiator case we have the rfcomm_process_rx doing an explicit put and in the initiator case the last dlc_unlink will drive the reference counter to 0. There have been several attempts to fix these issue: 6c2718d Bluetooth: Do not call rfcomm_session_put() for RFCOMM UA on closed socket 683d949 Bluetooth: Never deallocate a session when some DLC points to it but AFAICS they do not fix the issue just make it harder to reproduce. Signed-off-by: Octavian Purdila Signed-off-by: Gopala Krishna Murala Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/rfcomm/core.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 501649bf559..8a602388f1e 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1164,12 +1164,18 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) break; case BT_DISCONN: - /* When socket is closed and we are not RFCOMM - * initiator rfcomm_process_rx already calls - * rfcomm_session_put() */ - if (s->sock->sk->sk_state != BT_CLOSED) - if (list_empty(&s->dlcs)) - rfcomm_session_put(s); + /* rfcomm_session_put is called later so don't do + * anything here otherwise we will mess up the session + * reference counter: + * + * (a) when we are the initiator dlc_unlink will drive + * the reference counter to 0 (there is no initial put + * after session_add) + * + * (b) when we are not the initiator rfcomm_rx_process + * will explicitly call put to balance the initial hold + * done after session add. + */ break; } } -- cgit v1.2.3-70-g09d2 From f1c09c07cd1a6c1676c4df6450d2b28875e184c1 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 1 Feb 2012 18:27:56 -0300 Subject: Bluetooth: Fix invalid memory access when there's no SMP channel We only should try to free the SMP channel that was created if there is a pending SMP session. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 581833436af..9ff56e18d99 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -263,8 +263,11 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); - cancel_delayed_work_sync(&conn->security_timer); - smp_chan_destroy(conn); + + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { + cancel_delayed_work_sync(&conn->security_timer); + smp_chan_destroy(conn); + } } #define JUST_WORKS 0x00 @@ -506,7 +509,7 @@ void smp_chan_destroy(struct l2cap_conn *conn) { struct smp_chan *smp = conn->smp_chan; - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); + BUG_ON(!smp); if (smp->tfm) crypto_free_blkcipher(smp->tfm); -- cgit v1.2.3-70-g09d2 From b7d05bad1c10a363b6b99f66ac1fa76b6892e618 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 13 Jan 2012 15:11:30 +0100 Subject: Bluetooth: Fix l2cap conn failures for ssp devices Commit 330605423c fixed l2cap conn establishment for non-ssp remote devices by not setting HCI_CONN_ENCRYPT_PEND every time conn security is tested (which was always returning failure on any subsequent security checks). However, this broke l2cap conn establishment for ssp remote devices when an ACL link was already established at SDP-level security. This fix ensures that encryption must be pending whenever authentication is also pending. Signed-off-by: Peter Hurley Tested-by: Daniel Wagner Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 67c94c4dfc3..aca71c087a1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -630,6 +630,10 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; + + /* encrypt must be pending if auth is also pending */ + set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); -- cgit v1.2.3-70-g09d2 From 7a7f1e7c857959f5298020969741e389f21edbae Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 16 Jan 2012 13:34:29 +0530 Subject: Bluetooth: Send correct response to IO Capability Request This patch sends correct IO Capability response to remote device in case Local Device supports KeyBoardDisplay IO Capability as this capability is not valid as per BT spec for IO capability Request Reply Command. This capability is mapped to DisplayYesNo which is in accordance with BT spec. Signed-off-by: Hemant Gupta Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6fb9016652b..041a35eb25c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2965,7 +2965,10 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff struct hci_cp_io_capability_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); - cp.capability = conn->io_capability; + /* Change the IO capability from KeyboardDisplay + * to DisplayYesNo as it is not supported by BT spec. */ + cp.capability = (conn->io_capability == 0x04) ? + 0x01 : conn->io_capability; conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; -- cgit v1.2.3-70-g09d2 From 95947a391ebe685b9870cd25cac1433aedf5d49c Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 23 Jan 2012 15:36:11 +0530 Subject: Bluetooth: Fix clearing of debug and linkkey flags This patch fixes clearing of HCI_LINK_KEYS and HCI_DEBUG_KEYS dev_flags while resetting. Without this patch pairing does not work over management interface for BR-EDR devices. Signed-off-by: Hemant Gupta Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 041a35eb25c..a86f82b1131 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -196,7 +196,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); /* Reset all flags, except persistent ones */ - hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF); + hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF) | + BIT(HCI_LINK_KEYS) | BIT(HCI_DEBUG_KEYS); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 28424707a2e4ad38ab546d2ed5e3d6b035a84258 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Feb 2012 04:02:29 +0200 Subject: Bluetooth: mgmt: Implement Cancel Pair Device command This patch implements the Cancel Pair Device command for mgmt. It's used by user space to cancel an ongoing pairing attempt which was triggered by the Pair Device command. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 42eb48bb2c3..72975fd5398 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -39,6 +39,7 @@ #define MGMT_STATUS_INVALID_PARAMS 0x0d #define MGMT_STATUS_DISCONNECTED 0x0e #define MGMT_STATUS_NOT_POWERED 0x0f +#define MGMT_STATUS_CANCELLED 0x10 struct mgmt_hdr { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 89707996d35..00ab083749e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1594,6 +1594,54 @@ unlock: return err; } +static int cancel_pair_device(struct sock *sk, u16 index, + unsigned char *data, u16 len) +{ + struct mgmt_addr_info *addr = (void *) data; + struct hci_dev *hdev; + struct pending_cmd *cmd; + struct hci_conn *conn; + int err; + + BT_DBG(""); + + if (len != sizeof(*addr)) + return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); + if (!cmd) { + err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + goto unlock; + } + + conn = cmd->user_data; + + if (bacmp(&addr->bdaddr, &conn->dst) != 0) { + err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + goto unlock; + } + + pairing_complete(cmd, MGMT_STATUS_CANCELLED); + + err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr, + sizeof(*addr)); +unlock: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, u16 mgmt_op, u16 hci_op, __le32 passkey) { @@ -2271,6 +2319,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_PAIR_DEVICE: err = pair_device(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_CANCEL_PAIR_DEVICE: + err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); + break; case MGMT_OP_USER_CONFIRM_REPLY: err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len); break; -- cgit v1.2.3-70-g09d2 From 3c4e0df028935618d052235ba85bc7079be13394 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 2 Feb 2012 10:32:17 +0200 Subject: Bluetooth: Use list _safe deleting from conn_hash_list Use list_for_each_entry_safe which is safe version against removal of list entry. Otherwise we remove hci_conn element and reference next element which result in accessing LIST_POISON. [ 95.571834] Bluetooth: unknown link type 127 [ 95.578349] BUG: unable to handle kernel paging request at 20002000 [ 95.580236] IP: [<20002000>] 0x20001fff [ 95.580763] *pde = 00000000 [ 95.581196] Oops: 0000 [#1] SMP ... [ 95.582298] Pid: 3355, comm: hciconfig Tainted: G O 3.2.0-VirttualBox [ 95.582298] EIP: 0060:[<20002000>] EFLAGS: 00210206 CPU: 0 [ 95.582298] EIP is at 0x20002000 ... [ 95.582298] Call Trace: [ 95.582298] [] ? hci_conn_hash_flush+0x76/0xf0 [bluetooth] [ 95.582298] [] hci_dev_do_close+0xc1/0x2e0 [bluetooth] [ 95.582298] [] ? hci_dev_get+0x69/0xb0 [bluetooth] [ 95.582298] [] hci_dev_close+0x2a/0x50 [bluetooth] [ 95.582298] [] hci_sock_ioctl+0x1af/0x3f0 [bluetooth] [ 95.582298] [] ? handle_pte_fault+0x8a/0x8f0 [ 95.582298] [] sock_ioctl+0x5f/0x260 [ 95.582298] [] ? sock_fasync+0x90/0x90 [ 95.582298] [] do_vfs_ioctl+0x83/0x5b0 [ 95.582298] [] ? do_page_fault+0x297/0x500 [ 95.582298] [] ? spurious_fault+0xd0/0xd0 [ 95.582298] [] ? up_read+0x1b/0x30 [ 95.582298] [] ? do_page_fault+0x297/0x500 [ 95.582298] [] ? init_fpu+0xef/0x160 [ 95.582298] [] ? do_debug+0x180/0x180 [ 95.582298] [] ? fpu_finit+0x28/0x80 [ 95.582298] [] sys_ioctl+0x87/0x90 [ 95.582298] [] sysenter_do_call+0x12/0x38 ... Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index aca71c087a1..b074bd698cf 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -795,11 +795,11 @@ timer: void hci_conn_hash_flush(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; - struct hci_conn *c; + struct hci_conn *c, *n; BT_DBG("hdev %s", hdev->name); - list_for_each_entry_rcu(c, &h->list, list) { + list_for_each_entry_safe(c, n, &h->list, list) { c->state = BT_CLOSED; hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); -- cgit v1.2.3-70-g09d2 From 2a5a5ec620a29d4ba07743c3151cdf0a417c8f8c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 2 Feb 2012 10:32:18 +0200 Subject: Bluetooth: Use list _safe deleting from conn chan_list Fixes possible bug when deleting element from the list in function hci_chan_list_flush. list_for_each_entry_rcu is used and after deleting element from the list we also free pointer and then list_entry_rcu is taken from freed pointer. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b074bd698cf..b4ecddee11b 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -975,10 +975,10 @@ int hci_chan_del(struct hci_chan *chan) void hci_chan_list_flush(struct hci_conn *conn) { - struct hci_chan *chan; + struct hci_chan *chan, *n; BT_DBG("conn %p", conn); - list_for_each_entry_rcu(chan, &conn->chan_list, list) + list_for_each_entry_safe(chan, n, &conn->chan_list, list) hci_chan_del(chan); } -- cgit v1.2.3-70-g09d2 From 650f726d16a3f25153d785b531516f6e90d2014f Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:07:59 -0300 Subject: Bluetooth: Fix doing some useless casts when receiving MGMT commands Every command handler of mgmt does a cast to the command structure so it can properly interpreted. So we can avoid that cast if we make those functions receive a void * directly. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 205 +++++++++++++++++++++------------------------------ 1 file changed, 83 insertions(+), 122 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 00ab083749e..ad898627684 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -611,15 +611,13 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings)); } -static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int set_powered(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_mode *cp; + struct mgmt_mode *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; int err, up; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -664,17 +662,14 @@ failed: return err; } -static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_set_discoverable *cp; + struct mgmt_cp_set_discoverable *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; u8 scan; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -734,17 +729,14 @@ failed: return err; } -static int set_connectable(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_mode *cp; + struct mgmt_mode *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; u8 scan; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -827,16 +819,13 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, return 0; } -static int set_pairable(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_mode *cp; + struct mgmt_mode *cp = data; struct hci_dev *hdev; __le32 ev; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -870,15 +859,13 @@ failed: return err; } -static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_add_uuid *cp; + struct mgmt_cp_add_uuid *cp = data; struct hci_dev *hdev; struct bt_uuid *uuid; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -920,16 +907,14 @@ failed: return err; } -static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) { + struct mgmt_cp_remove_uuid *cp = data; struct list_head *p, *n; - struct mgmt_cp_remove_uuid *cp; struct hci_dev *hdev; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int err, found; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -983,15 +968,12 @@ unlock: return err; } -static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_set_dev_class *cp; + struct mgmt_cp_set_dev_class *cp = data; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -1026,16 +1008,13 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, return err; } -static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_load_link_keys *cp; + struct mgmt_cp_load_link_keys *cp = data; u16 key_count, expected_len; int i; - cp = (void *) data; - if (len < sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); @@ -1085,19 +1064,16 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, return 0; } -static int remove_keys(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_remove_keys *cp; + struct mgmt_cp_remove_keys *cp = data; struct mgmt_rp_remove_keys rp; struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; int err; - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, MGMT_STATUS_INVALID_PARAMS); @@ -1154,10 +1130,10 @@ unlock: return err; } -static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int disconnect(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_disconnect *cp; + struct mgmt_cp_disconnect *cp = data; struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; @@ -1165,8 +1141,6 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_DISCONNECT, MGMT_STATUS_INVALID_PARAMS); @@ -1314,12 +1288,11 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index, return err; } -static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct hci_conn *conn; - struct mgmt_cp_pin_code_reply *cp; + struct mgmt_cp_pin_code_reply *cp = data; struct mgmt_cp_pin_code_neg_reply ncp; struct hci_cp_pin_code_reply reply; struct pending_cmd *cmd; @@ -1327,8 +1300,6 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); @@ -1366,7 +1337,8 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, goto failed; } - cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len); + cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, + len); if (!cmd) { err = -ENOMEM; goto failed; @@ -1387,17 +1359,14 @@ failed: return err; } -static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_pin_code_neg_reply *cp; + struct mgmt_cp_pin_code_neg_reply *cp = data; int err; BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); @@ -1424,16 +1393,13 @@ failed: return err; } -static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_set_io_capability *cp; + struct mgmt_cp_set_io_capability *cp = data; BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, MGMT_STATUS_INVALID_PARAMS); @@ -1508,10 +1474,10 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) pairing_complete(cmd, status); } -static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int pair_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_pair_device *cp; + struct mgmt_cp_pair_device *cp = data; struct mgmt_rp_pair_device rp; struct pending_cmd *cmd; u8 sec_level, auth_type; @@ -1520,8 +1486,6 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); @@ -1721,7 +1685,7 @@ done: static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_user_confirm_reply *cp = (void *) data; + struct mgmt_cp_user_confirm_reply *cp = data; BT_DBG(""); @@ -1752,7 +1716,7 @@ static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_user_passkey_reply *cp = (void *) data; + struct mgmt_cp_user_passkey_reply *cp = data; BT_DBG(""); @@ -1768,7 +1732,7 @@ static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data; + struct mgmt_cp_user_passkey_neg_reply *cp = data; BT_DBG(""); @@ -1781,10 +1745,10 @@ static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } -static int set_local_name(struct sock *sk, u16 index, unsigned char *data, +static int set_local_name(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; + struct mgmt_cp_set_local_name *mgmt_cp = data; struct hci_cp_write_local_name hci_cp; struct hci_dev *hdev; struct pending_cmd *cmd; @@ -1803,7 +1767,8 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, hci_dev_lock(hdev); - cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, + len); if (!cmd) { err = -ENOMEM; goto failed; @@ -1872,11 +1837,11 @@ unlock: return err; } -static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int add_remote_oob_data(struct sock *sk, u16 index, void *data, + u16 len) { struct hci_dev *hdev; - struct mgmt_cp_add_remote_oob_data *cp = (void *) data; + struct mgmt_cp_add_remote_oob_data *cp = data; int err; BT_DBG("hci%u ", index); @@ -1908,10 +1873,10 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, } static int remove_remote_oob_data(struct sock *sk, u16 index, - unsigned char *data, u16 len) + void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_remove_remote_oob_data *cp = (void *) data; + struct mgmt_cp_remove_remote_oob_data *cp = data; int err; BT_DBG("hci%u ", index); @@ -1942,9 +1907,9 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, } static int start_discovery(struct sock *sk, u16 index, - unsigned char *data, u16 len) + void *data, u16 len) { - struct mgmt_cp_start_discovery *cp = (void *) data; + struct mgmt_cp_start_discovery *cp = data; struct pending_cmd *cmd; struct hci_dev *hdev; int err; @@ -2054,10 +2019,9 @@ unlock: return err; } -static int confirm_name(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_confirm_name *cp = (void *) data; + struct mgmt_cp_confirm_name *cp = data; struct inquiry_entry *e; struct hci_dev *hdev; int err; @@ -2104,11 +2068,10 @@ failed: return err; } -static int block_device(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int block_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_block_device *cp = (void *) data; + struct mgmt_cp_block_device *cp = data; int err; BT_DBG("hci%u", index); @@ -2138,11 +2101,10 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, return err; } -static int unblock_device(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_unblock_device *cp = (void *) data; + struct mgmt_cp_unblock_device *cp = data; int err; BT_DBG("hci%u", index); @@ -2174,10 +2136,10 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, } static int set_fast_connectable(struct sock *sk, u16 index, - unsigned char *data, u16 len) + void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_mode *cp = (void *) data; + struct mgmt_mode *cp = data; struct hci_cp_write_page_scan_activity acp; u8 type; int err; @@ -2231,7 +2193,8 @@ done: int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { - unsigned char *buf; + void *buf; + u8 *cp; struct mgmt_hdr *hdr; u16 opcode, index, len; int err; @@ -2250,7 +2213,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } - hdr = (struct mgmt_hdr *) buf; + hdr = buf; opcode = get_unaligned_le16(&hdr->opcode); index = get_unaligned_le16(&hdr->index); len = get_unaligned_le16(&hdr->len); @@ -2260,6 +2223,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } + cp = buf + sizeof(*hdr); + switch (opcode) { case MGMT_OP_READ_VERSION: err = read_version(sk); @@ -2271,98 +2236,94 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = read_controller_info(sk, index); break; case MGMT_OP_SET_POWERED: - err = set_powered(sk, index, buf + sizeof(*hdr), len); + err = set_powered(sk, index, cp, len); break; case MGMT_OP_SET_DISCOVERABLE: - err = set_discoverable(sk, index, buf + sizeof(*hdr), len); + err = set_discoverable(sk, index, cp, len); break; case MGMT_OP_SET_CONNECTABLE: - err = set_connectable(sk, index, buf + sizeof(*hdr), len); + err = set_connectable(sk, index, cp, len); break; case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, index, buf + sizeof(*hdr), - len); + err = set_fast_connectable(sk, index, cp, len); break; case MGMT_OP_SET_PAIRABLE: - err = set_pairable(sk, index, buf + sizeof(*hdr), len); + err = set_pairable(sk, index, cp, len); break; case MGMT_OP_ADD_UUID: - err = add_uuid(sk, index, buf + sizeof(*hdr), len); + err = add_uuid(sk, index, cp, len); break; case MGMT_OP_REMOVE_UUID: - err = remove_uuid(sk, index, buf + sizeof(*hdr), len); + err = remove_uuid(sk, index, cp, len); break; case MGMT_OP_SET_DEV_CLASS: - err = set_dev_class(sk, index, buf + sizeof(*hdr), len); + err = set_dev_class(sk, index, cp, len); break; case MGMT_OP_LOAD_LINK_KEYS: - err = load_link_keys(sk, index, buf + sizeof(*hdr), len); + err = load_link_keys(sk, index, cp, len); break; case MGMT_OP_REMOVE_KEYS: - err = remove_keys(sk, index, buf + sizeof(*hdr), len); + err = remove_keys(sk, index, cp, len); break; case MGMT_OP_DISCONNECT: - err = disconnect(sk, index, buf + sizeof(*hdr), len); + err = disconnect(sk, index, cp, len); break; case MGMT_OP_GET_CONNECTIONS: err = get_connections(sk, index); break; case MGMT_OP_PIN_CODE_REPLY: - err = pin_code_reply(sk, index, buf + sizeof(*hdr), len); + err = pin_code_reply(sk, index, cp, len); break; case MGMT_OP_PIN_CODE_NEG_REPLY: - err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len); + err = pin_code_neg_reply(sk, index, cp, len); break; case MGMT_OP_SET_IO_CAPABILITY: - err = set_io_capability(sk, index, buf + sizeof(*hdr), len); + err = set_io_capability(sk, index, cp, len); break; case MGMT_OP_PAIR_DEVICE: - err = pair_device(sk, index, buf + sizeof(*hdr), len); + err = pair_device(sk, index, cp, len); break; case MGMT_OP_CANCEL_PAIR_DEVICE: err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); break; case MGMT_OP_USER_CONFIRM_REPLY: - err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len); + err = user_confirm_reply(sk, index, cp, len); break; case MGMT_OP_USER_CONFIRM_NEG_REPLY: - err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr), - len); + err = user_confirm_neg_reply(sk, index, cp, len); break; case MGMT_OP_USER_PASSKEY_REPLY: - err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len); + err = user_passkey_reply(sk, index, cp, len); break; case MGMT_OP_USER_PASSKEY_NEG_REPLY: - err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr), - len); + err = user_passkey_neg_reply(sk, index, cp, len); break; case MGMT_OP_SET_LOCAL_NAME: - err = set_local_name(sk, index, buf + sizeof(*hdr), len); + err = set_local_name(sk, index, cp, len); break; case MGMT_OP_READ_LOCAL_OOB_DATA: err = read_local_oob_data(sk, index); break; case MGMT_OP_ADD_REMOTE_OOB_DATA: - err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len); + err = add_remote_oob_data(sk, index, cp, len); break; case MGMT_OP_REMOVE_REMOTE_OOB_DATA: - err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), - len); + err = remove_remote_oob_data(sk, index, cp, len); break; case MGMT_OP_START_DISCOVERY: - err = start_discovery(sk, index, buf + sizeof(*hdr), len); + err = start_discovery(sk, index, cp, len); break; case MGMT_OP_STOP_DISCOVERY: err = stop_discovery(sk, index); break; case MGMT_OP_CONFIRM_NAME: - err = confirm_name(sk, index, buf + sizeof(*hdr), len); + err = confirm_name(sk, index, cp, len); break; case MGMT_OP_BLOCK_DEVICE: - err = block_device(sk, index, buf + sizeof(*hdr), len); + err = block_device(sk, index, cp, len); break; case MGMT_OP_UNBLOCK_DEVICE: - err = unblock_device(sk, index, buf + sizeof(*hdr), len); + err = unblock_device(sk, index, cp, len); break; default: BT_DBG("Unknown op %u", opcode); -- cgit v1.2.3-70-g09d2 From b899efaf9b26cadb084752862490b4fc44bc3169 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:00 -0300 Subject: Bluetooth: Add new structures for handling SMP Long Term Keys This includes a new list for storing the keys and a new structure used to represent each key. Some notes: authenticated is used to identify that the key may be used to setup a HIGH security link. As the same list is used to store both the STK's and the LTK's the type field is used so we can separate between those two types of keys and if the key should be used when in the master or slave role. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 5 +++++ include/net/bluetooth/hci_core.h | 16 ++++++++++++++++ net/bluetooth/hci_core.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index cb9097acbf4..83f045a515a 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -274,6 +274,11 @@ enum { #define HCI_LK_SMP_LTK 0x81 #define HCI_LK_SMP_IRK 0x82 #define HCI_LK_SMP_CSRK 0x83 +/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */ +#define HCI_SMP_STK 0x80 +#define HCI_SMP_STK_SLAVE 0x81 +#define HCI_SMP_LTK 0x82 +#define HCI_SMP_LTK_SLAVE 0x83 /* ---- HCI Error Codes ---- */ #define HCI_ERROR_AUTH_FAILURE 0x05 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 896d9e4955f..c998176a503 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -88,6 +88,18 @@ struct bt_uuid { u8 svc_hint; }; +struct smp_ltk { + struct list_head list; + bdaddr_t bdaddr; + u8 bdaddr_type; + u8 authenticated; + u8 type; + u8 enc_size; + __le16 ediv; + u8 rand[8]; + u8 val[16]; +} __packed; + struct key_master_id { __le16 ediv; u8 rand[8]; @@ -239,6 +251,8 @@ struct hci_dev { struct list_head link_keys; + struct list_head long_term_keys; + struct list_head remote_oob_data; struct list_head adv_entries; @@ -647,8 +661,10 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); struct link_key *hci_find_link_key_type(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]); +int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remote_oob_data_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 45e2d2a72b1..a28e637152f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1163,6 +1163,18 @@ int hci_link_keys_clear(struct hci_dev *hdev) return 0; } +int hci_smp_ltks_clear(struct hci_dev *hdev) +{ + struct smp_ltk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + list_del(&k->list); + kfree(k); + } + + return 0; +} + struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *k; @@ -1355,6 +1367,23 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return 0; } +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct smp_ltk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + if (bacmp(bdaddr, &k->bdaddr)) + continue; + + BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); + + list_del(&k->list); + kfree(k); + } + + return 0; +} + /* HCI command timer function */ static void hci_cmd_timer(unsigned long arg) { @@ -1638,6 +1667,7 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); + INIT_LIST_HEAD(&hdev->long_term_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); @@ -1739,6 +1769,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_blacklist_clear(hdev); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); + hci_smp_ltks_clear(hdev); hci_remote_oob_data_clear(hdev); hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); -- cgit v1.2.3-70-g09d2 From c9839a11c0e460a2457e7cac76650d07773e6c3b Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:01 -0300 Subject: Bluetooth: Use the updated key structures for handling LTKs This updates all the users of the older way, that was using the link_keys list to store the SMP keys, to use the new way. This includes defining new types for the keys, we have a type for each combination of STK/LTK and Master/Slave. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 11 +++--- net/bluetooth/hci_core.c | 76 +++++++++++++++++----------------------- net/bluetooth/hci_event.c | 11 ++++-- net/bluetooth/smp.c | 38 ++++++++++++-------- 4 files changed, 71 insertions(+), 65 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c998176a503..2649caf4db9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -658,12 +658,13 @@ int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); -struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); -struct link_key *hci_find_link_key_type(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type); +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); +int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, + int new_key, u8 authenticated, u8 tk[16], + u8 enc_size, u16 ediv, u8 rand[8]); +struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a28e637152f..84b7a9e4f2f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1222,41 +1222,35 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return 0; } -struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) { - struct link_key *k; - - list_for_each_entry(k, &hdev->link_keys, list) { - struct key_master_id *id; + struct smp_ltk *k; - if (k->type != HCI_LK_SMP_LTK) + list_for_each_entry(k, &hdev->long_term_keys, list) { + if (k->ediv != ediv || + memcmp(rand, k->rand, sizeof(k->rand))) continue; - if (k->dlen != sizeof(*id)) - continue; - - id = (void *) &k->data; - if (id->ediv == ediv && - (memcmp(rand, id->rand, sizeof(id->rand)) == 0)) - return k; + return k; } return NULL; } EXPORT_SYMBOL(hci_find_ltk); -struct link_key *hci_find_link_key_type(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type) +struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type) { - struct link_key *k; + struct smp_ltk *k; - list_for_each_entry(k, &hdev->link_keys, list) - if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0) + list_for_each_entry(k, &hdev->long_term_keys, list) + if (addr_type == k->bdaddr_type && + bacmp(bdaddr, &k->bdaddr) == 0) return k; return NULL; } -EXPORT_SYMBOL(hci_find_link_key_type); +EXPORT_SYMBOL(hci_find_ltk_by_addr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) @@ -1313,40 +1307,36 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, return 0; } -int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]) +int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, + int new_key, u8 authenticated, u8 tk[16], + u8 enc_size, u16 ediv, u8 rand[8]) { - struct link_key *key, *old_key; - struct key_master_id *id; - u8 old_key_type; + struct smp_ltk *key, *old_key; - BT_DBG("%s addr %s", hdev->name, batostr(bdaddr)); + if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK)) + return 0; - old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK); - if (old_key) { + old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type); + if (old_key) key = old_key; - old_key_type = old_key->type; - } else { - key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC); + else { + key = kzalloc(sizeof(*key), GFP_ATOMIC); if (!key) return -ENOMEM; - list_add(&key->list, &hdev->link_keys); - old_key_type = 0xff; + list_add(&key->list, &hdev->long_term_keys); } - key->dlen = sizeof(*id); - bacpy(&key->bdaddr, bdaddr); - memcpy(key->val, ltk, sizeof(key->val)); - key->type = HCI_LK_SMP_LTK; - key->pin_len = key_size; - - id = (void *) &key->data; - id->ediv = ediv; - memcpy(id->rand, rand, sizeof(id->rand)); + key->bdaddr_type = addr_type; + memcpy(key->val, tk, sizeof(key->val)); + key->authenticated = authenticated; + key->ediv = ediv; + key->enc_size = enc_size; + key->type = type; + memcpy(key->rand, rand, sizeof(key->rand)); - if (new_key) - mgmt_new_link_key(hdev, key, old_key_type); + if (!new_key) + return 0; return 0; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a86f82b1131..23dbb31f042 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3256,7 +3256,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, struct hci_cp_le_ltk_reply cp; struct hci_cp_le_ltk_neg_reply neg; struct hci_conn *conn; - struct link_key *ltk; + struct smp_ltk *ltk; BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); @@ -3272,10 +3272,17 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, memcpy(cp.ltk, ltk->val, sizeof(ltk->val)); cp.handle = cpu_to_le16(conn->handle); - conn->pin_length = ltk->pin_len; + + if (ltk->authenticated) + conn->sec_level = BT_SECURITY_HIGH; hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); + if (ltk->type & HCI_SMP_STK) { + list_del(<k->list); + kfree(ltk); + } + hci_dev_unlock(hdev); return; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9ff56e18d99..0563f737779 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -475,8 +475,9 @@ static void random_work(struct work_struct *work) memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); - hci_add_ltk(hcon->hdev, 0, conn->dst, smp->enc_key_size, - ediv, rand, stk); + hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type, + HCI_SMP_STK_SLAVE, 0, 0, stk, + smp->enc_key_size, ediv, rand); } return; @@ -701,22 +702,18 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_ltk_encrypt(struct l2cap_conn *conn) { - struct link_key *key; - struct key_master_id *master; + struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; - key = hci_find_link_key_type(hcon->hdev, conn->dst, - HCI_LK_SMP_LTK); + key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type); if (!key) return 0; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return 1; - master = (void *) key->data; - hci_le_start_enc(hcon, master->ediv, master->rand, - key->val); - hcon->enc_key_size = key->pin_len; + hci_le_start_enc(hcon, key->ediv, key->rand, key->val); + hcon->enc_key_size = key->enc_size; return 1; @@ -819,13 +816,19 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; + struct hci_dev *hdev = conn->hcon->hdev; + struct hci_conn *hcon = conn->hcon; + u8 authenticated; skb_pull(skb, sizeof(*rp)); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, - rp->ediv, rp->rand, smp->tk); - + hci_dev_lock(hdev); + authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH); + hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, + HCI_SMP_LTK, 1, authenticated, smp->tk, + smp->enc_key_size, rp->ediv, rp->rand); smp_distribute_keys(conn, 1); + hci_dev_unlock(hdev); return 0; } @@ -935,6 +938,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) if (*keydist & SMP_DIST_ENC_KEY) { struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; + struct hci_conn *hcon = conn->hcon; + u8 authenticated; __le16 ediv; get_random_bytes(enc.ltk, sizeof(enc.ltk)); @@ -943,8 +948,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, - ediv, ident.rand, enc.ltk); + authenticated = hcon->sec_level == BT_SECURITY_HIGH; + hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, + HCI_SMP_LTK_SLAVE, 1, authenticated, + enc.ltk, smp->enc_key_size, + ediv, ident.rand); ident.ediv = cpu_to_le16(ediv); -- cgit v1.2.3-70-g09d2 From 346af67b8d116f01ef696fd47959a55deb2db8b6 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:02 -0300 Subject: Bluetooth: Add MGMT handlers for dealing with SMP LTK's This adds a method to notify that a new LTK is available and a handler to store keys coming from userspace into the kernel LTK list. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 + net/bluetooth/mgmt.c | 80 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2649caf4db9..7793fc644b8 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -995,6 +995,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr); +int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); + /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ad898627684..fd0b08115f2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2191,6 +2191,60 @@ done: return err; } +static int load_long_term_keys(struct sock *sk, u16 index, + void *cp_data, u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_load_long_term_keys *cp = cp_data; + u16 key_count, expected_len; + int i; + + if (len < sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + EINVAL); + + key_count = get_unaligned_le16(&cp->key_count); + + expected_len = sizeof(*cp) + key_count * + sizeof(struct mgmt_ltk_info); + if (expected_len != len) { + BT_ERR("load_keys: expected %u bytes, got %u bytes", + len, expected_len); + return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + EINVAL); + } + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + ENODEV); + + BT_DBG("hci%u key_count %u", index, key_count); + + hci_dev_lock(hdev); + + hci_smp_ltks_clear(hdev); + + for (i = 0; i < key_count; i++) { + struct mgmt_ltk_info *key = &cp->keys[i]; + u8 type; + + if (key->master) + type = HCI_SMP_LTK; + else + type = HCI_SMP_LTK_SLAVE; + + hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type, + type, 0, key->authenticated, key->val, + key->enc_size, key->ediv, key->rand); + } + + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return 0; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { void *buf; @@ -2325,6 +2379,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_UNBLOCK_DEVICE: err = unblock_device(sk, index, cp, len); break; + case MGMT_OP_LOAD_LONG_TERM_KEYS: + err = load_long_term_keys(sk, index, cp, len); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, @@ -2478,6 +2535,29 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } +int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) +{ + struct mgmt_ev_new_long_term_key ev; + + memset(&ev, 0, sizeof(ev)); + + ev.store_hint = persistent; + bacpy(&ev.key.addr.bdaddr, &key->bdaddr); + ev.key.addr.type = key->bdaddr_type; + ev.key.authenticated = key->authenticated; + ev.key.enc_size = key->enc_size; + ev.key.ediv = key->ediv; + + if (key->type == HCI_SMP_LTK) + ev.key.master = 1; + + memcpy(ev.key.rand, key->rand, sizeof(key->rand)); + memcpy(ev.key.val, key->val, sizeof(key->val)); + + return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, + &ev, sizeof(ev), NULL); +} + int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *name, u8 name_len, u8 *dev_class) -- cgit v1.2.3-70-g09d2 From b0dbfb46ba0c0d2fe4c90e2046f7b36275763a7e Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:03 -0300 Subject: Bluetooth: Add support for removing LTK's when pairing is removed Instead of having a separated command for removing SMP keys, we use the Remove Keys command to remove *all* keys. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fd0b08115f2..9e5dead1dbe 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1089,6 +1089,12 @@ static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) bacpy(&rp.bdaddr, &cp->bdaddr); rp.status = MGMT_STATUS_FAILED; + err = hci_remove_ltk(hdev, &cp->bdaddr); + if (err < 0) { + err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err); + goto unlock; + } + err = hci_remove_link_key(hdev, &cp->bdaddr); if (err < 0) { rp.status = MGMT_STATUS_NOT_PAIRED; -- cgit v1.2.3-70-g09d2 From 261cc5aa9e54aac633dcc3b6469739cb6e23e21a Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:05 -0300 Subject: Bluetooth: Add support for notifying userspace of new LTK's If we want to have proper pairing support over LE we need to inform userspace that a new LTK is available, so userspace can store that key permanently. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 84b7a9e4f2f..76dc1538e32 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1338,6 +1338,9 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (!new_key) return 0; + if (type & HCI_SMP_LTK) + mgmt_new_ltk(hdev, key, 1); + return 0; } -- cgit v1.2.3-70-g09d2 From b71d385a18cd4516c62d0198c9ec37e658112f75 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 3 Feb 2012 16:27:54 +0200 Subject: Bluetooth: Recalculate sched HCI blk/pkt flow ctrl Split HCI scheduling for block and packet flow control. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 85 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 76dc1538e32..9a56a408448 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2384,18 +2384,19 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) } -static inline void hci_sched_acl(struct hci_dev *hdev) +static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) +{ + /* Calculate count of blocks used by this packet */ + return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); +} + +static inline void hci_sched_acl_pkt(struct hci_dev *hdev) { struct hci_chan *chan; struct sk_buff *skb; int quote; unsigned int cnt; - BT_DBG("%s", hdev->name); - - if (!hci_conn_num(hdev, ACL_LINK)) - return; - if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ @@ -2435,6 +2436,78 @@ static inline void hci_sched_acl(struct hci_dev *hdev) hci_prio_recalculate(hdev, ACL_LINK); } +static inline void hci_sched_acl_blk(struct hci_dev *hdev) +{ + struct hci_chan *chan; + struct sk_buff *skb; + int quote; + unsigned int cnt; + + if (!test_bit(HCI_RAW, &hdev->flags)) { + /* ACL tx timeout must be longer than maximum + * link supervision timeout (40.9 seconds) */ + if (!hdev->block_cnt && time_after(jiffies, hdev->acl_last_tx + + msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) + hci_link_tx_to(hdev, ACL_LINK); + } + + cnt = hdev->block_cnt; + + while (hdev->block_cnt > 0 && + (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { + u32 priority = (skb_peek(&chan->data_q))->priority; + while (quote > 0 && (skb = skb_peek(&chan->data_q))) { + int blocks; + + BT_DBG("chan %p skb %p len %d priority %u", chan, skb, + skb->len, skb->priority); + + /* Stop if priority has changed */ + if (skb->priority < priority) + break; + + skb = skb_dequeue(&chan->data_q); + + blocks = __get_blocks(hdev, skb); + if (blocks > hdev->block_cnt) + return; + + hci_conn_enter_active_mode(chan->conn, + bt_cb(skb)->force_active); + + hci_send_frame(skb); + hdev->acl_last_tx = jiffies; + + hdev->block_cnt -= blocks; + quote -= blocks; + + chan->sent += blocks; + chan->conn->sent += blocks; + } + } + + if (cnt != hdev->block_cnt) + hci_prio_recalculate(hdev, ACL_LINK); +} + +static inline void hci_sched_acl(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (!hci_conn_num(hdev, ACL_LINK)) + return; + + switch (hdev->flow_ctl_mode) { + case HCI_FLOW_CTL_MODE_PACKET_BASED: + hci_sched_acl_pkt(hdev); + break; + + case HCI_FLOW_CTL_MODE_BLOCK_BASED: + hci_sched_acl_blk(hdev); + break; + } +} + /* Schedule SCO */ static inline void hci_sched_sco(struct hci_dev *hdev) { -- cgit v1.2.3-70-g09d2 From 63d2bc1b9a4d77f90b9719c3ff2570a274a7a22f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 3 Feb 2012 16:27:55 +0200 Subject: Bluetooth: Helper removes duplicated code Use __check_timout helper to remove duplicated code Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9a56a408448..95eeae59812 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2390,22 +2390,25 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); } -static inline void hci_sched_acl_pkt(struct hci_dev *hdev) +static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt) { - struct hci_chan *chan; - struct sk_buff *skb; - int quote; - unsigned int cnt; - if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ - if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + + if (!cnt && time_after(jiffies, hdev->acl_last_tx + msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) hci_link_tx_to(hdev, ACL_LINK); } +} - cnt = hdev->acl_cnt; +static inline void hci_sched_acl_pkt(struct hci_dev *hdev) +{ + unsigned int cnt = hdev->acl_cnt; + struct hci_chan *chan; + struct sk_buff *skb; + int quote; + + __check_timeout(hdev, cnt); while (hdev->acl_cnt && (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { @@ -2438,20 +2441,12 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev) static inline void hci_sched_acl_blk(struct hci_dev *hdev) { + unsigned int cnt = hdev->block_cnt; struct hci_chan *chan; struct sk_buff *skb; int quote; - unsigned int cnt; - - if (!test_bit(HCI_RAW, &hdev->flags)) { - /* ACL tx timeout must be longer than maximum - * link supervision timeout (40.9 seconds) */ - if (!hdev->block_cnt && time_after(jiffies, hdev->acl_last_tx + - msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) - hci_link_tx_to(hdev, ACL_LINK); - } - cnt = hdev->block_cnt; + __check_timeout(hdev, cnt); while (hdev->block_cnt > 0 && (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { -- cgit v1.2.3-70-g09d2 From 8af59467412b4b61850d3ccb3737c09ecc6dc100 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 3 Feb 2012 21:29:40 +0200 Subject: Bluetooth: Add missing QUIRK_NO_RESET test to hci_dev_do_close We should only perform a reset in hci_dev_do_close if the HCI_QUIRK_NO_RESET flag is set (since in such a case a reset will not be performed when initializing the device). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 95eeae59812..8bffd3eb344 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -767,7 +767,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Reset device */ skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); - if (!test_bit(HCI_RAW, &hdev->flags)) { + if (!test_bit(HCI_RAW, &hdev->flags) && + test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { set_bit(HCI_INIT, &hdev->flags); __hci_request(hdev, hci_reset_req, 0, msecs_to_jiffies(250)); -- cgit v1.2.3-70-g09d2 From c599008f8f999dab8cb4a6404be99bdc4716ba15 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:47:57 -0300 Subject: Bluetooth: LE scan should send Discovering events Send MGMT Discovering events once LE scan starts/stops so the userspace can track when local adapters are discovering LE devices. This way, we also keep the same behavior of inquiry which sends MGMT Discovering events once inquiry starts/stops even if it is triggered by an external tool (e.g. hcitool). Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 2 ++ net/bluetooth/hci_event.c | 5 +++++ 3 files changed, 8 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9751da78341..bf2ef566788 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -61,6 +61,7 @@ struct discovery_state { DISCOVERY_STOPPED, DISCOVERY_STARTING, DISCOVERY_INQUIRY, + DISCOVERY_LE_SCAN, DISCOVERY_RESOLVING, DISCOVERY_STOPPING, } state; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8bffd3eb344..1705d937272 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -361,6 +361,7 @@ bool hci_discovery_active(struct hci_dev *hdev) struct discovery_state *discov = &hdev->discovery; if (discov->state == DISCOVERY_INQUIRY || + discov->state == DISCOVERY_LE_SCAN || discov->state == DISCOVERY_RESOLVING) return true; @@ -381,6 +382,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) case DISCOVERY_STARTING: break; case DISCOVERY_INQUIRY: + case DISCOVERY_LE_SCAN: mgmt_discovering(hdev, 1); break; case DISCOVERY_RESOLVING: diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 23dbb31f042..8971c18205c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1056,12 +1056,17 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, hci_dev_lock(hdev); hci_adv_entries_clear(hdev); + hci_discovery_set_state(hdev, DISCOVERY_LE_SCAN); hci_dev_unlock(hdev); break; case LE_SCANNING_DISABLED: clear_bit(HCI_LE_SCAN, &hdev->dev_flags); + hci_dev_lock(hdev); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + hci_dev_unlock(hdev); + schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); break; -- cgit v1.2.3-70-g09d2 From 6fbe195dc41c4fae1fa7aca1a38c888de1d24e2d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:47:58 -0300 Subject: Bluetooth: Minor code refactoring This patch does a trivial code refacting in hci_discovery_active. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1705d937272..1175f27bd44 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -360,12 +360,15 @@ bool hci_discovery_active(struct hci_dev *hdev) { struct discovery_state *discov = &hdev->discovery; - if (discov->state == DISCOVERY_INQUIRY || - discov->state == DISCOVERY_LE_SCAN || - discov->state == DISCOVERY_RESOLVING) + switch (discov->state) { + case DISCOVERY_INQUIRY: + case DISCOVERY_LE_SCAN: + case DISCOVERY_RESOLVING: return true; - return false; + default: + return false; + } } void hci_discovery_set_state(struct hci_dev *hdev, int state) -- cgit v1.2.3-70-g09d2 From 7ba8b4be38e7c83b2b13333a82a0ecde921a7390 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:47:59 -0300 Subject: Bluetooth: Add hci_do_le_scan() This patch adds to hci_core the hci_do_le_scan function which should be used to scan LE devices. In order to enable LE scan, hci_do_le_scan() sends commands (Set LE Scan Parameters and Set LE Scan Enable) to the controller and waits for its results. If commands were executed successfully a delayed work is scheduled to disable the ongoing scanning after some amount of time. This function blocks. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 8 +++++ net/bluetooth/hci_core.c | 74 ++++++++++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 13 +++++-- 3 files changed, 92 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bf2ef566788..3e70872bffe 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -122,6 +122,12 @@ struct adv_entry { u8 bdaddr_type; }; +struct le_scan_params { + u8 type; + u16 interval; + u16 window; +}; + #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; @@ -261,6 +267,8 @@ struct hci_dev { unsigned long dev_flags; + struct delayed_work le_scan_disable; + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1175f27bd44..ae86cdd80ac 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -759,6 +759,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) cancel_delayed_work(&hdev->service_cache); + cancel_delayed_work_sync(&hdev->le_scan_disable); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); @@ -1596,6 +1598,76 @@ int hci_add_adv_entry(struct hci_dev *hdev, return 0; } +static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) +{ + struct le_scan_params *param = (struct le_scan_params *) opt; + struct hci_cp_le_set_scan_param cp; + + memset(&cp, 0, sizeof(cp)); + cp.type = param->type; + cp.interval = cpu_to_le16(param->interval); + cp.window = cpu_to_le16(param->window); + + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp); +} + +static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) +{ + struct hci_cp_le_set_scan_enable cp; + + memset(&cp, 0, sizeof(cp)); + cp.enable = 1; + + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); +} + +static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, + u16 window, int timeout) +{ + long timeo = msecs_to_jiffies(3000); + struct le_scan_params param; + int err; + + BT_DBG("%s", hdev->name); + + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return -EINPROGRESS; + + param.type = type; + param.interval = interval; + param.window = window; + + hci_req_lock(hdev); + + err = __hci_request(hdev, le_scan_param_req, (unsigned long) ¶m, + timeo); + if (!err) + err = __hci_request(hdev, le_scan_enable_req, 0, timeo); + + hci_req_unlock(hdev); + + if (err < 0) + return err; + + schedule_delayed_work(&hdev->le_scan_disable, + msecs_to_jiffies(timeout)); + + return 0; +} + +static void le_scan_disable_work(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, + le_scan_disable.work); + struct hci_cp_le_set_scan_enable cp; + + BT_DBG("%s", hdev->name); + + memset(&cp, 0, sizeof(cp)); + + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); +} + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1682,6 +1754,8 @@ int hci_register_dev(struct hci_dev *hdev) atomic_set(&hdev->promisc, 0); + INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); + write_unlock(&hci_dev_list_lock); hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8971c18205c..97152d9d711 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1031,6 +1031,8 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); + + hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status); } static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, @@ -1041,15 +1043,17 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - return; - cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); if (!cp) return; switch (cp->enable) { case LE_SCANNING_ENABLED: + hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status); + + if (status) + return; + set_bit(HCI_LE_SCAN, &hdev->dev_flags); cancel_delayed_work_sync(&hdev->adv_work); @@ -1061,6 +1065,9 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, break; case LE_SCANNING_DISABLED: + if (status) + return; + clear_bit(HCI_LE_SCAN, &hdev->dev_flags); hci_dev_lock(hdev); -- cgit v1.2.3-70-g09d2 From 28b75a89480df99a17c8facd5c33985847d06bb6 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:48:00 -0300 Subject: Bluetooth: Add hci_le_scan() We are not supposed to block in start_discovery() because start_discovery code is running in write() syscall context and this would block the write operation on the mgmt socket. This way, we cannot directly call hci_do_le_scan() to scan LE devices in start_discovery(). To overcome this issue a derefered work (hdev->le_scan) was created so we can properly call hci_do_le_scan(). The helper function hci_le_scan() simply set LE scan parameters and queue hdev->le_scan work. The work is queued on system_long_wq since it can sleep for a few seconds in the worst case (timeout). Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 6 ++++++ net/bluetooth/hci_core.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3e70872bffe..7107790817a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -126,6 +126,7 @@ struct le_scan_params { u8 type; u16 interval; u16 window; + int timeout; }; #define NUM_REASSEMBLY 4 @@ -269,6 +270,9 @@ struct hci_dev { struct delayed_work le_scan_disable; + struct work_struct le_scan; + struct le_scan_params le_scan_params; + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); @@ -1033,5 +1037,7 @@ void hci_le_ltk_neg_reply(struct hci_conn *conn); int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); +int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, + int timeout); #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ae86cdd80ac..3d09f4b4ca6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -735,6 +735,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); + cancel_work_sync(&hdev->le_scan); + hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); @@ -1668,6 +1670,37 @@ static void le_scan_disable_work(struct work_struct *work) hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } +static void le_scan_work(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan); + struct le_scan_params *param = &hdev->le_scan_params; + + BT_DBG("%s", hdev->name); + + hci_do_le_scan(hdev, param->type, param->interval, + param->window, param->timeout); +} + +int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, + int timeout) +{ + struct le_scan_params *param = &hdev->le_scan_params; + + BT_DBG("%s", hdev->name); + + if (work_busy(&hdev->le_scan)) + return -EINPROGRESS; + + param->type = type; + param->interval = interval; + param->window = window; + param->timeout = timeout; + + queue_work(system_long_wq, &hdev->le_scan); + + return 0; +} + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1754,6 +1787,8 @@ int hci_register_dev(struct hci_dev *hdev) atomic_set(&hdev->promisc, 0); + INIT_WORK(&hdev->le_scan, le_scan_work); + INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); write_unlock(&hci_dev_list_lock); -- cgit v1.2.3-70-g09d2 From 3fd2415363629b779549705f341e0645e32c1ad5 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:48:01 -0300 Subject: Bluetooth: MGMT start discovery LE-Only support This patch adds LE-Only discovery procedure support to MGMT Start Discovery command. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 13 ++++++++++++- net/bluetooth/mgmt.c | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 97152d9d711..ad5f37b13f7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1033,6 +1033,13 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status); + + if (status) { + hci_dev_lock(hdev); + mgmt_start_discovery_failed(hdev, status); + hci_dev_unlock(hdev); + return; + } } static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, @@ -1051,8 +1058,12 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, case LE_SCANNING_ENABLED: hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status); - if (status) + if (status) { + hci_dev_lock(hdev); + mgmt_start_discovery_failed(hdev, status); + hci_dev_unlock(hdev); return; + } set_bit(HCI_LE_SCAN, &hdev->dev_flags); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9e5dead1dbe..8c9de58779c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,6 +35,15 @@ #define MGMT_VERSION 0 #define MGMT_REVISION 1 +/* + * These LE scan and inquiry parameters were chosen according to LE General + * Discovery Procedure specification. + */ +#define LE_SCAN_TYPE 0x01 +#define LE_SCAN_WIN 0x12 +#define LE_SCAN_INT 0x12 +#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */ + #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ #define SERVICE_CACHE_TIMEOUT (5 * 1000) @@ -1916,6 +1925,7 @@ static int start_discovery(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; + unsigned long discov_type = cp->type; struct pending_cmd *cmd; struct hci_dev *hdev; int err; @@ -1951,7 +1961,15 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } - err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + if (test_bit(MGMT_ADDR_BREDR, &discov_type)) + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) && + test_bit(MGMT_ADDR_LE_RANDOM, &discov_type)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + else + err = -EINVAL; + if (err < 0) mgmt_pending_remove(cmd); else -- cgit v1.2.3-70-g09d2 From e87775250f322b8f1612cf9918fcde827948f087 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:48:02 -0300 Subject: Bluetooth: Fix indentation This patch fixes a #define indentation in mgmt.c. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8c9de58779c..de7326b111b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -44,7 +44,7 @@ #define LE_SCAN_INT 0x12 #define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */ -#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ +#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ #define SERVICE_CACHE_TIMEOUT (5 * 1000) -- cgit v1.2.3-70-g09d2 From 053c7e0c4a40e2bb44e3c1e61e263be00688a136 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 4 Feb 2012 00:06:00 +0200 Subject: Bluetooth: Fix device_found event length for remote name resolving The correct length of the event is the size of the ev struct (not size of the pointer like the code was previously using) plus the length of the variable-sized EIR data at the end of the struct. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index de7326b111b..11ee5db16e9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2964,7 +2964,8 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, put_unaligned_le16(eir_len, &ev->eir_len); - return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, + sizeof(*ev) + eir_len, NULL); } int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) -- cgit v1.2.3-70-g09d2 From 343fb14549a736b348b08e702057487a7ec44d5d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 22 Nov 2011 17:14:19 -0300 Subject: Bluetooth: Add BT_DBG to mgmt_discovering() This is helpful for device discovery implementation & debuging. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 11ee5db16e9..77bc5a4b026 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3002,6 +3002,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) { struct pending_cmd *cmd; + BT_DBG("%s discovering %u", hdev->name, discovering); + if (discovering) cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev); else -- cgit v1.2.3-70-g09d2 From cf4cd00915c659dc7b496c454bee36bb6b833fd1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 6 Feb 2012 15:03:59 +0200 Subject: Bluetooth: Change chan_ready param from sk to chan Change is needed to remove dependency on sk when possible before introducing l2cap channel lock. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 09cd8601ea8..80fbfcf0674 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -907,9 +907,9 @@ clean: release_sock(parent); } -static void l2cap_chan_ready(struct sock *sk) +static void l2cap_chan_ready(struct l2cap_chan *chan) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct sock *sk = chan->sk; struct sock *parent = bt_sk(sk)->parent; BT_DBG("sk %p, parent %p", sk, parent); @@ -945,7 +945,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->type == LE_LINK) { if (smp_conn_security(conn, chan->sec_level)) - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); @@ -2874,7 +2874,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); goto unlock; } @@ -3005,7 +3005,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } done: @@ -4524,7 +4524,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (chan->scid == L2CAP_CID_LE_DATA) { if (!status && encrypt) { chan->sec_level = hcon->sec_level; - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } bh_unlock_sock(sk); -- cgit v1.2.3-70-g09d2 From 5491120e75afe2a7f5b6f3a207de6d99934e5475 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 6 Feb 2012 15:04:00 +0200 Subject: Bluetooth: Clean up l2cap_chan_add Change elseif to switch. This make sense even more with following patches which otherwise have to add more elseifs statements. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 80fbfcf0674..48fc01ef16b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -320,7 +320,8 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->conn = conn; - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { + switch (chan->chan_type) { + case L2CAP_CHAN_CONN_ORIENTED: if (conn->hcon->type == LE_LINK) { /* LE connection */ chan->omtu = L2CAP_LE_DEFAULT_MTU; @@ -331,12 +332,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->scid = l2cap_alloc_cid(conn); chan->omtu = L2CAP_DEFAULT_MTU; } - } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { + break; + + case L2CAP_CHAN_CONN_LESS: /* Connectionless socket */ chan->scid = L2CAP_CID_CONN_LESS; chan->dcid = L2CAP_CID_CONN_LESS; chan->omtu = L2CAP_DEFAULT_MTU; - } else { + break; + + default: /* Raw socket can send/recv signalling messages only */ chan->scid = L2CAP_CID_SIGNALING; chan->dcid = L2CAP_CID_SIGNALING; -- cgit v1.2.3-70-g09d2 From 6d5922b01b5e8d684dae5baaea596a4a749738e3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 6 Feb 2012 15:04:01 +0200 Subject: Bluetooth: Remove unneeded sk variable In debug use chan %p instead of sk. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 48fc01ef16b..f1a6b3cbdba 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1561,13 +1561,12 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d priority %u", sk, (int)len, priority); + BT_DBG("chan %p len %d priority %u", chan, (int)len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1597,13 +1596,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, (int)len); + BT_DBG("chan %p len %d", chan, (int)len); count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1632,13 +1630,12 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 control, u16 sdulen) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, (int)len); + BT_DBG("chan %p len %d", chan, (int)len); if (!conn) return ERR_PTR(-ENOTCONN); -- cgit v1.2.3-70-g09d2 From 8ed7a0ae7834cbefb82ed15a92e36983924efa23 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 7 Feb 2012 15:43:01 +0100 Subject: Bluetooth: Fix possible missing I-Frame acknowledgement Make l2cap_ertm_send return number of pending I-Frames transmitted instead of all (pending + retransmitted) I-Frames transmitted. As only pending I-Frames are considered as acknowledgement, this could lead to situation when no ACK was sent in __l2cap_send_ack (if only already transmitted I-Frames were retransmitted). Signed-off-by: Szymon Janc Signed-off-by: Luiz Augusto von Dentz Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f1a6b3cbdba..9add8527165 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1453,8 +1453,10 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); - if (bt_cb(skb)->retries == 1) + if (bt_cb(skb)->retries == 1) { chan->unacked_frames++; + nsent++; + } chan->frames_sent++; @@ -1462,8 +1464,6 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) chan->tx_send_head = NULL; else chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); - - nsent++; } return nsent; -- cgit v1.2.3-70-g09d2 From 930fa4aee934ad59ed82163cdbee4922b883ef79 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 7 Feb 2012 15:43:02 +0100 Subject: Bluetooth: Fix double acking I-Frames when sending pending I-Frames Pending I-Frame(s) are considered as acknowledgement. To void double acking (via I-Frame and later via RR) clear ack timer when sending first pending I-Frame. Signed-off-by: Szymon Janc Signed-off-by: Luiz Augusto von Dentz Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9add8527165..8efac7884ff 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1455,7 +1455,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) if (bt_cb(skb)->retries == 1) { chan->unacked_frames++; - nsent++; + + if (!nsent++) + __clear_ack_timer(chan); } chan->frames_sent++; -- cgit v1.2.3-70-g09d2 From 124f6e35286c9d8dc96f147a9026081256136615 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 13:50:12 +0200 Subject: Bluetooth: Update and rename mgmt_remove_keys to mgmt_unpair_device This patch renames the mgmt_remove_keys command to mgmt_unpair_device and updates its parameters to match the latest API (specifically, it adds an address type parameter to the command and its response). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 34 ++++++++++++------------- net/bluetooth/mgmt.c | 60 +++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 72975fd5398..4c18cd5fb8c 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -175,17 +175,7 @@ struct mgmt_cp_load_long_term_keys { struct mgmt_ltk_info keys[0]; } __packed; -#define MGMT_OP_REMOVE_KEYS 0x0014 -struct mgmt_cp_remove_keys { - bdaddr_t bdaddr; - __u8 disconnect; -} __packed; -struct mgmt_rp_remove_keys { - bdaddr_t bdaddr; - __u8 status; -}; - -#define MGMT_OP_DISCONNECT 0x0015 +#define MGMT_OP_DISCONNECT 0x0014 struct mgmt_cp_disconnect { bdaddr_t bdaddr; } __packed; @@ -194,13 +184,13 @@ struct mgmt_rp_disconnect { __u8 status; } __packed; -#define MGMT_OP_GET_CONNECTIONS 0x0016 +#define MGMT_OP_GET_CONNECTIONS 0x0015 struct mgmt_rp_get_connections { __le16 conn_count; struct mgmt_addr_info addr[0]; } __packed; -#define MGMT_OP_PIN_CODE_REPLY 0x0017 +#define MGMT_OP_PIN_CODE_REPLY 0x0016 struct mgmt_cp_pin_code_reply { bdaddr_t bdaddr; __u8 pin_len; @@ -211,17 +201,17 @@ struct mgmt_rp_pin_code_reply { uint8_t status; } __packed; -#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0018 +#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017 struct mgmt_cp_pin_code_neg_reply { bdaddr_t bdaddr; } __packed; -#define MGMT_OP_SET_IO_CAPABILITY 0x0019 +#define MGMT_OP_SET_IO_CAPABILITY 0x0018 struct mgmt_cp_set_io_capability { __u8 io_capability; } __packed; -#define MGMT_OP_PAIR_DEVICE 0x001A +#define MGMT_OP_PAIR_DEVICE 0x0019 struct mgmt_cp_pair_device { struct mgmt_addr_info addr; __u8 io_cap; @@ -231,7 +221,17 @@ struct mgmt_rp_pair_device { __u8 status; } __packed; -#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001B +#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A + +#define MGMT_OP_UNPAIR_DEVICE 0x001B +struct mgmt_cp_unpair_device { + struct mgmt_addr_info addr; + __u8 disconnect; +} __packed; +struct mgmt_rp_unpair_device { + struct mgmt_addr_info addr; + __u8 status; +}; #define MGMT_OP_USER_CONFIRM_REPLY 0x001C struct mgmt_cp_user_confirm_reply { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 77bc5a4b026..c64e5db7f59 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1073,57 +1073,63 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) return 0; } -static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) +static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_remove_keys *cp = data; - struct mgmt_rp_remove_keys rp; + struct mgmt_cp_unpair_device *cp = data; + struct mgmt_rp_unpair_device rp; struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; int err; if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, + return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, + return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); memset(&rp, 0, sizeof(rp)); - bacpy(&rp.bdaddr, &cp->bdaddr); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; rp.status = MGMT_STATUS_FAILED; - err = hci_remove_ltk(hdev, &cp->bdaddr); - if (err < 0) { - err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err); - goto unlock; - } + if (cp->addr.type == MGMT_ADDR_BREDR) + err = hci_remove_link_key(hdev, &cp->addr.bdaddr); + else + err = hci_remove_ltk(hdev, &cp->addr.bdaddr); - err = hci_remove_link_key(hdev, &cp->bdaddr); if (err < 0) { rp.status = MGMT_STATUS_NOT_PAIRED; goto unlock; } if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); goto unlock; } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + if (cp->addr.type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + &cp->addr.bdaddr); + else + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, + &cp->addr.bdaddr); + if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); goto unlock; } - cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp)); + cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp, + sizeof(*cp)); if (!cmd) { err = -ENOMEM; goto unlock; @@ -1137,7 +1143,7 @@ static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) unlock: if (err < 0) - err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2340,9 +2346,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_LOAD_LINK_KEYS: err = load_link_keys(sk, index, cp, len); break; - case MGMT_OP_REMOVE_KEYS: - err = remove_keys(sk, index, cp, len); - break; case MGMT_OP_DISCONNECT: err = disconnect(sk, index, cp, len); break; @@ -2364,6 +2367,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_CANCEL_PAIR_DEVICE: err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_UNPAIR_DEVICE: + err = unpair_device(sk, index, cp, len); + break; case MGMT_OP_USER_CONFIRM_REPLY: err = user_confirm_reply(sk, index, cp, len); break; @@ -2624,18 +2630,19 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) mgmt_pending_remove(cmd); } -static void remove_keys_rsp(struct pending_cmd *cmd, void *data) +static void unpair_device_rsp(struct pending_cmd *cmd, void *data) { u8 *status = data; - struct mgmt_cp_remove_keys *cp = cmd->param; - struct mgmt_rp_remove_keys rp; + struct mgmt_cp_unpair_device *cp = cmd->param; + struct mgmt_rp_unpair_device rp; memset(&rp, 0, sizeof(rp)); - bacpy(&rp.bdaddr, &cp->bdaddr); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; if (status != NULL) rp.status = *status; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp, + cmd_complete(cmd->sk, cmd->index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -2659,7 +2666,8 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, if (sk) sock_put(sk); - mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL); + mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, + NULL); return err; } -- cgit v1.2.3-70-g09d2 From 88c3df13ca06718e5a8f509ae9cbb1228c10d537 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 14:27:38 +0200 Subject: Bluetooth: Update mgmt_disconnect to match latest API This patch adds an address type parameter to the disconnect command and response in order to match the latest mgmt API specification. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/hci_event.c | 28 +++++++++++++++++++++++++--- net/bluetooth/mgmt.c | 28 +++++++++++++--------------- 4 files changed, 42 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7107790817a..634a0cdcdad 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -958,7 +958,8 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); -int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); +int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status); int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4c18cd5fb8c..735e547e344 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -177,10 +177,10 @@ struct mgmt_cp_load_long_term_keys { #define MGMT_OP_DISCONNECT 0x0014 struct mgmt_cp_disconnect { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; struct mgmt_rp_disconnect { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ad5f37b13f7..f0c822db28d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1550,6 +1550,28 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) hci_dev_unlock(hdev); } +static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) +{ + struct hci_cp_disconnect *cp; + struct hci_conn *conn; + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) + mgmt_disconnect_failed(hdev, &conn->dst, conn->type, + conn->dst_type, status); + + hci_dev_unlock(hdev); +} + static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) { struct hci_cp_le_create_conn *cp; @@ -1839,7 +1861,8 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && (conn->type == ACL_LINK || conn->type == LE_LINK)) { if (ev->status != 0) - mgmt_disconnect_failed(hdev, &conn->dst, ev->status); + mgmt_disconnect_failed(hdev, &conn->dst, conn->type, + conn->dst_type, ev->status); else mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type); @@ -2350,8 +2373,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) break; case HCI_OP_DISCONNECT: - if (ev->status != 0) - mgmt_disconnect_failed(hdev, NULL, ev->status); + hci_cs_disconnect(hdev, ev->status); break; case HCI_OP_LE_CREATE_CONN: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c64e5db7f59..f1257ee5afb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1185,9 +1185,10 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); - if (!conn) - conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); + if (cp->addr.type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); + else + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); if (!conn) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, @@ -2619,7 +2620,8 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) struct sock **sk = data; struct mgmt_rp_disconnect rp; - bacpy(&rp.bdaddr, &cp->bdaddr); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; rp.status = 0; cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); @@ -2672,27 +2674,23 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, return err; } -int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) +int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status) { + struct mgmt_rp_disconnect rp; struct pending_cmd *cmd; - u8 mgmt_err = mgmt_status(status); int err; cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev); if (!cmd) return -ENOENT; - if (bdaddr) { - struct mgmt_rp_disconnect rp; - - bacpy(&rp.bdaddr, bdaddr); - rp.status = status; + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = link_to_mgmt(link_type, addr_type); + rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, + err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); - } else - err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, - mgmt_err); mgmt_pending_remove(cmd); -- cgit v1.2.3-70-g09d2 From 272d90df2d4d065e782cafb08358bd8918bf703a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 15:26:12 +0200 Subject: Bluetooth: Add address type to user_confirm and user_passkey messages This patch upadate the user confirm and user passkey mgmt messages to match the latest API specification by adding an address type parameter to them. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 18 ++++---- include/net/bluetooth/mgmt.h | 16 +++---- net/bluetooth/hci_event.c | 14 +++--- net/bluetooth/mgmt.c | 98 ++++++++++++++++++++-------------------- net/bluetooth/smp.c | 4 +- 5 files changed, 79 insertions(+), 71 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 634a0cdcdad..5f27694068f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -968,16 +968,18 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - __le32 value, u8 confirm_hint); + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint); int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); -int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status); -int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr); + u8 link_type, u8 addr_type, u8 status); +int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status); +int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type); int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); -int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status); + u8 link_type, u8 addr_type, u8 status); +int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status); int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 735e547e344..378d498896b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -235,31 +235,31 @@ struct mgmt_rp_unpair_device { #define MGMT_OP_USER_CONFIRM_REPLY 0x001C struct mgmt_cp_user_confirm_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; struct mgmt_rp_user_confirm_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D struct mgmt_cp_user_confirm_neg_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_USER_PASSKEY_REPLY 0x001E struct mgmt_cp_user_passkey_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __le32 passkey; } __packed; struct mgmt_rp_user_passkey_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; #define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F struct mgmt_cp_user_passkey_neg_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020 @@ -376,14 +376,14 @@ struct mgmt_ev_pin_code_request { #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F struct mgmt_ev_user_confirm_request { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 confirm_hint; __le32 value; } __packed; #define MGMT_EV_USER_PASSKEY_REQUEST 0x0010 struct mgmt_ev_user_passkey_request { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_EV_AUTH_FAILED 0x0011 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f0c822db28d..3bf3f4d59bc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -960,8 +960,8 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, - rp->status); + mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, + 0, rp->status); hci_dev_unlock(hdev); } @@ -977,6 +977,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr, + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); @@ -991,8 +992,8 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, - rp->status); + mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK, + 0, rp->status); hci_dev_unlock(hdev); } @@ -1008,6 +1009,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr, + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); @@ -3123,7 +3125,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, } confirm: - mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey, + mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey, confirm_hint); unlock: @@ -3140,7 +3142,7 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_passkey_request(hdev, &ev->bdaddr); + mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0); hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f1257ee5afb..16fc828096f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1629,7 +1629,8 @@ unlock: } static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, - u16 mgmt_op, u16 hci_op, __le32 passkey) + u8 type, u16 mgmt_op, u16 hci_op, + __le32 passkey) { struct pending_cmd *cmd; struct hci_dev *hdev; @@ -1648,24 +1649,18 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, goto done; } - /* - * Check for an existing ACL link, if present pair via - * HCI commands. - * - * If no ACL link is present, check for an LE link and if - * present, pair via the SMP engine. - * - * If neither ACL nor LE links are present, fail with error. - */ - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); - if (!conn) { + if (type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); + else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); - if (!conn) { - err = cmd_status(sk, index, mgmt_op, + + if (!conn) { + err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_CONNECTED); - goto done; - } + goto done; + } + if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) { /* Continue with pairing via SMP */ err = smp_user_confirm_reply(conn, mgmt_op, passkey); @@ -1715,9 +1710,9 @@ static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_CONFIRM_REPLY, - HCI_OP_USER_CONFIRM_REPLY, 0); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_CONFIRM_REPLY, + HCI_OP_USER_CONFIRM_REPLY, 0); } static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, @@ -1731,9 +1726,9 @@ static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_CONFIRM_NEG_REPLY, - HCI_OP_USER_CONFIRM_NEG_REPLY, 0); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_CONFIRM_NEG_REPLY, + HCI_OP_USER_CONFIRM_NEG_REPLY, 0); } static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) @@ -1746,9 +1741,10 @@ static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY, EINVAL); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_PASSKEY_REPLY, - HCI_OP_USER_PASSKEY_REPLY, cp->passkey); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_PASSKEY_REPLY, + HCI_OP_USER_PASSKEY_REPLY, + cp->passkey); } static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, @@ -1762,9 +1758,9 @@ static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY, EINVAL); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_PASSKEY_NEG_REPLY, - HCI_OP_USER_PASSKEY_NEG_REPLY, 0); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_PASSKEY_NEG_REPLY, + HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } static int set_local_name(struct sock *sk, u16 index, void *data, @@ -2765,13 +2761,15 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - __le32 value, u8 confirm_hint) + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint) { struct mgmt_ev_user_confirm_request ev; BT_DBG("%s", hdev->name); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_mgmt(link_type, addr_type); ev.confirm_hint = confirm_hint; put_unaligned_le32(value, &ev.value); @@ -2779,20 +2777,23 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, NULL); } -int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr) +int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type) { struct mgmt_ev_user_passkey_request ev; BT_DBG("%s", hdev->name); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_mgmt(link_type, addr_type); return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev), NULL); } static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status, u8 opcode) + u8 link_type, u8 addr_type, u8 status, + u8 opcode) { struct pending_cmd *cmd; struct mgmt_rp_user_confirm_reply rp; @@ -2802,7 +2803,8 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!cmd) return -ENOENT; - bacpy(&rp.bdaddr, bdaddr); + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = link_to_mgmt(link_type, addr_type); rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp)); @@ -2812,31 +2814,31 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_CONFIRM_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_CONFIRM_REPLY); } -int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status) +int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_CONFIRM_NEG_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_CONFIRM_NEG_REPLY); } int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_PASSKEY_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_PASSKEY_REPLY); } -int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status) +int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_PASSKEY_NEG_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_PASSKEY_NEG_REPLY); } int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0563f737779..589766d06f2 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -349,9 +349,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, hci_dev_lock(hcon->hdev); if (method == REQ_PASSKEY) - ret = mgmt_user_passkey_request(hcon->hdev, conn->dst); + ret = mgmt_user_passkey_request(hcon->hdev, conn->dst, + hcon->type, hcon->dst_type); else ret = mgmt_user_confirm_request(hcon->hdev, conn->dst, + hcon->type, hcon->dst_type, cpu_to_le32(passkey), 0); hci_dev_unlock(hcon->hdev); -- cgit v1.2.3-70-g09d2 From 664ce4cc293cd6c76236617f78689d0e03e69287 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 15:44:09 +0200 Subject: Bluetooth: Add address type to Out Of Band mgmt messages This patch updates the implementation for these mgmt to be up to date with the latest API specification. Right now the address type isn't actually used for anything but that might change in the future. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/mgmt.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 378d498896b..f284499b5f7 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -270,14 +270,14 @@ struct mgmt_rp_read_local_oob_data { #define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021 struct mgmt_cp_add_remote_oob_data { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 hash[16]; __u8 randomizer[16]; } __packed; #define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022 struct mgmt_cp_remove_remote_oob_data { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_START_DISCOVERY 0x0023 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 16fc828096f..763a447b253 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1875,7 +1875,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); - err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, + err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, cp->randomizer); if (err < 0) err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, @@ -1910,7 +1910,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, hci_dev_lock(hdev); - err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); + err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); if (err < 0) err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); -- cgit v1.2.3-70-g09d2 From 88c1fe4ba55c7245ad2f3c81689f854287875121 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 15:56:11 +0200 Subject: Bluetooth: Add address type to mgmt blacklist messages This patch updates the implmentation for mgmt_block_device and mgmt_unblock_device and their corresponding events to match the latest API specification. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 8 ++++---- include/net/bluetooth/mgmt.h | 8 ++++---- net/bluetooth/hci_core.c | 8 ++++---- net/bluetooth/hci_sock.c | 4 ++-- net/bluetooth/mgmt.c | 14 ++++++++------ 5 files changed, 22 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5f27694068f..14a655f3929 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -646,8 +646,8 @@ int hci_inquiry(void __user *arg); struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_blacklist_clear(struct hci_dev *hdev); -int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_uuids_clear(struct hci_dev *hdev); @@ -992,8 +992,8 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); -int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr); -int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr); +int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index f284499b5f7..92f85c83467 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -299,12 +299,12 @@ struct mgmt_rp_confirm_name { #define MGMT_OP_BLOCK_DEVICE 0x0026 struct mgmt_cp_block_device { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_UNBLOCK_DEVICE 0x0027 struct mgmt_cp_unblock_device { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_EV_CMD_COMPLETE 0x0001 @@ -405,10 +405,10 @@ struct mgmt_ev_device_found { #define MGMT_EV_DEVICE_BLOCKED 0x0014 struct mgmt_ev_device_blocked { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_EV_DEVICE_UNBLOCKED 0x0015 struct mgmt_ev_device_unblocked { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3d09f4b4ca6..9ada16449ae 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1489,7 +1489,7 @@ int hci_blacklist_clear(struct hci_dev *hdev) return 0; } -int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; @@ -1507,10 +1507,10 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) list_add(&entry->list, &hdev->blacklist); - return mgmt_device_blocked(hdev, bdaddr); + return mgmt_device_blocked(hdev, bdaddr, type); } -int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; @@ -1524,7 +1524,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) list_del(&entry->list); kfree(entry); - return mgmt_device_unblocked(hdev, bdaddr); + return mgmt_device_unblocked(hdev, bdaddr, type); } static void hci_clear_adv_cache(struct work_struct *work) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 0dcc9626677..9e854d9fb46 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -190,7 +190,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_add(hdev, &bdaddr); + err = hci_blacklist_add(hdev, &bdaddr, 0); hci_dev_unlock(hdev); @@ -207,7 +207,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_del(hdev, &bdaddr); + err = hci_blacklist_del(hdev, &bdaddr, 0); hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 763a447b253..413a0b97c53 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2114,7 +2114,7 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - err = hci_blacklist_add(hdev, &cp->bdaddr); + err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_FAILED); @@ -2147,7 +2147,7 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - err = hci_blacklist_del(hdev, &cp->bdaddr); + err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, @@ -3026,27 +3026,29 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) sizeof(discovering), NULL); } -int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr) +int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct pending_cmd *cmd; struct mgmt_ev_device_blocked ev; cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); } -int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr) +int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct pending_cmd *cmd; struct mgmt_ev_device_unblocked ev; cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); -- cgit v1.2.3-70-g09d2 From bab73cb68435232ba78a4bd1ac1a85862e3be0bb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 16:07:29 +0200 Subject: Bluetooth: Add address type to mgmt_ev_auth_failed This patch updates the Authentication Failed mgmt event to match the latest API specification by adding an address type to it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/hci_event.c | 6 ++++-- net/bluetooth/mgmt.c | 6 ++++-- net/bluetooth/smp.c | 5 ++++- 5 files changed, 15 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 14a655f3929..ccb24a4212c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -980,7 +980,8 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); -int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); +int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 92f85c83467..17bbf8bf04a 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -388,7 +388,7 @@ struct mgmt_ev_user_passkey_request { #define MGMT_EV_AUTH_FAILED 0x0011 struct mgmt_ev_auth_failed { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3bf3f4d59bc..b0784ee5f8b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1901,7 +1901,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->sec_level = conn->pending_sec_level; } } else { - mgmt_auth_failed(hdev, &conn->dst, ev->status); + mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, + ev->status); } clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); @@ -3166,7 +3167,8 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_ * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) - mgmt_auth_failed(hdev, &conn->dst, ev->status); + mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, + ev->status); hci_conn_put(conn); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 413a0b97c53..54591982856 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2841,11 +2841,13 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, status, MGMT_OP_USER_PASSKEY_NEG_REPLY); } -int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) +int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, u8 status) { struct mgmt_ev_auth_failed ev; - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_mgmt(link_type, addr_type); ev.status = mgmt_status(status); return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 589766d06f2..f6a6d8be305 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -257,12 +257,15 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) { + struct hci_conn *hcon = conn->hcon; + if (send) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); - mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); + mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, + hcon->dst_type, reason); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { cancel_delayed_work_sync(&conn->security_timer); -- cgit v1.2.3-70-g09d2 From 82eb703efc2ad2ac52cada85a5119bb9dfcea942 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 17:19:27 +0200 Subject: Bluetooth: Fix mgmt_unpair_device command status The default response status to unpair_device should be set as 0 instead of a generic failure value. When disconnection is not needed (i.e. we can reply imediately) we should return success and not failure. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 54591982856..0cf0f4dc821 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1097,7 +1097,6 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; - rp.status = MGMT_STATUS_FAILED; if (cp->addr.type == MGMT_ADDR_BREDR) err = hci_remove_link_key(hdev, &cp->addr.bdaddr); -- cgit v1.2.3-70-g09d2 From b1078ad0be344e7bec6e7991f33df17565d24e08 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 17:21:16 +0200 Subject: Bluetooth: Add Device Unpaired mgmt event This patch add a new Device Unpaired mgmt event. This will be sent to all mgmt sockets except the one that requested unpairing (that socket will get a command complete instead). The event is also reserved for future SMP updates where a remote device will be able to request pairing revocation from us. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 5 +++++ net/bluetooth/mgmt.c | 27 +++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 17bbf8bf04a..5b5edeed59e 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -412,3 +412,8 @@ struct mgmt_ev_device_blocked { struct mgmt_ev_device_unblocked { struct mgmt_addr_info addr; } __packed; + +#define MGMT_EV_DEVICE_UNPAIRED 0x0016 +struct mgmt_ev_device_unpaired { + struct mgmt_addr_info addr; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0cf0f4dc821..a2c2e12516c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1073,6 +1073,18 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) return 0; } +static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, struct sock *skip_sk) +{ + struct mgmt_ev_device_unpaired ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = addr_type; + + return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev), + skip_sk); +} + static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; @@ -1111,6 +1123,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); + device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -1124,6 +1137,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) if (!conn) { err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); + device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -2629,18 +2643,17 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) static void unpair_device_rsp(struct pending_cmd *cmd, void *data) { - u8 *status = data; + struct hci_dev *hdev = data; struct mgmt_cp_unpair_device *cp = cmd->param; struct mgmt_rp_unpair_device rp; memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; - if (status != NULL) - rp.status = *status; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); + + cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp)); mgmt_pending_remove(cmd); } @@ -2664,7 +2677,7 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, sock_put(sk); mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, - NULL); + hdev); return err; } @@ -2689,6 +2702,8 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, mgmt_pending_remove(cmd); + mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, + hdev); return err; } -- cgit v1.2.3-70-g09d2 From aa2b86d761a95068354511de755695ef6b53afc7 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 9 Feb 2012 21:58:30 +0100 Subject: Bluetooth: Introduce to_hci_dev() We currently use dev_set_drvdata to keep a pointer to ourself. This doesn't make sense as we are the bus and not a driver. Therefore, introduce to_hci_dev() so we can get a struct hci_dev pointer from a struct device pointer. dev_set/get_drvdata() is reserved for drivers that provide a device and not for the bus using the device. The bus can use simple pointer arithmetic to retrieve its private data. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_sysfs.c | 33 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ccb24a4212c..221d772ded5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -623,6 +623,8 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) #define hci_dev_lock(d) mutex_lock(&d->lock) #define hci_dev_unlock(d) mutex_unlock(&d->lock) +#define to_hci_dev(d) container_of(d, struct hci_dev, dev) + struct hci_dev *hci_dev_get(int index); struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index ec03ee2b301..2a0243add1e 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -189,19 +189,19 @@ static inline char *host_typetostr(int type) static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", host_bustostr(hdev->bus)); } static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type)); } static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); char name[HCI_MAX_NAME_LENGTH + 1]; int i; @@ -214,20 +214,20 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); } static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", batostr(&hdev->bdaddr)); } static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", hdev->features[0], hdev->features[1], @@ -238,31 +238,31 @@ static ssize_t show_features(struct device *dev, struct device_attribute *attr, static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->manufacturer); } static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->hci_ver); } static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->hci_rev); } static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->idle_timeout); } static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); unsigned int val; int rv; @@ -280,13 +280,13 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->sniff_max_interval); } static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); u16 val; int rv; @@ -304,13 +304,13 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->sniff_min_interval); } static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); u16 val; int rv; @@ -370,7 +370,7 @@ static const struct attribute_group *bt_host_groups[] = { static void bt_host_release(struct device *dev) { - void *data = dev_get_drvdata(dev); + void *data = to_hci_dev(dev); kfree(data); module_put(THIS_MODULE); } @@ -525,7 +525,6 @@ void hci_init_sysfs(struct hci_dev *hdev) dev->class = bt_class; __module_get(THIS_MODULE); - dev_set_drvdata(dev, hdev); device_initialize(dev); } -- cgit v1.2.3-70-g09d2 From 3dc07322b1ce3c8477690d54ebbf15a165f43066 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 9 Feb 2012 21:58:33 +0100 Subject: Bluetooth: Introduce to_hci_conn This avoids using the dev_set/get_drvdata() functions to retrieve a pointer to our own structure. We can use simple pointer arithmetic here. The drvdata field is actually not needed by any other code-path but this makes the code more consistent with hci_dev. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_sysfs.c | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4559189a22a..b20d990436b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -623,6 +623,7 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) #define hci_dev_unlock(d) mutex_unlock(&d->lock) #define to_hci_dev(d) container_of(d, struct hci_dev, dev) +#define to_hci_conn(c) container_of(c, struct hci_conn, dev) static inline void *hci_get_drvdata(struct hci_dev *hdev) { diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 2a0243add1e..17e6cd48ad4 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -33,19 +33,19 @@ static inline char *link_typetostr(int type) static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_conn *conn = dev_get_drvdata(dev); + struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "%s\n", link_typetostr(conn->type)); } static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_conn *conn = dev_get_drvdata(dev); + struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "%s\n", batostr(&conn->dst)); } static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_conn *conn = dev_get_drvdata(dev); + struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", conn->features[0], conn->features[1], @@ -79,7 +79,7 @@ static const struct attribute_group *bt_link_groups[] = { static void bt_link_release(struct device *dev) { - void *data = dev_get_drvdata(dev); + void *data = to_hci_conn(dev); kfree(data); } @@ -120,8 +120,6 @@ void hci_conn_add_sysfs(struct hci_conn *conn) dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); - dev_set_drvdata(&conn->dev, conn); - if (device_add(&conn->dev) < 0) { BT_ERR("Failed to register connection device"); return; -- cgit v1.2.3-70-g09d2 From 2dd106887d6503819f2cedc408497023547439bb Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 9 Feb 2012 21:58:34 +0100 Subject: Bluetooth: Use proper datatypes in release-callbacks This enhances code readability a lot and avoids using void* even though we know the type of the variable. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sysfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 17e6cd48ad4..bc154298979 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -79,8 +79,8 @@ static const struct attribute_group *bt_link_groups[] = { static void bt_link_release(struct device *dev) { - void *data = to_hci_conn(dev); - kfree(data); + struct hci_conn *conn = to_hci_conn(dev); + kfree(conn); } static struct device_type bt_link = { @@ -368,8 +368,8 @@ static const struct attribute_group *bt_host_groups[] = { static void bt_host_release(struct device *dev) { - void *data = to_hci_dev(dev); - kfree(data); + struct hci_dev *hdev = to_hci_dev(dev); + kfree(hdev); module_put(THIS_MODULE); } -- cgit v1.2.3-70-g09d2 From de8261c2fa364397ed872fad1244d75364689168 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 13 Feb 2012 04:09:20 +0000 Subject: gro: fix truesize underestimation skb_gro_receive() doesnt update truesize properly when adding one skb to frag_list. Signed-off-by: Eric Dumazet Cc: Herbert Xu Signed-off-by: David S. Miller --- net/core/skbuff.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index da0c97f2fab..f3a53078075 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2906,7 +2906,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) nskb->prev = p; nskb->data_len += p->len; - nskb->truesize += p->len; + nskb->truesize += p->truesize; nskb->len += p->len; *head = nskb; @@ -2916,6 +2916,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) p = nskb; merge: + p->truesize += skb->truesize - len; if (offset > headlen) { unsigned int eat = offset - headlen; -- cgit v1.2.3-70-g09d2 From 2132cf64371a20f5c427da42f9f9e7e99bc5fb88 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 13 Feb 2012 05:40:45 +0000 Subject: net_sched: sch_plug: plug_qdisc_ops is static net/sched/sch_plug.c:211:18: warning: symbol 'plug_qdisc_ops' was not declared. Should it be static? Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_plug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sched/sch_plug.c b/net/sched/sch_plug.c index ba7b737e405..89f8fcf73f1 100644 --- a/net/sched/sch_plug.c +++ b/net/sched/sch_plug.c @@ -208,7 +208,7 @@ static int plug_change(struct Qdisc *sch, struct nlattr *opt) return 0; } -struct Qdisc_ops plug_qdisc_ops = { +static struct Qdisc_ops plug_qdisc_ops __read_mostly = { .id = "plug", .priv_size = sizeof(struct plug_sched_data), .enqueue = plug_enqueue, -- cgit v1.2.3-70-g09d2 From 6f5133652eaab6fbd88bdb1b1fd2236fd82583cb Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 31 Jan 2012 14:09:00 +0400 Subject: SUNRPC: clear svc pools lists helper introduced This patch moves removing of service transport from it's pools ready lists to separated function. Also this clear is now done with list_for_each_entry_safe() helper. This is a precursor patch, which would be usefull with service shutdown in network namespace context, introduced later in the series. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/svc_xprt.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index de1e1a8b526..50bf7c1c731 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -932,26 +932,33 @@ static void svc_close_list(struct list_head *xprt_list) } } -void svc_close_all(struct svc_serv *serv) +static void svc_clear_pools(struct svc_serv *serv) { struct svc_pool *pool; struct svc_xprt *xprt; struct svc_xprt *tmp; int i; - svc_close_list(&serv->sv_tempsocks); - svc_close_list(&serv->sv_permsocks); - for (i = 0; i < serv->sv_nrpools; i++) { pool = &serv->sv_pools[i]; spin_lock_bh(&pool->sp_lock); - while (!list_empty(&pool->sp_sockets)) { - xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready); + list_for_each_entry_safe(xprt, tmp, &pool->sp_sockets, xpt_ready) { list_del_init(&xprt->xpt_ready); } spin_unlock_bh(&pool->sp_lock); } +} + +void svc_close_all(struct svc_serv *serv) +{ + struct svc_xprt *xprt; + struct svc_xprt *tmp; + + svc_close_list(&serv->sv_tempsocks); + svc_close_list(&serv->sv_permsocks); + + svc_clear_pools(serv); /* * At this point the sp_sockets lists will stay empty, since * svc_enqueue will not add new entries without taking the -- cgit v1.2.3-70-g09d2 From 3a22bf506c9df47e93e8dc8a68d86cd8ae384d98 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 31 Jan 2012 14:09:08 +0400 Subject: SUNRPC: clear svc transports lists helper introduced This patch moves service transports deletion from service sockets lists to separated function. This is a precursor patch, which would be usefull with service shutdown in network namespace context, introduced later in the series. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/svc_xprt.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 50bf7c1c731..493e70b72b7 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -950,11 +950,19 @@ static void svc_clear_pools(struct svc_serv *serv) } } -void svc_close_all(struct svc_serv *serv) +static void svc_clear_list(struct list_head *xprt_list) { struct svc_xprt *xprt; struct svc_xprt *tmp; + list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { + svc_delete_xprt(xprt); + } + BUG_ON(!list_empty(xprt_list)); +} + +void svc_close_all(struct svc_serv *serv) +{ svc_close_list(&serv->sv_tempsocks); svc_close_list(&serv->sv_permsocks); @@ -964,13 +972,8 @@ void svc_close_all(struct svc_serv *serv) * svc_enqueue will not add new entries without taking the * sp_lock and checking XPT_BUSY. */ - list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list) - svc_delete_xprt(xprt); - list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list) - svc_delete_xprt(xprt); - - BUG_ON(!list_empty(&serv->sv_permsocks)); - BUG_ON(!list_empty(&serv->sv_tempsocks)); + svc_clear_list(&serv->sv_tempsocks); + svc_clear_list(&serv->sv_permsocks); } /* -- cgit v1.2.3-70-g09d2 From 7b147f1ff267d12e0d189ca3d4156ed5a76b8d99 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 31 Jan 2012 14:09:17 +0400 Subject: SUNRPC: service destruction in network namespace context v2: Added comment to BUG_ON's in svc_destroy() to make code looks clearer. This patch introduces network namespace filter for service destruction function. Nothing special here - just do exactly the same operations, but only for tranports in passed networks namespace context. BTW, BUG_ON() checks for empty service transports lists were returned into svc_destroy() function. This is because of swithing generic svc_close_all() to networks namespace dependable svc_close_net(). Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/svcsock.h | 2 +- net/sunrpc/svc.c | 13 +++++++++++-- net/sunrpc/svc_xprt.c | 27 +++++++++++++++++---------- 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index c84e9741cb2..cb4ac69e1f3 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -34,7 +34,7 @@ struct svc_sock { /* * Function prototypes. */ -void svc_close_all(struct svc_serv *); +void svc_close_net(struct svc_serv *, struct net *); int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index a8b49a04461..6cc0ea3d26f 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -517,6 +517,8 @@ EXPORT_SYMBOL_GPL(svc_create_pooled); void svc_destroy(struct svc_serv *serv) { + struct net *net = current->nsproxy->net_ns; + dprintk("svc: svc_destroy(%s, %d)\n", serv->sv_program->pg_name, serv->sv_nrthreads); @@ -539,10 +541,17 @@ svc_destroy(struct svc_serv *serv) * caller is using--nfsd_mutex in the case of nfsd). So it's * safe to traverse those lists and shut everything down: */ - svc_close_all(serv); + svc_close_net(serv, net); + + /* + * The last user is gone and thus all sockets have to be destroyed to + * the point. Check this. + */ + BUG_ON(!list_empty(&serv->sv_permsocks)); + BUG_ON(!list_empty(&serv->sv_tempsocks)); if (serv->sv_shutdown) - serv->sv_shutdown(serv, current->nsproxy->net_ns); + serv->sv_shutdown(serv, net); cache_clean_deferred(serv); diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 493e70b72b7..4bda09d7e1a 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -922,17 +922,19 @@ void svc_close_xprt(struct svc_xprt *xprt) } EXPORT_SYMBOL_GPL(svc_close_xprt); -static void svc_close_list(struct list_head *xprt_list) +static void svc_close_list(struct list_head *xprt_list, struct net *net) { struct svc_xprt *xprt; list_for_each_entry(xprt, xprt_list, xpt_list) { + if (xprt->xpt_net != net) + continue; set_bit(XPT_CLOSE, &xprt->xpt_flags); set_bit(XPT_BUSY, &xprt->xpt_flags); } } -static void svc_clear_pools(struct svc_serv *serv) +static void svc_clear_pools(struct svc_serv *serv, struct net *net) { struct svc_pool *pool; struct svc_xprt *xprt; @@ -944,36 +946,41 @@ static void svc_clear_pools(struct svc_serv *serv) spin_lock_bh(&pool->sp_lock); list_for_each_entry_safe(xprt, tmp, &pool->sp_sockets, xpt_ready) { + if (xprt->xpt_net != net) + continue; list_del_init(&xprt->xpt_ready); } spin_unlock_bh(&pool->sp_lock); } } -static void svc_clear_list(struct list_head *xprt_list) +static void svc_clear_list(struct list_head *xprt_list, struct net *net) { struct svc_xprt *xprt; struct svc_xprt *tmp; list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { + if (xprt->xpt_net != net) + continue; svc_delete_xprt(xprt); } - BUG_ON(!list_empty(xprt_list)); + list_for_each_entry(xprt, xprt_list, xpt_list) + BUG_ON(xprt->xpt_net == net); } -void svc_close_all(struct svc_serv *serv) +void svc_close_net(struct svc_serv *serv, struct net *net) { - svc_close_list(&serv->sv_tempsocks); - svc_close_list(&serv->sv_permsocks); + svc_close_list(&serv->sv_tempsocks, net); + svc_close_list(&serv->sv_permsocks, net); - svc_clear_pools(serv); + svc_clear_pools(serv, net); /* * At this point the sp_sockets lists will stay empty, since * svc_enqueue will not add new entries without taking the * sp_lock and checking XPT_BUSY. */ - svc_clear_list(&serv->sv_tempsocks); - svc_clear_list(&serv->sv_permsocks); + svc_clear_list(&serv->sv_tempsocks, net); + svc_clear_list(&serv->sv_permsocks, net); } /* -- cgit v1.2.3-70-g09d2 From 074d0f67cfe0af4927ce49560f403096b490c47f Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 31 Jan 2012 14:09:25 +0400 Subject: SUNRPC: service shutdown function in network namespace context introduced This function is enough for releasing resources, allocated for network namespace context, in case of sharing service between them. IOW, each service "user" (LockD, NFSd, etc), which wants to share service between network namespaces, have to release related resources by the function, introduced in this patch, instead of performing service shutdown (of course in case the service is shared already to the moment of release). Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/svc.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 6cc0ea3d26f..78abac48985 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -510,6 +510,24 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, } EXPORT_SYMBOL_GPL(svc_create_pooled); +void svc_shutdown_net(struct svc_serv *serv, struct net *net) +{ + /* + * The set of xprts (contained in the sv_tempsocks and + * sv_permsocks lists) is now constant, since it is modified + * only by accepting new sockets (done by service threads in + * svc_recv) or aging old ones (done by sv_temptimer), or + * configuration changes (excluded by whatever locking the + * caller is using--nfsd_mutex in the case of nfsd). So it's + * safe to traverse those lists and shut everything down: + */ + svc_close_net(serv, net); + + if (serv->sv_shutdown) + serv->sv_shutdown(serv, net); +} +EXPORT_SYMBOL_GPL(svc_shutdown_net); + /* * Destroy an RPC service. Should be called with appropriate locking to * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. @@ -532,16 +550,8 @@ svc_destroy(struct svc_serv *serv) printk("svc_destroy: no threads for serv=%p!\n", serv); del_timer_sync(&serv->sv_temptimer); - /* - * The set of xprts (contained in the sv_tempsocks and - * sv_permsocks lists) is now constant, since it is modified - * only by accepting new sockets (done by service threads in - * svc_recv) or aging old ones (done by sv_temptimer), or - * configuration changes (excluded by whatever locking the - * caller is using--nfsd_mutex in the case of nfsd). So it's - * safe to traverse those lists and shut everything down: - */ - svc_close_net(serv, net); + + svc_shutdown_net(serv, net); /* * The last user is gone and thus all sockets have to be destroyed to @@ -550,9 +560,6 @@ svc_destroy(struct svc_serv *serv) BUG_ON(!list_empty(&serv->sv_permsocks)); BUG_ON(!list_empty(&serv->sv_tempsocks)); - if (serv->sv_shutdown) - serv->sv_shutdown(serv, net); - cache_clean_deferred(serv); if (svc_serv_is_pooled(serv)) -- cgit v1.2.3-70-g09d2 From bb2224df5ffe4f864f5b696199b17db1ce77bc0a Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 31 Jan 2012 15:08:05 +0400 Subject: Lockd: per-net up and down routines introduced This patch introduces per-net Lockd initialization and destruction routines. The logic is the same as in global Lockd up and down routines. Probably the solution is not the best one. But at least it looks clear. So per-net "up" routine are called only in case of lockd is running already. If per-net resources are not allocated yet, then service is being registered with local portmapper and lockd sockets created. Per-net "down" routine is called on every lockd_down() call in case of global users counter is not zero. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/lockd/svc.c | 47 ++++++++++++++++++++++++++++++++++++++++++++-- include/linux/sunrpc/svc.h | 2 ++ net/sunrpc/svc.c | 3 ++- 3 files changed, 49 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 73c9ebf0930..90dec426bfd 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -251,6 +251,45 @@ out_err: return err; } +static int lockd_up_net(struct net *net) +{ + struct lockd_net *ln = net_generic(net, lockd_net_id); + struct svc_serv *serv = nlmsvc_rqst->rq_server; + int error; + + if (ln->nlmsvc_users) + return 0; + + error = svc_rpcb_setup(serv, net); + if (error) + goto err_rpcb; + + error = make_socks(serv, net); + if (error < 0) + goto err_socks; + return 0; + +err_socks: + svc_rpcb_cleanup(serv, net); +err_rpcb: + return error; +} + +static void lockd_down_net(struct net *net) +{ + struct lockd_net *ln = net_generic(net, lockd_net_id); + struct svc_serv *serv = nlmsvc_rqst->rq_server; + + if (ln->nlmsvc_users) { + if (--ln->nlmsvc_users == 0) + svc_shutdown_net(serv, net); + } else { + printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n", + nlmsvc_task, net); + BUG(); + } +} + /* * Bring up the lockd process if it's not already up. */ @@ -264,8 +303,10 @@ int lockd_up(void) /* * Check whether we're already up and running. */ - if (nlmsvc_rqst) + if (nlmsvc_rqst) { + error = lockd_up_net(net); goto out; + } /* * Sanity check: if there's no pid, @@ -339,8 +380,10 @@ lockd_down(void) { mutex_lock(&nlmsvc_mutex); if (nlmsvc_users) { - if (--nlmsvc_users) + if (--nlmsvc_users) { + lockd_down_net(current->nsproxy->net_ns); goto out; + } } else { printk(KERN_ERR "lockd_down: no users! task=%p\n", nlmsvc_task); diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 7b65495aa4e..51b29ac45a8 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -414,6 +414,7 @@ struct svc_procedure { /* * Function prototypes. */ +int svc_rpcb_setup(struct svc_serv *serv, struct net *net); void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); struct svc_serv *svc_create(struct svc_program *, unsigned int, void (*shutdown)(struct svc_serv *, struct net *net)); @@ -426,6 +427,7 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); int svc_pool_stats_open(struct svc_serv *serv, struct file *file); void svc_destroy(struct svc_serv *); +void svc_shutdown_net(struct svc_serv *, struct net *); int svc_process(struct svc_rqst *); int bc_svc_process(struct svc_serv *, struct rpc_rqst *, struct svc_rqst *); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 78abac48985..4153846984a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -369,7 +369,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu) return &serv->sv_pools[pidx % serv->sv_nrpools]; } -static int svc_rpcb_setup(struct svc_serv *serv, struct net *net) +int svc_rpcb_setup(struct svc_serv *serv, struct net *net) { int err; @@ -381,6 +381,7 @@ static int svc_rpcb_setup(struct svc_serv *serv, struct net *net) svc_unregister(serv, net); return 0; } +EXPORT_SYMBOL_GPL(svc_rpcb_setup); void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) { -- cgit v1.2.3-70-g09d2 From 2f09c24216cd789653eb8efbf8be88409eb8d581 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 8 Feb 2012 22:01:15 -0500 Subject: SUNRPC: Ensure that we can trace waitqueues when !defined(CONFIG_SYSCTL) The tracepoint code relies on the queue->name being defined in order to be able to display the name of the waitqueue on which an RPC task is sleeping. Reported-by: Randy Dunlap Reported-by: Steven Rostedt Signed-off-by: Trond Myklebust Acked-by: Steven Rostedt Acked-by: Randy Dunlap --- include/linux/sunrpc/debug.h | 3 +++ include/linux/sunrpc/sched.h | 15 +++++++++++++-- net/sunrpc/sched.c | 4 +--- 3 files changed, 17 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index c2786f20016..2a11eb278f6 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -34,6 +34,9 @@ #ifdef CONFIG_SYSCTL #define RPC_DEBUG #endif +#ifdef CONFIG_TRACEPOINTS +#define RPC_TRACEPOINTS +#endif /* #define RPC_PROFILE */ /* diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index f7b2df5252b..22dfc24013b 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -195,7 +195,7 @@ struct rpc_wait_queue { unsigned char nr; /* # tasks remaining for cookie */ unsigned short qlen; /* total # tasks waiting in queue */ struct rpc_timer timer_list; -#ifdef RPC_DEBUG +#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS) const char * name; #endif }; @@ -270,11 +270,22 @@ static inline int rpc_task_has_priority(struct rpc_task *task, unsigned char pri return (task->tk_priority + RPC_PRIORITY_LOW == prio); } -#ifdef RPC_DEBUG +#if defined(RPC_DEBUG) || defined (RPC_TRACEPOINTS) static inline const char * rpc_qname(const struct rpc_wait_queue *q) { return ((q && q->name) ? q->name : "unknown"); } + +static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q, + const char *name) +{ + q->name = name; +} +#else +static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q, + const char *name) +{ +} #endif #endif /* _LINUX_SUNRPC_SCHED_H_ */ diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index d79c63df49b..1c570a81096 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -208,9 +208,7 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c queue->qlen = 0; setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue); INIT_LIST_HEAD(&queue->timer_list.list); -#ifdef RPC_DEBUG - queue->name = qname; -#endif + rpc_assign_waitqueue_name(queue, qname); } void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) -- cgit v1.2.3-70-g09d2 From e70bb2e89959983aebcfce28f645a1104ffa9ab2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 Feb 2012 16:59:33 +0200 Subject: Bluetooth: Implement Read Supported Commands commands for mgmt This patch implements the Read Supported Commands mgmt command which was recently added to the API specification. It returns a list of supported commands and events to user space. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 7 ++++ net/bluetooth/mgmt.c | 99 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 5b5edeed59e..255a99600f0 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -63,6 +63,13 @@ struct mgmt_rp_read_version { __le16 revision; } __packed; +#define MGMT_OP_READ_COMMANDS 0x0002 +struct mgmt_rp_read_commands { + __le16 num_commands; + __le16 num_events; + __le16 opcodes[0]; +} __packed; + #define MGMT_OP_READ_INDEX_LIST 0x0003 struct mgmt_rp_read_index_list { __le16 num_controllers; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a2c2e12516c..8efbd8eaa1b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,6 +35,69 @@ #define MGMT_VERSION 0 #define MGMT_REVISION 1 +static const u16 mgmt_commands[] = { + MGMT_OP_READ_INDEX_LIST, + MGMT_OP_READ_INFO, + MGMT_OP_SET_POWERED, + MGMT_OP_SET_DISCOVERABLE, + MGMT_OP_SET_CONNECTABLE, + MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_OP_SET_PAIRABLE, + MGMT_OP_SET_LINK_SECURITY, + MGMT_OP_SET_SSP, + MGMT_OP_SET_HS, + MGMT_OP_SET_LE, + MGMT_OP_SET_DEV_CLASS, + MGMT_OP_SET_LOCAL_NAME, + MGMT_OP_ADD_UUID, + MGMT_OP_REMOVE_UUID, + MGMT_OP_LOAD_LINK_KEYS, + MGMT_OP_LOAD_LONG_TERM_KEYS, + MGMT_OP_DISCONNECT, + MGMT_OP_GET_CONNECTIONS, + MGMT_OP_PIN_CODE_REPLY, + MGMT_OP_PIN_CODE_NEG_REPLY, + MGMT_OP_SET_IO_CAPABILITY, + MGMT_OP_PAIR_DEVICE, + MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_OP_UNPAIR_DEVICE, + MGMT_OP_USER_CONFIRM_REPLY, + MGMT_OP_USER_CONFIRM_NEG_REPLY, + MGMT_OP_USER_PASSKEY_REPLY, + MGMT_OP_USER_PASSKEY_NEG_REPLY, + MGMT_OP_READ_LOCAL_OOB_DATA, + MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_OP_START_DISCOVERY, + MGMT_OP_STOP_DISCOVERY, + MGMT_OP_CONFIRM_NAME, + MGMT_OP_BLOCK_DEVICE, + MGMT_OP_UNBLOCK_DEVICE, +}; + +static const u16 mgmt_events[] = { + MGMT_EV_CONTROLLER_ERROR, + MGMT_EV_INDEX_ADDED, + MGMT_EV_INDEX_REMOVED, + MGMT_EV_NEW_SETTINGS, + MGMT_EV_CLASS_OF_DEV_CHANGED, + MGMT_EV_LOCAL_NAME_CHANGED, + MGMT_EV_NEW_LINK_KEY, + MGMT_EV_NEW_LONG_TERM_KEY, + MGMT_EV_DEVICE_CONNECTED, + MGMT_EV_DEVICE_DISCONNECTED, + MGMT_EV_CONNECT_FAILED, + MGMT_EV_PIN_CODE_REQUEST, + MGMT_EV_USER_CONFIRM_REQUEST, + MGMT_EV_USER_PASSKEY_REQUEST, + MGMT_EV_AUTH_FAILED, + MGMT_EV_DEVICE_FOUND, + MGMT_EV_DISCOVERING, + MGMT_EV_DEVICE_BLOCKED, + MGMT_EV_DEVICE_UNBLOCKED, + MGMT_EV_DEVICE_UNPAIRED, +}; + /* * These LE scan and inquiry parameters were chosen according to LE General * Discovery Procedure specification. @@ -206,6 +269,39 @@ static int read_version(struct sock *sk) sizeof(rp)); } +static int read_commands(struct sock *sk) +{ + struct mgmt_rp_read_commands *rp; + u16 num_commands = ARRAY_SIZE(mgmt_commands); + u16 num_events = ARRAY_SIZE(mgmt_events); + u16 *opcode; + size_t rp_size; + int i, err; + + BT_DBG("sock %p", sk); + + rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16)); + + rp = kmalloc(rp_size, GFP_KERNEL); + if (!rp) + return -ENOMEM; + + put_unaligned_le16(num_commands, &rp->num_commands); + put_unaligned_le16(num_events, &rp->num_events); + + for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++) + put_unaligned_le16(mgmt_commands[i], opcode); + + for (i = 0; i < num_events; i++, opcode++) + put_unaligned_le16(mgmt_events[i], opcode); + + err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp, + rp_size); + kfree(rp); + + return err; +} + static int read_index_list(struct sock *sk) { struct mgmt_rp_read_index_list *rp; @@ -2323,6 +2419,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_READ_VERSION: err = read_version(sk); break; + case MGMT_OP_READ_COMMANDS: + err = read_commands(sk); + break; case MGMT_OP_READ_INDEX_LIST: err = read_index_list(sk); break; -- cgit v1.2.3-70-g09d2 From 203159d486006a18fa1ccf787a10d15d3128cdac Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 13 Feb 2012 15:41:01 -0300 Subject: Bluetooth: Fix discovery state machine In case of Start Discovery command failure, we should set the discovery state to DISCOVERY_STOPPED. Otherwise, we stuck at DISCOVERY_STARTING state and subsequent Start Discovery commands will simply fail. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8efbd8eaa1b..066d338be1c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3096,6 +3096,8 @@ int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) struct pending_cmd *cmd; int err; + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev); if (!cmd) return -ENOENT; -- cgit v1.2.3-70-g09d2 From 7b99b659d90c5d421cb1867295c78a4c0c030734 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 13 Feb 2012 15:41:02 -0300 Subject: Bluetooth: Fix event sending with DISCOVERY_STOPPED state We are not supposed to send mgmt_discovering events if we are transiting from DISCOVERY_STARTING to DISCOVERY_STOPPED state. It doesn't make sense to send mgmt_discovering event once discovery procedure has not been even started. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9ada16449ae..dc31e7d6028 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -380,7 +380,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) switch (state) { case DISCOVERY_STOPPED: - mgmt_discovering(hdev, 0); + if (hdev->discovery.state != DISCOVERY_STARTING) + mgmt_discovering(hdev, 0); break; case DISCOVERY_STARTING: break; -- cgit v1.2.3-70-g09d2 From f2cedb63df14342ad40a8b5b324fc5d94a60b665 Mon Sep 17 00:00:00 2001 From: Danny Kukawka Date: Wed, 15 Feb 2012 06:45:39 +0000 Subject: net: replace random_ether_addr() with eth_hw_addr_random() Replace usage of random_ether_addr() with eth_hw_addr_random() to set addr_assign_type correctly to NET_ADDR_RANDOM. Change the trivial cases. v2: adapt to renamed eth_hw_addr_random() Signed-off-by: Danny Kukawka Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 2 +- drivers/net/ethernet/cirrus/ep93xx_eth.c | 2 +- drivers/net/ethernet/davicom/dm9000.c | 2 +- drivers/net/ethernet/dnet.c | 2 +- drivers/net/ethernet/faraday/ftgmac100.c | 2 +- drivers/net/ethernet/faraday/ftmac100.c | 2 +- drivers/net/ethernet/mipsnet.c | 2 +- drivers/net/ethernet/natsemi/macsonic.c | 2 +- drivers/net/ethernet/rdc/r6040.c | 2 +- drivers/net/ethernet/sis/sis900.c | 2 +- drivers/net/ethernet/smsc/smsc9420.c | 5 ++--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- drivers/net/ethernet/toshiba/tc35815.c | 2 +- drivers/net/ethernet/via/via-rhine.c | 2 +- drivers/net/ifb.c | 2 +- drivers/net/tun.c | 2 +- drivers/net/usb/smsc75xx.c | 2 +- drivers/net/usb/smsc95xx.c | 2 +- drivers/net/veth.c | 4 ++-- drivers/net/virtio_net.c | 2 +- drivers/net/wan/hdlc_fr.c | 2 +- drivers/net/wan/hdlc_raw_eth.c | 2 +- net/ipv4/ip_gre.c | 2 +- net/l2tp/l2tp_eth.c | 2 +- 24 files changed, 26 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 85e044567f6..c4834c23be3 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -87,7 +87,7 @@ static void __init macb_get_hwaddr(struct macb *bp) memcpy(bp->dev->dev_addr, addr, sizeof(addr)); } else { netdev_info(bp->dev, "invalid hw address, using random\n"); - random_ether_addr(bp->dev->dev_addr); + eth_hw_addr_random(bp->dev); } } diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index c21e5ab8d1e..78c55213eaf 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -859,7 +859,7 @@ static int ep93xx_eth_probe(struct platform_device *pdev) ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */ if (is_zero_ether_addr(dev->dev_addr)) - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); err = register_netdev(dev); if (err) { diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 42383ab5227..36499d5edd9 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1585,7 +1585,7 @@ dm9000_probe(struct platform_device *pdev) dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " "set using ifconfig\n", ndev->name); - random_ether_addr(ndev->dev_addr); + eth_hw_addr_random(ndev); mac_src = "random"; } diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index 8536e376555..b276469f74e 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -895,7 +895,7 @@ static int __devinit dnet_probe(struct platform_device *pdev) if (!is_valid_ether_addr(dev->dev_addr)) { /* choose a random ethernet address */ - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); __dnet_set_hwaddr(bp); } diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 47f85c337cf..16b07048274 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -1289,7 +1289,7 @@ static int ftgmac100_probe(struct platform_device *pdev) netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base); if (!is_valid_ether_addr(netdev->dev_addr)) { - random_ether_addr(netdev->dev_addr); + eth_hw_addr_random(netdev); netdev_info(netdev, "generated random MAC address %pM\n", netdev->dev_addr); } diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index bb336a0959c..829b1092fd7 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -1133,7 +1133,7 @@ static int ftmac100_probe(struct platform_device *pdev) netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base); if (!is_valid_ether_addr(netdev->dev_addr)) { - random_ether_addr(netdev->dev_addr); + eth_hw_addr_random(netdev); netdev_info(netdev, "generated random MAC address %pM\n", netdev->dev_addr); } diff --git a/drivers/net/ethernet/mipsnet.c b/drivers/net/ethernet/mipsnet.c index dbc666a3d52..db5285befe2 100644 --- a/drivers/net/ethernet/mipsnet.c +++ b/drivers/net/ethernet/mipsnet.c @@ -281,7 +281,7 @@ static int __devinit mipsnet_probe(struct platform_device *dev) * Lacking any better mechanism to allocate a MAC address we use a * random one ... */ - random_ether_addr(netdev->dev_addr); + eth_hw_addr_random(netdev); err = register_netdev(netdev); if (err) { diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c index f1b85561c65..e640e23460d 100644 --- a/drivers/net/ethernet/natsemi/macsonic.c +++ b/drivers/net/ethernet/natsemi/macsonic.c @@ -307,7 +307,7 @@ static void __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev) printk(KERN_WARNING "macsonic: MAC address in CAM entry 15 " "seems invalid, will use a random MAC\n"); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); } static int __devinit mac_onboard_sonic_probe(struct net_device *dev) diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c index 76cab284876..b96e1920e04 100644 --- a/drivers/net/ethernet/rdc/r6040.c +++ b/drivers/net/ethernet/rdc/r6040.c @@ -1151,7 +1151,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, if (!(adrp[0] || adrp[1] || adrp[2])) { netdev_warn(dev, "MAC address not initialized, " "generating random\n"); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); } /* Link new device into r6040_root_dev */ diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index f968898c86d..5ccf02e7e3a 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -527,7 +527,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ret = sis900_get_mac_addr(pci_dev, net_dev); if (!ret || !is_valid_ether_addr(net_dev->dev_addr)) { - random_ether_addr(net_dev->dev_addr); + eth_hw_addr_random(net_dev); printk(KERN_WARNING "%s: Unreadable or invalid MAC address," "using random generated one\n", dev_name); } diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index ee1a1680b7a..38386478532 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -509,10 +509,9 @@ static void smsc9420_check_mac_address(struct net_device *dev) smsc_dbg(PROBE, "Mac Address is read from EEPROM"); } else { /* eeprom values are invalid, generate random MAC */ - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); smsc9420_set_mac_address(dev); - smsc_dbg(PROBE, - "MAC Address is set to random_ether_addr"); + smsc_dbg(PROBE, "MAC Address is set to random"); } } } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 166fc95e5ba..ab36dfcbd81 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -910,7 +910,7 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv) priv->dev->base_addr, priv->dev->dev_addr, 0); if (!is_valid_ether_addr(priv->dev->dev_addr)) - random_ether_addr(priv->dev->dev_addr); + eth_hw_addr_random(priv->dev); } pr_warning("%s: device MAC address %pM\n", priv->dev->name, priv->dev->dev_addr); diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index d117ad475c3..651a70c55e6 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -849,7 +849,7 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev, /* Retrieve the ethernet address. */ if (tc35815_init_dev_addr(dev)) { dev_warn(&pdev->dev, "not valid ether addr\n"); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); } rc = register_netdev(dev); diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index cb2ff28a060..39b8cf3dafc 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -983,7 +983,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (!is_valid_ether_addr(dev->dev_addr)) { /* Report it and use a random ethernet address instead */ netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); netdev_info(dev, "Using random MAC address: %pM\n", dev->dev_addr); } diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index e05b645bbc3..344dceb1aaf 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -184,7 +184,7 @@ static void ifb_setup(struct net_device *dev) dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); } static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 93c5d72711b..2c5d34957c5 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -531,7 +531,7 @@ static void tun_net_init(struct net_device *dev) ether_setup(dev); dev->priv_flags &= ~IFF_TX_SKB_SHARING; - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */ break; diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 3b017bbd2a2..187d01ccb97 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -615,7 +615,7 @@ static void smsc75xx_init_mac_address(struct usbnet *dev) } /* no eeprom, or eeprom values are invalid. generate random MAC */ - random_ether_addr(dev->net->dev_addr); + eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr"); } diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index d45520e6dd4..5f19f84d349 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -614,7 +614,7 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) } /* no eeprom, or eeprom values are invalid. generate random MAC */ - random_ether_addr(dev->net->dev_addr); + eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr\n"); } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 49f4667e1fa..b8a697f5cb6 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -346,7 +346,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, } if (tbp[IFLA_ADDRESS] == NULL) - random_ether_addr(peer->dev_addr); + eth_hw_addr_random(peer); err = register_netdevice(peer); put_net(net); @@ -368,7 +368,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, */ if (tb[IFLA_ADDRESS] == NULL) - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); if (tb[IFLA_IFNAME]) nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 83c503ed4ae..019da012669 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1060,7 +1060,7 @@ static int virtnet_probe(struct virtio_device *vdev) if (virtio_config_val_len(vdev, VIRTIO_NET_F_MAC, offsetof(struct virtio_net_config, mac), dev->dev_addr, dev->addr_len) < 0) - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); /* Set up our device-specific information */ vi = netdev_priv(dev); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index eb2028187fb..7c6cb4f3179 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1087,7 +1087,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) } if (type == ARPHRD_ETHER) - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); else { *(__be16*)dev->dev_addr = htons(dlci); dlci_to_q922(dev->broadcast, dlci); diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 05c9b0b9623..3ab72b3082d 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -101,7 +101,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) old_qlen = dev->tx_queue_len; ether_setup(dev); dev->tx_queue_len = old_qlen; - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); netif_dormant_off(dev); return 0; } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 0286d78c589..b59414a0c1e 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1536,7 +1536,7 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nla return -EEXIST; if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS]) - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); mtu = ipgre_tunnel_bind_dev(dev); if (!tb[IFLA_MTU]) diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index d2726a74597..63fe5f353f0 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -64,7 +64,7 @@ static int l2tp_eth_dev_init(struct net_device *dev) struct l2tp_eth *priv = netdev_priv(dev); priv->dev = dev; - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); memset(&dev->broadcast[0], 0xff, 6); return 0; -- cgit v1.2.3-70-g09d2 From 7ce5d222190cb3ce3ae88bafde7c4fa52a5103e0 Mon Sep 17 00:00:00 2001 From: Danny Kukawka Date: Wed, 15 Feb 2012 06:45:40 +0000 Subject: net: use eth_hw_addr_random() and reset addr_assign_type Use eth_hw_addr_random() instead of calling random_ether_addr() to set addr_assign_type correctly to NET_ADDR_RANDOM. Reset the state to NET_ADDR_PERM as soon as the MAC get changed via .ndo_set_mac_address. v2: adapt to renamed eth_hw_addr_random() Signed-off-by: Danny Kukawka Signed-off-by: David S. Miller --- drivers/net/dummy.c | 3 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 1 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 +- drivers/net/ethernet/calxeda/xgmac.c | 3 ++- drivers/net/ethernet/marvell/pxa168_eth.c | 3 ++- drivers/net/ethernet/micrel/ks8842.c | 3 ++- drivers/net/ethernet/micrel/ks8851.c | 3 ++- drivers/net/ethernet/micrel/ks8851_mll.c | 1 + drivers/net/ethernet/microchip/enc28j60.c | 3 ++- drivers/net/ethernet/nvidia/forcedeth.c | 3 ++- drivers/net/ethernet/smsc/smsc911x.c | 3 ++- drivers/net/ethernet/tile/tilepro.c | 3 ++- drivers/net/macvlan.c | 3 ++- drivers/net/team/team.c | 3 ++- net/bridge/br_device.c | 3 ++- net/openvswitch/vport-internal_dev.c | 3 ++- 16 files changed, 29 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 087648ea1ed..d5c6d92f1ee 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -47,6 +47,7 @@ static int dummy_set_address(struct net_device *dev, void *p) if (!is_valid_ether_addr(sa->sa_data)) return -EADDRNOTAVAIL; + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); return 0; } @@ -135,7 +136,7 @@ static void dummy_setup(struct net_device *dev) dev->flags &= ~IFF_MULTICAST; dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO; dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX; - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); } static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 5d15efc2a9e..aa14502289c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3007,6 +3007,7 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p) return rc; } + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); if (netif_running(dev)) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index b9afd26cfbe..8e809c1408b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9683,7 +9683,7 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) if (BP_NOMCP(bp)) { BNX2X_ERROR("warning: random MAC workaround active\n"); - random_ether_addr(bp->dev->dev_addr); + eth_hw_addr_random(bp->dev); } else if (IS_MF(bp)) { val2 = MF_CFG_RD(bp, func_mf_config[func].mac_upper); val = MF_CFG_RD(bp, func_mf_config[func].mac_lower); diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index 1fce186a903..11f667f6131 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -1012,7 +1012,7 @@ static int xgmac_open(struct net_device *dev) * address using the following linux command: * ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) { - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); netdev_dbg(priv->dev, "generated random MAC address %pM\n", dev->dev_addr); } @@ -1482,6 +1482,7 @@ static int xgmac_set_mac_address(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); xgmac_set_mac_addr(ioaddr, dev->dev_addr, 0); diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 75df2091bd2..83e37ad113e 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -629,6 +629,7 @@ static int pxa168_eth_set_mac_address(struct net_device *dev, void *addr) if (!is_valid_ether_addr(sa->sa_data)) return -EINVAL; memcpy(oldMac, dev->dev_addr, ETH_ALEN); + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); netif_addr_lock_bh(dev); update_hash_table_mac_address(pep, oldMac, dev->dev_addr); @@ -1520,7 +1521,7 @@ static int pxa168_eth_probe(struct platform_device *pdev) INIT_WORK(&pep->tx_timeout_task, pxa168_eth_tx_timeout_task); printk(KERN_INFO "%s:Using random mac address\n", DRIVER_NAME); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); pep->pd = pdev->dev.platform_data; pep->rx_ring_size = NUM_RX_DESCS; diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c index 0a85690a132..0686b93f185 100644 --- a/drivers/net/ethernet/micrel/ks8842.c +++ b/drivers/net/ethernet/micrel/ks8842.c @@ -1080,6 +1080,7 @@ static int ks8842_set_mac(struct net_device *netdev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + netdev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(netdev->dev_addr, mac, netdev->addr_len); ks8842_write_mac_addr(adapter, mac); @@ -1211,7 +1212,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev) ks8842_read_mac_addr(adapter, netdev->dev_addr); if (!is_valid_ether_addr(netdev->dev_addr)) - random_ether_addr(netdev->dev_addr); + eth_hw_addr_random(netdev); } id = ks8842_read16(adapter, 32, REG_SW_ID_AND_ENABLE); diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index 0930b9c950d..42a6a20efb1 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -439,7 +439,7 @@ static void ks8851_init_mac(struct ks8851_net *ks) dev->dev_addr); } - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); ks8851_write_mac_addr(dev); } @@ -1050,6 +1050,7 @@ static int ks8851_set_mac_address(struct net_device *dev, void *addr) if (!is_valid_ether_addr(sa->sa_data)) return -EADDRNOTAVAIL; + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); return ks8851_write_mac_addr(dev); } diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c index 3d9a04e7b49..180460f4e41 100644 --- a/drivers/net/ethernet/micrel/ks8851_mll.c +++ b/drivers/net/ethernet/micrel/ks8851_mll.c @@ -1241,6 +1241,7 @@ static int ks_set_mac_address(struct net_device *netdev, void *paddr) struct sockaddr *addr = paddr; u8 *da; + netdev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); da = (u8 *)netdev->dev_addr; diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c index 1d6b7ce3e1e..6118bdad244 100644 --- a/drivers/net/ethernet/microchip/enc28j60.c +++ b/drivers/net/ethernet/microchip/enc28j60.c @@ -527,6 +527,7 @@ static int enc28j60_set_mac_address(struct net_device *dev, void *addr) if (!is_valid_ether_addr(address->sa_data)) return -EADDRNOTAVAIL; + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, address->sa_data, dev->addr_len); return enc28j60_set_hw_macaddr(dev); } @@ -1575,7 +1576,7 @@ static int __devinit enc28j60_probe(struct spi_device *spi) ret = -EIO; goto error_irq; } - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); enc28j60_set_hw_macaddr(dev); /* Board setup must set the relevant edge trigger type; diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 5eeb92f8738..8561dd25db6 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -3022,6 +3022,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr) /* synchronized against open : rtnl_lock() held by caller */ memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN); + dev->addr_assign_type &= ~NET_ADDR_RANDOM; if (netif_running(dev)) { netif_tx_lock_bh(dev); @@ -5741,7 +5742,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev_err(&pci_dev->dev, "Invalid MAC address detected: %pM - Please complain to your hardware vendor.\n", dev->dev_addr); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); dev_err(&pci_dev->dev, "Using random MAC address: %pM\n", dev->dev_addr); } diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 6a1cd236081..4a697102707 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1833,6 +1833,7 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); spin_lock_irq(&pdata->mac_lock); @@ -2485,7 +2486,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) "Mac Address is read from LAN911x EEPROM"); } else { /* eeprom values are invalid, generate random MAC */ - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); smsc911x_set_hw_mac_address(pdata, dev->dev_addr); SMSC_TRACE(pdata, probe, "MAC Address is set to random_ether_addr"); diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index a8e5daaef6f..948c4f2a2d6 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -2190,6 +2190,7 @@ static int tile_net_set_mac_address(struct net_device *dev, void *p) /* ISSUE: Note that "dev_addr" is now a pointer. */ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + dev->addr_assign_type &= ~NET_ADDR_RANDOM; return 0; } @@ -2254,7 +2255,7 @@ static int tile_net_get_mac(struct net_device *dev) * can't get its MAC address, we are most likely running * the simulator, so let's generate a random MAC address. */ - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); } return 0; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 9ea99217f11..f975afdc315 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -372,6 +372,7 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) if (!(dev->flags & IFF_UP)) { /* Just copy in the new address */ + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); } else { /* Rehash and update the device filters */ @@ -687,7 +688,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, return -EINVAL; if (!tb[IFLA_ADDRESS]) - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); if (!macvlan_port_exists(lowerdev)) { err = macvlan_port_create(lowerdev); diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 6b678f38e5c..8f81805c682 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -868,6 +868,7 @@ static int team_set_mac_address(struct net_device *dev, void *p) struct team_port *port; struct sockaddr *addr = p; + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); rcu_read_lock(); list_for_each_entry_rcu(port, &team->port_list, list) @@ -1087,7 +1088,7 @@ static int team_newlink(struct net *src_net, struct net_device *dev, int err; if (tb[IFLA_ADDRESS] == NULL) - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); err = register_netdevice(dev); if (err) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 71773b014e0..a157bf827d8 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -171,6 +171,7 @@ static int br_set_mac_address(struct net_device *dev, void *p) spin_lock_bh(&br->lock); if (compare_ether_addr(dev->dev_addr, addr->sa_data)) { + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); br_fdb_change_mac_address(br, addr->sa_data); br_stp_change_bridge_id(br, addr->sa_data); @@ -334,7 +335,7 @@ void br_dev_setup(struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); ether_setup(dev); dev->netdev_ops = &br_netdev_ops; diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 322b8d20669..b6b1d7daa3c 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -66,6 +66,7 @@ static int internal_dev_mac_addr(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); return 0; } @@ -145,7 +146,7 @@ static void do_setup(struct net_device *netdev) netdev->vlan_features = netdev->features; netdev->features |= NETIF_F_HW_VLAN_TX; netdev->hw_features = netdev->features & ~NETIF_F_LLTX; - random_ether_addr(netdev->dev_addr); + eth_hw_addr_random(netdev); } static struct vport *internal_dev_create(const struct vport_parms *parms) -- cgit v1.2.3-70-g09d2 From 80703d265b7e8a801560d907b1bfe340e574dbca Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 15 Feb 2012 17:48:35 -0500 Subject: ipv4: Eliminate spurious argument to __ipv4_neigh_lookup 'tbl' is always arp_tbl, so specifying it is pointless. Signed-off-by: David S. Miller --- include/net/arp.h | 4 ++-- net/ipv4/route.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/arp.h b/include/net/arp.h index 0013dc87940..4a1f3fb562e 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -15,14 +15,14 @@ static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd return val * hash_rnd; } -static inline struct neighbour *__ipv4_neigh_lookup(struct neigh_table *tbl, struct net_device *dev, u32 key) +static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key) { struct neigh_hash_table *nht; struct neighbour *n; u32 hash_val; rcu_read_lock_bh(); - nht = rcu_dereference_bh(tbl->nht); + nht = rcu_dereference_bh(arp_tbl.nht); hash_val = arp_hashfn(key, dev, nht->hash_rnd[0]) >> (32 - nht->hash_shift); for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); n != NULL; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4eeb8ce856e..0489cedc167 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1127,7 +1127,7 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const vo else if (rt->rt_gateway) pkey = (const __be32 *) &rt->rt_gateway; - n = __ipv4_neigh_lookup(&arp_tbl, dev, *(__force u32 *)pkey); + n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey); if (n) return n; return neigh_create(&arp_tbl, pkey, dev); -- cgit v1.2.3-70-g09d2 From 7ddb6e0f3f7aa265c905b947e9ac4ab9562e52f2 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 14 Feb 2012 15:12:57 +0200 Subject: Bluetooth: Do not dereference zero sk Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 16360298590..138fe344667 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -795,7 +795,7 @@ static void l2cap_sock_kill(struct sock *sk) static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_chan *chan; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -803,6 +803,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) if (!sk) return 0; + chan = l2cap_pi(sk)->chan; + lock_sock(sk); if (!sk->sk_shutdown) { if (chan->mode == L2CAP_MODE_ERTM) -- cgit v1.2.3-70-g09d2 From 17071578888c7c18709e48e74fae228c04581b9a Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 7 Nov 2011 16:36:40 +0100 Subject: batman-adv: add tt_initialised flag to the orig_node struct (ttvn == 0) is currently used as initial condition. However this is not a good idea because ttvn gets the vale zero each time after reaching the maximum value (wrap around). For this reason a new flag is added in order to define whether a node has an initialised table or not. Moreover, after invoking tt_global_del_orig(), tt_initialised has to be set to false Reported-by: Alexey Fisher Signed-off-by: Antonio Quartulli Signed-off-by: Simon Wunderlich Tested-by: Alexey Fisher Signed-off-by: Marek Lindner --- net/batman-adv/originator.c | 1 + net/batman-adv/translation-table.c | 11 ++++++++--- net/batman-adv/types.h | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0bc2045a2f2..847ff7e98a6 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -219,6 +219,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr) /* extra reference for return */ atomic_set(&orig_node->refcount, 2); + orig_node->tt_initialised = false; orig_node->tt_poss_change = false; orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index ab8dea8b0b2..c632475df37 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -733,6 +733,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv, spin_unlock_bh(list_lock); } atomic_set(&orig_node->tt_size, 0); + orig_node->tt_initialised = false; } static void tt_global_roam_purge(struct bat_priv *bat_priv) @@ -1450,6 +1451,7 @@ static void _tt_update_changes(struct bat_priv *bat_priv, */ return; } + orig_node->tt_initialised = true; } static void tt_fill_gtable(struct bat_priv *bat_priv, @@ -1854,8 +1856,10 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); bool full_table = true; - /* the ttvn increased by one -> we can apply the attached changes */ - if (ttvn - orig_ttvn == 1) { + /* orig table not initialised AND first diff is in the OGM OR the ttvn + * increased by one -> we can apply the attached changes */ + if ((!orig_node->tt_initialised && ttvn == 1) || + ttvn - orig_ttvn == 1) { /* the OGM could not contain the changes due to their size or * because they have already been sent TT_OGM_APPEND_MAX times. * In this case send a tt request */ @@ -1889,7 +1893,8 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, } else { /* if we missed more than one change or our tables are not * in sync anymore -> request fresh tt data */ - if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) { + if (!orig_node->tt_initialised || ttvn != orig_ttvn || + orig_node->tt_crc != tt_crc) { request_table: bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. " "Need to retrieve the correct information " diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index e9eb043719a..35085f410b9 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -81,6 +81,7 @@ struct orig_node { int16_t tt_buff_len; spinlock_t tt_buff_lock; /* protects tt_buff */ atomic_t tt_size; + bool tt_initialised; /* The tt_poss_change flag is used to detect an ongoing roaming phase. * If true, then I sent a Roaming_adv to this orig_node and I have to * inspect every packet directed to it to check whether it is still -- cgit v1.2.3-70-g09d2 From 76543d14aec6ce5cb3fc7be9b39c50fcebd2043b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 20 Nov 2011 15:47:38 +0100 Subject: batman-adv: Explicitly mark the common header structure All batman-adv packets have a common 3 byte header. It can be used to share some code between different code paths, but it was never explicit stated that this header has to be always the same for all packets. Therefore, new code changes always have the problem that they may accidently introduce regressions by moving some elements around. A new structure is introduced that contains the common header and makes it easier visible that these 3 bytes have to be the same for all on-wire packets. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/bat_iv_ogm.c | 47 +++++++++++++++++++------------------- net/batman-adv/hard-interface.c | 6 ++--- net/batman-adv/icmp_socket.c | 6 ++--- net/batman-adv/packet.h | 38 +++++++++++------------------- net/batman-adv/routing.c | 18 +++++++-------- net/batman-adv/send.c | 2 +- net/batman-adv/soft-interface.c | 14 ++++++------ net/batman-adv/translation-table.c | 24 +++++++++---------- net/batman-adv/unicast.c | 16 ++++++------- net/batman-adv/vis.c | 14 ++++++------ 10 files changed, 87 insertions(+), 98 deletions(-) (limited to 'net') diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 3512e251545..d60e1ba0bc1 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -38,10 +38,10 @@ void bat_ogm_init(struct hard_iface *hard_iface) hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC); batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff; - batman_ogm_packet->packet_type = BAT_OGM; - batman_ogm_packet->version = COMPAT_VERSION; + batman_ogm_packet->header.packet_type = BAT_OGM; + batman_ogm_packet->header.version = COMPAT_VERSION; + batman_ogm_packet->header.ttl = 2; batman_ogm_packet->flags = NO_FLAGS; - batman_ogm_packet->ttl = 2; batman_ogm_packet->tq = TQ_MAX_VALUE; batman_ogm_packet->tt_num_changes = 0; batman_ogm_packet->ttvn = 0; @@ -53,7 +53,7 @@ void bat_ogm_init_primary(struct hard_iface *hard_iface) batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff; batman_ogm_packet->flags = PRIMARIES_FIRST_HOP; - batman_ogm_packet->ttl = TTL; + batman_ogm_packet->header.ttl = TTL; } void bat_ogm_update_mac(struct hard_iface *hard_iface) @@ -137,7 +137,7 @@ static void bat_ogm_send_to_if(struct forw_packet *forw_packet, fwd_str, (packet_num > 0 ? "aggregated " : ""), batman_ogm_packet->orig, ntohl(batman_ogm_packet->seqno), - batman_ogm_packet->tq, batman_ogm_packet->ttl, + batman_ogm_packet->tq, batman_ogm_packet->header.ttl, (batman_ogm_packet->flags & DIRECTLINK ? "on" : "off"), batman_ogm_packet->ttvn, hard_iface->net_dev->name, @@ -188,7 +188,7 @@ void bat_ogm_emit(struct forw_packet *forw_packet) /* multihomed peer assumed */ /* non-primary OGMs are only broadcasted on their interface */ - if ((directlink && (batman_ogm_packet->ttl == 1)) || + if ((directlink && (batman_ogm_packet->header.ttl == 1)) || (forw_packet->own && (forw_packet->if_incoming != primary_if))) { /* FIXME: what about aggregated packets ? */ @@ -198,7 +198,7 @@ void bat_ogm_emit(struct forw_packet *forw_packet) (forw_packet->own ? "Sending own" : "Forwarding"), batman_ogm_packet->orig, ntohl(batman_ogm_packet->seqno), - batman_ogm_packet->ttl, + batman_ogm_packet->header.ttl, forw_packet->if_incoming->net_dev->name, forw_packet->if_incoming->net_dev->dev_addr); @@ -272,7 +272,7 @@ static bool bat_ogm_can_aggregate(const struct batman_ogm_packet * are flooded through the net */ if ((!directlink) && (!(batman_ogm_packet->flags & DIRECTLINK)) && - (batman_ogm_packet->ttl != 1) && + (batman_ogm_packet->header.ttl != 1) && /* own packets originating non-primary * interfaces leave only that interface */ @@ -285,7 +285,7 @@ static bool bat_ogm_can_aggregate(const struct batman_ogm_packet /* if the incoming packet is sent via this one * interface only - we still can aggregate */ if ((directlink) && - (new_batman_ogm_packet->ttl == 1) && + (new_batman_ogm_packet->header.ttl == 1) && (forw_packet->if_incoming == if_incoming) && /* packets from direct neighbors or @@ -471,7 +471,7 @@ static void bat_ogm_forward(struct orig_node *orig_node, uint8_t in_tq, in_ttl, tq_avg = 0; uint8_t tt_num_changes; - if (batman_ogm_packet->ttl <= 1) { + if (batman_ogm_packet->header.ttl <= 1) { bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); return; } @@ -479,10 +479,10 @@ static void bat_ogm_forward(struct orig_node *orig_node, router = orig_node_get_router(orig_node); in_tq = batman_ogm_packet->tq; - in_ttl = batman_ogm_packet->ttl; + in_ttl = batman_ogm_packet->header.ttl; tt_num_changes = batman_ogm_packet->tt_num_changes; - batman_ogm_packet->ttl--; + batman_ogm_packet->header.ttl--; memcpy(batman_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN); /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast @@ -494,7 +494,8 @@ static void bat_ogm_forward(struct orig_node *orig_node, batman_ogm_packet->tq = router->tq_avg; if (router->last_ttl) - batman_ogm_packet->ttl = router->last_ttl - 1; + batman_ogm_packet->header.ttl = + router->last_ttl - 1; } tq_avg = router->tq_avg; @@ -510,7 +511,7 @@ static void bat_ogm_forward(struct orig_node *orig_node, "Forwarding packet: tq_orig: %i, tq_avg: %i, " "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", in_tq, tq_avg, batman_ogm_packet->tq, in_ttl - 1, - batman_ogm_packet->ttl); + batman_ogm_packet->header.ttl); batman_ogm_packet->seqno = htonl(batman_ogm_packet->seqno); batman_ogm_packet->tt_crc = htons(batman_ogm_packet->tt_crc); @@ -642,8 +643,8 @@ static void bat_ogm_orig_update(struct bat_priv *bat_priv, spin_unlock_bh(&neigh_node->tq_lock); if (!is_duplicate) { - orig_node->last_ttl = batman_ogm_packet->ttl; - neigh_node->last_ttl = batman_ogm_packet->ttl; + orig_node->last_ttl = batman_ogm_packet->header.ttl; + neigh_node->last_ttl = batman_ogm_packet->header.ttl; } bonding_candidate_add(orig_node, neigh_node); @@ -683,7 +684,7 @@ update_tt: /* I have to check for transtable changes only if the OGM has been * sent through a primary interface */ if (((batman_ogm_packet->orig != ethhdr->h_source) && - (batman_ogm_packet->ttl > 2)) || + (batman_ogm_packet->header.ttl > 2)) || (batman_ogm_packet->flags & PRIMARIES_FIRST_HOP)) tt_update_orig(bat_priv, orig_node, tt_buff, batman_ogm_packet->tt_num_changes, @@ -918,7 +919,7 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, * packet in an aggregation. Here we expect that the padding * is always zero (or not 0x01) */ - if (batman_ogm_packet->packet_type != BAT_OGM) + if (batman_ogm_packet->header.packet_type != BAT_OGM) return; /* could be changed by schedule_own_packet() */ @@ -938,8 +939,8 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, batman_ogm_packet->prev_sender, batman_ogm_packet->seqno, batman_ogm_packet->ttvn, batman_ogm_packet->tt_crc, batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq, - batman_ogm_packet->ttl, batman_ogm_packet->version, - has_directlink_flag); + batman_ogm_packet->header.ttl, + batman_ogm_packet->header.version, has_directlink_flag); rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &hardif_list, list) { @@ -966,10 +967,10 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, } rcu_read_unlock(); - if (batman_ogm_packet->version != COMPAT_VERSION) { + if (batman_ogm_packet->header.version != COMPAT_VERSION) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: incompatible batman version (%i)\n", - batman_ogm_packet->version); + batman_ogm_packet->header.version); return; } @@ -1091,7 +1092,7 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, if (is_bidirectional && (!is_duplicate || ((orig_node->last_real_seqno == batman_ogm_packet->seqno) && - (orig_node->last_ttl - 3 <= batman_ogm_packet->ttl)))) + (orig_node->last_ttl - 3 <= batman_ogm_packet->header.ttl)))) bat_ogm_orig_update(bat_priv, orig_node, ethhdr, batman_ogm_packet, if_incoming, tt_buff, is_duplicate); diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 7704df468e0..d3e0e32e51c 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -590,17 +590,17 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, batman_ogm_packet = (struct batman_ogm_packet *)skb->data; - if (batman_ogm_packet->version != COMPAT_VERSION) { + if (batman_ogm_packet->header.version != COMPAT_VERSION) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: incompatible batman version (%i)\n", - batman_ogm_packet->version); + batman_ogm_packet->header.version); goto err_free; } /* all receive handlers return whether they received or reused * the supplied skb. if not, we have to free the skb. */ - switch (batman_ogm_packet->packet_type) { + switch (batman_ogm_packet->header.packet_type) { /* batman originator packet */ case BAT_OGM: ret = recv_bat_ogm_packet(skb, hard_iface); diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index d9c1e7bb7fb..5d69e103faa 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -191,7 +191,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, goto free_skb; } - if (icmp_packet->packet_type != BAT_ICMP) { + if (icmp_packet->header.packet_type != BAT_ICMP) { bat_dbg(DBG_BATMAN, bat_priv, "Error - can't send packet from char device: " "got bogus packet type (expected: BAT_ICMP)\n"); @@ -209,9 +209,9 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, icmp_packet->uid = socket_client->index; - if (icmp_packet->version != COMPAT_VERSION) { + if (icmp_packet->header.version != COMPAT_VERSION) { icmp_packet->msg_type = PARAMETER_PROBLEM; - icmp_packet->version = COMPAT_VERSION; + icmp_packet->header.version = COMPAT_VERSION; bat_socket_add_packet(socket_client, icmp_packet, packet_len); goto free_skb; } diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 4d9e54c57a3..88c717b9344 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -90,10 +90,14 @@ enum tt_client_flags { TT_CLIENT_PENDING = 1 << 10 }; -struct batman_ogm_packet { +struct batman_header { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; +} __packed; + +struct batman_ogm_packet { + struct batman_header header; uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ uint32_t seqno; uint8_t orig[6]; @@ -108,9 +112,7 @@ struct batman_ogm_packet { #define BATMAN_OGM_LEN sizeof(struct batman_ogm_packet) struct icmp_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; + struct batman_header header; uint8_t msg_type; /* see ICMP message types above */ uint8_t dst[6]; uint8_t orig[6]; @@ -124,9 +126,7 @@ struct icmp_packet { /* icmp_packet_rr must start with all fields from imcp_packet * as this is assumed by code that handles ICMP packets */ struct icmp_packet_rr { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; + struct batman_header header; uint8_t msg_type; /* see ICMP message types above */ uint8_t dst[6]; uint8_t orig[6]; @@ -137,17 +137,13 @@ struct icmp_packet_rr { } __packed; struct unicast_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; + struct batman_header header; uint8_t ttvn; /* destination translation table version number */ uint8_t dest[6]; } __packed; struct unicast_frag_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; + struct batman_header header; uint8_t ttvn; /* destination translation table version number */ uint8_t dest[6]; uint8_t flags; @@ -157,18 +153,14 @@ struct unicast_frag_packet { } __packed; struct bcast_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; + struct batman_header header; uint8_t reserved; uint32_t seqno; uint8_t orig[6]; } __packed; struct vis_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; /* TTL */ + struct batman_header header; uint8_t vis_type; /* which type of vis-participant sent this? */ uint32_t seqno; /* sequence number */ uint8_t entries; /* number of entries behind this struct */ @@ -179,9 +171,7 @@ struct vis_packet { } __packed; struct tt_query_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; + struct batman_header header; /* the flag field is a combination of: * - TT_REQUEST or TT_RESPONSE * - TT_FULL_TABLE */ @@ -202,9 +192,7 @@ struct tt_query_packet { } __packed; struct roam_adv_packet { - uint8_t packet_type; - uint8_t version; - uint8_t ttl; + struct batman_header header; uint8_t reserved; uint8_t dst[ETH_ALEN]; uint8_t src[ETH_ALEN]; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 773e606f970..4363d197aeb 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -320,7 +320,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = ECHO_REPLY; - icmp_packet->ttl = TTL; + icmp_packet->header.ttl = TTL; send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; @@ -376,7 +376,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = TTL_EXCEEDED; - icmp_packet->ttl = TTL; + icmp_packet->header.ttl = TTL; send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; @@ -441,7 +441,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) return recv_my_icmp_packet(bat_priv, skb, hdr_size); /* TTL exceeded */ - if (icmp_packet->ttl < 2) + if (icmp_packet->header.ttl < 2) return recv_icmp_ttl_exceeded(bat_priv, skb); /* get routing information */ @@ -460,7 +460,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) icmp_packet = (struct icmp_packet_rr *)skb->data; /* decrement ttl */ - icmp_packet->ttl--; + icmp_packet->header.ttl--; /* route it */ send_skb_packet(skb, router->if_incoming, router->addr); @@ -815,7 +815,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) unicast_packet = (struct unicast_packet *)skb->data; /* TTL exceeded */ - if (unicast_packet->ttl < 2) { + if (unicast_packet->header.ttl < 2) { pr_debug("Warning - can't forward unicast packet from %pM to " "%pM: ttl exceeded\n", ethhdr->h_source, unicast_packet->dest); @@ -840,7 +840,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) unicast_packet = (struct unicast_packet *)skb->data; - if (unicast_packet->packet_type == BAT_UNICAST && + if (unicast_packet->header.packet_type == BAT_UNICAST && atomic_read(&bat_priv->fragmentation) && skb->len > neigh_node->if_incoming->net_dev->mtu) { ret = frag_send_skb(skb, bat_priv, @@ -848,7 +848,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) goto out; } - if (unicast_packet->packet_type == BAT_UNICAST_FRAG && + if (unicast_packet->header.packet_type == BAT_UNICAST_FRAG && frag_can_reassemble(skb, neigh_node->if_incoming->net_dev->mtu)) { ret = frag_reassemble_skb(skb, bat_priv, &new_skb); @@ -867,7 +867,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) } /* decrement ttl */ - unicast_packet->ttl--; + unicast_packet->header.ttl--; /* route it */ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); @@ -1041,7 +1041,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if) if (is_my_mac(bcast_packet->orig)) goto out; - if (bcast_packet->ttl < 2) + if (bcast_packet->header.ttl < 2) goto out; orig_node = orig_hash_find(bat_priv, bcast_packet->orig); diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 8a684eb738a..b00a0f537b4 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -234,7 +234,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, /* as we have a copy now, it is safe to decrease the TTL */ bcast_packet = (struct bcast_packet *)newskb->data; - bcast_packet->ttl--; + bcast_packet->header.ttl--; skb_reset_mac_header(newskb); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 987c75a775f..bd8c7cfaeac 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -457,10 +457,10 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, batman_ogm_packet = (struct batman_ogm_packet *) (skb->data + ETH_HLEN); - if (batman_ogm_packet->version != COMPAT_VERSION) + if (batman_ogm_packet->header.version != COMPAT_VERSION) goto out; - if (batman_ogm_packet->packet_type != BAT_OGM) + if (batman_ogm_packet->header.packet_type != BAT_OGM) goto out; if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP)) @@ -632,11 +632,11 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) goto dropped; bcast_packet = (struct bcast_packet *)skb->data; - bcast_packet->version = COMPAT_VERSION; - bcast_packet->ttl = TTL; + bcast_packet->header.version = COMPAT_VERSION; + bcast_packet->header.ttl = TTL; /* batman packet type: broadcast */ - bcast_packet->packet_type = BAT_BCAST; + bcast_packet->header.packet_type = BAT_BCAST; /* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ @@ -725,8 +725,8 @@ void interface_rx(struct net_device *soft_iface, skb_push(skb, hdr_size); unicast_packet = (struct unicast_packet *)skb->data; - if ((unicast_packet->packet_type != BAT_UNICAST) && - (unicast_packet->packet_type != BAT_UNICAST_FRAG)) + if ((unicast_packet->header.packet_type != BAT_UNICAST) && + (unicast_packet->header.packet_type != BAT_UNICAST_FRAG)) goto dropped; skb_reset_mac_header(skb); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index c632475df37..bc518fca0b6 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1135,11 +1135,11 @@ static int send_tt_request(struct bat_priv *bat_priv, tt_request = (struct tt_query_packet *)skb_put(skb, sizeof(struct tt_query_packet)); - tt_request->packet_type = BAT_TT_QUERY; - tt_request->version = COMPAT_VERSION; + tt_request->header.packet_type = BAT_TT_QUERY; + tt_request->header.version = COMPAT_VERSION; memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); - tt_request->ttl = TTL; + tt_request->header.ttl = TTL; tt_request->ttvn = ttvn; tt_request->tt_data = tt_crc; tt_request->flags = TT_REQUEST; @@ -1265,9 +1265,9 @@ static bool send_other_tt_response(struct bat_priv *bat_priv, tt_response = (struct tt_query_packet *)skb->data; } - tt_response->packet_type = BAT_TT_QUERY; - tt_response->version = COMPAT_VERSION; - tt_response->ttl = TTL; + tt_response->header.packet_type = BAT_TT_QUERY; + tt_response->header.version = COMPAT_VERSION; + tt_response->header.ttl = TTL; memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); memcpy(tt_response->dst, tt_request->src, ETH_ALEN); tt_response->flags = TT_RESPONSE; @@ -1382,9 +1382,9 @@ static bool send_my_tt_response(struct bat_priv *bat_priv, tt_response = (struct tt_query_packet *)skb->data; } - tt_response->packet_type = BAT_TT_QUERY; - tt_response->version = COMPAT_VERSION; - tt_response->ttl = TTL; + tt_response->header.packet_type = BAT_TT_QUERY; + tt_response->header.version = COMPAT_VERSION; + tt_response->header.ttl = TTL; memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(tt_response->dst, tt_request->src, ETH_ALEN); tt_response->flags = TT_RESPONSE; @@ -1671,9 +1671,9 @@ void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client, roam_adv_packet = (struct roam_adv_packet *)skb_put(skb, sizeof(struct roam_adv_packet)); - roam_adv_packet->packet_type = BAT_ROAM_ADV; - roam_adv_packet->version = COMPAT_VERSION; - roam_adv_packet->ttl = TTL; + roam_adv_packet->header.packet_type = BAT_ROAM_ADV; + roam_adv_packet->header.version = COMPAT_VERSION; + roam_adv_packet->header.ttl = TTL; primary_if = primary_if_get_selected(bat_priv); if (!primary_if) goto out; diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index 07d1c1da89d..6f3c65952f5 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -67,7 +67,7 @@ static struct sk_buff *frag_merge_packet(struct list_head *head, memmove(skb->data + uni_diff, skb->data, hdr_len); unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); - unicast_packet->packet_type = BAT_UNICAST; + unicast_packet->header.packet_type = BAT_UNICAST; return skb; @@ -251,9 +251,9 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, memcpy(frag1, &tmp_uc, sizeof(tmp_uc)); - frag1->ttl--; - frag1->version = COMPAT_VERSION; - frag1->packet_type = BAT_UNICAST_FRAG; + frag1->header.ttl--; + frag1->header.version = COMPAT_VERSION; + frag1->header.packet_type = BAT_UNICAST_FRAG; memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(frag2, frag1, sizeof(*frag2)); @@ -320,11 +320,11 @@ find_router: unicast_packet = (struct unicast_packet *)skb->data; - unicast_packet->version = COMPAT_VERSION; + unicast_packet->header.version = COMPAT_VERSION; /* batman packet type: unicast */ - unicast_packet->packet_type = BAT_UNICAST; + unicast_packet->header.packet_type = BAT_UNICAST; /* set unicast ttl */ - unicast_packet->ttl = TTL; + unicast_packet->header.ttl = TTL; /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); /* set the destination tt version number */ @@ -335,7 +335,7 @@ find_router: data_len + sizeof(*unicast_packet) > neigh_node->if_incoming->net_dev->mtu) { /* send frag skb decreases ttl */ - unicast_packet->ttl++; + unicast_packet->header.ttl++; ret = frag_send_skb(skb, bat_priv, neigh_node->if_incoming, neigh_node->addr); goto out; diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index cc3b9f2f3b5..ac7e6610059 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -617,7 +617,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) packet->vis_type = atomic_read(&bat_priv->vis_mode); memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); - packet->ttl = TTL; + packet->header.ttl = TTL; packet->seqno = htonl(ntohl(packet->seqno) + 1); packet->entries = 0; skb_trim(info->skb_packet, sizeof(*packet)); @@ -818,19 +818,19 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) goto out; packet = (struct vis_packet *)info->skb_packet->data; - if (packet->ttl < 2) { + if (packet->header.ttl < 2) { pr_debug("Error - can't send vis packet: ttl exceeded\n"); goto out; } memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN); - packet->ttl--; + packet->header.ttl--; if (is_broadcast_ether_addr(packet->target_orig)) broadcast_vis_packet(bat_priv, info); else unicast_vis_packet(bat_priv, info); - packet->ttl++; /* restore TTL */ + packet->header.ttl++; /* restore TTL */ out: if (primary_if) @@ -910,9 +910,9 @@ int vis_init(struct bat_priv *bat_priv) INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list); kref_init(&bat_priv->my_vis_info->refcount); bat_priv->my_vis_info->bat_priv = bat_priv; - packet->version = COMPAT_VERSION; - packet->packet_type = BAT_VIS; - packet->ttl = TTL; + packet->header.version = COMPAT_VERSION; + packet->header.packet_type = BAT_VIS; + packet->header.ttl = TTL; packet->seqno = 0; packet->entries = 0; -- cgit v1.2.3-70-g09d2 From 8780dad9e97f564da0eb3443009c3203122e7e7d Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 5 Dec 2011 04:01:51 +0800 Subject: batman-adv: simplify bat_ogm_receive API call Most of the values in that call are derived from the skb, so we can hand over the skb instead. Reported-by: Simon Wunderlich Signed-off-by: Marek Lindner --- net/batman-adv/bat_iv_ogm.c | 11 +++++++---- net/batman-adv/bat_ogm.h | 3 +-- net/batman-adv/routing.c | 4 +--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index d60e1ba0bc1..3402fa575b4 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1140,13 +1140,16 @@ out: orig_node_free_ref(orig_node); } -void bat_ogm_receive(const struct ethhdr *ethhdr, unsigned char *packet_buff, - int packet_len, struct hard_iface *if_incoming) +void bat_ogm_receive(struct hard_iface *if_incoming, struct sk_buff *skb) { struct batman_ogm_packet *batman_ogm_packet; - int buff_pos = 0; - unsigned char *tt_buff; + struct ethhdr *ethhdr; + int buff_pos = 0, packet_len; + unsigned char *tt_buff, *packet_buff; + packet_len = skb_headlen(skb); + ethhdr = (struct ethhdr *)skb_mac_header(skb); + packet_buff = skb->data; batman_ogm_packet = (struct batman_ogm_packet *)packet_buff; /* unpack the aggregated packets and process them one by one */ diff --git a/net/batman-adv/bat_ogm.h b/net/batman-adv/bat_ogm.h index 69329c107e2..47edfde6f92 100644 --- a/net/batman-adv/bat_ogm.h +++ b/net/batman-adv/bat_ogm.h @@ -29,7 +29,6 @@ void bat_ogm_init_primary(struct hard_iface *hard_iface); void bat_ogm_update_mac(struct hard_iface *hard_iface); void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes); void bat_ogm_emit(struct forw_packet *forw_packet); -void bat_ogm_receive(const struct ethhdr *ethhdr, unsigned char *packet_buff, - int packet_len, struct hard_iface *if_incoming); +void bat_ogm_receive(struct hard_iface *if_incoming, struct sk_buff *skb); #endif /* _NET_BATMAN_ADV_OGM_H_ */ diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 4363d197aeb..5bc41c896e3 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -272,9 +272,7 @@ int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface) if (skb_linearize(skb) < 0) return NET_RX_DROP; - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - bat_ogm_receive(ethhdr, skb->data, skb_headlen(skb), hard_iface); + bat_ogm_receive(hard_iface, skb); kfree_skb(skb); return NET_RX_SUCCESS; -- cgit v1.2.3-70-g09d2 From c51f9c09fabc96f23e449b5e39b1fc4e2cabcd85 Mon Sep 17 00:00:00 2001 From: Martin Hundebøll Date: Thu, 8 Dec 2011 12:48:26 +0100 Subject: batman-adv: Rm empty line from is_my_mac() in main.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Hundebøll Signed-off-by: Marek Lindner --- net/batman-adv/main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index fb87bdc2ce9..71b56cf9cdd 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -170,7 +170,6 @@ int is_my_mac(const uint8_t *addr) } rcu_read_unlock(); return 0; - } module_init(batman_init); -- cgit v1.2.3-70-g09d2 From a04ccd5970ec11f0b320971051435d86d3233c92 Mon Sep 17 00:00:00 2001 From: Martin Hundebøll Date: Thu, 8 Dec 2011 13:32:41 +0100 Subject: batman-adv: Move is_out_of_time() to main.h for general use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both translation tables and network coding use timeouts to do house keeping, so we might as well share the function used to compare a timestamp+timeout with current time. For readability and simplicity, the function is renamed to has_timed_out() and uses time_is_before_jiffies() instead of time_after(). Signed-off-by: Martin Hundebøll Signed-off-by: Marek Lindner --- net/batman-adv/main.h | 11 +++++++++++ net/batman-adv/translation-table.c | 32 ++++++++++++-------------------- 2 files changed, 23 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 86354e06eb4..f9c659b3f3a 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -202,6 +202,17 @@ static inline int compare_eth(const void *data1, const void *data2) return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); } +/** + * has_timed_out - compares current time (jiffies) and timestamp + timeout + * @timestamp: base value to compare with (in jiffies) + * @timeout: added to base value before comparing (in milliseconds) + * + * Returns true if current time is after timestamp + timeout + */ +static inline bool has_timed_out(unsigned long timestamp, unsigned int timeout) +{ + return time_is_before_jiffies(timestamp + msecs_to_jiffies(timeout)); +} #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index bc518fca0b6..a84e80409f9 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -108,14 +108,6 @@ static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv, } -static bool is_out_of_time(unsigned long starting_time, unsigned long timeout) -{ - unsigned long deadline; - deadline = starting_time + msecs_to_jiffies(timeout); - - return time_after(jiffies, deadline); -} - static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry) { if (atomic_dec_and_test(&tt_local_entry->common.refcount)) @@ -420,8 +412,8 @@ static void tt_local_purge(struct bat_priv *bat_priv) if (tt_local_entry->common.flags & TT_CLIENT_PENDING) continue; - if (!is_out_of_time(tt_local_entry->last_seen, - TT_LOCAL_TIMEOUT * 1000)) + if (!has_timed_out(tt_local_entry->last_seen, + TT_LOCAL_TIMEOUT * 1000)) continue; tt_local_set_pending(bat_priv, tt_local_entry, @@ -758,8 +750,8 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv) common); if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM)) continue; - if (!is_out_of_time(tt_global_entry->roam_at, - TT_CLIENT_ROAM_TIMEOUT * 1000)) + if (!has_timed_out(tt_global_entry->roam_at, + TT_CLIENT_ROAM_TIMEOUT * 1000)) continue; bat_dbg(DBG_TT, bat_priv, "Deleting global " @@ -978,8 +970,8 @@ static void tt_req_purge(struct bat_priv *bat_priv) spin_lock_bh(&bat_priv->tt_req_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { - if (is_out_of_time(node->issued_at, - TT_REQUEST_TIMEOUT * 1000)) { + if (has_timed_out(node->issued_at, + TT_REQUEST_TIMEOUT * 1000)) { list_del(&node->list); kfree(node); } @@ -997,8 +989,8 @@ static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, spin_lock_bh(&bat_priv->tt_req_list_lock); list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { if (compare_eth(tt_req_node_tmp, orig_node) && - !is_out_of_time(tt_req_node_tmp->issued_at, - TT_REQUEST_TIMEOUT * 1000)) + !has_timed_out(tt_req_node_tmp->issued_at, + TT_REQUEST_TIMEOUT * 1000)) goto unlock; } @@ -1591,8 +1583,8 @@ static void tt_roam_purge(struct bat_priv *bat_priv) spin_lock_bh(&bat_priv->tt_roam_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { - if (!is_out_of_time(node->first_time, - ROAMING_MAX_TIME * 1000)) + if (!has_timed_out(node->first_time, + ROAMING_MAX_TIME * 1000)) continue; list_del(&node->list); @@ -1619,8 +1611,8 @@ static bool tt_check_roam_count(struct bat_priv *bat_priv, if (!compare_eth(tt_roam_node->addr, client)) continue; - if (is_out_of_time(tt_roam_node->first_time, - ROAMING_MAX_TIME * 1000)) + if (has_timed_out(tt_roam_node->first_time, + ROAMING_MAX_TIME * 1000)) continue; if (!atomic_dec_not_zero(&tt_roam_node->counter)) -- cgit v1.2.3-70-g09d2 From 6e242f9037f8a82ce2608c20a5460b670b2d5ff4 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Wed, 7 Dec 2011 18:02:50 +0800 Subject: batman-adv: warn if added interface is part of a bridge Signed-off-by: Marek Lindner --- net/batman-adv/hard-interface.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index d3e0e32e51c..68b667c1d85 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -281,6 +281,14 @@ int hardif_enable_interface(struct hard_iface *hard_iface, if (!atomic_inc_not_zero(&hard_iface->refcount)) goto out; + /* hard-interface is part of a bridge */ + if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT) + pr_err("You are about to enable batman-adv on '%s' which " + "already is part of a bridge. Unless you know exactly " + "what you are doing this is probably wrong and won't " + "work the way you think it would.\n", + hard_iface->net_dev->name); + soft_iface = dev_get_by_name(&init_net, iface_name); if (!soft_iface) { -- cgit v1.2.3-70-g09d2 From 1c280471b013e26c833fc86acc231c73442cfa21 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 28 Nov 2011 17:40:17 +0800 Subject: batman-adv: add infrastructure to change routing algorithm at runtime Signed-off-by: Marek Lindner --- net/batman-adv/bat_algo.h | 27 ++++++++++++++++ net/batman-adv/bat_debugfs.c | 22 +++++++++++++ net/batman-adv/bat_iv_ogm.c | 10 ++++++ net/batman-adv/main.c | 72 +++++++++++++++++++++++++++++++++++++++++ net/batman-adv/main.h | 4 +++ net/batman-adv/soft-interface.c | 4 +++ net/batman-adv/types.h | 6 ++++ 7 files changed, 145 insertions(+) create mode 100644 net/batman-adv/bat_algo.h (limited to 'net') diff --git a/net/batman-adv/bat_algo.h b/net/batman-adv/bat_algo.h new file mode 100644 index 00000000000..755379fd367 --- /dev/null +++ b/net/batman-adv/bat_algo.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2011 B.A.T.M.A.N. contributors: + * + * Marek Lindner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef _NET_BATMAN_ADV_BAT_ALGO_H_ +#define _NET_BATMAN_ADV_BAT_ALGO_H_ + +int bat_iv_init(void); + +#endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */ diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c index d0af9bf69e4..a7a393eeb93 100644 --- a/net/batman-adv/bat_debugfs.c +++ b/net/batman-adv/bat_debugfs.c @@ -221,6 +221,11 @@ static void debug_log_cleanup(struct bat_priv *bat_priv) } #endif +static int bat_algorithms_open(struct inode *inode, struct file *file) +{ + return single_open(file, bat_algo_seq_print_text, NULL); +} + static int originators_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; @@ -274,6 +279,7 @@ struct bat_debuginfo bat_debuginfo_##_name = { \ } \ }; +static BAT_DEBUGINFO(routing_algos, S_IRUGO, bat_algorithms_open); static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); @@ -293,9 +299,25 @@ static struct bat_debuginfo *mesh_debuginfos[] = { void debugfs_init(void) { + struct bat_debuginfo *bat_debug; + struct dentry *file; + bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); if (bat_debugfs == ERR_PTR(-ENODEV)) bat_debugfs = NULL; + + if (!bat_debugfs) + goto out; + + bat_debug = &bat_debuginfo_routing_algos; + file = debugfs_create_file(bat_debug->attr.name, + S_IFREG | bat_debug->attr.mode, + bat_debugfs, NULL, &bat_debug->fops); + if (!file) + pr_err("Can't add debugfs file: %s\n", bat_debug->attr.name); + +out: + return; } void debugfs_destroy(void) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 3402fa575b4..1847efaaa6f 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -29,6 +29,7 @@ #include "gateway_client.h" #include "hard-interface.h" #include "send.h" +#include "bat_algo.h" void bat_ogm_init(struct hard_iface *hard_iface) { @@ -1172,3 +1173,12 @@ void bat_ogm_receive(struct hard_iface *if_incoming, struct sk_buff *skb) } while (bat_ogm_aggr_packet(buff_pos, packet_len, batman_ogm_packet->tt_num_changes)); } + +static struct bat_algo_ops batman_iv __read_mostly = { + .name = "BATMAN IV", +}; + +int __init bat_iv_init(void) +{ + return bat_algo_register(&batman_iv); +} diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 71b56cf9cdd..7c87a341f29 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -32,11 +32,14 @@ #include "gateway_client.h" #include "vis.h" #include "hash.h" +#include "bat_algo.h" /* List manipulations on hardif_list have to be rtnl_lock()'ed, * list traversals just rcu-locked */ struct list_head hardif_list; +char bat_routing_algo[20] = "BATMAN IV"; +static struct hlist_head bat_algo_list; unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -45,6 +48,9 @@ struct workqueue_struct *bat_event_workqueue; static int __init batman_init(void) { INIT_LIST_HEAD(&hardif_list); + INIT_HLIST_HEAD(&bat_algo_list); + + bat_iv_init(); /* the name should not be longer than 10 chars - see * http://lwn.net/Articles/23634/ */ @@ -172,6 +178,72 @@ int is_my_mac(const uint8_t *addr) return 0; } +static struct bat_algo_ops *bat_algo_get(char *name) +{ + struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; + struct hlist_node *node; + + hlist_for_each_entry(bat_algo_ops_tmp, node, &bat_algo_list, list) { + if (strcmp(bat_algo_ops_tmp->name, name) != 0) + continue; + + bat_algo_ops = bat_algo_ops_tmp; + break; + } + + return bat_algo_ops; +} + +int bat_algo_register(struct bat_algo_ops *bat_algo_ops) +{ + struct bat_algo_ops *bat_algo_ops_tmp; + int ret = -1; + + bat_algo_ops_tmp = bat_algo_get(bat_algo_ops->name); + if (bat_algo_ops_tmp) { + pr_info("Trying to register already registered routing " + "algorithm: %s\n", bat_algo_ops->name); + goto out; + } + + INIT_HLIST_NODE(&bat_algo_ops->list); + hlist_add_head(&bat_algo_ops->list, &bat_algo_list); + ret = 0; + +out: + return ret; +} + +int bat_algo_select(struct bat_priv *bat_priv, char *name) +{ + struct bat_algo_ops *bat_algo_ops; + int ret = -1; + + bat_algo_ops = bat_algo_get(name); + if (!bat_algo_ops) + goto out; + + bat_priv->bat_algo_ops = bat_algo_ops; + ret = 0; + +out: + return ret; +} + +int bat_algo_seq_print_text(struct seq_file *seq, void *offset) +{ + struct bat_algo_ops *bat_algo_ops; + struct hlist_node *node; + + seq_printf(seq, "Available routing algorithms:\n"); + + hlist_for_each_entry(bat_algo_ops, node, &bat_algo_list, list) { + seq_printf(seq, "%s\n", bat_algo_ops->name); + } + + return 0; +} + module_init(batman_init); module_exit(batman_exit); diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index f9c659b3f3a..586afafb1b6 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -147,6 +147,7 @@ enum dbg_level { #include #include "types.h" +extern char bat_routing_algo[]; extern struct list_head hardif_list; extern unsigned char broadcast_addr[]; @@ -157,6 +158,9 @@ void mesh_free(struct net_device *soft_iface); void inc_module_count(void); void dec_module_count(void); int is_my_mac(const uint8_t *addr); +int bat_algo_register(struct bat_algo_ops *bat_algo_ops); +int bat_algo_select(struct bat_priv *bat_priv, char *name); +int bat_algo_seq_print_text(struct seq_file *seq, void *offset); #ifdef CONFIG_BATMAN_ADV_DEBUG int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) __printf(2, 3); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index bd8c7cfaeac..b5aecd5e45c 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -855,6 +855,10 @@ struct net_device *softif_create(const char *name) bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0; + ret = bat_algo_select(bat_priv, bat_routing_algo); + if (ret < 0) + goto unreg_soft_iface; + ret = sysfs_add_meshif(soft_iface); if (ret < 0) goto unreg_soft_iface; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 35085f410b9..d21ff2cf668 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -206,6 +206,7 @@ struct bat_priv { atomic_t gw_reselect; struct hard_iface __rcu *primary_if; /* rcu protected pointer */ struct vis_info *my_vis_info; + struct bat_algo_ops *bat_algo_ops; }; struct socket_client { @@ -344,4 +345,9 @@ struct softif_neigh { struct rcu_head rcu; }; +struct bat_algo_ops { + struct hlist_node list; + char *name; +}; + #endif /* _NET_BATMAN_ADV_TYPES_H_ */ -- cgit v1.2.3-70-g09d2 From 01c4224b51feba2ba64d070ab9f4aa32c9d0bb29 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 28 Nov 2011 21:31:55 +0800 Subject: batman-adv: convert batman iv algorithm to use dynamic infrastructure Signed-off-by: Marek Lindner --- net/batman-adv/bat_iv_ogm.c | 179 +++++++++++++++++++++------------------- net/batman-adv/bat_ogm.h | 34 -------- net/batman-adv/hard-interface.c | 10 +-- net/batman-adv/main.c | 12 +++ net/batman-adv/routing.c | 4 +- net/batman-adv/send.c | 5 +- net/batman-adv/types.h | 14 ++++ 7 files changed, 129 insertions(+), 129 deletions(-) delete mode 100644 net/batman-adv/bat_ogm.h (limited to 'net') diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 1847efaaa6f..1c483a5dd80 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -20,7 +20,6 @@ */ #include "main.h" -#include "bat_ogm.h" #include "translation-table.h" #include "ring_buffer.h" #include "originator.h" @@ -31,7 +30,7 @@ #include "send.h" #include "bat_algo.h" -void bat_ogm_init(struct hard_iface *hard_iface) +static void bat_iv_ogm_init(struct hard_iface *hard_iface) { struct batman_ogm_packet *batman_ogm_packet; @@ -48,7 +47,7 @@ void bat_ogm_init(struct hard_iface *hard_iface) batman_ogm_packet->ttvn = 0; } -void bat_ogm_init_primary(struct hard_iface *hard_iface) +static void bat_iv_ogm_init_primary(struct hard_iface *hard_iface) { struct batman_ogm_packet *batman_ogm_packet; @@ -57,7 +56,7 @@ void bat_ogm_init_primary(struct hard_iface *hard_iface) batman_ogm_packet->header.ttl = TTL; } -void bat_ogm_update_mac(struct hard_iface *hard_iface) +static void bat_iv_ogm_update_mac(struct hard_iface *hard_iface) { struct batman_ogm_packet *batman_ogm_packet; @@ -69,7 +68,7 @@ void bat_ogm_update_mac(struct hard_iface *hard_iface) } /* when do we schedule our own ogm to be sent */ -static unsigned long bat_ogm_emit_send_time(const struct bat_priv *bat_priv) +static unsigned long bat_iv_ogm_emit_send_time(const struct bat_priv *bat_priv) { return jiffies + msecs_to_jiffies( atomic_read(&bat_priv->orig_interval) - @@ -77,7 +76,7 @@ static unsigned long bat_ogm_emit_send_time(const struct bat_priv *bat_priv) } /* when do we schedule a ogm packet to be sent */ -static unsigned long bat_ogm_fwd_send_time(void) +static unsigned long bat_iv_ogm_fwd_send_time(void) { return jiffies + msecs_to_jiffies(random32() % (JITTER/2)); } @@ -90,8 +89,8 @@ static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv) } /* is there another aggregated packet here? */ -static int bat_ogm_aggr_packet(int buff_pos, int packet_len, - int tt_num_changes) +static int bat_iv_ogm_aggr_packet(int buff_pos, int packet_len, + int tt_num_changes) { int next_buff_pos = buff_pos + BATMAN_OGM_LEN + tt_len(tt_num_changes); @@ -100,8 +99,8 @@ static int bat_ogm_aggr_packet(int buff_pos, int packet_len, } /* send a batman ogm to a given interface */ -static void bat_ogm_send_to_if(struct forw_packet *forw_packet, - struct hard_iface *hard_iface) +static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet, + struct hard_iface *hard_iface) { struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); char *fwd_str; @@ -118,8 +117,8 @@ static void bat_ogm_send_to_if(struct forw_packet *forw_packet, batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data; /* adjust all flags and log packets */ - while (bat_ogm_aggr_packet(buff_pos, forw_packet->packet_len, - batman_ogm_packet->tt_num_changes)) { + while (bat_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len, + batman_ogm_packet->tt_num_changes)) { /* we might have aggregated direct link packets with an * ordinary base packet */ @@ -158,7 +157,7 @@ static void bat_ogm_send_to_if(struct forw_packet *forw_packet, } /* send a batman ogm packet */ -void bat_ogm_emit(struct forw_packet *forw_packet) +static void bat_iv_ogm_emit(struct forw_packet *forw_packet) { struct hard_iface *hard_iface; struct net_device *soft_iface; @@ -217,7 +216,7 @@ void bat_ogm_emit(struct forw_packet *forw_packet) if (hard_iface->soft_iface != soft_iface) continue; - bat_ogm_send_to_if(forw_packet, hard_iface); + bat_iv_ogm_send_to_if(forw_packet, hard_iface); } rcu_read_unlock(); @@ -227,13 +226,13 @@ out: } /* return true if new_packet can be aggregated with forw_packet */ -static bool bat_ogm_can_aggregate(const struct batman_ogm_packet +static bool bat_iv_ogm_can_aggregate(const struct batman_ogm_packet *new_batman_ogm_packet, - struct bat_priv *bat_priv, - int packet_len, unsigned long send_time, - bool directlink, - const struct hard_iface *if_incoming, - const struct forw_packet *forw_packet) + struct bat_priv *bat_priv, + int packet_len, unsigned long send_time, + bool directlink, + const struct hard_iface *if_incoming, + const struct forw_packet *forw_packet) { struct batman_ogm_packet *batman_ogm_packet; int aggregated_bytes = forw_packet->packet_len + packet_len; @@ -307,11 +306,11 @@ out: } /* create a new aggregated packet and add this packet to it */ -static void bat_ogm_aggregate_new(const unsigned char *packet_buff, - int packet_len, unsigned long send_time, - bool direct_link, - struct hard_iface *if_incoming, - int own_packet) +static void bat_iv_ogm_aggregate_new(const unsigned char *packet_buff, + int packet_len, unsigned long send_time, + bool direct_link, + struct hard_iface *if_incoming, + int own_packet) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct forw_packet *forw_packet_aggr; @@ -386,9 +385,9 @@ out: } /* aggregate a new packet into the existing ogm packet */ -static void bat_ogm_aggregate(struct forw_packet *forw_packet_aggr, - const unsigned char *packet_buff, - int packet_len, bool direct_link) +static void bat_iv_ogm_aggregate(struct forw_packet *forw_packet_aggr, + const unsigned char *packet_buff, + int packet_len, bool direct_link) { unsigned char *skb_buff; @@ -403,10 +402,10 @@ static void bat_ogm_aggregate(struct forw_packet *forw_packet_aggr, (1 << forw_packet_aggr->num_packets); } -static void bat_ogm_queue_add(struct bat_priv *bat_priv, - unsigned char *packet_buff, - int packet_len, struct hard_iface *if_incoming, - int own_packet, unsigned long send_time) +static void bat_iv_ogm_queue_add(struct bat_priv *bat_priv, + unsigned char *packet_buff, + int packet_len, struct hard_iface *if_incoming, + int own_packet, unsigned long send_time) { /** * _aggr -> pointer to the packet we want to aggregate with @@ -426,11 +425,11 @@ static void bat_ogm_queue_add(struct bat_priv *bat_priv, if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { hlist_for_each_entry(forw_packet_pos, tmp_node, &bat_priv->forw_bat_list, list) { - if (bat_ogm_can_aggregate(batman_ogm_packet, - bat_priv, packet_len, - send_time, direct_link, - if_incoming, - forw_packet_pos)) { + if (bat_iv_ogm_can_aggregate(batman_ogm_packet, + bat_priv, packet_len, + send_time, direct_link, + if_incoming, + forw_packet_pos)) { forw_packet_aggr = forw_packet_pos; break; } @@ -452,20 +451,20 @@ static void bat_ogm_queue_add(struct bat_priv *bat_priv, (atomic_read(&bat_priv->aggregated_ogms))) send_time += msecs_to_jiffies(MAX_AGGREGATION_MS); - bat_ogm_aggregate_new(packet_buff, packet_len, - send_time, direct_link, - if_incoming, own_packet); + bat_iv_ogm_aggregate_new(packet_buff, packet_len, + send_time, direct_link, + if_incoming, own_packet); } else { - bat_ogm_aggregate(forw_packet_aggr, packet_buff, packet_len, - direct_link); + bat_iv_ogm_aggregate(forw_packet_aggr, packet_buff, + packet_len, direct_link); spin_unlock_bh(&bat_priv->forw_bat_list_lock); } } -static void bat_ogm_forward(struct orig_node *orig_node, - const struct ethhdr *ethhdr, - struct batman_ogm_packet *batman_ogm_packet, - int directlink, struct hard_iface *if_incoming) +static void bat_iv_ogm_forward(struct orig_node *orig_node, + const struct ethhdr *ethhdr, + struct batman_ogm_packet *batman_ogm_packet, + int directlink, struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct neigh_node *router; @@ -524,12 +523,13 @@ static void bat_ogm_forward(struct orig_node *orig_node, else batman_ogm_packet->flags &= ~DIRECTLINK; - bat_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet, - BATMAN_OGM_LEN + tt_len(tt_num_changes), - if_incoming, 0, bat_ogm_fwd_send_time()); + bat_iv_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet, + BATMAN_OGM_LEN + tt_len(tt_num_changes), + if_incoming, 0, bat_iv_ogm_fwd_send_time()); } -void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes) +static void bat_iv_ogm_schedule(struct hard_iface *hard_iface, + int tt_num_changes) { struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batman_ogm_packet *batman_ogm_packet; @@ -566,21 +566,22 @@ void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes) atomic_inc(&hard_iface->seqno); slide_own_bcast_window(hard_iface); - bat_ogm_queue_add(bat_priv, hard_iface->packet_buff, - hard_iface->packet_len, hard_iface, 1, - bat_ogm_emit_send_time(bat_priv)); + bat_iv_ogm_queue_add(bat_priv, hard_iface->packet_buff, + hard_iface->packet_len, hard_iface, 1, + bat_iv_ogm_emit_send_time(bat_priv)); if (primary_if) hardif_free_ref(primary_if); } -static void bat_ogm_orig_update(struct bat_priv *bat_priv, - struct orig_node *orig_node, - const struct ethhdr *ethhdr, - const struct batman_ogm_packet +static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv, + struct orig_node *orig_node, + const struct ethhdr *ethhdr, + const struct batman_ogm_packet *batman_ogm_packet, - struct hard_iface *if_incoming, - const unsigned char *tt_buff, int is_duplicate) + struct hard_iface *if_incoming, + const unsigned char *tt_buff, + int is_duplicate) { struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; struct neigh_node *router = NULL; @@ -715,10 +716,10 @@ out: neigh_node_free_ref(router); } -static int bat_ogm_calc_tq(struct orig_node *orig_node, - struct orig_node *orig_neigh_node, - struct batman_ogm_packet *batman_ogm_packet, - struct hard_iface *if_incoming) +static int bat_iv_ogm_calc_tq(struct orig_node *orig_node, + struct orig_node *orig_neigh_node, + struct batman_ogm_packet *batman_ogm_packet, + struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct neigh_node *neigh_node = NULL, *tmp_neigh_node; @@ -827,10 +828,10 @@ out: * -1 the packet is old and has been received while the seqno window * was protected. Caller should drop it. */ -static int bat_ogm_update_seqnos(const struct ethhdr *ethhdr, - const struct batman_ogm_packet +static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, + const struct batman_ogm_packet *batman_ogm_packet, - const struct hard_iface *if_incoming) + const struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct orig_node *orig_node; @@ -892,10 +893,10 @@ out: return ret; } -static void bat_ogm_process(const struct ethhdr *ethhdr, - struct batman_ogm_packet *batman_ogm_packet, - const unsigned char *tt_buff, - struct hard_iface *if_incoming) +static void bat_iv_ogm_process(const struct ethhdr *ethhdr, + struct batman_ogm_packet *batman_ogm_packet, + const unsigned char *tt_buff, + struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct hard_iface *hard_iface; @@ -1033,8 +1034,8 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, if (!orig_node) return; - is_duplicate = bat_ogm_update_seqnos(ethhdr, batman_ogm_packet, - if_incoming); + is_duplicate = bat_iv_ogm_update_seqnos(ethhdr, batman_ogm_packet, + if_incoming); if (is_duplicate == -1) { bat_dbg(DBG_BATMAN, bat_priv, @@ -1083,8 +1084,8 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, goto out_neigh; } - is_bidirectional = bat_ogm_calc_tq(orig_node, orig_neigh_node, - batman_ogm_packet, if_incoming); + is_bidirectional = bat_iv_ogm_calc_tq(orig_node, orig_neigh_node, + batman_ogm_packet, if_incoming); bonding_save_primary(orig_node, orig_neigh_node, batman_ogm_packet); @@ -1094,16 +1095,16 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, (!is_duplicate || ((orig_node->last_real_seqno == batman_ogm_packet->seqno) && (orig_node->last_ttl - 3 <= batman_ogm_packet->header.ttl)))) - bat_ogm_orig_update(bat_priv, orig_node, ethhdr, - batman_ogm_packet, if_incoming, - tt_buff, is_duplicate); + bat_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, + batman_ogm_packet, if_incoming, + tt_buff, is_duplicate); /* is single hop (direct) neighbor */ if (is_single_hop_neigh) { /* mark direct link on incoming interface */ - bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet, - 1, if_incoming); + bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet, + 1, if_incoming); bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " "rebroadcast neighbor packet with direct link flag\n"); @@ -1125,7 +1126,8 @@ static void bat_ogm_process(const struct ethhdr *ethhdr, bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: rebroadcast originator packet\n"); - bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet, 0, if_incoming); + bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet, + 0, if_incoming); out_neigh: if ((orig_neigh_node) && (!is_single_hop_neigh)) @@ -1141,7 +1143,8 @@ out: orig_node_free_ref(orig_node); } -void bat_ogm_receive(struct hard_iface *if_incoming, struct sk_buff *skb) +static void bat_iv_ogm_receive(struct hard_iface *if_incoming, + struct sk_buff *skb) { struct batman_ogm_packet *batman_ogm_packet; struct ethhdr *ethhdr; @@ -1162,20 +1165,26 @@ void bat_ogm_receive(struct hard_iface *if_incoming, struct sk_buff *skb) tt_buff = packet_buff + buff_pos + BATMAN_OGM_LEN; - bat_ogm_process(ethhdr, batman_ogm_packet, - tt_buff, if_incoming); + bat_iv_ogm_process(ethhdr, batman_ogm_packet, + tt_buff, if_incoming); buff_pos += BATMAN_OGM_LEN + tt_len(batman_ogm_packet->tt_num_changes); batman_ogm_packet = (struct batman_ogm_packet *) (packet_buff + buff_pos); - } while (bat_ogm_aggr_packet(buff_pos, packet_len, - batman_ogm_packet->tt_num_changes)); + } while (bat_iv_ogm_aggr_packet(buff_pos, packet_len, + batman_ogm_packet->tt_num_changes)); } static struct bat_algo_ops batman_iv __read_mostly = { .name = "BATMAN IV", + .bat_ogm_init = bat_iv_ogm_init, + .bat_ogm_init_primary = bat_iv_ogm_init_primary, + .bat_ogm_update_mac = bat_iv_ogm_update_mac, + .bat_ogm_schedule = bat_iv_ogm_schedule, + .bat_ogm_emit = bat_iv_ogm_emit, + .bat_ogm_receive = bat_iv_ogm_receive, }; int __init bat_iv_init(void) diff --git a/net/batman-adv/bat_ogm.h b/net/batman-adv/bat_ogm.h deleted file mode 100644 index 47edfde6f92..00000000000 --- a/net/batman-adv/bat_ogm.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_OGM_H_ -#define _NET_BATMAN_ADV_OGM_H_ - -#include "main.h" - -void bat_ogm_init(struct hard_iface *hard_iface); -void bat_ogm_init_primary(struct hard_iface *hard_iface); -void bat_ogm_update_mac(struct hard_iface *hard_iface); -void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes); -void bat_ogm_emit(struct forw_packet *forw_packet); -void bat_ogm_receive(struct hard_iface *if_incoming, struct sk_buff *skb); - -#endif /* _NET_BATMAN_ADV_OGM_H_ */ diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 68b667c1d85..ff5ba406b1c 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -28,7 +28,6 @@ #include "bat_sysfs.h" #include "originator.h" #include "hash.h" -#include "bat_ogm.h" #include @@ -147,7 +146,7 @@ static void primary_if_select(struct bat_priv *bat_priv, if (!new_hard_iface) return; - bat_ogm_init_primary(new_hard_iface); + bat_priv->bat_algo_ops->bat_ogm_init_primary(new_hard_iface); primary_if_update_addr(bat_priv); } @@ -233,7 +232,7 @@ static void hardif_activate_interface(struct hard_iface *hard_iface) bat_priv = netdev_priv(hard_iface->soft_iface); - bat_ogm_update_mac(hard_iface); + bat_priv->bat_algo_ops->bat_ogm_update_mac(hard_iface); hard_iface->if_status = IF_TO_BE_ACTIVATED; /** @@ -315,7 +314,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface, hard_iface->soft_iface = soft_iface; bat_priv = netdev_priv(hard_iface->soft_iface); - bat_ogm_init(hard_iface); + bat_priv->bat_algo_ops->bat_ogm_init(hard_iface); if (!hard_iface->packet_buff) { bat_err(hard_iface->soft_iface, "Can't add interface packet " @@ -535,9 +534,10 @@ static int hard_if_event(struct notifier_block *this, goto hardif_put; check_known_mac_addr(hard_iface->net_dev); - bat_ogm_update_mac(hard_iface); bat_priv = netdev_priv(hard_iface->soft_iface); + bat_priv->bat_algo_ops->bat_ogm_update_mac(hard_iface); + primary_if = primary_if_get_selected(bat_priv); if (!primary_if) goto hardif_put; diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 7c87a341f29..bcc2bddd893 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -206,6 +206,18 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops) goto out; } + /* all algorithms must implement all ops (for now) */ + if (!bat_algo_ops->bat_ogm_init || + !bat_algo_ops->bat_ogm_init_primary || + !bat_algo_ops->bat_ogm_update_mac || + !bat_algo_ops->bat_ogm_schedule || + !bat_algo_ops->bat_ogm_emit || + !bat_algo_ops->bat_ogm_receive) { + pr_info("Routing algo '%s' does not implement required ops\n", + bat_algo_ops->name); + goto out; + } + INIT_HLIST_NODE(&bat_algo_ops->list); hlist_add_head(&bat_algo_ops->list, &bat_algo_list); ret = 0; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 5bc41c896e3..b72d7f3b3c6 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -29,7 +29,6 @@ #include "originator.h" #include "vis.h" #include "unicast.h" -#include "bat_ogm.h" void slide_own_bcast_window(struct hard_iface *hard_iface) { @@ -248,6 +247,7 @@ int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff, int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface) { + struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct ethhdr *ethhdr; /* drop packet if it has not necessary minimum size */ @@ -272,7 +272,7 @@ int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface) if (skb_linearize(skb) < 0) return NET_RX_DROP; - bat_ogm_receive(hard_iface, skb); + bat_priv->bat_algo_ops->bat_ogm_receive(hard_iface, skb); kfree_skb(skb); return NET_RX_SUCCESS; diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index b00a0f537b4..019337e3eaf 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -28,7 +28,6 @@ #include "vis.h" #include "gateway_common.h" #include "originator.h" -#include "bat_ogm.h" static void send_outstanding_bcast_packet(struct work_struct *work); @@ -168,7 +167,7 @@ void schedule_bat_ogm(struct hard_iface *hard_iface) if (primary_if) hardif_free_ref(primary_if); - bat_ogm_schedule(hard_iface, tt_num_changes); + bat_priv->bat_algo_ops->bat_ogm_schedule(hard_iface, tt_num_changes); } static void forw_packet_free(struct forw_packet *forw_packet) @@ -318,7 +317,7 @@ void send_outstanding_bat_ogm_packet(struct work_struct *work) if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; - bat_ogm_emit(forw_packet); + bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet); /** * we have to have at least one packet in the queue diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index d21ff2cf668..650ce5fb119 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -348,6 +348,20 @@ struct softif_neigh { struct bat_algo_ops { struct hlist_node list; char *name; + /* init OGM when hard-interface is enabled */ + void (*bat_ogm_init)(struct hard_iface *hard_iface); + /* init primary OGM when primary interface is selected */ + void (*bat_ogm_init_primary)(struct hard_iface *hard_iface); + /* init mac addresses of the OGM belonging to this hard-interface */ + void (*bat_ogm_update_mac)(struct hard_iface *hard_iface); + /* prepare a new outgoing OGM for the send queue */ + void (*bat_ogm_schedule)(struct hard_iface *hard_iface, + int tt_num_changes); + /* send scheduled OGM */ + void (*bat_ogm_emit)(struct forw_packet *forw_packet); + /* receive incoming OGM */ + void (*bat_ogm_receive)(struct hard_iface *if_incoming, + struct sk_buff *skb); }; #endif /* _NET_BATMAN_ADV_TYPES_H_ */ -- cgit v1.2.3-70-g09d2 From 032b7969f8874d5ddc65691cd3d008beffd2a09e Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Tue, 20 Dec 2011 19:30:40 +0800 Subject: batman-adv: convert time_after instances to has_timed_out To increase readability the has_timed_out() functions has been introduced. This patch converts existing time_after() calls to use this wrapper function (if applicable). This patch also converts all timeouts to miliseconds to be consistent. Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich --- net/batman-adv/gateway_client.c | 2 +- net/batman-adv/main.h | 13 +++++++------ net/batman-adv/originator.c | 11 ++++------- net/batman-adv/routing.c | 3 +-- net/batman-adv/soft-interface.c | 4 ++-- net/batman-adv/translation-table.c | 15 ++++++--------- net/batman-adv/vis.c | 3 +-- net/batman-adv/vis.h | 3 ++- 8 files changed, 24 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 24403a7350f..df5631e1f2a 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -396,7 +396,7 @@ void gw_node_purge(struct bat_priv *bat_priv) { struct gw_node *gw_node, *curr_gw; struct hlist_node *node, *node_tmp; - unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; + unsigned long timeout = msecs_to_jiffies(2 * PURGE_TIMEOUT); int do_deselect = 0; curr_gw = gw_get_selected_gw_node(bat_priv); diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 586afafb1b6..ecfed88d0d4 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -41,13 +41,14 @@ /* purge originators after time in seconds if no valid packet comes in * -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */ -#define PURGE_TIMEOUT 200 -#define TT_LOCAL_TIMEOUT 3600 /* in seconds */ -#define TT_CLIENT_ROAM_TIMEOUT 600 +#define PURGE_TIMEOUT 200000 /* 200 seconds */ +#define TT_LOCAL_TIMEOUT 3600000 /* in miliseconds */ +#define TT_CLIENT_ROAM_TIMEOUT 600000 /* in miliseconds */ /* sliding packet range of received originator messages in sequence numbers * (should be a multiple of our word size) */ #define TQ_LOCAL_WINDOW_SIZE 64 -#define TT_REQUEST_TIMEOUT 3 /* seconds we have to keep pending tt_req */ +#define TT_REQUEST_TIMEOUT 3000 /* miliseconds we have to keep + * pending tt_req */ #define TQ_GLOBAL_WINDOW_SIZE 5 #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 @@ -56,8 +57,8 @@ #define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */ -#define ROAMING_MAX_TIME 20 /* Time in which a client can roam at most - * ROAMING_MAX_COUNT times */ +#define ROAMING_MAX_TIME 20000 /* Time in which a client can roam at most + * ROAMING_MAX_COUNT times in miliseconds*/ #define ROAMING_MAX_COUNT 5 #define NO_FLAGS 0 diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 847ff7e98a6..1161f27ad8c 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -282,8 +282,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv, hlist_for_each_entry_safe(neigh_node, node, node_tmp, &orig_node->neigh_list, list) { - if ((time_after(jiffies, - neigh_node->last_valid + PURGE_TIMEOUT * HZ)) || + if ((has_timed_out(neigh_node->last_valid, PURGE_TIMEOUT)) || (neigh_node->if_incoming->if_status == IF_INACTIVE) || (neigh_node->if_incoming->if_status == IF_NOT_IN_USE) || (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) { @@ -327,9 +326,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv, { struct neigh_node *best_neigh_node; - if (time_after(jiffies, - orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) { - + if (has_timed_out(orig_node->last_valid, 2 * PURGE_TIMEOUT)) { bat_dbg(DBG_BATMAN, bat_priv, "Originator timeout: originator %pM, last_valid %lu\n", orig_node->orig, (orig_node->last_valid / HZ)); @@ -372,8 +369,8 @@ static void _purge_orig(struct bat_priv *bat_priv) continue; } - if (time_after(jiffies, orig_node->last_frag_packet + - msecs_to_jiffies(FRAG_TIMEOUT))) + if (has_timed_out(orig_node->last_frag_packet, + FRAG_TIMEOUT)) frag_list_free(&orig_node->frag_list); } spin_unlock_bh(list_lock); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index b72d7f3b3c6..c1e45c0bb18 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -231,8 +231,7 @@ int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff, { if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { - if (time_after(jiffies, *last_reset + - msecs_to_jiffies(RESET_PROTECTION_MS))) { + if (has_timed_out(*last_reset, RESET_PROTECTION_MS)) { *last_reset = jiffies; bat_dbg(DBG_BATMAN, bat_priv, diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index b5aecd5e45c..c41dac3bbf8 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -396,8 +396,8 @@ void softif_neigh_purge(struct bat_priv *bat_priv) hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2, &softif_neigh_vid->softif_neigh_list, list) { - if ((!time_after(jiffies, softif_neigh->last_seen + - msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && + if ((!has_timed_out(softif_neigh->last_seen, + SOFTIF_NEIGH_TIMEOUT)) && (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) continue; diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index a84e80409f9..ff9a1b33c13 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -413,7 +413,7 @@ static void tt_local_purge(struct bat_priv *bat_priv) continue; if (!has_timed_out(tt_local_entry->last_seen, - TT_LOCAL_TIMEOUT * 1000)) + TT_LOCAL_TIMEOUT)) continue; tt_local_set_pending(bat_priv, tt_local_entry, @@ -751,7 +751,7 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv) if (!(tt_global_entry->common.flags & TT_CLIENT_ROAM)) continue; if (!has_timed_out(tt_global_entry->roam_at, - TT_CLIENT_ROAM_TIMEOUT * 1000)) + TT_CLIENT_ROAM_TIMEOUT)) continue; bat_dbg(DBG_TT, bat_priv, "Deleting global " @@ -970,8 +970,7 @@ static void tt_req_purge(struct bat_priv *bat_priv) spin_lock_bh(&bat_priv->tt_req_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) { - if (has_timed_out(node->issued_at, - TT_REQUEST_TIMEOUT * 1000)) { + if (has_timed_out(node->issued_at, TT_REQUEST_TIMEOUT)) { list_del(&node->list); kfree(node); } @@ -990,7 +989,7 @@ static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv, list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) { if (compare_eth(tt_req_node_tmp, orig_node) && !has_timed_out(tt_req_node_tmp->issued_at, - TT_REQUEST_TIMEOUT * 1000)) + TT_REQUEST_TIMEOUT)) goto unlock; } @@ -1583,8 +1582,7 @@ static void tt_roam_purge(struct bat_priv *bat_priv) spin_lock_bh(&bat_priv->tt_roam_list_lock); list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) { - if (!has_timed_out(node->first_time, - ROAMING_MAX_TIME * 1000)) + if (!has_timed_out(node->first_time, ROAMING_MAX_TIME)) continue; list_del(&node->list); @@ -1611,8 +1609,7 @@ static bool tt_check_roam_count(struct bat_priv *bat_priv, if (!compare_eth(tt_roam_node->addr, client)) continue; - if (has_timed_out(tt_roam_node->first_time, - ROAMING_MAX_TIME * 1000)) + if (has_timed_out(tt_roam_node->first_time, ROAMING_MAX_TIME)) continue; if (!atomic_dec_not_zero(&tt_roam_node->counter)) diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index ac7e6610059..4f4b2a0c2d7 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -714,8 +714,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv) if (info == bat_priv->my_vis_info) continue; - if (time_after(jiffies, - info->first_seen + VIS_TIMEOUT * HZ)) { + if (has_timed_out(info->first_seen, VIS_TIMEOUT)) { hlist_del(node); send_list_del(info); kref_put(&info->refcount, free_info); diff --git a/net/batman-adv/vis.h b/net/batman-adv/vis.h index 31b820d07f2..851bc4f1e35 100644 --- a/net/batman-adv/vis.h +++ b/net/batman-adv/vis.h @@ -22,7 +22,8 @@ #ifndef _NET_BATMAN_ADV_VIS_H_ #define _NET_BATMAN_ADV_VIS_H_ -#define VIS_TIMEOUT 200 /* timeout of vis packets in seconds */ +#define VIS_TIMEOUT 200000 /* timeout of vis packets + * in miliseconds */ int vis_seq_print_text(struct seq_file *seq, void *offset); void receive_server_sync_packet(struct bat_priv *bat_priv, -- cgit v1.2.3-70-g09d2 From d419be1fd1e4417adc833365a3b69d0968c27c3f Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sat, 10 Dec 2011 19:45:53 +0800 Subject: batman-adv: allowing changing the routing algorithm via module parameter Signed-off-by: Marek Lindner --- net/batman-adv/main.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'net') diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index bcc2bddd893..8ae497b26bd 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -256,6 +256,30 @@ int bat_algo_seq_print_text(struct seq_file *seq, void *offset) return 0; } +static int param_set_ra(const char *val, const struct kernel_param *kp) +{ + struct bat_algo_ops *bat_algo_ops; + + bat_algo_ops = bat_algo_get((char *)val); + if (!bat_algo_ops) { + pr_err("Routing algorithm '%s' is not supported\n", val); + return -EINVAL; + } + + return param_set_copystring(val, kp); +} + +static const struct kernel_param_ops param_ops_ra = { + .set = param_set_ra, + .get = param_get_string, +}; + +static struct kparam_string __param_string_ra = { + .maxlen = sizeof(bat_routing_algo), + .string = bat_routing_algo, +}; + +module_param_cb(routing_algo, ¶m_ops_ra, &__param_string_ra, 0644); module_init(batman_init); module_exit(batman_exit); -- cgit v1.2.3-70-g09d2 From 92f90f56caa30dfcb6c5755776d73df23ef2ae1a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 22 Dec 2011 20:31:12 +0800 Subject: batman-adv: refactor tt_global_del() to avoid misalignment Signed-off-by: Sven Eckelmann Acked-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/translation-table.c | 42 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index ff9a1b33c13..30c2d1b7de4 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -657,29 +657,31 @@ void tt_global_del(struct bat_priv *bat_priv, struct tt_local_entry *tt_local_entry = NULL; tt_global_entry = tt_global_hash_find(bat_priv, addr); - if (!tt_global_entry) + if (!tt_global_entry || tt_global_entry->orig_node != orig_node) goto out; - if (tt_global_entry->orig_node == orig_node) { - if (roaming) { - /* if we are deleting a global entry due to a roam - * event, there are two possibilities: - * 1) the client roamed from node A to node B => we mark - * it with TT_CLIENT_ROAM, we start a timer and we - * wait for node B to claim it. In case of timeout - * the entry is purged. - * 2) the client roamed to us => we can directly delete - * the global entry, since it is useless now. */ - tt_local_entry = tt_local_hash_find(bat_priv, - tt_global_entry->common.addr); - if (!tt_local_entry) { - tt_global_entry->common.flags |= TT_CLIENT_ROAM; - tt_global_entry->roam_at = jiffies; - goto out; - } - } - _tt_global_del(bat_priv, tt_global_entry, message); + if (!roaming) + goto out_del; + + /* if we are deleting a global entry due to a roam + * event, there are two possibilities: + * 1) the client roamed from node A to node B => we mark + * it with TT_CLIENT_ROAM, we start a timer and we + * wait for node B to claim it. In case of timeout + * the entry is purged. + * 2) the client roamed to us => we can directly delete + * the global entry, since it is useless now. */ + tt_local_entry = tt_local_hash_find(bat_priv, + tt_global_entry->common.addr); + if (!tt_local_entry) { + tt_global_entry->common.flags |= TT_CLIENT_ROAM; + tt_global_entry->roam_at = jiffies; + goto out; } + +out_del: + _tt_global_del(bat_priv, tt_global_entry, message); + out: if (tt_global_entry) tt_global_entry_free_ref(tt_global_entry); -- cgit v1.2.3-70-g09d2 From ea3d2fd1b11fb3ef8706a48ece0a49a61bcd08bc Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Tue, 29 Nov 2011 00:15:37 +0800 Subject: batman-adv: export used routing algorithm via sysfs Signed-off-by: Marek Lindner --- Documentation/ABI/testing/sysfs-class-net-mesh | 7 +++++++ net/batman-adv/bat_sysfs.c | 9 +++++++++ 2 files changed, 16 insertions(+) (limited to 'net') diff --git a/Documentation/ABI/testing/sysfs-class-net-mesh b/Documentation/ABI/testing/sysfs-class-net-mesh index b02001488ee..b218e0f8bdb 100644 --- a/Documentation/ABI/testing/sysfs-class-net-mesh +++ b/Documentation/ABI/testing/sysfs-class-net-mesh @@ -65,6 +65,13 @@ Description: Defines the penalty which will be applied to an originator message's tq-field on every hop. +What: /sys/class/net//mesh/routing_algo +Date: Dec 2011 +Contact: Marek Lindner +Description: + Defines the routing procotol this mesh instance + uses to find the optimal paths through the mesh. + What: /sys/class/net//mesh/vis_mode Date: May 2010 Contact: Marek Lindner diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c index c25492f7d66..480ae0a5ba4 100644 --- a/net/batman-adv/bat_sysfs.c +++ b/net/batman-adv/bat_sysfs.c @@ -272,6 +272,13 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, return count; } +static ssize_t show_bat_algo(struct kobject *kobj, struct attribute *attr, + char *buff) +{ + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); + return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name); +} + static void post_gw_deselect(struct net_device *net_dev) { struct bat_priv *bat_priv = netdev_priv(net_dev); @@ -382,6 +389,7 @@ BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); BAT_ATTR_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); +static BAT_ATTR(routing_algo, S_IRUGO, show_bat_algo, NULL); static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); @@ -399,6 +407,7 @@ static struct bat_attribute *mesh_attrs[] = { &bat_attr_fragmentation, &bat_attr_ap_isolation, &bat_attr_vis_mode, + &bat_attr_routing_algo, &bat_attr_gw_mode, &bat_attr_orig_interval, &bat_attr_hop_penalty, -- cgit v1.2.3-70-g09d2 From 567db7b0b7c0a94cc62846f8ebb429bdda2884bc Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 1 Jan 2012 00:41:38 +0100 Subject: batman-adv: Update copyright years Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/Makefile | 2 +- net/batman-adv/bat_algo.h | 2 +- net/batman-adv/bat_debugfs.c | 2 +- net/batman-adv/bat_debugfs.h | 2 +- net/batman-adv/bat_iv_ogm.c | 2 +- net/batman-adv/bat_sysfs.c | 2 +- net/batman-adv/bat_sysfs.h | 2 +- net/batman-adv/bitarray.c | 2 +- net/batman-adv/bitarray.h | 2 +- net/batman-adv/gateway_client.c | 2 +- net/batman-adv/gateway_client.h | 2 +- net/batman-adv/gateway_common.c | 2 +- net/batman-adv/gateway_common.h | 2 +- net/batman-adv/hard-interface.c | 2 +- net/batman-adv/hard-interface.h | 2 +- net/batman-adv/hash.c | 2 +- net/batman-adv/hash.h | 2 +- net/batman-adv/icmp_socket.c | 2 +- net/batman-adv/icmp_socket.h | 2 +- net/batman-adv/main.c | 2 +- net/batman-adv/main.h | 2 +- net/batman-adv/originator.c | 2 +- net/batman-adv/originator.h | 2 +- net/batman-adv/packet.h | 2 +- net/batman-adv/ring_buffer.c | 2 +- net/batman-adv/ring_buffer.h | 2 +- net/batman-adv/routing.c | 2 +- net/batman-adv/routing.h | 2 +- net/batman-adv/send.c | 2 +- net/batman-adv/send.h | 2 +- net/batman-adv/soft-interface.c | 2 +- net/batman-adv/soft-interface.h | 2 +- net/batman-adv/translation-table.c | 2 +- net/batman-adv/translation-table.h | 2 +- net/batman-adv/types.h | 2 +- net/batman-adv/unicast.c | 2 +- net/batman-adv/unicast.h | 2 +- net/batman-adv/vis.c | 2 +- net/batman-adv/vis.h | 2 +- 39 files changed, 39 insertions(+), 39 deletions(-) (limited to 'net') diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index ce686116649..4e392ebedb6 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: +# Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: # # Marek Lindner, Simon Wunderlich # diff --git a/net/batman-adv/bat_algo.h b/net/batman-adv/bat_algo.h index 755379fd367..9852a688ba4 100644 --- a/net/batman-adv/bat_algo.h +++ b/net/batman-adv/bat_algo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2011-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c index a7a393eeb93..c3b0548b175 100644 --- a/net/batman-adv/bat_debugfs.c +++ b/net/batman-adv/bat_debugfs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/bat_debugfs.h b/net/batman-adv/bat_debugfs.h index bc9cda3f01e..d605c674642 100644 --- a/net/batman-adv/bat_debugfs.h +++ b/net/batman-adv/bat_debugfs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 1c483a5dd80..2b66daef1ef 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c index 480ae0a5ba4..7317729a00f 100644 --- a/net/batman-adv/bat_sysfs.c +++ b/net/batman-adv/bat_sysfs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h index a3f75a723c5..fece77ae586 100644 --- a/net/batman-adv/bat_sysfs.h +++ b/net/batman-adv/bat_sysfs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c index 9bc63b209b3..e63069d61db 100644 --- a/net/batman-adv/bitarray.c +++ b/net/batman-adv/bitarray.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h index 9c04422aeb0..c6135728a68 100644 --- a/net/batman-adv/bitarray.h +++ b/net/batman-adv/bitarray.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index df5631e1f2a..65a77a10f17 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index e1edba08eb1..bf56a5aea10 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index c4ac7b0a2a6..7f79e156e64 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h index 55e527a489f..b8fb11c4f92 100644 --- a/net/batman-adv/gateway_common.h +++ b/net/batman-adv/gateway_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index ff5ba406b1c..41826b96d9f 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index 67f78d1a63b..e68c5655e61 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c index d1da29da333..117687bedf2 100644 --- a/net/batman-adv/hash.c +++ b/net/batman-adv/hash.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h index 4768717f07f..d4bd7862719 100644 --- a/net/batman-adv/hash.h +++ b/net/batman-adv/hash.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2006-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 5d69e103faa..9b755f9eb18 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h index 462b190fa10..380ed4c2443 100644 --- a/net/batman-adv/icmp_socket.h +++ b/net/batman-adv/icmp_socket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 8ae497b26bd..08f3b3a8e88 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index ecfed88d0d4..6b276e17941 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 1161f27ad8c..c2e46b55162 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 67765ffef73..3fe2eda8565 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 88c717b9344..441f3db1bd9 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/ring_buffer.c b/net/batman-adv/ring_buffer.c index f1ccfa76ce8..fd63951d118 100644 --- a/net/batman-adv/ring_buffer.c +++ b/net/batman-adv/ring_buffer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/ring_buffer.h b/net/batman-adv/ring_buffer.h index 7cdfe62b657..8b58bd82767 100644 --- a/net/batman-adv/ring_buffer.h +++ b/net/batman-adv/ring_buffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index c1e45c0bb18..cf9a2f62de6 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index 7aaee0fb0fd..92ac100d83d 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 019337e3eaf..41375806532 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h index c8ca3ef7385..824ef06f9b0 100644 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index c41dac3bbf8..2ffdc74ac40 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 001546fc96f..756eab5b8dd 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner * diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 30c2d1b7de4..4dc5af334f6 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 30efd49881a..c753633b1da 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 650ce5fb119..302efb52347 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index 6f3c65952f5..0897dfa72c5 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: * * Andreas Langer * diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h index 8fd5535544b..a9faf6b1db1 100644 --- a/net/batman-adv/unicast.h +++ b/net/batman-adv/unicast.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: * * Andreas Langer * diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index 4f4b2a0c2d7..c4a5b8cafad 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2008-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich * diff --git a/net/batman-adv/vis.h b/net/batman-adv/vis.h index 851bc4f1e35..ee2e46e5347 100644 --- a/net/batman-adv/vis.h +++ b/net/batman-adv/vis.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 B.A.T.M.A.N. contributors: + * Copyright (C) 2008-2012 B.A.T.M.A.N. contributors: * * Simon Wunderlich, Marek Lindner * -- cgit v1.2.3-70-g09d2 From c40ed2bfa6cc30174d5c547b37bcd6528c830ef4 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 6 Jan 2012 21:31:33 +0100 Subject: batman-adv: set TT_CLIENT_NEW flag before invoking hash_add() In case of a new tt_local_entry, the TT_CLIENT_NEW flag has to be set before adding such entry to the hash table. Otherwise, it opens a race condition in which the entry can be found but the flag has not been set. Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/translation-table.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 4dc5af334f6..9be9c41c529 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -210,6 +210,11 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, if (compare_eth(addr, soft_iface->dev_addr)) tt_local_entry->common.flags |= TT_CLIENT_NOPURGE; + /* The local entry has to be marked as NEW to avoid to send it in + * a full table response going out before the next ttvn increment + * (consistency check) */ + tt_local_entry->common.flags |= TT_CLIENT_NEW; + hash_added = hash_add(bat_priv->tt_local_hash, compare_tt, choose_orig, &tt_local_entry->common, &tt_local_entry->common.hash_entry); @@ -222,11 +227,6 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, tt_local_event(bat_priv, addr, tt_local_entry->common.flags); - /* The local entry has to be marked as NEW to avoid to send it in - * a full table response going out before the next ttvn increment - * (consistency check) */ - tt_local_entry->common.flags |= TT_CLIENT_NEW; - /* remove address from global hash if present */ tt_global_entry = tt_global_hash_find(bat_priv, addr); -- cgit v1.2.3-70-g09d2 From c566dbbef029d7ea957e9566e3073e68b9e05de9 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 6 Jan 2012 21:31:34 +0100 Subject: batman-adv: code refactoring - move debug print into tt_local_set_pending Each tt_local_set_pending is always followed by a bat_dbg invocation. This can be simplified by moving the bat_dbg() call. Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/translation-table.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 9be9c41c529..1ff7fbebf92 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -355,7 +355,7 @@ out: static void tt_local_set_pending(struct bat_priv *bat_priv, struct tt_local_entry *tt_local_entry, - uint16_t flags) + uint16_t flags, const char *message) { tt_local_event(bat_priv, tt_local_entry->common.addr, tt_local_entry->common.flags | flags); @@ -364,6 +364,9 @@ static void tt_local_set_pending(struct bat_priv *bat_priv, * to be kept in the table in order to send it in a full table * response issued before the net ttvn increment (consistency check) */ tt_local_entry->common.flags |= TT_CLIENT_PENDING; + + bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " + "%s\n", tt_local_entry->common.addr, message); } void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, @@ -376,10 +379,7 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, goto out; tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL | - (roaming ? TT_CLIENT_ROAM : NO_FLAGS)); - - bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " - "%s\n", tt_local_entry->common.addr, message); + (roaming ? TT_CLIENT_ROAM : NO_FLAGS), message); out: if (tt_local_entry) tt_local_entry_free_ref(tt_local_entry); @@ -417,10 +417,7 @@ static void tt_local_purge(struct bat_priv *bat_priv) continue; tt_local_set_pending(bat_priv, tt_local_entry, - TT_CLIENT_DEL); - bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) " - "pending to be removed: timed out\n", - tt_local_entry->common.addr); + TT_CLIENT_DEL, "timed out"); } spin_unlock_bh(list_lock); } -- cgit v1.2.3-70-g09d2 From 78d6942a45f86126ebdadd45418188b221d63344 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 12 Jan 2012 19:07:00 +0100 Subject: batman-adv: TT_CLIENT_PENDING is never set in struct tt_global_entry Actually the TT_CLIENT_PENDING flag is never set in the tt_global_entry structure, therefore this code is useless and can be removed. Reported-by: Simon Wunderlich Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/translation-table.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'net') diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 1ff7fbebf92..9a6f315b7d4 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -603,7 +603,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) struct tt_global_entry, common); seq_printf(seq, " * %pM (%3u) via %pM (%3u) " - "[%c%c%c]\n", + "[%c%c]\n", tt_global_entry->common.addr, tt_global_entry->ttvn, tt_global_entry->orig_node->orig, @@ -612,8 +612,6 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) last_ttvn), (tt_global_entry->common.flags & TT_CLIENT_ROAM ? 'R' : '.'), - (tt_global_entry->common.flags & - TT_CLIENT_PENDING ? 'X' : '.'), (tt_global_entry->common.flags & TT_CLIENT_WIFI ? 'W' : '.')); } @@ -838,11 +836,6 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) goto out; - /* A global client marked as PENDING has already moved from that - * originator */ - if (tt_global_entry->common.flags & TT_CLIENT_PENDING) - goto out; - orig_node = tt_global_entry->orig_node; out: -- cgit v1.2.3-70-g09d2 From fdc8ff101163f10d36187a890a3c4990cebb8b12 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 5 Feb 2012 15:23:55 +0100 Subject: batman-adv: Start new development cycle Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 6b276e17941..1468788a9d6 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -28,7 +28,7 @@ #define DRIVER_DEVICE "batman-adv" #ifndef SOURCE_VERSION -#define SOURCE_VERSION "2012.0.0" +#define SOURCE_VERSION "2012.1.0" #endif /* B.A.T.M.A.N. parameters */ -- cgit v1.2.3-70-g09d2 From 1d96e80faff57b9eefa283b35716a384bbb3d5b3 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 16 Feb 2012 17:42:12 +0400 Subject: SUNRPC: init per-net rpcbind spinlock Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/sunrpc_syms.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index d16ac088f6d..21d106e2ca0 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -50,6 +50,7 @@ static __net_init int sunrpc_init_net(struct net *net) rpc_pipefs_init_net(net); INIT_LIST_HEAD(&sn->all_clients); spin_lock_init(&sn->rpc_client_lock); + spin_lock_init(&sn->rpcb_clnt_lock); return 0; err_unixgid: -- cgit v1.2.3-70-g09d2 From 15a4520621824a3c2eb2de2d1f3984bc1663d3c8 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Tue, 14 Feb 2012 16:19:18 -0500 Subject: SUNRPC: add sending,pending queue and max slot to xprt stats With static RPC slots, the xprt backlog queue stats were useful in showing when the transport (TCP) was starved by lack of RPC slots. The new dynamic RPC slot code, commit d9ba131d8f58c0d2ff5029e7002ab43f913b36f9, always provides an RPC slot and so only uses the xprt backlog queue when the tcp_max_slot_table_entries value has been hit or when an allocation error occurs. All requests are now placed on the xprt sending or pending queue which need to be monitored for debugging. The max_slot stat shows the maximum number of dynamic RPC slots reached which is useful when debugging performance issues. Add the new fields at the end of the mountstats xprt stanza so that mountstats outputs the previous correct values and ignores the new fields. Bump NFS_IOSTATS_VERS. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust --- include/linux/nfs_iostat.h | 2 +- include/linux/sunrpc/xprt.h | 7 +++++-- net/sunrpc/xprt.c | 7 ++++++- net/sunrpc/xprtsock.c | 23 +++++++++++++++++------ 4 files changed, 29 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/nfs_iostat.h b/include/linux/nfs_iostat.h index 8866bb3502e..9dcbbe9a51f 100644 --- a/include/linux/nfs_iostat.h +++ b/include/linux/nfs_iostat.h @@ -21,7 +21,7 @@ #ifndef _LINUX_NFS_IOSTAT #define _LINUX_NFS_IOSTAT -#define NFS_IOSTAT_VERS "1.0" +#define NFS_IOSTAT_VERS "1.1" /* * NFS byte counters diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index b033f366d5f..ea712f97f4a 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -219,10 +219,13 @@ struct rpc_xprt { connect_time, /* jiffies waiting for connect */ sends, /* how many complete requests */ recvs, /* how many complete requests */ - bad_xids; /* lookup_rqst didn't find XID */ + bad_xids, /* lookup_rqst didn't find XID */ + max_slots; /* max rpc_slots used */ unsigned long long req_u, /* average requests on the wire */ - bklog_u; /* backlog queue utilization */ + bklog_u, /* backlog queue utilization */ + sending_u, /* send q utilization */ + pending_u; /* pend q utilization */ } stat; struct net *xprt_net; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index efe5495ecf6..739df8a1138 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -885,7 +885,7 @@ void xprt_transmit(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - int status; + int status, numreqs; dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); @@ -922,9 +922,14 @@ void xprt_transmit(struct rpc_task *task) xprt->ops->set_retrans_timeout(task); + numreqs = atomic_read(&xprt->num_reqs); + if (numreqs > xprt->stat.max_slots) + xprt->stat.max_slots = numreqs; xprt->stat.sends++; xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; xprt->stat.bklog_u += xprt->backlog.qlen; + xprt->stat.sending_u += xprt->sending.qlen; + xprt->stat.pending_u += xprt->pending.qlen; /* Don't race with disconnect */ if (!xprt_connected(xprt)) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 55472c48825..4c8281d29e2 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2227,7 +2227,7 @@ static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) idle_time = (long)(jiffies - xprt->last_used) / HZ; seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu " - "%llu %llu\n", + "%llu %llu %lu %llu %llu\n", xprt->stat.bind_count, xprt->stat.connect_count, xprt->stat.connect_time, @@ -2236,7 +2236,10 @@ static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) xprt->stat.recvs, xprt->stat.bad_xids, xprt->stat.req_u, - xprt->stat.bklog_u); + xprt->stat.bklog_u, + xprt->stat.max_slots, + xprt->stat.sending_u, + xprt->stat.pending_u); } /** @@ -2249,14 +2252,18 @@ static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n", + seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %llu %llu " + "%lu %llu %llu\n", transport->srcport, xprt->stat.bind_count, xprt->stat.sends, xprt->stat.recvs, xprt->stat.bad_xids, xprt->stat.req_u, - xprt->stat.bklog_u); + xprt->stat.bklog_u, + xprt->stat.max_slots, + xprt->stat.sending_u, + xprt->stat.pending_u); } /** @@ -2273,7 +2280,8 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) if (xprt_connected(xprt)) idle_time = (long)(jiffies - xprt->last_used) / HZ; - seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n", + seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu " + "%llu %llu %lu %llu %llu\n", transport->srcport, xprt->stat.bind_count, xprt->stat.connect_count, @@ -2283,7 +2291,10 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) xprt->stat.recvs, xprt->stat.bad_xids, xprt->stat.req_u, - xprt->stat.bklog_u); + xprt->stat.bklog_u, + xprt->stat.max_slots, + xprt->stat.sending_u, + xprt->stat.pending_u); } /* -- cgit v1.2.3-70-g09d2 From 76a7f3a40c2bfbdb5f2b23ac780fa4e4f22e8659 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 00:34:40 +0200 Subject: Bluetooth: Remove unused member from cmd_lookup struct The val member of cmd_lookup isn't used anywhere so it can be removed. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 066d338be1c..5520858553c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2561,7 +2561,6 @@ int mgmt_index_removed(struct hci_dev *hdev) } struct cmd_lookup { - u8 val; struct sock *sk; struct hci_dev *hdev; }; @@ -2584,7 +2583,7 @@ static void settings_rsp(struct pending_cmd *cmd, void *data) int mgmt_powered(struct hci_dev *hdev, u8 powered) { - struct cmd_lookup match = { powered, NULL, hdev }; + struct cmd_lookup match = { NULL, hdev }; __le32 ev; int ret; @@ -2608,7 +2607,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { - struct cmd_lookup match = { discoverable, NULL, hdev }; + struct cmd_lookup match = { NULL, hdev }; __le32 ev; int ret; @@ -2627,7 +2626,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) int mgmt_connectable(struct hci_dev *hdev, u8 connectable) { __le32 ev; - struct cmd_lookup match = { connectable, NULL, hdev }; + struct cmd_lookup match = { NULL, hdev }; int ret; mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, -- cgit v1.2.3-70-g09d2 From 7bb895d68e0c18b730bd89f2ed7e58de0e3a591a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 01:20:00 +0200 Subject: Bluetooth: mgmt: Use more consistent error variable names For simple integer errors the variable name "err" is more consistent with the existing code base than "ret". Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5520858553c..d5dbe402bc0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2585,7 +2585,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) { struct cmd_lookup match = { NULL, hdev }; __le32 ev; - int ret; + int err; mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); @@ -2596,50 +2596,50 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); if (match.sk) sock_put(match.sk); - return ret; + return err; } int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { struct cmd_lookup match = { NULL, hdev }; __le32 ev; - int ret; + int err; mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); if (match.sk) sock_put(match.sk); - return ret; + return err; } int mgmt_connectable(struct hci_dev *hdev, u8 connectable) { __le32 ev; struct cmd_lookup match = { NULL, hdev }; - int ret; + int err; mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, &match); ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); if (match.sk) sock_put(match.sk); - return ret; + return err; } int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) -- cgit v1.2.3-70-g09d2 From 33ef95ed30283eb17c686a815caf1d33e966fe4a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 16 Feb 2012 23:56:27 +0200 Subject: Bluetooth: mgmt: Add support for Set Link Security command The Set Link Security mgmt command is used to enable or disable link level security, also known as Security Mode 3. This is rarely enabled in modern systems but the command needs to be available for completeness, qualification purposes and those few systems that actually want to enable it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 3 ++ net/bluetooth/mgmt.c | 87 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b20d990436b..66f84adbbbe 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -994,6 +994,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); +int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b0784ee5f8b..239e9fb8f7c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -254,6 +254,9 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_AUTH, &hdev->flags); } + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_auth_enable_complete(hdev, status); + hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d5dbe402bc0..0c9fbb45d2e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -964,6 +964,65 @@ failed: return err; } +static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct pending_cmd *cmd; + struct hci_dev *hdev; + uint8_t val; + int err; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_NOT_POWERED); + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_BUSY); + goto failed; + } + + val = !!cp->val; + + if (test_bit(HCI_AUTH, &hdev->flags) == val) { + err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2443,6 +2502,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_PAIRABLE: err = set_pairable(sk, index, cp, len); break; + case MGMT_OP_SET_LINK_SECURITY: + err = set_link_security(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; @@ -2965,6 +3027,31 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); } +int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + __le32 ev; + int err; + + if (status) { + u8 mgmt_err = mgmt_status(status); + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, + cmd_status_rsp, &mgmt_err); + return 0; + } + + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, + &match); + + ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + + if (match.sk) + sock_put(match.sk); + + return err; +} + int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; -- cgit v1.2.3-70-g09d2 From ed2c4ee360709ca838efa0ea4d6295590aff3d24 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 00:56:28 +0200 Subject: Bluetooth: mgmt: Add support for Set SSP command The Set SSP mgmt command can be used for enabling and disabling Secure Simple Pairing support for controllers that support it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 6 ++- net/bluetooth/mgmt.c | 85 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 66f84adbbbe..43e0b1eda02 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -995,6 +995,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 239e9fb8f7c..179d127601f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -447,7 +447,7 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); if (status) - return; + goto done; sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); if (!sent) @@ -457,6 +457,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); else clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + +done: + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_ssp_enable_complete(hdev, status); } static u8 hci_get_inquiry_mode(struct hci_dev *hdev) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0c9fbb45d2e..36c4ff6fdf0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1023,6 +1023,64 @@ failed: return err; } +static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct pending_cmd *cmd; + struct hci_dev *hdev; + uint8_t val; + int err; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_NOT_POWERED); + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); + goto failed; + } + + val = !!cp->val; + + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) { + err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2505,6 +2563,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_LINK_SECURITY: err = set_link_security(sk, index, cp, len); break; + case MGMT_OP_SET_SSP: + err = set_ssp(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; @@ -3052,6 +3113,30 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) return err; } +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + __le32 ev; + int err; + + if (status) { + u8 mgmt_err = mgmt_status(status); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, + cmd_status_rsp, &mgmt_err); + return 0; + } + + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); + + ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + + if (match.sk) + sock_put(match.sk); + + return err; +} + int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; -- cgit v1.2.3-70-g09d2 From 3ed7003e724a04482e0ef1e794eece8c1c177b37 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 16 Feb 2012 23:32:42 -0800 Subject: Bluetooth: Add logging functions bt_info and bt_err Use specific logging functions instead of a generic bt_printk function can save some text. Remove now unused bt_printk function. Add compatibility BT_INFO and BT_ERR macros. (compiled x86 and defconfig with bluetooth and all bluetooth drivers) $ size net/bluetooth/built-in.o* text data bss dec hex filename 381662 20072 100416 502150 7a986 net/bluetooth/built-in.o.allyesconfig.new 382463 20072 100400 502935 7ac97 net/bluetooth/built-in.o.allyesconfig.old 126635 1388 132 128155 1f49b net/bluetooth/built-in.o.defconfig.new 127175 1388 132 128695 1f6b7 net/bluetooth/built-in.o.defconfig.old $ size drivers/bluetooth/built-in.o* 127575 8976 29476 166027 2888b drivers/bluetooth/built-in.o.allyesconfig.new 129512 8976 29516 168004 29044 drivers/bluetooth/built-in.o.allyesconfig.old 52998 3292 156 56446 dc7e drivers/bluetooth/built-in.o.defconfig.new 54358 3292 156 57806 e1ce drivers/bluetooth/built-in.o.defconfig.old Signed-off-by: Joe Perches Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 14 ++++++++------ net/bluetooth/lib.c | 27 ++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 4a82ca0bb0b..9f5f2c1c555 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -109,12 +109,14 @@ struct bt_power { */ #define BT_CHANNEL_POLICY_AMP_PREFERRED 2 -__printf(2, 3) -int bt_printk(const char *level, const char *fmt, ...); - -#define BT_INFO(fmt, arg...) bt_printk(KERN_INFO, pr_fmt(fmt), ##arg) -#define BT_ERR(fmt, arg...) bt_printk(KERN_ERR, pr_fmt(fmt), ##arg) -#define BT_DBG(fmt, arg...) pr_debug(fmt "\n", ##arg) +__printf(1, 2) +int bt_info(const char *fmt, ...); +__printf(1, 2) +int bt_err(const char *fmt, ...); + +#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__) +#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__) +#define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__) /* Connection and socket states */ enum { diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 86a6bed229d..506628876f3 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -24,6 +24,8 @@ /* Bluetooth kernel library. */ +#define pr_fmt(fmt) "Bluetooth: " fmt + #include #include @@ -151,7 +153,26 @@ int bt_to_errno(__u16 code) } EXPORT_SYMBOL(bt_to_errno); -int bt_printk(const char *level, const char *format, ...) +int bt_info(const char *format, ...) +{ + struct va_format vaf; + va_list args; + int r; + + va_start(args, format); + + vaf.fmt = format; + vaf.va = &args; + + r = pr_info("%pV", &vaf); + + va_end(args); + + return r; +} +EXPORT_SYMBOL(bt_info); + +int bt_err(const char *format, ...) { struct va_format vaf; va_list args; @@ -162,10 +183,10 @@ int bt_printk(const char *level, const char *format, ...) vaf.fmt = format; vaf.va = &args; - r = printk("%sBluetooth: %pV\n", level, &vaf); + r = pr_err("%pV", &vaf); va_end(args); return r; } -EXPORT_SYMBOL(bt_printk); +EXPORT_SYMBOL(bt_err); -- cgit v1.2.3-70-g09d2 From 20d1803a70ddafc8410b461caaa397e49da246ac Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 17 Feb 2012 11:40:55 +0200 Subject: Bluetooth: Move scope of state_to_string Function state_to_string will be used in other files in debug statements. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 27 +++++++++++++++++++++++++++ net/bluetooth/l2cap_core.c | 26 -------------------------- 2 files changed, 27 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 9f5f2c1c555..5ca9219fe94 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -131,6 +131,33 @@ enum { BT_CLOSED }; +/* If unused will be removed by compiler */ +static inline const char *state_to_string(int state) +{ + switch (state) { + case BT_CONNECTED: + return "BT_CONNECTED"; + case BT_OPEN: + return "BT_OPEN"; + case BT_BOUND: + return "BT_BOUND"; + case BT_LISTEN: + return "BT_LISTEN"; + case BT_CONNECT: + return "BT_CONNECT"; + case BT_CONNECT2: + return "BT_CONNECT2"; + case BT_CONFIG: + return "BT_CONFIG"; + case BT_DISCONN: + return "BT_DISCONN"; + case BT_CLOSED: + return "BT_CLOSED"; + } + + return "invalid state"; +} + /* BD Address */ typedef struct { __u8 b[6]; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8efac7884ff..252a96e474c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -215,32 +215,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static char *state_to_string(int state) -{ - switch(state) { - case BT_CONNECTED: - return "BT_CONNECTED"; - case BT_OPEN: - return "BT_OPEN"; - case BT_BOUND: - return "BT_BOUND"; - case BT_LISTEN: - return "BT_LISTEN"; - case BT_CONNECT: - return "BT_CONNECT"; - case BT_CONNECT2: - return "BT_CONNECT2"; - case BT_CONFIG: - return "BT_CONFIG"; - case BT_DISCONN: - return "BT_DISCONN"; - case BT_CLOSED: - return "BT_CLOSED"; - } - - return "invalid state"; -} - static void l2cap_state_change(struct l2cap_chan *chan, int state) { BT_DBG("%p %s -> %s", chan, state_to_string(chan->state), -- cgit v1.2.3-70-g09d2 From e05dcc3291dcfe9ab1b456f38ccb3041ebbda59c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 17 Feb 2012 11:40:56 +0200 Subject: Bluetooth: Use symbolic names for state in debug Use state_to_string function in debug statements. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/l2cap_core.c | 5 +++-- net/bluetooth/l2cap_sock.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 42fdbb83325..bbb0e214e51 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -612,7 +612,8 @@ static inline void l2cap_chan_put(struct l2cap_chan *c) static inline void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) { - BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); + BT_DBG("chan %p state %s timeout %ld", chan, + state_to_string(chan->state), timeout); if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b4ecddee11b..f38e1b11d83 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -282,7 +282,7 @@ static void hci_conn_timeout(struct work_struct *work) disc_work.work); __u8 reason; - BT_DBG("conn %p state %d", conn, conn->state); + BT_DBG("conn %p state %s", conn, state_to_string(conn->state)); if (atomic_read(&conn->refcnt)) return; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 252a96e474c..88968e711d3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -231,7 +231,7 @@ static void l2cap_chan_timeout(struct work_struct *work) struct sock *sk = chan->sk; int reason; - BT_DBG("chan %p state %d", chan, chan->state); + BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); lock_sock(sk); @@ -413,7 +413,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) struct l2cap_conn *conn = chan->conn; struct sock *sk = chan->sk; - BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket); + BT_DBG("chan %p state %s sk %p", chan, + state_to_string(chan->state), sk); switch (chan->state) { case BT_LISTEN: diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 138fe344667..b48d6c1b9db 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -783,7 +783,7 @@ static void l2cap_sock_kill(struct sock *sk) if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) return; - BT_DBG("sk %p state %d", sk, sk->sk_state); + BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state)); /* Kill poor orphan */ -- cgit v1.2.3-70-g09d2 From 42d2d87cfe837e987802588f8d8b119a76714a74 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 17 Feb 2012 11:40:57 +0200 Subject: Bluetooth: Prefix hex numbers with object name Several hex numbers were printed without object name which complicates debugging. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/l2cap_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f38e1b11d83..7ee6895c4b0 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -80,7 +80,7 @@ void hci_acl_connect(struct hci_conn *conn) struct inquiry_entry *ie; struct hci_cp_create_conn cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); conn->state = BT_CONNECT; conn->out = true; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 88968e711d3..37736c6603f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -217,7 +217,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) static void l2cap_state_change(struct l2cap_chan *chan, int state) { - BT_DBG("%p %s -> %s", chan, state_to_string(chan->state), + BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state), state_to_string(state)); chan->state = state; -- cgit v1.2.3-70-g09d2 From d753fdc40f60da2eef03b4816392081a552fea5a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:06:34 +0200 Subject: Bluetooth: mgmt: Add address type to link key messages The latest mgmt API includes an address type wherever there's an address present. This patch updates the link key messages to match it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/mgmt.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 255a99600f0..5aafe929d01 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -153,7 +153,7 @@ struct mgmt_cp_remove_uuid { } __packed; struct mgmt_link_key_info { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; u8 type; u8 val[16]; u8 pin_len; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 36c4ff6fdf0..b0de7194249 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1274,8 +1274,8 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; - hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, - key->pin_len); + hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val, + key->type, key->pin_len); } cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0); @@ -2788,7 +2788,8 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, memset(&ev, 0, sizeof(ev)); ev.store_hint = persistent; - bacpy(&ev.key.bdaddr, &key->bdaddr); + bacpy(&ev.key.addr.bdaddr, &key->bdaddr); + ev.key.addr.type = MGMT_ADDR_BREDR; ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; -- cgit v1.2.3-70-g09d2 From d8457698e7f23a05055396a15ec72ba663282867 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:24:57 +0200 Subject: Bluetooth: mgmt: Add address type to PIN code messages The latest mgmt API includes address types for all messages containing an address. This patch updates the PIN code messages to match this. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 8 ++++---- net/bluetooth/mgmt.c | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 5aafe929d01..eb584cc287d 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -199,18 +199,18 @@ struct mgmt_rp_get_connections { #define MGMT_OP_PIN_CODE_REPLY 0x0016 struct mgmt_cp_pin_code_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 pin_len; __u8 pin_code[16]; } __packed; struct mgmt_rp_pin_code_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; uint8_t status; } __packed; #define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017 struct mgmt_cp_pin_code_neg_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_SET_IO_CAPABILITY 0x0018 @@ -377,7 +377,7 @@ struct mgmt_ev_connect_failed { #define MGMT_EV_PIN_CODE_REQUEST 0x000E struct mgmt_ev_pin_code_request { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 secure; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b0de7194249..68623401933 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1528,8 +1528,8 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index, if (!cmd) return -ENOMEM; - err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr), - &cp->bdaddr); + err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, + sizeof(cp->addr.bdaddr), &cp->addr.bdaddr); if (err < 0) mgmt_pending_remove(cmd); @@ -1541,7 +1541,6 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) struct hci_dev *hdev; struct hci_conn *conn; struct mgmt_cp_pin_code_reply *cp = data; - struct mgmt_cp_pin_code_neg_reply ncp; struct hci_cp_pin_code_reply reply; struct pending_cmd *cmd; int err; @@ -1565,7 +1564,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); if (!conn) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_CONNECTED); @@ -1573,7 +1572,9 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) } if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) { - bacpy(&ncp.bdaddr, &cp->bdaddr); + struct mgmt_cp_pin_code_neg_reply ncp; + + memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr)); BT_ERR("PIN code is not 16 bytes long"); @@ -1592,7 +1593,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - bacpy(&reply.bdaddr, &cp->bdaddr); + bacpy(&reply.bdaddr, &cp->addr.bdaddr); reply.pin_len = cp->pin_len; memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code)); @@ -2945,7 +2946,8 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) { struct mgmt_ev_pin_code_request ev; - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = MGMT_ADDR_BREDR; ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), @@ -2963,7 +2965,8 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!cmd) return -ENOENT; - bacpy(&rp.bdaddr, bdaddr); + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = MGMT_ADDR_BREDR; rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp, @@ -2985,7 +2988,8 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!cmd) return -ENOENT; - bacpy(&rp.bdaddr, bdaddr); + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = MGMT_ADDR_BREDR; rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, -- cgit v1.2.3-70-g09d2 From a198e7b100b26dd6ac0240487ca37bad0f53e3e6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:27:06 +0200 Subject: Bluetooth: mgmt: Add address type to confirm name command The latest mgmt API includes an address type for all messages containing an address. This patch updates the confirm name command to match this. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/mgmt.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index eb584cc287d..14c1816cac6 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -296,11 +296,11 @@ struct mgmt_cp_start_discovery { #define MGMT_OP_CONFIRM_NAME 0x0025 struct mgmt_cp_confirm_name { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 name_known; } __packed; struct mgmt_rp_confirm_name { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 68623401933..01c8d6239a4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2299,7 +2299,7 @@ static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr); + e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, MGMT_STATUS_INVALID_PARAMS); -- cgit v1.2.3-70-g09d2 From ea585ab51d3fe2eb2d738c91f83e7c309e76b4fe Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:50:39 +0200 Subject: Bluetooth: Add Intel copyright to mgmt files This patch adds the appropriate Intel copyright to mgmt files. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 14c1816cac6..ee625a6ad79 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -2,6 +2,7 @@ BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2010 Nokia Corporation + Copyright (C) 2011-2012 Intel Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 01c8d6239a4..f9f3e4c4415 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1,6 +1,8 @@ /* BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2010 Nokia Corporation + Copyright (C) 2011-2012 Intel Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as -- cgit v1.2.3-70-g09d2 From 0a702195234eb77c4097148285cccf7f095de9cf Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Fri, 17 Feb 2012 13:15:24 -0500 Subject: NFS: include filelayout DS rpc stats in mountstats Include RPC statistics from all data servers in /proc/self/mountstats for pNFS filelayout mounts. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust --- fs/nfs/nfs4filelayout.c | 19 +++++++++++++++++++ include/linux/sunrpc/metrics.h | 6 ++++-- include/linux/sunrpc/sched.h | 1 + net/sunrpc/stats.c | 8 ++++---- net/sunrpc/xprt.c | 5 ++++- 5 files changed, 32 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 79be7acc9ba..47e8f3435d3 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -33,6 +33,8 @@ #include #include +#include + #include "internal.h" #include "nfs4filelayout.h" @@ -189,6 +191,13 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data) rdata->mds_ops->rpc_call_done(task, data); } +static void filelayout_read_count_stats(struct rpc_task *task, void *data) +{ + struct nfs_read_data *rdata = (struct nfs_read_data *)data; + + rpc_count_iostats(task, NFS_SERVER(rdata->inode)->client->cl_metrics); +} + static void filelayout_read_release(void *data) { struct nfs_read_data *rdata = (struct nfs_read_data *)data; @@ -268,6 +277,13 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data) wdata->mds_ops->rpc_call_done(task, data); } +static void filelayout_write_count_stats(struct rpc_task *task, void *data) +{ + struct nfs_write_data *wdata = (struct nfs_write_data *)data; + + rpc_count_iostats(task, NFS_SERVER(wdata->inode)->client->cl_metrics); +} + static void filelayout_write_release(void *data) { struct nfs_write_data *wdata = (struct nfs_write_data *)data; @@ -288,18 +304,21 @@ static void filelayout_commit_release(void *data) struct rpc_call_ops filelayout_read_call_ops = { .rpc_call_prepare = filelayout_read_prepare, .rpc_call_done = filelayout_read_call_done, + .rpc_count_stats = filelayout_read_count_stats, .rpc_release = filelayout_read_release, }; struct rpc_call_ops filelayout_write_call_ops = { .rpc_call_prepare = filelayout_write_prepare, .rpc_call_done = filelayout_write_call_done, + .rpc_count_stats = filelayout_write_count_stats, .rpc_release = filelayout_write_release, }; struct rpc_call_ops filelayout_commit_call_ops = { .rpc_call_prepare = filelayout_write_prepare, .rpc_call_done = filelayout_write_call_done, + .rpc_count_stats = filelayout_write_count_stats, .rpc_release = filelayout_commit_release, }; diff --git a/include/linux/sunrpc/metrics.h b/include/linux/sunrpc/metrics.h index b6edbc0ea83..1565bbe86d5 100644 --- a/include/linux/sunrpc/metrics.h +++ b/include/linux/sunrpc/metrics.h @@ -74,14 +74,16 @@ struct rpc_clnt; #ifdef CONFIG_PROC_FS struct rpc_iostats * rpc_alloc_iostats(struct rpc_clnt *); -void rpc_count_iostats(struct rpc_task *); +void rpc_count_iostats(const struct rpc_task *, + struct rpc_iostats *); void rpc_print_iostats(struct seq_file *, struct rpc_clnt *); void rpc_free_iostats(struct rpc_iostats *); #else /* CONFIG_PROC_FS */ static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; } -static inline void rpc_count_iostats(struct rpc_task *task) {} +static inline void rpc_count_iostats(const struct rpc_task *task, + struct rpc_iostats *stats) {} static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {} static inline void rpc_free_iostats(struct rpc_iostats *stats) {} diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 22dfc24013b..dc0c3cc3ada 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -103,6 +103,7 @@ typedef void (*rpc_action)(struct rpc_task *); struct rpc_call_ops { void (*rpc_call_prepare)(struct rpc_task *, void *); void (*rpc_call_done)(struct rpc_task *, void *); + void (*rpc_count_stats)(struct rpc_task *, void *); void (*rpc_release)(void *); }; diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 3c4f6888c89..1eb3304bc10 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -133,20 +133,19 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats); /** * rpc_count_iostats - tally up per-task stats * @task: completed rpc_task + * @stats: array of stat structures * * Relies on the caller for serialization. */ -void rpc_count_iostats(struct rpc_task *task) +void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats) { struct rpc_rqst *req = task->tk_rqstp; - struct rpc_iostats *stats; struct rpc_iostats *op_metrics; ktime_t delta; - if (!task->tk_client || !task->tk_client->cl_metrics || !req) + if (!stats || !req) return; - stats = task->tk_client->cl_metrics; op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; op_metrics->om_ops++; @@ -164,6 +163,7 @@ void rpc_count_iostats(struct rpc_task *task) delta = ktime_sub(ktime_get(), task->tk_start); op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta); } +EXPORT_SYMBOL_GPL(rpc_count_iostats); static void _print_name(struct seq_file *seq, unsigned int op, struct rpc_procinfo *procs) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 739df8a1138..32e37945a84 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1137,7 +1137,10 @@ void xprt_release(struct rpc_task *task) return; xprt = req->rq_xprt; - rpc_count_iostats(task); + if (task->tk_ops->rpc_count_stats != NULL) + task->tk_ops->rpc_count_stats(task, task->tk_calldata); + else if (task->tk_client) + rpc_count_iostats(task, task->tk_client->cl_metrics); spin_lock_bh(&xprt->transport_lock); xprt->ops->release_xprt(xprt, task); if (xprt->ops->release_request) -- cgit v1.2.3-70-g09d2 From 28009a6cab764f04d4e7c409c180c77b2ef36ba1 Mon Sep 17 00:00:00 2001 From: Danny Kukawka Date: Fri, 17 Feb 2012 05:43:27 +0000 Subject: batman-adv: use eth_hw_addr_random() instead of random_ether_addr() Use eth_hw_addr_random() instead of calling random_ether_addr() to set addr_assign_type correctly to NET_ADDR_RANDOM. Remove dev_addr in interface_setup(), it's not needed anymore. Reset the state to NET_ADDR_PERM as soon as the MAC get changed via .ndo_set_mac_address. v2: use bitops, adapt to eth_hw_addr_random() Signed-off-by: Danny Kukawka Signed-off-by: David S. Miller --- net/batman-adv/soft-interface.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index b5aecd5e45c..2d8bd2ad6ba 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -541,6 +541,7 @@ static int interface_set_mac_addr(struct net_device *dev, void *p) } memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + dev->addr_assign_type &= ~NET_ADDR_RANDOM; return 0; } @@ -783,7 +784,6 @@ static const struct net_device_ops bat_netdev_ops = { static void interface_setup(struct net_device *dev) { struct bat_priv *priv = netdev_priv(dev); - char dev_addr[ETH_ALEN]; ether_setup(dev); @@ -800,8 +800,7 @@ static void interface_setup(struct net_device *dev) dev->hard_header_len = BAT_HEADER_LEN; /* generate random address */ - random_ether_addr(dev_addr); - memcpy(dev->dev_addr, dev_addr, ETH_ALEN); + eth_hw_addr_random(dev); SET_ETHTOOL_OPS(dev, &bat_ethtool_ops); -- cgit v1.2.3-70-g09d2 From cec56c8ff5e28f58ff13041dca7853738ae577a1 Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Wed, 15 Feb 2012 11:30:00 -0600 Subject: svcrdma: Cleanup sparse warnings in the svcrdma module The svcrdma transport was un-marshalling requests in-place. This resulted in sparse warnings due to __beXX data containing both NBO and HBO data. The code has been restructured to do byte-swapping as the header is parsed instead of when the header is validated immediately after receipt. Also moved extern declarations for the workqueue and memory pools to the private header file. Signed-off-by: Tom Tucker Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_rdma.h | 2 +- net/sunrpc/xprtrdma/svc_rdma.c | 1 + net/sunrpc/xprtrdma/svc_rdma_marshal.c | 66 ++++++++------------------------ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 20 +++++----- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 26 +++++++------ net/sunrpc/xprtrdma/svc_rdma_transport.c | 10 +---- net/sunrpc/xprtrdma/xprt_rdma.h | 7 ++++ 7 files changed, 51 insertions(+), 81 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index c14fe86dac5..d205e9f938c 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -292,7 +292,7 @@ svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp) if (wr_ary) { rp_ary = (struct rpcrdma_write_array *) &wr_ary-> - wc_array[wr_ary->wc_nchunks].wc_target.rs_length; + wc_array[ntohl(wr_ary->wc_nchunks)].wc_target.rs_length; goto found_it; } diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c index 09af4fab1a4..8343737e85f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma.c +++ b/net/sunrpc/xprtrdma/svc_rdma.c @@ -47,6 +47,7 @@ #include #include #include +#include "xprt_rdma.h" #define RPCDBG_FACILITY RPCDBG_SVCXPRT diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c index 9530ef2d40d..8d2edddf48c 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_marshal.c +++ b/net/sunrpc/xprtrdma/svc_rdma_marshal.c @@ -60,21 +60,11 @@ static u32 *decode_read_list(u32 *va, u32 *vaend) struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va; while (ch->rc_discrim != xdr_zero) { - u64 ch_offset; - if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) > (unsigned long)vaend) { dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch); return NULL; } - - ch->rc_discrim = ntohl(ch->rc_discrim); - ch->rc_position = ntohl(ch->rc_position); - ch->rc_target.rs_handle = ntohl(ch->rc_target.rs_handle); - ch->rc_target.rs_length = ntohl(ch->rc_target.rs_length); - va = (u32 *)&ch->rc_target.rs_offset; - xdr_decode_hyper(va, &ch_offset); - put_unaligned(ch_offset, (u64 *)va); ch++; } return (u32 *)&ch->rc_position; @@ -91,7 +81,7 @@ void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch, *byte_count = 0; *ch_count = 0; for (; ch->rc_discrim != 0; ch++) { - *byte_count = *byte_count + ch->rc_target.rs_length; + *byte_count = *byte_count + ntohl(ch->rc_target.rs_length); *ch_count = *ch_count + 1; } } @@ -108,7 +98,8 @@ void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch, */ static u32 *decode_write_list(u32 *va, u32 *vaend) { - int ch_no; + int nchunks; + struct rpcrdma_write_array *ary = (struct rpcrdma_write_array *)va; @@ -121,37 +112,24 @@ static u32 *decode_write_list(u32 *va, u32 *vaend) dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend); return NULL; } - ary->wc_discrim = ntohl(ary->wc_discrim); - ary->wc_nchunks = ntohl(ary->wc_nchunks); + nchunks = ntohl(ary->wc_nchunks); if (((unsigned long)&ary->wc_array[0] + - (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) > + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > (unsigned long)vaend) { dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n", - ary, ary->wc_nchunks, vaend); + ary, nchunks, vaend); return NULL; } - for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) { - u64 ch_offset; - - ary->wc_array[ch_no].wc_target.rs_handle = - ntohl(ary->wc_array[ch_no].wc_target.rs_handle); - ary->wc_array[ch_no].wc_target.rs_length = - ntohl(ary->wc_array[ch_no].wc_target.rs_length); - va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset; - xdr_decode_hyper(va, &ch_offset); - put_unaligned(ch_offset, (u64 *)va); - } - /* * rs_length is the 2nd 4B field in wc_target and taking its * address skips the list terminator */ - return (u32 *)&ary->wc_array[ch_no].wc_target.rs_length; + return (u32 *)&ary->wc_array[nchunks].wc_target.rs_length; } static u32 *decode_reply_array(u32 *va, u32 *vaend) { - int ch_no; + int nchunks; struct rpcrdma_write_array *ary = (struct rpcrdma_write_array *)va; @@ -164,28 +142,15 @@ static u32 *decode_reply_array(u32 *va, u32 *vaend) dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend); return NULL; } - ary->wc_discrim = ntohl(ary->wc_discrim); - ary->wc_nchunks = ntohl(ary->wc_nchunks); + nchunks = ntohl(ary->wc_nchunks); if (((unsigned long)&ary->wc_array[0] + - (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) > + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > (unsigned long)vaend) { dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n", - ary, ary->wc_nchunks, vaend); + ary, nchunks, vaend); return NULL; } - for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) { - u64 ch_offset; - - ary->wc_array[ch_no].wc_target.rs_handle = - ntohl(ary->wc_array[ch_no].wc_target.rs_handle); - ary->wc_array[ch_no].wc_target.rs_length = - ntohl(ary->wc_array[ch_no].wc_target.rs_length); - va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset; - xdr_decode_hyper(va, &ch_offset); - put_unaligned(ch_offset, (u64 *)va); - } - - return (u32 *)&ary->wc_array[ch_no]; + return (u32 *)&ary->wc_array[nchunks]; } int svc_rdma_xdr_decode_req(struct rpcrdma_msg **rdma_req, @@ -386,13 +351,14 @@ void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *ary, void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary, int chunk_no, - u32 rs_handle, u64 rs_offset, + __be32 rs_handle, + __be64 rs_offset, u32 write_len) { struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target; - seg->rs_handle = htonl(rs_handle); + seg->rs_handle = rs_handle; + seg->rs_offset = rs_offset; seg->rs_length = htonl(write_len); - xdr_encode_hyper((u32 *) &seg->rs_offset, rs_offset); } void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt, diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index df67211c4ba..41cb63b623d 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -147,7 +147,7 @@ static int map_read_chunks(struct svcxprt_rdma *xprt, page_off = 0; ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0]; ch_no = 0; - ch_bytes = ch->rc_target.rs_length; + ch_bytes = ntohl(ch->rc_target.rs_length); head->arg.head[0] = rqstp->rq_arg.head[0]; head->arg.tail[0] = rqstp->rq_arg.tail[0]; head->arg.pages = &head->pages[head->count]; @@ -183,7 +183,7 @@ static int map_read_chunks(struct svcxprt_rdma *xprt, ch_no++; ch++; chl_map->ch[ch_no].start = sge_no; - ch_bytes = ch->rc_target.rs_length; + ch_bytes = ntohl(ch->rc_target.rs_length); /* If bytes remaining account for next chunk */ if (byte_count) { head->arg.page_len += ch_bytes; @@ -281,11 +281,12 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt, offset = 0; ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0]; for (ch_no = 0; ch_no < ch_count; ch_no++) { + int len = ntohl(ch->rc_target.rs_length); rpl_map->sge[ch_no].iov_base = frmr->kva + offset; - rpl_map->sge[ch_no].iov_len = ch->rc_target.rs_length; + rpl_map->sge[ch_no].iov_len = len; chl_map->ch[ch_no].count = 1; chl_map->ch[ch_no].start = ch_no; - offset += ch->rc_target.rs_length; + offset += len; ch++; } @@ -316,7 +317,7 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt, for (i = 0; i < count; i++) { ctxt->sge[i].length = 0; /* in case map fails */ if (!frmr) { - BUG_ON(0 == virt_to_page(vec[i].iov_base)); + BUG_ON(!virt_to_page(vec[i].iov_base)); off = (unsigned long)vec[i].iov_base & ~PAGE_MASK; ctxt->sge[i].addr = ib_dma_map_page(xprt->sc_cm_id->device, @@ -426,6 +427,7 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt, for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0]; ch->rc_discrim != 0; ch++, ch_no++) { + u64 rs_offset; next_sge: ctxt = svc_rdma_get_context(xprt); ctxt->direction = DMA_FROM_DEVICE; @@ -440,10 +442,10 @@ next_sge: read_wr.opcode = IB_WR_RDMA_READ; ctxt->wr_op = read_wr.opcode; read_wr.send_flags = IB_SEND_SIGNALED; - read_wr.wr.rdma.rkey = ch->rc_target.rs_handle; - read_wr.wr.rdma.remote_addr = - get_unaligned(&(ch->rc_target.rs_offset)) + - sgl_offset; + read_wr.wr.rdma.rkey = ntohl(ch->rc_target.rs_handle); + xdr_decode_hyper((__be32 *)&ch->rc_target.rs_offset, + &rs_offset); + read_wr.wr.rdma.remote_addr = rs_offset + sgl_offset; read_wr.sg_list = ctxt->sge; read_wr.num_sge = rdma_read_max_sge(xprt, chl_map->ch[ch_no].count); diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 249a835b703..42eb7ba0b90 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -409,21 +409,21 @@ static int send_write_chunks(struct svcxprt_rdma *xprt, u64 rs_offset; arg_ch = &arg_ary->wc_array[chunk_no].wc_target; - write_len = min(xfer_len, arg_ch->rs_length); + write_len = min(xfer_len, ntohl(arg_ch->rs_length)); /* Prepare the response chunk given the length actually * written */ - rs_offset = get_unaligned(&(arg_ch->rs_offset)); + xdr_decode_hyper((__be32 *)&arg_ch->rs_offset, &rs_offset); svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no, - arg_ch->rs_handle, - rs_offset, - write_len); + arg_ch->rs_handle, + arg_ch->rs_offset, + write_len); chunk_off = 0; while (write_len) { int this_write; this_write = min(write_len, max_write); ret = send_write(xprt, rqstp, - arg_ch->rs_handle, + ntohl(arg_ch->rs_handle), rs_offset + chunk_off, xdr_off, this_write, @@ -457,6 +457,7 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt, u32 xdr_off; int chunk_no; int chunk_off; + int nchunks; struct rpcrdma_segment *ch; struct rpcrdma_write_array *arg_ary; struct rpcrdma_write_array *res_ary; @@ -476,26 +477,27 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt, max_write = xprt->sc_max_sge * PAGE_SIZE; /* xdr offset starts at RPC message */ + nchunks = ntohl(arg_ary->wc_nchunks); for (xdr_off = 0, chunk_no = 0; - xfer_len && chunk_no < arg_ary->wc_nchunks; + xfer_len && chunk_no < nchunks; chunk_no++) { u64 rs_offset; ch = &arg_ary->wc_array[chunk_no].wc_target; - write_len = min(xfer_len, ch->rs_length); + write_len = min(xfer_len, htonl(ch->rs_length)); /* Prepare the reply chunk given the length actually * written */ - rs_offset = get_unaligned(&(ch->rs_offset)); + xdr_decode_hyper((__be32 *)&ch->rs_offset, &rs_offset); svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no, - ch->rs_handle, rs_offset, - write_len); + ch->rs_handle, ch->rs_offset, + write_len); chunk_off = 0; while (write_len) { int this_write; this_write = min(write_len, max_write); ret = send_write(xprt, rqstp, - ch->rs_handle, + ntohl(ch->rs_handle), rs_offset + chunk_off, xdr_off, this_write, diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 894cb42db91..73b428bef59 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -51,6 +51,7 @@ #include #include #include +#include "xprt_rdma.h" #define RPCDBG_FACILITY RPCDBG_SVCXPRT @@ -90,12 +91,6 @@ struct svc_xprt_class svc_rdma_class = { .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, }; -/* WR context cache. Created in svc_rdma.c */ -extern struct kmem_cache *svc_rdma_ctxt_cachep; - -/* Workqueue created in svc_rdma.c */ -extern struct workqueue_struct *svc_rdma_wq; - struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) { struct svc_rdma_op_ctxt *ctxt; @@ -150,9 +145,6 @@ void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages) atomic_dec(&xprt->sc_ctxt_used); } -/* Temporary NFS request map cache. Created in svc_rdma.c */ -extern struct kmem_cache *svc_rdma_map_cachep; - /* * Temporary NFS req mappings are shared across all transport * instances. These are short lived and should be bounded by the number diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index 08c5d5a128f..9a66c95b583 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h @@ -343,4 +343,11 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *); */ int rpcrdma_marshal_req(struct rpc_rqst *); +/* Temporary NFS request map cache. Created in svc_rdma.c */ +extern struct kmem_cache *svc_rdma_map_cachep; +/* WR context cache. Created in svc_rdma.c */ +extern struct kmem_cache *svc_rdma_ctxt_cachep; +/* Workqueue created in svc_rdma.c */ +extern struct workqueue_struct *svc_rdma_wq; + #endif /* _LINUX_SUNRPC_XPRT_RDMA_H */ -- cgit v1.2.3-70-g09d2 From f39799f5047c4827b200acbf33cd0ba076afd7ed Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:35 -0300 Subject: Bluetooth: Prepare start_discovery This patch does some code refactoring in start_discovery function in order to prepare it for interleaved discovery support. MGMT_ADDR_* macros were moved to hci_core.h since they are now used to define discovery type macros. Discovery type macros were defined according to mgmt-api.txt specification: Possible values for the Type parameter are a bit-wise or of the following bits: 1 BR/EDR 2 LE Public 3 LE Random By combining these e.g. the following values are possible: 1 BR/EDR 6 LE (public & random) 7 BR/EDR/LE (interleaved discovery) Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 12 ++++++++++++ include/net/bluetooth/mgmt.h | 5 ----- net/bluetooth/mgmt.c | 15 ++++++++++----- 3 files changed, 22 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 43e0b1eda02..be8da5d54ab 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -956,6 +956,18 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, struct sock *skip_sk); /* Management interface */ +#define MGMT_ADDR_BREDR 0x00 +#define MGMT_ADDR_LE_PUBLIC 0x01 +#define MGMT_ADDR_LE_RANDOM 0x02 +#define MGMT_ADDR_INVALID 0xff + +#define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR)) +#define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \ + BIT(MGMT_ADDR_LE_RANDOM)) +#define DISCOV_TYPE_INTERLEAVED (BIT(MGMT_ADDR_BREDR) | \ + BIT(MGMT_ADDR_LE_PUBLIC) | \ + BIT(MGMT_ADDR_LE_RANDOM)) + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); int mgmt_index_added(struct hci_dev *hdev); int mgmt_index_removed(struct hci_dev *hdev); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ee625a6ad79..ad54b5fd634 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -48,11 +48,6 @@ struct mgmt_hdr { __le16 len; } __packed; -#define MGMT_ADDR_BREDR 0x00 -#define MGMT_ADDR_LE_PUBLIC 0x01 -#define MGMT_ADDR_LE_RANDOM 0x02 -#define MGMT_ADDR_INVALID 0xff - struct mgmt_addr_info { bdaddr_t bdaddr; __u8 type; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f9f3e4c4415..196215c9d42 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2157,7 +2157,6 @@ static int start_discovery(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; - unsigned long discov_type = cp->type; struct pending_cmd *cmd; struct hci_dev *hdev; int err; @@ -2193,14 +2192,20 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } - if (test_bit(MGMT_ADDR_BREDR, &discov_type)) + switch (cp->type) { + case DISCOV_TYPE_BREDR: + case DISCOV_TYPE_INTERLEAVED: err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); - else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) && - test_bit(MGMT_ADDR_LE_RANDOM, &discov_type)) + break; + + case DISCOV_TYPE_LE: err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); - else + break; + + default: err = -EINVAL; + } if (err < 0) mgmt_pending_remove(cmd); -- cgit v1.2.3-70-g09d2 From 4aab14e5504e84c42534378f91e836e6f55d0886 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:36 -0300 Subject: Bluetooth: Track discovery type This patch adds to struct discovery_state the field 'type' so that we can track the discovery type the device is performing. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 2 ++ net/bluetooth/mgmt.c | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index be8da5d54ab..d7c79b5335c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -57,6 +57,7 @@ struct inquiry_entry { }; struct discovery_state { + int type; enum { DISCOVERY_STOPPED, DISCOVERY_STARTING, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index dc31e7d6028..29a9b01c3b9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -380,6 +380,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) switch (state) { case DISCOVERY_STOPPED: + hdev->discovery.type = 0; + if (hdev->discovery.state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 196215c9d42..9d98382e48c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2192,7 +2192,9 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } - switch (cp->type) { + hdev->discovery.type = cp->type; + + switch (hdev->discovery.type) { case DISCOV_TYPE_BREDR: case DISCOV_TYPE_INTERLEAVED: err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); -- cgit v1.2.3-70-g09d2 From 343f935bfa44189c68527102c409286b0cfc4526 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:37 -0300 Subject: Bluetooth: Merge INQUIRY and LE_SCAN discovery states This patch merges DISCOVERY_INQUIRY and DISCOVERY_LE_SCAN states into a new state called DISCOVERY_FINDING. From the discovery perspective, we are pretty much worried about to know just if we are finding devices than what exactly phase of "finding devices" (inquiry or LE scan) we are currently running. Besides, to know if the controller is performing inquiry or LE scan we should check HCI_INQUIRY or HCI_LE_SCAN bits in hdev flags. Moreover, merging this two states will simplify the discovery state machine and will keep interleaved discovery implementation simpler. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 +-- net/bluetooth/hci_core.c | 6 ++---- net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d7c79b5335c..942de776427 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -61,8 +61,7 @@ struct discovery_state { enum { DISCOVERY_STOPPED, DISCOVERY_STARTING, - DISCOVERY_INQUIRY, - DISCOVERY_LE_SCAN, + DISCOVERY_FINDING, DISCOVERY_RESOLVING, DISCOVERY_STOPPING, } state; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 29a9b01c3b9..fabca080ae7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -361,8 +361,7 @@ bool hci_discovery_active(struct hci_dev *hdev) struct discovery_state *discov = &hdev->discovery; switch (discov->state) { - case DISCOVERY_INQUIRY: - case DISCOVERY_LE_SCAN: + case DISCOVERY_FINDING: case DISCOVERY_RESOLVING: return true; @@ -387,8 +386,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) break; case DISCOVERY_STARTING: break; - case DISCOVERY_INQUIRY: - case DISCOVERY_LE_SCAN: + case DISCOVERY_FINDING: mgmt_discovering(hdev, 1); break; case DISCOVERY_RESOLVING: diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 179d127601f..9aea7b89882 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1080,7 +1080,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, hci_dev_lock(hdev); hci_adv_entries_clear(hdev); - hci_discovery_set_state(hdev, DISCOVERY_LE_SCAN); + hci_discovery_set_state(hdev, DISCOVERY_FINDING); hci_dev_unlock(hdev); break; @@ -1159,7 +1159,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) set_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_INQUIRY); + hci_discovery_set_state(hdev, DISCOVERY_FINDING); hci_dev_unlock(hdev); } @@ -1645,7 +1645,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff hci_dev_lock(hdev); - if (discov->state != DISCOVERY_INQUIRY) + if (discov->state != DISCOVERY_FINDING) goto unlock; if (list_empty(&discov->resolve)) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9d98382e48c..a9cd38dc2ca 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2250,7 +2250,7 @@ static int stop_discovery(struct sock *sk, u16 index) goto unlock; } - if (hdev->discovery.state == DISCOVERY_INQUIRY) { + if (hdev->discovery.state == DISCOVERY_FINDING) { err = hci_cancel_inquiry(hdev); if (err < 0) mgmt_pending_remove(cmd); -- cgit v1.2.3-70-g09d2 From 5e0452c00a2e4b04ec1482248c897dacf106f1df Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:38 -0300 Subject: Bluetooth: Interleaved discovery support This patch adds interleaved discovery support to MGMT Start Discovery command. In case interleaved discovery is not supported (not a dual mode device), we perform BR/EDR or LE-only discovery according to the device capabilities. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_event.c | 13 +++++++---- net/bluetooth/mgmt.c | 47 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 942de776427..2aafeb3a879 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -716,6 +716,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) #define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE) +#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR)) /* ----- Extended LMP capabilities ----- */ #define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE) @@ -1019,6 +1020,7 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); +int mgmt_interleaved_discovery(struct hci_dev *hdev); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9aea7b89882..04fb1f02dfc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1090,11 +1090,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, clear_bit(HCI_LE_SCAN, &hdev->dev_flags); - hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); - hci_dev_unlock(hdev); - schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); + + if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) { + mgmt_interleaved_discovery(hdev); + } else { + hci_dev_lock(hdev); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + hci_dev_unlock(hdev); + } + break; default: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a9cd38dc2ca..89754bbcd02 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -108,8 +108,10 @@ static const u16 mgmt_events[] = { #define LE_SCAN_WIN 0x12 #define LE_SCAN_INT 0x12 #define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */ +#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */ #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ +#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */ #define SERVICE_CACHE_TIMEOUT (5 * 1000) @@ -2153,6 +2155,46 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return err; } +static int discovery(struct hci_dev *hdev) +{ + int err; + + if (lmp_host_le_capable(hdev)) { + if (lmp_bredr_capable(hdev)) { + err = hci_le_scan(hdev, LE_SCAN_TYPE, + LE_SCAN_INT, LE_SCAN_WIN, + LE_SCAN_TIMEOUT_BREDR_LE); + } else { + hdev->discovery.type = DISCOV_TYPE_LE; + err = hci_le_scan(hdev, LE_SCAN_TYPE, + LE_SCAN_INT, LE_SCAN_WIN, + LE_SCAN_TIMEOUT_LE_ONLY); + } + } else { + hdev->discovery.type = DISCOV_TYPE_BREDR; + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + } + + return err; +} + +int mgmt_interleaved_discovery(struct hci_dev *hdev) +{ + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE); + if (err < 0) + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + + hci_dev_unlock(hdev); + + return err; +} + static int start_discovery(struct sock *sk, u16 index, void *data, u16 len) { @@ -2196,7 +2238,6 @@ static int start_discovery(struct sock *sk, u16 index, switch (hdev->discovery.type) { case DISCOV_TYPE_BREDR: - case DISCOV_TYPE_INTERLEAVED: err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); break; @@ -2205,6 +2246,10 @@ static int start_discovery(struct sock *sk, u16 index, LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); break; + case DISCOV_TYPE_INTERLEAVED: + err = discovery(hdev); + break; + default: err = -EINVAL; } -- cgit v1.2.3-70-g09d2 From aee9b218036476b8b659de5bbfada3a4633f635b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 18 Feb 2012 15:07:59 +0200 Subject: Bluetooth: mgmt: Move status parameters into the cmd_complete header Instead of having status paramters part of each individual command response it's simpler to just have the status as part of the command complete header. This patch updates the code to follow this convention and thereby also ensures compliance with the latest mgmt API specification. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 8 +--- net/bluetooth/mgmt.c | 107 ++++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 59 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 36e68b4551a..7e3d38bfaec 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -184,7 +184,6 @@ struct mgmt_cp_disconnect { } __packed; struct mgmt_rp_disconnect { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_GET_CONNECTIONS 0x0015 @@ -201,7 +200,6 @@ struct mgmt_cp_pin_code_reply { } __packed; struct mgmt_rp_pin_code_reply { struct mgmt_addr_info addr; - uint8_t status; } __packed; #define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017 @@ -221,7 +219,6 @@ struct mgmt_cp_pair_device { } __packed; struct mgmt_rp_pair_device { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A @@ -233,7 +230,6 @@ struct mgmt_cp_unpair_device { } __packed; struct mgmt_rp_unpair_device { struct mgmt_addr_info addr; - __u8 status; }; #define MGMT_OP_USER_CONFIRM_REPLY 0x001C @@ -242,7 +238,6 @@ struct mgmt_cp_user_confirm_reply { } __packed; struct mgmt_rp_user_confirm_reply { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D @@ -257,7 +252,6 @@ struct mgmt_cp_user_passkey_reply { } __packed; struct mgmt_rp_user_passkey_reply { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F @@ -297,7 +291,6 @@ struct mgmt_cp_confirm_name { } __packed; struct mgmt_rp_confirm_name { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_BLOCK_DEVICE 0x0026 @@ -313,6 +306,7 @@ struct mgmt_cp_unblock_device { #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; + __u8 status; __u8 data[0]; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 89754bbcd02..61d0250bd77 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -227,8 +227,8 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) return err; } -static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, - size_t rp_len) +static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, + void *rp, size_t rp_len) { struct sk_buff *skb; struct mgmt_hdr *hdr; @@ -249,6 +249,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, ev = (void *) skb_put(skb, sizeof(*ev) + rp_len); put_unaligned_le16(cmd, &ev->opcode); + ev->status = status; if (rp) memcpy(ev->data, rp, rp_len); @@ -269,7 +270,7 @@ static int read_version(struct sock *sk) rp.version = MGMT_VERSION; put_unaligned_le16(MGMT_REVISION, &rp.revision); - return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp, + return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp, sizeof(rp)); } @@ -299,7 +300,7 @@ static int read_commands(struct sock *sk) for (i = 0; i < num_events; i++, opcode++) put_unaligned_le16(mgmt_events[i], opcode); - err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp, + err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp, rp_size); kfree(rp); @@ -347,7 +348,7 @@ static int read_index_list(struct sock *sk) read_unlock(&hci_dev_list_lock); - err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp, + err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp, rp_len); kfree(rp); @@ -637,7 +638,7 @@ static int read_controller_info(struct sock *sk, u16 index) hci_dev_unlock(hdev); hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); + return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp)); } static void mgmt_pending_free(struct pending_cmd *cmd) @@ -717,7 +718,8 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) { __le32 settings = cpu_to_le32(get_current_settings(hdev)); - return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings)); + return cmd_complete(sk, hdev->id, opcode, 0, &settings, + sizeof(settings)); } static int set_powered(struct sock *sk, u16 index, void *data, u16 len) @@ -1124,7 +1126,7 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0); failed: hci_dev_unlock(hdev); @@ -1185,7 +1187,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto unlock; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0); unlock: hci_dev_unlock(hdev); @@ -1226,7 +1228,8 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) err = update_class(hdev); if (err == 0) - err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -1282,7 +1285,7 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) key->type, key->pin_len); } - cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0); + cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -1310,6 +1313,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; + u8 status = 0; int err; if (len != sizeof(*cp)) @@ -1333,13 +1337,13 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) err = hci_remove_ltk(hdev, &cp->addr.bdaddr); if (err < 0) { - rp.status = MGMT_STATUS_NOT_PAIRED; + status = MGMT_STATUS_NOT_PAIRED; goto unlock; } if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -1352,8 +1356,8 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) &cp->addr.bdaddr); if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -1373,8 +1377,8 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) unlock: if (err < 0) - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + &rp, sizeof(rp)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -1512,7 +1516,7 @@ static int get_connections(struct sock *sk, u16 index) /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); - err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len); + err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len); unlock: kfree(rp); @@ -1672,7 +1676,7 @@ static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) hci_dev_unlock(hdev); hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); + return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0); } static inline struct pending_cmd *find_pairing(struct hci_conn *conn) @@ -1700,9 +1704,9 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) bacpy(&rp.addr.bdaddr, &conn->dst); rp.addr.type = link_to_mgmt(conn->type, conn->dst_type); - rp.status = status; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp)); + cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status, + &rp, sizeof(rp)); /* So we don't get further callbacks for this connection */ conn->connect_cfm_cb = NULL; @@ -1735,6 +1739,7 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) struct pending_cmd *cmd; u8 sec_level, auth_type; struct hci_conn *conn; + u8 status = 0; int err; BT_DBG(""); @@ -1768,16 +1773,16 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (IS_ERR(conn)) { - rp.status = -PTR_ERR(conn); - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + status = -PTR_ERR(conn); + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, &rp, sizeof(rp)); goto unlock; } if (conn->connect_cfm_cb) { hci_conn_put(conn); - rp.status = EBUSY; - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + status = EBUSY; + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, &rp, sizeof(rp)); goto unlock; } @@ -1850,7 +1855,7 @@ static int cancel_pair_device(struct sock *sk, u16 index, pairing_complete(cmd, MGMT_STATUS_CANCELLED); - err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr, + err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr, sizeof(*addr)); unlock: hci_dev_unlock(hdev); @@ -2112,8 +2117,8 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_FAILED); else - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, - 0); + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, 0, + NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2147,7 +2152,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, MGMT_STATUS_INVALID_PARAMS); else err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - NULL, 0); + 0, NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2307,7 +2312,8 @@ static int stop_discovery(struct sock *sk, u16 index) e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); if (!e) { mgmt_pending_remove(cmd); - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0, + NULL, 0); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; } @@ -2400,8 +2406,8 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_FAILED); else - err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, - NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, 0, + NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2434,7 +2440,7 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); else - err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, + err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, 0, NULL, 0); hci_dev_unlock(hdev); @@ -2490,8 +2496,8 @@ static int set_fast_connectable(struct sock *sk, u16 index, goto done; } - err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0, + NULL, 0); done: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2908,9 +2914,9 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; - rp.status = 0; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); + cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp, + sizeof(rp)); *sk = cmd->sk; sock_hold(*sk); @@ -2930,7 +2936,7 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); - cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp)); + cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp)); mgmt_pending_remove(cmd); } @@ -2972,10 +2978,9 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = link_to_mgmt(link_type, addr_type); - rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, - &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3021,10 +3026,9 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = MGMT_ADDR_BREDR; - rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp, - sizeof(rp)); + err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3044,10 +3048,9 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = MGMT_ADDR_BREDR; - rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, - sizeof(rp)); + err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3099,8 +3102,8 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = link_to_mgmt(link_type, addr_type); - rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp)); + err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status), + &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3217,7 +3220,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) update_eir(hdev); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev, + err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev, sizeof(ev)); if (err < 0) goto failed; @@ -3256,7 +3259,7 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - &rp, sizeof(rp)); + 0, &rp, sizeof(rp)); } mgmt_pending_remove(cmd); @@ -3365,7 +3368,7 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev); if (cmd != NULL) { - cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0); + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, NULL, 0); mgmt_pending_remove(cmd); } -- cgit v1.2.3-70-g09d2 From e211326c0b064e8fe2a8cb51427c3f2044ad84be Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 18 Feb 2012 15:20:03 +0200 Subject: Bluetooth: mgmt: Fix Pair Device response status values This patch fixes the status in Pair Device responses to follow proper mgmt status values. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 61d0250bd77..79255f53627 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1728,7 +1728,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) if (!cmd) BT_DBG("Unable to find a pending command"); else - pairing_complete(cmd, status); + pairing_complete(cmd, mgmt_status(status)); } static int pair_device(struct sock *sk, u16 index, void *data, u16 len) @@ -1739,7 +1739,6 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) struct pending_cmd *cmd; u8 sec_level, auth_type; struct hci_conn *conn; - u8 status = 0; int err; BT_DBG(""); @@ -1773,17 +1772,16 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (IS_ERR(conn)) { - status = -PTR_ERR(conn); - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, - &rp, sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_CONNECT_FAILED, + &rp, sizeof(rp)); goto unlock; } if (conn->connect_cfm_cb) { hci_conn_put(conn); - status = EBUSY; - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, - &rp, sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } -- cgit v1.2.3-70-g09d2 From f808e166e7c529a7e706cda916c8c99589d2d95b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 12:52:07 +0200 Subject: Bluetooth: mgmt: Fix Start Discovery return parameters The same address type that was passed to the Start Discovery command should also be returned in the response message. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 79255f53627..258adf44493 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3325,6 +3325,7 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; + u8 type; int err; hci_discovery_set_state(hdev, DISCOVERY_STOPPED); @@ -3333,7 +3334,10 @@ int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) if (!cmd) return -ENOENT; - err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status)); + type = hdev->discovery.type; + + err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), + &type, sizeof(type)); mgmt_pending_remove(cmd); return err; @@ -3366,7 +3370,14 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev); if (cmd != NULL) { - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, NULL, 0); + u8 type = hdev->discovery.type; + + if (discovering) + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, + &type, sizeof(type)); + else + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, + NULL, 0); mgmt_pending_remove(cmd); } -- cgit v1.2.3-70-g09d2 From f0eeea8b61d6e8316f6137b372eb3f3ac180508c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 12:58:54 +0200 Subject: Bluetooth: mgmt: Fix (Un)Block Device return parameters The same address as was passed to the (Un)Block Device command should also be returned in the command response message. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 258adf44493..c7e9a450b44 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2384,6 +2384,7 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct mgmt_cp_block_device *cp = data; + u8 status; int err; BT_DBG("hci%u", index); @@ -2394,18 +2395,20 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) - err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_FAILED); + status = MGMT_STATUS_FAILED; else - err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, 0, - NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2417,6 +2420,7 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct mgmt_cp_unblock_device *cp = data; + u8 status; int err; BT_DBG("hci%u", index); @@ -2427,19 +2431,20 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); - if (err < 0) - err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + status = MGMT_STATUS_INVALID_PARAMS; else - err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, 0, - NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3-70-g09d2 From bf1e3541f75a395e1e21b144fe1c387cc71baff1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 13:16:14 +0200 Subject: Bluetooth: mgmt: Fix OOB command response parameters The response to the Add/Remove Out Of Band Data commands should include the same address as was given in the command itself. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c7e9a450b44..952c0a8ca30 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2094,6 +2094,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, { struct hci_dev *hdev; struct mgmt_cp_add_remote_oob_data *cp = data; + u8 status; int err; BT_DBG("hci%u ", index); @@ -2104,19 +2105,21 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, cp->randomizer); if (err < 0) - err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_FAILED); + status = MGMT_STATUS_FAILED; else - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, 0, - NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2129,6 +2132,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, { struct hci_dev *hdev; struct mgmt_cp_remove_remote_oob_data *cp = data; + u8 status; int err; BT_DBG("hci%u ", index); @@ -2139,18 +2143,20 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); if (err < 0) - err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + status = MGMT_STATUS_INVALID_PARAMS; else - err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - 0, NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3-70-g09d2 From 2da9c55c5a4a0b8f0348b7acd70d8b08a6ae4573 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:39:28 +0200 Subject: Bluetooth: mgmt: Bump mgmt version This patch bumps the mgmt version to 1 and resets the revision to 0. This is in order to indicate API stability to user space. The mgmt API has reached a point where no major backwards incompatible changes are expected so it makes sense to do this version bump now. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 952c0a8ca30..18d593f2393 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -34,8 +34,8 @@ #include #include -#define MGMT_VERSION 0 -#define MGMT_REVISION 1 +#define MGMT_VERSION 1 +#define MGMT_REVISION 0 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, -- cgit v1.2.3-70-g09d2 From 48c7aba91f372251867d15efc9cf694ceee2de02 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 14:06:48 +0200 Subject: Bluetooth: Fix hci_connect error return values The hci_connect function should either return a valid hci_conn pointer or a ERR_PTR() but never NULL. This patch fixes the two places where hci_conn_add failures would have caused a NULL return. The only reason for failure with hci_conn_add is memory allocation so ENOMEM seems to be a good choice here. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7ee6895c4b0..8549d04e331 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -551,7 +551,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 if (!acl) { acl = hci_conn_add(hdev, ACL_LINK, dst); if (!acl) - return NULL; + return ERR_PTR(-ENOMEM); } hci_conn_hold(acl); @@ -571,7 +571,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sco = hci_conn_add(hdev, type, dst); if (!sco) { hci_conn_put(acl); - return NULL; + return ERR_PTR(-ENOMEM); } } -- cgit v1.2.3-70-g09d2 From 470fe1b540fb50ba8ce01e0ac985602e8fbb108c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:30 +0100 Subject: Bluetooth: Split sending for HCI raw and control sockets The sending functions for HCI raw and control sockets have nothing in common except that they iterate over the socket list. Split them into two so they can do their job more efficient. In addition the code becomes more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/hci_event.c | 2 +- net/bluetooth/hci_sock.c | 51 ++++++++++++++++++++++++++++++---------- net/bluetooth/mgmt.c | 2 +- 5 files changed, 45 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2aafeb3a879..9209e4c8a21 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -953,8 +953,8 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); /* ----- HCI Sockets ----- */ -void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, - struct sock *skip_sk); +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); +void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); /* Management interface */ #define MGMT_ADDR_BREDR 0x00 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fabca080ae7..638fa8c393d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2131,7 +2131,7 @@ static int hci_send_frame(struct sk_buff *skb) /* Time stamp */ __net_timestamp(skb); - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); } /* Get rid of skb owner, prior to sending to the driver. */ @@ -2818,7 +2818,7 @@ static void hci_rx_work(struct work_struct *work) while ((skb = skb_dequeue(&hdev->rx_q))) { if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); } if (test_bit(HCI_RAW, &hdev->flags)) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 04fb1f02dfc..e69db4a7b3e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3571,7 +3571,7 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) bt_cb(skb)->pkt_type = HCI_EVENT_PKT; skb->dev = (void *) hdev; - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); kfree_skb(skb); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 9e854d9fb46..b5b3bc8d284 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -85,8 +85,7 @@ static struct bt_sock_list hci_sk_list = { }; /* Send frame to RAW socket */ -void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, - struct sock *skip_sk) +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) { struct sock *sk; struct hlist_node *node; @@ -94,13 +93,11 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, BT_DBG("hdev %p len %d", hdev, skb->len); read_lock(&hci_sk_list.lock); + sk_for_each(sk, node, &hci_sk_list.head) { struct hci_filter *flt; struct sk_buff *nskb; - if (sk == skip_sk) - continue; - if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev) continue; @@ -108,12 +105,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, if (skb->sk == sk) continue; - if (bt_cb(skb)->channel != hci_pi(sk)->channel) + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) continue; - if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL) - goto clone; - /* Apply filter */ flt = &hci_pi(sk)->filter; @@ -137,18 +131,51 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, continue; } -clone: nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) continue; /* Put type byte before the data */ - if (bt_cb(skb)->channel == HCI_CHANNEL_RAW) - memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); + memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); +} + +/* Send frame to control socket */ +void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) +{ + struct sock *sk; + struct hlist_node *node; + + BT_DBG("len %d", skb->len); + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + /* Skip the original socket */ + if (sk == skip_sk) + continue; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL) + continue; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + continue; if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } + read_unlock(&hci_sk_list.lock); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 18d593f2393..1695d04d927 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -924,7 +924,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (data) memcpy(skb_put(skb, data_len), data, data_len); - hci_send_to_sock(NULL, skb, skip_sk); + hci_send_to_control(skb, skip_sk); kfree_skb(skb); return 0; -- cgit v1.2.3-70-g09d2 From a6fb08dfe8654e399c9bbca34be914e213560b5e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:31 +0100 Subject: Bluetooth: Remove unneeded bt_cb(skb)->channel variable The bt_cb(skb)->channel was only needed to make hci_send_to_sock() be used for HCI raw and control sockets. Since they have now separate sending functions this is no longer needed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 1 - net/bluetooth/mgmt.c | 2 -- 2 files changed, 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 5ca9219fe94..262ebd1747d 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -222,7 +222,6 @@ struct bt_skb_cb { __u16 tx_seq; __u8 retries; __u8 sar; - unsigned short channel; __u8 force_active; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1695d04d927..bc71b45ef4e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -911,8 +911,6 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (!skb) return -ENOMEM; - bt_cb(skb)->channel = HCI_CHANNEL_CONTROL; - hdr = (void *) skb_put(skb, sizeof(*hdr)); hdr->opcode = cpu_to_le16(event); if (hdev) -- cgit v1.2.3-70-g09d2 From 2f39cdb7a270da24532734dfdfd10c490be981c4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:32 +0100 Subject: Bluetooth: Limit HCI raw socket options to actual raw sockets Currently the socket options of HCI sockets can be set on raw and control sockets, but on control sockets they make no sense. So just return EINVAL in that case. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index b5b3bc8d284..612bc2af05a 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -601,6 +601,11 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char lock_sock(sk); + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { + err = -EINVAL; + goto done; + } + switch (optname) { case HCI_DATA_DIR: if (get_user(opt, (int __user *)optval)) { @@ -663,6 +668,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char break; } +done: release_sock(sk); return err; } -- cgit v1.2.3-70-g09d2 From cedc5469778846ee18c653aaa6d70681961eed93 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:33 +0100 Subject: Bluetooth: Lock socket when reading HCI socket options When reading the HCI raw socket option, the socket was never locked. So lock the socket and in addition return EINVAL on non raw sockets. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 612bc2af05a..27ec9088508 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -677,11 +677,20 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char { struct hci_ufilter uf; struct sock *sk = sock->sk; - int len, opt; + int len, opt, err = 0; + + BT_DBG("sk %p, opt %d", sk, optname); if (get_user(len, optlen)) return -EFAULT; + lock_sock(sk); + + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { + err = -EINVAL; + goto done; + } + switch (optname) { case HCI_DATA_DIR: if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR) @@ -690,7 +699,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char opt = 0; if (put_user(opt, optval)) - return -EFAULT; + err = -EFAULT; break; case HCI_TIME_STAMP: @@ -700,7 +709,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char opt = 0; if (put_user(opt, optval)) - return -EFAULT; + err = -EFAULT; break; case HCI_FILTER: @@ -715,15 +724,17 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char len = min_t(unsigned int, len, sizeof(uf)); if (copy_to_user(optval, &uf, len)) - return -EFAULT; + err = -EFAULT; break; default: - return -ENOPROTOOPT; + err = -ENOPROTOOPT; break; } - return 0; +done: + release_sock(sk); + return err; } static const struct proto_ops hci_sock_ops = { -- cgit v1.2.3-70-g09d2 From 3a208627f3ac83d3b749608770f7eb631db31a77 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:34 +0100 Subject: Bluetooth: Add HCI CMSG details only to raw sockets The HCI CMSG specific data is for raw sockets only. So only add them to actual raw sockets. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 27ec9088508..71a02adbaa7 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -488,7 +488,11 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, skb_reset_transport_header(skb); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - hci_sock_cmsg(sk, msg, skb); + switch (hci_pi(sk)->channel) { + case HCI_CHANNEL_RAW: + hci_sock_cmsg(sk, msg, skb); + break; + } skb_free_datagram(sk, skb); -- cgit v1.2.3-70-g09d2 From 7cc2ade2cbc6f71090f0f8d0e11cb68886ddc65e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:35 +0100 Subject: Bluetooth: Simplify HCI socket bind handling The HCI socket bind handling checks a few too many times the channel we are binding. So centralize this and make the function easier to read. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 71a02adbaa7..4dda4574db3 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -367,34 +367,49 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le if (haddr.hci_family != AF_BLUETOOTH) return -EINVAL; - if (haddr.hci_channel > HCI_CHANNEL_CONTROL) - return -EINVAL; - - if (haddr.hci_channel == HCI_CHANNEL_CONTROL) { - if (!enable_mgmt) - return -EINVAL; - set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); - } - lock_sock(sk); - if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) { + if (sk->sk_state == BT_BOUND) { err = -EALREADY; goto done; } - if (haddr.hci_dev != HCI_DEV_NONE) { - hdev = hci_dev_get(haddr.hci_dev); - if (!hdev) { - err = -ENODEV; + switch (haddr.hci_channel) { + case HCI_CHANNEL_RAW: + if (hci_pi(sk)->hdev) { + err = -EALREADY; goto done; } - atomic_inc(&hdev->promisc); + if (haddr.hci_dev != HCI_DEV_NONE) { + hdev = hci_dev_get(haddr.hci_dev); + if (!hdev) { + err = -ENODEV; + goto done; + } + + atomic_inc(&hdev->promisc); + } + + hci_pi(sk)->hdev = hdev; + break; + + case HCI_CHANNEL_CONTROL: + if (haddr.hci_dev != HCI_DEV_NONE || !enable_mgmt) { + err = -EINVAL; + goto done; + } + + set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); + break; + + default: + err = -EINVAL; + goto done; } + hci_pi(sk)->channel = haddr.hci_channel; - hci_pi(sk)->hdev = hdev; sk->sk_state = BT_BOUND; done: -- cgit v1.2.3-70-g09d2 From e0edf3733fb62f91bbb8ec3fab4a90b0ac2dd037 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:36 +0100 Subject: Bluetooth: Fix issue with shared SKB between HCI raw socket and driver Any HCI raw socket gets a copy of each SKB that is either received or send via the Bluetooth subsystem. The raw socket uses SKB clones to send out data, but the problem is that it needs to add an extra packet type byte in front of it. And some drivers need to also add an extra header before submitting the packet. So far this all worked magically fine since all of the drivers and the raw sockets are adding the same byte at the same location. But that is by pure coincidence. Since the data of cloned SKBs is shared, this means that the raw socket and driver kept writing into the shared data area. To fix this the only safe way is if the HCI raw socket creates a copy of the SKB before sending it out. To not always copy all SKBs around, the copy is only created once and only after any of the HCI filter checks succeeded. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4dda4574db3..cf940bd7a2b 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -89,6 +89,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) { struct sock *sk; struct hlist_node *node; + struct sk_buff *skb_copy = NULL; BT_DBG("hdev %p len %d", hdev, skb->len); @@ -131,18 +132,27 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) continue; } - nskb = skb_clone(skb, GFP_ATOMIC); + if (!skb_copy) { + /* Create a private copy with headroom */ + skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC); + if (!skb_copy) + continue; + + /* Put type byte before the data */ + memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1); + } + + nskb = skb_clone(skb_copy, GFP_ATOMIC); if (!nskb) continue; - /* Put type byte before the data */ - memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); - if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } read_unlock(&hci_sk_list.lock); + + kfree_skb(skb_copy); } /* Send frame to control socket */ -- cgit v1.2.3-70-g09d2 From 040030ef7d907107e6489b39da518bdf94136d68 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:37 +0100 Subject: Bluetooth: Remove HCI notifier handling The HCI notifier handling was never used outside of Bluetooth core layer and thus remove it and replace it with direct function calls. Also move the stack internal event generation into the HCI socket layer. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 7 +-- net/bluetooth/hci_conn.c | 1 - net/bluetooth/hci_core.c | 16 +----- net/bluetooth/hci_event.c | 29 ----------- net/bluetooth/hci_sock.c | 105 +++++++++++++++++++++++---------------- 5 files changed, 64 insertions(+), 94 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9209e4c8a21..41adae509e9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -941,21 +941,18 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); -int hci_register_notifier(struct notifier_block *nb); -int hci_unregister_notifier(struct notifier_block *nb); - int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); -void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); - /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); +void hci_sock_dev_event(struct hci_dev *hdev, int event); + /* Management interface */ #define MGMT_ADDR_BREDR 0x00 #define MGMT_ADDR_LE_PUBLIC 0x01 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8549d04e331..3c68e606d5e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 638fa8c393d..47217281d9a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -69,24 +68,11 @@ DEFINE_RWLOCK(hci_dev_list_lock); LIST_HEAD(hci_cb_list); DEFINE_RWLOCK(hci_cb_list_lock); -/* HCI notifiers list */ -static ATOMIC_NOTIFIER_HEAD(hci_notifier); - /* ---- HCI notifications ---- */ -int hci_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&hci_notifier, nb); -} - -int hci_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&hci_notifier, nb); -} - static void hci_notify(struct hci_dev *hdev, int event) { - atomic_notifier_call_chain(&hci_notifier, event, hdev); + hci_sock_dev_event(hdev, event); } /* ---- HCI requests ---- */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e69db4a7b3e..f00faf0ac32 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -3547,33 +3546,5 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hdev->stat.evt_rx++; } -/* Generate internal stack event */ -void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) -{ - struct hci_event_hdr *hdr; - struct hci_ev_stack_internal *ev; - struct sk_buff *skb; - - skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); - if (!skb) - return; - - hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE); - hdr->evt = HCI_EV_STACK_INTERNAL; - hdr->plen = sizeof(*ev) + dlen; - - ev = (void *) skb_put(skb, sizeof(*ev) + dlen); - ev->type = type; - memcpy(ev->data, data, dlen); - - bt_cb(skb)->incoming = 1; - __net_timestamp(skb); - - bt_cb(skb)->pkt_type = HCI_EVENT_PKT; - skb->dev = (void *) hdev; - hci_send_to_sock(hdev, skb); - kfree_skb(skb); -} - module_param(enable_le, bool, 0644); MODULE_PARM_DESC(enable_le, "Enable LE support"); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index cf940bd7a2b..14727cb43f6 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -189,6 +189,67 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) read_unlock(&hci_sk_list.lock); } +/* Generate internal stack event */ +static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) +{ + struct hci_event_hdr *hdr; + struct hci_ev_stack_internal *ev; + struct sk_buff *skb; + + skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); + if (!skb) + return; + + hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE); + hdr->evt = HCI_EV_STACK_INTERNAL; + hdr->plen = sizeof(*ev) + dlen; + + ev = (void *) skb_put(skb, sizeof(*ev) + dlen); + ev->type = type; + memcpy(ev->data, data, dlen); + + bt_cb(skb)->incoming = 1; + __net_timestamp(skb); + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + skb->dev = (void *) hdev; + hci_send_to_sock(hdev, skb); + kfree_skb(skb); +} + +void hci_sock_dev_event(struct hci_dev *hdev, int event) +{ + struct hci_ev_si_device ev; + + BT_DBG("hdev %s event %d", hdev->name, event); + + /* Send event to sockets */ + ev.event = event; + ev.dev_id = hdev->id; + hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev); + + if (event == HCI_DEV_UNREG) { + struct sock *sk; + struct hlist_node *node; + + /* Detach sockets from device */ + read_lock(&hci_sk_list.lock); + sk_for_each(sk, node, &hci_sk_list.head) { + bh_lock_sock_nested(sk); + if (hci_pi(sk)->hdev == hdev) { + hci_pi(sk)->hdev = NULL; + sk->sk_err = EPIPE; + sk->sk_state = BT_OPEN; + sk->sk_state_change(sk); + + hci_dev_put(hdev); + } + bh_unlock_sock(sk); + } + read_unlock(&hci_sk_list.lock); + } +} + static int hci_sock_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -821,52 +882,12 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol, return 0; } -static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct hci_dev *hdev = (struct hci_dev *) ptr; - struct hci_ev_si_device ev; - - BT_DBG("hdev %s event %ld", hdev->name, event); - - /* Send event to sockets */ - ev.event = event; - ev.dev_id = hdev->id; - hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev); - - if (event == HCI_DEV_UNREG) { - struct sock *sk; - struct hlist_node *node; - - /* Detach sockets from device */ - read_lock(&hci_sk_list.lock); - sk_for_each(sk, node, &hci_sk_list.head) { - bh_lock_sock_nested(sk); - if (hci_pi(sk)->hdev == hdev) { - hci_pi(sk)->hdev = NULL; - sk->sk_err = EPIPE; - sk->sk_state = BT_OPEN; - sk->sk_state_change(sk); - - hci_dev_put(hdev); - } - bh_unlock_sock(sk); - } - read_unlock(&hci_sk_list.lock); - } - - return NOTIFY_DONE; -} - static const struct net_proto_family hci_sock_family_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .create = hci_sock_create, }; -static struct notifier_block hci_sock_nblock = { - .notifier_call = hci_sock_dev_event -}; - int __init hci_sock_init(void) { int err; @@ -879,8 +900,6 @@ int __init hci_sock_init(void) if (err < 0) goto error; - hci_register_notifier(&hci_sock_nblock); - BT_INFO("HCI socket layer initialized"); return 0; @@ -896,8 +915,6 @@ void hci_sock_cleanup(void) if (bt_sock_unregister(BTPROTO_HCI) < 0) BT_ERR("HCI socket unregistration failed"); - hci_unregister_notifier(&hci_sock_nblock); - proto_unregister(&hci_sk_proto); } -- cgit v1.2.3-70-g09d2 From da88cea1200b9df65a7811a3920aa5a4be7dab9f Mon Sep 17 00:00:00 2001 From: "H. J. Lu" Date: Fri, 10 Feb 2012 14:12:15 -0800 Subject: compat: Use COMPAT_USE_64BIT_TIME in the Bluetooth subsystem Enable the Bluetooth subsystem to be used with a compat ABI with 64-bit time. Signed-off-by: H. Peter Anvin Cc: Marcel Holtmann Cc: Gustavo F. Padovan Cc: David S. Miller --- net/bluetooth/hci_sock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 0dcc9626677..b2eb2b93580 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -418,7 +418,8 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_ data = &tv; len = sizeof(tv); #ifdef CONFIG_COMPAT - if (msg->msg_flags & MSG_CMSG_COMPAT) { + if (!COMPAT_USE_64BIT_TIME && + (msg->msg_flags & MSG_CMSG_COMPAT)) { ctv.tv_sec = tv.tv_sec; ctv.tv_usec = tv.tv_usec; data = &ctv; -- cgit v1.2.3-70-g09d2 From ee4fa23c4bfcc635d077a9633d405610de45bc70 Mon Sep 17 00:00:00 2001 From: "H. J. Lu" Date: Sun, 19 Feb 2012 17:50:46 -0800 Subject: compat: Use COMPAT_USE_64BIT_TIME in net/compat.c Handle 64-bit time structures in the networking core compat code. Signed-off-by: H. Peter Anvin Cc: David S. Miller --- net/compat.c | 65 +++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/net/compat.c b/net/compat.c index 6def90e0a11..73bf0e06f3d 100644 --- a/net/compat.c +++ b/net/compat.c @@ -219,8 +219,6 @@ Efault: int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data) { - struct compat_timeval ctv; - struct compat_timespec cts[3]; struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; struct compat_cmsghdr cmhdr; int cmlen; @@ -230,24 +228,28 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat return 0; /* XXX: return error? check spec. */ } - if (level == SOL_SOCKET && type == SCM_TIMESTAMP) { - struct timeval *tv = (struct timeval *)data; - ctv.tv_sec = tv->tv_sec; - ctv.tv_usec = tv->tv_usec; - data = &ctv; - len = sizeof(ctv); - } - if (level == SOL_SOCKET && - (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) { - int count = type == SCM_TIMESTAMPNS ? 1 : 3; - int i; - struct timespec *ts = (struct timespec *)data; - for (i = 0; i < count; i++) { - cts[i].tv_sec = ts[i].tv_sec; - cts[i].tv_nsec = ts[i].tv_nsec; + if (!COMPAT_USE_64BIT_TIME) { + struct compat_timeval ctv; + struct compat_timespec cts[3]; + if (level == SOL_SOCKET && type == SCM_TIMESTAMP) { + struct timeval *tv = (struct timeval *)data; + ctv.tv_sec = tv->tv_sec; + ctv.tv_usec = tv->tv_usec; + data = &ctv; + len = sizeof(ctv); + } + if (level == SOL_SOCKET && + (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) { + int count = type == SCM_TIMESTAMPNS ? 1 : 3; + int i; + struct timespec *ts = (struct timespec *)data; + for (i = 0; i < count; i++) { + cts[i].tv_sec = ts[i].tv_sec; + cts[i].tv_nsec = ts[i].tv_nsec; + } + data = &cts; + len = sizeof(cts[0]) * count; } - data = &cts; - len = sizeof(cts[0]) * count; } cmlen = CMSG_COMPAT_LEN(len); @@ -454,11 +456,15 @@ static int compat_sock_getsockopt(struct socket *sock, int level, int optname, int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) { - struct compat_timeval __user *ctv = - (struct compat_timeval __user *) userstamp; - int err = -ENOENT; + struct compat_timeval __user *ctv; + int err; struct timeval tv; + if (COMPAT_USE_64BIT_TIME) + return sock_get_timestamp(sk, userstamp); + + ctv = (struct compat_timeval __user *) userstamp; + err = -ENOENT; if (!sock_flag(sk, SOCK_TIMESTAMP)) sock_enable_timestamp(sk, SOCK_TIMESTAMP); tv = ktime_to_timeval(sk->sk_stamp); @@ -478,11 +484,15 @@ EXPORT_SYMBOL(compat_sock_get_timestamp); int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp) { - struct compat_timespec __user *ctv = - (struct compat_timespec __user *) userstamp; - int err = -ENOENT; + struct compat_timespec __user *ctv; + int err; struct timespec ts; + if (COMPAT_USE_64BIT_TIME) + return sock_get_timestampns (sk, userstamp); + + ctv = (struct compat_timespec __user *) userstamp; + err = -ENOENT; if (!sock_flag(sk, SOCK_TIMESTAMP)) sock_enable_timestamp(sk, SOCK_TIMESTAMP); ts = ktime_to_timespec(sk->sk_stamp); @@ -767,6 +777,11 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, int datagrams; struct timespec ktspec; + if (COMPAT_USE_64BIT_TIME) + return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, + flags | MSG_CMSG_COMPAT, + (struct timespec *) timeout); + if (timeout == NULL) return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, flags | MSG_CMSG_COMPAT, NULL); -- cgit v1.2.3-70-g09d2 From 644595f89620ba8446cc555be336d24a34464950 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 19 Feb 2012 17:51:59 -0800 Subject: compat: Handle COMPAT_USE_64BIT_TIME in net/socket.c Use helper functions aware of COMPAT_USE_64BIT_TIME to write struct timeval and struct timespec to userspace in net/socket.c. Signed-off-by: H. Peter Anvin --- net/socket.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index 28a96af484b..5325d4c797c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2600,7 +2600,7 @@ void socket_seq_show(struct seq_file *seq) #ifdef CONFIG_COMPAT static int do_siocgstamp(struct net *net, struct socket *sock, - unsigned int cmd, struct compat_timeval __user *up) + unsigned int cmd, void __user *up) { mm_segment_t old_fs = get_fs(); struct timeval ktv; @@ -2609,15 +2609,14 @@ static int do_siocgstamp(struct net *net, struct socket *sock, set_fs(KERNEL_DS); err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); set_fs(old_fs); - if (!err) { - err = put_user(ktv.tv_sec, &up->tv_sec); - err |= __put_user(ktv.tv_usec, &up->tv_usec); - } + if (!err) + err = compat_put_timeval(up, &ktv); + return err; } static int do_siocgstampns(struct net *net, struct socket *sock, - unsigned int cmd, struct compat_timespec __user *up) + unsigned int cmd, void __user *up) { mm_segment_t old_fs = get_fs(); struct timespec kts; @@ -2626,10 +2625,9 @@ static int do_siocgstampns(struct net *net, struct socket *sock, set_fs(KERNEL_DS); err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); set_fs(old_fs); - if (!err) { - err = put_user(kts.tv_sec, &up->tv_sec); - err |= __put_user(kts.tv_nsec, &up->tv_nsec); - } + if (!err) + err = compat_put_timespec(up, &kts); + return err; } -- cgit v1.2.3-70-g09d2 From cd82e61c110a36e398323e422896fcfe05879fed Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 20:34:38 +0100 Subject: Bluetooth: Add support for HCI monitor channel The HCI monitor channel can be used to monitor all packets and events from the Bluetooth subsystem. The monitor is not bound to any specific HCI device and allows even capturing multiple devices at the same time. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/hci_mon.h | 51 ++++++++++ net/bluetooth/hci_core.c | 13 ++- net/bluetooth/hci_sock.c | 207 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 include/net/bluetooth/hci_mon.h (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 1b634e12687..60a4727be93 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1320,6 +1320,7 @@ struct sockaddr_hci { #define HCI_CHANNEL_RAW 0 #define HCI_CHANNEL_CONTROL 1 +#define HCI_CHANNEL_MONITOR 2 struct hci_filter { unsigned long type_mask; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 41adae509e9..094b5dbdb13 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -950,6 +950,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); +void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); void hci_sock_dev_event(struct hci_dev *hdev, int event); diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h new file mode 100644 index 00000000000..07a25c92502 --- /dev/null +++ b/include/net/bluetooth/hci_mon.h @@ -0,0 +1,51 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + + Copyright (C) 2011-2012 Intel Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_MON_H +#define __HCI_MON_H + +struct hci_mon_hdr { + __le16 opcode; + __le16 index; + __le16 len; +} __packed; +#define HCI_MON_HDR_SIZE 6 + +#define HCI_MON_NEW_INDEX 0 +#define HCI_MON_DEL_INDEX 1 +#define HCI_MON_COMMAND_PKT 2 +#define HCI_MON_EVENT_PKT 3 +#define HCI_MON_ACL_TX_PKT 4 +#define HCI_MON_ACL_RX_PKT 5 +#define HCI_MON_SCO_TX_PKT 6 +#define HCI_MON_SCO_RX_PKT 7 + +struct hci_mon_new_index { + __u8 type; + __u8 bus; + bdaddr_t bdaddr; + char name[8]; +} __packed; +#define HCI_MON_NEW_INDEX_SIZE 16 + +#endif /* __HCI_MON_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 47217281d9a..87ff7ffdb36 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2113,10 +2113,14 @@ static int hci_send_frame(struct sk_buff *skb) BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); - if (atomic_read(&hdev->promisc)) { - /* Time stamp */ - __net_timestamp(skb); + /* Time stamp */ + __net_timestamp(skb); + /* Send copy to monitor */ + hci_send_to_monitor(hdev, skb); + + if (atomic_read(&hdev->promisc)) { + /* Send copy to the sockets */ hci_send_to_sock(hdev, skb); } @@ -2802,6 +2806,9 @@ static void hci_rx_work(struct work_struct *work) BT_DBG("%s", hdev->name); while ((skb = skb_dequeue(&hdev->rx_q))) { + /* Send copy to monitor */ + hci_send_to_monitor(hdev, skb); + if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ hci_send_to_sock(hdev, skb); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 14727cb43f6..213697d2377 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -48,9 +48,12 @@ #include #include +#include static bool enable_mgmt; +static atomic_t monitor_promisc = ATOMIC_INIT(0); + /* ----- HCI socket interface ----- */ static inline int hci_test_bit(int nr, void *addr) @@ -189,6 +192,174 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) read_unlock(&hci_sk_list.lock); } +/* Send frame to monitor socket */ +void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + struct sk_buff *skb_copy = NULL; + __le16 opcode; + + if (!atomic_read(&monitor_promisc)) + return; + + BT_DBG("hdev %p len %d", hdev, skb->len); + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT); + break; + case HCI_EVENT_PKT: + opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT); + break; + case HCI_ACLDATA_PKT: + if (bt_cb(skb)->incoming) + opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT); + else + opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT); + break; + case HCI_SCODATA_PKT: + if (bt_cb(skb)->incoming) + opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT); + else + opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT); + break; + default: + return; + } + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR) + continue; + + if (!skb_copy) { + struct hci_mon_hdr *hdr; + + /* Create a private copy with headroom */ + skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC); + if (!skb_copy) + continue; + + /* Put header before the data */ + hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE); + hdr->opcode = opcode; + hdr->index = cpu_to_le16(hdev->id); + hdr->len = cpu_to_le16(skb->len); + } + + nskb = skb_clone(skb_copy, GFP_ATOMIC); + if (!nskb) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); + + kfree_skb(skb_copy); +} + +static void send_monitor_event(struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + + BT_DBG("len %d", skb->len); + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR) + continue; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); +} + +static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) +{ + struct hci_mon_hdr *hdr; + struct hci_mon_new_index *ni; + struct sk_buff *skb; + __le16 opcode; + + switch (event) { + case HCI_DEV_REG: + skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC); + if (!skb) + return NULL; + + ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE); + ni->type = hdev->dev_type; + ni->bus = hdev->bus; + bacpy(&ni->bdaddr, &hdev->bdaddr); + memcpy(ni->name, hdev->name, 8); + + opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX); + break; + + case HCI_DEV_UNREG: + skb = bt_skb_alloc(0, GFP_ATOMIC); + if (!skb) + return NULL; + + opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX); + break; + + default: + return NULL; + } + + __net_timestamp(skb); + + hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE); + hdr->opcode = opcode; + hdr->index = cpu_to_le16(hdev->id); + hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); + + return skb; +} + +static void send_monitor_replay(struct sock *sk) +{ + struct hci_dev *hdev; + + read_lock(&hci_dev_list_lock); + + list_for_each_entry(hdev, &hci_dev_list, list) { + struct sk_buff *skb; + + skb = create_monitor_event(hdev, HCI_DEV_REG); + if (!skb) + continue; + + if (sock_queue_rcv_skb(sk, skb)) + kfree_skb(skb); + } + + read_unlock(&hci_dev_list_lock); +} + /* Generate internal stack event */ static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) { @@ -223,6 +394,17 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) BT_DBG("hdev %s event %d", hdev->name, event); + /* Send event to monitor */ + if (atomic_read(&monitor_promisc)) { + struct sk_buff *skb; + + skb = create_monitor_event(hdev, event); + if (skb) { + send_monitor_event(skb); + kfree_skb(skb); + } + } + /* Send event to sockets */ ev.event = event; ev.dev_id = hdev->id; @@ -262,6 +444,9 @@ static int hci_sock_release(struct socket *sock) hdev = hci_pi(sk)->hdev; + if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR) + atomic_dec(&monitor_promisc); + bt_sock_unlink(&hci_sk_list, sk); if (hdev) { @@ -474,6 +659,22 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; + case HCI_CHANNEL_MONITOR: + if (haddr.hci_dev != HCI_DEV_NONE) { + err = -EINVAL; + goto done; + } + + if (!capable(CAP_NET_RAW)) { + err = -EPERM; + goto done; + } + + send_monitor_replay(sk); + + atomic_inc(&monitor_promisc); + break; + default: err = -EINVAL; goto done; @@ -578,6 +779,9 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_RAW: hci_sock_cmsg(sk, msg, skb); break; + case HCI_CHANNEL_MONITOR: + sock_recv_timestamp(msg, sk, skb); + break; } skb_free_datagram(sk, skb); @@ -612,6 +816,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_CONTROL: err = mgmt_control(sk, msg, len); goto done; + case HCI_CHANNEL_MONITOR: + err = -EOPNOTSUPP; + goto done; default: err = -EINVAL; goto done; -- cgit v1.2.3-70-g09d2 From 801f13bd8ecc58f2cf42ec602a2b5db10fc5a132 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 20:54:10 +0100 Subject: Bluetooth: Restrict access to management interface The management interface on the HCI control channel should be restricted to applications with CAP_NET_ADMIN permission. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 213697d2377..8c429a179aa 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -656,6 +656,11 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } + if (!capable(CAP_NET_ADMIN)) { + err = -EPERM; + goto done; + } + set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; -- cgit v1.2.3-70-g09d2 From d7b7e79688c07b445bc52adfedf9a176be156f4b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 21:47:49 +0100 Subject: Bluetooth: Set supported settings based on enabled HS and/or LE Since neither High Speed (HS) nor Low Energy (LE) are fully implemented yet, only expose them in supported settings when enabled. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 5 ----- net/bluetooth/hci_event.c | 5 ----- net/bluetooth/mgmt.c | 18 ++++++++++++++++-- 4 files changed, 17 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 60a4727be93..ad5e94c757e 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1422,5 +1422,6 @@ struct hci_inquiry_req { #define IREQ_CACHE_FLUSH 0x0001 extern bool enable_hs; +extern bool enable_le; #endif /* __HCI_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 87ff7ffdb36..cc52e037440 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -54,8 +54,6 @@ #define AUTO_OFF_TIMEOUT 2000 -bool enable_hs; - static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work); @@ -2913,6 +2911,3 @@ int hci_cancel_inquiry(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); } - -module_param(enable_hs, bool, 0644); -MODULE_PARM_DESC(enable_hs, "Enable High Speed"); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f00faf0ac32..5d0f92a948c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -44,8 +44,6 @@ #include #include -static bool enable_le; - /* Handle HCI Event packets */ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) @@ -3545,6 +3543,3 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb); hdev->stat.evt_rx++; } - -module_param(enable_le, bool, 0644); -MODULE_PARM_DESC(enable_le, "Enable LE support"); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bc71b45ef4e..f7c2969d882 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -34,6 +34,9 @@ #include #include +bool enable_hs; +bool enable_le; + #define MGMT_VERSION 1 #define MGMT_REVISION 0 @@ -374,8 +377,13 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_LINK_SECURITY; } - if (hdev->features[4] & LMP_LE) - settings |= MGMT_SETTING_LE; + if (enable_hs) + settings |= MGMT_SETTING_HS; + + if (enable_le) { + if (hdev->features[4] & LMP_LE) + settings |= MGMT_SETTING_LE; + } return settings; } @@ -3421,3 +3429,9 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); } + +module_param(enable_hs, bool, 0644); +MODULE_PARM_DESC(enable_hs, "Enable High Speed support"); + +module_param(enable_le, bool, 0644); +MODULE_PARM_DESC(enable_le, "Enable Low Energy support"); -- cgit v1.2.3-70-g09d2 From 4b95a24ce12c4545fd7d2e3075841dc3119d1d71 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 21:24:37 +0100 Subject: Bluetooth: Always enable management interface The management interface API has reached stable version 1.0 and thus it can now be always enabled. All future changes will be made backwards compatible. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 8c429a179aa..dd563506414 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -50,8 +50,6 @@ #include #include -static bool enable_mgmt; - static atomic_t monitor_promisc = ATOMIC_INIT(0); /* ----- HCI socket interface ----- */ @@ -651,7 +649,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le break; case HCI_CHANNEL_CONTROL: - if (haddr.hci_dev != HCI_DEV_NONE || !enable_mgmt) { + if (haddr.hci_dev != HCI_DEV_NONE) { err = -EINVAL; goto done; } @@ -1129,6 +1127,3 @@ void hci_sock_cleanup(void) proto_unregister(&hci_sk_proto); } - -module_param(enable_mgmt, bool, 0644); -MODULE_PARM_DESC(enable_mgmt, "Enable Management interface"); -- cgit v1.2.3-70-g09d2 From d930650b59be72342bc373ef52006ca99c1dd09e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:25:18 +0200 Subject: Bluetooth: mgmt: Add address type parameter to Stop Discovery command This patch adds an address type parameter to the Stop Discovery command which should match the value given to Start Discovery. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 3 +++ net/bluetooth/mgmt.c | 33 ++++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 7e3d38bfaec..870a3deab6e 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -283,6 +283,9 @@ struct mgmt_cp_start_discovery { } __packed; #define MGMT_OP_STOP_DISCOVERY 0x0024 +struct mgmt_cp_stop_discovery { + __u8 type; +} __packed; #define MGMT_OP_CONFIRM_NAME 0x0025 struct mgmt_cp_confirm_name { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f7c2969d882..3db8525b029 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2281,8 +2281,9 @@ failed: return err; } -static int stop_discovery(struct sock *sk, u16 index) +static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) { + struct mgmt_cp_stop_discovery *mgmt_cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; struct hci_cp_remote_name_req_cancel cp; @@ -2291,6 +2292,10 @@ static int stop_discovery(struct sock *sk, u16 index) BT_DBG("hci%u", index); + if (len != sizeof(*mgmt_cp)) + return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_INVALID_PARAMS); + hdev = hci_dev_get(index); if (!hdev) return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, @@ -2299,8 +2304,16 @@ static int stop_discovery(struct sock *sk, u16 index) hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { - err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_REJECTED); + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_REJECTED, + &mgmt_cp->type, sizeof(mgmt_cp->type)); + goto unlock; + } + + if (hdev->discovery.type != mgmt_cp->type) { + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_INVALID_PARAMS, + &mgmt_cp->type, sizeof(mgmt_cp->type)); goto unlock; } @@ -2323,7 +2336,7 @@ static int stop_discovery(struct sock *sk, u16 index) if (!e) { mgmt_pending_remove(cmd); err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0, - NULL, 0); + &mgmt_cp->type, sizeof(mgmt_cp->type)); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; } @@ -2706,7 +2719,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = start_discovery(sk, index, cp, len); break; case MGMT_OP_STOP_DISCOVERY: - err = stop_discovery(sk, index); + err = stop_discovery(sk, index, cp, len); break; case MGMT_OP_CONFIRM_NAME: err = confirm_name(sk, index, cp, len); @@ -3369,7 +3382,9 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status) if (!cmd) return -ENOENT; - err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status)); + err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), + &hdev->discovery.type, + sizeof(hdev->discovery.type)); mgmt_pending_remove(cmd); return err; @@ -3389,12 +3404,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) if (cmd != NULL) { u8 type = hdev->discovery.type; - if (discovering) - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type, sizeof(type)); - else - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, - NULL, 0); mgmt_pending_remove(cmd); } -- cgit v1.2.3-70-g09d2 From f963e8e9d3652f4a8065d969206707a1c21ff9b0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:30:44 +0200 Subject: Bluetooth: mgmt: Add address type parameter to Discovering event This patch adds an address type parameter to the Discovering event. The value matches that given to Start/Stop Discovery. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 4 ++++ net/bluetooth/hci_core.c | 3 +-- net/bluetooth/mgmt.c | 8 ++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 870a3deab6e..1dbadbe1478 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -402,6 +402,10 @@ struct mgmt_ev_device_found { } __packed; #define MGMT_EV_DISCOVERING 0x0013 +struct mgmt_ev_discovering { + __u8 type; + __u8 discovering; +} __packed; #define MGMT_EV_DEVICE_BLOCKED 0x0014 struct mgmt_ev_device_blocked { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cc52e037440..a7439aeb1f9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -363,10 +363,9 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) switch (state) { case DISCOVERY_STOPPED: - hdev->discovery.type = 0; - if (hdev->discovery.state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); + hdev->discovery.type = 0; break; case DISCOVERY_STARTING: break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3db8525b029..86148b18289 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3392,6 +3392,7 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status) int mgmt_discovering(struct hci_dev *hdev, u8 discovering) { + struct mgmt_ev_discovering ev; struct pending_cmd *cmd; BT_DBG("%s discovering %u", hdev->name, discovering); @@ -3409,8 +3410,11 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) mgmt_pending_remove(cmd); } - return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering, - sizeof(discovering), NULL); + memset(&ev, 0, sizeof(ev)); + ev.type = hdev->discovery.type; + ev.discovering = discovering; + + return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); } int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) -- cgit v1.2.3-70-g09d2 From 6d80dfd094a7b286e95cdcac79efeb7bbb4e226f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:50:38 +0200 Subject: Bluetooth: mgmt: Add basic support for Set High Speed command This patch adds rudimentary support for the Set High Speed command in the form of a new HCI dev flag (HCI_HS_ENABLED). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/mgmt.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ad5e94c757e..ec370494e56 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -95,6 +95,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, + HCI_HS_ENABLED, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 86148b18289..edf84c3e6a2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -418,6 +418,9 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_SSP; + if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags)) + settings |= MGMT_SETTING_HS; + return settings; } @@ -1093,6 +1096,41 @@ failed: return err; } +static int set_hs(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct hci_dev *hdev; + int err; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_HS, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_HS, + MGMT_STATUS_INVALID_PARAMS); + + if (!enable_hs) { + err = cmd_status(sk, index, MGMT_OP_SET_HS, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + + if (cp->val) + set_bit(HCI_HS_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_HS_ENABLED, &hdev->dev_flags); + + err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); + +failed: + hci_dev_put(hdev); + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2655,6 +2693,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_SSP: err = set_ssp(sk, index, cp, len); break; + case MGMT_OP_SET_HS: + err = set_hs(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; -- cgit v1.2.3-70-g09d2 From 1e16357480fdeaeff7c5572f1afba7835473fcb6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:53:46 +0200 Subject: Bluetooth: mgmt: Fix Set SSP check for supported feature If the local controller doesn't support SSP we should always return an error for the Set SSP command. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index edf84c3e6a2..aa0d64040fa 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1065,6 +1065,12 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) goto failed; } + if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); goto failed; -- cgit v1.2.3-70-g09d2 From cacaf52f51697f832a26e8fdaa7b8e85785085da Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 00:52:42 +0200 Subject: Bluetooth: mgmt: Clear EIR data when disabling SSP EIR shouldn't be enabled if SSP isn't enabled. This patch adds the clearing of EIR data when disabling SSP and restores the data when SSP is re-enabled. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index aa0d64040fa..a5a2a6844ae 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3250,6 +3250,18 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) return err; } +static int clear_eir(struct hci_dev *hdev) +{ + struct hci_cp_write_eir cp; + + if (!(hdev->features[6] & LMP_EXT_INQ)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); +} + int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; @@ -3268,9 +3280,15 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) ev = cpu_to_le32(get_current_settings(hdev)); err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); - if (match.sk) + if (match.sk) { sock_put(match.sk); + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + update_eir(hdev); + else + clear_eir(hdev); + } + return err; } -- cgit v1.2.3-70-g09d2 From f0d4b78a68c4fe3b0d45de9a50e8d29419177b83 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 21 Feb 2012 12:14:25 +0100 Subject: Bluetooth: Only keep controller up after init if powered on When a new controller gets added to the system, it needs to be brought up briefly to read basic information like features, BD_ADDR etc. and after a timeout it will be brought back down. The only command that should overwrite this timeout is the set power command from the management interface. Just reading the controller list or information is not a good reason to keep the controller up. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a5a2a6844ae..c25cb648059 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -339,9 +339,6 @@ static int read_index_list(struct sock *sk) i = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags)) - cancel_delayed_work(&d->power_off); - if (test_bit(HCI_SETUP, &d->dev_flags)) continue; @@ -392,11 +389,12 @@ static u32 get_current_settings(struct hci_dev *hdev) { u32 settings = 0; - if (test_bit(HCI_UP, &hdev->flags)) - settings |= MGMT_SETTING_POWERED; - else + if (!test_bit(HCI_UP, &hdev->flags)) return settings; + if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + settings |= MGMT_SETTING_POWERED; + if (test_bit(HCI_PSCAN, &hdev->flags)) settings |= MGMT_SETTING_CONNECTABLE; @@ -623,9 +621,6 @@ static int read_controller_info(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_INFO, MGMT_STATUS_INVALID_PARAMS); - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work_sync(&hdev->power_off); - hci_dev_lock(hdev); if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) @@ -753,6 +748,16 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { + cancel_delayed_work(&hdev->power_off); + + if (cp->val) { + err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); + mgmt_powered(hdev, 1); + goto failed; + } + } + up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); -- cgit v1.2.3-70-g09d2 From 8ee5654034c85b3915d078147a9d1064cac1852e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 21 Feb 2012 12:33:48 +0100 Subject: Bluetooth: Don't send New Settings event during setup power down When the controller gets brought up for initial setup, it will be brought back down after a timeout. In that case, don't send a New Settings event. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a7439aeb1f9..a787c9c9d4c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -739,9 +739,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->discov_timeout = 0; } - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work(&hdev->power_off); - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) cancel_delayed_work(&hdev->service_cache); @@ -787,9 +784,11 @@ static int hci_dev_do_close(struct hci_dev *hdev) * and no tasks are scheduled. */ hdev->close(hdev); - hci_dev_lock(hdev); - mgmt_powered(hdev, 0); - hci_dev_unlock(hdev); + if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { + hci_dev_lock(hdev); + mgmt_powered(hdev, 0); + hci_dev_unlock(hdev); + } /* Clear flags */ hdev->flags = 0; @@ -808,7 +807,12 @@ int hci_dev_close(__u16 dev) hdev = hci_dev_get(dev); if (!hdev) return -ENODEV; + + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + cancel_delayed_work(&hdev->power_off); + err = hci_dev_do_close(hdev); + hci_dev_put(hdev); return err; } @@ -1102,9 +1106,7 @@ static void hci_power_off(struct work_struct *work) BT_DBG("%s", hdev->name); - clear_bit(HCI_AUTO_OFF, &hdev->dev_flags); - - hci_dev_close(hdev->id); + hci_dev_do_close(hdev); } static void hci_discov_off(struct work_struct *work) -- cgit v1.2.3-70-g09d2 From 4b34ee782164fbaf29b2e7c0e8cb3a898c0986ca Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 14:13:02 +0200 Subject: Bluetooth: mgmt: Fix powered checks for commands Having the HCI_AUTO_OFF flag set means that from a mgmt interface perspective we're still not powered, so all tests for HCI_UP should also include a test for HCI_AUTO_OFF. This patch adds a convenience macro for it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c25cb648059..c27481c3c95 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -118,6 +118,9 @@ static const u16 mgmt_events[] = { #define SERVICE_CACHE_TIMEOUT (5 * 1000) +#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ + !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + struct pending_cmd { struct list_head list; u16 opcode; @@ -733,7 +736,7 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_mode *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; - int err, up; + int err; BT_DBG("request for hci%u", index); @@ -758,8 +761,7 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) } } - up = test_bit(HCI_UP, &hdev->flags); - if ((cp->val && up) || (!cp->val && !up)) { + if (!!cp->val == hdev_is_powered(hdev)) { err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); goto failed; } @@ -810,7 +812,7 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_NOT_POWERED); goto failed; @@ -877,7 +879,7 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1005,7 +1007,7 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1064,7 +1066,7 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1621,7 +1623,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1690,7 +1692,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1933,7 +1935,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED); goto done; } @@ -2109,7 +2111,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_NOT_POWERED); goto unlock; @@ -2280,7 +2282,7 @@ static int start_discovery(struct sock *sk, u16 index, hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, MGMT_STATUS_NOT_POWERED); goto failed; -- cgit v1.2.3-70-g09d2 From b5235a65ad19f47c5995f054d3dcce90570d1a1c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 14:32:24 +0200 Subject: Bluetooth: mgmt: Fix set_local_name and set_dev_class powered checks Both the Set Local Name and the Set Device Class commands should fail if the adapter is not powered on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c27481c3c95..03a13843cd1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1272,6 +1272,12 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -1288,6 +1294,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, NULL, 0); +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2076,6 +2083,12 @@ static int set_local_name(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, + MGMT_STATUS_NOT_POWERED); + goto failed; + } + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); if (!cmd) { -- cgit v1.2.3-70-g09d2 From 5400c044f3fac38f521362d76711e4c170f78b89 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 16:40:33 +0200 Subject: Bluetooth: mgmt: Fix set_fast_connectable error return This patch ensures that Set Fast Connectable fails apropriately if we are not already in a connectable state (which is a pre-requisite for fast connectable). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 03a13843cd1..563190c9f7b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2560,6 +2560,13 @@ static int set_fast_connectable(struct sock *sk, u16 index, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); + if (!hdev_is_powered(hdev)) + return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_NOT_POWERED); + + if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_REJECTED); hci_dev_lock(hdev); -- cgit v1.2.3-70-g09d2 From 0cbf4ed6e6f43ac399afefdd14a1ee86db8de7d0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 17:25:22 +0200 Subject: Bluetooth: mgmt: Fix pairable setting upon initialization When mgmt is not in use the HCI_PAIRABLE flag will get implicitly set so that pairing still works with old user space versions. However, as soon as mgmt comes into play we should clear this flag so that it can be properly set through the set_pairable command by user space. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 563190c9f7b..0f87030f9c3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -604,9 +604,17 @@ static void service_cache_off(struct work_struct *work) static void mgmt_init_hdev(struct hci_dev *hdev) { - if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) + if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) { INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + /* Non-mgmt controlled devices get this bit set + * implicitly so that pairing works for them, however + * for mgmt we require user-space to explicitly enable + * it + */ + clear_bit(HCI_PAIRABLE, &hdev->dev_flags); + } + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) schedule_delayed_work(&hdev->service_cache, msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); -- cgit v1.2.3-70-g09d2 From 4f9c8c1b091628a550b70ee51d7d729187f5c290 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 6 Jan 2012 17:06:11 -0800 Subject: ipv4: Convert call_rcu() to kfree_rcu(), drop opt_kfree_rcu() Because opt_kfree_rcu() just calls kfree(), all call_rcu() uses of it may be converted to kfree_rcu(). This permits opt_kfree_rcu() to be eliminated. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Acked-by: David S. Miller Cc: Alexey Kuznetsov Cc: James Morris Cc: Hideaki YOSHIFUJI Cc: Patrick McHardy Cc: netdev@vger.kernel.org --- net/ipv4/cipso_ipv4.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 86f3b885b4f..c48adc565e9 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1857,11 +1857,6 @@ static int cipso_v4_genopt(unsigned char *buf, u32 buf_len, return CIPSO_V4_HDR_LEN + ret_val; } -static void opt_kfree_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct ip_options_rcu, rcu)); -} - /** * cipso_v4_sock_setattr - Add a CIPSO option to a socket * @sk: the socket @@ -1938,7 +1933,7 @@ int cipso_v4_sock_setattr(struct sock *sk, } rcu_assign_pointer(sk_inet->inet_opt, opt); if (old) - call_rcu(&old->rcu, opt_kfree_rcu); + kfree_rcu(old, rcu); return 0; @@ -2005,7 +2000,7 @@ int cipso_v4_req_setattr(struct request_sock *req, req_inet = inet_rsk(req); opt = xchg(&req_inet->opt, opt); if (opt) - call_rcu(&opt->rcu, opt_kfree_rcu); + kfree_rcu(opt, rcu); return 0; @@ -2075,7 +2070,7 @@ static int cipso_v4_delopt(struct ip_options_rcu **opt_ptr) * remove the entire option struct */ *opt_ptr = NULL; hdr_delta = opt->opt.optlen; - call_rcu(&opt->rcu, opt_kfree_rcu); + kfree_rcu(opt, rcu); } return hdr_delta; -- cgit v1.2.3-70-g09d2 From 605b4afec8e51d0603089eac01a3ca9dd919e909 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 6 Jan 2012 17:08:33 -0800 Subject: ipv4: Convert call_rcu() to kfree_rcu(), drop opt_kfree_rcu The call_rcu() in do_ip_setsockopt() invokes opt_kfree_rcu(), which just calls kfree(). So convert the call_rcu() to kfree_rcu(), which allows opt_kfree_rcu() to be eliminated. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Acked-by: David S. Miller Cc: Alexey Kuznetsov Cc: James Morris Cc: Hideaki YOSHIFUJI Cc: Patrick McHardy Cc: netdev@vger.kernel.org --- net/ipv4/ip_sockglue.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 8aa87c19fa0..5343d9ac510 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -445,11 +445,6 @@ out: } -static void opt_kfree_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct ip_options_rcu, rcu)); -} - /* * Socket option code for IP. This is the end of the line after any * TCP,UDP etc options on an IP socket. @@ -525,7 +520,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, } rcu_assign_pointer(inet->inet_opt, opt); if (old) - call_rcu(&old->rcu, opt_kfree_rcu); + kfree_rcu(old, rcu); break; } case IP_PKTINFO: -- cgit v1.2.3-70-g09d2 From ae1f18e480c83d15539fb234a2dc5f0aa04cb119 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 6 Jan 2012 17:10:37 -0800 Subject: mac80211: Convert call_rcu() to kfree_rcu(), drop mesh_gate_node_reclaim() The call_rcu() in mesh_gate_del() invokes mesh_gate_node_reclaim(), which simply calls kfree(). So convert the call_rcu() to kfree_rcu(), allowing mesh_gate_node_reclaim() to be eliminated. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Cc: "John W. Linville" Cc: Johannes Berg Cc: "David S. Miller" Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org --- net/mac80211/mesh_pathtbl.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index edf167e3b8f..30420bc1f69 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -413,12 +413,6 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data return NULL; } -static void mesh_gate_node_reclaim(struct rcu_head *rp) -{ - struct mpath_node *node = container_of(rp, struct mpath_node, rcu); - kfree(node); -} - /** * mesh_path_add_gate - add the given mpath to a mesh gate to our path table * @mpath: gate path to add to table @@ -479,7 +473,7 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) if (gate->mpath == mpath) { spin_lock_bh(&tbl->gates_lock); hlist_del_rcu(&gate->list); - call_rcu(&gate->rcu, mesh_gate_node_reclaim); + kfree_rcu(gate, rcu); spin_unlock_bh(&tbl->gates_lock); mpath->sdata->u.mesh.num_gates--; mpath->is_gate = false; -- cgit v1.2.3-70-g09d2 From 5e5282bbfde9ca6157dba913d90cbab859a837e2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 16:01:30 +0200 Subject: Bluetooth: mgmt: Allow connectable/discoverable changes in off state This patch makes it possible to toggle the connectable & discoverable settings when powered off. Two new hdev->dev_flags flags are added to track what the scan mode should be when the device is finally powered on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 2 + net/bluetooth/hci_core.c | 1 + net/bluetooth/mgmt.c | 91 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 76 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ec370494e56..169d2f8cc4e 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -96,6 +96,8 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_HS_ENABLED, + HCI_CONNECTABLE, + HCI_DISCOVERABLE, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a787c9c9d4c..9d199494bd6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -737,6 +737,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (hdev->discov_timeout > 0) { cancel_delayed_work(&hdev->discov_off); hdev->discov_timeout = 0; + clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0f87030f9c3..6311be775ff 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -398,10 +398,10 @@ static u32 get_current_settings(struct hci_dev *hdev) if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) settings |= MGMT_SETTING_POWERED; - if (test_bit(HCI_PSCAN, &hdev->flags)) + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_CONNECTABLE; - if (test_bit(HCI_ISCAN, &hdev->flags)) + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_DISCOVERABLE; if (test_bit(HCI_PAIRABLE, &hdev->dev_flags)) @@ -804,6 +804,7 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_cp_set_discoverable *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; + u16 timeout; u8 scan; int err; @@ -818,9 +819,11 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); + timeout = get_unaligned_le16(&cp->timeout); + hci_dev_lock(hdev); - if (!hdev_is_powered(hdev)) { + if (!hdev_is_powered(hdev) && timeout > 0) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_NOT_POWERED); goto failed; @@ -833,8 +836,22 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) && - test_bit(HCI_PSCAN, &hdev->flags)) { + if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + MGMT_STATUS_REJECTED); + goto failed; + } + + if (!hdev_is_powered(hdev)) { + if (cp->val) + set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + else + clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); + goto failed; + } + + if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); goto failed; } @@ -857,7 +874,7 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) mgmt_pending_remove(cmd); if (cp->val) - hdev->discov_timeout = get_unaligned_le16(&cp->timeout); + hdev->discov_timeout = timeout; failed: hci_dev_unlock(hdev); @@ -888,8 +905,13 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_NOT_POWERED); + if (cp->val) + set_bit(HCI_CONNECTABLE, &hdev->dev_flags); + else { + clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); + clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + } + err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); goto failed; } @@ -900,7 +922,7 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { + if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); goto failed; } @@ -2881,9 +2903,22 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) __le32 ev; int err; + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + return 0; + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); - if (!powered) { + if (powered) { + u8 scan = 0; + + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + scan |= SCAN_PAGE; + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + scan |= SCAN_INQUIRY; + + if (scan) + hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + } else { u8 status = ENETDOWN; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); } @@ -2902,15 +2937,25 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; - int err; + bool changed = false; + int err = 0; mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); + if (discoverable) { + if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + changed = true; + } - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + if (changed) { + __le32 ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + } + if (match.sk) sock_put(match.sk); @@ -2919,16 +2964,26 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) int mgmt_connectable(struct hci_dev *hdev, u8 connectable) { - __le32 ev; struct cmd_lookup match = { NULL, hdev }; - int err; + bool changed = false; + int err = 0; mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); + if (connectable) { + if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + changed = true; + } - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + if (changed) { + __le32 ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + match.sk); + } if (match.sk) sock_put(match.sk); -- cgit v1.2.3-70-g09d2 From df2c6c5ed5c0bc13b78e855d3e5d9aa3472567ba Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 19:15:49 +0200 Subject: Bluetooth: mgmt: Fix Removing discoverable timeout in set_connectable When switching connectable mode off any pending discoverable timeout must also be disabled to avoid duplicate write_scan_enable commands. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6311be775ff..eec70a4ba36 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -935,9 +935,14 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) if (cp->val) scan = SCAN_PAGE; - else + else { scan = 0; + if (test_bit(HCI_ISCAN, &hdev->flags) && + hdev->discov_timeout > 0) + cancel_delayed_work(&hdev->discov_off); + } + err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); if (err < 0) mgmt_pending_remove(cmd); -- cgit v1.2.3-70-g09d2 From f1f0eb02213a3003ecb10b9c61694e588267b824 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 17:15:41 +0200 Subject: Bluetooth: mgmt: Fix current settings values when powered off We should not stop iterating through the various settings if powered off since most may still be set even then. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index eec70a4ba36..86e63a707f5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -392,10 +392,7 @@ static u32 get_current_settings(struct hci_dev *hdev) { u32 settings = 0; - if (!test_bit(HCI_UP, &hdev->flags)) - return settings; - - if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + if (hdev_is_powered(hdev)) settings |= MGMT_SETTING_POWERED; if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) -- cgit v1.2.3-70-g09d2 From beadb2bddce5810dc668da156b4c2ca457940250 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 16:55:31 +0200 Subject: Bluetooth: mgmt: Add convenience function for sending New Settings The New Settings event needs to be sent from quite many places so it makes sense to have a convenience function for it to simplify the code. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 96 ++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 52 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 86e63a707f5..439ec786ff8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -796,6 +796,42 @@ failed: return err; } +static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, + u16 data_len, struct sock *skip_sk) +{ + struct sk_buff *skb; + struct mgmt_hdr *hdr; + + skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (void *) skb_put(skb, sizeof(*hdr)); + hdr->opcode = cpu_to_le16(event); + if (hdev) + hdr->index = cpu_to_le16(hdev->id); + else + hdr->index = cpu_to_le16(MGMT_INDEX_NONE); + hdr->len = cpu_to_le16(data_len); + + if (data) + memcpy(skb_put(skb, data_len), data, data_len); + + hci_send_to_control(skb, skip_sk); + kfree_skb(skb); + + return 0; +} + +static int new_settings(struct hci_dev *hdev, struct sock *skip) +{ + __le32 ev; + + ev = cpu_to_le32(get_current_settings(hdev)); + + return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip); +} + static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_set_discoverable *cp = data; @@ -951,38 +987,10 @@ failed: return err; } -static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, - u16 data_len, struct sock *skip_sk) -{ - struct sk_buff *skb; - struct mgmt_hdr *hdr; - - skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = cpu_to_le16(event); - if (hdev) - hdr->index = cpu_to_le16(hdev->id); - else - hdr->index = cpu_to_le16(MGMT_INDEX_NONE); - hdr->len = cpu_to_le16(data_len); - - if (data) - memcpy(skb_put(skb, data_len), data, data_len); - - hci_send_to_control(skb, skip_sk); - kfree_skb(skb); - - return 0; -} - static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_mode *cp = data; struct hci_dev *hdev; - __le32 ev; int err; BT_DBG("request for hci%u", index); @@ -1007,9 +1015,7 @@ static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - ev = cpu_to_le32(get_current_settings(hdev)); - - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk); + err = new_settings(hdev, sk); failed: hci_dev_unlock(hdev); @@ -2902,7 +2908,6 @@ static void settings_rsp(struct pending_cmd *cmd, void *data) int mgmt_powered(struct hci_dev *hdev, u8 powered) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; int err; if (!test_bit(HCI_MGMT, &hdev->dev_flags)) @@ -2925,10 +2930,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); } - ev = cpu_to_le32(get_current_settings(hdev)); - - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), - match.sk); + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -2952,11 +2954,8 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) changed = true; } - if (changed) { - __le32 ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), - match.sk); - } + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -2981,11 +2980,8 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) changed = true; } - if (changed) { - __le32 ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), - match.sk); - } + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -3320,7 +3316,6 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; int err; if (status) { @@ -3333,8 +3328,7 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -3357,7 +3351,6 @@ static int clear_eir(struct hci_dev *hdev) int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; int err; if (status) { @@ -3369,8 +3362,7 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + err = new_settings(hdev, match.sk); if (match.sk) { sock_put(match.sk); -- cgit v1.2.3-70-g09d2 From 0224d2fafbbed4ac0cb05d08d3adab506a398451 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 19:40:05 +0200 Subject: Bluetooth: mgmt: Fix New Settings event for connectable/discoverable When powered off and doing changes to the Connectable or Discoverable setting we should also send an appropriate New Settings event in addition to the command response. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 439ec786ff8..08b867a4d0e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -876,11 +876,20 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) } if (!hdev_is_powered(hdev)) { - if (cp->val) - set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - else - clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + bool changed = false; + + if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { + change_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + changed = true; + } + err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } @@ -938,13 +947,25 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { + bool changed = false; + + if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + changed = true; + if (cp->val) set_bit(HCI_CONNECTABLE, &hdev->dev_flags); else { clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } + err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } -- cgit v1.2.3-70-g09d2 From a297e97cf7228467a8c5c76216945ccf029ae2a4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 17:55:47 +0200 Subject: Bluetooth: Fix clearing of persistent dev_flags Now that most flags are persistent, only the LE_SCAN flag should be cleared after a reset. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5d0f92a948c..2a5d05c05e3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -192,9 +192,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); - /* Reset all flags, except persistent ones */ - hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF) | - BIT(HCI_LINK_KEYS) | BIT(HCI_DEBUG_KEYS); + /* Reset all non-persistent flags */ + hdev->dev_flags &= ~(BIT(HCI_LE_SCAN)); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From ed9b5f2fa053adce8dac88a385d2225a8ac5f0b5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 20:47:06 +0200 Subject: Bluetooth: mgmt: Fix connectable/discoverable response values The connectable/discoverable flags need to be changed before sending the response since otherwise the settings value will be incorrect. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 08b867a4d0e..e8f890d7256 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2965,8 +2965,6 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) bool changed = false; int err = 0; - mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); - if (discoverable) { if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) changed = true; @@ -2975,6 +2973,9 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) changed = true; } + mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, + &match); + if (changed) err = new_settings(hdev, match.sk); @@ -2990,9 +2991,6 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) bool changed = false; int err = 0; - mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, - &match); - if (connectable) { if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags)) changed = true; @@ -3001,6 +2999,9 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) changed = true; } + mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, + &match); + if (changed) err = new_settings(hdev, match.sk); -- cgit v1.2.3-70-g09d2 From 8617b093d0031837a7be9b32bc674580cfb5f6b5 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 20 Feb 2012 10:05:31 +0530 Subject: mac80211: zero initialize count field in ieee80211_tx_rate rate control algorithms concludes the rate as invalid with rate[i].idx < -1 , while they do also check for rate[i].count is non-zero. it would be safer to zero initialize the 'count' field. recently we had a ath9k rate control crash where the ath9k rate control in ath_tx_status assumed to check only for rate[i].count being non-zero in one instance and ended up in using invalid rate index for 'connection monitoring NULL func frames' which eventually lead to the crash. thanks to Pavel Roskin for fixing it and finding the root cause. https://bugzilla.redhat.com/show_bug.cgi?id=768639 Cc: stable@vger.kernel.org Cc: Pavel Roskin Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- net/mac80211/rate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index ad64f4d5271..f9b8e819ca6 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -344,7 +344,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { info->control.rates[i].idx = -1; info->control.rates[i].flags = 0; - info->control.rates[i].count = 1; + info->control.rates[i].count = 0; } if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) -- cgit v1.2.3-70-g09d2 From 0dee00686da88cc32753e02e4e8efdd9e326e4d2 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 20 Feb 2012 14:44:01 +0530 Subject: mac80211: Fix a warning on changing to monitor mode from STA nothing needs to be done for monitor/AP_VLAN mode on calling ieee80211_bss_info_change_notify -> drv_bss_info_changed with the change flag 'BSS_CHANGED_IDLE'. 'wl1271' seems to use BSS_CHANGED_IDLE only for STA and IBSS mode. further the non-idle state of the monitor mode is taken care by the 'count' variable which counts non-idle interfaces. ieee80211_idle_off(local, "in use") will be called. this fixes the following WARNING when we have initially STA mode (network manager running) and not associated, and change it to monitor mode with network manager disabled and bringing up the monitor mode. this changes the idle state from 'true' (STA unassociated) to 'false' (MONITOR mode) exposed by the commit 405385f8ce7a2ed8f82e216d88b5282142e1288b "mac80211: set bss_conf.idle when vif is connected" WARNING: net/mac80211/main.c:212 ieee80211_bss_info_change_notify+0x1cf/0x330 [mac80211]() Hardware name: 64756D6 Pid: 3835, comm: ifconfig Tainted: G O 3.3.0-rc3-wl #9 Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? ieee80211_bss_info_change_notify+0x1cf/0x330 [mac80211] [] ? ieee80211_bss_info_change_notify+0x1cf/0x330 [mac80211] [] warn_slowpath_null+0x22/0x30 [] ieee80211_bss_info_change_notify+0x1cf/0x330 [mac80211] [] __ieee80211_recalc_idle+0x113/0x430 [mac80211] [] ieee80211_do_open+0x156/0x7e0 [mac80211] [] ? ieee80211_check_concurrent_iface+0x25/0x180 [mac80211] [] ? raw_notifier_call_chain+0x1f/0x30 [] ieee80211_open+0x40/0x80 [mac80211] [] __dev_open+0x96/0xe0 [] ? _raw_spin_unlock_bh+0x35/0x40 [] __dev_change_flags+0x109/0x170 [] dev_change_flags+0x23/0x60 [] devinet_ioctl+0x6a0/0x770 ieee80211 phy0: device no longer idle - in use Cc: Eliad Peller Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- net/mac80211/iface.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 01a21c2f6ab..8e2137bd87e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1332,6 +1332,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) hw_roc = true; list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + continue; if (sdata->old_idle == sdata->vif.bss_conf.idle) continue; if (!ieee80211_sdata_running(sdata)) -- cgit v1.2.3-70-g09d2 From 4934b0329f7150dcb5f90506860e2db32274c755 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 21 Feb 2012 07:30:33 +0000 Subject: datagram: Factor out sk queue referencing This makes lines shorter and simplifies further patching. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/datagram.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/core/datagram.c b/net/core/datagram.c index 68bbf9f65cb..6f54d0a17f8 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -180,18 +180,19 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, * However, this function was correct in any case. 8) */ unsigned long cpu_flags; + struct sk_buff_head *queue = &sk->sk_receive_queue; - spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); - skb = skb_peek(&sk->sk_receive_queue); + spin_lock_irqsave(&queue->lock, cpu_flags); + skb = skb_peek(queue); if (skb) { *peeked = skb->peeked; if (flags & MSG_PEEK) { skb->peeked = 1; atomic_inc(&skb->users); } else - __skb_unlink(skb, &sk->sk_receive_queue); + __skb_unlink(skb, queue); } - spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); + spin_unlock_irqrestore(&queue->lock, cpu_flags); if (skb) return skb; -- cgit v1.2.3-70-g09d2 From 3f518bf745cbd6007d8069100fb9cb09e960c872 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 21 Feb 2012 07:30:58 +0000 Subject: datagram: Add offset argument to __skb_recv_datagram This one is only considered for MSG_PEEK flag and the value pointed by it specifies where to start peeking bytes from. If the offset happens to point into the middle of the returned skb, the offset within this skb is put back to this very argument. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 +- net/core/datagram.c | 21 +++++++++++++-------- net/ipv4/udp.c | 4 ++-- net/ipv6/udp.c | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2b7317ff297..f3cf43de3c2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2046,7 +2046,7 @@ static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag) for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, - int *peeked, int *err); + int *peeked, int *off, int *err); extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err); extern unsigned int datagram_poll(struct file *file, struct socket *sock, diff --git a/net/core/datagram.c b/net/core/datagram.c index 6f54d0a17f8..d3cf12f62c8 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -132,6 +132,8 @@ out_noerr: * __skb_recv_datagram - Receive a datagram skbuff * @sk: socket * @flags: MSG_ flags + * @off: an offset in bytes to peek skb from. Returns an offset + * within an skb where data actually starts * @peeked: returns non-zero if this packet has been seen before * @err: error code returned * @@ -158,7 +160,7 @@ out_noerr: * the standard around please. */ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, - int *peeked, int *err) + int *peeked, int *off, int *err) { struct sk_buff *skb; long timeo; @@ -183,19 +185,22 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, struct sk_buff_head *queue = &sk->sk_receive_queue; spin_lock_irqsave(&queue->lock, cpu_flags); - skb = skb_peek(queue); - if (skb) { + skb_queue_walk(queue, skb) { *peeked = skb->peeked; if (flags & MSG_PEEK) { + if (*off >= skb->len) { + *off -= skb->len; + continue; + } skb->peeked = 1; atomic_inc(&skb->users); } else __skb_unlink(skb, queue); - } - spin_unlock_irqrestore(&queue->lock, cpu_flags); - if (skb) + spin_unlock_irqrestore(&queue->lock, cpu_flags); return skb; + } + spin_unlock_irqrestore(&queue->lock, cpu_flags); /* User doesn't want to wait */ error = -EAGAIN; @@ -215,10 +220,10 @@ EXPORT_SYMBOL(__skb_recv_datagram); struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err) { - int peeked; + int peeked, off = 0; return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, err); + &peeked, &off, err); } EXPORT_SYMBOL(skb_recv_datagram); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index cd99f1a0f59..7c41ab84e72 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1167,7 +1167,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; unsigned int ulen, copied; - int peeked; + int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); bool slow; @@ -1183,7 +1183,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, try_again: skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); + &peeked, &off, &err); if (!skb) goto out; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8aebf8f9043..37b0699e95e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -342,7 +342,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct inet_sock *inet = inet_sk(sk); struct sk_buff *skb; unsigned int ulen, copied; - int peeked; + int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); int is_udp4; @@ -359,7 +359,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, try_again: skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); + &peeked, &off, &err); if (!skb) goto out; -- cgit v1.2.3-70-g09d2 From ef64a54f6e558155b4f149bb10666b9e914b6c54 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 21 Feb 2012 07:31:34 +0000 Subject: sock: Introduce the SO_PEEK_OFF sock option This one specifies where to start MSG_PEEK-ing queue data from. When set to negative value means that MSG_PEEK works as ususally -- peeks from the head of the queue always. When some bytes are peeked from queue and the peeking offset is non negative it is moved forward so that the next peek will return next portion of data. When non-peeking recvmsg occurs and the peeking offset is non negative is is moved backward so that the next peek will still peek the proper data (i.e. the one that would have been picked if there were no non peeking recv in between). The offset is set using per-proto opteration to let the protocol handle the locking issues and to check whether the peeking offset feature is supported by the protocol the socket belongs to. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- arch/alpha/include/asm/socket.h | 1 + arch/arm/include/asm/socket.h | 1 + arch/avr32/include/asm/socket.h | 1 + arch/cris/include/asm/socket.h | 1 + arch/frv/include/asm/socket.h | 1 + arch/h8300/include/asm/socket.h | 1 + arch/ia64/include/asm/socket.h | 1 + arch/m32r/include/asm/socket.h | 1 + arch/m68k/include/asm/socket.h | 1 + arch/mips/include/asm/socket.h | 1 + arch/mn10300/include/asm/socket.h | 1 + arch/parisc/include/asm/socket.h | 1 + arch/powerpc/include/asm/socket.h | 1 + arch/s390/include/asm/socket.h | 1 + arch/sparc/include/asm/socket.h | 1 + arch/xtensa/include/asm/socket.h | 1 + include/asm-generic/socket.h | 1 + include/linux/net.h | 1 + include/net/sock.h | 25 +++++++++++++++++++++++++ net/core/sock.c | 13 +++++++++++++ 20 files changed, 56 insertions(+) (limited to 'net') diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 082355f159e..16449d330da 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -71,6 +71,7 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index dec6f9afb3c..d958c74e526 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index 247b88c760b..30078f98b3a 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index e269264df7c..048aba64600 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -66,6 +66,7 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index ce80fdadcce..7a361810f3c 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -64,6 +64,7 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index cf1daab6f27..e7bbfcee5b9 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 4b03664e3fb..ced62de9d5a 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -73,5 +73,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index e8b8c5bb053..696cb4c7ca4 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index d4708ce466e..e8b41a6775f 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index ad5c0a7a02a..52104872e9e 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -84,6 +84,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #ifdef __KERNEL__ diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 876356d7852..013fcc51698 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index d28c51b6106..f717c9bec16 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -63,6 +63,7 @@ #define SO_WIFI_STATUS 0x4022 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 0x4023 /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 2fc2af8fbf5..fe1c0b478fd 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -71,5 +71,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index 67b5c1b14b5..581702fa1b0 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -72,5 +72,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 8af1b64168b..68e2e2746f6 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -60,6 +60,7 @@ #define SO_WIFI_STATUS 0x0025 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 0x0026 /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index bb06968be22..74818b16136 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -75,5 +75,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _XTENSA_SOCKET_H */ diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h index 49c1704173e..d9aaac0c36d 100644 --- a/include/asm-generic/socket.h +++ b/include/asm-generic/socket.h @@ -67,4 +67,5 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/include/linux/net.h b/include/linux/net.h index b29923006b1..be60c7f5e14 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -206,6 +206,7 @@ struct proto_ops { int offset, size_t size, int flags); ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); + void (*set_peek_off)(struct sock *sk, int val); }; #define DECLARE_SOCKADDR(type, dst, src) \ diff --git a/include/net/sock.h b/include/net/sock.h index 91c1c8baf02..9c0553b9e45 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -357,6 +357,7 @@ struct sock { struct page *sk_sndmsg_page; struct sk_buff *sk_send_head; __u32 sk_sndmsg_off; + __s32 sk_peek_off; int sk_write_pending; #ifdef CONFIG_SECURITY void *sk_security; @@ -373,6 +374,30 @@ struct sock { void (*sk_destruct)(struct sock *sk); }; +static inline int sk_peek_offset(struct sock *sk, int flags) +{ + if ((flags & MSG_PEEK) && (sk->sk_peek_off >= 0)) + return sk->sk_peek_off; + else + return 0; +} + +static inline void sk_peek_offset_bwd(struct sock *sk, int val) +{ + if (sk->sk_peek_off >= 0) { + if (sk->sk_peek_off >= val) + sk->sk_peek_off -= val; + else + sk->sk_peek_off = 0; + } +} + +static inline void sk_peek_offset_fwd(struct sock *sk, int val) +{ + if (sk->sk_peek_off >= 0) + sk->sk_peek_off += val; +} + /* * Hashed lists helper routines */ diff --git a/net/core/sock.c b/net/core/sock.c index 02f8dfe320b..19942d4bb6e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -793,6 +793,12 @@ set_rcvbuf: sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool); break; + case SO_PEEK_OFF: + if (sock->ops->set_peek_off) + sock->ops->set_peek_off(sk, val); + else + ret = -EOPNOTSUPP; + break; default: ret = -ENOPROTOOPT; break; @@ -1018,6 +1024,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = !!sock_flag(sk, SOCK_WIFI_STATUS); break; + case SO_PEEK_OFF: + if (!sock->ops->set_peek_off) + return -EOPNOTSUPP; + + v.val = sk->sk_peek_off; + break; default: return -ENOPROTOOPT; } @@ -2092,6 +2104,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_sndmsg_page = NULL; sk->sk_sndmsg_off = 0; + sk->sk_peek_off = -1; sk->sk_peer_pid = NULL; sk->sk_peer_cred = NULL; -- cgit v1.2.3-70-g09d2 From f55bb7f9cb82dec2f2e803d7bd0fc5929248e4d8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 21 Feb 2012 07:31:51 +0000 Subject: unix: Support peeking offset for datagram and seqpacket sockets The sk_peek_off manipulations are protected with the unix_sk->readlock mutex. This mutex is enough since all we need is to syncronize setting the offset vs reading the queue head. The latter is fully covered with the mentioned lock. The recently added __skb_recv_datagram's offset is used to pick the skb to read the data from. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/unix/af_unix.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 85d3bb7490a..3d9481de031 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -530,6 +530,16 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *, static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *, struct msghdr *, size_t, int); +static void unix_set_peek_off(struct sock *sk, int val) +{ + struct unix_sock *u = unix_sk(sk); + + mutex_lock(&u->readlock); + sk->sk_peek_off = val; + mutex_unlock(&u->readlock); +} + + static const struct proto_ops unix_stream_ops = { .family = PF_UNIX, .owner = THIS_MODULE, @@ -570,6 +580,7 @@ static const struct proto_ops unix_dgram_ops = { .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, }; static const struct proto_ops unix_seqpacket_ops = { @@ -591,6 +602,7 @@ static const struct proto_ops unix_seqpacket_ops = { .recvmsg = unix_seqpacket_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, }; static struct proto unix_proto = { @@ -1756,6 +1768,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, int noblock = flags & MSG_DONTWAIT; struct sk_buff *skb; int err; + int peeked, skip; err = -EOPNOTSUPP; if (flags&MSG_OOB) @@ -1769,7 +1782,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } - skb = skb_recv_datagram(sk, flags, noblock, &err); + skip = sk_peek_offset(sk, flags); + + skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err); if (!skb) { unix_state_lock(sk); /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ @@ -1786,12 +1801,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, if (msg->msg_name) unix_copy_addr(msg, skb->sk); - if (size > skb->len) - size = skb->len; - else if (size < skb->len) + if (size > skb->len - skip) + size = skb->len - skip; + else if (size < skb->len - skip) msg->msg_flags |= MSG_TRUNC; - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size); + err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size); if (err) goto out_free; @@ -1808,6 +1823,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, if (!(flags & MSG_PEEK)) { if (UNIXCB(skb).fp) unix_detach_fds(siocb->scm, skb); + + sk_peek_offset_bwd(sk, skb->len); } else { /* It is questionable: on PEEK we could: - do not return fds - good, but too simple 8) @@ -1821,6 +1838,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, clearly however! */ + + sk_peek_offset_fwd(sk, size); + if (UNIXCB(skb).fp) siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); } -- cgit v1.2.3-70-g09d2 From fc0d753641f7b919c7273d9bd21ae6ab45e757f3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 21 Feb 2012 07:32:06 +0000 Subject: unix: Support peeking offset for stream sockets The same here -- we can protect the sk_peek_off manipulations with the unix_sk->readlock mutex. The peeking of data from a stream socket is done in the datagram style, i.e. even if there's enough room for more data in the user buffer, only the head skb's data is copied in there. This feature is preserved when peeking data from a given offset -- the data is read till the nearest skb's boundary. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/unix/af_unix.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3d9481de031..0be4d24f6ae 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -559,6 +559,7 @@ static const struct proto_ops unix_stream_ops = { .recvmsg = unix_stream_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, }; static const struct proto_ops unix_dgram_ops = { @@ -1904,6 +1905,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, int target; int err = 0; long timeo; + int skip; err = -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) @@ -1933,12 +1935,15 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } + skip = sk_peek_offset(sk, flags); + do { int chunk; struct sk_buff *skb; unix_state_lock(sk); skb = skb_peek(&sk->sk_receive_queue); +again: if (skb == NULL) { unix_sk(sk)->recursion_level = 0; if (copied >= target) @@ -1973,6 +1978,13 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, unix_state_unlock(sk); break; } + + if (skip >= skb->len) { + skip -= skb->len; + skb = skb_peek_next(skb, &sk->sk_receive_queue); + goto again; + } + unix_state_unlock(sk); if (check_creds) { @@ -1992,8 +2004,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, sunaddr = NULL; } - chunk = min_t(unsigned int, skb->len, size); - if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { + chunk = min_t(unsigned int, skb->len - skip, size); + if (memcpy_toiovec(msg->msg_iov, skb->data + skip, chunk)) { if (copied == 0) copied = -EFAULT; break; @@ -2005,6 +2017,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (!(flags & MSG_PEEK)) { skb_pull(skb, chunk); + sk_peek_offset_bwd(sk, chunk); + if (UNIXCB(skb).fp) unix_detach_fds(siocb->scm, skb); @@ -2022,6 +2036,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (UNIXCB(skb).fp) siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); + sk_peek_offset_fwd(sk, chunk); + break; } } while (size); -- cgit v1.2.3-70-g09d2 From cdf49c283e2e105da86ca575ad35b453f5ff24ea Mon Sep 17 00:00:00 2001 From: Danny Kukawka Date: Wed, 22 Feb 2012 02:36:39 +0000 Subject: net/ieee802154/6lowpan.c: reuse eth_mac_addr() Use eth_mac_addr() for .ndo_set_mac_address, remove lowpan_set_address since it do currently the same as eth_mac_addr(). Additional advantage: eth_mac_addr() already checks if the given address is valid Signed-off-by: Danny Kukawka Acked-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller --- net/ieee802154/6lowpan.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index e4ecc1eef98..36851588536 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -924,19 +925,6 @@ drop: return -EINVAL; } -static int lowpan_set_address(struct net_device *dev, void *p) -{ - struct sockaddr *sa = p; - - if (netif_running(dev)) - return -EBUSY; - - /* TODO: validate addr */ - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - - return 0; -} - static int lowpan_get_mac_header_length(struct sk_buff *skb) { /* @@ -1062,7 +1050,7 @@ static struct header_ops lowpan_header_ops = { static const struct net_device_ops lowpan_netdev_ops = { .ndo_start_xmit = lowpan_xmit, - .ndo_set_mac_address = lowpan_set_address, + .ndo_set_mac_address = eth_mac_addr, }; static void lowpan_setup(struct net_device *dev) -- cgit v1.2.3-70-g09d2 From 9f6f9af7694ede6314bed281eec74d588ba9474f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Feb 2012 23:24:55 +0000 Subject: af_unix: MSG_TRUNC support for dgram sockets Piergiorgio Beruto expressed the need to fetch size of first datagram in queue for AF_UNIX sockets and suggested a patch against SIOCINQ ioctl. I suggested instead to implement MSG_TRUNC support as a recv() input flag, as already done for RAW, UDP & NETLINK sockets. len = recv(fd, &byte, 1, MSG_PEEK | MSG_TRUNC); MSG_TRUNC asks recv() to return the real length of the packet, even when is was longer than the passed buffer. There is risk that a userland application used MSG_TRUNC by accident (since it had no effect on af_unix sockets) and this might break after this patch. Signed-off-by: Eric Dumazet Tested-by: Piergiorgio Beruto CC: Michael Kerrisk Signed-off-by: David S. Miller --- net/unix/af_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 0be4d24f6ae..8ee85aa79fa 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1845,7 +1845,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, if (UNIXCB(skb).fp) siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); } - err = size; + err = (flags & MSG_TRUNC) ? skb->len - skip : size; scm_recv(sock, msg, siocb->scm, flags); -- cgit v1.2.3-70-g09d2 From 8860020e0be1f03d83dc9e9e93e18a4ddbe01038 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Feb 2012 15:17:18 +0100 Subject: cfg80211: restructure AP/GO mode API The AP/GO mode API isn't very clearly defined, it has "set beacon" and "new beacon" etc. Modify the API to the following: * start AP -- all settings * change beacon -- new beacon data * stop AP -- stop AP mode operation This also reflects in the nl80211 API, rename the commands there correspondingly (but keep the old names for compatibility.) Overall, this makes it much clearer what's going on in the API. Kalle developed the ath6kl changes, I created the rest of the patch. Signed-off-by: Kalle Valo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 82 ++++++---- include/linux/nl80211.h | 34 ++-- include/net/cfg80211.h | 70 ++++---- net/mac80211/cfg.c | 146 +++++++---------- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/tx.c | 13 +- net/wireless/nl80211.c | 255 ++++++++++++++++------------- 7 files changed, 316 insertions(+), 286 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d1922d8eb3b..5370333883e 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2269,25 +2269,11 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif, return ret; } -static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info, bool add) +static int ath6kl_set_ies(struct ath6kl_vif *vif, + struct cfg80211_beacon_data *info) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); - struct ieee80211_mgmt *mgmt; - u8 *ies; - int ies_len; - struct wmi_connect_cmd p; + struct ath6kl *ar = vif->ar; int res; - int i, ret; - - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); - - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; - - if (vif->next_mode != AP_NETWORK) - return -EOPNOTSUPP; if (info->beacon_ies) { res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, @@ -2297,12 +2283,14 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, if (res) return res; } + if (info->proberesp_ies) { res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, info->proberesp_ies_len); if (res) return res; } + if (info->assocresp_ies) { res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_ASSOC_RESP, @@ -2312,8 +2300,30 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, return res; } - if (!add) - return 0; + return 0; +} + +static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *info) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + struct ieee80211_mgmt *mgmt; + u8 *ies; + int ies_len; + struct wmi_connect_cmd p; + int res; + int i, ret; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + if (vif->next_mode != AP_NETWORK) + return -EOPNOTSUPP; + + res = ath6kl_set_ies(vif, &info->beacon); ar->ap_mode_bkey.valid = false; @@ -2322,13 +2332,13 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, * info->dtim_period */ - if (info->head == NULL) + if (info->beacon.head == NULL) return -EINVAL; - mgmt = (struct ieee80211_mgmt *) info->head; + mgmt = (struct ieee80211_mgmt *) info->beacon.head; ies = mgmt->u.beacon.variable; - if (ies > info->head + info->head_len) + if (ies > info->beacon.head + info->beacon.head_len) return -EINVAL; - ies_len = info->head + info->head_len - ies; + ies_len = info->beacon.head + info->beacon.head_len - ies; if (info->ssid == NULL) return -EINVAL; @@ -2436,19 +2446,21 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, return 0; } -static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) +static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *beacon) { - return ath6kl_ap_beacon(wiphy, dev, info, true); -} + struct ath6kl_vif *vif = netdev_priv(dev); -static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) -{ - return ath6kl_ap_beacon(wiphy, dev, info, false); + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + if (vif->next_mode != AP_NETWORK) + return -EOPNOTSUPP; + + return ath6kl_set_ies(vif, beacon); } -static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) +static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -2783,9 +2795,9 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .resume = __ath6kl_cfg80211_resume, #endif .set_channel = ath6kl_set_channel, - .add_beacon = ath6kl_add_beacon, - .set_beacon = ath6kl_set_beacon, - .del_beacon = ath6kl_del_beacon, + .start_ap = ath6kl_start_ap, + .change_beacon = ath6kl_change_beacon, + .stop_ap = ath6kl_stop_ap, .del_station = ath6kl_del_station, .change_station = ath6kl_change_station, .remain_on_channel = ath6kl_remain_on_channel, diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index ad56e21a9f1..be35a68746a 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -156,21 +156,23 @@ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX * or %NL80211_ATTR_MAC. * - * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a - * %NL80222_CMD_NEW_BEACON message) - * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface - * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, - * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. - * Following attributes are provided for drivers that generate full Beacon - * and Probe Response frames internally: %NL80211_ATTR_SSID, + * @NL80211_CMD_GET_BEACON: (not used) + * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface + * using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL + * attributes. For drivers that generate the beacon and probe responses + * internally, the following attributes must be provided: %NL80211_ATTR_IE, + * %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP. + * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters + * are like for %NL80211_CMD_SET_BEACON, and additionally parameters that + * do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL, + * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID, * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, - * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, - * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP, - * %NL80211_ATTR_IE_ASSOC_RESP. - * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, - * parameters are like for %NL80211_CMD_SET_BEACON. - * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY and + * %NL80211_ATTR_AUTH_TYPE. + * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP + * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface + * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP * * @NL80211_CMD_GET_STATION: Get station attributes for station identified by * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. @@ -565,8 +567,10 @@ enum nl80211_commands { NL80211_CMD_GET_BEACON, NL80211_CMD_SET_BEACON, - NL80211_CMD_NEW_BEACON, - NL80211_CMD_DEL_BEACON, + NL80211_CMD_START_AP, + NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP, + NL80211_CMD_STOP_AP, + NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP, NL80211_CMD_GET_STATION, NL80211_CMD_SET_STATION, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e0c9ff3a197..755a7707a7c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -366,25 +366,13 @@ struct cfg80211_crypto_settings { }; /** - * struct beacon_parameters - beacon parameters - * - * Used to configure the beacon for an interface. - * + * struct cfg80211_beacon_data - beacon data * @head: head portion of beacon (before TIM IE) * or %NULL if not changed * @tail: tail portion of beacon (after TIM IE) * or %NULL if not changed - * @interval: beacon interval or zero if not changed - * @dtim_period: DTIM period or zero if not changed * @head_len: length of @head * @tail_len: length of @tail - * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from - * user space) - * @ssid_len: length of @ssid - * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames - * @crypto: crypto settings - * @privacy: the BSS uses privacy - * @auth_type: Authentication type (algorithm) * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL * @beacon_ies_len: length of beacon_ies in octets * @proberesp_ies: extra information element(s) to add into Probe Response @@ -396,24 +384,46 @@ struct cfg80211_crypto_settings { * @probe_resp_len: length of probe response template (@probe_resp) * @probe_resp: probe response template (AP mode only) */ -struct beacon_parameters { - u8 *head, *tail; - int interval, dtim_period; - int head_len, tail_len; +struct cfg80211_beacon_data { + const u8 *head, *tail; + const u8 *beacon_ies; + const u8 *proberesp_ies; + const u8 *assocresp_ies; + const u8 *probe_resp; + + size_t head_len, tail_len; + size_t beacon_ies_len; + size_t proberesp_ies_len; + size_t assocresp_ies_len; + size_t probe_resp_len; +}; + +/** + * struct cfg80211_ap_settings - AP configuration + * + * Used to configure an AP interface. + * + * @beacon: beacon data + * @beacon_interval: beacon interval + * @dtim_period: DTIM period + * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from + * user space) + * @ssid_len: length of @ssid + * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames + * @crypto: crypto settings + * @privacy: the BSS uses privacy + * @auth_type: Authentication type (algorithm) + */ +struct cfg80211_ap_settings { + struct cfg80211_beacon_data beacon; + + int beacon_interval, dtim_period; const u8 *ssid; size_t ssid_len; enum nl80211_hidden_ssid hidden_ssid; struct cfg80211_crypto_settings crypto; bool privacy; enum nl80211_auth_type auth_type; - const u8 *beacon_ies; - size_t beacon_ies_len; - const u8 *proberesp_ies; - size_t proberesp_ies_len; - const u8 *assocresp_ies; - size_t assocresp_ies_len; - int probe_resp_len; - u8 *probe_resp; }; /** @@ -1518,11 +1528,11 @@ struct cfg80211_ops { struct net_device *netdev, u8 key_index); - int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info); - int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info); - int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); + int (*start_ap)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings); + int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *info); + int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev); int (*add_station)(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c3de921c8cf..f7eb25aabf8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -489,27 +489,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, return ret; } -static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata, - struct beacon_parameters *params) -{ - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; - - bss_conf->ssid_len = params->ssid_len; - - if (params->ssid_len) - memcpy(bss_conf->ssid, params->ssid, params->ssid_len); - - bss_conf->hidden_ssid = - (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); -} - static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, - u8 *resp, size_t resp_len) + const u8 *resp, size_t resp_len) { struct sk_buff *new, *old; if (!resp || !resp_len) - return -EINVAL; + return 1; old = rtnl_dereference(sdata->u.ap.probe_resp); @@ -520,50 +506,28 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, memcpy(skb_put(new, resp_len), resp, resp_len); rcu_assign_pointer(sdata->u.ap.probe_resp, new); - synchronize_rcu(); - - if (old) + if (old) { + /* TODO: use call_rcu() */ + synchronize_rcu(); dev_kfree_skb(old); + } return 0; } -/* - * This handles both adding a beacon and setting new beacon info - */ -static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, - struct beacon_parameters *params) +static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct cfg80211_beacon_data *params) { struct beacon_data *new, *old; int new_head_len, new_tail_len; - int size; - int err = -EINVAL; - u32 changed = 0; + int size, err; + u32 changed = BSS_CHANGED_BEACON; old = rtnl_dereference(sdata->u.ap.beacon); - /* head must not be zero-length */ - if (params->head && !params->head_len) - return -EINVAL; - - /* - * This is a kludge. beacon interval should really be part - * of the beacon information. - */ - if (params->interval && - (sdata->vif.bss_conf.beacon_int != params->interval)) { - sdata->vif.bss_conf.beacon_int = params->interval; - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BEACON_INT); - } - /* Need to have a beacon head if we don't have one yet */ if (!params->head && !old) - return err; - - /* sorry, no way to start beaconing without dtim period */ - if (!params->dtim_period && !old) - return err; + return -EINVAL; /* new or old head? */ if (params->head) @@ -586,12 +550,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, /* start filling the new info now */ - /* new or old dtim period? */ - if (params->dtim_period) - new->dtim_period = params->dtim_period; - else - new->dtim_period = old->dtim_period; - /* * pointers go into the block we allocated, * memory is | beacon_data | head | tail | @@ -614,46 +572,37 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, if (old) memcpy(new->tail, old->tail, new_tail_len); - sdata->vif.bss_conf.dtim_period = new->dtim_period; - - rcu_assign_pointer(sdata->u.ap.beacon, new); - - synchronize_rcu(); - - kfree(old); - err = ieee80211_set_probe_resp(sdata, params->probe_resp, params->probe_resp_len); - if (!err) + if (err < 0) + return err; + if (err == 0) changed |= BSS_CHANGED_AP_PROBE_RESP; - ieee80211_config_ap_ssid(sdata, params); - changed |= BSS_CHANGED_BEACON_ENABLED | - BSS_CHANGED_BEACON | - BSS_CHANGED_SSID; + rcu_assign_pointer(sdata->u.ap.beacon, new); + + if (old) + kfree_rcu(old, rcu_head); - ieee80211_bss_info_change_notify(sdata, changed); - return 0; + return changed; } -static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *params) +static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *params) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct beacon_data *old; struct ieee80211_sub_if_data *vlan; - int ret; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + u32 changed = BSS_CHANGED_BEACON_INT | + BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON | + BSS_CHANGED_SSID; + int err; old = rtnl_dereference(sdata->u.ap.beacon); if (old) return -EALREADY; - ret = ieee80211_config_beacon(sdata, params); - if (ret) - return ret; - /* * Apply control port protocol, this allows us to * not encrypt dynamic WEP control frames. @@ -667,14 +616,32 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_no_encrypt; } + sdata->vif.bss_conf.beacon_int = params->beacon_interval; + sdata->vif.bss_conf.dtim_period = params->dtim_period; + + sdata->vif.bss_conf.ssid_len = params->ssid_len; + if (params->ssid_len) + memcpy(sdata->vif.bss_conf.ssid, params->ssid, + params->ssid_len); + sdata->vif.bss_conf.hidden_ssid = + (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); + + err = ieee80211_assign_beacon(sdata, ¶ms->beacon); + if (err < 0) + return err; + changed |= err; + + ieee80211_bss_info_change_notify(sdata, changed); + return 0; } -static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *params) +static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *params) { struct ieee80211_sub_if_data *sdata; struct beacon_data *old; + int err; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -682,10 +649,14 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, if (!old) return -ENOENT; - return ieee80211_config_beacon(sdata, params); + err = ieee80211_assign_beacon(sdata, params); + if (err < 0) + return err; + ieee80211_bss_info_change_notify(sdata, err); + return 0; } -static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ieee80211_sub_if_data *sdata; struct beacon_data *old; @@ -697,10 +668,11 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) return -ENOENT; RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); - synchronize_rcu(); - kfree(old); + + kfree_rcu(old, rcu_head); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + return 0; } @@ -2699,9 +2671,9 @@ struct cfg80211_ops mac80211_config_ops = { .get_key = ieee80211_get_key, .set_default_key = ieee80211_config_default_key, .set_default_mgmt_key = ieee80211_config_default_mgmt_key, - .add_beacon = ieee80211_add_beacon, - .set_beacon = ieee80211_set_beacon, - .del_beacon = ieee80211_del_beacon, + .start_ap = ieee80211_start_ap, + .change_beacon = ieee80211_change_beacon, + .stop_ap = ieee80211_stop_ap, .add_station = ieee80211_add_station, .del_station = ieee80211_del_station, .change_station = ieee80211_change_station, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 74594f012cd..67aed1eff13 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -228,7 +228,7 @@ struct ieee80211_rx_data { struct beacon_data { u8 *head, *tail; int head_len, tail_len; - int dtim_period; + struct rcu_head rcu_head; }; struct ieee80211_if_ap { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1be0ca2b593..c6eadac9ca4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2206,7 +2206,8 @@ void ieee80211_tx_pending(unsigned long data) /* functions for drivers to get certain frames */ -static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, +static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, + struct ieee80211_if_ap *bss, struct sk_buff *skb, struct beacon_data *beacon) { @@ -2223,7 +2224,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, IEEE80211_MAX_AID+1); if (bss->dtim_count == 0) - bss->dtim_count = beacon->dtim_period - 1; + bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1; else bss->dtim_count--; @@ -2231,7 +2232,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, *pos++ = WLAN_EID_TIM; *pos++ = 4; *pos++ = bss->dtim_count; - *pos++ = beacon->dtim_period; + *pos++ = sdata->vif.bss_conf.dtim_period; if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) aid0 = 1; @@ -2324,12 +2325,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - ieee80211_beacon_add_tim(ap, skb, beacon); + ieee80211_beacon_add_tim(sdata, ap, skb, + beacon); } else { unsigned long flags; spin_lock_irqsave(&local->tim_lock, flags); - ieee80211_beacon_add_tim(ap, skb, beacon); + ieee80211_beacon_add_tim(sdata, ap, skb, + beacon); spin_unlock_irqrestore(&local->tim_lock, flags); } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fe274765356..1998c368277 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -871,7 +871,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(add_virtual_intf, NEW_INTERFACE); CMD(change_virtual_intf, SET_INTERFACE); CMD(add_key, NEW_KEY); - CMD(add_beacon, NEW_BEACON); + CMD(start_ap, START_AP); CMD(add_station, NEW_STATION); CMD(add_mpath, NEW_MPATH); CMD(update_mesh_config, SET_MESH_CONFIG); @@ -2075,15 +2075,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) return err; } -static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) +static int nl80211_parse_beacon(struct genl_info *info, + struct cfg80211_beacon_data *bcn) { - int (*call)(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info); - struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct beacon_parameters params; - int haveinfo = 0, err; + bool haveinfo = false; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) || !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) || @@ -2091,149 +2086,183 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP])) return -EINVAL; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) - return -EOPNOTSUPP; - - memset(¶ms, 0, sizeof(params)); - - switch (info->genlhdr->cmd) { - case NL80211_CMD_NEW_BEACON: - /* these are required for NEW_BEACON */ - if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || - !info->attrs[NL80211_ATTR_DTIM_PERIOD] || - !info->attrs[NL80211_ATTR_BEACON_HEAD]) - return -EINVAL; - - params.interval = - nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); - params.dtim_period = - nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); - - err = cfg80211_validate_beacon_int(rdev, params.interval); - if (err) - return err; - - /* - * In theory, some of these attributes could be required for - * NEW_BEACON, but since they were not used when the command was - * originally added, keep them optional for old user space - * programs to work with drivers that do not need the additional - * information. - */ - if (info->attrs[NL80211_ATTR_SSID]) { - params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); - params.ssid_len = - nla_len(info->attrs[NL80211_ATTR_SSID]); - if (params.ssid_len == 0 || - params.ssid_len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - } - - if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) { - params.hidden_ssid = nla_get_u32( - info->attrs[NL80211_ATTR_HIDDEN_SSID]); - if (params.hidden_ssid != - NL80211_HIDDEN_SSID_NOT_IN_USE && - params.hidden_ssid != - NL80211_HIDDEN_SSID_ZERO_LEN && - params.hidden_ssid != - NL80211_HIDDEN_SSID_ZERO_CONTENTS) - return -EINVAL; - } - - params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; - - if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { - params.auth_type = nla_get_u32( - info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(params.auth_type)) - return -EINVAL; - } else - params.auth_type = NL80211_AUTHTYPE_AUTOMATIC; - - err = nl80211_crypto_settings(rdev, info, ¶ms.crypto, - NL80211_MAX_NR_CIPHER_SUITES); - if (err) - return err; - - call = rdev->ops->add_beacon; - break; - case NL80211_CMD_SET_BEACON: - call = rdev->ops->set_beacon; - break; - default: - WARN_ON(1); - return -EOPNOTSUPP; - } - - if (!call) - return -EOPNOTSUPP; + memset(bcn, 0, sizeof(*bcn)); if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { - params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); - params.head_len = - nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); - haveinfo = 1; + bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); + bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); + if (!bcn->head_len) + return -EINVAL; + haveinfo = true; } if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { - params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); - params.tail_len = + bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); + bcn->tail_len = nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); - haveinfo = 1; + haveinfo = true; } if (!haveinfo) return -EINVAL; if (info->attrs[NL80211_ATTR_IE]) { - params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); - params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); + bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); + bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); } if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) { - params.proberesp_ies = + bcn->proberesp_ies = nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); - params.proberesp_ies_len = + bcn->proberesp_ies_len = nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); } if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) { - params.assocresp_ies = + bcn->assocresp_ies = nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); - params.assocresp_ies_len = + bcn->assocresp_ies_len = nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); } if (info->attrs[NL80211_ATTR_PROBE_RESP]) { - params.probe_resp = + bcn->probe_resp = nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); - params.probe_resp_len = + bcn->probe_resp_len = nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); } - err = call(&rdev->wiphy, dev, ¶ms); - if (!err && params.interval) - wdev->beacon_interval = params.interval; + return 0; +} + +static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_ap_settings params; + int err; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (!rdev->ops->start_ap) + return -EOPNOTSUPP; + + if (wdev->beacon_interval) + return -EALREADY; + + memset(¶ms, 0, sizeof(params)); + + /* these are required for START_AP */ + if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || + !info->attrs[NL80211_ATTR_DTIM_PERIOD] || + !info->attrs[NL80211_ATTR_BEACON_HEAD]) + return -EINVAL; + + err = nl80211_parse_beacon(info, ¶ms.beacon); + if (err) + return err; + + params.beacon_interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + params.dtim_period = + nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); + + err = cfg80211_validate_beacon_int(rdev, params.beacon_interval); + if (err) + return err; + + /* + * In theory, some of these attributes should be required here + * but since they were not used when the command was originally + * added, keep them optional for old user space programs to let + * them continue to work with drivers that do not need the + * additional information -- drivers must check! + */ + if (info->attrs[NL80211_ATTR_SSID]) { + params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + params.ssid_len = + nla_len(info->attrs[NL80211_ATTR_SSID]); + if (params.ssid_len == 0 || + params.ssid_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) { + params.hidden_ssid = nla_get_u32( + info->attrs[NL80211_ATTR_HIDDEN_SSID]); + if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE && + params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN && + params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS) + return -EINVAL; + } + + params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; + + if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { + params.auth_type = nla_get_u32( + info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(params.auth_type)) + return -EINVAL; + } else + params.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + + err = nl80211_crypto_settings(rdev, info, ¶ms.crypto, + NL80211_MAX_NR_CIPHER_SUITES); + if (err) + return err; + + err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); + if (!err) + wdev->beacon_interval = params.beacon_interval; return err; } -static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) +static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_beacon_data params; + int err; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (!rdev->ops->change_beacon) + return -EOPNOTSUPP; + + if (!wdev->beacon_interval) + return -EINVAL; + + err = nl80211_parse_beacon(info, ¶ms); + if (err) + return err; + + return rdev->ops->change_beacon(&rdev->wiphy, dev, ¶ms); +} + +static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; int err; - if (!rdev->ops->del_beacon) + if (!rdev->ops->stop_ap) return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - err = rdev->ops->del_beacon(&rdev->wiphy, dev); + if (!wdev->beacon_interval) + return -ENOENT; + + err = rdev->ops->stop_ap(&rdev->wiphy, dev); if (!err) wdev->beacon_interval = 0; return err; @@ -6357,23 +6386,23 @@ static struct genl_ops nl80211_ops[] = { .cmd = NL80211_CMD_SET_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .doit = nl80211_addset_beacon, + .doit = nl80211_set_beacon, .internal_flags = NL80211_FLAG_NEED_NETDEV | NL80211_FLAG_NEED_RTNL, }, { - .cmd = NL80211_CMD_NEW_BEACON, + .cmd = NL80211_CMD_START_AP, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .doit = nl80211_addset_beacon, + .doit = nl80211_start_ap, .internal_flags = NL80211_FLAG_NEED_NETDEV | NL80211_FLAG_NEED_RTNL, }, { - .cmd = NL80211_CMD_DEL_BEACON, + .cmd = NL80211_CMD_STOP_AP, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .doit = nl80211_del_beacon, + .doit = nl80211_stop_ap, .internal_flags = NL80211_FLAG_NEED_NETDEV | NL80211_FLAG_NEED_RTNL, }, -- cgit v1.2.3-70-g09d2 From 1b009c982482ee0e4cbabcd9bdae690a29119ede Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:54 +0200 Subject: Bluetooth: trivial: Fix long line Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 37736c6603f..63539f94057 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2720,7 +2720,8 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd result = __le16_to_cpu(rsp->result); status = __le16_to_cpu(rsp->status); - BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", + dcid, scid, result, status); if (scid) { chan = l2cap_get_chan_by_scid(conn, scid); -- cgit v1.2.3-70-g09d2 From 3df91ea20e744344100b10ae69a17211fcf5b207 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:55 +0200 Subject: Bluetooth: Revert to mutexes from RCU list Usage of RCU list looks not reasonalbe for a number of reasons: our code sleep and we had to use socket spinlocks. Most parts of code are updaters thus there is little sense to use RCU. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 166 +++++++++++++++++++++++++++------------------ net/bluetooth/l2cap_sock.c | 10 +++ 2 files changed, 109 insertions(+), 67 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 63539f94057..8e8e9e93fb3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -77,36 +77,24 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->dcid == cid) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->dcid == cid) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->scid == cid) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->scid == cid) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } /* Find channel with given SCID. @@ -115,36 +103,32 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci { struct l2cap_chan *c; + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); - if (c) - lock_sock(c->sk); + mutex_unlock(&conn->chan_lock); + return c; } static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->ident == ident) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->ident == ident) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); - if (c) - lock_sock(c->sk); + mutex_unlock(&conn->chan_lock); + return c; } @@ -228,11 +212,13 @@ static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, chan_timer.work); + struct l2cap_conn *conn = chan->conn; struct sock *sk = chan->sk; int reason; BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); + mutex_lock(&conn->chan_lock); lock_sock(sk); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) @@ -248,6 +234,8 @@ static void l2cap_chan_timeout(struct work_struct *work) release_sock(sk); chan->ops->close(chan->data); + mutex_unlock(&conn->chan_lock); + l2cap_chan_put(chan); } @@ -331,7 +319,9 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_chan_hold(chan); - list_add_rcu(&chan->list, &conn->chan_l); + mutex_lock(&conn->chan_lock); + list_add(&chan->list, &conn->chan_l); + mutex_unlock(&conn->chan_lock); } /* Delete channel. @@ -348,8 +338,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) if (conn) { /* Delete from channel list */ - list_del_rcu(&chan->list); - synchronize_rcu(); + list_del(&chan->list); l2cap_chan_put(chan); @@ -400,10 +389,12 @@ static void l2cap_chan_cleanup_listen(struct sock *parent) /* Close not yet accepted channels */ while ((sk = bt_accept_dequeue(parent, NULL))) { struct l2cap_chan *chan = l2cap_pi(sk)->chan; + __clear_chan_timer(chan); lock_sock(sk); l2cap_chan_close(chan, ECONNRESET); release_sock(sk); + chan->ops->close(chan->data); } } @@ -718,13 +709,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct l2cap_chan *chan; + struct l2cap_chan *chan, *tmp; BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -804,7 +795,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* Find socket with cid and source bdaddr. @@ -916,9 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->out && conn->hcon->type == LE_LINK) smp_conn_security(conn, conn->hcon->pending_sec_level); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -938,7 +929,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -948,16 +939,16 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) sk->sk_err = err; } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } static void l2cap_info_timeout(struct work_struct *work) @@ -984,6 +975,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); + mutex_lock(&conn->chan_lock); + /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { sk = chan->sk; @@ -993,6 +986,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) chan->ops->close(chan->data); } + mutex_unlock(&conn->chan_lock); + hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) @@ -1050,6 +1045,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); + mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); @@ -1792,9 +1788,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (chan->chan_type != L2CAP_CHAN_RAW) continue; @@ -1810,7 +1806,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) kfree_skb(nskb); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* ---- L2CAP signalling commands ---- */ @@ -2600,6 +2596,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd parent = pchan->sk; + mutex_lock(&conn->chan_lock); lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ @@ -2673,6 +2670,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd response: release_sock(parent); + mutex_unlock(&conn->chan_lock); sendresp: rsp.scid = cpu_to_le16(scid); @@ -2714,6 +2712,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_chan *chan; struct sock *sk; u8 req[128]; + int err; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); @@ -2723,17 +2722,26 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + mutex_lock(&conn->chan_lock); + if (scid) { - chan = l2cap_get_chan_by_scid(conn, scid); - if (!chan) - return -EFAULT; + chan = __l2cap_get_chan_by_scid(conn, scid); + if (!chan) { + err = -EFAULT; + goto unlock; + } } else { - chan = l2cap_get_chan_by_ident(conn, cmd->ident); - if (!chan) - return -EFAULT; + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); + if (!chan) { + err = -EFAULT; + goto unlock; + } } + err = 0; + sk = chan->sk; + lock_sock(sk); switch (result) { case L2CAP_CR_SUCCESS: @@ -2760,7 +2768,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd } release_sock(sk); - return 0; + +unlock: + mutex_unlock(&conn->chan_lock); + + return err; } static inline void set_default_fcs(struct l2cap_chan *chan) @@ -2793,6 +2805,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr return -ENOENT; sk = chan->sk; + lock_sock(sk); if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -2905,6 +2918,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr return 0; sk = chan->sk; + lock_sock(sk); switch (result) { case L2CAP_CONF_SUCCESS: @@ -3006,11 +3020,16 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - chan = l2cap_get_chan_by_scid(conn, dcid); - if (!chan) + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_scid(conn, dcid); + if (!chan) { + mutex_unlock(&conn->chan_lock); return 0; + } sk = chan->sk; + lock_sock(sk); rsp.dcid = cpu_to_le16(chan->scid); rsp.scid = cpu_to_le16(chan->dcid); @@ -3022,6 +3041,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd release_sock(sk); chan->ops->close(chan->data); + + mutex_unlock(&conn->chan_lock); + return 0; } @@ -3037,16 +3059,24 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - chan = l2cap_get_chan_by_scid(conn, scid); - if (!chan) + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_scid(conn, scid); + if (!chan) { + mutex_unlock(&conn->chan_lock); return 0; + } sk = chan->sk; + lock_sock(sk); l2cap_chan_del(chan, 0); release_sock(sk); chan->ops->close(chan->data); + + mutex_unlock(&conn->chan_lock); + return 0; } @@ -4205,6 +4235,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk } sk = chan->sk; + lock_sock(sk); BT_DBG("chan %p, len %d", chan, skb->len); @@ -4492,9 +4523,9 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) cancel_delayed_work(&conn->security_timer); } - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -4574,7 +4605,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); return 0; } @@ -4635,6 +4666,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) if (chan && chan->sk) { struct sock *sk = chan->sk; + lock_sock(sk); if (chan->imtu < len - L2CAP_HDR_SIZE) { BT_ERR("Frame exceeding recv MTU (len %d, " diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b48d6c1b9db..1273fcbeec2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -796,6 +796,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; struct l2cap_chan *chan; + struct l2cap_conn *conn; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -804,6 +805,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) return 0; chan = l2cap_pi(sk)->chan; + conn = chan->conn; + + if (conn) + mutex_lock(&conn->chan_lock); lock_sock(sk); if (!sk->sk_shutdown) { @@ -811,6 +816,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = __l2cap_wait_ack(sk); sk->sk_shutdown = SHUTDOWN_MASK; + l2cap_chan_close(chan, 0); if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) @@ -822,6 +828,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = -sk->sk_err; release_sock(sk); + + if (conn) + mutex_unlock(&conn->chan_lock); + return err; } -- cgit v1.2.3-70-g09d2 From c03b355ea2938495bbdf25a4645be545be8890f4 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:56 +0200 Subject: Bluetooth: Add l2cap_chan_lock Channel lock will be used to lock L2CAP channels which are locked currently by socket locks. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 11 +++++++++++ net/bluetooth/l2cap_core.c | 2 ++ 2 files changed, 13 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bbb0e214e51..d6d8ec8eb8c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -497,6 +497,7 @@ struct l2cap_chan { void *data; struct l2cap_ops *ops; + struct mutex lock; }; struct l2cap_ops { @@ -609,6 +610,16 @@ static inline void l2cap_chan_put(struct l2cap_chan *c) kfree(c); } +static inline void l2cap_chan_lock(struct l2cap_chan *chan) +{ + mutex_lock(&chan->lock); +} + +static inline void l2cap_chan_unlock(struct l2cap_chan *chan) +{ + mutex_unlock(&chan->lock); +} + static inline void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8e8e9e93fb3..e39eba1ac4d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -247,6 +247,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) if (!chan) return NULL; + mutex_init(&chan->lock); + chan->sk = sk; write_lock(&chan_list_lock); -- cgit v1.2.3-70-g09d2 From 0e587be728a522fd8e522ad905b02f2892b61712 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:57 +0200 Subject: Bluetooth: Add locked and unlocked state_change Split to locked and unlocked versions of l2cap_state_change helping to remove socket locks from l2cap code. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e39eba1ac4d..4638dbbaa4b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -199,7 +199,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static void l2cap_state_change(struct l2cap_chan *chan, int state) +static void __l2cap_state_change(struct l2cap_chan *chan, int state) { BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state), state_to_string(state)); @@ -208,6 +208,15 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) chan->ops->state_change(chan->data, state); } +static void l2cap_state_change(struct l2cap_chan *chan, int state) +{ + struct sock *sk = chan->sk; + + lock_sock(sk); + __l2cap_state_change(chan, state); + release_sock(sk); +} + static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -348,7 +357,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) hci_conn_put(conn->hcon); } - l2cap_state_change(chan, BT_CLOSED); + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); if (err) @@ -413,7 +422,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) case BT_LISTEN: l2cap_chan_cleanup_listen(sk); - l2cap_state_change(chan, BT_CLOSED); + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); break; @@ -704,7 +713,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); - l2cap_state_change(chan, BT_DISCONN); + __l2cap_state_change(chan, BT_DISCONN); sk->sk_err = err; } @@ -770,7 +779,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); } @@ -873,7 +882,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) __set_chan_timer(chan, sk->sk_sndtimeo); - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); parent->sk_data_ready(parent, 0); clean: @@ -890,7 +899,7 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) chan->conf_state = 0; __clear_chan_timer(chan); - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); sk->sk_state_change(sk); if (parent) @@ -922,7 +931,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); sk->sk_state_change(sk); } else if (chan->state == BT_CONNECT) @@ -1196,14 +1205,14 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d l2cap_chan_add(conn, chan); - l2cap_state_change(chan, BT_CONNECT); + __l2cap_state_change(chan, BT_CONNECT); __set_chan_timer(chan, sk->sk_sndtimeo); if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); if (l2cap_chan_check_security(chan)) - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); } else l2cap_do_start(chan); } @@ -2650,22 +2659,22 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_chan_check_security(chan)) { if (bt_sk(sk)->defer_setup) { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHOR_PEND; parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); result = L2CAP_CR_SUCCESS; status = L2CAP_CS_NO_INFO; } } else { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHEN_PEND; } } else { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_NO_INFO; } @@ -4584,12 +4593,12 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (parent) parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); res = L2CAP_CR_SUCCESS; stat = L2CAP_CS_NO_INFO; } } else { - l2cap_state_change(chan, BT_DISCONN); + __l2cap_state_change(chan, BT_DISCONN); __set_chan_timer(chan, msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); res = L2CAP_CR_SEC_BLOCK; -- cgit v1.2.3-70-g09d2 From 2e0052e4cf78e3e205e92d82ee572ed726e315d6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:58 +0200 Subject: Bluetooth: Add socket error function Use locked and unlocked versions to help removing socket locks from l2cap core functions. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4638dbbaa4b..c0640b73c62 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -217,6 +217,22 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) release_sock(sk); } +static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err) +{ + struct sock *sk = chan->sk; + + sk->sk_err = err; +} + +static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) +{ + struct sock *sk = chan->sk; + + lock_sock(sk); + __l2cap_chan_set_err(chan, err); + release_sock(sk); +} + static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -361,7 +377,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) sock_set_flag(sk, SOCK_ZAPPED); if (err) - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); if (parent) { bt_accept_unlink(sk); @@ -694,14 +710,11 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) { - struct sock *sk; struct l2cap_disconn_req req; if (!conn) return; - sk = chan->sk; - if (chan->mode == L2CAP_MODE_ERTM) { __clear_retrans_timer(chan); __clear_monitor_timer(chan); @@ -714,7 +727,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c L2CAP_DISCONN_REQ, sizeof(req), &req); __l2cap_state_change(chan, BT_DISCONN); - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); } /* ---- L2CAP connections ---- */ @@ -953,10 +966,8 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; - if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); } mutex_unlock(&conn->chan_lock); @@ -2988,7 +2999,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } default: - sk->sk_err = ECONNRESET; + __l2cap_chan_set_err(chan, ECONNRESET); + __set_chan_timer(chan, msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); l2cap_send_disconn_req(conn, chan, ECONNRESET); -- cgit v1.2.3-70-g09d2 From 47990ea09d393da8fb6cf284f4dba704c3661973 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 11:58:37 +0200 Subject: Bluetooth: mgmt: Make Set Link Security callable while powered off This patch makes it possible to change the Link Security setting while powered off and have it automatically enabled when powering on a device. To track the desired state once powered on a new HCI_LINK_SECURITY flag is added. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_event.c | 6 ++++++ net/bluetooth/mgmt.c | 33 ++++++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 169d2f8cc4e..806eb412079 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -98,6 +98,7 @@ enum { HCI_HS_ENABLED, HCI_CONNECTABLE, HCI_DISCOVERABLE, + HCI_LINK_SECURITY, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2a5d05c05e3..5fb1ee516d3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -594,6 +594,12 @@ static void hci_setup(struct hci_dev *hdev) sizeof(cp), &cp); } + if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) { + u8 enable = 1; + hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, + sizeof(enable), &enable); + } + if (hdev->features[4] & LMP_LE) hci_set_le_support(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e8f890d7256..69d4e1a699a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -410,7 +410,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (hdev->host_features[0] & LMP_HOST_LE) settings |= MGMT_SETTING_LE; - if (test_bit(HCI_AUTH, &hdev->flags)) + if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) settings |= MGMT_SETTING_LINK_SECURITY; if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) @@ -1067,8 +1067,21 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_NOT_POWERED); + bool changed = false; + + if (!!cp->val != test_bit(HCI_LINK_SECURITY, + &hdev->dev_flags)) { + change_bit(HCI_LINK_SECURITY, &hdev->dev_flags); + changed = true; + } + + err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } @@ -3338,7 +3351,8 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; - int err; + bool changed = false; + int err = 0; if (status) { u8 mgmt_err = mgmt_status(status); @@ -3347,10 +3361,19 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) return 0; } + if (test_bit(HCI_AUTH, &hdev->flags)) { + if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) + changed = true; + } + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, &match); - err = new_settings(hdev, match.sk); + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); -- cgit v1.2.3-70-g09d2 From 2e99b0afc7445769bb886dc14a31aaa0dc17c4b5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 12:28:39 +0200 Subject: Bluetooth: Remove unneeded hci_cc_read_ssp_mode function The kernel has no need to track the hci_read_ssp_mode command since it has the hci_sent_cmd_data function to check what value was set when hci_write_ssp_mode completes. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5fb1ee516d3..1b1c3480a24 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -420,21 +420,6 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status); } -static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct hci_rp_read_ssp_mode *rp = (void *) skb->data; - - BT_DBG("%s status 0x%x", hdev->name, rp->status); - - if (rp->status) - return; - - if (rp->mode) - set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); - else - clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); -} - static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2201,10 +2186,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_host_buffer_size(hdev, skb); break; - case HCI_OP_READ_SSP_MODE: - hci_cc_read_ssp_mode(hdev, skb); - break; - case HCI_OP_WRITE_SSP_MODE: hci_cc_write_ssp_mode(hdev, skb); break; -- cgit v1.2.3-70-g09d2 From c0ecddc2507da980af307aae40d6bcdea4c195dc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 12:38:31 +0200 Subject: Bluetooth: mgmt: Make Set SSP command callable while powered off This patch makes it possible to enable SSP through mgmt even when powered off. The setting will then get automatically actiated when powering on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_event.c | 20 ++++++++---------- net/bluetooth/mgmt.c | 44 ++++++++++++++++++++++++++++++++-------- 3 files changed, 46 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 094b5dbdb13..6ba3a4b1078 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1006,7 +1006,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); -int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status); +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1b1c3480a24..240dc1640c0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -427,21 +427,18 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - goto done; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); if (!sent) return; - if (*((u8 *) sent)) - set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); - else - clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); - -done: if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_ssp_enable_complete(hdev, status); + mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status); + else if (!status) { + if (*((u8 *) sent)) + set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + } } static u8 hci_get_inquiry_mode(struct hci_dev *hdev) @@ -560,7 +557,8 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - if (hdev->features[6] & LMP_SIMPLE_PAIR) { + if (hdev->features[6] & LMP_SIMPLE_PAIR && + test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 69d4e1a699a..eefd0846800 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1138,9 +1138,23 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + val = !!cp->val; + if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, - MGMT_STATUS_NOT_POWERED); + bool changed = false; + + if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + change_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + changed = true; + } + + err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } @@ -1155,8 +1169,6 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - val = !!cp->val; - if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) { err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); goto failed; @@ -3393,21 +3405,37 @@ static int clear_eir(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); } -int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) { struct cmd_lookup match = { NULL, hdev }; - int err; + bool changed = false; + int err = 0; if (status) { u8 mgmt_err = mgmt_status(status); + + if (enable && test_and_clear_bit(HCI_SSP_ENABLED, + &hdev->dev_flags)) + err = new_settings(hdev, NULL); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, &mgmt_err); - return 0; + + return err; + } + + if (enable) { + if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + changed = true; } mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); - err = new_settings(hdev, match.sk); + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) { sock_put(match.sk); -- cgit v1.2.3-70-g09d2 From e5f0e151426bd83e4852a7a150fc6ad8ee349e69 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 11:59:01 +0100 Subject: Bluetooth: Fix two minor style issues in management code WARNING: Statements terminations use 1 semicolon + return err;; WARNING: space prohibited between function name and open parenthesis '(' + err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index eefd0846800..3f4c50eebbe 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -264,7 +264,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, if (err < 0) kfree_skb(skb); - return err;; + return err; } static int read_version(struct sock *sk) @@ -2532,7 +2532,7 @@ static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { - err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, + err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, MGMT_STATUS_INVALID_PARAMS); goto failed; } -- cgit v1.2.3-70-g09d2 From 70c1f20b00495fd25b81be14b263d32648a3d629 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 12:06:43 +0100 Subject: Bluetooth: Fix two minor style issues in HCI code WARNING: min() should probably be min_t(__u16, scb->expect, count) + len = min(scb->expect, (__u16)count); WARNING: Statements terminations use 1 semicolon + INIT_LIST_HEAD(&conn->chan_list);; Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/hci_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3c68e606d5e..947172bf162 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -402,7 +402,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) skb_queue_head_init(&conn->data_q); - INIT_LIST_HEAD(&conn->chan_list);; + INIT_LIST_HEAD(&conn->chan_list); INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9d199494bd6..e1dadeea4c2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1957,7 +1957,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, while (count) { scb = (void *) skb->cb; - len = min(scb->expect, (__u16)count); + len = min_t(__u16, scb->expect, count); memcpy(skb_put(skb, len), data, len); -- cgit v1.2.3-70-g09d2 From 6bf0e4699d1dd56f7f8c12cf332ebffaf1c5e83e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 13:21:16 +0200 Subject: Bluetooth: Fix coding style issues in mgmt code In this case we need to use braces in both branches. Signed-off-by: Andrei Emeltchenko Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3f4c50eebbe..9fb44900f7d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -952,9 +952,9 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) changed = true; - if (cp->val) + if (cp->val) { set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else { + } else { clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } @@ -987,9 +987,9 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (cp->val) + if (cp->val) { scan = SCAN_PAGE; - else { + } else { scan = 0; if (test_bit(HCI_ISCAN, &hdev->flags) && -- cgit v1.2.3-70-g09d2 From 5fc6ebb102fdf6f589242ebfe3a07d112d60c7d5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 15:10:59 +0200 Subject: Bluetooth: mgmt: Fix EIR toggling with SSP This patch fixes setting the EIR properly when the SSP flag has been set when powered off (in such a case there is no pending Set_SSP command). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9fb44900f7d..bdaadb278ce 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3437,14 +3437,13 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) if (changed) err = new_settings(hdev, match.sk); - if (match.sk) { + if (match.sk) sock_put(match.sk); - if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) - update_eir(hdev); - else - clear_eir(hdev); - } + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + update_eir(hdev); + else + clear_eir(hdev); return err; } -- cgit v1.2.3-70-g09d2 From c80da27e868f6ffbe1c6588937aa4e7aeab21dec Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 15:38:48 +0200 Subject: Bluetooth: mgmt: Fix clearing of hdev->eir The hdev->eir buffer needs to be cleared when clearing the EIR data. Otherwise subsequent attempts at setting the EIR to something valid again may fail because the code thinks that the EIR hasn't changed. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bdaadb278ce..08c657df7f8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3400,6 +3400,8 @@ static int clear_eir(struct hci_dev *hdev) if (!(hdev->features[6] & LMP_EXT_INQ)) return 0; + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(&cp, 0, sizeof(cp)); return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); -- cgit v1.2.3-70-g09d2 From 54d04dbbb933e8a49429d602b847e367782267e9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 15:47:48 +0200 Subject: Bluetooth: Explicitly clear EIR data upon hci_dev setup Some controllers preserve their EIR data even after a reset so we need to explicitly clear this during the device setup procedure. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 240dc1640c0..3476d5c7b02 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -557,10 +557,19 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - if (hdev->features[6] & LMP_SIMPLE_PAIR && - test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { - u8 mode = 0x01; - hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); + if (hdev->features[6] & LMP_SIMPLE_PAIR) { + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + u8 mode = 0x01; + hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, + sizeof(mode), &mode); + } else { + struct hci_cp_write_eir cp; + + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(&cp, 0, sizeof(cp)); + + hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); + } } if (hdev->features[3] & LMP_RSSI_INQ) -- cgit v1.2.3-70-g09d2 From 97e0bdeb93cc9bd014c21d5400af4fa7f2fe2f91 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 13:49:28 +0100 Subject: Bluetooth: Enable timestamps for control channel The control channel can be also monitored, so include timestamps here as well. And make sure management events get their timestamp when they are created. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 1 + net/bluetooth/mgmt.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index dd563506414..8a814bca00d 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -782,6 +782,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_RAW: hci_sock_cmsg(sk, msg, skb); break; + case HCI_CHANNEL_CONTROL: case HCI_CHANNEL_MONITOR: sock_recv_timestamp(msg, sk, skb); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 08c657df7f8..8b4df0473ec 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -817,6 +817,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (data) memcpy(skb_put(skb, data_len), data, data_len); + /* Time stamp */ + __net_timestamp(skb); + hci_send_to_control(skb, skip_sk); kfree_skb(skb); -- cgit v1.2.3-70-g09d2 From 6c8f12c143fe83485afa530320e6f70dfc1aad54 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 16:35:26 +0200 Subject: Bluetooth: mgmt: Fix Set SSP supported check The test for SSP support needs to be earlier in the set_ssp function so that we return an error when SSP is not supported even when the device is powered off. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8b4df0473ec..ac8ba839a78 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1141,6 +1141,12 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + val = !!cp->val; if (!hdev_is_powered(hdev)) { @@ -1161,12 +1167,6 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, - MGMT_STATUS_NOT_SUPPORTED); - goto failed; - } - if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); goto failed; -- cgit v1.2.3-70-g09d2 From 06199cf86a84206cfdc96b8dc02d5c27efa8c60f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 16:37:11 +0200 Subject: Bluetooth: mgmt: Implement Set LE command This patch implements support for the Set LE mgmt command. Now, in addition to the enable_le module parameter user space needs to send an explicit Enable LE command to enable LE support. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 7 ++- net/bluetooth/mgmt.c | 119 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 126 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 806eb412079..c97cf0872ac 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -96,6 +96,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_HS_ENABLED, + HCI_LE_ENABLED, HCI_CONNECTABLE, HCI_DISCOVERABLE, HCI_LINK_SECURITY, diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6ba3a4b1078..abdaa7900ed 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1010,6 +1010,7 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); +int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 *eir, u16 eir_len); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3476d5c7b02..498b71a0579 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -539,7 +539,7 @@ static void hci_set_le_support(struct hci_dev *hdev) memset(&cp, 0, sizeof(cp)); - if (enable_le) { + if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 1; cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); } @@ -1130,10 +1130,15 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_cp_read_local_ext_features cp; + struct hci_cp_write_le_host_supported *sent; __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); + if (sent && test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_le_enable_complete(hdev, sent->le, status); + if (status) return; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ac8ba839a78..8bc6a7a4873 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -407,7 +407,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (!(hdev->features[4] & LMP_NO_BREDR)) settings |= MGMT_SETTING_BREDR; - if (hdev->host_features[0] & LMP_HOST_LE) + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_LE; if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) @@ -1231,6 +1231,82 @@ failed: return err; } +static int set_le(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct hci_cp_write_le_host_supported hci_cp; + struct pending_cmd *cmd; + struct hci_dev *hdev; + int err; + u8 val; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_LE, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LE, + MGMT_STATUS_INVALID_PARAMS); + + if (!enable_le || !(hdev->features[4] & LMP_LE)) { + err = cmd_status(sk, index, MGMT_OP_SET_LE, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + + val = !!cp->val; + + if (!hdev_is_powered(hdev)) { + bool changed = false; + + if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + change_bit(HCI_LE_ENABLED, &hdev->dev_flags); + changed = true; + } + + err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memset(&hci_cp, 0, sizeof(hci_cp)); + + if (val) { + hci_cp.le = val; + hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, + sizeof(hci_cp), &hci_cp); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_put(hdev); + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2816,6 +2892,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_HS: err = set_hs(sk, index, cp, len); break; + case MGMT_OP_SET_LE: + err = set_le(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; @@ -3521,6 +3600,44 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, return err; } +int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + bool changed = false; + int err = 0; + + if (status) { + u8 mgmt_err = mgmt_status(status); + + if (enable && test_and_clear_bit(HCI_LE_ENABLED, + &hdev->dev_flags)) + err = new_settings(hdev, NULL); + + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, + cmd_status_rsp, &mgmt_err); + + return err; + } + + if (enable) { + if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + changed = true; + } + + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); + + if (changed) + err = new_settings(hdev, match.sk); + + if (match.sk) + sock_put(match.sk); + + return err; +} + int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 *eir, u16 eir_len) -- cgit v1.2.3-70-g09d2 From e59fda8dc14c173b74b5e9d5c8d72849d2ff6b5f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 18:11:53 +0200 Subject: Bluetooth: Fix EIR data clearing when powering off When powering off we should assume that the EIR data isn't valid anymore. This patch makes sure it gets cleared in hci_dev_do_close and thereby ensures that a correct new EIR is recreated when powering on again. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e1dadeea4c2..2d75ffb42f7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -794,6 +794,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Clear flags */ hdev->flags = 0; + memset(hdev->eir, 0, sizeof(hdev->eir)); + hci_req_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3-70-g09d2 From f51d5b248981d05269e4f83ab8f8ed7ed494fe33 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 18:17:32 +0200 Subject: Bluetooth: mgmt: Fix updating EIR when updating the name Whenever we update the local device name the EIR data also needs to be updated to reflect this. The update_eir() function in mgmt.c depends on hdev->dev_name to be up to date so the patch also makes sure that the mgmt function is called from hci_event.c after the update has happened. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 498b71a0579..e44e3fd6862 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -209,12 +209,12 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_set_local_name_complete(hdev, sent, status); - if (status == 0) memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_set_local_name_complete(hdev, sent, status); + hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8bc6a7a4873..d756644163b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3561,6 +3561,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) send_event: err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); + update_eir(hdev); failed: if (cmd) -- cgit v1.2.3-70-g09d2 From 24c54a90527ca5b85e7feedde2c779dc056ffddb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 18:06:34 +0100 Subject: Bluetooth: Disabling discoverable with timeout is invalid Add one extra sanity check to ensure that the supplied timeout value is actually valid in this context. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d756644163b..6df4af6e99c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -850,13 +850,16 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); + timeout = get_unaligned_le16(&cp->timeout); + if (!cp->val && timeout > 0) + return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + MGMT_STATUS_INVALID_PARAMS); + hdev = hci_dev_get(index); if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); - timeout = get_unaligned_le16(&cp->timeout); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev) && timeout > 0) { -- cgit v1.2.3-70-g09d2 From 955638ecec9431788e291fc99f34c42124071abe Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 18:21:00 +0100 Subject: Bluetooth: Fix handling of discoverable setting with timeout The current handling of the discoverable timeout was missing the proper handling of the timeout when the mode was already set. Now the command can be used to expire or retrigger the timeout. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6df4af6e99c..f7e111f3043 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -900,6 +900,17 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) } if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { + if (hdev->discov_timeout > 0) { + cancel_delayed_work(&hdev->discov_off); + hdev->discov_timeout = 0; + } + + if (cp->val && timeout > 0) { + hdev->discov_timeout = timeout; + queue_delayed_work(hdev->workqueue, &hdev->discov_off, + msecs_to_jiffies(hdev->discov_timeout * 1000)); + } + err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); goto failed; } -- cgit v1.2.3-70-g09d2 From 7f9a903c57bb42b9f7ad8fb7867859d3252229ab Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 18:38:01 +0100 Subject: Bluetooth: Send management event for class of device changes Currently there are no events to other management sockets if the class of device got changed. So make sure they are sent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_event.c | 13 +++++++++---- net/bluetooth/mgmt.c | 10 ++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index abdaa7900ed..24dd770d442 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1007,6 +1007,8 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); +int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, + u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, u8 *randomizer, u8 status); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e44e3fd6862..c79ffb95555 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -350,14 +350,19 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - return; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV); if (!sent) return; - memcpy(hdev->dev_class, sent, 3); + hci_dev_lock(hdev); + + if (status == 0) + memcpy(hdev->dev_class, sent, 3); + + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_set_class_of_dev_complete(hdev, sent, status); + + hci_dev_unlock(hdev); } static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f7e111f3043..16bddd22713 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3546,6 +3546,16 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) return err; } +int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, + u8 status) +{ + int err; + + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL); + + return err; +} + int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; -- cgit v1.2.3-70-g09d2 From 490c5baba7a5ad80782d5eb778638d1cfc8d70ce Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 19:19:09 +0200 Subject: Bluetooth: Add hdev->short_name for EIR generation It's possible to provide a short name through the mgmt interface and this name can be used for EIR generation when the full name doesn't fit there. This patch adds the preliminary tracking of the provided short name. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 +++ include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/mgmt.c | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 24dd770d442..3fcc7f0d08c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -129,6 +129,8 @@ struct le_scan_params { int timeout; }; +#define HCI_MAX_SHORT_NAME_LENGTH 10 + #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; @@ -141,6 +143,7 @@ struct hci_dev { __u8 dev_type; bdaddr_t bdaddr; __u8 dev_name[HCI_MAX_NAME_LENGTH]; + __u8 short_name[HCI_MAX_SHORT_NAME_LENGTH]; __u8 eir[HCI_MAX_EIR_LENGTH]; __u8 dev_class[3]; __u8 major_class; diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ac59cdd0fa1..495668c77fb 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -75,7 +75,7 @@ struct mgmt_rp_read_index_list { /* Reserve one extra byte for names in management messages so that they * are always guaranteed to be nul-terminated */ #define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) -#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1) +#define MGMT_MAX_SHORT_NAME_LENGTH (HCI_MAX_SHORT_NAME_LENGTH + 1) #define MGMT_SETTING_POWERED 0x00000001 #define MGMT_SETTING_CONNECTABLE 0x00000002 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 16bddd22713..3f6a2df9d15 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2273,6 +2273,9 @@ static int set_local_name(struct sock *sk, u16 index, void *data, goto failed; } + memcpy(hdev->short_name, mgmt_cp->short_name, + sizeof(hdev->short_name)); + memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), &hci_cp); -- cgit v1.2.3-70-g09d2 From db99b5fc77e6cec47d80703b471f1efe04527d2f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 20:14:22 +0200 Subject: Bluetooth: Fix read_name updating when HCI_SETUP is not set The local name should only be updated as a consequence of a hci_read_local_name if we are in the HCI_SETUP state. In all other scenarios it should only be updated through hci_write_local_name. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c79ffb95555..9917fe3d1d1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -227,7 +227,8 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); + if (test_bit(HCI_SETUP, &hdev->dev_flags)) + memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); } static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 28cc7bde5978cbc58c9026123fa5f33b62ad66b3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 21:06:55 +0200 Subject: Bluetooth: mgmt: Allow local name changes while powered off This patch makes it possible to set the local name before powering on the device. The name will be applied using the hci_write_local_name command once the device gets powered on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 13 ++++++++++--- net/bluetooth/mgmt.c | 38 ++++++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9917fe3d1d1..9b30587c0de 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -209,11 +209,10 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (status == 0) - memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); - if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_set_local_name_complete(hdev, sent, status); + else if (!status) + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); hci_dev_unlock(hdev); } @@ -563,6 +562,14 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); + if (!test_bit(HCI_SETUP, &hdev->dev_flags) && + test_bit(HCI_MGMT, &hdev->dev_flags)) { + struct hci_cp_write_local_name cp; + + memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); + hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); + } + if (hdev->features[6] & LMP_SIMPLE_PAIR) { if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3f6a2df9d15..9c1f7714794 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2260,22 +2260,29 @@ static int set_local_name(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); + memcpy(hdev->short_name, mgmt_cp->short_name, + sizeof(hdev->short_name)); + if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, - MGMT_STATUS_NOT_POWERED); + memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name)); + + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, + data, len); + if (err < 0) + goto failed; + + err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len, + sk); + goto failed; } - cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, - len); + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); if (!cmd) { err = -ENOMEM; goto failed; } - memcpy(hdev->short_name, mgmt_cp->short_name, - sizeof(hdev->short_name)); - memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), &hci_cp); @@ -3563,10 +3570,17 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; struct mgmt_cp_set_local_name ev; - int err; + bool changed = false; + int err = 0; + + if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) { + memcpy(hdev->dev_name, name, sizeof(hdev->dev_name)); + changed = true; + } memset(&ev, 0, sizeof(ev)); memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH); cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev); if (!cmd) @@ -3578,16 +3592,16 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) goto failed; } - update_eir(hdev); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev, sizeof(ev)); if (err < 0) goto failed; send_event: - err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); + if (changed) + err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, + sizeof(ev), cmd ? cmd->sk : NULL); + update_eir(hdev); failed: -- cgit v1.2.3-70-g09d2 From 7bdaae4a4bc075cf73ab9c3a531b7229caa1f49e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 21:39:58 +0200 Subject: Bluetooth: mgmt: Fix name_changed event for short name changes Since we can't reliably track the short name changes just assume that we had a change whenever there's a pending mgmt command. In the worst case we just get one unnecessary name_changed signal. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9c1f7714794..ee57edbb13e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3586,6 +3586,10 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) if (!cmd) goto send_event; + /* Always assume that either the short or the complete name has + * changed if there was a pending mgmt command */ + changed = true; + if (status) { err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, mgmt_status(status)); -- cgit v1.2.3-70-g09d2 From 27fcc362297b8e838a929c947b82eabb3f4b7591 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 21:46:22 +0200 Subject: Bluetooth: mgmt: Fix missing short_name in read_info The short name is part of the Read Controller Info response and should be appropriately filled in based on the value of hdev->short_name. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ee57edbb13e..6850a8b46c6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -648,6 +648,7 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.dev_class, hdev->dev_class, 3); memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); + memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3-70-g09d2 From 09b3c3fbbee9aef8ac5d9148ae61aae35766b2a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:01:41 +0200 Subject: Bluetooth: Fix clearing of dev_class when powering down We should assume a value of 0 for the device class when powered off. The appropriate place to do this is in hci_dev_do_close(). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2d75ffb42f7..2ab78bfc108 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -795,6 +795,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->flags = 0; memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); hci_req_unlock(hdev); -- cgit v1.2.3-70-g09d2 From 8ec37034ef36b89cfb060bd9273db24e6acb1b3a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:02:50 +0200 Subject: Bluetooth: mgmt: Fix return value for set_class The return parameters for Set Device Class should consist of the new class value. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6850a8b46c6..23421f05abf 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1470,7 +1470,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, - NULL, 0); + hdev->dev_class, 3); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3-70-g09d2 From 7770c4aacaf34fb69cb2acfb7469e9b4e34f1674 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:06:38 +0200 Subject: Bluetooth: mgmt: Check for HCI_UP in update_eir() and update_class() These functions should just silently fail when we're not powered on instead of trying to send HCI commands. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 23421f05abf..3a2066504ff 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -532,6 +532,9 @@ static int update_eir(struct hci_dev *hdev) { struct hci_cp_write_eir cp; + if (!test_bit(HCI_UP, &hdev->flags)) + return 0; + if (!(hdev->features[6] & LMP_EXT_INQ)) return 0; @@ -570,6 +573,9 @@ static int update_class(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + if (!test_bit(HCI_UP, &hdev->flags)) + return 0; + if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return 0; -- cgit v1.2.3-70-g09d2 From 932f5ff5e32bf520eb9287b050c926faa6e76bcf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:11:32 +0200 Subject: Bluetooth: mgmt: Allow class of device changes while powered off This patch makes it possible to set the class when powered off. When powering on the right class of device value will be automatically writen to the controller. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3a2066504ff..a45c2b70dfd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1456,15 +1456,15 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + hdev->major_class = cp->major; + hdev->minor_class = cp->minor; + if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_NOT_POWERED); + err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + hdev->dev_class, 3); goto unlock; } - hdev->major_class = cp->major; - hdev->minor_class = cp->minor; - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { hci_dev_unlock(hdev); cancel_delayed_work_sync(&hdev->service_cache); -- cgit v1.2.3-70-g09d2 From 5f97c1df5563349795f26ed249e2a8840237c569 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:41:18 +0200 Subject: Bluetooth: mgmt: Add missing powered checks to commands This patch adds missing powered checks to pair_device, cancel_pair_device, add_remote_oob_data and remove_remote_oob_data. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a45c2b70dfd..7c7bc2a2139 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1735,6 +1735,12 @@ static int get_connections(struct sock *sk, u16 index) hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + count = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) @@ -1766,8 +1772,9 @@ static int get_connections(struct sock *sk, u16 index) err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len); -unlock: kfree(rp); + +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -2002,6 +2009,12 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + sec_level = BT_SECURITY_MEDIUM; if (cp->io_cap == 0x03) auth_type = HCI_AT_DEDICATED_BONDING; @@ -2084,6 +2097,12 @@ static int cancel_pair_device(struct sock *sk, u16 index, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); if (!cmd) { err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, @@ -2375,6 +2394,13 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, cp->randomizer); if (err < 0) @@ -2385,6 +2411,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2413,6 +2440,13 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); if (err < 0) status = MGMT_STATUS_INVALID_PARAMS; @@ -2422,6 +2456,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3-70-g09d2 From 86a8cfc6d0428f32d702ec59c1b3ef38541a6821 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:53:34 +0200 Subject: Bluetooth: mgmt: Fix unpair_device responses This patch adds an error return when not powered and cleans up/simpifies the function logic in the same go. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7c7bc2a2139..36bebfb2d84 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1561,7 +1561,6 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; - u8 status = 0; int err; if (len != sizeof(*cp)) @@ -1579,32 +1578,38 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + MGMT_STATUS_NOT_POWERED, + &rp, sizeof(rp)); + goto unlock; + } + if (cp->addr.type == MGMT_ADDR_BREDR) err = hci_remove_link_key(hdev, &cp->addr.bdaddr); else err = hci_remove_ltk(hdev, &cp->addr.bdaddr); if (err < 0) { - status = MGMT_STATUS_NOT_PAIRED; - goto unlock; - } - - if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, - &rp, sizeof(rp)); - device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + MGMT_STATUS_NOT_PAIRED, + &rp, sizeof(rp)); goto unlock; } - if (cp->addr.type == MGMT_ADDR_BREDR) - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + if (cp->disconnect) { + if (cp->addr.type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); - else - conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, + else + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); + } else { + conn = NULL; + } if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0, &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; @@ -1624,9 +1629,6 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) mgmt_pending_remove(cmd); unlock: - if (err < 0) - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, - &rp, sizeof(rp)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3-70-g09d2 From 9a395a80dc6a2004787539dcc0c7d167ba87e89a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 00:00:32 +0200 Subject: Bluetooth: mgmt: Fix device_found parameters According to the latest mgmt API there's a flags field instead of a separate confirm_name paramter. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 5 ++++- net/bluetooth/mgmt.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 495668c77fb..09646f5ef36 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -393,11 +393,14 @@ struct mgmt_ev_auth_failed { __u8 status; } __packed; +#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01 +#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02 + #define MGMT_EV_DEVICE_FOUND 0x0012 struct mgmt_ev_device_found { struct mgmt_addr_info addr; __s8 rssi; - __u8 confirm_name; + __u8 flags[4]; __le16 eir_len; __u8 eir[0]; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 36bebfb2d84..b7b10ca297d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3745,7 +3745,8 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev->addr.bdaddr, bdaddr); ev->addr.type = link_to_mgmt(link_type, addr_type); ev->rssi = rssi; - ev->confirm_name = cfm_name; + if (cfm_name) + ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME; if (eir_len > 0) memcpy(ev->eir, eir, eir_len); -- cgit v1.2.3-70-g09d2 From 388fc8faf200f80159353eb86cde4ab75d0a0bbd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 00:38:59 +0200 Subject: Bluetooth: mgmt: Add legacy pairing info to dev_found events This patch makes sure that legacy pairing vs SSP infomation gets properly propageted to the device_found events in the form of the legacy pairing flag. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/hci_core.c | 8 +++++++- net/bluetooth/hci_event.c | 26 ++++++++++++++------------ net/bluetooth/mgmt.c | 4 +++- 4 files changed, 27 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3fcc7f0d08c..720bdc26b7e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -407,7 +407,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, struct inquiry_entry *ie); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known); + bool name_known, bool *ssp); /* ----- HCI Connections ----- */ enum { @@ -1018,7 +1018,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 *eir, u16 eir_len); + u8 cfm_name, u8 ssp, u8 *eir, + u16 eir_len); int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, s8 rssi, u8 *name, u8 name_len); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2ab78bfc108..e6cbb8a1f47 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -466,15 +466,21 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, } bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known) + bool name_known, bool *ssp) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); + if (ssp) + *ssp = data->ssp_mode; + ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); if (ie) { + if (ie->data.ssp_mode && ssp) + *ssp = true; + if (ie->name_state == NAME_NEEDED && data->rssi != ie->data.rssi) { ie->data.rssi = data->rssi; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9b30587c0de..276f3ac0608 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1696,7 +1696,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { - bool name_known; + bool name_known, ssp; bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -1707,9 +1707,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * data.rssi = 0x00; data.ssp_mode = 0x00; - name_known = hci_inquiry_cache_update(hdev, &data, false); + name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, !name_known, + info->dev_class, 0, !name_known, ssp, NULL, 0); } @@ -2783,7 +2783,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct { struct inquiry_data data; int num_rsp = *((__u8 *) skb->data); - bool name_known; + bool name_known, ssp; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); @@ -2807,10 +2807,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL, 0); + !name_known, ssp, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2825,10 +2825,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.rssi = info->rssi; data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL, 0); + !name_known, ssp, NULL, 0); } } @@ -2964,7 +2964,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { - bool name_known; + bool name_known, ssp; bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -2982,10 +2982,11 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct else name_known = true; - name_known = hci_inquiry_cache_update(hdev, &data, name_known); + name_known = hci_inquiry_cache_update(hdev, &data, name_known, + &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, info->data, + !name_known, ssp, info->data, sizeof(info->data)); } @@ -3310,7 +3311,8 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, - NULL, rssi, 0, ev->data, ev->length); + NULL, rssi, 0, 1, ev->data, + ev->length); ptr += sizeof(*ev) + ev->length + 1; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b7b10ca297d..42d665bdc01 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3730,7 +3730,7 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 *eir, u16 eir_len) + u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len) { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; @@ -3747,6 +3747,8 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev->rssi = rssi; if (cfm_name) ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME; + if (!ssp) + ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING; if (eir_len > 0) memcpy(ev->eir, eir, eir_len); -- cgit v1.2.3-70-g09d2 From 643162a8e2c15a1c1983a0063d9941240b3bde30 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 17:11:55 +0200 Subject: Bluetooth: Add unlocked __l2cap_chan_add function Add unlocked L2CAP channel add function. Unlocked version will be used in later patches. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c0640b73c62..0e4f4cb2acb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -300,7 +300,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) l2cap_chan_put(chan); } -static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, chan->psm, chan->dcid); @@ -346,8 +346,13 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_chan_hold(chan); - mutex_lock(&conn->chan_lock); list_add(&chan->list, &conn->chan_l); +} + +void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +{ + mutex_lock(&conn->chan_lock); + __l2cap_chan_add(conn, chan); mutex_unlock(&conn->chan_lock); } -- cgit v1.2.3-70-g09d2 From 6be3655552ee49aa2b5fd20fa1b08f28d0feac86 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 17:11:56 +0200 Subject: Bluetooth: Change sk lock to chan lock in L2CAP core Change sk lock to chan lock in l2cap core and move sk locks to l2cap sock code. bh_locks were used because of being RCU critical section. When needed use explicit socket locks. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 166 ++++++++++++++++++++++++++------------------- net/bluetooth/l2cap_sock.c | 18 ++++- 2 files changed, 114 insertions(+), 70 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0e4f4cb2acb..5f4cfea3391 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -238,13 +238,12 @@ static void l2cap_chan_timeout(struct work_struct *work) struct l2cap_chan *chan = container_of(work, struct l2cap_chan, chan_timer.work); struct l2cap_conn *conn = chan->conn; - struct sock *sk = chan->sk; int reason; BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); mutex_lock(&conn->chan_lock); - lock_sock(sk); + l2cap_chan_lock(chan); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) reason = ECONNREFUSED; @@ -256,7 +255,7 @@ static void l2cap_chan_timeout(struct work_struct *work) l2cap_chan_close(chan, reason); - release_sock(sk); + l2cap_chan_unlock(chan); chan->ops->close(chan->data); mutex_unlock(&conn->chan_lock); @@ -356,8 +355,6 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) mutex_unlock(&conn->chan_lock); } -/* Delete channel. - * Must be called on the locked socket. */ static void l2cap_chan_del(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; @@ -378,6 +375,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) hci_conn_put(conn->hcon); } + lock_sock(sk); + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); @@ -390,6 +389,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); + release_sock(sk); + if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) && test_bit(CONF_INPUT_DONE, &chan->conf_state))) return; @@ -422,10 +423,10 @@ static void l2cap_chan_cleanup_listen(struct sock *parent) while ((sk = bt_accept_dequeue(parent, NULL))) { struct l2cap_chan *chan = l2cap_pi(sk)->chan; + l2cap_chan_lock(chan); __clear_chan_timer(chan); - lock_sock(sk); l2cap_chan_close(chan, ECONNRESET); - release_sock(sk); + l2cap_chan_unlock(chan); chan->ops->close(chan->data); } @@ -441,10 +442,12 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) switch (chan->state) { case BT_LISTEN: + lock_sock(sk); l2cap_chan_cleanup_listen(sk); __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); + release_sock(sk); break; case BT_CONNECTED: @@ -487,7 +490,9 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) break; default: + lock_sock(sk); sock_set_flag(sk, SOCK_ZAPPED); + release_sock(sk); break; } } @@ -715,6 +720,7 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) { + struct sock *sk = chan->sk; struct l2cap_disconn_req req; if (!conn) @@ -731,8 +737,10 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); + lock_sock(sk); __l2cap_state_change(chan, BT_DISCONN); __l2cap_chan_set_err(chan, err); + release_sock(sk); } /* ---- L2CAP connections ---- */ @@ -747,10 +755,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn) list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; - bh_lock_sock(sk); + l2cap_chan_lock(chan); if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -759,17 +767,15 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (!l2cap_chan_check_security(chan) || !__l2cap_no_conn_pending(chan)) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (!l2cap_mode_supported(chan->mode, conn->feat_mask) && test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) { - /* l2cap_chan_close() calls list_del(chan) - * so release the lock */ l2cap_chan_close(chan, ECONNRESET); - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -789,6 +795,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.dcid = cpu_to_le16(chan->scid); if (l2cap_chan_check_security(chan)) { + lock_sock(sk); if (bt_sk(sk)->defer_setup) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); @@ -801,6 +808,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); } + release_sock(sk); } else { rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); @@ -811,7 +819,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (test_bit(CONF_REQ_SENT, &chan->conf_state) || rsp.result != L2CAP_CR_SUCCESS) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -821,7 +829,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) chan->num_conf_req++; } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } mutex_unlock(&conn->chan_lock); @@ -910,7 +918,11 @@ clean: static void l2cap_chan_ready(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - struct sock *parent = bt_sk(sk)->parent; + struct sock *parent; + + lock_sock(sk); + + parent = bt_sk(sk)->parent; BT_DBG("sk %p, parent %p", sk, parent); @@ -922,6 +934,8 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) if (parent) parent->sk_data_ready(parent, 0); + + release_sock(sk); } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -939,23 +953,25 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; - bh_lock_sock(sk); + l2cap_chan_lock(chan); if (conn->hcon->type == LE_LINK) { if (smp_conn_security(conn, chan->sec_level)) l2cap_chan_ready(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { + struct sock *sk = chan->sk; __clear_chan_timer(chan); + lock_sock(sk); __l2cap_state_change(chan, BT_CONNECTED); sk->sk_state_change(sk); + release_sock(sk); } else if (chan->state == BT_CONNECT) l2cap_do_start(chan); - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } mutex_unlock(&conn->chan_lock); @@ -993,7 +1009,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan, *l; - struct sock *sk; if (!conn) return; @@ -1006,10 +1021,12 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); + l2cap_chan_del(chan, err); - release_sock(sk); + + l2cap_chan_unlock(chan); + chan->ops->close(chan->data); } @@ -1140,7 +1157,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d hci_dev_lock(hdev); - lock_sock(sk); + l2cap_chan_lock(chan); /* PSM must be odd and lsb of upper byte must be 0 */ if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && @@ -1167,17 +1184,21 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d goto done; } + lock_sock(sk); + switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: /* Already connecting */ err = 0; + release_sock(sk); goto done; case BT_CONNECTED: /* Already connected */ err = -EISCONN; + release_sock(sk); goto done; case BT_OPEN: @@ -1187,11 +1208,15 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d default: err = -EBADFD; + release_sock(sk); goto done; } /* Set destination address and psm */ bacpy(&bt_sk(sk)->dst, dst); + + release_sock(sk); + chan->psm = psm; chan->dcid = cid; @@ -1219,16 +1244,18 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d /* Update source addr of the socket */ bacpy(src, conn->src); + l2cap_chan_unlock(chan); l2cap_chan_add(conn, chan); + l2cap_chan_lock(chan); - __l2cap_state_change(chan, BT_CONNECT); + l2cap_state_change(chan, BT_CONNECT); __set_chan_timer(chan, sk->sk_sndtimeo); if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); if (l2cap_chan_check_security(chan)) - __l2cap_state_change(chan, BT_CONNECTED); + l2cap_state_change(chan, BT_CONNECTED); } else l2cap_do_start(chan); } @@ -1236,6 +1263,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d err = 0; done: + l2cap_chan_unlock(chan); hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1277,14 +1305,14 @@ static void l2cap_monitor_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, monitor_timer.work); - struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - lock_sock(sk); + l2cap_chan_lock(chan); + if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); - release_sock(sk); + l2cap_chan_unlock(chan); return; } @@ -1292,25 +1320,26 @@ static void l2cap_monitor_timeout(struct work_struct *work) __set_monitor_timer(chan); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - release_sock(sk); + l2cap_chan_unlock(chan); } static void l2cap_retrans_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, retrans_timer.work); - struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - lock_sock(sk); + l2cap_chan_lock(chan); + chan->retry_count = 1; __set_monitor_timer(chan); set_bit(CONN_WAIT_F, &chan->conn_state); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - release_sock(sk); + + l2cap_chan_unlock(chan); } static void l2cap_drop_acked_frames(struct l2cap_chan *chan) @@ -2001,9 +2030,11 @@ static void l2cap_ack_timeout(struct work_struct *work) BT_DBG("chan %p", chan); - lock_sock(chan->sk); + l2cap_chan_lock(chan); + __l2cap_send_ack(chan); - release_sock(chan->sk); + + l2cap_chan_unlock(chan); l2cap_chan_put(chan); } @@ -2664,7 +2695,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd bt_accept_enqueue(parent, sk); - l2cap_chan_add(conn, chan); + __l2cap_chan_add(conn, chan); dcid = chan->scid; @@ -2737,7 +2768,6 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; struct l2cap_chan *chan; - struct sock *sk; u8 req[128]; int err; @@ -2767,8 +2797,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd err = 0; - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); switch (result) { case L2CAP_CR_SUCCESS: @@ -2794,7 +2823,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; } - release_sock(sk); + l2cap_chan_unlock(chan); unlock: mutex_unlock(&conn->chan_lock); @@ -2819,7 +2848,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u8 rsp[64]; struct l2cap_chan *chan; - struct sock *sk; int len; dcid = __le16_to_cpu(req->dcid); @@ -2831,8 +2859,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return -ENOENT; - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -2921,7 +2948,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } unlock: - release_sock(sk); + l2cap_chan_unlock(chan); return 0; } @@ -2930,7 +2957,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; struct l2cap_chan *chan; - struct sock *sk; int len = cmd->len - sizeof(*rsp); scid = __le16_to_cpu(rsp->scid); @@ -2944,8 +2970,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return 0; - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); switch (result) { case L2CAP_CONF_SUCCESS: @@ -3004,7 +3029,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } default: - __l2cap_chan_set_err(chan, ECONNRESET); + l2cap_chan_set_err(chan, ECONNRESET); __set_chan_timer(chan, msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); @@ -3031,7 +3056,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } done: - release_sock(sk); + l2cap_chan_unlock(chan); return 0; } @@ -3056,17 +3081,21 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd return 0; } + l2cap_chan_lock(chan); + sk = chan->sk; - lock_sock(sk); rsp.dcid = cpu_to_le16(chan->scid); rsp.scid = cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); + lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; + release_sock(sk); l2cap_chan_del(chan, ECONNRESET); - release_sock(sk); + + l2cap_chan_unlock(chan); chan->ops->close(chan->data); @@ -3080,7 +3109,6 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; u16 dcid, scid; struct l2cap_chan *chan; - struct sock *sk; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); @@ -3095,11 +3123,11 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; } - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); l2cap_chan_del(chan, 0); - release_sock(sk); + + l2cap_chan_unlock(chan); chan->ops->close(chan->data); @@ -4251,7 +4279,6 @@ drop: static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct l2cap_chan *chan; - struct sock *sk = NULL; u32 control; u16 tx_seq; int len; @@ -4259,11 +4286,12 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk chan = l2cap_get_chan_by_scid(conn, cid); if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); - goto drop; + /* Drop packet and return */ + kfree(skb); + return 0; } - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); BT_DBG("chan %p, len %d", chan, skb->len); @@ -4334,8 +4362,7 @@ drop: kfree_skb(skb); done: - if (sk) - release_sock(sk); + l2cap_chan_unlock(chan); return 0; } @@ -4554,9 +4581,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; - - bh_lock_sock(sk); + l2cap_chan_lock(chan); BT_DBG("chan->scid %d", chan->scid); @@ -4566,19 +4591,19 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) l2cap_chan_ready(chan); } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (!status && (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)) { l2cap_check_encryption(chan, encrypt); - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -4599,9 +4624,12 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); } } else if (chan->state == BT_CONNECT2) { + struct sock *sk = chan->sk; struct l2cap_conn_rsp rsp; __u16 res, stat; + lock_sock(sk); + if (!status) { if (bt_sk(sk)->defer_setup) { struct sock *parent = bt_sk(sk)->parent; @@ -4622,6 +4650,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) stat = L2CAP_CS_NO_INFO; } + release_sock(sk); + rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(res); @@ -4630,7 +4660,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) sizeof(rsp), &rsp); } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } mutex_unlock(&conn->chan_lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1273fcbeec2..73a06c1b0cd 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -127,6 +127,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al if (err) goto done; + lock_sock(sk); + err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); done: @@ -810,14 +812,18 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) if (conn) mutex_lock(&conn->chan_lock); + l2cap_chan_lock(chan); lock_sock(sk); + if (!sk->sk_shutdown) { if (chan->mode == L2CAP_MODE_ERTM) err = __l2cap_wait_ack(sk); sk->sk_shutdown = SHUTDOWN_MASK; + release_sock(sk); l2cap_chan_close(chan, 0); + lock_sock(sk); if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) err = bt_sock_wait_state(sk, BT_CLOSED, @@ -828,6 +834,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = -sk->sk_err; release_sock(sk); + l2cap_chan_unlock(chan); if (conn) mutex_unlock(&conn->chan_lock); @@ -874,8 +881,12 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb) struct sock *sk = data; struct l2cap_pinfo *pi = l2cap_pi(sk); - if (pi->rx_busy_skb) - return -ENOMEM; + lock_sock(sk); + + if (pi->rx_busy_skb) { + err = -ENOMEM; + goto done; + } err = sock_queue_rcv_skb(sk, skb); @@ -894,6 +905,9 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb) err = 0; } +done: + release_sock(sk); + return err; } -- cgit v1.2.3-70-g09d2 From b3fb611ec7b76048cb14600e9a5a9b57e5d913da Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 17:11:57 +0200 Subject: Bluetooth: Remove socket lock check Simplify code so that we do not need to check whether socket is locked. Signed-off-by: Andrei Emeltchenko Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 73a06c1b0cd..52c94c76577 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -125,15 +125,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); if (err) - goto done; + return err; lock_sock(sk); err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); -done: - if (sock_owned_by_user(sk)) - release_sock(sk); + + release_sock(sk); + return err; } -- cgit v1.2.3-70-g09d2 From 60fc5fb66efa0bcbe028637206ed59df8cd4ac19 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 09:52:28 +0200 Subject: Bluetooth: mgmt: Fix count parameter in get_connections reply This patch fixes the count parameter in the Get Connections reply message. We cannot know the right number until iterating through all connections so set the parameter value only after the loop. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 42d665bdc01..7fdba8fb980 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1725,8 +1725,8 @@ static int get_connections(struct sock *sk, u16 index) struct hci_dev *hdev; struct hci_conn *c; size_t rp_len; - u16 count; - int i, err; + int err; + u16 i; BT_DBG(""); @@ -1743,21 +1743,19 @@ static int get_connections(struct sock *sk, u16 index) goto unlock; } - count = 0; + i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) - count++; + i++; } - rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info)); + rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); rp = kmalloc(rp_len, GFP_ATOMIC); if (!rp) { err = -ENOMEM; goto unlock; } - put_unaligned_le16(count, &rp->conn_count); - i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) @@ -1769,6 +1767,8 @@ static int get_connections(struct sock *sk, u16 index) i++; } + put_unaligned_le16(i, &rp->conn_count); + /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); -- cgit v1.2.3-70-g09d2 From 69775ff6d101ccf435bd26ae822c24bbb20e11cf Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 23 Feb 2012 16:50:05 +0200 Subject: Bluetooth: Set DISCOVERY_STOPPED if controller resets If controller is reset during the discovery procedure, Start Discovery command stops working. This can be easily reproduced by running "hciconfig hci0 reset" while discovering devices, for instance. We should force discovery state to DISCOVERY_STOPPED in case we receive a reset command complete event. Otherwise we may stuck in one of the active discovery states (DISCOVERY_INQUIRY, DISCOVERY_LE_SCAN and DISCOVERY_RESOLVING) and subsequent Start Discovery commands will simply fail. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 276f3ac0608..3d1eef0df2a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -194,6 +194,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) /* Reset all non-persistent flags */ hdev->dev_flags &= ~(BIT(HCI_LE_SCAN)); + + hdev->discovery.state = DISCOVERY_STOPPED; } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 504c8dcd6b0ec3cd36ab221695c5516e88cf3d79 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 13:30:41 +0200 Subject: Bluetooth: mgmt: Fix update_eir/class with HCI_AUTO_OFF flag set If we're powered but still have the HCI_AUTO_OFF flag set the update_eir and update_class functions should not do anything. Additionally these functions need to be called when the flag is finally cleared through set_powered or when powering on for real. Signed-off-by: Johan Hedberg Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7fdba8fb980..4e488949063 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -532,7 +532,7 @@ static int update_eir(struct hci_dev *hdev) { struct hci_cp_write_eir cp; - if (!test_bit(HCI_UP, &hdev->flags)) + if (!hdev_is_powered(hdev)) return 0; if (!(hdev->features[6] & LMP_EXT_INQ)) @@ -573,7 +573,7 @@ static int update_class(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (!test_bit(HCI_UP, &hdev->flags)) + if (!hdev_is_powered(hdev)) return 0; if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) @@ -3121,6 +3121,9 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) if (scan) hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + + update_class(hdev); + update_eir(hdev); } else { u8 status = ENETDOWN; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); -- cgit v1.2.3-70-g09d2 From 9997a5332320dbaaee64b5c0581ccaa6589a15c9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 15:57:46 +0200 Subject: Bluetooth: mgmt: Fix return value of add/remove_uuid The Add/Remove UUID commands should return the device class instead of an empty parameter list. Signed-off-by: Johan Hedberg Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4e488949063..000abc07bc1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1367,7 +1367,7 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3); failed: hci_dev_unlock(hdev); @@ -1428,7 +1428,8 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto unlock; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + hdev->dev_class, 3); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3-70-g09d2 From 4004b6d96a14edbd157a62ae25bf61022d7caccc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 21:30:12 +0200 Subject: Bluetooth: mgmt: Move service cache setting to a more sensible place Since we can now add UUIDs when powered off we don't really need to always use the service cache to avoid large bursts of HCI commands. Instead, the only important use case is when we're already powered and user space starts to initialize itself. This can be easiest detected by a "clear UUIDs" operation which is where this patch moves the service cache setting. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 000abc07bc1..30a30b7b301 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -617,10 +617,6 @@ static void mgmt_init_hdev(struct hci_dev *hdev) */ clear_bit(HCI_PAIRABLE, &hdev->dev_flags); } - - if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) - schedule_delayed_work(&hdev->service_cache, - msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); } static int read_controller_info(struct sock *sk, u16 index) @@ -1399,6 +1395,12 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); + + if (hdev_is_powered(hdev) && + !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) + schedule_delayed_work(&hdev->service_cache, + msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + goto unlock; } -- cgit v1.2.3-70-g09d2 From 9246a8693e74b3480913cf6e0c2d472267169990 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 21:33:16 +0200 Subject: Bluetooth: mgmt: Fix clear UUIDs response We also need to send a proper response when clearing UUIDs. This patch adds fixes the missing response for this use case. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 30a30b7b301..93f2c1348ad 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1401,7 +1401,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) schedule_delayed_work(&hdev->service_cache, msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); - goto unlock; + goto update_class; } found = 0; @@ -1422,6 +1422,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) goto unlock; } +update_class: err = update_class(hdev); if (err < 0) goto unlock; -- cgit v1.2.3-70-g09d2 From 08c79b6133b70a6e3d462d11a89c80259ac66ec7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 22:31:51 +0200 Subject: Bluetooth: mgmt: Add flags parameter to device_connected This patch updates the Device Connected events to match the latest API by adding a flags parameter to them. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ++-- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/hci_event.c | 8 ++++---- net/bluetooth/mgmt.c | 6 ++++-- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 720bdc26b7e..facd7ed32b7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -980,8 +980,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent); int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *name, u8 name_len, - u8 *dev_class); + u8 addr_type, u32 flags, u8 *name, + u8 name_len, u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 09646f5ef36..7aab53e6b81 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -357,6 +357,7 @@ struct mgmt_ev_new_long_term_key { #define MGMT_EV_DEVICE_CONNECTED 0x000B struct mgmt_ev_device_connected { struct mgmt_addr_info addr; + __le32 flags; __le16 eir_len; __u8 eir[0]; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3d1eef0df2a..fb6543b60de 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1368,7 +1368,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, struct inquiry_entry *e; if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) - mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, + mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name, name_len, conn->dev_class); if (discov->state == DISCOVERY_STOPPED) @@ -2104,7 +2104,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, NULL, 0, + conn->dst_type, 0, NULL, 0, conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { @@ -2872,7 +2872,7 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, NULL, 0, + conn->dst_type, 0, NULL, 0, conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { @@ -3282,7 +3282,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type, NULL, 0, 0); + conn->dst_type, 0, NULL, 0, 0); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 93f2c1348ad..79fe5757346 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3249,8 +3249,8 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) } int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *name, u8 name_len, - u8 *dev_class) + u8 addr_type, u32 flags, u8 *name, + u8 name_len, u8 *dev_class) { char buf[512]; struct mgmt_ev_device_connected *ev = (void *) buf; @@ -3259,6 +3259,8 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev->addr.bdaddr, bdaddr); ev->addr.type = link_to_mgmt(link_type, addr_type); + put_unaligned_le32(flags, &ev->flags); + if (name_len > 0) eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, name_len); -- cgit v1.2.3-70-g09d2 From 7ca1e11ab7d83ec76f3a8ef8704adca8c7518f41 Mon Sep 17 00:00:00 2001 From: Danny Kukawka Date: Tue, 21 Feb 2012 02:07:52 +0000 Subject: br_device: unify return value of .ndo_set_mac_address if address is invalid Unify return value of .ndo_set_mac_address if the given address isn't valid. Return -EADDRNOTAVAIL as eth_mac_addr() already does if is_valid_ether_addr() fails. Signed-off-by: Danny Kukawka Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index a157bf827d8..ba829de8442 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -167,7 +167,7 @@ static int br_set_mac_address(struct net_device *dev, void *p) struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; + return -EADDRNOTAVAIL; spin_lock_bh(&br->lock); if (compare_ether_addr(dev->dev_addr, addr->sa_data)) { -- cgit v1.2.3-70-g09d2 From c95f0ba76f902bc8b540468b695bcfe8948e8e46 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 22:54:38 +0200 Subject: Bluetooth: mgmt: Track pending class changes This patch adds a flag to track pending changes to the class of device. This is needed since we cannot cleanly handle multiple simultaneous commands and need to return a "busy" error status in the mgmt commands that might trigger a class change. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/mgmt.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index c97cf0872ac..05bd9aca405 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -100,6 +100,7 @@ enum { HCI_CONNECTABLE, HCI_DISCOVERABLE, HCI_LINK_SECURITY, + HCI_PENDING_CLASS, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 79fe5757346..9f912dc71ba 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -570,6 +570,7 @@ static u8 get_service_classes(struct hci_dev *hdev) static int update_class(struct hci_dev *hdev) { u8 cod[3]; + int err; BT_DBG("%s", hdev->name); @@ -586,7 +587,11 @@ static int update_class(struct hci_dev *hdev) if (memcmp(cod, hdev->dev_class, 3) == 0) return 0; - return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); + err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); + if (err == 0) + set_bit(HCI_PENDING_CLASS, &hdev->dev_flags); + + return err; } static void service_cache_off(struct work_struct *work) @@ -1344,6 +1349,12 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_ADD_UUID, + MGMT_STATUS_BUSY); + goto failed; + } + uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); if (!uuid) { err = -ENOMEM; @@ -1393,6 +1404,12 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + MGMT_STATUS_BUSY); + goto unlock; + } + if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); @@ -1460,6 +1477,12 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + MGMT_STATUS_BUSY); + goto unlock; + } + hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -3259,7 +3282,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev->addr.bdaddr, bdaddr); ev->addr.type = link_to_mgmt(link_type, addr_type); - put_unaligned_le32(flags, &ev->flags); + ev->flags = __cpu_to_le32(flags); if (name_len > 0) eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, @@ -3614,6 +3637,8 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, { int err; + clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags); + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL); return err; -- cgit v1.2.3-70-g09d2 From 90e704543d6702971ecfe3fe2325829d89b76f6b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 23:09:40 +0200 Subject: Bluetooth: mgmt: Fix dev_class related command response timing All mgmt commands that may fire off a hci_write_class_of_device command should wait for the completion of the HCI command before sending a response to user space. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9f912dc71ba..7a906d6e023 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1332,6 +1332,7 @@ failed: static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; + struct pending_cmd *cmd; struct hci_dev *hdev; struct bt_uuid *uuid; int err; @@ -1374,7 +1375,17 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3); + if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, + hdev->dev_class, 3); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } failed: hci_dev_unlock(hdev); @@ -1386,6 +1397,7 @@ failed: static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_remove_uuid *cp = data; + struct pending_cmd *cmd; struct list_head *p, *n; struct hci_dev *hdev; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -1448,8 +1460,17 @@ update_class: if (err < 0) goto unlock; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, hdev->dev_class, 3); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } unlock: hci_dev_unlock(hdev); @@ -1462,6 +1483,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct mgmt_cp_set_dev_class *cp = data; + struct pending_cmd *cmd; int err; BT_DBG("request for hci%u", index); @@ -1500,10 +1522,20 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) } err = update_class(hdev); + if (err < 0) + goto unlock; - if (err == 0) + if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, hdev->dev_class, 3); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } unlock: hci_dev_unlock(hdev); @@ -3110,6 +3142,7 @@ int mgmt_index_removed(struct hci_dev *hdev) struct cmd_lookup { struct sock *sk; struct hci_dev *hdev; + u8 mgmt_status; }; static void settings_rsp(struct pending_cmd *cmd, void *data) @@ -3632,14 +3665,41 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) return err; } +static void class_rsp(struct pending_cmd *cmd, void *data) +{ + struct cmd_lookup *match = data; + + cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status, + match->hdev->dev_class, 3); + + list_del(&cmd->list); + + if (match->sk == NULL) { + match->sk = cmd->sk; + sock_hold(match->sk); + } + + mgmt_pending_free(cmd); +} + int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, u8 status) { - int err; + struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; + int err = 0; clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags); - err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL); + mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match); + mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match); + mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match); + + if (!status) + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, + dev_class, 3, NULL); + + if (match.sk) + sock_put(match.sk); return err; } -- cgit v1.2.3-70-g09d2 From 24b78d0f49b94f658e8bae707c158962535053dd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 23:24:30 +0200 Subject: Bluetooth: mgmt: Fix clear_uuids response Since the clear_uuids operation doesn't send an immediate HCI command but just sets off a timer to wait for subsequent add_uuid calls it doesn't make sense to wait until the timer fires off to send the response. Instead send the response immediately. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7a906d6e023..07e31f73f70 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1394,6 +1394,20 @@ failed: return err; } +static bool enable_service_cache(struct hci_dev *hdev) +{ + if (!hdev_is_powered(hdev)) + return false; + + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { + schedule_delayed_work(&hdev->service_cache, + msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + return true; + } + + return false; +} + static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_remove_uuid *cp = data; @@ -1425,10 +1439,11 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); - if (hdev_is_powered(hdev) && - !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) - schedule_delayed_work(&hdev->service_cache, - msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + if (enable_service_cache(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + hdev->dev_class, 3); + goto unlock; + } goto update_class; } -- cgit v1.2.3-70-g09d2 From c5905afb0ee6550b42c49213da1c22d67316c194 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 24 Feb 2012 08:31:31 +0100 Subject: static keys: Introduce 'struct static_key', static_key_true()/false() and static_key_slow_[inc|dec]() So here's a boot tested patch on top of Jason's series that does all the cleanups I talked about and turns jump labels into a more intuitive to use facility. It should also address the various misconceptions and confusions that surround jump labels. Typical usage scenarios: #include struct static_key key = STATIC_KEY_INIT_TRUE; if (static_key_false(&key)) do unlikely code else do likely code Or: if (static_key_true(&key)) do likely code else do unlikely code The static key is modified via: static_key_slow_inc(&key); ... static_key_slow_dec(&key); The 'slow' prefix makes it abundantly clear that this is an expensive operation. I've updated all in-kernel code to use this everywhere. Note that I (intentionally) have not pushed through the rename blindly through to the lowest levels: the actual jump-label patching arch facility should be named like that, so we want to decouple jump labels from the static-key facility a bit. On non-jump-label enabled architectures static keys default to likely()/unlikely() branches. Signed-off-by: Ingo Molnar Acked-by: Jason Baron Acked-by: Steven Rostedt Cc: a.p.zijlstra@chello.nl Cc: mathieu.desnoyers@efficios.com Cc: davem@davemloft.net Cc: ddaney.cavm@gmail.com Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20120222085809.GA26397@elte.hu Signed-off-by: Ingo Molnar --- arch/Kconfig | 29 ++++--- arch/ia64/include/asm/paravirt.h | 6 +- arch/ia64/kernel/paravirt.c | 4 +- arch/mips/include/asm/jump_label.h | 2 +- arch/powerpc/include/asm/jump_label.h | 2 +- arch/s390/include/asm/jump_label.h | 2 +- arch/sparc/include/asm/jump_label.h | 2 +- arch/x86/include/asm/jump_label.h | 6 +- arch/x86/include/asm/paravirt.h | 6 +- arch/x86/kernel/kvm.c | 4 +- arch/x86/kernel/paravirt.c | 4 +- arch/x86/kvm/mmu_audit.c | 8 +- include/linux/jump_label.h | 139 ++++++++++++++++++++++++---------- include/linux/netdevice.h | 4 +- include/linux/netfilter.h | 6 +- include/linux/perf_event.h | 12 +-- include/linux/static_key.h | 1 + include/linux/tracepoint.h | 8 +- include/net/sock.h | 6 +- kernel/events/core.c | 16 ++-- kernel/jump_label.c | 128 ++++++++++++++++++------------- kernel/sched/core.c | 18 ++--- kernel/sched/fair.c | 8 +- kernel/sched/sched.h | 14 ++-- kernel/tracepoint.c | 20 ++--- net/core/dev.c | 24 +++--- net/core/net-sysfs.c | 4 +- net/core/sock.c | 4 +- net/core/sysctl_net_core.c | 4 +- net/ipv4/tcp_memcontrol.c | 6 +- net/netfilter/core.c | 6 +- 31 files changed, 298 insertions(+), 205 deletions(-) create mode 100644 include/linux/static_key.h (limited to 'net') diff --git a/arch/Kconfig b/arch/Kconfig index 4f55c736be1..5b448a74d0f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -47,18 +47,29 @@ config KPROBES If in doubt, say "N". config JUMP_LABEL - bool "Optimize trace point call sites" + bool "Optimize very unlikely/likely branches" depends on HAVE_ARCH_JUMP_LABEL help + This option enables a transparent branch optimization that + makes certain almost-always-true or almost-always-false branch + conditions even cheaper to execute within the kernel. + + Certain performance-sensitive kernel code, such as trace points, + scheduler functionality, networking code and KVM have such + branches and include support for this optimization technique. + If it is detected that the compiler has support for "asm goto", - the kernel will compile trace point locations with just a - nop instruction. When trace points are enabled, the nop will - be converted to a jump to the trace function. This technique - lowers overhead and stress on the branch prediction of the - processor. - - On i386, options added to the compiler flags may increase - the size of the kernel slightly. + the kernel will compile such branches with just a nop + instruction. When the condition flag is toggled to true, the + nop will be converted to a jump instruction to execute the + conditional block of instructions. + + This technique lowers overhead and stress on the branch prediction + of the processor and generally makes the kernel faster. The update + of the condition is slower, but those are always very rare. + + ( On 32-bit x86, the necessary options added to the compiler + flags may increase the size of the kernel slightly. ) config OPTPROBES def_bool y diff --git a/arch/ia64/include/asm/paravirt.h b/arch/ia64/include/asm/paravirt.h index 32551d304cd..b149b88ea79 100644 --- a/arch/ia64/include/asm/paravirt.h +++ b/arch/ia64/include/asm/paravirt.h @@ -281,9 +281,9 @@ paravirt_init_missing_ticks_accounting(int cpu) pv_time_ops.init_missing_ticks_accounting(cpu); } -struct jump_label_key; -extern struct jump_label_key paravirt_steal_enabled; -extern struct jump_label_key paravirt_steal_rq_enabled; +struct static_key; +extern struct static_key paravirt_steal_enabled; +extern struct static_key paravirt_steal_rq_enabled; static inline int paravirt_do_steal_accounting(unsigned long *new_itm) diff --git a/arch/ia64/kernel/paravirt.c b/arch/ia64/kernel/paravirt.c index 100868216c5..1b22f6de293 100644 --- a/arch/ia64/kernel/paravirt.c +++ b/arch/ia64/kernel/paravirt.c @@ -634,8 +634,8 @@ struct pv_irq_ops pv_irq_ops = { * pv_time_ops * time operations */ -struct jump_label_key paravirt_steal_enabled; -struct jump_label_key paravirt_steal_rq_enabled; +struct static_key paravirt_steal_enabled; +struct static_key paravirt_steal_rq_enabled; static int ia64_native_do_steal_accounting(unsigned long *new_itm) diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h index 1881b316ca4..4d6d77ed9b9 100644 --- a/arch/mips/include/asm/jump_label.h +++ b/arch/mips/include/asm/jump_label.h @@ -20,7 +20,7 @@ #define WORD_INSN ".word" #endif -static __always_inline bool arch_static_branch(struct jump_label_key *key) +static __always_inline bool arch_static_branch(struct static_key *key) { asm goto("1:\tnop\n\t" "nop\n\t" diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h index 938986e412f..ae098c438f0 100644 --- a/arch/powerpc/include/asm/jump_label.h +++ b/arch/powerpc/include/asm/jump_label.h @@ -17,7 +17,7 @@ #define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG) #define JUMP_LABEL_NOP_SIZE 4 -static __always_inline bool arch_static_branch(struct jump_label_key *key) +static __always_inline bool arch_static_branch(struct static_key *key) { asm goto("1:\n\t" "nop\n\t" diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h index 95a6cf2b5b6..6c32190dc73 100644 --- a/arch/s390/include/asm/jump_label.h +++ b/arch/s390/include/asm/jump_label.h @@ -13,7 +13,7 @@ #define ASM_ALIGN ".balign 4" #endif -static __always_inline bool arch_static_branch(struct jump_label_key *key) +static __always_inline bool arch_static_branch(struct static_key *key) { asm goto("0: brcl 0,0\n" ".pushsection __jump_table, \"aw\"\n" diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h index fc73a82366f..5080d16a832 100644 --- a/arch/sparc/include/asm/jump_label.h +++ b/arch/sparc/include/asm/jump_label.h @@ -7,7 +7,7 @@ #define JUMP_LABEL_NOP_SIZE 4 -static __always_inline bool arch_static_branch(struct jump_label_key *key) +static __always_inline bool arch_static_branch(struct static_key *key) { asm goto("1:\n\t" "nop\n\t" diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index a32b18ce6ea..3a16c1483b4 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -9,12 +9,12 @@ #define JUMP_LABEL_NOP_SIZE 5 -#define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t" +#define STATIC_KEY_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t" -static __always_inline bool arch_static_branch(struct jump_label_key *key) +static __always_inline bool arch_static_branch(struct static_key *key) { asm goto("1:" - JUMP_LABEL_INITIAL_NOP + STATIC_KEY_INITIAL_NOP ".pushsection __jump_table, \"aw\" \n\t" _ASM_ALIGN "\n\t" _ASM_PTR "1b, %l[l_yes], %c0 \n\t" diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index a7d2db9a74f..c0180fd372d 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -230,9 +230,9 @@ static inline unsigned long long paravirt_sched_clock(void) return PVOP_CALL0(unsigned long long, pv_time_ops.sched_clock); } -struct jump_label_key; -extern struct jump_label_key paravirt_steal_enabled; -extern struct jump_label_key paravirt_steal_rq_enabled; +struct static_key; +extern struct static_key paravirt_steal_enabled; +extern struct static_key paravirt_steal_rq_enabled; static inline u64 paravirt_steal_clock(int cpu) { diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index f0c6fd6f176..694d801bf60 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -438,9 +438,9 @@ void __init kvm_guest_init(void) static __init int activate_jump_labels(void) { if (has_steal_clock) { - jump_label_inc(¶virt_steal_enabled); + static_key_slow_inc(¶virt_steal_enabled); if (steal_acc) - jump_label_inc(¶virt_steal_rq_enabled); + static_key_slow_inc(¶virt_steal_rq_enabled); } return 0; diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index d90272e6bc4..ada2f99388d 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -202,8 +202,8 @@ static void native_flush_tlb_single(unsigned long addr) __native_flush_tlb_single(addr); } -struct jump_label_key paravirt_steal_enabled; -struct jump_label_key paravirt_steal_rq_enabled; +struct static_key paravirt_steal_enabled; +struct static_key paravirt_steal_rq_enabled; static u64 native_steal_clock(int cpu) { diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c index fe15dcc07a6..ea7b4fd3467 100644 --- a/arch/x86/kvm/mmu_audit.c +++ b/arch/x86/kvm/mmu_audit.c @@ -234,7 +234,7 @@ static void audit_vcpu_spte(struct kvm_vcpu *vcpu) } static bool mmu_audit; -static struct jump_label_key mmu_audit_key; +static struct static_key mmu_audit_key; static void __kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) { @@ -250,7 +250,7 @@ static void __kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) static inline void kvm_mmu_audit(struct kvm_vcpu *vcpu, int point) { - if (static_branch((&mmu_audit_key))) + if (static_key_false((&mmu_audit_key))) __kvm_mmu_audit(vcpu, point); } @@ -259,7 +259,7 @@ static void mmu_audit_enable(void) if (mmu_audit) return; - jump_label_inc(&mmu_audit_key); + static_key_slow_inc(&mmu_audit_key); mmu_audit = true; } @@ -268,7 +268,7 @@ static void mmu_audit_disable(void) if (!mmu_audit) return; - jump_label_dec(&mmu_audit_key); + static_key_slow_dec(&mmu_audit_key); mmu_audit = false; } diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index f7c69580fea..2172da2d9bb 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -9,15 +9,15 @@ * * Jump labels provide an interface to generate dynamic branches using * self-modifying code. Assuming toolchain and architecture support the result - * of a "if (static_branch(&key))" statement is a unconditional branch (which + * of a "if (static_key_false(&key))" statement is a unconditional branch (which * defaults to false - and the true block is placed out of line). * - * However at runtime we can change the 'static' branch target using - * jump_label_{inc,dec}(). These function as a 'reference' count on the key + * However at runtime we can change the branch target using + * static_key_slow_{inc,dec}(). These function as a 'reference' count on the key * object and for as long as there are references all branches referring to * that particular key will point to the (out of line) true block. * - * Since this relies on modifying code the jump_label_{inc,dec}() functions + * Since this relies on modifying code the static_key_slow_{inc,dec}() functions * must be considered absolute slow paths (machine wide synchronization etc.). * OTOH, since the affected branches are unconditional their runtime overhead * will be absolutely minimal, esp. in the default (off) case where the total @@ -26,12 +26,26 @@ * * When the control is directly exposed to userspace it is prudent to delay the * decrement to avoid high frequency code modifications which can (and do) - * cause significant performance degradation. Struct jump_label_key_deferred and - * jump_label_dec_deferred() provide for this. + * cause significant performance degradation. Struct static_key_deferred and + * static_key_slow_dec_deferred() provide for this. * * Lacking toolchain and or architecture support, it falls back to a simple * conditional branch. - */ + * + * struct static_key my_key = STATIC_KEY_INIT_TRUE; + * + * if (static_key_true(&my_key)) { + * } + * + * will result in the true case being in-line and starts the key with a single + * reference. Mixing static_key_true() and static_key_false() on the same key is not + * allowed. + * + * Not initializing the key (static data is initialized to 0s anyway) is the + * same as using STATIC_KEY_INIT_FALSE and static_key_false() is + * equivalent with static_branch(). + * +*/ #include #include @@ -39,16 +53,17 @@ #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) -struct jump_label_key { +struct static_key { atomic_t enabled; +/* Set lsb bit to 1 if branch is default true, 0 ot */ struct jump_entry *entries; #ifdef CONFIG_MODULES - struct jump_label_mod *next; + struct static_key_mod *next; #endif }; -struct jump_label_key_deferred { - struct jump_label_key key; +struct static_key_deferred { + struct static_key key; unsigned long timeout; struct delayed_work work; }; @@ -66,13 +81,34 @@ struct module; #ifdef HAVE_JUMP_LABEL -#ifdef CONFIG_MODULES -#define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL, NULL} -#else -#define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL} -#endif +#define JUMP_LABEL_TRUE_BRANCH 1UL + +static +inline struct jump_entry *jump_label_get_entries(struct static_key *key) +{ + return (struct jump_entry *)((unsigned long)key->entries + & ~JUMP_LABEL_TRUE_BRANCH); +} + +static inline bool jump_label_get_branch_default(struct static_key *key) +{ + if ((unsigned long)key->entries & JUMP_LABEL_TRUE_BRANCH) + return true; + return false; +} + +static __always_inline bool static_key_false(struct static_key *key) +{ + return arch_static_branch(key); +} -static __always_inline bool static_branch(struct jump_label_key *key) +static __always_inline bool static_key_true(struct static_key *key) +{ + return !static_key_false(key); +} + +/* Deprecated. Please use 'static_key_false() instead. */ +static __always_inline bool static_branch(struct static_key *key) { return arch_static_branch(key); } @@ -88,21 +124,24 @@ extern void arch_jump_label_transform(struct jump_entry *entry, extern void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type); extern int jump_label_text_reserved(void *start, void *end); -extern void jump_label_inc(struct jump_label_key *key); -extern void jump_label_dec(struct jump_label_key *key); -extern void jump_label_dec_deferred(struct jump_label_key_deferred *key); -extern bool jump_label_enabled(struct jump_label_key *key); +extern void static_key_slow_inc(struct static_key *key); +extern void static_key_slow_dec(struct static_key *key); +extern void static_key_slow_dec_deferred(struct static_key_deferred *key); +extern bool static_key_enabled(struct static_key *key); extern void jump_label_apply_nops(struct module *mod); -extern void jump_label_rate_limit(struct jump_label_key_deferred *key, - unsigned long rl); +extern void +jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl); + +#define STATIC_KEY_INIT_TRUE ((struct static_key) \ + { .enabled = ATOMIC_INIT(1), .entries = (void *)1 }) +#define STATIC_KEY_INIT_FALSE ((struct static_key) \ + { .enabled = ATOMIC_INIT(0), .entries = (void *)0 }) #else /* !HAVE_JUMP_LABEL */ #include -#define JUMP_LABEL_INIT {ATOMIC_INIT(0)} - -struct jump_label_key { +struct static_key { atomic_t enabled; }; @@ -110,30 +149,45 @@ static __always_inline void jump_label_init(void) { } -struct jump_label_key_deferred { - struct jump_label_key key; +struct static_key_deferred { + struct static_key key; }; -static __always_inline bool static_branch(struct jump_label_key *key) +static __always_inline bool static_key_false(struct static_key *key) +{ + if (unlikely(atomic_read(&key->enabled)) > 0) + return true; + return false; +} + +static __always_inline bool static_key_true(struct static_key *key) { - if (unlikely(atomic_read(&key->enabled))) + if (likely(atomic_read(&key->enabled)) > 0) return true; return false; } -static inline void jump_label_inc(struct jump_label_key *key) +/* Deprecated. Please use 'static_key_false() instead. */ +static __always_inline bool static_branch(struct static_key *key) +{ + if (unlikely(atomic_read(&key->enabled)) > 0) + return true; + return false; +} + +static inline void static_key_slow_inc(struct static_key *key) { atomic_inc(&key->enabled); } -static inline void jump_label_dec(struct jump_label_key *key) +static inline void static_key_slow_dec(struct static_key *key) { atomic_dec(&key->enabled); } -static inline void jump_label_dec_deferred(struct jump_label_key_deferred *key) +static inline void static_key_slow_dec_deferred(struct static_key_deferred *key) { - jump_label_dec(&key->key); + static_key_slow_dec(&key->key); } static inline int jump_label_text_reserved(void *start, void *end) @@ -144,9 +198,9 @@ static inline int jump_label_text_reserved(void *start, void *end) static inline void jump_label_lock(void) {} static inline void jump_label_unlock(void) {} -static inline bool jump_label_enabled(struct jump_label_key *key) +static inline bool static_key_enabled(struct static_key *key) { - return !!atomic_read(&key->enabled); + return (atomic_read(&key->enabled) > 0); } static inline int jump_label_apply_nops(struct module *mod) @@ -154,13 +208,20 @@ static inline int jump_label_apply_nops(struct module *mod) return 0; } -static inline void jump_label_rate_limit(struct jump_label_key_deferred *key, +static inline void +jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl) { } + +#define STATIC_KEY_INIT_TRUE ((struct static_key) \ + { .enabled = ATOMIC_INIT(1) }) +#define STATIC_KEY_INIT_FALSE ((struct static_key) \ + { .enabled = ATOMIC_INIT(0) }) + #endif /* HAVE_JUMP_LABEL */ -#define jump_label_key_enabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(1), }) -#define jump_label_key_disabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(0), }) +#define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE +#define jump_label_enabled static_key_enabled #endif /* _LINUX_JUMP_LABEL_H */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0eac07c9525..7dfaae7846a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -214,8 +214,8 @@ enum { #include #ifdef CONFIG_RPS -#include -extern struct jump_label_key rps_needed; +#include +extern struct static_key rps_needed; #endif struct neighbour; diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index b809265607d..29734be334c 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -163,13 +163,13 @@ extern struct ctl_path nf_net_ipv4_netfilter_sysctl_path[]; extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; #if defined(CONFIG_JUMP_LABEL) -#include -extern struct jump_label_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; +#include +extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) { if (__builtin_constant_p(pf) && __builtin_constant_p(hook)) - return static_branch(&nf_hooks_needed[pf][hook]); + return static_key_false(&nf_hooks_needed[pf][hook]); return !list_empty(&nf_hooks[pf][hook]); } diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 412b790f5da..0d21e6f1cf5 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -514,7 +514,7 @@ struct perf_guest_info_callbacks { #include #include #include -#include +#include #include #include @@ -1038,7 +1038,7 @@ static inline int is_software_event(struct perf_event *event) return event->pmu->task_ctx_nr == perf_sw_context; } -extern struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; +extern struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; extern void __perf_sw_event(u32, u64, struct pt_regs *, u64); @@ -1066,7 +1066,7 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) { struct pt_regs hot_regs; - if (static_branch(&perf_swevent_enabled[event_id])) { + if (static_key_false(&perf_swevent_enabled[event_id])) { if (!regs) { perf_fetch_caller_regs(&hot_regs); regs = &hot_regs; @@ -1075,12 +1075,12 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) } } -extern struct jump_label_key_deferred perf_sched_events; +extern struct static_key_deferred perf_sched_events; static inline void perf_event_task_sched_in(struct task_struct *prev, struct task_struct *task) { - if (static_branch(&perf_sched_events.key)) + if (static_key_false(&perf_sched_events.key)) __perf_event_task_sched_in(prev, task); } @@ -1089,7 +1089,7 @@ static inline void perf_event_task_sched_out(struct task_struct *prev, { perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); - if (static_branch(&perf_sched_events.key)) + if (static_key_false(&perf_sched_events.key)) __perf_event_task_sched_out(prev, next); } diff --git a/include/linux/static_key.h b/include/linux/static_key.h new file mode 100644 index 00000000000..27bd3f8a085 --- /dev/null +++ b/include/linux/static_key.h @@ -0,0 +1 @@ +#include diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index fc36da97ff7..bd96ecd0e05 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include struct module; struct tracepoint; @@ -29,7 +29,7 @@ struct tracepoint_func { struct tracepoint { const char *name; /* Tracepoint name */ - struct jump_label_key key; + struct static_key key; void (*regfunc)(void); void (*unregfunc)(void); struct tracepoint_func __rcu *funcs; @@ -145,7 +145,7 @@ static inline void tracepoint_synchronize_unregister(void) extern struct tracepoint __tracepoint_##name; \ static inline void trace_##name(proto) \ { \ - if (static_branch(&__tracepoint_##name.key)) \ + if (static_key_false(&__tracepoint_##name.key)) \ __DO_TRACE(&__tracepoint_##name, \ TP_PROTO(data_proto), \ TP_ARGS(data_args), \ @@ -188,7 +188,7 @@ static inline void tracepoint_synchronize_unregister(void) __attribute__((section("__tracepoints_strings"))) = #name; \ struct tracepoint __tracepoint_##name \ __attribute__((section("__tracepoints"))) = \ - { __tpstrtab_##name, JUMP_LABEL_INIT, reg, unreg, NULL };\ + { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\ static struct tracepoint * const __tracepoint_ptr_##name __used \ __attribute__((section("__tracepoints_ptrs"))) = \ &__tracepoint_##name; diff --git a/include/net/sock.h b/include/net/sock.h index 91c1c8baf02..dcde2d9268c 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -55,7 +55,7 @@ #include #include #include -#include +#include #include #include @@ -924,13 +924,13 @@ inline void sk_refcnt_debug_release(const struct sock *sk) #endif /* SOCK_REFCNT_DEBUG */ #if defined(CONFIG_CGROUP_MEM_RES_CTLR_KMEM) && defined(CONFIG_NET) -extern struct jump_label_key memcg_socket_limit_enabled; +extern struct static_key memcg_socket_limit_enabled; static inline struct cg_proto *parent_cg_proto(struct proto *proto, struct cg_proto *cg_proto) { return proto->proto_cgroup(parent_mem_cgroup(cg_proto->memcg)); } -#define mem_cgroup_sockets_enabled static_branch(&memcg_socket_limit_enabled) +#define mem_cgroup_sockets_enabled static_key_false(&memcg_socket_limit_enabled) #else #define mem_cgroup_sockets_enabled 0 static inline struct cg_proto *parent_cg_proto(struct proto *proto, diff --git a/kernel/events/core.c b/kernel/events/core.c index 7c3b9de55f6..5e0f8bb89b2 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -128,7 +128,7 @@ enum event_type_t { * perf_sched_events : >0 events exist * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu */ -struct jump_label_key_deferred perf_sched_events __read_mostly; +struct static_key_deferred perf_sched_events __read_mostly; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static atomic_t nr_mmap_events __read_mostly; @@ -2769,7 +2769,7 @@ static void free_event(struct perf_event *event) if (!event->parent) { if (event->attach_state & PERF_ATTACH_TASK) - jump_label_dec_deferred(&perf_sched_events); + static_key_slow_dec_deferred(&perf_sched_events); if (event->attr.mmap || event->attr.mmap_data) atomic_dec(&nr_mmap_events); if (event->attr.comm) @@ -2780,7 +2780,7 @@ static void free_event(struct perf_event *event) put_callchain_buffers(); if (is_cgroup_event(event)) { atomic_dec(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_dec_deferred(&perf_sched_events); + static_key_slow_dec_deferred(&perf_sched_events); } } @@ -4982,7 +4982,7 @@ fail: return err; } -struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; +struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; static void sw_perf_event_destroy(struct perf_event *event) { @@ -4990,7 +4990,7 @@ static void sw_perf_event_destroy(struct perf_event *event) WARN_ON(event->parent); - jump_label_dec(&perf_swevent_enabled[event_id]); + static_key_slow_dec(&perf_swevent_enabled[event_id]); swevent_hlist_put(event); } @@ -5020,7 +5020,7 @@ static int perf_swevent_init(struct perf_event *event) if (err) return err; - jump_label_inc(&perf_swevent_enabled[event_id]); + static_key_slow_inc(&perf_swevent_enabled[event_id]); event->destroy = sw_perf_event_destroy; } @@ -5843,7 +5843,7 @@ done: if (!event->parent) { if (event->attach_state & PERF_ATTACH_TASK) - jump_label_inc(&perf_sched_events.key); + static_key_slow_inc(&perf_sched_events.key); if (event->attr.mmap || event->attr.mmap_data) atomic_inc(&nr_mmap_events); if (event->attr.comm) @@ -6081,7 +6081,7 @@ SYSCALL_DEFINE5(perf_event_open, * - that may need work on context switch */ atomic_inc(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_inc(&perf_sched_events.key); + static_key_slow_inc(&perf_sched_events.key); } /* diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 543782e7cdd..bf9dcadbb53 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #ifdef HAVE_JUMP_LABEL @@ -29,10 +29,11 @@ void jump_label_unlock(void) mutex_unlock(&jump_label_mutex); } -bool jump_label_enabled(struct jump_label_key *key) +bool static_key_enabled(struct static_key *key) { - return !!atomic_read(&key->enabled); + return (atomic_read(&key->enabled) > 0); } +EXPORT_SYMBOL_GPL(static_key_enabled); static int jump_label_cmp(const void *a, const void *b) { @@ -58,22 +59,26 @@ jump_label_sort_entries(struct jump_entry *start, struct jump_entry *stop) sort(start, size, sizeof(struct jump_entry), jump_label_cmp, NULL); } -static void jump_label_update(struct jump_label_key *key, int enable); +static void jump_label_update(struct static_key *key, int enable); -void jump_label_inc(struct jump_label_key *key) +void static_key_slow_inc(struct static_key *key) { if (atomic_inc_not_zero(&key->enabled)) return; jump_label_lock(); - if (atomic_read(&key->enabled) == 0) - jump_label_update(key, JUMP_LABEL_ENABLE); + if (atomic_read(&key->enabled) == 0) { + if (!jump_label_get_branch_default(key)) + jump_label_update(key, JUMP_LABEL_ENABLE); + else + jump_label_update(key, JUMP_LABEL_DISABLE); + } atomic_inc(&key->enabled); jump_label_unlock(); } -EXPORT_SYMBOL_GPL(jump_label_inc); +EXPORT_SYMBOL_GPL(static_key_slow_inc); -static void __jump_label_dec(struct jump_label_key *key, +static void __static_key_slow_dec(struct static_key *key, unsigned long rate_limit, struct delayed_work *work) { if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) { @@ -85,32 +90,35 @@ static void __jump_label_dec(struct jump_label_key *key, if (rate_limit) { atomic_inc(&key->enabled); schedule_delayed_work(work, rate_limit); - } else - jump_label_update(key, JUMP_LABEL_DISABLE); - + } else { + if (!jump_label_get_branch_default(key)) + jump_label_update(key, JUMP_LABEL_DISABLE); + else + jump_label_update(key, JUMP_LABEL_ENABLE); + } jump_label_unlock(); } -EXPORT_SYMBOL_GPL(jump_label_dec); static void jump_label_update_timeout(struct work_struct *work) { - struct jump_label_key_deferred *key = - container_of(work, struct jump_label_key_deferred, work.work); - __jump_label_dec(&key->key, 0, NULL); + struct static_key_deferred *key = + container_of(work, struct static_key_deferred, work.work); + __static_key_slow_dec(&key->key, 0, NULL); } -void jump_label_dec(struct jump_label_key *key) +void static_key_slow_dec(struct static_key *key) { - __jump_label_dec(key, 0, NULL); + __static_key_slow_dec(key, 0, NULL); } +EXPORT_SYMBOL_GPL(static_key_slow_dec); -void jump_label_dec_deferred(struct jump_label_key_deferred *key) +void static_key_slow_dec_deferred(struct static_key_deferred *key) { - __jump_label_dec(&key->key, key->timeout, &key->work); + __static_key_slow_dec(&key->key, key->timeout, &key->work); } +EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred); - -void jump_label_rate_limit(struct jump_label_key_deferred *key, +void jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl) { key->timeout = rl; @@ -153,7 +161,7 @@ void __weak __init_or_module arch_jump_label_transform_static(struct jump_entry arch_jump_label_transform(entry, type); } -static void __jump_label_update(struct jump_label_key *key, +static void __jump_label_update(struct static_key *key, struct jump_entry *entry, struct jump_entry *stop, int enable) { @@ -170,27 +178,40 @@ static void __jump_label_update(struct jump_label_key *key, } } +static enum jump_label_type jump_label_type(struct static_key *key) +{ + bool true_branch = jump_label_get_branch_default(key); + bool state = static_key_enabled(key); + + if ((!true_branch && state) || (true_branch && !state)) + return JUMP_LABEL_ENABLE; + + return JUMP_LABEL_DISABLE; +} + void __init jump_label_init(void) { struct jump_entry *iter_start = __start___jump_table; struct jump_entry *iter_stop = __stop___jump_table; - struct jump_label_key *key = NULL; + struct static_key *key = NULL; struct jump_entry *iter; jump_label_lock(); jump_label_sort_entries(iter_start, iter_stop); for (iter = iter_start; iter < iter_stop; iter++) { - struct jump_label_key *iterk; + struct static_key *iterk; - iterk = (struct jump_label_key *)(unsigned long)iter->key; - arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ? - JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE); + iterk = (struct static_key *)(unsigned long)iter->key; + arch_jump_label_transform_static(iter, jump_label_type(iterk)); if (iterk == key) continue; key = iterk; - key->entries = iter; + /* + * Set key->entries to iter, but preserve JUMP_LABEL_TRUE_BRANCH. + */ + *((unsigned long *)&key->entries) += (unsigned long)iter; #ifdef CONFIG_MODULES key->next = NULL; #endif @@ -200,8 +221,8 @@ void __init jump_label_init(void) #ifdef CONFIG_MODULES -struct jump_label_mod { - struct jump_label_mod *next; +struct static_key_mod { + struct static_key_mod *next; struct jump_entry *entries; struct module *mod; }; @@ -221,9 +242,9 @@ static int __jump_label_mod_text_reserved(void *start, void *end) start, end); } -static void __jump_label_mod_update(struct jump_label_key *key, int enable) +static void __jump_label_mod_update(struct static_key *key, int enable) { - struct jump_label_mod *mod = key->next; + struct static_key_mod *mod = key->next; while (mod) { struct module *m = mod->mod; @@ -254,11 +275,7 @@ void jump_label_apply_nops(struct module *mod) return; for (iter = iter_start; iter < iter_stop; iter++) { - struct jump_label_key *iterk; - - iterk = (struct jump_label_key *)(unsigned long)iter->key; - arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ? - JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE); + arch_jump_label_transform_static(iter, JUMP_LABEL_DISABLE); } } @@ -267,8 +284,8 @@ static int jump_label_add_module(struct module *mod) struct jump_entry *iter_start = mod->jump_entries; struct jump_entry *iter_stop = iter_start + mod->num_jump_entries; struct jump_entry *iter; - struct jump_label_key *key = NULL; - struct jump_label_mod *jlm; + struct static_key *key = NULL; + struct static_key_mod *jlm; /* if the module doesn't have jump label entries, just return */ if (iter_start == iter_stop) @@ -277,28 +294,30 @@ static int jump_label_add_module(struct module *mod) jump_label_sort_entries(iter_start, iter_stop); for (iter = iter_start; iter < iter_stop; iter++) { - if (iter->key == (jump_label_t)(unsigned long)key) - continue; + struct static_key *iterk; - key = (struct jump_label_key *)(unsigned long)iter->key; + iterk = (struct static_key *)(unsigned long)iter->key; + if (iterk == key) + continue; + key = iterk; if (__module_address(iter->key) == mod) { - atomic_set(&key->enabled, 0); - key->entries = iter; + /* + * Set key->entries to iter, but preserve JUMP_LABEL_TRUE_BRANCH. + */ + *((unsigned long *)&key->entries) += (unsigned long)iter; key->next = NULL; continue; } - - jlm = kzalloc(sizeof(struct jump_label_mod), GFP_KERNEL); + jlm = kzalloc(sizeof(struct static_key_mod), GFP_KERNEL); if (!jlm) return -ENOMEM; - jlm->mod = mod; jlm->entries = iter; jlm->next = key->next; key->next = jlm; - if (jump_label_enabled(key)) + if (jump_label_type(key) == JUMP_LABEL_ENABLE) __jump_label_update(key, iter, iter_stop, JUMP_LABEL_ENABLE); } @@ -310,14 +329,14 @@ static void jump_label_del_module(struct module *mod) struct jump_entry *iter_start = mod->jump_entries; struct jump_entry *iter_stop = iter_start + mod->num_jump_entries; struct jump_entry *iter; - struct jump_label_key *key = NULL; - struct jump_label_mod *jlm, **prev; + struct static_key *key = NULL; + struct static_key_mod *jlm, **prev; for (iter = iter_start; iter < iter_stop; iter++) { if (iter->key == (jump_label_t)(unsigned long)key) continue; - key = (struct jump_label_key *)(unsigned long)iter->key; + key = (struct static_key *)(unsigned long)iter->key; if (__module_address(iter->key) == mod) continue; @@ -419,9 +438,10 @@ int jump_label_text_reserved(void *start, void *end) return ret; } -static void jump_label_update(struct jump_label_key *key, int enable) +static void jump_label_update(struct static_key *key, int enable) { - struct jump_entry *entry = key->entries, *stop = __stop___jump_table; + struct jump_entry *stop = __stop___jump_table; + struct jump_entry *entry = jump_label_get_entries(key); #ifdef CONFIG_MODULES struct module *mod = __module_address((unsigned long)key); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 5255c9d2e05..112c6824476 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -162,13 +162,13 @@ static int sched_feat_show(struct seq_file *m, void *v) #ifdef HAVE_JUMP_LABEL -#define jump_label_key__true jump_label_key_enabled -#define jump_label_key__false jump_label_key_disabled +#define jump_label_key__true STATIC_KEY_INIT_TRUE +#define jump_label_key__false STATIC_KEY_INIT_FALSE #define SCHED_FEAT(name, enabled) \ jump_label_key__##enabled , -struct jump_label_key sched_feat_keys[__SCHED_FEAT_NR] = { +struct static_key sched_feat_keys[__SCHED_FEAT_NR] = { #include "features.h" }; @@ -176,14 +176,14 @@ struct jump_label_key sched_feat_keys[__SCHED_FEAT_NR] = { static void sched_feat_disable(int i) { - if (jump_label_enabled(&sched_feat_keys[i])) - jump_label_dec(&sched_feat_keys[i]); + if (static_key_enabled(&sched_feat_keys[i])) + static_key_slow_dec(&sched_feat_keys[i]); } static void sched_feat_enable(int i) { - if (!jump_label_enabled(&sched_feat_keys[i])) - jump_label_inc(&sched_feat_keys[i]); + if (!static_key_enabled(&sched_feat_keys[i])) + static_key_slow_inc(&sched_feat_keys[i]); } #else static void sched_feat_disable(int i) { }; @@ -894,7 +894,7 @@ static void update_rq_clock_task(struct rq *rq, s64 delta) delta -= irq_delta; #endif #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING - if (static_branch((¶virt_steal_rq_enabled))) { + if (static_key_false((¶virt_steal_rq_enabled))) { u64 st; steal = paravirt_steal_clock(cpu_of(rq)); @@ -2756,7 +2756,7 @@ void account_idle_time(cputime_t cputime) static __always_inline bool steal_account_process_tick(void) { #ifdef CONFIG_PARAVIRT - if (static_branch(¶virt_steal_enabled)) { + if (static_key_false(¶virt_steal_enabled)) { u64 steal, st = 0; steal = paravirt_steal_clock(smp_processor_id()); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7c6414fc669..423547ada38 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1399,20 +1399,20 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) #ifdef CONFIG_CFS_BANDWIDTH #ifdef HAVE_JUMP_LABEL -static struct jump_label_key __cfs_bandwidth_used; +static struct static_key __cfs_bandwidth_used; static inline bool cfs_bandwidth_used(void) { - return static_branch(&__cfs_bandwidth_used); + return static_key_false(&__cfs_bandwidth_used); } void account_cfs_bandwidth_used(int enabled, int was_enabled) { /* only need to count groups transitioning between enabled/!enabled */ if (enabled && !was_enabled) - jump_label_inc(&__cfs_bandwidth_used); + static_key_slow_inc(&__cfs_bandwidth_used); else if (!enabled && was_enabled) - jump_label_dec(&__cfs_bandwidth_used); + static_key_slow_dec(&__cfs_bandwidth_used); } #else /* HAVE_JUMP_LABEL */ static bool cfs_bandwidth_used(void) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 98c0c2623db..b4cd6d8ea15 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -611,7 +611,7 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) * Tunables that become constants when CONFIG_SCHED_DEBUG is off: */ #ifdef CONFIG_SCHED_DEBUG -# include +# include # define const_debug __read_mostly #else # define const_debug const @@ -630,18 +630,18 @@ enum { #undef SCHED_FEAT #if defined(CONFIG_SCHED_DEBUG) && defined(HAVE_JUMP_LABEL) -static __always_inline bool static_branch__true(struct jump_label_key *key) +static __always_inline bool static_branch__true(struct static_key *key) { - return likely(static_branch(key)); /* Not out of line branch. */ + return static_key_true(key); /* Not out of line branch. */ } -static __always_inline bool static_branch__false(struct jump_label_key *key) +static __always_inline bool static_branch__false(struct static_key *key) { - return unlikely(static_branch(key)); /* Out of line branch. */ + return static_key_false(key); /* Out of line branch. */ } #define SCHED_FEAT(name, enabled) \ -static __always_inline bool static_branch_##name(struct jump_label_key *key) \ +static __always_inline bool static_branch_##name(struct static_key *key) \ { \ return static_branch__##enabled(key); \ } @@ -650,7 +650,7 @@ static __always_inline bool static_branch_##name(struct jump_label_key *key) \ #undef SCHED_FEAT -extern struct jump_label_key sched_feat_keys[__SCHED_FEAT_NR]; +extern struct static_key sched_feat_keys[__SCHED_FEAT_NR]; #define sched_feat(x) (static_branch_##x(&sched_feat_keys[__SCHED_FEAT_##x])) #else /* !(SCHED_DEBUG && HAVE_JUMP_LABEL) */ #define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x)) diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index f1539decd99..d96ba22dabf 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include extern struct tracepoint * const __start___tracepoints_ptrs[]; extern struct tracepoint * const __stop___tracepoints_ptrs[]; @@ -256,9 +256,9 @@ static void set_tracepoint(struct tracepoint_entry **entry, { WARN_ON(strcmp((*entry)->name, elem->name) != 0); - if (elem->regfunc && !jump_label_enabled(&elem->key) && active) + if (elem->regfunc && !static_key_enabled(&elem->key) && active) elem->regfunc(); - else if (elem->unregfunc && jump_label_enabled(&elem->key) && !active) + else if (elem->unregfunc && static_key_enabled(&elem->key) && !active) elem->unregfunc(); /* @@ -269,10 +269,10 @@ static void set_tracepoint(struct tracepoint_entry **entry, * is used. */ rcu_assign_pointer(elem->funcs, (*entry)->funcs); - if (active && !jump_label_enabled(&elem->key)) - jump_label_inc(&elem->key); - else if (!active && jump_label_enabled(&elem->key)) - jump_label_dec(&elem->key); + if (active && !static_key_enabled(&elem->key)) + static_key_slow_inc(&elem->key); + else if (!active && static_key_enabled(&elem->key)) + static_key_slow_dec(&elem->key); } /* @@ -283,11 +283,11 @@ static void set_tracepoint(struct tracepoint_entry **entry, */ static void disable_tracepoint(struct tracepoint *elem) { - if (elem->unregfunc && jump_label_enabled(&elem->key)) + if (elem->unregfunc && static_key_enabled(&elem->key)) elem->unregfunc(); - if (jump_label_enabled(&elem->key)) - jump_label_dec(&elem->key); + if (static_key_enabled(&elem->key)) + static_key_slow_dec(&elem->key); rcu_assign_pointer(elem->funcs, NULL); } diff --git a/net/core/dev.c b/net/core/dev.c index 115dee1d985..da7ce7f0e56 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -134,7 +134,7 @@ #include #include #include -#include +#include #include #include "net-sysfs.h" @@ -1441,11 +1441,11 @@ int call_netdevice_notifiers(unsigned long val, struct net_device *dev) } EXPORT_SYMBOL(call_netdevice_notifiers); -static struct jump_label_key netstamp_needed __read_mostly; +static struct static_key netstamp_needed __read_mostly; #ifdef HAVE_JUMP_LABEL -/* We are not allowed to call jump_label_dec() from irq context +/* We are not allowed to call static_key_slow_dec() from irq context * If net_disable_timestamp() is called from irq context, defer the - * jump_label_dec() calls. + * static_key_slow_dec() calls. */ static atomic_t netstamp_needed_deferred; #endif @@ -1457,12 +1457,12 @@ void net_enable_timestamp(void) if (deferred) { while (--deferred) - jump_label_dec(&netstamp_needed); + static_key_slow_dec(&netstamp_needed); return; } #endif WARN_ON(in_interrupt()); - jump_label_inc(&netstamp_needed); + static_key_slow_inc(&netstamp_needed); } EXPORT_SYMBOL(net_enable_timestamp); @@ -1474,19 +1474,19 @@ void net_disable_timestamp(void) return; } #endif - jump_label_dec(&netstamp_needed); + static_key_slow_dec(&netstamp_needed); } EXPORT_SYMBOL(net_disable_timestamp); static inline void net_timestamp_set(struct sk_buff *skb) { skb->tstamp.tv64 = 0; - if (static_branch(&netstamp_needed)) + if (static_key_false(&netstamp_needed)) __net_timestamp(skb); } #define net_timestamp_check(COND, SKB) \ - if (static_branch(&netstamp_needed)) { \ + if (static_key_false(&netstamp_needed)) { \ if ((COND) && !(SKB)->tstamp.tv64) \ __net_timestamp(SKB); \ } \ @@ -2660,7 +2660,7 @@ EXPORT_SYMBOL(__skb_get_rxhash); struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly; EXPORT_SYMBOL(rps_sock_flow_table); -struct jump_label_key rps_needed __read_mostly; +struct static_key rps_needed __read_mostly; static struct rps_dev_flow * set_rps_cpu(struct net_device *dev, struct sk_buff *skb, @@ -2945,7 +2945,7 @@ int netif_rx(struct sk_buff *skb) trace_netif_rx(skb); #ifdef CONFIG_RPS - if (static_branch(&rps_needed)) { + if (static_key_false(&rps_needed)) { struct rps_dev_flow voidflow, *rflow = &voidflow; int cpu; @@ -3309,7 +3309,7 @@ int netif_receive_skb(struct sk_buff *skb) return NET_RX_SUCCESS; #ifdef CONFIG_RPS - if (static_branch(&rps_needed)) { + if (static_key_false(&rps_needed)) { struct rps_dev_flow voidflow, *rflow = &voidflow; int cpu, ret; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index a1727cda03d..495586232aa 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -608,10 +608,10 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue, spin_unlock(&rps_map_lock); if (map) - jump_label_inc(&rps_needed); + static_key_slow_inc(&rps_needed); if (old_map) { kfree_rcu(old_map, rcu); - jump_label_dec(&rps_needed); + static_key_slow_dec(&rps_needed); } free_cpumask_var(mask); return len; diff --git a/net/core/sock.c b/net/core/sock.c index 3e81fd2e3c7..3a4e5817a2a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -111,7 +111,7 @@ #include #include #include -#include +#include #include #include @@ -184,7 +184,7 @@ void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss) static struct lock_class_key af_family_keys[AF_MAX]; static struct lock_class_key af_family_slock_keys[AF_MAX]; -struct jump_label_key memcg_socket_limit_enabled; +struct static_key memcg_socket_limit_enabled; EXPORT_SYMBOL(memcg_socket_limit_enabled); /* diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index d05559d4d9c..0c285087425 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -69,9 +69,9 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write, if (sock_table != orig_sock_table) { rcu_assign_pointer(rps_sock_flow_table, sock_table); if (sock_table) - jump_label_inc(&rps_needed); + static_key_slow_inc(&rps_needed); if (orig_sock_table) { - jump_label_dec(&rps_needed); + static_key_slow_dec(&rps_needed); synchronize_rcu(); vfree(orig_sock_table); } diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index 49978788a9d..602fb305365 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c @@ -111,7 +111,7 @@ void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT); if (val != RESOURCE_MAX) - jump_label_dec(&memcg_socket_limit_enabled); + static_key_slow_dec(&memcg_socket_limit_enabled); } EXPORT_SYMBOL(tcp_destroy_cgroup); @@ -143,9 +143,9 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) net->ipv4.sysctl_tcp_mem[i]); if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX) - jump_label_dec(&memcg_socket_limit_enabled); + static_key_slow_dec(&memcg_socket_limit_enabled); else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX) - jump_label_inc(&memcg_socket_limit_enabled); + static_key_slow_inc(&memcg_socket_limit_enabled); return 0; } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index b4e8ff05b30..e1b7e051332 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -56,7 +56,7 @@ struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly; EXPORT_SYMBOL(nf_hooks); #if defined(CONFIG_JUMP_LABEL) -struct jump_label_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; +struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; EXPORT_SYMBOL(nf_hooks_needed); #endif @@ -77,7 +77,7 @@ int nf_register_hook(struct nf_hook_ops *reg) list_add_rcu(®->list, elem->list.prev); mutex_unlock(&nf_hook_mutex); #if defined(CONFIG_JUMP_LABEL) - jump_label_inc(&nf_hooks_needed[reg->pf][reg->hooknum]); + static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif return 0; } @@ -89,7 +89,7 @@ void nf_unregister_hook(struct nf_hook_ops *reg) list_del_rcu(®->list); mutex_unlock(&nf_hook_mutex); #if defined(CONFIG_JUMP_LABEL) - jump_label_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); + static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif synchronize_net(); } -- cgit v1.2.3-70-g09d2 From 36eabda3d094dae30a74350c6289c163349b744d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sat, 11 Feb 2012 15:39:14 +0000 Subject: net: Support RXFCS feature flag. When set on hardware that supports the feature, this causes the Ethernet FCS to be appended to the end of the skb. Useful for sniffing packets. Signed-off-by: Ben Greear Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- Documentation/networking/netdev-features.txt | 6 ++++++ include/linux/netdev_features.h | 2 ++ net/core/ethtool.c | 1 + 3 files changed, 9 insertions(+) (limited to 'net') diff --git a/Documentation/networking/netdev-features.txt b/Documentation/networking/netdev-features.txt index 4b1c0dcef84..7d2781230d3 100644 --- a/Documentation/networking/netdev-features.txt +++ b/Documentation/networking/netdev-features.txt @@ -152,3 +152,9 @@ NETIF_F_VLAN_CHALLENGED should be set for devices which can't cope with VLAN headers. Some drivers set this because the cards can't handle the bigger MTU. [FIXME: Those cases could be fixed in VLAN code by allowing only reduced-MTU VLANs. This may be not useful, though.] + +* rx-fcs + +This requests that the NIC append the Ethernet Frame Checksum (FCS) +to the end of the skb data. This allows sniffers and other tools to +read the CRC recorded by the NIC on receipt of the packet. diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index 77f5202977c..d1331865f83 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -54,6 +54,7 @@ enum { NETIF_F_RXCSUM_BIT, /* Receive checksumming offload */ NETIF_F_NOCACHE_COPY_BIT, /* Use no-cache copyfromuser */ NETIF_F_LOOPBACK_BIT, /* Enable loopback */ + NETIF_F_RXFCS_BIT, /* Append FCS to skb pkt data */ /* * Add your fresh new feature above and remember to update @@ -98,6 +99,7 @@ enum { #define NETIF_F_TSO __NETIF_F(TSO) #define NETIF_F_UFO __NETIF_F(UFO) #define NETIF_F_VLAN_CHALLENGED __NETIF_F(VLAN_CHALLENGED) +#define NETIF_F_RXFCS __NETIF_F(RXFCS) /* Features valid for ethtool to change */ /* = all defined minus driver/device-class-related */ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 3f79db1b612..080161924a0 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -73,6 +73,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_RXCSUM_BIT] = "rx-checksum", [NETIF_F_NOCACHE_COPY_BIT] = "tx-nocache-copy", [NETIF_F_LOOPBACK_BIT] = "loopback", + [NETIF_F_RXFCS_BIT] = "rx-fcs", }; static int ethtool_get_features(struct net_device *dev, void __user *useraddr) -- cgit v1.2.3-70-g09d2 From 3bdc0eba0b8b47797f4a76e377dd8360f317450f Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sat, 11 Feb 2012 15:39:30 +0000 Subject: net: Add framework to allow sending packets with customized CRC. This is useful for testing RX handling of frames with bad CRCs. Requires driver support to actually put the packet on the wire properly. Signed-off-by: Ben Greear Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- arch/alpha/include/asm/socket.h | 3 +++ arch/arm/include/asm/socket.h | 3 +++ arch/avr32/include/asm/socket.h | 3 +++ arch/cris/include/asm/socket.h | 3 +++ arch/frv/include/asm/socket.h | 3 +++ arch/h8300/include/asm/socket.h | 3 +++ arch/ia64/include/asm/socket.h | 3 +++ arch/m32r/include/asm/socket.h | 3 +++ arch/m68k/include/asm/socket.h | 3 +++ arch/mips/include/asm/socket.h | 3 +++ arch/mn10300/include/asm/socket.h | 3 +++ arch/parisc/include/asm/socket.h | 4 ++++ arch/powerpc/include/asm/socket.h | 3 +++ arch/s390/include/asm/socket.h | 3 +++ arch/sparc/include/asm/socket.h | 4 ++++ arch/xtensa/include/asm/socket.h | 3 +++ include/asm-generic/socket.h | 4 ++++ include/linux/if.h | 2 ++ include/linux/netdevice.h | 8 +++++++- include/linux/skbuff.h | 4 +++- include/net/sock.h | 4 ++++ net/core/skbuff.c | 1 + net/core/sock.c | 5 +++++ net/packet/af_packet.c | 32 ++++++++++++++++++++++++++++---- 24 files changed, 104 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 16449d330da..dcb221a4b5b 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -73,6 +73,9 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index d958c74e526..6433cadb6ed 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -66,4 +66,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index 30078f98b3a..a473f8c6a9a 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -66,4 +66,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index 048aba64600..ae52825021a 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -68,6 +68,9 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index 7a361810f3c..a5b1d7dbb20 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -66,5 +66,8 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index e7bbfcee5b9..ec4554e7b04 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -66,4 +66,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index ced62de9d5a..41fc28a4a18 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -75,4 +75,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index 696cb4c7ca4..a15f40b5278 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -66,4 +66,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index e8b41a6775f..d1be684edf9 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -66,4 +66,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index 52104872e9e..a2ed6fdad4e 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -86,6 +86,9 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #ifdef __KERNEL__ /** sock_type - Socket types diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 013fcc51698..820463a484b 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -66,4 +66,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index f717c9bec16..1b52c2c31a7 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -65,6 +65,10 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 0x4023 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 0x4024 + + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index fe1c0b478fd..3d5179bb122 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -73,4 +73,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index 581702fa1b0..c91b720965c 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -74,4 +74,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 68e2e2746f6..bea1568ae4a 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -62,6 +62,10 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 0x0026 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 0x0027 + + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index 74818b16136..e36c6818492 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -77,4 +77,7 @@ #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* _XTENSA_SOCKET_H */ diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h index d9aaac0c36d..b1bea03274d 100644 --- a/include/asm-generic/socket.h +++ b/include/asm-generic/socket.h @@ -68,4 +68,8 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS #define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/include/linux/if.h b/include/linux/if.h index 06b6ef60c82..f995c663c49 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -80,6 +80,8 @@ * skbs on transmit */ #define IFF_UNICAST_FLT 0x20000 /* Supports unicast filtering */ #define IFF_TEAM_PORT 0x40000 /* device used as team port */ +#define IFF_SUPP_NOFCS 0x80000 /* device supports sending custom FCS */ + #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0eac07c9525..f1b7d037c2c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1082,7 +1082,8 @@ struct net_device { const struct header_ops *header_ops; unsigned int flags; /* interface flags (a la BSD) */ - unsigned int priv_flags; /* Like 'flags' but invisible to userspace. */ + unsigned int priv_flags; /* Like 'flags' but invisible to userspace. + * See if.h for definitions. */ unsigned short gflags; unsigned short padded; /* How much padding added by alloc_netdev() */ @@ -2650,6 +2651,11 @@ static inline int netif_is_bond_slave(struct net_device *dev) return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING; } +static inline bool netif_supports_nofcs(struct net_device *dev) +{ + return dev->priv_flags & IFF_SUPP_NOFCS; +} + extern struct pernet_operations __net_initdata loopback_net_ops; /* Logging, debugging and troubleshooting/diagnostic helpers. */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c11a44ea1bf..06a4c0fd7be 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -361,6 +361,7 @@ typedef unsigned char *sk_buff_data_t; * ports. * @wifi_acked_valid: wifi_acked was set * @wifi_acked: whether frame was acked on wifi or not + * @no_fcs: Request NIC to treat last 4 bytes as Ethernet FCS * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking @@ -459,7 +460,8 @@ struct sk_buff { __u8 l4_rxhash:1; __u8 wifi_acked_valid:1; __u8 wifi_acked:1; - /* 10/12 bit hole (depending on ndisc_nodetype presence) */ + __u8 no_fcs:1; + /* 9/11 bit hole (depending on ndisc_nodetype presence) */ kmemcheck_bitfield_end(flags2); #ifdef CONFIG_NET_DMA diff --git a/include/net/sock.h b/include/net/sock.h index 9c0553b9e45..ba761e7de25 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -615,6 +615,10 @@ enum sock_flags { SOCK_RXQ_OVFL, SOCK_ZEROCOPY, /* buffers from userspace */ SOCK_WIFI_STATUS, /* push wifi status to userspace */ + SOCK_NOFCS, /* Tell NIC not to do the Ethernet FCS. + * Will use last 4 bytes of packet sent from + * user-space instead. + */ }; static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f3a53078075..6eb656acdfe 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -592,6 +592,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->rxhash = old->rxhash; new->ooo_okay = old->ooo_okay; new->l4_rxhash = old->l4_rxhash; + new->no_fcs = old->no_fcs; #ifdef CONFIG_XFRM new->sp = secpath_get(old->sp); #endif diff --git a/net/core/sock.c b/net/core/sock.c index 19942d4bb6e..55011cb691a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -799,6 +799,11 @@ set_rcvbuf: else ret = -EOPNOTSUPP; break; + + case SO_NOFCS: + sock_valbool_flag(sk, SOCK_NOFCS, valbool); + break; + default: ret = -ENOPROTOOPT; break; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 2dbb32b988c..ae2d484416d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1459,6 +1459,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, struct net_device *dev; __be16 proto = 0; int err; + int extra_len = 0; /* * Get and verify the address. @@ -1493,8 +1494,16 @@ retry: * raw protocol and you must do your own fragmentation at this level. */ + if (unlikely(sock_flag(sk, SOCK_NOFCS))) { + if (!netif_supports_nofcs(dev)) { + err = -EPROTONOSUPPORT; + goto out_unlock; + } + extra_len = 4; /* We're doing our own CRC */ + } + err = -EMSGSIZE; - if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN) + if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN + extra_len) goto out_unlock; if (!skb) { @@ -1526,7 +1535,7 @@ retry: goto retry; } - if (len > (dev->mtu + dev->hard_header_len)) { + if (len > (dev->mtu + dev->hard_header_len + extra_len)) { /* Earlier code assumed this would be a VLAN pkt, * double-check this now that we have the actual * packet in hand. @@ -1548,6 +1557,9 @@ retry: if (err < 0) goto out_unlock; + if (unlikely(extra_len == 4)) + skb->no_fcs = 1; + dev_queue_xmit(skb); rcu_read_unlock(); return len; @@ -2209,6 +2221,7 @@ static int packet_snd(struct socket *sock, struct packet_sock *po = pkt_sk(sk); unsigned short gso_type = 0; int hlen, tlen; + int extra_len = 0; /* * Get and verify the address. @@ -2288,8 +2301,16 @@ static int packet_snd(struct socket *sock, } } + if (unlikely(sock_flag(sk, SOCK_NOFCS))) { + if (!netif_supports_nofcs(dev)) { + err = -EPROTONOSUPPORT; + goto out_unlock; + } + extra_len = 4; /* We're doing our own CRC */ + } + err = -EMSGSIZE; - if (!gso_type && (len > dev->mtu + reserve + VLAN_HLEN)) + if (!gso_type && (len > dev->mtu + reserve + VLAN_HLEN + extra_len)) goto out_unlock; err = -ENOBUFS; @@ -2315,7 +2336,7 @@ static int packet_snd(struct socket *sock, if (err < 0) goto out_free; - if (!gso_type && (len > dev->mtu + reserve)) { + if (!gso_type && (len > dev->mtu + reserve + extra_len)) { /* Earlier code assumed this would be a VLAN pkt, * double-check this now that we have the actual * packet in hand. @@ -2353,6 +2374,9 @@ static int packet_snd(struct socket *sock, len += vnet_hdr_len; } + if (unlikely(extra_len == 4)) + skb->no_fcs = 1; + /* * Now send it */ -- cgit v1.2.3-70-g09d2 From 5e0c03c8cd40e5c3b7ba624b8ba9a343de79ade1 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sat, 11 Feb 2012 15:39:45 +0000 Subject: net: Support RX-ALL feature flag. This flag requests that network devices pass all received frames up the stack, even ones with errors such as invalid FCS (frame check sum). This will allow sniffers to see bad packets and perhaps give the user some idea how to fix the problem. Signed-off-by: Ben Greear Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- Documentation/networking/netdev-features.txt | 7 +++++++ include/linux/netdev_features.h | 2 ++ net/core/ethtool.c | 1 + 3 files changed, 10 insertions(+) (limited to 'net') diff --git a/Documentation/networking/netdev-features.txt b/Documentation/networking/netdev-features.txt index 7d2781230d3..4164f5c02e4 100644 --- a/Documentation/networking/netdev-features.txt +++ b/Documentation/networking/netdev-features.txt @@ -158,3 +158,10 @@ VLANs. This may be not useful, though.] This requests that the NIC append the Ethernet Frame Checksum (FCS) to the end of the skb data. This allows sniffers and other tools to read the CRC recorded by the NIC on receipt of the packet. + +* rx-all + +This requests that the NIC receive all possible frames, including errored +frames (such as bad FCS, etc). This can be helpful when sniffing a link with +bad packets on it. Some NICs may receive more packets if also put into normal +PROMISC mdoe. diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index d1331865f83..5ac32123035 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -55,6 +55,7 @@ enum { NETIF_F_NOCACHE_COPY_BIT, /* Use no-cache copyfromuser */ NETIF_F_LOOPBACK_BIT, /* Enable loopback */ NETIF_F_RXFCS_BIT, /* Append FCS to skb pkt data */ + NETIF_F_RXALL_BIT, /* Receive errored frames too */ /* * Add your fresh new feature above and remember to update @@ -100,6 +101,7 @@ enum { #define NETIF_F_UFO __NETIF_F(UFO) #define NETIF_F_VLAN_CHALLENGED __NETIF_F(VLAN_CHALLENGED) #define NETIF_F_RXFCS __NETIF_F(RXFCS) +#define NETIF_F_RXALL __NETIF_F(RXALL) /* Features valid for ethtool to change */ /* = all defined minus driver/device-class-related */ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 080161924a0..6d6d7d25caa 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -74,6 +74,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_NOCACHE_COPY_BIT] = "tx-nocache-copy", [NETIF_F_LOOPBACK_BIT] = "loopback", [NETIF_F_RXFCS_BIT] = "rx-fcs", + [NETIF_F_RXALL_BIT] = "rx-all", }; static int ethtool_get_features(struct net_device *dev, void __user *useraddr) -- cgit v1.2.3-70-g09d2 From 3159d3843aa628b0ee9e8ef4b4fe8c935500c03f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Feb 2012 13:47:56 +0200 Subject: Bluetooth: Fix init request completion with old controllers With Bluetooth 1.1 controllers the last command in the HCI init sequence will be a write_local_name, however there was no callback to indicate init request completion in this case. This patch fixes the issue by adding the necessary callback to the write_local_name_complete handler. Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fb6543b60de..3e817fed770 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -217,6 +217,8 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); hci_dev_unlock(hdev); + + hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); } static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 28b8df77449faa03b573638e089a855f8d25e0ed Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 24 Feb 2012 12:45:44 +0200 Subject: Bluetooth: Fix init request completion with AMP controllers Mark request status as done for Read Local Version HCI command. In AMP initialization this HCI command is the last and needs to be completed. Signed-off-by: Andrei Emeltchenko Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3e817fed770..e920cd520a8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -620,7 +620,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, rp->status); if (rp->status) - return; + goto done; hdev->hci_ver = rp->hci_ver; hdev->hci_rev = __le16_to_cpu(rp->hci_rev); @@ -634,6 +634,9 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(HCI_INIT, &hdev->flags)) hci_setup(hdev); + +done: + hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status); } static void hci_setup_link_policy(struct hci_dev *hdev) -- cgit v1.2.3-70-g09d2 From 5b4cedaa14bd1fe3ca1d59c684203a6ae7747faa Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 24 Feb 2012 16:35:32 +0200 Subject: Bluetooth: Fix double locking in LE and conless chan Remove socket lock since chan->ops->recv locks socket itself. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5f4cfea3391..db04c9e4e1d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4369,18 +4369,13 @@ done: static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) { - struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_psm(0, psm, conn->src); if (!chan) goto drop; - sk = chan->sk; - - lock_sock(sk); - - BT_DBG("sk %p, len %d", sk, skb->len); + BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_BOUND && chan->state != BT_CONNECTED) goto drop; @@ -4389,31 +4384,23 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str goto drop; if (!chan->ops->recv(chan->data, skb)) - goto done; + return 0; drop: kfree_skb(skb); -done: - if (sk) - release_sock(sk); return 0; } static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) { - struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_scid(0, cid, conn->src); if (!chan) goto drop; - sk = chan->sk; - - lock_sock(sk); - - BT_DBG("sk %p, len %d", sk, skb->len); + BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_BOUND && chan->state != BT_CONNECTED) goto drop; @@ -4422,14 +4409,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct goto drop; if (!chan->ops->recv(chan->data, skb)) - goto done; + return 0; drop: kfree_skb(skb); -done: - if (sk) - release_sock(sk); return 0; } -- cgit v1.2.3-70-g09d2 From 9b27f350688c9399da10c2b888c4044c2c1bd923 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 24 Feb 2012 16:00:00 +0200 Subject: Bluetooth: Remove duplicated code in l2cap conn req The same sequence sending L2CAP Connection Request was used in several places. Using subroutine makes those places easy to read. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 49 ++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index db04c9e4e1d..bdcfbf0f631 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -667,6 +667,21 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); } +static void l2cap_send_conn_req(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct l2cap_conn_req req; + + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; + + chan->ident = l2cap_get_ident(conn); + + set_bit(CONF_CONNECT_PEND, &chan->conf_state); + + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); +} + static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; @@ -676,17 +691,8 @@ static void l2cap_do_start(struct l2cap_chan *chan) return; if (l2cap_chan_check_security(chan) && - __l2cap_no_conn_pending(chan)) { - struct l2cap_conn_req req; - req.scid = cpu_to_le16(chan->scid); - req.psm = chan->psm; - - chan->ident = l2cap_get_ident(conn); - set_bit(CONF_CONNECT_PEND, &chan->conf_state); - - l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, - sizeof(req), &req); - } + __l2cap_no_conn_pending(chan)) + l2cap_send_conn_req(chan); } else { struct l2cap_info_req req; req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); @@ -763,8 +769,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } if (chan->state == BT_CONNECT) { - struct l2cap_conn_req req; - if (!l2cap_chan_check_security(chan) || !__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); @@ -779,14 +783,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) continue; } - req.scid = cpu_to_le16(chan->scid); - req.psm = chan->psm; - - chan->ident = l2cap_get_ident(conn); - set_bit(CONF_CONNECT_PEND, &chan->conf_state); - - l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, - sizeof(req), &req); + l2cap_send_conn_req(chan); } else if (chan->state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -4593,15 +4590,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (chan->state == BT_CONNECT) { if (!status) { - struct l2cap_conn_req req; - req.scid = cpu_to_le16(chan->scid); - req.psm = chan->psm; - - chan->ident = l2cap_get_ident(conn); - set_bit(CONF_CONNECT_PEND, &chan->conf_state); - - l2cap_send_cmd(conn, chan->ident, - L2CAP_CONN_REQ, sizeof(req), &req); + l2cap_send_conn_req(chan); } else { __clear_chan_timer(chan); __set_chan_timer(chan, -- cgit v1.2.3-70-g09d2 From bc2f7996858db66f2d5b154aac10971655f72cad Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 24 Feb 2012 14:48:34 -0500 Subject: net: Add missing getsockopt for SO_NOFCS. Signed-off-by: David S. Miller --- net/core/sock.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/core/sock.c b/net/core/sock.c index 55011cb691a..216719cb5c7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1035,6 +1035,9 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sk->sk_peek_off; break; + case SO_NOFCS: + v.val = !!sock_flag(sk, SOCK_NOFCS); + break; default: return -ENOPROTOOPT; } -- cgit v1.2.3-70-g09d2 From fc0eea691a06ba8516795fb7a198239fb9db1cfc Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 28 Oct 2011 16:26:41 -0400 Subject: tipc: Introduce node signature field in neighbor discovery message Adds support for the new "node signature" in neighbor discovery messages, which is a 16 bit identifier chosen randomly when TIPC is initialized. This field makes it possible for nodes receiving a neighbor discovery message to detect if multiple neighboring nodes are using the same network address (i.e. ), even when the messages are arriving on different interfaces. This first phase of node signature support creates the signature, incorporates it into outgoing neighbor discovery messages, and tracks the signature used by valid neighbors. An upcoming patch builds on this foundation to implement the improved duplicate neighbor detection checking. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/discover.c | 3 +++ net/tipc/msg.h | 10 ++++++++++ net/tipc/node.c | 1 + net/tipc/node.h | 7 +++++++ 4 files changed, 21 insertions(+) (limited to 'net') diff --git a/net/tipc/discover.c b/net/tipc/discover.c index a00e5f81156..7ae1b4c33ae 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -82,6 +82,7 @@ static struct sk_buff *tipc_disc_init_msg(u32 type, msg = buf_msg(buf); tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain); msg_set_non_seq(msg, 1); + msg_set_node_sig(msg, tipc_random); msg_set_dest_domain(msg, dest_domain); msg_set_bc_netid(msg, tipc_net_id); b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg)); @@ -128,6 +129,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); + u32 signature = msg_node_sig(msg); int link_fully_up; media_addr.broadcast = 1; @@ -197,6 +199,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } /* Accept discovery message & send response, if necessary */ + n_ptr->signature = signature; link_fully_up = link_working_working(link); if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 7b0cda16710..2ec13b73181 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -517,6 +517,16 @@ static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n) msg_set_bits(m, 1, 16, 0x1fff, n); } +static inline u32 msg_node_sig(struct tipc_msg *m) +{ + return msg_bits(m, 1, 0, 0xffff); +} + +static inline void msg_set_node_sig(struct tipc_msg *m, u32 n) +{ + msg_set_bits(m, 1, 0, 0xffff, n); +} + /* * Word 2 diff --git a/net/tipc/node.c b/net/tipc/node.c index 7bc45e135fb..153425997cc 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -112,6 +112,7 @@ struct tipc_node *tipc_node_create(u32 addr) } list_add_tail(&n_ptr->list, &temp_node->list); n_ptr->block_setup = WAIT_PEER_DOWN; + n_ptr->signature = INVALID_NODE_SIG; tipc_num_nodes++; diff --git a/net/tipc/node.h b/net/tipc/node.h index e1b78a2199c..7bf526af1df 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -42,6 +42,11 @@ #include "net.h" #include "bearer.h" +/* + * Out-of-range value for node signature + */ +#define INVALID_NODE_SIG 0x10000 + /* Flags used to block (re)establishment of contact with a neighboring node */ #define WAIT_PEER_DOWN 0x0001 /* wait to see that peer's links are down */ @@ -61,6 +66,7 @@ * @block_setup: bit mask of conditions preventing link establishment to node * @link_cnt: number of links to node * @permit_changeover: non-zero if node has redundant links to this system + * @signature: node instance identifier * @bclink: broadcast-related info * @supportable: non-zero if node supports TIPC b'cast link capability * @supported: non-zero if node supports TIPC b'cast capability @@ -86,6 +92,7 @@ struct tipc_node { int working_links; int block_setup; int permit_changeover; + u32 signature; struct { u8 supportable; u8 supported; -- cgit v1.2.3-70-g09d2 From 97878a405c0ffe0f6433e1fb51834d4619ece025 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 28 Oct 2011 17:30:08 -0400 Subject: tipc: Detect duplicate nodes using different network interfaces Utilizes the new "node signature" field in neighbor discovery messages to ensure that all links TIPC associates with a given network address belong to the same neighboring node. (Previously, TIPC could not tell if link setup requests arriving on different interfaces were from the same node or from two different nodes that has mistakenly been assigned the same network address.) The revised algorithm for detecting a duplicate node considers both the node signature and the network interface adddress specified in a request message when deciding how to respond to a link setup request. This prevents false alarms that might otherwise arise during normal network operation under the following scenarios: a) A neighboring node reboots. (The node's signature changes, but the network interface address remains unchanged.) b) A neighboring node's network interface is replaced. (The node's signature remains unchanged, but the network interface address changes.) c) A neighboring node is completely replaced. (The node's signature and network interface address both change.) The algorithm also handles cases in which a node reboots and re-establishes its links to TIPC (or begins re-establishing those links) before TIPC detects that it is using a new node signature. In such cases of "delayed rediscovery" TIPC simply accepts the new signature without disrupting communication that is already underway over the links. Thanks to Laser [gotolaser@gmail.com] for his contributions to the development of this enhancement. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/discover.c | 72 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 7ae1b4c33ae..f5f9bf7a043 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -122,7 +122,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) { struct tipc_node *n_ptr; struct tipc_link *link; - struct tipc_media_addr media_addr, *addr; + struct tipc_media_addr media_addr; struct sk_buff *rbuf; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); @@ -130,13 +130,14 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); u32 signature = msg_node_sig(msg); + int addr_mismatch; int link_fully_up; media_addr.broadcast = 1; b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); buf_discard(buf); - /* Validate discovery message from requesting node */ + /* Ensure message from node is valid and communication is permitted */ if (net_id != tipc_net_id) return; if (media_addr.broadcast) @@ -164,15 +165,50 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } tipc_node_lock(n_ptr); + /* Prepare to validate requesting node's signature and media address */ link = n_ptr->links[b_ptr->identity]; + addr_mismatch = (link != NULL) && + memcmp(&link->media_addr, &media_addr, sizeof(media_addr)); - /* Create a link endpoint for this bearer, if necessary */ - if (!link) { - link = tipc_link_create(n_ptr, b_ptr, &media_addr); - if (!link) { + /* + * Ensure discovery message's signature is correct + * + * If signature is incorrect and there is no working link to the node, + * accept the new signature but invalidate all existing links to the + * node so they won't re-activate without a new discovery message. + * + * If signature is incorrect and the requested link to the node is + * working, accept the new signature. (This is an instance of delayed + * rediscovery, where a link endpoint was able to re-establish contact + * with its peer endpoint on a node that rebooted before receiving a + * discovery message from that node.) + * + * If signature is incorrect and there is a working link to the node + * that is not the requested link, reject the request (must be from + * a duplicate node). + */ + if (signature != n_ptr->signature) { + if (n_ptr->working_links == 0) { + struct tipc_link *curr_link; + int i; + + for (i = 0; i < MAX_BEARERS; i++) { + curr_link = n_ptr->links[i]; + if (curr_link) { + memset(&curr_link->media_addr, 0, + sizeof(media_addr)); + tipc_link_reset(curr_link); + } + } + addr_mismatch = (link != NULL); + } else if (tipc_link_is_up(link) && !addr_mismatch) { + /* delayed rediscovery */ + } else { + disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; } + n_ptr->signature = signature; } /* @@ -185,21 +221,29 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) * the new media address and reset the link to ensure it starts up * cleanly. */ - addr = &link->media_addr; - if (memcmp(addr, &media_addr, sizeof(*addr))) { - if (tipc_link_is_up(link) || (!link->started)) { + + if (addr_mismatch) { + if (tipc_link_is_up(link)) { disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; + } else { + memcpy(&link->media_addr, &media_addr, + sizeof(media_addr)); + tipc_link_reset(link); + } + } + + /* Create a link endpoint for this bearer, if necessary */ + if (!link) { + link = tipc_link_create(n_ptr, b_ptr, &media_addr); + if (!link) { + tipc_node_unlock(n_ptr); + return; } - warn("Resetting link <%s>, peer interface address changed\n", - link->name); - memcpy(addr, &media_addr, sizeof(*addr)); - tipc_link_reset(link); } /* Accept discovery message & send response, if necessary */ - n_ptr->signature = signature; link_fully_up = link_working_working(link); if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { -- cgit v1.2.3-70-g09d2 From c74a46110fd5f97bf9299e68e9ed0453bdacb181 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 2 Nov 2011 15:08:44 -0400 Subject: tipc: Remove duplicate check of message destination node Eliminates a check in the processing of TIPC messages arriving from off node that ensures the message is destined for this node, since this check duplicates an earlier check. (The check would be necessary if TIPC needed to be able to route incoming messages to another node, but the elimination of multi-cluster support means that this never happens and all incoming messages are consumed by the receiving node.) Note: This change involves the elimination of a single "if" statement with a large "then" clause; consequently, a significant number of lines end up getting re-indented. In addition, a simple message header access routine that is no longer referenced is eliminated. However, the only functional change is the elimination of the single check described above. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 93 ++++++++++++++++++++++++++++----------------------------- net/tipc/msg.h | 5 ---- 2 files changed, 46 insertions(+), 52 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index d8b0a22367b..6cc78a97012 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1773,57 +1773,56 @@ protocol_check: if (unlikely(l_ptr->oldest_deferred_in)) head = link_insert_deferred_queue(l_ptr, head); - if (likely(msg_is_dest(msg, tipc_own_addr))) { - int ret; deliver: - if (likely(msg_isdata(msg))) { - tipc_node_unlock(n_ptr); - tipc_port_recv_msg(buf); - continue; + if (likely(msg_isdata(msg))) { + tipc_node_unlock(n_ptr); + tipc_port_recv_msg(buf); + continue; + } + switch (msg_user(msg)) { + int ret; + case MSG_BUNDLER: + l_ptr->stats.recv_bundles++; + l_ptr->stats.recv_bundled += + msg_msgcnt(msg); + tipc_node_unlock(n_ptr); + tipc_link_recv_bundle(buf); + continue; + case NAME_DISTRIBUTOR: + tipc_node_unlock(n_ptr); + tipc_named_recv(buf); + continue; + case CONN_MANAGER: + tipc_node_unlock(n_ptr); + tipc_port_recv_proto_msg(buf); + continue; + case MSG_FRAGMENTER: + l_ptr->stats.recv_fragments++; + ret = tipc_link_recv_fragment( + &l_ptr->defragm_buf, + &buf, &msg); + if (ret == 1) { + l_ptr->stats.recv_fragmented++; + goto deliver; } - switch (msg_user(msg)) { - case MSG_BUNDLER: - l_ptr->stats.recv_bundles++; - l_ptr->stats.recv_bundled += - msg_msgcnt(msg); - tipc_node_unlock(n_ptr); - tipc_link_recv_bundle(buf); - continue; - case NAME_DISTRIBUTOR: - tipc_node_unlock(n_ptr); - tipc_named_recv(buf); - continue; - case CONN_MANAGER: - tipc_node_unlock(n_ptr); - tipc_port_recv_proto_msg(buf); - continue; - case MSG_FRAGMENTER: - l_ptr->stats.recv_fragments++; - ret = tipc_link_recv_fragment( - &l_ptr->defragm_buf, - &buf, &msg); - if (ret == 1) { - l_ptr->stats.recv_fragmented++; + if (ret == -1) + l_ptr->next_in_no--; + break; + case CHANGEOVER_PROTOCOL: + type = msg_type(msg); + if (link_recv_changeover_msg(&l_ptr, + &buf)) { + msg = buf_msg(buf); + seq_no = msg_seqno(msg); + if (type == ORIGINAL_MSG) goto deliver; - } - if (ret == -1) - l_ptr->next_in_no--; - break; - case CHANGEOVER_PROTOCOL: - type = msg_type(msg); - if (link_recv_changeover_msg(&l_ptr, &buf)) { - msg = buf_msg(buf); - seq_no = msg_seqno(msg); - if (type == ORIGINAL_MSG) - goto deliver; - goto protocol_check; - } - break; - default: - buf_discard(buf); - buf = NULL; - break; + goto protocol_check; } + break; + default: + buf_discard(buf); + buf = NULL; + break; } tipc_node_unlock(n_ptr); tipc_net_route_msg(buf); diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 2ec13b73181..eba524e34a6 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -384,11 +384,6 @@ static inline void msg_set_destnode(struct tipc_msg *m, u32 a) msg_set_word(m, 7, a); } -static inline int msg_is_dest(struct tipc_msg *m, u32 d) -{ - return msg_short(m) || (msg_destnode(m) == d); -} - static inline u32 msg_nametype(struct tipc_msg *m) { return msg_word(m, 8); -- cgit v1.2.3-70-g09d2 From c422f1bdc3d3f9f637b3d288a6601668e26111d6 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 2 Nov 2011 15:49:40 -0400 Subject: tipc: Simplify enforcement of reserved name type prohibition Streamlines the logic that prevents an application from binding a reserved TIPC name type to a port by moving the check to the code that handles a socket bind() operation. This allows internal TIPC subsystems to bind a reserved name without having to set an atomic flag to gain permission to use such a name. (This simplification is now possible due to the elimination of support for TIPC's native API.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/config.c | 2 +- net/tipc/name_table.c | 24 +----------------------- net/tipc/name_table.h | 2 -- net/tipc/socket.c | 3 +++ net/tipc/subscr.c | 2 +- 5 files changed, 6 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/tipc/config.c b/net/tipc/config.c index 4785bf26cdf..9fefd32e9b2 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -481,7 +481,7 @@ int tipc_cfg_init(void) seq.type = TIPC_CFG_SRV; seq.lower = seq.upper = tipc_own_addr; - res = tipc_nametbl_publish_rsv(config_port_ref, TIPC_ZONE_SCOPE, &seq); + res = tipc_publish(config_port_ref, TIPC_ZONE_SCOPE, &seq); if (res) goto failed; diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 89eb5621ebb..1196f050e33 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -114,10 +114,8 @@ struct name_table { }; static struct name_table table; -static atomic_t rsv_publ_ok = ATOMIC_INIT(0); DEFINE_RWLOCK(tipc_nametbl_lock); - static int hash(int x) { return x & (tipc_nametbl_size - 1); @@ -665,22 +663,7 @@ exit: return res; } -/** - * tipc_nametbl_publish_rsv - publish port name using a reserved name type - */ - -int tipc_nametbl_publish_rsv(u32 ref, unsigned int scope, - struct tipc_name_seq const *seq) -{ - int res; - - atomic_inc(&rsv_publ_ok); - res = tipc_publish(ref, scope, seq); - atomic_dec(&rsv_publ_ok); - return res; -} - -/** +/* * tipc_nametbl_publish - add name publication to network name tables */ @@ -694,11 +677,6 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, tipc_max_publications); return NULL; } - if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) { - warn("Publication failed, reserved name {%u,%u,%u}\n", - type, lower, upper); - return NULL; - } write_lock_bh(&tipc_nametbl_lock); table.local_publ_count++; diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 8086b42f92a..207d59ebf84 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h @@ -91,8 +91,6 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space); u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *node); int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, struct tipc_port_list *dports); -int tipc_nametbl_publish_rsv(u32 ref, unsigned int scope, - struct tipc_name_seq const *seq); struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, u32 scope, u32 port_ref, u32 key); int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e2f7c5d370b..d3227f2a216 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -355,6 +355,9 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) else if (addr->addrtype != TIPC_ADDR_NAMESEQ) return -EAFNOSUPPORT; + if (addr->addr.nameseq.type < TIPC_RESERVED_TYPES) + return -EACCES; + return (addr->scope > 0) ? tipc_publish(portref, addr->scope, &addr->addr.nameseq) : tipc_withdraw(portref, -addr->scope, &addr->addr.nameseq); diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 8c49566da8f..b2964e9895d 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -552,7 +552,7 @@ int tipc_subscr_start(void) if (res) goto failed; - res = tipc_nametbl_publish_rsv(topsrv.setup_port, TIPC_NODE_SCOPE, &seq); + res = tipc_publish(topsrv.setup_port, TIPC_NODE_SCOPE, &seq); if (res) { tipc_deleteport(topsrv.setup_port); topsrv.setup_port = 0; -- cgit v1.2.3-70-g09d2 From f80c24d9964c8a15c55d1afc2dea327c5eff7d6b Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 3 Nov 2011 11:12:01 -0400 Subject: tipc: Add check to prevent insertion of duplicate name table entries Adds a new check to TIPC's name table logic to reject any attempt to create a new name publication that is identical to an existing one. (Such an attempt will never happen under normal circumstances, but could arise if another network node malfunctions and issues a duplicate name publication message.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/name_table.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net') diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 1196f050e33..c2224f98e64 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -268,6 +268,13 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, } info = sseq->info; + + /* Check if an identical publication already exists */ + list_for_each_entry(publ, &info->zone_list, zone_list) { + if ((publ->ref == port) && (publ->key == key) && + (!publ->node || (publ->node == node))) + return NULL; + } } else { u32 inspos; struct sub_seq *freesseq; -- cgit v1.2.3-70-g09d2 From 732efba4d77e1b0857984c401a7b18784f51b075 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 23 Feb 2012 15:44:08 -0500 Subject: tipc: nuke the delimit static inline function. This "shortform" is actually longer than typing out what it is really trying to do, and just makes reading the code more difficult, so lets simply shoot it in the head. In the case of log.c - the comparison is on a u32, so we can drop the check for < 0 at the same time. Signed-off-by: Paul Gortmaker --- net/tipc/config.c | 8 ++++---- net/tipc/core.h | 10 ---------- net/tipc/log.c | 2 +- 3 files changed, 5 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/tipc/config.c b/net/tipc/config.c index 9fefd32e9b2..69cca4f67e8 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -218,7 +218,7 @@ static struct sk_buff *cfg_set_max_publications(void) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); - if (value != delimit(value, 1, 65535)) + if (value < 1 || value > 65535) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max publications must be 1-65535)"); tipc_max_publications = value; @@ -233,7 +233,7 @@ static struct sk_buff *cfg_set_max_subscriptions(void) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); - if (value != delimit(value, 1, 65535)) + if (value < 1 || value > 65535) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max subscriptions must be 1-65535"); tipc_max_subscriptions = value; @@ -249,7 +249,7 @@ static struct sk_buff *cfg_set_max_ports(void) value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_ports) return tipc_cfg_reply_none(); - if (value != delimit(value, 127, 65535)) + if (value < 127 || value > 65535) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max ports must be 127-65535)"); if (tipc_mode != TIPC_NOT_RUNNING) @@ -268,7 +268,7 @@ static struct sk_buff *cfg_set_netid(void) value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_net_id) return tipc_cfg_reply_none(); - if (value != delimit(value, 1, 9999)) + if (value < 1 || value > 9999) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network id must be 1-9999)"); if (tipc_mode == TIPC_NET_MODE) diff --git a/net/tipc/core.h b/net/tipc/core.h index 2761af36d14..1260b053bf2 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -168,16 +168,6 @@ extern void tipc_netlink_stop(void); extern int tipc_socket_init(void); extern void tipc_socket_stop(void); -static inline int delimit(int val, int min, int max) -{ - if (val > max) - return max; - if (val < min) - return min; - return val; -} - - /* * TIPC timer and signal code */ diff --git a/net/tipc/log.c b/net/tipc/log.c index 952c39f643e..895c6e530b0 100644 --- a/net/tipc/log.c +++ b/net/tipc/log.c @@ -304,7 +304,7 @@ struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, int req_tlv_space) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); - if (value != delimit(value, 0, 32768)) + if (value > 32768) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (log size must be 0-32768)"); if (tipc_log_resize(value)) -- cgit v1.2.3-70-g09d2 From 9efde4a0bd2f21dec0c7b40da2bf2c3e189e98e2 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 3 Nov 2011 13:15:10 -0400 Subject: tipc: Eliminate a test for negative unsigned quantities Simplifies a comparison operation to eliminate a useless test that checks if an unsigned value is less than zero. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bearer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 329fb659fae..5f5e89e12fc 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -456,8 +456,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) warn("Bearer <%s> rejected, illegal discovery domain\n", name); return -EINVAL; } - if ((priority < TIPC_MIN_LINK_PRI || - priority > TIPC_MAX_LINK_PRI) && + if ((priority > TIPC_MAX_LINK_PRI) && (priority != TIPC_MEDIA_LINK_PRI)) { warn("Bearer <%s> rejected, illegal priority\n", name); return -EINVAL; -- cgit v1.2.3-70-g09d2 From a635b46bd884efc1fc98819cb5a200da255d575c Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 4 Nov 2011 11:54:43 -0400 Subject: tipc: Hide internal details of node table implementation Relocates information about the size of TIPC's node table index and its associated hash function, since only node subsystem routines need to have access to this information. Note that these changes are essentially cosmetic in nature, and have no impact on the actual operation of TIPC. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/node.c | 13 +++++++++++++ net/tipc/node.h | 12 ------------ 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/tipc/node.c b/net/tipc/node.c index 153425997cc..1790f503f57 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -39,6 +39,8 @@ #include "node.h" #include "name_distr.h" +#define NODE_HTABLE_SIZE 512 + static void node_lost_contact(struct tipc_node *n_ptr); static void node_established_contact(struct tipc_node *n_ptr); @@ -50,6 +52,17 @@ static u32 tipc_num_nodes; static atomic_t tipc_num_links = ATOMIC_INIT(0); +/* + * A trivial power-of-two bitmask technique is used for speed, since this + * operation is done for every incoming TIPC packet. The number of hash table + * entries has been chosen so that no hash chain exceeds 8 nodes and will + * usually be much smaller (typically only a single node). + */ +static inline unsigned int tipc_hashfn(u32 addr) +{ + return addr & (NODE_HTABLE_SIZE - 1); +} + /* * tipc_node_find - locate specified node object, if it exists */ diff --git a/net/tipc/node.h b/net/tipc/node.h index 7bf526af1df..72561c971d6 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -107,20 +107,8 @@ struct tipc_node { } bclink; }; -#define NODE_HTABLE_SIZE 512 extern struct list_head tipc_node_list; -/* - * A trivial power-of-two bitmask technique is used for speed, since this - * operation is done for every incoming TIPC packet. The number of hash table - * entries has been chosen so that no hash chain exceeds 8 nodes and will - * usually be much smaller (typically only a single node). - */ -static inline unsigned int tipc_hashfn(u32 addr) -{ - return addr & (NODE_HTABLE_SIZE - 1); -} - struct tipc_node *tipc_node_find(u32 addr); struct tipc_node *tipc_node_create(u32 addr); void tipc_node_delete(struct tipc_node *n_ptr); -- cgit v1.2.3-70-g09d2 From 5f6d9123f1c7ef7297b0da1620988fe16c738e75 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 4 Nov 2011 13:24:29 -0400 Subject: tipc: Eliminate trivial buffer manipulation helper routines Gets rid of two inlined routines that simply call existing sk_buff manipulation routines, since there is no longer any extra processing done by the helper routines. Note that these changes are essentially cosmetic in nature, and have no impact on the actual operation of TIPC. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 12 ++++---- net/tipc/core.h | 24 ---------------- net/tipc/discover.c | 6 ++-- net/tipc/link.c | 80 +++++++++++++++++++++++++-------------------------- net/tipc/msg.c | 2 +- net/tipc/name_distr.c | 4 +-- net/tipc/net.c | 4 +-- net/tipc/node.c | 4 +-- net/tipc/port.c | 14 ++++----- net/tipc/socket.c | 8 +++--- 10 files changed, 67 insertions(+), 91 deletions(-) (limited to 'net') diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 41ecf313073..e00441a2092 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -256,7 +256,7 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) if (bcbuf_acks(crs) == 0) { bcl->first_out = next; bcl->out_queue_size--; - buf_discard(crs); + kfree_skb(crs); released = 1; } crs = next; @@ -330,7 +330,7 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent) tipc_bearer_send(&bcbearer->bearer, buf, NULL); bcl->stats.sent_nacks++; spin_unlock_bh(&bc_lock); - buf_discard(buf); + kfree_skb(buf); n_ptr->bclink.oos_state++; } @@ -374,7 +374,7 @@ int tipc_bclink_send_msg(struct sk_buff *buf) if (!bclink->bcast_nodes.count) { res = msg_data_sz(buf_msg(buf)); - buf_discard(buf); + kfree_skb(buf); goto exit; } @@ -480,7 +480,7 @@ receive: if (likely(msg_mcast(msg))) tipc_port_recv_mcast(buf, NULL); else - buf_discard(buf); + kfree_skb(buf); } else if (msg_user(msg) == MSG_BUNDLER) { spin_lock_bh(&bc_lock); bclink_accept_pkt(node, seqno); @@ -513,7 +513,7 @@ receive: bclink_accept_pkt(node, seqno); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); - buf_discard(buf); + kfree_skb(buf); } buf = NULL; @@ -569,7 +569,7 @@ receive: unlock: tipc_node_unlock(node); exit: - buf_discard(buf); + kfree_skb(buf); } u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr) diff --git a/net/tipc/core.h b/net/tipc/core.h index 1260b053bf2..aefe1869572 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -269,28 +269,4 @@ static inline struct tipc_msg *buf_msg(struct sk_buff *skb) extern struct sk_buff *tipc_buf_acquire(u32 size); -/** - * buf_discard - frees a TIPC message buffer - * @skb: message buffer - * - * Frees a message buffer. If passed NULL, just returns. - */ - -static inline void buf_discard(struct sk_buff *skb) -{ - kfree_skb(skb); -} - -/** - * buf_linearize - convert a TIPC message buffer into a single contiguous piece - * @skb: message buffer - * - * Returns 0 on success. - */ - -static inline int buf_linearize(struct sk_buff *skb) -{ - return skb_linearize(skb); -} - #endif diff --git a/net/tipc/discover.c b/net/tipc/discover.c index f5f9bf7a043..c630a21b2be 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -135,7 +135,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) media_addr.broadcast = 1; b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); - buf_discard(buf); + kfree_skb(buf); /* Ensure message from node is valid and communication is permitted */ if (net_id != tipc_net_id) @@ -250,7 +250,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); if (rbuf) { b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); - buf_discard(rbuf); + kfree_skb(rbuf); } } @@ -396,7 +396,7 @@ void tipc_disc_delete(struct tipc_link_req *req) { k_cancel_timer(&req->timer); k_term_timer(&req->timer); - buf_discard(req->buf); + kfree_skb(req->buf); kfree(req); } diff --git a/net/tipc/link.c b/net/tipc/link.c index 6cc78a97012..f16e65dd50c 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -484,7 +484,7 @@ static void link_release_outqueue(struct tipc_link *l_ptr) while (buf) { next = buf->next; - buf_discard(buf); + kfree_skb(buf); buf = next; } l_ptr->first_out = NULL; @@ -503,7 +503,7 @@ void tipc_link_reset_fragments(struct tipc_link *l_ptr) while (buf) { next = buf->next; - buf_discard(buf); + kfree_skb(buf); buf = next; } l_ptr->defragm_buf = NULL; @@ -522,20 +522,20 @@ void tipc_link_stop(struct tipc_link *l_ptr) buf = l_ptr->oldest_deferred_in; while (buf) { next = buf->next; - buf_discard(buf); + kfree_skb(buf); buf = next; } buf = l_ptr->first_out; while (buf) { next = buf->next; - buf_discard(buf); + kfree_skb(buf); buf = next; } tipc_link_reset_fragments(l_ptr); - buf_discard(l_ptr->proto_msg_queue); + kfree_skb(l_ptr->proto_msg_queue); l_ptr->proto_msg_queue = NULL; } @@ -571,12 +571,12 @@ void tipc_link_reset(struct tipc_link *l_ptr) /* Clean up all queues: */ link_release_outqueue(l_ptr); - buf_discard(l_ptr->proto_msg_queue); + kfree_skb(l_ptr->proto_msg_queue); l_ptr->proto_msg_queue = NULL; buf = l_ptr->oldest_deferred_in; while (buf) { struct sk_buff *next = buf->next; - buf_discard(buf); + kfree_skb(buf); buf = next; } if (!list_empty(&l_ptr->waiting_ports)) @@ -810,7 +810,7 @@ static int link_bundle_buf(struct tipc_link *l_ptr, skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size); msg_set_size(bundler_msg, to_pos + size); msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); - buf_discard(buf); + kfree_skb(buf); l_ptr->stats.sent_bundled++; return 1; } @@ -878,10 +878,10 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf) if (unlikely(queue_size >= queue_limit)) { if (imp <= TIPC_CRITICAL_IMPORTANCE) { link_schedule_port(l_ptr, msg_origport(msg), size); - buf_discard(buf); + kfree_skb(buf); return -ELINKCONG; } - buf_discard(buf); + kfree_skb(buf); if (imp > CONN_MANAGER) { warn("Resetting link <%s>, send queue full", l_ptr->name); tipc_link_reset(l_ptr); @@ -968,10 +968,10 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector) if (l_ptr) res = tipc_link_send_buf(l_ptr, buf); else - buf_discard(buf); + kfree_skb(buf); tipc_node_unlock(n_ptr); } else { - buf_discard(buf); + kfree_skb(buf); } read_unlock_bh(&tipc_net_lock); return res; @@ -1018,7 +1018,7 @@ void tipc_link_send_names(struct list_head *message_list, u32 dest) list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) { list_del((struct list_head *)buf); - buf_discard(buf); + kfree_skb(buf); } } @@ -1262,7 +1262,7 @@ again: error: for (; buf_chain; buf_chain = buf) { buf = buf_chain->next; - buf_discard(buf_chain); + kfree_skb(buf_chain); } return -EFAULT; } @@ -1316,7 +1316,7 @@ error: tipc_node_unlock(node); for (; buf_chain; buf_chain = buf) { buf = buf_chain->next; - buf_discard(buf_chain); + kfree_skb(buf_chain); } goto again; } @@ -1324,7 +1324,7 @@ error: reject: for (; buf_chain; buf_chain = buf) { buf = buf_chain->next; - buf_discard(buf_chain); + kfree_skb(buf_chain); } return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, total_len, TIPC_ERR_NO_NODE); @@ -1390,7 +1390,7 @@ u32 tipc_link_push_packet(struct tipc_link *l_ptr) msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { l_ptr->unacked_window = 0; - buf_discard(buf); + kfree_skb(buf); l_ptr->proto_msg_queue = NULL; return 0; } else { @@ -1679,7 +1679,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) /* Ensure message data is a single contiguous unit */ - if (unlikely(buf_linearize(buf))) + if (unlikely(skb_linearize(buf))) goto cont; /* Handle arrival of a non-unicast link message */ @@ -1744,7 +1744,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) less_eq(buf_seqno(crs), ackd)) { struct sk_buff *next = crs->next; - buf_discard(crs); + kfree_skb(crs); crs = next; released++; } @@ -1820,7 +1820,7 @@ deliver: } break; default: - buf_discard(buf); + kfree_skb(buf); buf = NULL; break; } @@ -1851,7 +1851,7 @@ deliver: } tipc_node_unlock(n_ptr); cont: - buf_discard(buf); + kfree_skb(buf); } read_unlock_bh(&tipc_net_lock); } @@ -1891,7 +1891,7 @@ u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail, u32 curr_seqno = buf_seqno(queue_buf); if (seq_no == curr_seqno) { - buf_discard(buf); + kfree_skb(buf); return 0; } @@ -1932,7 +1932,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, if (less(seq_no, mod(l_ptr->next_in_no))) { l_ptr->stats.duplicates++; - buf_discard(buf); + kfree_skb(buf); return; } @@ -1961,7 +1961,7 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, /* Discard any previous message that was deferred due to congestion */ if (l_ptr->proto_msg_queue) { - buf_discard(l_ptr->proto_msg_queue); + kfree_skb(l_ptr->proto_msg_queue); l_ptr->proto_msg_queue = NULL; } @@ -2060,7 +2060,7 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, /* Discard message if it was sent successfully */ l_ptr->unacked_window = 0; - buf_discard(buf); + kfree_skb(buf); } /* @@ -2204,7 +2204,7 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) break; } exit: - buf_discard(buf); + kfree_skb(buf); } @@ -2402,7 +2402,7 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr, warn("Link changeover error, duplicate msg dropped\n"); goto exit; } - buf_discard(tunnel_buf); + kfree_skb(tunnel_buf); return 1; } @@ -2434,7 +2434,7 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr, } else { *buf = buf_extract(tunnel_buf, INT_H_SIZE); if (*buf != NULL) { - buf_discard(tunnel_buf); + kfree_skb(tunnel_buf); return 1; } else { warn("Link changeover error, original msg dropped\n"); @@ -2442,7 +2442,7 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr, } exit: *buf = NULL; - buf_discard(tunnel_buf); + kfree_skb(tunnel_buf); return 0; } @@ -2464,7 +2464,7 @@ void tipc_link_recv_bundle(struct sk_buff *buf) pos += align(msg_size(buf_msg(obuf))); tipc_net_route_msg(obuf); } - buf_discard(buf); + kfree_skb(buf); } /* @@ -2513,11 +2513,11 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) } fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); if (fragm == NULL) { - buf_discard(buf); + kfree_skb(buf); while (buf_chain) { buf = buf_chain; buf_chain = buf_chain->next; - buf_discard(buf); + kfree_skb(buf); } return -ENOMEM; } @@ -2534,7 +2534,7 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) crs += fragm_sz; msg_set_type(&fragm_hdr, FRAGMENT); } - buf_discard(buf); + kfree_skb(buf); /* Append chain of fragments to send queue & send them */ @@ -2621,7 +2621,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, if (msg_type(imsg) == TIPC_MCAST_MSG) max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE; if (msg_size(imsg) > max) { - buf_discard(fbuf); + kfree_skb(fbuf); return 0; } pbuf = tipc_buf_acquire(msg_size(imsg)); @@ -2637,10 +2637,10 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, set_expected_frags(pbuf, exp_fragm_cnt - 1); } else { dbg("Link unable to reassemble fragmented message\n"); - buf_discard(fbuf); + kfree_skb(fbuf); return -1; } - buf_discard(fbuf); + kfree_skb(fbuf); return 0; } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) { u32 dsz = msg_data_sz(fragm); @@ -2649,7 +2649,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, u32 exp_frags = get_expected_frags(pbuf) - 1; skb_copy_to_linear_data_offset(pbuf, crs, msg_data(fragm), dsz); - buf_discard(fbuf); + kfree_skb(fbuf); /* Is message complete? */ @@ -2666,7 +2666,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, set_expected_frags(pbuf, exp_frags); return 0; } - buf_discard(fbuf); + kfree_skb(fbuf); return 0; } @@ -2697,7 +2697,7 @@ static void link_check_defragm_bufs(struct tipc_link *l_ptr) prev->next = buf->next; else l_ptr->defragm_buf = buf->next; - buf_discard(buf); + kfree_skb(buf); } buf = next; } @@ -3072,7 +3072,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_s str_len = tipc_link_stats((char *)TLV_DATA(req_tlv_area), (char *)TLV_DATA(rep_tlv), MAX_LINK_STATS_INFO); if (!str_len) { - buf_discard(buf); + kfree_skb(buf); return tipc_cfg_reply_error_string("link not found"); } diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 3e4d3e29be6..e3afe162c0a 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -106,7 +106,7 @@ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, if (likely(res)) return dsz; - buf_discard(*buf); + kfree_skb(*buf); *buf = NULL; return -EFAULT; } diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index acecfda82f3..d57da615961 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -120,7 +120,7 @@ static void named_cluster_distribute(struct sk_buff *buf) } } - buf_discard(buf); + kfree_skb(buf); } /** @@ -312,7 +312,7 @@ void tipc_named_recv(struct sk_buff *buf) item++; } write_unlock_bh(&tipc_nametbl_lock); - buf_discard(buf); + kfree_skb(buf); } /** diff --git a/net/tipc/net.c b/net/tipc/net.c index 61afee7e829..2abd4be4933 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -117,7 +117,7 @@ static void net_route_named_msg(struct sk_buff *buf) u32 dport; if (!msg_named(msg)) { - buf_discard(buf); + kfree_skb(buf); return; } @@ -161,7 +161,7 @@ void tipc_net_route_msg(struct sk_buff *buf) tipc_port_recv_proto_msg(buf); break; default: - buf_discard(buf); + kfree_skb(buf); } return; } diff --git a/net/tipc/node.c b/net/tipc/node.c index 1790f503f57..24c42f7568a 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -353,12 +353,12 @@ static void node_lost_contact(struct tipc_node *n_ptr) while (n_ptr->bclink.deferred_head) { struct sk_buff *buf = n_ptr->bclink.deferred_head; n_ptr->bclink.deferred_head = buf->next; - buf_discard(buf); + kfree_skb(buf); } n_ptr->bclink.deferred_size = 0; if (n_ptr->bclink.defragm) { - buf_discard(n_ptr->bclink.defragm); + kfree_skb(n_ptr->bclink.defragm); n_ptr->bclink.defragm = NULL; } diff --git a/net/tipc/port.c b/net/tipc/port.c index ba3268b8da4..c4b5a347037 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -116,13 +116,13 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, ibuf = skb_copy(buf, GFP_ATOMIC); if (ibuf == NULL) { tipc_port_list_free(&dports); - buf_discard(buf); + kfree_skb(buf); return -ENOMEM; } } res = tipc_bclink_send_msg(buf); if ((res < 0) && (dports.count != 0)) - buf_discard(ibuf); + kfree_skb(ibuf); } else { ibuf = buf; } @@ -187,7 +187,7 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp) } } exit: - buf_discard(buf); + kfree_skb(buf); tipc_port_list_free(dp); } @@ -420,7 +420,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) else tipc_link_send(rbuf, src_node, msg_link_selector(rmsg)); exit: - buf_discard(buf); + kfree_skb(buf); return data_sz; } @@ -568,7 +568,7 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf) tipc_port_unlock(p_ptr); exit: tipc_net_route_msg(r_buf); - buf_discard(buf); + kfree_skb(buf); } static void port_print(struct tipc_port *p_ptr, struct print_buf *buf, int full_id) @@ -759,7 +759,7 @@ static void port_dispatcher_sigh(void *dummy) } } if (buf) - buf_discard(buf); + kfree_skb(buf); buf = next; continue; err: @@ -813,7 +813,7 @@ err: } } if (buf) - buf_discard(buf); + kfree_skb(buf); buf = next; continue; reject: diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d3227f2a216..29e957f6445 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -126,7 +126,7 @@ static atomic_t tipc_queue_size = ATOMIC_INIT(0); static void advance_rx_queue(struct sock *sk) { - buf_discard(__skb_dequeue(&sk->sk_receive_queue)); + kfree_skb(__skb_dequeue(&sk->sk_receive_queue)); atomic_dec(&tipc_queue_size); } @@ -142,7 +142,7 @@ static void discard_rx_queue(struct sock *sk) while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { atomic_dec(&tipc_queue_size); - buf_discard(buf); + kfree_skb(buf); } } @@ -288,7 +288,7 @@ static int release(struct socket *sock) break; atomic_dec(&tipc_queue_size); if (TIPC_SKB_CB(buf)->handle != 0) - buf_discard(buf); + kfree_skb(buf); else { if ((sock->state == SS_CONNECTING) || (sock->state == SS_CONNECTED)) { @@ -1615,7 +1615,7 @@ restart: if (buf) { atomic_dec(&tipc_queue_size); if (TIPC_SKB_CB(buf)->handle != 0) { - buf_discard(buf); + kfree_skb(buf); goto restart; } tipc_disconnect(tport->ref); -- cgit v1.2.3-70-g09d2 From 1cc35df847f7dba4ba06cb65bc41713df5d41404 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 4 Nov 2011 14:54:06 -0400 Subject: tipc: Remove obsolete comments about routing table updates Eliminates a block of comments that describe how routing table updates are to be handled. These comments no longer apply following the removal of TIPC's prototype multi-cluster support. Note that these changes are essentially cosmetic in nature, and have no impact on the actual operation of TIPC. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/node.c | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) (limited to 'net') diff --git a/net/tipc/node.c b/net/tipc/node.c index 24c42f7568a..d7f8b7be3d8 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -266,52 +266,6 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) n_ptr->link_cnt--; } -/* - * Routing table management - five cases to handle: - * - * 1: A link towards a zone/cluster external node comes up. - * => Send a multicast message updating routing tables of all - * system nodes within own cluster that the new destination - * can be reached via this node. - * (node.establishedContact()=>cluster.multicastNewRoute()) - * - * 2: A link towards a slave node comes up. - * => Send a multicast message updating routing tables of all - * system nodes within own cluster that the new destination - * can be reached via this node. - * (node.establishedContact()=>cluster.multicastNewRoute()) - * => Send a message to the slave node about existence - * of all system nodes within cluster: - * (node.establishedContact()=>cluster.sendLocalRoutes()) - * - * 3: A new cluster local system node becomes available. - * => Send message(s) to this particular node containing - * information about all cluster external and slave - * nodes which can be reached via this node. - * (node.establishedContact()==>network.sendExternalRoutes()) - * (node.establishedContact()==>network.sendSlaveRoutes()) - * => Send messages to all directly connected slave nodes - * containing information about the existence of the new node - * (node.establishedContact()=>cluster.multicastNewRoute()) - * - * 4: The link towards a zone/cluster external node or slave - * node goes down. - * => Send a multcast message updating routing tables of all - * nodes within cluster that the new destination can not any - * longer be reached via this node. - * (node.lostAllLinks()=>cluster.bcastLostRoute()) - * - * 5: A cluster local system node becomes unavailable. - * => Remove all references to this node from the local - * routing tables. Note: This is a completely node - * local operation. - * (node.lostAllLinks()=>network.removeAsRouter()) - * => Send messages to all directly connected slave nodes - * containing information about loss of the node - * (node.establishedContact()=>cluster.multicastLostRoute()) - * - */ - static void node_established_contact(struct tipc_node *n_ptr) { tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr); -- cgit v1.2.3-70-g09d2 From 75aba9af2410ae8fc70600d9dcda0651f20e091e Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 4 Nov 2011 15:00:02 -0400 Subject: tipc: Minor optimization to broadcast link synchronization logic Optimizes processing done when contact with a neighboring node is established to avoid recording the current state of outgoing broadcast messages if the neighboring node isn't a valid broadcast link destination, since this state information isn't needed for such nodes. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/node.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/tipc/node.c b/net/tipc/node.c index d7f8b7be3d8..12ddc658157 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -270,10 +270,8 @@ static void node_established_contact(struct tipc_node *n_ptr) { tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr); - /* Syncronize broadcast acks */ - n_ptr->bclink.acked = tipc_bclink_get_last_sent(); - if (n_ptr->bclink.supportable) { + n_ptr->bclink.acked = tipc_bclink_get_last_sent(); tipc_bclink_add_node(n_ptr->addr); n_ptr->bclink.supported = 1; } -- cgit v1.2.3-70-g09d2 From bc9f8143ecf96c17a56635d2ef4c3c6b6ec27947 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 7 Nov 2011 17:00:54 -0500 Subject: tipc: Revert name table translation optimization Restores name table translation using a non-zero domain that is "out of scope", which was broken by an earlier commit (5d9c54c1e9ececcf7e99c4f014f9bec7ee3a7def). Comments have now been added to the name table translation routine to make it clear that there are actually three possible outcomes to a translation request (found/not found/deferred), rather than just two (found/not found). Note that a straightforward revert of the earlier commit is not possible, as other changes to the name table translation logic have occurred since the incorrect optimization was made. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/name_table.c | 17 +++++++++++++---- net/tipc/port.c | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index c2224f98e64..c6a1ae36952 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -539,10 +539,17 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, } /* - * tipc_nametbl_translate - translate name to port id + * tipc_nametbl_translate - perform name translation * - * Note: on entry 'destnode' is the search domain used during translation; - * on exit it passes back the node address of the matching port (if any) + * On entry, 'destnode' is the search domain used during translation. + * + * On exit: + * - if name translation is deferred to another node/cluster/zone, + * leaves 'destnode' unchanged (will be non-zero) and returns 0 + * - if name translation is attempted and succeeds, sets 'destnode' + * to publishing node and returns port reference (will be non-zero) + * - if name translation is attempted and fails, sets 'destnode' to 0 + * and returns 0 */ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) @@ -552,6 +559,7 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) struct publication *publ; struct name_seq *seq; u32 ref = 0; + u32 node = 0; if (!tipc_in_scope(*destnode, tipc_own_addr)) return 0; @@ -609,11 +617,12 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) } ref = publ->ref; - *destnode = publ->node; + node = publ->node; no_match: spin_unlock_bh(&seq->lock); not_found: read_unlock_bh(&tipc_nametbl_lock); + *destnode = node; return ref; } diff --git a/net/tipc/port.c b/net/tipc/port.c index c4b5a347037..b103d7630c8 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -1221,7 +1221,7 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, msg_set_destnode(msg, destnode); msg_set_destport(msg, destport); - if (likely(destport)) { + if (likely(destport || destnode)) { if (likely(destnode == tipc_own_addr)) res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect, total_len); -- cgit v1.2.3-70-g09d2 From 077a26f029e76a5918edf9c1d44d5566eec719fc Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 8 Nov 2011 13:18:59 -0500 Subject: tipc: Eliminate obsolete support for "not running" mode Removes all references to TIPC's "not running" mode, since the removal of support for the native API means that there is no longer any way to interact with TIPC if it has not been initialized. The changes made consist of removing mode-based checks that are no longer needed, along with any associated code lying on non-executable control paths. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/config.c | 7 ++----- net/tipc/core.c | 10 +--------- net/tipc/core.h | 2 +- 3 files changed, 4 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/tipc/config.c b/net/tipc/config.c index 69cca4f67e8..7ca3854a2ac 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -252,11 +252,8 @@ static struct sk_buff *cfg_set_max_ports(void) if (value < 127 || value > 65535) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max ports must be 127-65535)"); - if (tipc_mode != TIPC_NOT_RUNNING) - return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED - " (cannot change max ports while TIPC is active)"); - tipc_max_ports = value; - return tipc_cfg_reply_none(); + return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED + " (cannot change max ports while TIPC is active)"); } static struct sk_buff *cfg_set_netid(void) diff --git a/net/tipc/core.c b/net/tipc/core.c index 2691cd57b8a..ec381d444bc 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -53,7 +53,7 @@ /* global variables used by multiple sub-systems within TIPC */ -int tipc_mode = TIPC_NOT_RUNNING; +int tipc_mode; int tipc_random; const char tipc_alphabet[] = @@ -125,11 +125,6 @@ int tipc_core_start_net(unsigned long addr) static void tipc_core_stop(void) { - if (tipc_mode != TIPC_NODE_MODE) - return; - - tipc_mode = TIPC_NOT_RUNNING; - tipc_netlink_stop(); tipc_handler_stop(); tipc_cfg_stop(); @@ -148,9 +143,6 @@ static int tipc_core_start(void) { int res; - if (tipc_mode != TIPC_NOT_RUNNING) - return -ENOPROTOOPT; - get_random_bytes(&tipc_random, sizeof(tipc_random)); tipc_mode = TIPC_NODE_MODE; diff --git a/net/tipc/core.h b/net/tipc/core.h index aefe1869572..9842ec08dd5 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -132,7 +132,7 @@ void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *); /* * TIPC operating mode routines */ -#define TIPC_NOT_RUNNING 0 + #define TIPC_NODE_MODE 1 #define TIPC_NET_MODE 2 -- cgit v1.2.3-70-g09d2 From b58343f9ea75f02ef48b984767511c6b3ba76eaf Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 8 Nov 2011 13:48:28 -0500 Subject: tipc: Eliminate support for tipc_mode global variable Removes all references to the global variable that records whether TIPC is running in "single node" mode or "network" mode, since this information can be easily deduced from the global variable that records TIPC's network address. (i.e. a non-zero network address means that TIPC is running in network mode.) The changes made update most existing mode-based checks to use the network address global variable. A few checks that are no longer needed are removed entirely, along with any associated code lying on non-executable control paths. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bearer.c | 2 +- net/tipc/config.c | 4 ++-- net/tipc/core.c | 2 -- net/tipc/core.h | 8 -------- net/tipc/net.c | 7 +------ net/tipc/node.c | 2 +- 6 files changed, 5 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 5f5e89e12fc..5dfd89c4042 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -435,7 +435,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) u32 i; int res = -EINVAL; - if (tipc_mode != TIPC_NET_MODE) { + if (!tipc_own_addr) { warn("Bearer <%s> rejected, not supported in standalone mode\n", name); return -ENOPROTOOPT; diff --git a/net/tipc/config.c b/net/tipc/config.c index 7ca3854a2ac..f76d3b15e4e 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -179,7 +179,7 @@ static struct sk_buff *cfg_set_own_addr(void) if (!tipc_addr_node_valid(addr)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (node address)"); - if (tipc_mode == TIPC_NET_MODE) + if (tipc_own_addr) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot change node address once assigned)"); @@ -268,7 +268,7 @@ static struct sk_buff *cfg_set_netid(void) if (value < 1 || value > 9999) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network id must be 1-9999)"); - if (tipc_mode == TIPC_NET_MODE) + if (tipc_own_addr) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot change network id once TIPC has joined a network)"); tipc_net_id = value; diff --git a/net/tipc/core.c b/net/tipc/core.c index ec381d444bc..68eba03e795 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -53,7 +53,6 @@ /* global variables used by multiple sub-systems within TIPC */ -int tipc_mode; int tipc_random; const char tipc_alphabet[] = @@ -144,7 +143,6 @@ static int tipc_core_start(void) int res; get_random_bytes(&tipc_random, sizeof(tipc_random)); - tipc_mode = TIPC_NODE_MODE; res = tipc_handler_start(); if (!res) diff --git a/net/tipc/core.h b/net/tipc/core.h index 9842ec08dd5..13837e0e56b 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -129,13 +129,6 @@ void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *); #define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */ -/* - * TIPC operating mode routines - */ - -#define TIPC_NODE_MODE 1 -#define TIPC_NET_MODE 2 - /* * Global configuration variables */ @@ -151,7 +144,6 @@ extern int tipc_remote_management; * Other global variables */ -extern int tipc_mode; extern int tipc_random; extern const char tipc_alphabet[]; diff --git a/net/tipc/net.c b/net/tipc/net.c index 2abd4be4933..d4531b07076 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -175,14 +175,10 @@ int tipc_net_start(u32 addr) { char addr_string[16]; - if (tipc_mode != TIPC_NODE_MODE) - return -ENOPROTOOPT; - tipc_subscr_stop(); tipc_cfg_stop(); tipc_own_addr = addr; - tipc_mode = TIPC_NET_MODE; tipc_named_reinit(); tipc_port_reinit(); @@ -201,10 +197,9 @@ void tipc_net_stop(void) { struct tipc_node *node, *t_node; - if (tipc_mode != TIPC_NET_MODE) + if (!tipc_own_addr) return; write_lock_bh(&tipc_net_lock); - tipc_mode = TIPC_NODE_MODE; tipc_bearer_stop(); tipc_bclink_stop(); list_for_each_entry_safe(node, t_node, &tipc_node_list, list) diff --git a/net/tipc/node.c b/net/tipc/node.c index 12ddc658157..a34cabc2c43 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -406,7 +406,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network address)"); - if (tipc_mode != TIPC_NET_MODE) + if (!tipc_own_addr) return tipc_cfg_reply_none(); read_lock_bh(&tipc_net_lock); -- cgit v1.2.3-70-g09d2 From e899b1119f1428f2b04dd7e9dba94864c33dd30b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 22 Feb 2012 16:14:32 +0100 Subject: netfilter: bridge: fix module autoload in compat case We expected 0 if module doesn't exist, which is no longer the case (42046e2e45c109ba703993c510401a11f716c8df, netfilter: x_tables: return -ENOENT for non-existant matches/targets). Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/bridge/netfilter/ebtables.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 5864cc49136..8aa4ad0e06a 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1893,10 +1893,7 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, switch (compat_mwt) { case EBT_COMPAT_MATCH: - match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE, - name, 0), "ebt_%s", name); - if (match == NULL) - return -ENOENT; + match = xt_request_find_match(NFPROTO_BRIDGE, name, 0); if (IS_ERR(match)) return PTR_ERR(match); @@ -1915,10 +1912,7 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, break; case EBT_COMPAT_WATCHER: /* fallthrough */ case EBT_COMPAT_TARGET: - wt = try_then_request_module(xt_find_target(NFPROTO_BRIDGE, - name, 0), "ebt_%s", name); - if (wt == NULL) - return -ENOENT; + wt = xt_request_find_target(NFPROTO_BRIDGE, name, 0); if (IS_ERR(wt)) return PTR_ERR(wt); off = xt_compat_target_offset(wt); -- cgit v1.2.3-70-g09d2 From 80d326fab534a5380e8f6e509a0b9076655a9670 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 24 Feb 2012 14:30:15 +0000 Subject: netlink: add netlink_dump_control structure for netlink_dump_start() Davem considers that the argument list of this interface is getting out of control. This patch tries to address this issue following his proposal: struct netlink_dump_control c = { .dump = dump, .done = done, ... }; netlink_dump_start(..., &c); Suggested by David S. Miller. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- crypto/crypto_user.c | 10 +++++++--- drivers/infiniband/core/netlink.c | 10 +++++++--- include/linux/netlink.h | 10 +++++++--- net/core/rtnetlink.c | 9 +++++++-- net/ipv4/inet_diag.c | 18 ++++++++++++------ net/netfilter/ipset/ip_set_core.c | 10 +++++++--- net/netfilter/nf_conntrack_netlink.c | 18 ++++++++++++------ net/netfilter/nfnetlink_acct.c | 6 ++++-- net/netlink/af_netlink.c | 11 ++++------- net/netlink/genetlink.c | 9 +++++++-- net/unix/diag.c | 10 ++++++---- net/xfrm/xfrm_user.c | 9 +++++++-- 12 files changed, 87 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 16f8693cc14..b6ac1387770 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -389,9 +389,13 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) (nlh->nlmsg_flags & NLM_F_DUMP))) { if (link->dump == NULL) return -EINVAL; - - return netlink_dump_start(crypto_nlsk, skb, nlh, - link->dump, link->done, 0); + { + struct netlink_dump_control c = { + .dump = link->dump, + .done = link->done, + }; + return netlink_dump_start(crypto_nlsk, skb, nlh, &c); + } } err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX, diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c index d1c8196d15d..396e2937030 100644 --- a/drivers/infiniband/core/netlink.c +++ b/drivers/infiniband/core/netlink.c @@ -147,9 +147,13 @@ static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (op < 0 || op >= client->nops || !client->cb_table[RDMA_NL_GET_OP(op)].dump) return -EINVAL; - return netlink_dump_start(nls, skb, nlh, - client->cb_table[op].dump, - NULL, 0); + + { + struct netlink_dump_control c = { + .dump = client->cb_table[op].dump, + }; + return netlink_dump_start(nls, skb, nlh, &c); + } } } diff --git a/include/linux/netlink.h b/include/linux/netlink.h index a390e9d5482..1f8c1a95f57 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -248,11 +248,15 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) #define NLMSG_PUT(skb, pid, seq, type, len) \ NLMSG_NEW(skb, pid, seq, type, len, 0) +struct netlink_dump_control { + int (*dump)(struct sk_buff *skb, struct netlink_callback *); + int (*done)(struct netlink_callback*); + u16 min_dump_alloc; +}; + extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, const struct nlmsghdr *nlh, - int (*dump)(struct sk_buff *skb, struct netlink_callback*), - int (*done)(struct netlink_callback*), - u16 min_dump_alloc); + struct netlink_dump_control *control); #define NL_NONROOT_RECV 0x1 diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 65aebd45002..7aef62e5311 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1981,8 +1981,13 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) __rtnl_unlock(); rtnl = net->rtnl; - err = netlink_dump_start(rtnl, skb, nlh, dumpit, - NULL, min_dump_alloc); + { + struct netlink_dump_control c = { + .dump = dumpit, + .min_dump_alloc = min_dump_alloc, + }; + err = netlink_dump_start(rtnl, skb, nlh, &c); + } rtnl_lock(); return err; } diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index fcf281819cd..8d25a1c557e 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -960,9 +960,12 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) inet_diag_bc_audit(nla_data(attr), nla_len(attr))) return -EINVAL; } - - return netlink_dump_start(sock_diag_nlsk, skb, nlh, - inet_diag_dump_compat, NULL, 0); + { + struct netlink_dump_control c = { + .dump = inet_diag_dump_compat, + }; + return netlink_dump_start(sock_diag_nlsk, skb, nlh, &c); + } } return inet_diag_get_exact_compat(skb, nlh); @@ -985,9 +988,12 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) inet_diag_bc_audit(nla_data(attr), nla_len(attr))) return -EINVAL; } - - return netlink_dump_start(sock_diag_nlsk, skb, h, - inet_diag_dump, NULL, 0); + { + struct netlink_dump_control c = { + .dump = inet_diag_dump, + }; + return netlink_dump_start(sock_diag_nlsk, skb, h, &c); + } } return inet_diag_get_exact(skb, h, (struct inet_diag_req_v2 *)NLMSG_DATA(h)); diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 32dbf0fa89d..e7f90e7082b 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1162,9 +1162,13 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb, if (unlikely(protocol_failed(attr))) return -IPSET_ERR_PROTOCOL; - return netlink_dump_start(ctnl, skb, nlh, - ip_set_dump_start, - ip_set_dump_done, 0); + { + struct netlink_dump_control c = { + .dump = ip_set_dump_start, + .done = ip_set_dump_done, + }; + return netlink_dump_start(ctnl, skb, nlh, &c); + } } /* Add, del and test */ diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 9307b033c0c..61f7feb7932 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -977,9 +977,13 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, u16 zone; int err; - if (nlh->nlmsg_flags & NLM_F_DUMP) - return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table, - ctnetlink_done, 0); + if (nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { + .dump = ctnetlink_dump_table, + .done = ctnetlink_done, + }; + return netlink_dump_start(ctnl, skb, nlh, &c); + } err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone); if (err < 0) @@ -1850,9 +1854,11 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, int err; if (nlh->nlmsg_flags & NLM_F_DUMP) { - return netlink_dump_start(ctnl, skb, nlh, - ctnetlink_exp_dump_table, - ctnetlink_exp_done, 0); + struct netlink_dump_control c = { + .dump = ctnetlink_exp_dump_table, + .done = ctnetlink_exp_done, + }; + return netlink_dump_start(ctnl, skb, nlh, &c); } err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone); diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index 11ba013e47f..3eb348bfc4f 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c @@ -171,8 +171,10 @@ nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb, char *acct_name; if (nlh->nlmsg_flags & NLM_F_DUMP) { - return netlink_dump_start(nfnl, skb, nlh, nfnl_acct_dump, - NULL, 0); + struct netlink_dump_control c = { + .dump = nfnl_acct_dump, + }; + return netlink_dump_start(nfnl, skb, nlh, &c); } if (!tb[NFACCT_NAME]) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 4d751e3d4b4..ab74845876d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1736,10 +1736,7 @@ errout_skb: int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, const struct nlmsghdr *nlh, - int (*dump)(struct sk_buff *skb, - struct netlink_callback *), - int (*done)(struct netlink_callback *), - u16 min_dump_alloc) + struct netlink_dump_control *control) { struct netlink_callback *cb; struct sock *sk; @@ -1750,10 +1747,10 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, if (cb == NULL) return -ENOBUFS; - cb->dump = dump; - cb->done = done; + cb->dump = control->dump; + cb->done = control->done; cb->nlh = nlh; - cb->min_dump_alloc = min_dump_alloc; + cb->min_dump_alloc = control->min_dump_alloc; atomic_inc(&skb->users); cb->skb = skb; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index a1154717219..9f40441d7a7 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -563,8 +563,13 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EOPNOTSUPP; genl_unlock(); - err = netlink_dump_start(net->genl_sock, skb, nlh, - ops->dumpit, ops->done, 0); + { + struct netlink_dump_control c = { + .dump = ops->dumpit, + .done = ops->done, + }; + err = netlink_dump_start(net->genl_sock, skb, nlh, &c); + } genl_lock(); return err; } diff --git a/net/unix/diag.c b/net/unix/diag.c index 6b7697fd911..4195555aea6 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -301,10 +301,12 @@ static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) if (nlmsg_len(h) < hdrlen) return -EINVAL; - if (h->nlmsg_flags & NLM_F_DUMP) - return netlink_dump_start(sock_diag_nlsk, skb, h, - unix_diag_dump, NULL, 0); - else + if (h->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { + .dump = unix_diag_dump, + }; + return netlink_dump_start(sock_diag_nlsk, skb, h, &c); + } else return unix_diag_get_exact(skb, h, (struct unix_diag_req *)NLMSG_DATA(h)); } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 66b84fbf274..7128dde0fe1 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2299,8 +2299,13 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->dump == NULL) return -EINVAL; - return netlink_dump_start(net->xfrm.nlsk, skb, nlh, - link->dump, link->done, 0); + { + struct netlink_dump_control c = { + .dump = link->dump, + .done = link->done, + }; + return netlink_dump_start(net->xfrm.nlsk, skb, nlh, &c); + } } err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, -- cgit v1.2.3-70-g09d2 From 7175c883071515f0d4c1cece2646203b8a5a7415 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 24 Feb 2012 14:30:16 +0000 Subject: netlink: allow to pass data pointer to netlink_dump_start() callback This patch allows you to pass a data pointer that can be accessed from the dump callback. Netfilter is going to use this patch to provide filtered dumps to user-space. This is specifically interesting in ctnetlink that may handle lots of conntrack entries. We can save precious cycles by skipping the conversion to TLV format of conntrack entries that are not interesting for user-space. More specifically, ctnetlink will include one operation to allow to filter the dumping of conntrack entries by ctmark values. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/linux/netlink.h | 2 ++ net/netlink/af_netlink.c | 1 + 2 files changed, 3 insertions(+) (limited to 'net') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 1f8c1a95f57..a2092f582a7 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -225,6 +225,7 @@ struct netlink_callback { int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); int (*done)(struct netlink_callback *cb); + void *data; u16 family; u16 min_dump_alloc; unsigned int prev_seq, seq; @@ -251,6 +252,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) struct netlink_dump_control { int (*dump)(struct sk_buff *skb, struct netlink_callback *); int (*done)(struct netlink_callback*); + void *data; u16 min_dump_alloc; }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index ab74845876d..32bb75324e7 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1750,6 +1750,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, cb->dump = control->dump; cb->done = control->done; cb->nlh = nlh; + cb->data = control->data; cb->min_dump_alloc = control->min_dump_alloc; atomic_inc(&skb->users); cb->skb = skb; -- cgit v1.2.3-70-g09d2 From 0f298a285f2e365cb34f69d1f79bb9fc996f683d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 24 Feb 2012 14:41:50 +0000 Subject: netfilter: ctnetlink: support kernel-space dump filtering by ctmark This patch adds CTA_MARK_MASK which, together with CTA_MARK, allows you to selectively send conntrack entries to user-space by returning those that match mark & mask. With this, we can save cycles in the building and the parsing of the entries that may be later on filtered out in user-space by using the ctmark & mask. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/linux/netfilter/nfnetlink_conntrack.h | 1 + net/netfilter/nf_conntrack_netlink.c | 35 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index debf1aefd75..d498a4426eb 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -43,6 +43,7 @@ enum ctattr_type { CTA_ZONE, CTA_SECCTX, CTA_TIMESTAMP, + CTA_MARK_MASK, __CTA_MAX }; #define CTA_MAX (__CTA_MAX - 1) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 61f7feb7932..28d0312d890 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -691,9 +691,18 @@ static int ctnetlink_done(struct netlink_callback *cb) { if (cb->args[1]) nf_ct_put((struct nf_conn *)cb->args[1]); + if (cb->data) + kfree(cb->data); return 0; } +struct ctnetlink_dump_filter { + struct { + u_int32_t val; + u_int32_t mask; + } mark; +}; + static int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { @@ -703,7 +712,9 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct hlist_nulls_node *n; struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; - +#ifdef CONFIG_NF_CONNTRACK_MARK + const struct ctnetlink_dump_filter *filter = cb->data; +#endif spin_lock_bh(&nf_conntrack_lock); last = (struct nf_conn *)cb->args[1]; for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) { @@ -723,6 +734,12 @@ restart: continue; cb->args[1] = 0; } +#ifdef CONFIG_NF_CONNTRACK_MARK + if (filter && !((ct->mark & filter->mark.mask) == + filter->mark.val)) { + continue; + } +#endif if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NFNL_MSG_TYPE( @@ -894,6 +911,7 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { [CTA_NAT_DST] = { .type = NLA_NESTED }, [CTA_TUPLE_MASTER] = { .type = NLA_NESTED }, [CTA_ZONE] = { .type = NLA_U16 }, + [CTA_MARK_MASK] = { .type = NLA_U32 }, }; static int @@ -982,6 +1000,21 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, .dump = ctnetlink_dump_table, .done = ctnetlink_done, }; +#ifdef CONFIG_NF_CONNTRACK_MARK + if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { + struct ctnetlink_dump_filter *filter; + + filter = kzalloc(sizeof(struct ctnetlink_dump_filter), + GFP_ATOMIC); + if (filter == NULL) + return -ENOMEM; + + filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); + filter->mark.mask = + ntohl(nla_get_be32(cda[CTA_MARK_MASK])); + c.data = filter; + } +#endif return netlink_dump_start(ctnl, skb, nlh, &c); } -- cgit v1.2.3-70-g09d2 From a314f2748e76c866222a18e639c640d584d277fb Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Wed, 1 Feb 2012 12:48:53 -0800 Subject: net/9p: don't allow Tflush to be interrupted When a signal is received while sending a Tflush, the client, which has recursed into p9_client_rpc() while sending another request, should wait for Rflush as long as the transport is still up. Signed-off-by: Jim Garlick Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/9p/client.c b/net/9p/client.c index 776618cd2be..6efbb334c3a 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -740,10 +740,18 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) c->status = Disconnected; goto reterr; } +again: /* Wait for the response */ err = wait_event_interruptible(*req->wq, req->status >= REQ_STATUS_RCVD); + if ((err == -ERESTARTSYS) && (c->status == Connected) + && (type == P9_TFLUSH)) { + sigpending = 1; + clear_thread_flag(TIF_SIGPENDING); + goto again; + } + if (req->status == REQ_STATUS_ERROR) { p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); err = req->t_err; -- cgit v1.2.3-70-g09d2 From 208f3c28aab706fca2bc1bae7091da8a99c5e322 Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Sun, 26 Feb 2012 14:49:57 -0600 Subject: net/9p: handle flushed Tclunk/Tremove When a Tclunk or Tremove request is flushed, the fid is not freed on the server. p9_client_clunk() should retry once on interrupt, then if interrupted again, leak the fid for the duration of the connection. p9_client_remove() should call p9_client_clunk() on interrupt instead of unconditionally destroying the fid. Signed-off-by: Jim Garlick Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/9p/client.c b/net/9p/client.c index 6efbb334c3a..b23a17c431c 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1428,6 +1428,7 @@ int p9_client_clunk(struct p9_fid *fid) int err; struct p9_client *clnt; struct p9_req_t *req; + int retries = 0; if (!fid) { pr_warn("%s (%d): Trying to clunk with NULL fid\n", @@ -1436,7 +1437,9 @@ int p9_client_clunk(struct p9_fid *fid) return 0; } - p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); +again: + p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n", fid->fid, + retries); err = 0; clnt = fid->clnt; @@ -1452,8 +1455,14 @@ int p9_client_clunk(struct p9_fid *fid) error: /* * Fid is not valid even after a failed clunk + * If interrupted, retry once then give up and + * leak fid until umount. */ - p9_fid_destroy(fid); + if (err == -ERESTARTSYS) { + if (retries++ == 0) + goto again; + } else + p9_fid_destroy(fid); return err; } EXPORT_SYMBOL(p9_client_clunk); @@ -1478,7 +1487,10 @@ int p9_client_remove(struct p9_fid *fid) p9_free_req(clnt, req); error: - p9_fid_destroy(fid); + if (err == -ERESTARTSYS) + p9_client_clunk(fid); + else + p9_fid_destroy(fid); return err; } EXPORT_SYMBOL(p9_client_remove); -- cgit v1.2.3-70-g09d2 From 816a11d5ced501d368fabe09172f3d62744e8b53 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 26 Feb 2012 13:04:52 +0200 Subject: Bluetooth: Use kernel int types instead of ones from stdint.h u8/__u8/u32/etc should be used in the kernel instead of stdint.h types. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 4 ++-- net/bluetooth/bnep/sock.c | 6 +++--- net/bluetooth/cmtp/sock.c | 6 +++--- net/bluetooth/hidp/sock.c | 6 +++--- net/bluetooth/mgmt.c | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 05bd9aca405..0c54fcfe7e0 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -691,8 +691,8 @@ struct hci_cp_host_buffer_size { #define HCI_OP_WRITE_EIR 0x0c52 struct hci_cp_write_eir { - uint8_t fec; - uint8_t data[HCI_MAX_EIR_LENGTH]; + __u8 fec; + __u8 data[HCI_MAX_EIR_LENGTH]; } __packed; #define HCI_OP_READ_SSP_MODE 0x0c55 diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 17800b1d28e..9f9c8dcd8af 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -143,10 +143,10 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == BNEPGETCONNLIST) { struct bnep_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -157,7 +157,7 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = bnep_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 3f2dd5c25ae..1230faaac29 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -137,10 +137,10 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == CMTPGETCONNLIST) { struct cmtp_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -151,7 +151,7 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = cmtp_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 178ac7f127a..73a32d705c1 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -160,10 +160,10 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == HIDPGETCONNLIST) { struct hidp_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -174,7 +174,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = hidp_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 07e31f73f70..27830f40169 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1075,7 +1075,7 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_mode *cp = data; struct pending_cmd *cmd; struct hci_dev *hdev; - uint8_t val; + u8 val; int err; BT_DBG("request for hci%u", index); @@ -1147,7 +1147,7 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_mode *cp = data; struct pending_cmd *cmd; struct hci_dev *hdev; - uint8_t val; + u8 val; int err; BT_DBG("request for hci%u", index); -- cgit v1.2.3-70-g09d2 From da3b462296e421e8f54b54b7d2706488661c36e2 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 27 Feb 2012 22:05:29 +0400 Subject: SUNRPC: release per-net clients lock before calling PipeFS dentries creation v3: 1) Lookup for client is performed from the beginning of the list on each PipeFS event handling operation. Lockdep is sad otherwise, because inode mutex is taken on PipeFS dentry creation, which can be called on mount notification, where this per-net client lock is taken on clients list walk. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index bb7ed2f3aee..25c3da53fb6 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -204,21 +204,37 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, return err; } +static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct rpc_clnt *clnt; + + spin_lock(&sn->rpc_client_lock); + list_for_each_entry(clnt, &sn->all_clients, cl_clients) { + if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || + ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) + continue; + atomic_inc(&clnt->cl_count); + spin_unlock(&sn->rpc_client_lock); + return clnt; + } + spin_unlock(&sn->rpc_client_lock); + return NULL; +} + static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) { struct super_block *sb = ptr; struct rpc_clnt *clnt; int error = 0; - struct sunrpc_net *sn = net_generic(sb->s_fs_info, sunrpc_net_id); - spin_lock(&sn->rpc_client_lock); - list_for_each_entry(clnt, &sn->all_clients, cl_clients) { + while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) { error = __rpc_pipefs_event(clnt, event, sb); + rpc_release_client(clnt); if (error) break; } - spin_unlock(&sn->rpc_client_lock); return error; } -- cgit v1.2.3-70-g09d2 From 2c9030eef9dbd0d737a7f55646da70d217fd6255 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 27 Feb 2012 22:05:45 +0400 Subject: SUNRPC: check RPC inode's pipe reference before dereferencing There are 2 tightly bound objects: pipe data (created for kernel needs, has reference to dentry, which depends on PipeFS mount/umount) and PipeFS dentry/inode pair (created on mount for user-space needs). They both independently may have or have not a valid reference to each other. This means, that we have to make sure, that pipe->dentry reference is valid on upcalls, and dentry->pipe reference is valid on downcalls. The latter check is absent - my fault. IOW, PipeFS dentry can be opened by some process (rpc.idmapd for example), but it's pipe data can belong to NFS mount, which was unmounted already and thus pipe data was destroyed. To fix this, pipe reference have to be set to NULL on rpc_unlink() and checked on PipeFS file operations instead of pipe->dentry check. Note: PipeFS "poll" file operation will be updated in next patch, because it's logic is more complicated. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 6873c9b51cc..b67b2aecc4f 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -174,6 +174,7 @@ rpc_close_pipes(struct inode *inode) pipe->ops->release_pipe(inode); cancel_delayed_work_sync(&pipe->queue_timeout); rpc_inode_setowner(inode, NULL); + RPC_I(inode)->pipe = NULL; mutex_unlock(&inode->i_mutex); } @@ -203,12 +204,13 @@ rpc_destroy_inode(struct inode *inode) static int rpc_pipe_open(struct inode *inode, struct file *filp) { - struct rpc_pipe *pipe = RPC_I(inode)->pipe; + struct rpc_pipe *pipe; int first_open; int res = -ENXIO; mutex_lock(&inode->i_mutex); - if (pipe->dentry == NULL) + pipe = RPC_I(inode)->pipe; + if (pipe == NULL) goto out; first_open = pipe->nreaders == 0 && pipe->nwriters == 0; if (first_open && pipe->ops->open_pipe) { @@ -229,12 +231,13 @@ out: static int rpc_pipe_release(struct inode *inode, struct file *filp) { - struct rpc_pipe *pipe = RPC_I(inode)->pipe; + struct rpc_pipe *pipe; struct rpc_pipe_msg *msg; int last_close; mutex_lock(&inode->i_mutex); - if (pipe->dentry == NULL) + pipe = RPC_I(inode)->pipe; + if (pipe == NULL) goto out; msg = filp->private_data; if (msg != NULL) { @@ -270,12 +273,13 @@ static ssize_t rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) { struct inode *inode = filp->f_path.dentry->d_inode; - struct rpc_pipe *pipe = RPC_I(inode)->pipe; + struct rpc_pipe *pipe; struct rpc_pipe_msg *msg; int res = 0; mutex_lock(&inode->i_mutex); - if (pipe->dentry == NULL) { + pipe = RPC_I(inode)->pipe; + if (pipe == NULL) { res = -EPIPE; goto out_unlock; } @@ -313,13 +317,12 @@ static ssize_t rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) { struct inode *inode = filp->f_path.dentry->d_inode; - struct rpc_pipe *pipe = RPC_I(inode)->pipe; int res; mutex_lock(&inode->i_mutex); res = -EPIPE; - if (pipe->dentry != NULL) - res = pipe->ops->downcall(filp, buf, len); + if (RPC_I(inode)->pipe != NULL) + res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len); mutex_unlock(&inode->i_mutex); return res; } @@ -344,16 +347,18 @@ static long rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = filp->f_path.dentry->d_inode; - struct rpc_pipe *pipe = RPC_I(inode)->pipe; + struct rpc_pipe *pipe; int len; switch (cmd) { case FIONREAD: - spin_lock(&pipe->lock); - if (pipe->dentry == NULL) { - spin_unlock(&pipe->lock); + mutex_lock(&inode->i_mutex); + pipe = RPC_I(inode)->pipe; + if (pipe == NULL) { + mutex_unlock(&inode->i_mutex); return -EPIPE; } + spin_lock(&pipe->lock); len = pipe->pipelen; if (filp->private_data) { struct rpc_pipe_msg *msg; @@ -361,6 +366,7 @@ rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) len += msg->len - msg->copied; } spin_unlock(&pipe->lock); + mutex_unlock(&inode->i_mutex); return put_user(len, (int __user *)arg); default: return -EINVAL; -- cgit v1.2.3-70-g09d2 From 591ad7feaec5417681b4112f8df52fc43bb7c92e Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 27 Feb 2012 22:05:54 +0400 Subject: SUNRPC: move waitq from RPC pipe to RPC inode Currently, wait queue, used for polling of RPC pipe changes from user-space, is a part of RPC pipe. But the pipe data itself can be released on NFS umount prior to dentry-inode pair, connected to it (is case of this pair is open by some process). This is not a problem for almost all pipe users, because all PipeFS file operations checks pipe reference prior to using it. Except evenfd. This thing registers itself with "poll" file operation and thus has a reference to pipe wait queue. This leads to oopses on destroying eventfd after NFS umount (like rpc_idmapd do) since not pipe data left to the point already. The solution is to wait queue from pipe data to internal RPC inode data. This looks more logical, because this wiat queue used only for user-space processes, which already holds inode reference. Note: upcalls have to get pipe->dentry prior to dereferecing wait queue to make sure, that mount point won't disappear from underneath us. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 2 +- net/sunrpc/rpc_pipe.c | 39 +++++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 426ce6eeee6..a7b422b33ed 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -28,7 +28,6 @@ struct rpc_pipe { int pipelen; int nreaders; int nwriters; - wait_queue_head_t waitq; #define RPC_PIPE_WAIT_FOR_OPEN 1 int flags; struct delayed_work queue_timeout; @@ -41,6 +40,7 @@ struct rpc_inode { struct inode vfs_inode; void *private; struct rpc_pipe *pipe; + wait_queue_head_t waitq; }; static inline struct rpc_inode * diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index b67b2aecc4f..ac9ee159073 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -57,7 +57,7 @@ void rpc_pipefs_notifier_unregister(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister); -static void rpc_purge_list(struct rpc_pipe *pipe, struct list_head *head, +static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head, void (*destroy_msg)(struct rpc_pipe_msg *), int err) { struct rpc_pipe_msg *msg; @@ -70,7 +70,7 @@ static void rpc_purge_list(struct rpc_pipe *pipe, struct list_head *head, msg->errno = err; destroy_msg(msg); } while (!list_empty(head)); - wake_up(&pipe->waitq); + wake_up(waitq); } static void @@ -80,6 +80,7 @@ rpc_timeout_upcall_queue(struct work_struct *work) struct rpc_pipe *pipe = container_of(work, struct rpc_pipe, queue_timeout.work); void (*destroy_msg)(struct rpc_pipe_msg *); + struct dentry *dentry; spin_lock(&pipe->lock); destroy_msg = pipe->ops->destroy_msg; @@ -87,8 +88,13 @@ rpc_timeout_upcall_queue(struct work_struct *work) list_splice_init(&pipe->pipe, &free_list); pipe->pipelen = 0; } + dentry = dget(pipe->dentry); spin_unlock(&pipe->lock); - rpc_purge_list(pipe, &free_list, destroy_msg, -ETIMEDOUT); + if (dentry) { + rpc_purge_list(&RPC_I(dentry->d_inode)->waitq, + &free_list, destroy_msg, -ETIMEDOUT); + dput(dentry); + } } ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, @@ -125,6 +131,7 @@ int rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) { int res = -EPIPE; + struct dentry *dentry; spin_lock(&pipe->lock); if (pipe->nreaders) { @@ -140,8 +147,12 @@ rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) pipe->pipelen += msg->len; res = 0; } + dentry = dget(pipe->dentry); spin_unlock(&pipe->lock); - wake_up(&pipe->waitq); + if (dentry) { + wake_up(&RPC_I(dentry->d_inode)->waitq); + dput(dentry); + } return res; } EXPORT_SYMBOL_GPL(rpc_queue_upcall); @@ -168,7 +179,7 @@ rpc_close_pipes(struct inode *inode) pipe->pipelen = 0; pipe->dentry = NULL; spin_unlock(&pipe->lock); - rpc_purge_list(pipe, &free_list, pipe->ops->destroy_msg, -EPIPE); + rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE); pipe->nwriters = 0; if (need_release && pipe->ops->release_pipe) pipe->ops->release_pipe(inode); @@ -257,7 +268,7 @@ rpc_pipe_release(struct inode *inode, struct file *filp) list_splice_init(&pipe->pipe, &free_list); pipe->pipelen = 0; spin_unlock(&pipe->lock); - rpc_purge_list(pipe, &free_list, + rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EAGAIN); } } @@ -330,16 +341,18 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of static unsigned int rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) { - struct rpc_pipe *pipe = RPC_I(filp->f_path.dentry->d_inode)->pipe; - unsigned int mask = 0; + struct inode *inode = filp->f_path.dentry->d_inode; + struct rpc_inode *rpci = RPC_I(inode); + unsigned int mask = POLLOUT | POLLWRNORM; - poll_wait(filp, &pipe->waitq, wait); + poll_wait(filp, &rpci->waitq, wait); - mask = POLLOUT | POLLWRNORM; - if (pipe->dentry == NULL) + mutex_lock(&inode->i_mutex); + if (rpci->pipe == NULL) mask |= POLLERR | POLLHUP; - if (filp->private_data || !list_empty(&pipe->pipe)) + else if (filp->private_data || !list_empty(&rpci->pipe->pipe)) mask |= POLLIN | POLLRDNORM; + mutex_unlock(&inode->i_mutex); return mask; } @@ -543,7 +556,6 @@ init_pipe(struct rpc_pipe *pipe) INIT_LIST_HEAD(&pipe->in_downcall); INIT_LIST_HEAD(&pipe->pipe); pipe->pipelen = 0; - init_waitqueue_head(&pipe->waitq); INIT_DELAYED_WORK(&pipe->queue_timeout, rpc_timeout_upcall_queue); pipe->ops = NULL; @@ -1165,6 +1177,7 @@ init_once(void *foo) inode_init_once(&rpci->vfs_inode); rpci->private = NULL; rpci->pipe = NULL; + init_waitqueue_head(&rpci->waitq); } int register_rpc_pipefs(void) -- cgit v1.2.3-70-g09d2 From 494f1fe559748a54bb30c066057dfae02d29676e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 19 Feb 2012 15:26:09 +0200 Subject: mac80211: don't queue monitor work for HW_CONNECTION_MONITOR Devices that monitor the connection in the hw don't need the monitor work in the driver. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 52133dab929..7ece99a5980 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2974,13 +2974,17 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) { + u32 flags; + if (sdata->vif.type == NL80211_IFTYPE_STATION) { sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL); /* let's probe the connection once */ - ieee80211_queue_work(&sdata->local->hw, - &sdata->u.mgd.monitor_work); + flags = sdata->local->hw.flags; + if (!(flags & IEEE80211_HW_CONNECTION_MONITOR)) + ieee80211_queue_work(&sdata->local->hw, + &sdata->u.mgd.monitor_work); /* and do all the other regular work too */ ieee80211_queue_work(&sdata->local->hw, &sdata->work); } -- cgit v1.2.3-70-g09d2 From 6b5773ebd5c9719aec30e58429db2d3b3f343d2c Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 19 Feb 2012 15:26:10 +0200 Subject: mac80211: remove redundant monitor_work enqueueing ieee80211_restart_sta_timer() takes care for enqueueing monitor_work if needed, so no need to do it again. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7ece99a5980..586d4fb8e13 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3048,7 +3048,6 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) add_timer(&ifmgd->chswitch_timer); ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_restart_sta_timer(sdata); - ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work); } #endif -- cgit v1.2.3-70-g09d2 From d26ad3771fe7405bf80d736cae9ba4c706a7b1d8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Feb 2012 11:38:41 +0100 Subject: mac80211: clean up asm/unaligned.h inclusion Some files implicitly get this via mesh.h which itself doesn't need it, so move the inclusion into the right files. Some other files don't need it at all but include it, so remove it from there. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 1 - net/mac80211/key.c | 1 + net/mac80211/mesh.h | 1 - net/mac80211/mesh_hwmp.c | 1 + net/mac80211/rx.c | 1 + net/mac80211/status.c | 1 + 6 files changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8361da4b36a..7f9ac577600 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "ieee80211_i.h" #include "driver-ops.h" diff --git a/net/mac80211/key.c b/net/mac80211/key.c index e8616b3ff63..5bb600d93d7 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "ieee80211_i.h" #include "driver-ops.h" #include "debugfs_key.h" diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index bd14bd26a2b..c7e5c49471e 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -13,7 +13,6 @@ #include #include -#include #include "ieee80211_i.h" diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c27dec90496..31bc762f209 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -8,6 +8,7 @@ */ #include +#include #include "wme.h" #include "mesh.h" diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3ab85c02ef0..7a4ff02af26 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "ieee80211_i.h" #include "driver-ops.h" diff --git a/net/mac80211/status.c b/net/mac80211/status.c index d67f0b967f8..c928e4a4eff 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -11,6 +11,7 @@ #include #include +#include #include "ieee80211_i.h" #include "rate.h" #include "mesh.h" -- cgit v1.2.3-70-g09d2 From 79ebfb85d4ad3495d70124a249a1096ab6396c05 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Feb 2012 14:19:58 +0100 Subject: mac80211: fix associated vs. idle race Eliad reports that if a scan finishes in the middle of processing associated (however it happens), the interface can go idle. This is because we set assoc_data to NULL before we set associated. Change the order so any idle check will find either one of them. Doing this requires duplicating the TX sync processing, but I already have a patch to delete that completely and will submit that as soon as my driver changes to no longer require it are submitted. Reported-by: Eliad Peller Tested-by: Eliad Peller Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 586d4fb8e13..1495fb99b37 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2238,14 +2238,28 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } else { printk(KERN_DEBUG "%s: associated\n", sdata->name); - ieee80211_destroy_assoc_data(sdata, true); + /* tell driver about sync done first */ + if (assoc_data->synced) { + drv_finish_tx_sync(sdata->local, sdata, + assoc_data->bss->bssid, + IEEE80211_TX_SYNC_ASSOC); + assoc_data->synced = false; + } if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { /* oops -- internal error -- send timeout for now */ + ieee80211_destroy_assoc_data(sdata, true); sta_info_destroy_addr(sdata, mgmt->bssid); cfg80211_put_bss(*bss); return RX_MGMT_CFG80211_ASSOC_TIMEOUT; } + + /* + * destroy assoc_data afterwards, as otherwise an idle + * recalc after assoc_data is NULL but before associated + * is set can cause the interface to go idle + */ + ieee80211_destroy_assoc_data(sdata, true); } return RX_MGMT_CFG80211_RX_ASSOC; -- cgit v1.2.3-70-g09d2 From 9d88c7f6709aab0e4342d80fad6fb7d3f7efc7ff Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Feb 2012 02:17:48 +0100 Subject: mac80211: use proper sub_if_data on suspend path Use interface data from sta instead of invalid pointer to list head in calls to drv_sta_state. Signed-off-by: Jakub Kicinski Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 2b53a5348ac..ef8eba1d736 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -102,7 +102,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) state = sta->sta_state; for (; state > IEEE80211_STA_NOTEXIST; state--) - WARN_ON(drv_sta_state(local, sdata, sta, + WARN_ON(drv_sta_state(local, sta->sdata, sta, state, state - 1)); } -- cgit v1.2.3-70-g09d2 From 54e4ffb2abb3c086637cbc75a2bfe55a8ce987c8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Feb 2012 21:48:08 +0100 Subject: mac80211: fix auth/assoc data & timer leak When removing an interface while it is in the process of authenticating or associating, we leak the auth_data or assoc_data, and leave the timer pending. The timer then crashes the system when it fires as its data is gone. Fix this by explicitly deleting all the data when the interface is removed. This uncovered another bug -- this problem should have been detected by the sta_info_flush() warning but that function doesn't ever return non-zero, I'll fix that in a separate patch. Reported-by: Hieu Nguyen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 2 ++ net/mac80211/mlme.c | 13 +++++++++++++ 3 files changed, 16 insertions(+) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 67aed1eff13..4a722b10b4d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1178,6 +1178,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); +void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata); /* IBSS code */ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6b3cd65d1e0..60b240ce709 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -644,6 +644,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_rmc_free(sdata); + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + ieee80211_mgd_teardown(sdata); flushed = sta_info_flush(local, sdata); WARN_ON(flushed); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1495fb99b37..0c220e1b6c9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3513,6 +3513,19 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return 0; } +void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + mutex_lock(&ifmgd->mtx); + if (ifmgd->assoc_data) + ieee80211_destroy_assoc_data(sdata, false); + if (ifmgd->auth_data) + ieee80211_destroy_auth_data(sdata, false); + del_timer_sync(&ifmgd->timer); + mutex_unlock(&ifmgd->mtx); +} + void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, enum nl80211_cqm_rssi_threshold_event rssi_event, gfp_t gfp) -- cgit v1.2.3-70-g09d2 From 3431683759596409427b6726e582f3ee66082728 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Feb 2012 21:40:46 +0100 Subject: mac80211: fix sta_info_flush() return value The comment for sta_info_flush() states "Returns the number of removed STA entries" but that isn't actually true. Consequently, the warning when a station is still around on interface removal can never trigger and this delayed finding the timer issue the previous patch fixed. Fix the return value here to make that warning useful again. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4034ee61602..98613c8f08c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -865,8 +865,10 @@ int sta_info_flush(struct ieee80211_local *local, mutex_lock(&local->sta_mtx); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - if (!sdata || sdata == sta->sdata) + if (!sdata || sdata == sta->sdata) { WARN_ON(__sta_info_destroy(sta)); + ret++; + } } mutex_unlock(&local->sta_mtx); -- cgit v1.2.3-70-g09d2 From 005e472b45131250fe09c194f8b872b86fd266c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 26 Feb 2012 11:24:35 +0100 Subject: mac80211: remove local_to_hw That's a lot longer than open-coding it and doesn't really add value, so just remove it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 6 ------ net/mac80211/main.c | 6 +++--- net/mac80211/tx.c | 2 +- net/mac80211/util.c | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4a722b10b4d..4d1682950a6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1128,12 +1128,6 @@ static inline struct ieee80211_local *hw_to_local( return container_of(hw, struct ieee80211_local, hw); } -static inline struct ieee80211_hw *local_to_hw( - struct ieee80211_local *local) -{ - return &local->hw; -} - static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2306d7514ff..36fa8051296 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -286,11 +286,11 @@ static void ieee80211_tasklet_handler(unsigned long data) /* Clear skb->pkt_type in order to not confuse kernel * netstack. */ skb->pkt_type = 0; - ieee80211_rx(local_to_hw(local), skb); + ieee80211_rx(&local->hw, skb); break; case IEEE80211_TX_STATUS_MSG: skb->pkt_type = 0; - ieee80211_tx_status(local_to_hw(local), skb); + ieee80211_tx_status(&local->hw, skb); break; case IEEE80211_EOSP_MSG: eosp_data = (void *)skb->cb; @@ -668,7 +668,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, ieee80211_hw_roc_setup(local); - return local_to_hw(local); + return &local->hw; } EXPORT_SYMBOL(ieee80211_alloc_hw); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c6eadac9ca4..7c021f25571 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -625,7 +625,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) tx->local->hw.wiphy->frag_threshold); /* set up the tx rate control struct we give the RC algo */ - txrc.hw = local_to_hw(tx->local); + txrc.hw = &tx->local->hw; txrc.sband = sband; txrc.bss_conf = &tx->sdata->vif.bss_conf; txrc.skb = tx->skb; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 264397aee81..f6e4cef9202 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -753,7 +753,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); - for (queue = 0; queue < local_to_hw(local)->queues; queue++) { + for (queue = 0; queue < local->hw.queues; queue++) { /* Set defaults according to 802.11-2007 Table 7-37 */ aCWmax = 1023; if (use_11b) -- cgit v1.2.3-70-g09d2 From 0b60eba1b29740a606e6b7694d2dc98b6085a1bf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 00:57:24 +0200 Subject: Bluetooth: Don't send unnecessary write_le_enable command If the local host features indicate that LE is already in the state that is desired there's no point in sending the HCI command to try to change the setting. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 27830f40169..c4d3bc9c86b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1260,7 +1260,7 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) struct pending_cmd *cmd; struct hci_dev *hdev; int err; - u8 val; + u8 val, enabled; BT_DBG("request for hci%u", index); @@ -1280,8 +1280,9 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) } val = !!cp->val; + enabled = !!(hdev->host_features[0] & LMP_HOST_LE); - if (!hdev_is_powered(hdev)) { + if (!hdev_is_powered(hdev) || val == enabled) { bool changed = false; if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { -- cgit v1.2.3-70-g09d2 From 8f984dfaf0bfa1355548cfba00473c8fa8e22d6e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 01:07:22 +0200 Subject: Bluetooth: Remove redundant read_host_features commands Previously the write_le_enable would trigger a read_host_features command but since we have access to the value LE support was set to we can simply just clear or set the bit in hdev->host_features. This also removes a second unnecessary read_host_features command from the device initialization procedure since LE is only enabled after the first read_host_features command completes. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 59 +++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e920cd520a8..488fdbcfe76 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -542,20 +542,6 @@ static void hci_setup_event_mask(struct hci_dev *hdev) hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); } -static void hci_set_le_support(struct hci_dev *hdev) -{ - struct hci_cp_write_le_host_supported cp; - - memset(&cp, 0, sizeof(cp)); - - if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { - cp.le = 1; - cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); - } - - hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); -} - static void hci_setup(struct hci_dev *hdev) { if (hdev->dev_type != HCI_BREDR) @@ -608,9 +594,6 @@ static void hci_setup(struct hci_dev *hdev) hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable), &enable); } - - if (hdev->features[4] & LMP_LE) - hci_set_le_support(hdev); } static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) @@ -730,6 +713,22 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb hdev->features[6], hdev->features[7]); } +static void hci_set_le_support(struct hci_dev *hdev) +{ + struct hci_cp_write_le_host_supported cp; + + memset(&cp, 0, sizeof(cp)); + + if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + cp.le = 1; + cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); + } + + if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE)) + hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, + sizeof(cp), &cp); +} + static void hci_cc_read_local_ext_features(struct hci_dev *hdev, struct sk_buff *skb) { @@ -738,7 +737,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, BT_DBG("%s status 0x%x", hdev->name, rp->status); if (rp->status) - return; + goto done; switch (rp->page) { case 0: @@ -749,6 +748,10 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, break; } + if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE) + hci_set_le_support(hdev); + +done: hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status); } @@ -1149,21 +1152,27 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_cp_read_local_ext_features cp; struct hci_cp_write_le_host_supported *sent; __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); - if (sent && test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_le_enable_complete(hdev, sent->le, status); - - if (status) + if (!sent) return; - cp.page = 0x01; - hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp); + if (!status) { + if (sent->le) + hdev->host_features[0] |= LMP_HOST_LE; + else + hdev->host_features[0] &= ~LMP_HOST_LE; + } + + if (test_bit(HCI_MGMT, &hdev->dev_flags) && + !test_bit(HCI_INIT, &hdev->flags)) + mgmt_le_enable_complete(hdev, sent->le, status); + + hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status); } static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) -- cgit v1.2.3-70-g09d2 From 02b7cc62b6176748dc5b55e0ca9c965f73a5c300 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 02:28:43 +0200 Subject: Bluetooth: Use LMP_HOST_SSP define instead of magic values This patch fixes the code to use the proper LMP_HOST_SSP define instead of magic values and thereby makes the code more readable. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 488fdbcfe76..8c3261db761 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2869,9 +2869,9 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b ie = hci_inquiry_cache_lookup(hdev, &conn->dst); if (ie) - ie->data.ssp_mode = (ev->features[0] & 0x01); + ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP); - if (ev->features[0] & 0x01) + if (ev->features[0] & LMP_HOST_SSP) set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } @@ -3224,7 +3224,7 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); if (ie) - ie->data.ssp_mode = (ev->features[0] & 0x01); + ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP); hci_dev_unlock(hdev); } -- cgit v1.2.3-70-g09d2 From 7c64fd98ce512de6c6dae0452dc026446bd368d5 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 28 Feb 2012 10:55:36 +0100 Subject: batman-adv: Fix indentation of multiline statements Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/bat_sysfs.c | 4 ++-- net/batman-adv/bitarray.c | 8 ++++---- net/batman-adv/gateway_client.c | 2 +- net/batman-adv/gateway_common.c | 4 ++-- net/batman-adv/hard-interface.c | 30 +++++++++++++++--------------- net/batman-adv/originator.c | 5 ++--- net/batman-adv/routing.c | 8 ++++---- net/batman-adv/soft-interface.c | 2 +- net/batman-adv/translation-table.c | 26 +++++++++++++------------- 9 files changed, 44 insertions(+), 45 deletions(-) (limited to 'net') diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c index 7317729a00f..b00101db5cc 100644 --- a/net/batman-adv/bat_sysfs.c +++ b/net/batman-adv/bat_sysfs.c @@ -321,11 +321,11 @@ static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, gw_mode_tmp = GW_MODE_OFF; if (strncmp(buff, GW_MODE_CLIENT_NAME, - strlen(GW_MODE_CLIENT_NAME)) == 0) + strlen(GW_MODE_CLIENT_NAME)) == 0) gw_mode_tmp = GW_MODE_CLIENT; if (strncmp(buff, GW_MODE_SERVER_NAME, - strlen(GW_MODE_SERVER_NAME)) == 0) + strlen(GW_MODE_SERVER_NAME)) == 0) gw_mode_tmp = GW_MODE_SERVER; if (gw_mode_tmp < 0) { diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c index e63069d61db..6d0aa216b23 100644 --- a/net/batman-adv/bitarray.c +++ b/net/batman-adv/bitarray.c @@ -154,8 +154,8 @@ int bit_get_packet(void *priv, unsigned long *seq_bits, /* sequence number is much newer, probably missed a lot of packets */ - if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE) - && (seq_num_diff < EXPECTED_SEQNO_RANGE)) { + if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE) && + (seq_num_diff < EXPECTED_SEQNO_RANGE)) { bat_dbg(DBG_BATMAN, bat_priv, "We missed a lot of packets (%i) !\n", seq_num_diff - 1); @@ -170,8 +170,8 @@ int bit_get_packet(void *priv, unsigned long *seq_bits, * packet should be dropped without calling this function if the * seqno window is protected. */ - if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) - || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { + if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) || + (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { bat_dbg(DBG_BATMAN, bat_priv, "Other host probably restarted!\n"); diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 65a77a10f17..0fa8e2d7c46 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -629,7 +629,7 @@ bool gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) /* check for bootp port */ if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && - (ntohs(udphdr->dest) != 67)) + (ntohs(udphdr->dest) != 67)) return false; if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 7f79e156e64..3ccb9c87fd1 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -93,7 +93,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, multi = 1024; if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || - (multi > 1)) + (multi > 1)) *tmp_ptr = '\0'; } @@ -118,7 +118,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, multi = 1024; if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || - (multi > 1)) + (multi > 1)) *tmp_ptr = '\0'; } diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 41826b96d9f..409d0273c9d 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -341,23 +341,23 @@ int hardif_enable_interface(struct hard_iface *hard_iface, if (atomic_read(&bat_priv->fragmentation) && hard_iface->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(hard_iface->soft_iface, - "The MTU of interface %s is too small (%i) to handle " - "the transport of batman-adv packets. Packets going " - "over this interface will be fragmented on layer2 " - "which could impact the performance. Setting the MTU " - "to %zi would solve the problem.\n", - hard_iface->net_dev->name, hard_iface->net_dev->mtu, - ETH_DATA_LEN + BAT_HEADER_LEN); + "The MTU of interface %s is too small (%i) to handle " + "the transport of batman-adv packets. Packets going " + "over this interface will be fragmented on layer2 " + "which could impact the performance. Setting the MTU " + "to %zi would solve the problem.\n", + hard_iface->net_dev->name, hard_iface->net_dev->mtu, + ETH_DATA_LEN + BAT_HEADER_LEN); if (!atomic_read(&bat_priv->fragmentation) && hard_iface->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(hard_iface->soft_iface, - "The MTU of interface %s is too small (%i) to handle " - "the transport of batman-adv packets. If you experience" - " problems getting traffic through try increasing the " - "MTU to %zi.\n", - hard_iface->net_dev->name, hard_iface->net_dev->mtu, - ETH_DATA_LEN + BAT_HEADER_LEN); + "The MTU of interface %s is too small (%i) to handle " + "the transport of batman-adv packets. If you " + "experience problems getting traffic through try " + "increasing the MTU to %zi.\n", + hard_iface->net_dev->name, hard_iface->net_dev->mtu, + ETH_DATA_LEN + BAT_HEADER_LEN); if (hardif_is_iface_up(hard_iface)) hardif_activate_interface(hard_iface); @@ -580,8 +580,8 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, goto err_free; /* expect a valid ethernet header here. */ - if (unlikely(skb->mac_len != sizeof(struct ethhdr) - || !skb_mac_header(skb))) + if (unlikely(skb->mac_len != sizeof(struct ethhdr) || + !skb_mac_header(skb))) goto err_free; if (!hard_iface->soft_iface) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index c2e46b55162..371cc93d8e1 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -143,7 +143,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu) frag_list_free(&orig_node->frag_list); tt_global_del_orig(orig_node->bat_priv, orig_node, - "originator timed out"); + "originator timed out"); kfree(orig_node->tt_buff); kfree(orig_node->bcast_own); @@ -333,9 +333,8 @@ static bool purge_orig_node(struct bat_priv *bat_priv, return true; } else { if (purge_orig_neighbors(bat_priv, orig_node, - &best_neigh_node)) { + &best_neigh_node)) update_route(bat_priv, orig_node, best_neigh_node); - } } return false; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index cf9a2f62de6..f53515562a4 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -72,7 +72,7 @@ static void _update_route(struct bat_priv *bat_priv, bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", orig_node->orig); tt_global_del_orig(bat_priv, orig_node, - "Deleted route towards originator"); + "Deleted route towards originator"); /* route added */ } else if ((!curr_router) && (neigh_node)) { @@ -229,8 +229,8 @@ void bonding_save_primary(const struct orig_node *orig_node, int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff, unsigned long *last_reset) { - if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) - || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { + if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) || + (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { if (has_timed_out(*last_reset, RESET_PROTECTION_MS)) { *last_reset = jiffies; @@ -429,7 +429,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) if ((hdr_size == sizeof(struct icmp_packet_rr)) && (icmp_packet->rr_cur < BAT_RR_LEN)) { memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), - ethhdr->h_dest, ETH_ALEN); + ethhdr->h_dest, ETH_ALEN); icmp_packet->rr_cur++; } diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 2ffdc74ac40..c39c120e117 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -397,7 +397,7 @@ void softif_neigh_purge(struct bat_priv *bat_priv) &softif_neigh_vid->softif_neigh_list, list) { if ((!has_timed_out(softif_neigh->last_seen, - SOFTIF_NEIGH_TIMEOUT)) && + SOFTIF_NEIGH_TIMEOUT)) && (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) continue; diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 9a6f315b7d4..c9507057c98 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -261,7 +261,7 @@ int tt_changes_fill_buffer(struct bat_priv *bat_priv, atomic_set(&bat_priv->tt_local_changes, 0); list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list, - list) { + list) { if (count < tot_changes) { memcpy(buff + tt_len(count), &entry->change, sizeof(struct tt_change)); @@ -333,17 +333,17 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset) hlist_for_each_entry_rcu(tt_common_entry, node, head, hash_entry) { seq_printf(seq, " * %pM [%c%c%c%c%c]\n", - tt_common_entry->addr, - (tt_common_entry->flags & - TT_CLIENT_ROAM ? 'R' : '.'), - (tt_common_entry->flags & - TT_CLIENT_NOPURGE ? 'P' : '.'), - (tt_common_entry->flags & - TT_CLIENT_NEW ? 'N' : '.'), - (tt_common_entry->flags & - TT_CLIENT_PENDING ? 'X' : '.'), - (tt_common_entry->flags & - TT_CLIENT_WIFI ? 'W' : '.')); + tt_common_entry->addr, + (tt_common_entry->flags & + TT_CLIENT_ROAM ? 'R' : '.'), + (tt_common_entry->flags & + TT_CLIENT_NOPURGE ? 'P' : '.'), + (tt_common_entry->flags & + TT_CLIENT_NEW ? 'N' : '.'), + (tt_common_entry->flags & + TT_CLIENT_PENDING ? 'X' : '.'), + (tt_common_entry->flags & + TT_CLIENT_WIFI ? 'W' : '.')); } rcu_read_unlock(); } @@ -704,7 +704,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv, spin_lock_bh(list_lock); hlist_for_each_entry_safe(tt_common_entry, node, safe, - head, hash_entry) { + head, hash_entry) { tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, common); -- cgit v1.2.3-70-g09d2 From 4c90d3b30334833450ccbb02f452d4972a3c3c3f Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sun, 26 Feb 2012 10:06:19 +0000 Subject: tcp: fix false reordering signal in tcp_shifted_skb When tcp_shifted_skb() shifts bytes from the skb that is currently pointed to by 'highest_sack' then the increment of TCP_SKB_CB(skb)->seq implicitly advances tcp_highest_sack_seq(). This implicit advancement, combined with the recent fix to pass the correct SACKed range into tcp_sacktag_one(), caused tcp_sacktag_one() to think that the newly SACKed range was before the tcp_highest_sack_seq(), leading to a call to tcp_update_reordering() with a degree of reordering matching the size of the newly SACKed range (typically just 1 packet, which is a NOP, but potentially larger). This commit fixes this by simply calling tcp_sacktag_one() before the TCP_SKB_CB(skb)->seq advancement that can advance our notion of the highest SACKed sequence. Correspondingly, we can simplify the code a little now that tcp_shifted_skb() should update the lost_cnt_hint in all cases where skb == tp->lost_skb_hint. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 53c8ce4046b..ee42d42b2f4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1403,8 +1403,16 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, BUG_ON(!pcount); - /* Adjust hint for FACK. Non-FACK is handled in tcp_sacktag_one(). */ - if (tcp_is_fack(tp) && (skb == tp->lost_skb_hint)) + /* Adjust counters and hints for the newly sacked sequence + * range but discard the return value since prev is already + * marked. We must tag the range first because the seq + * advancement below implicitly advances + * tcp_highest_sack_seq() when skb is highest_sack. + */ + tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked, + start_seq, end_seq, dup_sack, pcount); + + if (skb == tp->lost_skb_hint) tp->lost_cnt_hint += pcount; TCP_SKB_CB(prev)->end_seq += shifted; @@ -1430,12 +1438,6 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, skb_shinfo(skb)->gso_type = 0; } - /* Adjust counters and hints for the newly sacked sequence range but - * discard the return value since prev is already marked. - */ - tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked, - start_seq, end_seq, dup_sack, pcount); - /* Difference in this won't matter, both ACKed by the same cumul. ACK */ TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS); -- cgit v1.2.3-70-g09d2 From 3379013bcfceb3c0365a3cf03543d6c67b84fc34 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Feb 2012 09:52:46 +0300 Subject: Bluetooth: use kfree_skb() instead of kfree() sk_buffs should be freed using kfree_skb(). Signed-off-by: Dan Carpenter Acked-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bdcfbf0f631..df3be692f2c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4284,7 +4284,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); /* Drop packet and return */ - kfree(skb); + kfree_skb(skb); return 0; } -- cgit v1.2.3-70-g09d2 From 89bb46d02046b59c1de3d2e92680f3a1062750d0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Feb 2012 09:57:59 +0300 Subject: Bluetooth: change min_t() cast in hci_reassembly() "count" is type int so the cast to __u16 truncates the high bits away and triggers a Smatch static checker warning. It looks like a high value of count could cause a forever loop, but I didn't follow it through to see if count is capped somewhere. Signed-off-by: Dan Carpenter Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e6cbb8a1f47..db484a8e736 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1966,7 +1966,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, while (count) { scb = (void *) skb->cb; - len = min_t(__u16, scb->expect, count); + len = min_t(uint, scb->expect, count); memcpy(skb_put(skb, len), data, len); -- cgit v1.2.3-70-g09d2 From 978c93b90fc4768e295b20492b5db76d5e026e5e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 29 Feb 2012 10:41:41 +0200 Subject: Bluetooth: Save remote L2CAP fixed channel mask Fixed channel mask needs to be stored to decide whether to use A2MP for example. So far save only one relevant byte which keeps all information we need. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d6d8ec8eb8c..3732a4849f2 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -522,6 +522,7 @@ struct l2cap_conn { unsigned int mtu; __u32 feat_mask; + __u8 fixed_chan_mask; __u8 info_state; __u8 info_ident; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index df3be692f2c..bc8d558b01f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3209,7 +3209,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm return 0; } - if (type == L2CAP_IT_FEAT_MASK) { + switch (type) { + case L2CAP_IT_FEAT_MASK: conn->feat_mask = get_unaligned_le32(rsp->data); if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { @@ -3226,11 +3227,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm l2cap_conn_start(conn); } - } else if (type == L2CAP_IT_FIXED_CHAN) { + break; + + case L2CAP_IT_FIXED_CHAN: + conn->fixed_chan_mask = rsp->data[0]; conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; l2cap_conn_start(conn); + break; } return 0; -- cgit v1.2.3-70-g09d2 From 426c189a1b34c0d36d5eddbe1c35bc961b1a1b68 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Feb 2012 11:41:04 -0300 Subject: Bluetooth: Change interleaved discovery behavior According to last discussion on IRC, if an interleaved discovery is issued, but the device is not dual mode, we should return error instead of performing a regular BR/EDR or LE-only discovery. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c4d3bc9c86b..b0c43fe4356 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2540,29 +2540,6 @@ unlock: return err; } -static int discovery(struct hci_dev *hdev) -{ - int err; - - if (lmp_host_le_capable(hdev)) { - if (lmp_bredr_capable(hdev)) { - err = hci_le_scan(hdev, LE_SCAN_TYPE, - LE_SCAN_INT, LE_SCAN_WIN, - LE_SCAN_TIMEOUT_BREDR_LE); - } else { - hdev->discovery.type = DISCOV_TYPE_LE; - err = hci_le_scan(hdev, LE_SCAN_TYPE, - LE_SCAN_INT, LE_SCAN_WIN, - LE_SCAN_TIMEOUT_LE_ONLY); - } - } else { - hdev->discovery.type = DISCOV_TYPE_BREDR; - err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); - } - - return err; -} - int mgmt_interleaved_discovery(struct hci_dev *hdev) { int err; @@ -2632,7 +2609,11 @@ static int start_discovery(struct sock *sk, u16 index, break; case DISCOV_TYPE_INTERLEAVED: - err = discovery(hdev); + if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE); + else + err = -ENOTSUPP; break; default: -- cgit v1.2.3-70-g09d2 From 95b23582d796305c66952188de2f5159b28be766 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Sun, 12 Feb 2012 13:55:35 +0100 Subject: Bluetooth: Use NULL instead of integer for mgmt_device_connected param Last param of mgmt_device_connected is of pointer type, so use NULL instead of 0 for it. This fix following sparse warning: CHECK net/bluetooth/hci_event.c net/bluetooth/hci_event.c:3262:74: warning: Using plain integer as NULL pointer Signed-off-by: Szymon Janc Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8c3261db761..746f7d37225 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3296,7 +3296,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type, 0, NULL, 0, 0); + conn->dst_type, 0, NULL, 0, NULL); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); -- cgit v1.2.3-70-g09d2 From 9b641251aee1a804169a17fe4236a50188894994 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 9 Nov 2011 13:29:18 -0500 Subject: tipc: Un-inline port routine for processing incoming messages Converts a non-trivial routine from inline to non-inline form to avoid bloating the TIPC code base with 6 copies of its body. This change is essentially cosmetic, and doesn't change existing TIPC behavior. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/port.c | 43 +++++++++++++++++++++++++++++++++++++++++++ net/tipc/port.h | 42 +----------------------------------------- 2 files changed, 44 insertions(+), 41 deletions(-) (limited to 'net') diff --git a/net/tipc/port.c b/net/tipc/port.c index b103d7630c8..6adcdf99123 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -1133,6 +1133,49 @@ int tipc_shutdown(u32 ref) return tipc_disconnect(ref); } +/** + * tipc_port_recv_msg - receive message from lower layer and deliver to port user + */ + +int tipc_port_recv_msg(struct sk_buff *buf) +{ + struct tipc_port *p_ptr; + struct tipc_msg *msg = buf_msg(buf); + u32 destport = msg_destport(msg); + u32 dsz = msg_data_sz(msg); + u32 err; + + /* forward unresolved named message */ + if (unlikely(!destport)) { + tipc_net_route_msg(buf); + return dsz; + } + + /* validate destination & pass to port, otherwise reject message */ + p_ptr = tipc_port_lock(destport); + if (likely(p_ptr)) { + if (likely(p_ptr->connected)) { + if ((unlikely(msg_origport(msg) != + tipc_peer_port(p_ptr))) || + (unlikely(msg_orignode(msg) != + tipc_peer_node(p_ptr))) || + (unlikely(!msg_connected(msg)))) { + err = TIPC_ERR_NO_PORT; + tipc_port_unlock(p_ptr); + goto reject; + } + } + err = p_ptr->dispatcher(p_ptr, buf); + tipc_port_unlock(p_ptr); + if (likely(!err)) + return dsz; + } else { + err = TIPC_ERR_NO_PORT; + } +reject: + return tipc_reject_msg(buf, err); +} + /* * tipc_port_recv_sections(): Concatenate and deliver sectioned * message for this node. diff --git a/net/tipc/port.h b/net/tipc/port.h index f751807e2a9..9b88531e5a6 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -205,6 +205,7 @@ int tipc_disconnect_port(struct tipc_port *tp_ptr); /* * TIPC messaging routines */ +int tipc_port_recv_msg(struct sk_buff *buf); int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect, unsigned int total_len); @@ -271,45 +272,4 @@ static inline int tipc_port_congested(struct tipc_port *p_ptr) return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2); } -/** - * tipc_port_recv_msg - receive message from lower layer and deliver to port user - */ - -static inline int tipc_port_recv_msg(struct sk_buff *buf) -{ - struct tipc_port *p_ptr; - struct tipc_msg *msg = buf_msg(buf); - u32 destport = msg_destport(msg); - u32 dsz = msg_data_sz(msg); - u32 err; - - /* forward unresolved named message */ - if (unlikely(!destport)) { - tipc_net_route_msg(buf); - return dsz; - } - - /* validate destination & pass to port, otherwise reject message */ - p_ptr = tipc_port_lock(destport); - if (likely(p_ptr)) { - if (likely(p_ptr->connected)) { - if ((unlikely(msg_origport(msg) != tipc_peer_port(p_ptr))) || - (unlikely(msg_orignode(msg) != tipc_peer_node(p_ptr))) || - (unlikely(!msg_connected(msg)))) { - err = TIPC_ERR_NO_PORT; - tipc_port_unlock(p_ptr); - goto reject; - } - } - err = p_ptr->dispatcher(p_ptr, buf); - tipc_port_unlock(p_ptr); - if (likely(!err)) - return dsz; - } else { - err = TIPC_ERR_NO_PORT; - } -reject: - return tipc_reject_msg(buf, err); -} - #endif -- cgit v1.2.3-70-g09d2 From e8ec1ae756de320644c69194898c53d247925586 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 9 Nov 2011 17:38:20 -0500 Subject: tipc: Eliminate obsolete code for re-sending a message Removes code that updated the "previous node" field of an out-going message over TIPC's links. Such updating is unnecessary since the removal of the prototype multi-cluster capability means that all outgoing messages are generated locally and already have this field populated correctly. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index f16e65dd50c..b4b9b30167a 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -871,8 +871,6 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf) u32 queue_limit = l_ptr->queue_limit[imp]; u32 max_packet = l_ptr->max_pkt; - msg_set_prevnode(msg, tipc_own_addr); /* If routed message */ - /* Match msg importance against queue limits: */ if (unlikely(queue_size >= queue_limit)) { -- cgit v1.2.3-70-g09d2 From 9bbbc59dbd4e69da078b65a7f708c4250984dd29 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 9 Nov 2011 16:30:55 -0500 Subject: tipc: Optimize setting of immutable payload message header fields Optimizes routines that send payload messages so that they no longer update the "originating node" and "originating port" fields of the outgoing message header template, since these fields are initialized when the sending port is created and never change thereafter. Also optimizes the routine which updates the message header template when a connection to a port is established, for the same reason. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/port.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'net') diff --git a/net/tipc/port.c b/net/tipc/port.c index 6adcdf99123..94d2904cce6 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -1054,8 +1054,6 @@ int tipc_connect2port(u32 ref, struct tipc_portid const *peer) msg = &p_ptr->phdr; msg_set_destnode(msg, peer->node); msg_set_destport(msg, peer->ref); - msg_set_orignode(msg, tipc_own_addr); - msg_set_origport(msg, p_ptr->ref); msg_set_type(msg, TIPC_CONN_MSG); msg_set_lookup_scope(msg, 0); msg_set_hdr_sz(msg, SHORT_H_SIZE); @@ -1254,8 +1252,6 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, msg = &p_ptr->phdr; msg_set_type(msg, TIPC_NAMED_MSG); - msg_set_orignode(msg, tipc_own_addr); - msg_set_origport(msg, ref); msg_set_hdr_sz(msg, NAMED_H_SIZE); msg_set_nametype(msg, name->type); msg_set_nameinst(msg, name->instance); @@ -1305,8 +1301,6 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest, msg = &p_ptr->phdr; msg_set_type(msg, TIPC_DIRECT_MSG); msg_set_lookup_scope(msg, 0); - msg_set_orignode(msg, tipc_own_addr); - msg_set_origport(msg, ref); msg_set_destnode(msg, dest->node); msg_set_destport(msg, dest->ref); msg_set_hdr_sz(msg, BASIC_H_SIZE); @@ -1345,8 +1339,6 @@ int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest, msg = &p_ptr->phdr; msg_set_type(msg, TIPC_DIRECT_MSG); - msg_set_orignode(msg, tipc_own_addr); - msg_set_origport(msg, ref); msg_set_destnode(msg, dest->node); msg_set_destport(msg, dest->ref); msg_set_hdr_sz(msg, BASIC_H_SIZE); -- cgit v1.2.3-70-g09d2 From 53bf2426b4122d933213bba78bf736e88f7dc929 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 29 Feb 2012 16:38:13 -0300 Subject: Bluetooth: Fix Kconfig help description SMP is not a kernel module, it is part of Bluetooth Core (as already described in lines above). Signed-off-by: Andre Guedes Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 9ec85eb8853..3537d385035 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -29,7 +29,6 @@ menuconfig BT BNEP Module (Bluetooth Network Encapsulation Protocol) CMTP Module (CAPI Message Transport Protocol) HIDP Module (Human Interface Device Protocol) - SMP Module (Security Manager Protocol) Say Y here to compile Bluetooth support into the kernel or say M to compile it as module (bluetooth). -- cgit v1.2.3-70-g09d2 From 63c9c5e77c36f8793dddf0e905a4bc43a0972735 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Feb 2012 13:50:51 +0100 Subject: cfg80211: remove cookies from callbacks In "cfg80211: no cookies in cfg80211_send_XXX()" Holger Schurig removed the cookies in the calls from mac80211 to cfg80211, but the ones in the other direction were left in. Remove them now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 6 ++---- net/mac80211/cfg.c | 12 ++++-------- net/mac80211/ieee80211_i.h | 6 ++---- net/mac80211/mlme.c | 28 ++++++++++++++-------------- net/wireless/mlme.c | 6 +++--- 5 files changed, 25 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 755a7707a7c..0178c748937 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1587,11 +1587,9 @@ struct cfg80211_ops { int (*assoc)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req); int (*deauth)(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_deauth_request *req, - void *cookie); + struct cfg80211_deauth_request *req); int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_disassoc_request *req, - void *cookie); + struct cfg80211_disassoc_request *req); int (*connect)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f7eb25aabf8..6a77d4c910f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1595,19 +1595,15 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_deauth_request *req, - void *cookie) + struct cfg80211_deauth_request *req) { - return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), - req, cookie); + return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_disassoc_request *req, - void *cookie) + struct cfg80211_disassoc_request *req) { - return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), - req, cookie); + return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4d1682950a6..cee0c7493fd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1150,11 +1150,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req); int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req, - void *cookie); + struct cfg80211_deauth_request *req); int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req, - void *cookie); + struct cfg80211_disassoc_request *req); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0c220e1b6c9..edba1d8158f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -612,8 +612,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, u16 stype, u16 reason, - void *cookie, bool send_frame) + const u8 *bssid, u16 stype, + u16 reason, bool cfg80211_locked, + bool send_frame) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -637,12 +638,12 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - if (cookie) + if (cfg80211_locked) __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); else cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); else - if (cookie) + if (cfg80211_locked) __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); else cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); @@ -1696,7 +1697,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - NULL, true); + false, true); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -2706,8 +2707,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, * but that's not a problem. */ ieee80211_send_deauth_disassoc(sdata, bssid, - IEEE80211_STYPE_DEAUTH, reason, - NULL, true); + IEEE80211_STYPE_DEAUTH, + reason, false, true); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -3439,8 +3440,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req, - void *cookie) + struct cfg80211_deauth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; bool assoc_bss = false; @@ -3461,8 +3461,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", sdata->name, req->bssid, req->reason_code); - ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, - req->reason_code, cookie, true); + ieee80211_send_deauth_disassoc(sdata, req->bssid, + IEEE80211_STYPE_DEAUTH, + req->reason_code, true, true); if (assoc_bss) sta_info_flush(sdata->local, sdata); @@ -3474,8 +3475,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req, - void *cookie) + struct cfg80211_disassoc_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 bssid[ETH_ALEN]; @@ -3503,7 +3503,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, IEEE80211_STYPE_DISASSOC, req->reason_code, - cookie, !req->local_state_change); + true, !req->local_state_change); sta_info_flush(sdata->local, sdata); mutex_lock(&sdata->local->mtx); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d553d365e75..fb1e7217911 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -455,7 +455,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, return 0; } - return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); + return rdev->ops->deauth(&rdev->wiphy, dev, &req); } int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, @@ -500,7 +500,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, else return -ENOTCONN; - return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev); + return rdev->ops->disassoc(&rdev->wiphy, dev, &req); } int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, @@ -541,7 +541,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); req.bssid = bssid; - rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); + rdev->ops->deauth(&rdev->wiphy, dev, &req); if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); -- cgit v1.2.3-70-g09d2 From 5fef7dbcadbb85079d3bf56625dd12e6d2816e3d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Feb 2012 13:50:52 +0100 Subject: mac80211: dont call cfg80211 from ieee80211_send_deauth_disassoc Instead of calling cfg80211 in ieee80211_send_deauth_disassoc() pass out the frame and call it from the caller. That saves the SKB allocation if we don't actually want to send the frame and enables us to make the ordering smarter in the future. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 71 ++++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index edba1d8158f..82d49341eaa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -88,6 +88,8 @@ MODULE_PARM_DESC(probe_wait_ms, #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 +#define DEAUTH_DISASSOC_LEN (24 /* hdr */ + 2 /* reason */) + /* * All cfg80211 functions have to be called outside a locked * section so that they can acquire a lock themselves... This @@ -613,47 +615,41 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *bssid, u16 stype, - u16 reason, bool cfg80211_locked, - bool send_frame) + u16 reason, bool send_frame, + u8 *frame_buf) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); - if (!skb) - return; + struct ieee80211_mgmt *mgmt = (void *)frame_buf; - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); + /* build frame */ + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); + mgmt->duration = 0; /* initialize only */ + mgmt->seq_ctrl = 0; /* initialize only */ memcpy(mgmt->da, bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); - skb_put(skb, 2); /* u.deauth.reason_code == u.disassoc.reason_code */ mgmt->u.deauth.reason_code = cpu_to_le16(reason); - if (stype == IEEE80211_STYPE_DEAUTH) - if (cfg80211_locked) - __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); - else - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); - else - if (cfg80211_locked) - __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); - else - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); - if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + if (send_frame) { + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + DEAUTH_DISASSOC_LEN); + if (!skb) + return; - if (send_frame) + skb_reserve(skb, local->hw.extra_tx_headroom); + + /* copy in frame */ + memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN), + mgmt, DEAUTH_DISASSOC_LEN); + + if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) + IEEE80211_SKB_CB(skb)->flags |= + IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); - else - kfree_skb(skb); + } } void ieee80211_send_pspoll(struct ieee80211_local *local, @@ -1675,6 +1671,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; u8 bssid[ETH_ALEN]; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) { @@ -1697,7 +1694,8 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - false, true); + false, frame_buf); + cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -2696,6 +2694,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); @@ -2708,7 +2707,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, */ ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, - reason, false, true); + reason, false, frame_buf); + cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&local->mtx); ieee80211_recalc_idle(local); @@ -3444,6 +3444,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; bool assoc_bss = false; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; mutex_lock(&ifmgd->mtx); @@ -3463,7 +3464,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, - req->reason_code, true, true); + req->reason_code, true, frame_buf); + __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); if (assoc_bss) sta_info_flush(sdata->local, sdata); @@ -3479,6 +3481,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 bssid[ETH_ALEN]; + u8 frame_buf[DEAUTH_DISASSOC_LEN]; mutex_lock(&ifmgd->mtx); @@ -3502,8 +3505,10 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, - IEEE80211_STYPE_DISASSOC, req->reason_code, - true, !req->local_state_change); + IEEE80211_STYPE_DISASSOC, + req->reason_code, + !req->local_state_change, frame_buf); + __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); sta_info_flush(sdata->local, sdata); mutex_lock(&sdata->local->mtx); -- cgit v1.2.3-70-g09d2 From 02d83e60b9864e7920d87b49e1fbedffd32470f8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Feb 2012 13:50:53 +0100 Subject: mac80211: fix ieee80211_set_disassoc() sending DelBA When ieee80211_set_disassoc() is called with the tx argument set to true, it will send DelBA out to the peer. This isn't useful or necessary in a few cases where we do it today, those being when we lost the connection or when the supplicant explicitly asked us to not tell the AP. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 82d49341eaa..379a1d14016 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1684,7 +1684,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n", sdata->name, bssid); - ieee80211_set_disassoc(sdata, true, true); + ieee80211_set_disassoc(sdata, true, false); mutex_unlock(&ifmgd->mtx); /* @@ -2699,7 +2699,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); - ieee80211_set_disassoc(sdata, true, true); + ieee80211_set_disassoc(sdata, true, false); mutex_unlock(&ifmgd->mtx); /* * must be outside lock due to cfg80211, @@ -3500,7 +3500,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, sdata->name, req->bss->bssid, req->reason_code); memcpy(bssid, req->bss->bssid, ETH_ALEN); - ieee80211_set_disassoc(sdata, false, true); + ieee80211_set_disassoc(sdata, false, !req->local_state_change); mutex_unlock(&ifmgd->mtx); -- cgit v1.2.3-70-g09d2 From 37ad38887d9ca5ed66c6f2b14a8921794bf3d4c3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Feb 2012 13:50:54 +0100 Subject: mac80211: make deauth/disassoc sequence more natural The association sequence looks (roughly) like this now: * set BSSID * set station to EXIST state * send auth * set station to AUTH state * send assoc * set station to ASSOC state * set BSS info to associated In contrast, the deauth/disassoc sequence is the other way around: * clear BSSID/BSS info state * remove station * send deauth/disassoc (in some cases the last two steps are reversed.) This patch encodes the entire sequence in the ieee80211_set_disassoc() function and changes it to be like this, for good measure with an explicit flush: * send deauth/disassoc * flush * remove station * clear BSSID/BSS info state At least iwlwifi gets confused with the other sequence in P2P mode and complains that it wasn't able to flush the queues. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 84 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 37 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 379a1d14016..caf97f5a293 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1389,7 +1389,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - bool remove_sta, bool tx) + u16 stype, u16 reason, bool tx, + u8 *frame_buf) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1399,6 +1400,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ASSERT_MGD_MTX(ifmgd); + if (WARN_ON_ONCE(tx && !frame_buf)) + return; + if (WARN_ON(!ifmgd->associated)) return; @@ -1432,6 +1436,19 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } mutex_unlock(&local->sta_mtx); + /* deauthenticate/disassociate now */ + if (tx || frame_buf) + ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason, + tx, frame_buf); + + /* flush out frame */ + if (tx) + drv_flush(local, false); + + /* remove AP and TDLS peers */ + sta_info_flush(local, sdata); + + /* finally reset all BSS / config parameters */ changed |= ieee80211_reset_erp_info(sdata); ieee80211_led_assoc(local, 0); @@ -1471,10 +1488,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); - /* remove AP and TDLS peers */ - if (remove_sta) - sta_info_flush(local, sdata); - del_timer_sync(&sdata->u.mgd.conn_mon_timer); del_timer_sync(&sdata->u.mgd.bcn_mon_timer); del_timer_sync(&sdata->u.mgd.timer); @@ -1684,17 +1697,15 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n", sdata->name, bssid); - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + false, frame_buf); mutex_unlock(&ifmgd->mtx); /* * must be outside lock due to cfg80211, * but that's not a problem. */ - ieee80211_send_deauth_disassoc(sdata, bssid, - IEEE80211_STYPE_DEAUTH, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - false, frame_buf); cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&local->mtx); @@ -1902,7 +1913,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", sdata->name, bssid, reason_code); - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); + mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); mutex_unlock(&sdata->local->mtx); @@ -1932,10 +1944,12 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", sdata->name, mgmt->sa, reason_code); - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); + mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); mutex_unlock(&sdata->local->mtx); + return RX_MGMT_CFG80211_DISASSOC; } @@ -2699,15 +2713,14 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, + false, frame_buf); mutex_unlock(&ifmgd->mtx); + /* * must be outside lock due to cfg80211, * but that's not a problem. */ - ieee80211_send_deauth_disassoc(sdata, bssid, - IEEE80211_STYPE_DEAUTH, - reason, false, frame_buf); cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); mutex_lock(&local->mtx); @@ -3192,7 +3205,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, ifmgd->auth_data = auth_data; if (ifmgd->associated) - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); printk(KERN_DEBUG "%s: authenticate with %pM\n", sdata->name, req->bss->bssid); @@ -3270,7 +3283,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); if (ifmgd->associated) - ieee80211_set_disassoc(sdata, true, false); + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); if (ifmgd->auth_data && !ifmgd->auth_data->done) { err = -EBUSY; @@ -3443,31 +3456,32 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct cfg80211_deauth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - bool assoc_bss = false; u8 frame_buf[DEAUTH_DISASSOC_LEN]; mutex_lock(&ifmgd->mtx); - if (ifmgd->associated && - memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) { - ieee80211_set_disassoc(sdata, false, true); - assoc_bss = true; - } else if (ifmgd->auth_data) { + if (ifmgd->auth_data) { ieee80211_destroy_auth_data(sdata, false); mutex_unlock(&ifmgd->mtx); return 0; } - mutex_unlock(&ifmgd->mtx); - printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", + printk(KERN_DEBUG + "%s: deauthenticating from %pM by local choice (reason=%d)\n", sdata->name, req->bssid, req->reason_code); - ieee80211_send_deauth_disassoc(sdata, req->bssid, - IEEE80211_STYPE_DEAUTH, + if (ifmgd->associated && + memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, req->reason_code, true, frame_buf); + else + ieee80211_send_deauth_disassoc(sdata, req->bssid, + IEEE80211_STYPE_DEAUTH, + req->reason_code, true, + frame_buf); + mutex_unlock(&ifmgd->mtx); + __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); - if (assoc_bss) - sta_info_flush(sdata->local, sdata); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); @@ -3500,16 +3514,12 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, sdata->name, req->bss->bssid, req->reason_code); memcpy(bssid, req->bss->bssid, ETH_ALEN); - ieee80211_set_disassoc(sdata, false, !req->local_state_change); - + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, + req->reason_code, !req->local_state_change, + frame_buf); mutex_unlock(&ifmgd->mtx); - ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, - IEEE80211_STYPE_DISASSOC, - req->reason_code, - !req->local_state_change, frame_buf); __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); - sta_info_flush(sdata->local, sdata); mutex_lock(&sdata->local->mtx); ieee80211_recalc_idle(sdata->local); -- cgit v1.2.3-70-g09d2 From 02f2f1a951f87644166926862ec32fb13511e2f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Feb 2012 12:18:30 +0100 Subject: mac80211: handle non-bufferable MMPDUs correctly This renames the IEEE80211_TX_CTL_POLL_RESPONSE TX flag to IEEE80211_TX_CTL_NO_PS_BUFFER and also uses it for non-bufferable MMPDUs (all MMPDUs but deauth, disassoc and action frames.) Previously, mac80211 would let the MMPDU through but not set the flag so drivers supporting some hardware aids for avoiding the PS races would then reject the frame. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/4965-mac.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 6 +++++- drivers/net/wireless/p54/txrx.c | 2 +- include/net/mac80211.h | 17 ++++++++++------- net/mac80211/sta_info.c | 4 ++-- net/mac80211/tx.c | 17 +++++++++++------ 6 files changed, 30 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 2d01db0f08e..2329033e23d 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -1693,7 +1693,7 @@ il4965_tx_skb(struct il_priv *il, struct sk_buff *skb) sta_priv = (void *)sta->drv_priv; if (sta_priv && sta_priv->asleep && - (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { + (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index da18a8fc9af..5f78567f418 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -322,7 +322,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) sta_priv = (void *)info->control.sta->drv_priv; if (sta_priv && sta_priv->asleep && - (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { + (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the @@ -331,6 +331,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) * counter. * For now set the counter to just 1 since we do not * support uAPSD yet. + * + * FIXME: If we get two non-bufferable frames one + * after the other, we might only send out one of + * them because this is racy. */ iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); } diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 42b97bc3847..a08a6f0e4dd 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -690,7 +690,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; - if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE) + if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index cbff4f94a20..7477f020ee7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -341,9 +341,9 @@ struct ieee80211_bss_conf { * used to indicate that a frame was already retried due to PS * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, * used to indicate frame should not be encrypted - * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll - * frame (PS-Poll or uAPSD) and should be sent although the station - * is in powersave mode. + * @IEEE80211_TX_CTL_NO_PS_BUFFER: This frame is a response to a poll + * frame (PS-Poll or uAPSD) or a non-bufferable MMPDU and must + * be sent although the station is in powersave mode. * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the * transmit function after the current frame, this can be used * by drivers to kick the DMA queue only if unset or when the @@ -399,7 +399,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), - IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17), + IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17), IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), /* hole at 20, use later */ @@ -425,7 +425,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ - IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE | \ + IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_NO_PS_BUFFER | \ IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP) @@ -1634,7 +1634,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); * the station sends a PS-Poll or a uAPSD trigger frame, mac80211 * will inform the driver of this with the @allow_buffered_frames * callback; this callback is optional. mac80211 will then transmit - * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE + * the frames as usual and set the %IEEE80211_TX_CTL_NO_PS_BUFFER * on each frame. The last frame in the service period (or the only * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to * indicate that it ends the service period; as this frame must have @@ -1642,6 +1642,9 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); * When TX status is reported for this frame, the service period is * marked has having ended and a new one can be started by the peer. * + * Additionally, non-bufferable MMPDUs can also be transmitted by + * mac80211 with the %IEEE80211_TX_CTL_NO_PS_BUFFER set in them. + * * Another race condition can happen on some devices like iwlwifi * when there are frames queued for the station and it wakes up * or polls; the frames that are already queued could end up being @@ -2140,7 +2143,7 @@ enum ieee80211_frame_release_type { * @allow_buffered_frames: Prepare device to allow the given number of frames * to go out to the given station. The frames will be sent by mac80211 * via the usual TX path after this call. The TX information for frames - * released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set + * released will also have the %IEEE80211_TX_CTL_NO_PS_BUFFER flag set * and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case * frames from multiple TIDs are released and the driver might reorder * them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 98613c8f08c..cd0f265f42e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1050,7 +1050,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, * exchange. Also set EOSP to indicate this packet * ends the poll/service period. */ - info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE | + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | IEEE80211_TX_STATUS_EOSP | IEEE80211_TX_CTL_REQ_TX_STATUS; @@ -1177,7 +1177,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, * STA may still remain is PS mode after this frame * exchange. */ - info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE; + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; /* * Use MoreData flag to indicate whether there are diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7c021f25571..570737df2d2 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -448,18 +448,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; struct ieee80211_local *local = tx->local; - if (unlikely(!sta || - ieee80211_is_probe_resp(hdr->frame_control) || - ieee80211_is_auth(hdr->frame_control) || - ieee80211_is_assoc_resp(hdr->frame_control) || - ieee80211_is_reassoc_resp(hdr->frame_control))) + if (unlikely(!sta)) return TX_CONTINUE; if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || test_sta_flag(sta, WLAN_STA_PS_DRIVER)) && - !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) { + !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { int ac = skb_get_queue_mapping(tx->skb); + /* only deauth, disassoc and action are bufferable MMPDUs */ + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_deauth(hdr->frame_control) && + !ieee80211_is_disassoc(hdr->frame_control) && + !ieee80211_is_action(hdr->frame_control)) { + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; + return TX_CONTINUE; + } + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n", sta->sta.addr, sta->sta.aid, ac); -- cgit v1.2.3-70-g09d2 From 00abfe4442864144a77f70b6b411d691bcb796bf Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 1 Mar 2012 00:37:10 -0300 Subject: Bluetooth: Fix coding style with breaking lines Our limit is 80 and broken lines should as right as possible. Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btmrvl_debugfs.c | 19 +++++++++---------- net/bluetooth/hci_event.c | 3 ++- net/bluetooth/mgmt.c | 3 +-- 3 files changed, 12 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 60fe333cfd4..3497347e6db 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -401,28 +401,27 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, - priv, &btmrvl_psmode_fops); + priv, &btmrvl_psmode_fops); dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, - priv, &btmrvl_pscmd_fops); + priv, &btmrvl_pscmd_fops); dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, - priv, &btmrvl_gpiogap_fops); + priv, &btmrvl_gpiogap_fops); dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, - priv, &btmrvl_hsmode_fops); + priv, &btmrvl_hsmode_fops); dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, - priv, &btmrvl_hscmd_fops); + priv, &btmrvl_hscmd_fops); dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, - priv, &btmrvl_hscfgcmd_fops); + priv, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); dbg->curpsmode = debugfs_create_file("curpsmode", 0444, dbg->status_dir, priv, &btmrvl_curpsmode_fops); dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, - priv, &btmrvl_psstate_fops); + priv, &btmrvl_psstate_fops); dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, - priv, &btmrvl_hsstate_fops); + priv, &btmrvl_hsstate_fops); dbg->txdnldready = debugfs_create_file("txdnldready", 0444, - dbg->status_dir, - priv, + dbg->status_dir, priv, &btmrvl_txdnldready_fops); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 746f7d37225..aee9556e103 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1344,7 +1344,8 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, return 1; } -static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e) +static inline int hci_resolve_name(struct hci_dev *hdev, + struct inquiry_entry *e) { struct hci_cp_remote_name_req cp; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b0c43fe4356..373b46a9eb1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1926,8 +1926,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, - len); + cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len); if (!cmd) { err = -ENOMEM; goto failed; -- cgit v1.2.3-70-g09d2 From 1de028ceb54ccd28cc96f1530a195ae1b6a6d5b5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Feb 2012 19:55:35 -0800 Subject: Bluetooth: mgmt: Add missing hci_dev locking to set_le() The set_le() function was missing hci_dev locking which is e.g. critical for the mgmt pending command adding/removing. Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 373b46a9eb1..abf1adb8bc1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1273,10 +1273,12 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_INVALID_PARAMS); + hci_dev_lock(hdev); + if (!enable_le || !(hdev->features[4] & LMP_LE)) { err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_NOT_SUPPORTED); - goto failed; + goto unlock; } val = !!cp->val; @@ -1292,23 +1294,23 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev); if (err < 0) - goto failed; + goto unlock; if (changed) err = new_settings(hdev, sk); - goto failed; + goto unlock; } if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY); - goto failed; + goto unlock; } cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len); if (!cmd) { err = -ENOMEM; - goto failed; + goto unlock; } memset(&hci_cp, 0, sizeof(hci_cp)); @@ -1322,10 +1324,11 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) sizeof(hci_cp), &hci_cp); if (err < 0) { mgmt_pending_remove(cmd); - goto failed; + goto unlock; } -failed: +unlock: + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } -- cgit v1.2.3-70-g09d2 From 48752f6513012a1b078da08b145d5c40a644f058 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Wed, 8 Feb 2012 00:45:00 +0000 Subject: rtnetlink: Fix VF IFLA policy Add VF spoof check to IFLA policy. The original patch I submitted to add the spoof checking feature to rtnl failed to add the proper policy rule that identifies the data type and len. This patch corrects that oversight. No bugs have been reported against this but it may cause some problem for the netlink message parsing that uses the policy table. CC: stable@vger.kernel.org Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- net/core/rtnetlink.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5cf39cd7da8..2be10181d58 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1132,6 +1132,8 @@ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { .len = sizeof(struct ifla_vf_vlan) }, [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, .len = sizeof(struct ifla_vf_tx_rate) }, + [IFLA_VF_SPOOFCHK] = { .type = NLA_BINARY, + .len = sizeof(struct ifla_vf_spoofchk) }, }; static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = { -- cgit v1.2.3-70-g09d2 From 8b90129cc5789a4c65547c91c9a7b1fd3a4d56a4 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 23 Feb 2012 18:09:27 -0300 Subject: Bluetooth: Check capabilities in BR/EDR and LE-Only discovery This patch add an extra check for BR/EDR and LE-Only discovery. This way, we are able to return error immediately if the discovery type requested is not supported by the device. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index abf1adb8bc1..3fcccad7545 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2602,12 +2602,18 @@ static int start_discovery(struct sock *sk, u16 index, switch (hdev->discovery.type) { case DISCOV_TYPE_BREDR: - err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + if (lmp_bredr_capable(hdev)) + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + else + err = -ENOTSUPP; break; case DISCOV_TYPE_LE: - err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + if (lmp_host_le_capable(hdev)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + else + err = -ENOTSUPP; break; case DISCOV_TYPE_INTERLEAVED: -- cgit v1.2.3-70-g09d2 From 75fb0e324daa48ec458fb5c2960eb07b80cfad9d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 1 Mar 2012 21:35:55 +0200 Subject: Bluetooth: Fix init sequence for some CSR based controllers Some CSR controllers will generate a spontaneous reset during init and just eat up any pending command without sending a command complete for it. This patch solves the issue by just resending whatever was the last sent command. hci_send_cmd is not used since we need to bypass all other commands in the send queue. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index db484a8e736..d3ddc0ba9cd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -82,8 +82,28 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) /* If this is the init phase check if the completed command matches * the last init command, and if not just return. */ - if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) + if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) { + struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; + struct sk_buff *skb; + + /* Some CSR based controllers generate a spontaneous + * reset complete event during init and any pending + * command will never be completed. In such a case we + * need to resend whatever was the last sent + * command. + */ + + if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET) + return; + + skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC); + if (skb) { + skb_queue_head(&hdev->cmd_q, skb); + queue_work(hdev->workqueue, &hdev->cmd_work); + } + return; + } if (hdev->req_status == HCI_REQ_PEND) { hdev->req_result = result; -- cgit v1.2.3-70-g09d2 From bdb6d97154b7b7e98867e9b71bae0f47ec70b1d7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 06:13:32 +0200 Subject: Bluetooth: mgmt: Refactor hci_dev lookup for commands Almost all mgmt commands need to lookup a struct hci_dev based on the index received within the mgmt headers. It makese therefore sense to look this up in a single place and then just pass the hdev pointer to each command handler function. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 764 ++++++++++++++++++--------------------------------- 1 file changed, 274 insertions(+), 490 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3fcccad7545..cc9fb64def9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -624,17 +624,11 @@ static void mgmt_init_hdev(struct hci_dev *hdev) } } -static int read_controller_info(struct sock *sk, u16 index) +static int read_controller_info(struct sock *sk, struct hci_dev *hdev) { struct mgmt_rp_read_info rp; - struct hci_dev *hdev; - - BT_DBG("sock %p hci%u", sk, index); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_READ_INFO, - MGMT_STATUS_INVALID_PARAMS); + BT_DBG("sock %p %s", sk, hdev->name); hci_dev_lock(hdev); @@ -658,9 +652,9 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name)); hci_dev_unlock(hdev); - hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp)); + return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp, + sizeof(rp)); } static void mgmt_pending_free(struct pending_cmd *cmd) @@ -744,22 +738,17 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) sizeof(settings)); } -static int set_powered(struct sock *sk, u16 index, void *data, u16 len) +static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_POWERED, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_POWERED, + return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -780,7 +769,7 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_POWERED, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, MGMT_STATUS_BUSY); goto failed; } @@ -800,7 +789,6 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } @@ -843,48 +831,43 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip) return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip); } -static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) +static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_set_discoverable *cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; u16 timeout; u8 scan; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); timeout = get_unaligned_le16(&cp->timeout); if (!cp->val && timeout > 0) - return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev) && timeout > 0) { - err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_BUSY); goto failed; } if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_REJECTED); goto failed; } @@ -945,28 +928,21 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) +static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; u8 scan; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -996,7 +972,7 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_BUSY); goto failed; } @@ -1028,26 +1004,19 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) +static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -1065,28 +1034,21 @@ static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) +static int set_link_security(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; u8 val; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -1111,7 +1073,7 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, MGMT_STATUS_BUSY); goto failed; } @@ -1137,34 +1099,26 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) +static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; u8 val; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_SSP, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_SSP, + return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, MGMT_STATUS_NOT_SUPPORTED); goto failed; } @@ -1190,7 +1144,8 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, + MGMT_STATUS_BUSY); goto failed; } @@ -1213,70 +1168,49 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_hs(struct sock *sk, u16 index, void *data, u16 len) +static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; - int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_HS, + return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_HS, - MGMT_STATUS_INVALID_PARAMS); - - if (!enable_hs) { - err = cmd_status(sk, index, MGMT_OP_SET_HS, - MGMT_STATUS_NOT_SUPPORTED); - goto failed; - } + if (!enable_hs) + return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, + MGMT_STATUS_NOT_SUPPORTED); if (cp->val) set_bit(HCI_HS_ENABLED, &hdev->dev_flags); else clear_bit(HCI_HS_ENABLED, &hdev->dev_flags); - err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); - -failed: - hci_dev_put(hdev); - return err; + return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); } -static int set_le(struct sock *sk, u16 index, void *data, u16 len) +static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; struct hci_cp_write_le_host_supported hci_cp; struct pending_cmd *cmd; - struct hci_dev *hdev; int err; u8 val, enabled; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_LE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_LE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!enable_le || !(hdev->features[4] & LMP_LE)) { - err = cmd_status(sk, index, MGMT_OP_SET_LE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, MGMT_STATUS_NOT_SUPPORTED); goto unlock; } @@ -1303,7 +1237,8 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, + MGMT_STATUS_BUSY); goto unlock; } @@ -1329,33 +1264,26 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) +static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; struct bt_uuid *uuid; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_ADD_UUID, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_ADD_UUID, + return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_ADD_UUID, + err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, MGMT_STATUS_BUSY); goto failed; } @@ -1380,7 +1308,7 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) goto failed; if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3); goto failed; } @@ -1393,8 +1321,6 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } @@ -1412,30 +1338,25 @@ static bool enable_service_cache(struct hci_dev *hdev) return false; } -static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) +static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_remove_uuid *cp = data; struct pending_cmd *cmd; struct list_head *p, *n; - struct hci_dev *hdev; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int err, found; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, MGMT_STATUS_BUSY); goto unlock; } @@ -1444,8 +1365,8 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) err = hci_uuids_clear(hdev); if (enable_service_cache(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, - hdev->dev_class, 3); + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, + 0, hdev->dev_class, 3); goto unlock; } @@ -1465,7 +1386,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) } if (found == 0) { - err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -1480,7 +1401,7 @@ update_class: goto unlock; if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0, hdev->dev_class, 3); goto unlock; } @@ -1493,33 +1414,26 @@ update_class: unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) +static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_set_dev_class *cp = data; struct pending_cmd *cmd; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, MGMT_STATUS_BUSY); goto unlock; } @@ -1528,7 +1442,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hdev->minor_class = cp->minor; if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, hdev->dev_class, 3); goto unlock; } @@ -1545,7 +1459,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) goto unlock; if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, hdev->dev_class, 3); goto unlock; } @@ -1558,20 +1472,18 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) +static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_load_link_keys *cp = data; u16 key_count, expected_len; int i; if (len < sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); key_count = get_unaligned_le16(&cp->key_count); @@ -1581,16 +1493,11 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) if (expected_len != len) { BT_ERR("load_link_keys: expected %u bytes, got %u bytes", len, expected_len); - return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); } - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); - - BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, + BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, key_count); hci_dev_lock(hdev); @@ -1611,10 +1518,9 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) key->type, key->pin_len); } - cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); + cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); hci_dev_unlock(hdev); - hci_dev_put(hdev); return 0; } @@ -1631,9 +1537,9 @@ static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, skip_sk); } -static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) +static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_unpair_device *cp = data; struct mgmt_rp_unpair_device rp; struct hci_cp_disconnect dc; @@ -1642,12 +1548,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) int err; if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -1657,7 +1558,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); goto unlock; @@ -1669,7 +1570,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) err = hci_remove_ltk(hdev, &cp->addr.bdaddr); if (err < 0) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp)); goto unlock; @@ -1687,7 +1588,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) } if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0, &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; @@ -1708,14 +1609,12 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int disconnect(struct sock *sk, u16 index, void *data, u16 len) +static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_disconnect *cp = data; struct hci_cp_disconnect dc; struct pending_cmd *cmd; @@ -1725,24 +1624,19 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_DISCONNECT, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_DISCONNECT, + return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { - err = cmd_status(sk, index, MGMT_OP_DISCONNECT, + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { - err = cmd_status(sk, index, MGMT_OP_DISCONNECT, + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_BUSY); goto failed; } @@ -1753,7 +1647,7 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); if (!conn) { - err = cmd_status(sk, index, MGMT_OP_DISCONNECT, + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1773,8 +1667,6 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } @@ -1797,10 +1689,9 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) } } -static int get_connections(struct sock *sk, u16 index) +static int get_connections(struct sock *sk, struct hci_dev *hdev) { struct mgmt_rp_get_connections *rp; - struct hci_dev *hdev; struct hci_conn *c; size_t rp_len; int err; @@ -1808,15 +1699,10 @@ static int get_connections(struct sock *sk, u16 index) BT_DBG(""); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, + err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -1850,18 +1736,18 @@ static int get_connections(struct sock *sk, u16 index) /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); - err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len); + err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp, + rp_len); kfree(rp); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int send_pin_code_neg_reply(struct sock *sk, u16 index, - struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp) +static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, + struct mgmt_cp_pin_code_neg_reply *cp) { struct pending_cmd *cmd; int err; @@ -1879,9 +1765,9 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index, return err; } -static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) +static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct hci_conn *conn; struct mgmt_cp_pin_code_reply *cp = data; struct hci_cp_pin_code_reply reply; @@ -1891,25 +1777,20 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); if (!conn) { - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1921,9 +1802,9 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) BT_ERR("PIN code is not 16 bytes long"); - err = send_pin_code_neg_reply(sk, index, hdev, &ncp); + err = send_pin_code_neg_reply(sk, hdev, &ncp); if (err >= 0) - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); goto failed; @@ -1945,59 +1826,45 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len) +static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_pin_code_neg_reply *cp = data; int err; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; } - err = send_pin_code_neg_reply(sk, index, hdev, cp); + err = send_pin_code_neg_reply(sk, hdev, cp); failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) +static int set_io_capability(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_set_io_capability *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, + return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -2008,9 +1875,9 @@ static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) hdev->io_capability); hci_dev_unlock(hdev); - hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0); + return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, + NULL, 0); } static inline struct pending_cmd *find_pairing(struct hci_conn *conn) @@ -2065,9 +1932,9 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) pairing_complete(cmd, mgmt_status(status)); } -static int pair_device(struct sock *sk, u16 index, void *data, u16 len) +static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_pair_device *cp = data; struct mgmt_rp_pair_device rp; struct pending_cmd *cmd; @@ -2078,18 +1945,13 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -2112,7 +1974,7 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (IS_ERR(conn)) { - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_CONNECT_FAILED, &rp, sizeof(rp)); goto unlock; @@ -2120,7 +1982,7 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) if (conn->connect_cfm_cb) { hci_conn_put(conn); - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } @@ -2149,16 +2011,13 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int cancel_pair_device(struct sock *sk, u16 index, +static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, unsigned char *data, u16 len) { struct mgmt_addr_info *addr = (void *) data; - struct hci_dev *hdev; struct pending_cmd *cmd; struct hci_conn *conn; int err; @@ -2166,25 +2025,20 @@ static int cancel_pair_device(struct sock *sk, u16 index, BT_DBG(""); if (len != sizeof(*addr)) - return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_NOT_POWERED); goto unlock; } cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); if (!cmd) { - err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -2192,40 +2046,33 @@ static int cancel_pair_device(struct sock *sk, u16 index, conn = cmd->user_data; if (bacmp(&addr->bdaddr, &conn->dst) != 0) { - err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); goto unlock; } pairing_complete(cmd, MGMT_STATUS_CANCELLED); - err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr, - sizeof(*addr)); + err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0, + addr, sizeof(*addr)); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, - u8 type, u16 mgmt_op, u16 hci_op, - __le32 passkey) +static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type, u16 mgmt_op, + u16 hci_op, __le32 passkey) { struct pending_cmd *cmd; - struct hci_dev *hdev; struct hci_conn *conn; int err; - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, mgmt_op, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED); + err = cmd_status(sk, hdev->id, mgmt_op, + MGMT_STATUS_NOT_POWERED); goto done; } @@ -2235,7 +2082,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); if (!conn) { - err = cmd_status(sk, index, mgmt_op, + err = cmd_status(sk, hdev->id, mgmt_op, MGMT_STATUS_NOT_CONNECTED); goto done; } @@ -2245,10 +2092,10 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, err = smp_user_confirm_reply(conn, mgmt_op, passkey); if (!err) - err = cmd_status(sk, index, mgmt_op, + err = cmd_status(sk, hdev->id, mgmt_op, MGMT_STATUS_SUCCESS); else - err = cmd_status(sk, index, mgmt_op, + err = cmd_status(sk, hdev->id, mgmt_op, MGMT_STATUS_FAILED); goto done; @@ -2275,92 +2122,86 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, done: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) +static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_confirm_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_CONFIRM_REPLY, HCI_OP_USER_CONFIRM_REPLY, 0); } -static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, - u16 len) +static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_confirm_neg_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_CONFIRM_NEG_REPLY, HCI_OP_USER_CONFIRM_NEG_REPLY, 0); } -static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) +static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_passkey_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY, EINVAL); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_REPLY, HCI_OP_USER_PASSKEY_REPLY, cp->passkey); } -static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, - u16 len) +static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_passkey_neg_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY, - EINVAL); + return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY, + EINVAL); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_NEG_REPLY, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } -static int set_local_name(struct sock *sk, u16 index, void *data, +static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_set_local_name *mgmt_cp = data; struct hci_cp_write_local_name hci_cp; - struct hci_dev *hdev; struct pending_cmd *cmd; int err; BT_DBG(""); if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, + return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -2396,40 +2237,32 @@ static int set_local_name(struct sock *sk, u16 index, void *data, failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int read_local_oob_data(struct sock *sk, u16 index) +static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev) { - struct hci_dev *hdev; struct pending_cmd *cmd; int err; - BT_DBG("hci%u", index); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + BT_DBG("%s", hdev->name); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_NOT_POWERED); goto unlock; } if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { - err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_NOT_SUPPORTED); goto unlock; } if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) { - err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_BUSY); goto unlock; } @@ -2446,35 +2279,26 @@ static int read_local_oob_data(struct sock *sk, u16 index) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int add_remote_oob_data(struct sock *sk, u16 index, void *data, - u16 len) +static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_add_remote_oob_data *cp = data; u8 status; int err; - BT_DBG("hci%u ", index); + BT_DBG("%s ", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_NOT_POWERED, &cp->addr, sizeof(cp->addr)); goto unlock; @@ -2487,42 +2311,34 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, else status = 0; - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status, + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int remove_remote_oob_data(struct sock *sk, u16 index, +static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_remove_remote_oob_data *cp = data; u8 status; int err; - BT_DBG("hci%u ", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_NOT_POWERED, - &cp->addr, sizeof(cp->addr)); + err = cmd_complete(sk, hdev->id, + MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, + &cp->addr, sizeof(cp->addr)); goto unlock; } @@ -2532,13 +2348,11 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, else status = 0; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status, - &cp->addr, sizeof(cp->addr)); + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + status, &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } @@ -2559,36 +2373,30 @@ int mgmt_interleaved_discovery(struct hci_dev *hdev) return err; } -static int start_discovery(struct sock *sk, u16 index, +static int start_discovery(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, + return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, + err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, MGMT_STATUS_NOT_POWERED); goto failed; } if (hdev->discovery.state != DISCOVERY_STOPPED) { - err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, + MGMT_STATUS_BUSY); goto failed; } @@ -2635,42 +2443,35 @@ static int start_discovery(struct sock *sk, u16 index, failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) +static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_stop_discovery *mgmt_cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; struct hci_cp_remote_name_req_cancel cp; struct inquiry_entry *e; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, + return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_REJECTED, &mgmt_cp->type, sizeof(mgmt_cp->type)); goto unlock; } if (hdev->discovery.type != mgmt_cp->type) { - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type, sizeof(mgmt_cp->type)); goto unlock; @@ -2694,7 +2495,7 @@ static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); if (!e) { mgmt_pending_remove(cmd); - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0, &mgmt_cp->type, sizeof(mgmt_cp->type)); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; @@ -2710,41 +2511,34 @@ static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) +static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_confirm_name *cp = data; struct inquiry_entry *e; - struct hci_dev *hdev; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); + return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { - err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, + err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, MGMT_STATUS_FAILED); goto failed; } e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { - err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); + err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS); goto failed; } @@ -2760,29 +2554,22 @@ static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - return err; } -static int block_device(struct sock *sk, u16 index, void *data, u16 len) +static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_block_device *cp = data; u8 status; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2791,34 +2578,27 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) else status = 0; - err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status, + err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) +static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_unblock_device *cp = data; u8 status; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2827,41 +2607,35 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) else status = 0; - err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int set_fast_connectable(struct sock *sk, u16 index, - void *data, u16 len) +static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_mode *cp = data; struct hci_cp_write_page_scan_activity acp; u8 type; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); if (!hdev_is_powered(hdev)) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_NOT_POWERED); if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_REJECTED); + return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_REJECTED); hci_dev_lock(hdev); @@ -2878,37 +2652,34 @@ static int set_fast_connectable(struct sock *sk, u16 index, err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp), &acp); if (err < 0) { - err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_FAILED); goto done; } err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); if (err < 0) { - err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_FAILED); goto done; } - err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0, NULL, 0); done: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int load_long_term_keys(struct sock *sk, u16 index, +static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, void *cp_data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_load_long_term_keys *cp = cp_data; u16 key_count, expected_len; int i; if (len < sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, EINVAL); key_count = get_unaligned_le16(&cp->key_count); @@ -2918,16 +2689,11 @@ static int load_long_term_keys(struct sock *sk, u16 index, if (expected_len != len) { BT_ERR("load_keys: expected %u bytes, got %u bytes", len, expected_len); - return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, EINVAL); } - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, - ENODEV); - - BT_DBG("hci%u key_count %u", index, key_count); + BT_DBG("%s key_count %u", hdev->name, key_count); hci_dev_lock(hdev); @@ -2948,7 +2714,6 @@ static int load_long_term_keys(struct sock *sk, u16 index, } hci_dev_unlock(hdev); - hci_dev_put(hdev); return 0; } @@ -2959,6 +2724,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) u8 *cp; struct mgmt_hdr *hdr; u16 opcode, index, len; + struct hci_dev *hdev = NULL; int err; BT_DBG("got %zu bytes", msglen); @@ -2985,6 +2751,21 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } + if (opcode < MGMT_OP_READ_INFO) { + if (index != MGMT_INDEX_NONE) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; + } + } else { + hdev = hci_dev_get(index); + if (!hdev) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; + } + } + cp = buf + sizeof(*hdr); switch (opcode) { @@ -2998,112 +2779,112 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = read_index_list(sk); break; case MGMT_OP_READ_INFO: - err = read_controller_info(sk, index); + err = read_controller_info(sk, hdev); break; case MGMT_OP_SET_POWERED: - err = set_powered(sk, index, cp, len); + err = set_powered(sk, hdev, cp, len); break; case MGMT_OP_SET_DISCOVERABLE: - err = set_discoverable(sk, index, cp, len); + err = set_discoverable(sk, hdev, cp, len); break; case MGMT_OP_SET_CONNECTABLE: - err = set_connectable(sk, index, cp, len); + err = set_connectable(sk, hdev, cp, len); break; case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, index, cp, len); + err = set_fast_connectable(sk, hdev, cp, len); break; case MGMT_OP_SET_PAIRABLE: - err = set_pairable(sk, index, cp, len); + err = set_pairable(sk, hdev, cp, len); break; case MGMT_OP_SET_LINK_SECURITY: - err = set_link_security(sk, index, cp, len); + err = set_link_security(sk, hdev, cp, len); break; case MGMT_OP_SET_SSP: - err = set_ssp(sk, index, cp, len); + err = set_ssp(sk, hdev, cp, len); break; case MGMT_OP_SET_HS: - err = set_hs(sk, index, cp, len); + err = set_hs(sk, hdev, cp, len); break; case MGMT_OP_SET_LE: - err = set_le(sk, index, cp, len); + err = set_le(sk, hdev, cp, len); break; case MGMT_OP_ADD_UUID: - err = add_uuid(sk, index, cp, len); + err = add_uuid(sk, hdev, cp, len); break; case MGMT_OP_REMOVE_UUID: - err = remove_uuid(sk, index, cp, len); + err = remove_uuid(sk, hdev, cp, len); break; case MGMT_OP_SET_DEV_CLASS: - err = set_dev_class(sk, index, cp, len); + err = set_dev_class(sk, hdev, cp, len); break; case MGMT_OP_LOAD_LINK_KEYS: - err = load_link_keys(sk, index, cp, len); + err = load_link_keys(sk, hdev, cp, len); break; case MGMT_OP_DISCONNECT: - err = disconnect(sk, index, cp, len); + err = disconnect(sk, hdev, cp, len); break; case MGMT_OP_GET_CONNECTIONS: - err = get_connections(sk, index); + err = get_connections(sk, hdev); break; case MGMT_OP_PIN_CODE_REPLY: - err = pin_code_reply(sk, index, cp, len); + err = pin_code_reply(sk, hdev, cp, len); break; case MGMT_OP_PIN_CODE_NEG_REPLY: - err = pin_code_neg_reply(sk, index, cp, len); + err = pin_code_neg_reply(sk, hdev, cp, len); break; case MGMT_OP_SET_IO_CAPABILITY: - err = set_io_capability(sk, index, cp, len); + err = set_io_capability(sk, hdev, cp, len); break; case MGMT_OP_PAIR_DEVICE: - err = pair_device(sk, index, cp, len); + err = pair_device(sk, hdev, cp, len); break; case MGMT_OP_CANCEL_PAIR_DEVICE: - err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); + err = cancel_pair_device(sk, hdev, buf + sizeof(*hdr), len); break; case MGMT_OP_UNPAIR_DEVICE: - err = unpair_device(sk, index, cp, len); + err = unpair_device(sk, hdev, cp, len); break; case MGMT_OP_USER_CONFIRM_REPLY: - err = user_confirm_reply(sk, index, cp, len); + err = user_confirm_reply(sk, hdev, cp, len); break; case MGMT_OP_USER_CONFIRM_NEG_REPLY: - err = user_confirm_neg_reply(sk, index, cp, len); + err = user_confirm_neg_reply(sk, hdev, cp, len); break; case MGMT_OP_USER_PASSKEY_REPLY: - err = user_passkey_reply(sk, index, cp, len); + err = user_passkey_reply(sk, hdev, cp, len); break; case MGMT_OP_USER_PASSKEY_NEG_REPLY: - err = user_passkey_neg_reply(sk, index, cp, len); + err = user_passkey_neg_reply(sk, hdev, cp, len); break; case MGMT_OP_SET_LOCAL_NAME: - err = set_local_name(sk, index, cp, len); + err = set_local_name(sk, hdev, cp, len); break; case MGMT_OP_READ_LOCAL_OOB_DATA: - err = read_local_oob_data(sk, index); + err = read_local_oob_data(sk, hdev); break; case MGMT_OP_ADD_REMOTE_OOB_DATA: - err = add_remote_oob_data(sk, index, cp, len); + err = add_remote_oob_data(sk, hdev, cp, len); break; case MGMT_OP_REMOVE_REMOTE_OOB_DATA: - err = remove_remote_oob_data(sk, index, cp, len); + err = remove_remote_oob_data(sk, hdev, cp, len); break; case MGMT_OP_START_DISCOVERY: - err = start_discovery(sk, index, cp, len); + err = start_discovery(sk, hdev, cp, len); break; case MGMT_OP_STOP_DISCOVERY: - err = stop_discovery(sk, index, cp, len); + err = stop_discovery(sk, hdev, cp, len); break; case MGMT_OP_CONFIRM_NAME: - err = confirm_name(sk, index, cp, len); + err = confirm_name(sk, hdev, cp, len); break; case MGMT_OP_BLOCK_DEVICE: - err = block_device(sk, index, cp, len); + err = block_device(sk, hdev, cp, len); break; case MGMT_OP_UNBLOCK_DEVICE: - err = unblock_device(sk, index, cp, len); + err = unblock_device(sk, hdev, cp, len); break; case MGMT_OP_LOAD_LONG_TERM_KEYS: - err = load_long_term_keys(sk, index, cp, len); + err = load_long_term_keys(sk, hdev, cp, len); break; default: BT_DBG("Unknown op %u", opcode); @@ -3118,6 +2899,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = msglen; done: + if (hdev) + hci_dev_put(hdev); + kfree(buf); return err; } -- cgit v1.2.3-70-g09d2 From 6a919082e9b82a0de20f1248a33f3b3f005cebaf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 06:17:26 +0200 Subject: Bluetooth: mgmt: Initialize HCI_MGMT flag for any command The read_controller_info is typically the first command that user space sends when taking a controller into use. This is also the reason why this command has been used as the trigger to set the HCI_MGMT flag. However, when not running the user-space daemon and using command line tools it is possible that read_controller_info is not the first controller specific command. This patch moves the HCI_MGMT initialization to a generic place where it will be set for whatever happens to be the first mgmt command targetting a specific controller. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cc9fb64def9..cf8c8403571 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -610,8 +610,11 @@ static void service_cache_off(struct work_struct *work) hci_dev_unlock(hdev); } -static void mgmt_init_hdev(struct hci_dev *hdev) +static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) { + if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) + return; + if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) { INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); @@ -632,9 +635,6 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev) hci_dev_lock(hdev); - if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) - mgmt_init_hdev(hdev); - memset(&rp, 0, sizeof(rp)); bacpy(&rp.bdaddr, &hdev->bdaddr); @@ -2764,6 +2764,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) MGMT_STATUS_INVALID_PARAMS); goto done; } + + mgmt_init_hdev(sk, hdev); } cp = buf + sizeof(*hdr); -- cgit v1.2.3-70-g09d2 From 0f4e68cf6e70fc219f219799c799a8a3e3c13100 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 17:18:30 +0200 Subject: Bluetooth: mgmt: Move command handlers into a table By moving the command handlers into a table (the index being equal to the opcode) the lookup is made a bit more efficient. Having a struct to describe each handler also paves the way to add more meta-data for each handler, e.g. the minimum message size for the command and allow handling of common tasks like this in a centralized place. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 219 +++++++++++++++++++-------------------------------- 1 file changed, 79 insertions(+), 140 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cf8c8403571..88a342a1259 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -267,7 +267,8 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, return err; } -static int read_version(struct sock *sk) +static int read_version(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_version rp; @@ -280,7 +281,8 @@ static int read_version(struct sock *sk) sizeof(rp)); } -static int read_commands(struct sock *sk) +static int read_commands(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_commands *rp; u16 num_commands = ARRAY_SIZE(mgmt_commands); @@ -313,7 +315,8 @@ static int read_commands(struct sock *sk) return err; } -static int read_index_list(struct sock *sk) +static int read_index_list(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_index_list *rp; struct list_head *p; @@ -627,7 +630,8 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) } } -static int read_controller_info(struct sock *sk, struct hci_dev *hdev) +static int read_controller_info(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_info rp; @@ -1689,7 +1693,8 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) } } -static int get_connections(struct sock *sk, struct hci_dev *hdev) +static int get_connections(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_get_connections *rp; struct hci_conn *c; @@ -2015,9 +2020,9 @@ unlock: } static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, - unsigned char *data, u16 len) + void *data, u16 len) { - struct mgmt_addr_info *addr = (void *) data; + struct mgmt_addr_info *addr = data; struct pending_cmd *cmd; struct hci_conn *conn; int err; @@ -2240,7 +2245,8 @@ failed: return err; } -static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev) +static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct pending_cmd *cmd; int err; @@ -2718,6 +2724,53 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, return 0; } +struct mgmt_handler { + int (*func) (struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len); +} mgmt_handlers[] = { + { NULL }, /* 0x0000 (no command) */ + { read_version, }, + { read_commands, }, + { read_index_list, }, + { read_controller_info, }, + { set_powered, }, + { set_discoverable, }, + { set_connectable, }, + { set_fast_connectable, }, + { set_pairable, }, + { set_link_security, }, + { set_ssp, }, + { set_hs, }, + { set_le, }, + { set_dev_class, }, + { set_local_name, }, + { add_uuid, }, + { remove_uuid, }, + { load_link_keys, }, + { load_long_term_keys, }, + { disconnect, }, + { get_connections, }, + { pin_code_reply, }, + { pin_code_neg_reply, }, + { set_io_capability, }, + { pair_device, }, + { cancel_pair_device, }, + { unpair_device, }, + { user_confirm_reply, }, + { user_confirm_neg_reply, }, + { user_passkey_reply, }, + { user_passkey_neg_reply, }, + { read_local_oob_data, }, + { add_remote_oob_data, }, + { remove_remote_oob_data, }, + { start_discovery, }, + { stop_discovery, }, + { confirm_name, }, + { block_device, }, + { unblock_device, }, +}; + + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { void *buf; @@ -2751,150 +2804,36 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } - if (opcode < MGMT_OP_READ_INFO) { - if (index != MGMT_INDEX_NONE) { - err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); - goto done; - } - } else { + if (index != MGMT_INDEX_NONE) { hdev = hci_dev_get(index); if (!hdev) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto done; } - - mgmt_init_hdev(sk, hdev); } - cp = buf + sizeof(*hdr); - - switch (opcode) { - case MGMT_OP_READ_VERSION: - err = read_version(sk); - break; - case MGMT_OP_READ_COMMANDS: - err = read_commands(sk); - break; - case MGMT_OP_READ_INDEX_LIST: - err = read_index_list(sk); - break; - case MGMT_OP_READ_INFO: - err = read_controller_info(sk, hdev); - break; - case MGMT_OP_SET_POWERED: - err = set_powered(sk, hdev, cp, len); - break; - case MGMT_OP_SET_DISCOVERABLE: - err = set_discoverable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_CONNECTABLE: - err = set_connectable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_PAIRABLE: - err = set_pairable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_LINK_SECURITY: - err = set_link_security(sk, hdev, cp, len); - break; - case MGMT_OP_SET_SSP: - err = set_ssp(sk, hdev, cp, len); - break; - case MGMT_OP_SET_HS: - err = set_hs(sk, hdev, cp, len); - break; - case MGMT_OP_SET_LE: - err = set_le(sk, hdev, cp, len); - break; - case MGMT_OP_ADD_UUID: - err = add_uuid(sk, hdev, cp, len); - break; - case MGMT_OP_REMOVE_UUID: - err = remove_uuid(sk, hdev, cp, len); - break; - case MGMT_OP_SET_DEV_CLASS: - err = set_dev_class(sk, hdev, cp, len); - break; - case MGMT_OP_LOAD_LINK_KEYS: - err = load_link_keys(sk, hdev, cp, len); - break; - case MGMT_OP_DISCONNECT: - err = disconnect(sk, hdev, cp, len); - break; - case MGMT_OP_GET_CONNECTIONS: - err = get_connections(sk, hdev); - break; - case MGMT_OP_PIN_CODE_REPLY: - err = pin_code_reply(sk, hdev, cp, len); - break; - case MGMT_OP_PIN_CODE_NEG_REPLY: - err = pin_code_neg_reply(sk, hdev, cp, len); - break; - case MGMT_OP_SET_IO_CAPABILITY: - err = set_io_capability(sk, hdev, cp, len); - break; - case MGMT_OP_PAIR_DEVICE: - err = pair_device(sk, hdev, cp, len); - break; - case MGMT_OP_CANCEL_PAIR_DEVICE: - err = cancel_pair_device(sk, hdev, buf + sizeof(*hdr), len); - break; - case MGMT_OP_UNPAIR_DEVICE: - err = unpair_device(sk, hdev, cp, len); - break; - case MGMT_OP_USER_CONFIRM_REPLY: - err = user_confirm_reply(sk, hdev, cp, len); - break; - case MGMT_OP_USER_CONFIRM_NEG_REPLY: - err = user_confirm_neg_reply(sk, hdev, cp, len); - break; - case MGMT_OP_USER_PASSKEY_REPLY: - err = user_passkey_reply(sk, hdev, cp, len); - break; - case MGMT_OP_USER_PASSKEY_NEG_REPLY: - err = user_passkey_neg_reply(sk, hdev, cp, len); - break; - case MGMT_OP_SET_LOCAL_NAME: - err = set_local_name(sk, hdev, cp, len); - break; - case MGMT_OP_READ_LOCAL_OOB_DATA: - err = read_local_oob_data(sk, hdev); - break; - case MGMT_OP_ADD_REMOTE_OOB_DATA: - err = add_remote_oob_data(sk, hdev, cp, len); - break; - case MGMT_OP_REMOVE_REMOTE_OOB_DATA: - err = remove_remote_oob_data(sk, hdev, cp, len); - break; - case MGMT_OP_START_DISCOVERY: - err = start_discovery(sk, hdev, cp, len); - break; - case MGMT_OP_STOP_DISCOVERY: - err = stop_discovery(sk, hdev, cp, len); - break; - case MGMT_OP_CONFIRM_NAME: - err = confirm_name(sk, hdev, cp, len); - break; - case MGMT_OP_BLOCK_DEVICE: - err = block_device(sk, hdev, cp, len); - break; - case MGMT_OP_UNBLOCK_DEVICE: - err = unblock_device(sk, hdev, cp, len); - break; - case MGMT_OP_LOAD_LONG_TERM_KEYS: - err = load_long_term_keys(sk, hdev, cp, len); - break; - default: + if (opcode >= ARRAY_SIZE(mgmt_handlers) || + mgmt_handlers[opcode].func == NULL) { BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, MGMT_STATUS_UNKNOWN_COMMAND); - break; + goto done; + } + + if ((hdev && opcode < MGMT_OP_READ_INFO) || + (!hdev && opcode >= MGMT_OP_READ_INFO)) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; } + if (hdev) + mgmt_init_hdev(sk, hdev); + + cp = buf + sizeof(*hdr); + + err = mgmt_handlers[opcode].func(sk, hdev, cp, len); if (err < 0) goto done; -- cgit v1.2.3-70-g09d2 From be22b54e8711734f4cb93ac31723b955fe9dbbe0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 1 Mar 2012 22:24:41 +0200 Subject: Bluetooth: mgmt: Centralize message length checks This patch moves the command length information into the command handler table allowing the removal of length checks from the handler functions and doing the check in a single place before calling the handler function. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 220 ++++++++++++--------------------------------------- 1 file changed, 52 insertions(+), 168 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 88a342a1259..7bd7d57a877 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -751,10 +751,6 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { @@ -846,10 +842,6 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_INVALID_PARAMS); - timeout = get_unaligned_le16(&cp->timeout); if (!cp->val && timeout > 0) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, @@ -945,10 +937,6 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1019,10 +1007,6 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (cp->val) @@ -1051,10 +1035,6 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1115,10 +1095,6 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { @@ -1181,10 +1157,6 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, - MGMT_STATUS_INVALID_PARAMS); - if (!enable_hs) return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, MGMT_STATUS_NOT_SUPPORTED); @@ -1207,10 +1179,6 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!enable_le || !(hdev->features[4] & LMP_LE)) { @@ -1280,10 +1248,6 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { @@ -1353,10 +1317,6 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { @@ -1430,10 +1390,6 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { @@ -1486,10 +1442,6 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 key_count, expected_len; int i; - if (len < sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); - key_count = get_unaligned_le16(&cp->key_count); expected_len = sizeof(*cp) + key_count * @@ -1551,10 +1503,6 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_conn *conn; int err; - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); memset(&rp, 0, sizeof(rp)); @@ -1627,10 +1575,6 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { @@ -1781,10 +1725,6 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1842,10 +1782,6 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1868,10 +1804,6 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; @@ -1949,10 +1881,6 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2029,10 +1957,6 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*addr)) - return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2153,10 +2077,6 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY, - MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_CONFIRM_NEG_REPLY, HCI_OP_USER_CONFIRM_NEG_REPLY, 0); @@ -2169,10 +2089,6 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY, - EINVAL); - return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_REPLY, HCI_OP_USER_PASSKEY_REPLY, @@ -2186,10 +2102,6 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY, - EINVAL); - return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_NEG_REPLY, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); @@ -2205,10 +2117,6 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); memcpy(hdev->short_name, mgmt_cp->short_name, @@ -2297,10 +2205,6 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s ", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2334,10 +2238,6 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2388,10 +2288,6 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2463,10 +2359,6 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { @@ -2529,10 +2421,6 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { @@ -2572,10 +2460,6 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2601,10 +2485,6 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2631,10 +2511,6 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - if (!hdev_is_powered(hdev)) return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_NOT_POWERED); @@ -2684,10 +2560,6 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, u16 key_count, expected_len; int i; - if (len < sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, - EINVAL); - key_count = get_unaligned_le16(&cp->key_count); expected_len = sizeof(*cp) + key_count * @@ -2727,47 +2599,49 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); + bool var_len; + size_t data_len; } mgmt_handlers[] = { { NULL }, /* 0x0000 (no command) */ - { read_version, }, - { read_commands, }, - { read_index_list, }, - { read_controller_info, }, - { set_powered, }, - { set_discoverable, }, - { set_connectable, }, - { set_fast_connectable, }, - { set_pairable, }, - { set_link_security, }, - { set_ssp, }, - { set_hs, }, - { set_le, }, - { set_dev_class, }, - { set_local_name, }, - { add_uuid, }, - { remove_uuid, }, - { load_link_keys, }, - { load_long_term_keys, }, - { disconnect, }, - { get_connections, }, - { pin_code_reply, }, - { pin_code_neg_reply, }, - { set_io_capability, }, - { pair_device, }, - { cancel_pair_device, }, - { unpair_device, }, - { user_confirm_reply, }, - { user_confirm_neg_reply, }, - { user_passkey_reply, }, - { user_passkey_neg_reply, }, - { read_local_oob_data, }, - { add_remote_oob_data, }, - { remove_remote_oob_data, }, - { start_discovery, }, - { stop_discovery, }, - { confirm_name, }, - { block_device, }, - { unblock_device, }, + { read_version, false, MGMT_READ_VERSION_SIZE }, + { read_commands, false, MGMT_READ_COMMANDS_SIZE }, + { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE }, + { read_controller_info, false, MGMT_READ_INFO_SIZE }, + { set_powered, false, MGMT_SETTING_SIZE }, + { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE }, + { set_connectable, false, MGMT_SETTING_SIZE }, + { set_fast_connectable, false, MGMT_SETTING_SIZE }, + { set_pairable, false, MGMT_SETTING_SIZE }, + { set_link_security, false, MGMT_SETTING_SIZE }, + { set_ssp, false, MGMT_SETTING_SIZE }, + { set_hs, false, MGMT_SETTING_SIZE }, + { set_le, false, MGMT_SETTING_SIZE }, + { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE }, + { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE }, + { add_uuid, false, MGMT_ADD_UUID_SIZE }, + { remove_uuid, false, MGMT_REMOVE_UUID_SIZE }, + { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE }, + { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE }, + { disconnect, false, MGMT_DISCONNECT_SIZE }, + { get_connections, false, MGMT_GET_CONNECTIONS_SIZE }, + { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE }, + { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE }, + { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE }, + { pair_device, false, MGMT_PAIR_DEVICE_SIZE }, + { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE }, + { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE }, + { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE }, + { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE }, + { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE }, + { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE }, + { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE }, + { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE }, + { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE }, + { start_discovery, false, MGMT_START_DISCOVERY_SIZE }, + { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE }, + { confirm_name, false, MGMT_CONFIRM_NAME_SIZE }, + { block_device, false, MGMT_BLOCK_DEVICE_SIZE }, + { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE }, }; @@ -2778,6 +2652,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) struct mgmt_hdr *hdr; u16 opcode, index, len; struct hci_dev *hdev = NULL; + struct mgmt_handler *handler; int err; BT_DBG("got %zu bytes", msglen); @@ -2828,12 +2703,21 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } + handler = &mgmt_handlers[opcode]; + + if ((handler->var_len && len < handler->data_len) || + (!handler->var_len && len != handler->data_len)) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; + } + if (hdev) mgmt_init_hdev(sk, hdev); cp = buf + sizeof(*hdr); - err = mgmt_handlers[opcode].func(sk, hdev, cp, len); + err = handler->func(sk, hdev, cp, len); if (err < 0) goto done; -- cgit v1.2.3-70-g09d2 From ba13ccd9b911e043c0f11e60cbb72bd4de194205 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 1 Mar 2012 14:25:33 -0800 Subject: Bluetooth: Update L2CAP timeout constants to use msecs_to_jiffies The L2CAP timeout constants are always used in form of jiffies. So just include the conversion from msecs in the define itself. This has the advantage of making the code where the timeout is used more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 10 +++++----- net/bluetooth/l2cap_core.c | 18 ++++++------------ net/bluetooth/l2cap_sock.c | 2 +- 3 files changed, 12 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 3732a4849f2..e4669d0230c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -45,11 +45,11 @@ #define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF #define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF -#define L2CAP_DISC_TIMEOUT (100) -#define L2CAP_DISC_REJ_TIMEOUT (5000) /* 5 seconds */ -#define L2CAP_ENC_TIMEOUT (5000) /* 5 seconds */ -#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ -#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ +#define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100) +#define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000) +#define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000) +#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000) +#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000) /* L2CAP socket address */ struct sockaddr_l2 { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bc8d558b01f..0b1aabff864 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -700,8 +700,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - schedule_delayed_work(&conn->info_timer, - msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ, sizeof(req), &req); @@ -2741,8 +2740,7 @@ sendresp: conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - schedule_delayed_work(&conn->info_timer, - msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ, sizeof(info), &info); @@ -3028,8 +3026,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: l2cap_chan_set_err(chan, ECONNRESET); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); + __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -4539,8 +4536,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __clear_chan_timer(chan); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_ENC_TIMEOUT)); + __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); } else { @@ -4598,8 +4594,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) l2cap_send_conn_req(chan); } else { __clear_chan_timer(chan); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); } } else if (chan->state == BT_CONNECT2) { struct sock *sk = chan->sk; @@ -4622,8 +4617,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } } else { __l2cap_state_change(chan, BT_DISCONN); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); res = L2CAP_CR_SEC_BLOCK; stat = L2CAP_CS_NO_INFO; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 52c94c76577..3da56c5c1fc 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1039,7 +1039,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p INIT_LIST_HEAD(&bt_sk(sk)->accept_q); sk->sk_destruct = l2cap_sock_destruct; - sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); + sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; sock_reset_flag(sk, SOCK_ZAPPED); -- cgit v1.2.3-70-g09d2 From 17b02e625662906f370a3eb5e7495cf06ed7d4a4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 1 Mar 2012 14:32:37 -0800 Subject: Bluetooth: Update MGMT and SMP timeout constants to use msecs_to_jiffies The MGMT and SMP timeout constants are always used in form of jiffies. So just include the conversion from msecs in the define itself. This has the advantage of making the code where the timeout is used more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 5 ++--- net/bluetooth/smp.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7bd7d57a877..40b3da3d5e6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -116,7 +116,7 @@ static const u16 mgmt_events[] = { #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ #define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */ -#define SERVICE_CACHE_TIMEOUT (5 * 1000) +#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) #define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) @@ -1298,8 +1298,7 @@ static bool enable_service_cache(struct hci_dev *hdev) return false; if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { - schedule_delayed_work(&hdev->service_cache, - msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT); return true; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f6a6d8be305..75937d73d8a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -29,7 +29,7 @@ #include #include -#define SMP_TIMEOUT 30000 /* 30 seconds */ +#define SMP_TIMEOUT msecs_to_jiffies(30000) static inline void swap128(u8 src[16], u8 dst[16]) { @@ -186,8 +186,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) hci_send_acl(conn->hchan, skb, 0); cancel_delayed_work_sync(&conn->security_timer); - schedule_delayed_work(&conn->security_timer, - msecs_to_jiffies(SMP_TIMEOUT)); + schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT); } static __u8 authreq_to_seclevel(__u8 authreq) -- cgit v1.2.3-70-g09d2 From 9f8ce967caed427f78d00bb6b07d79cb040a88bd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 03:06:04 +0200 Subject: Bluetooth: Fix clearing of HCI_PENDING_CLASS flag When doing reset HCI_PENDING_CLASS is one of the flags that should be cleared (since it's used for a pending HCI command and a reset clear all pending commands). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index aee9556e103..d6c41bbfe75 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -193,7 +193,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); /* Reset all non-persistent flags */ - hdev->dev_flags &= ~(BIT(HCI_LE_SCAN)); + hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS)); hdev->discovery.state = DISCOVERY_STOPPED; } -- cgit v1.2.3-70-g09d2 From d4f68526e438dbb7d194b08499a96c733131ad72 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 03:07:07 +0200 Subject: Bluetooth: mgmt: Fix command status error code values Error codes in the command status should always be from the set of values defined for mgmt and never e.g. POSIX error codes. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 40b3da3d5e6..bd01e4a4784 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2745,7 +2745,7 @@ int mgmt_index_added(struct hci_dev *hdev) int mgmt_index_removed(struct hci_dev *hdev) { - u8 status = ENODEV; + u8 status = MGMT_STATUS_INVALID_PARAMS; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); @@ -2798,7 +2798,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) update_class(hdev); update_eir(hdev); } else { - u8 status = ENETDOWN; + u8 status = MGMT_STATUS_NOT_POWERED; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); } -- cgit v1.2.3-70-g09d2 From 5f15903279143eb640f9ba1c0e72b52fe9e9e2a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 03:13:19 +0200 Subject: Bluetooth: mgmt: Add new error code for invalid index The index is part of the command header and not its parameters so it makes sense to distinguish this from the invalid parameters error. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index d33457d657c..0ca3519e08b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -41,6 +41,7 @@ #define MGMT_STATUS_DISCONNECTED 0x0e #define MGMT_STATUS_NOT_POWERED 0x0f #define MGMT_STATUS_CANCELLED 0x10 +#define MGMT_STATUS_INVALID_INDEX 0x11 struct mgmt_hdr { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bd01e4a4784..fa9a5896427 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2682,7 +2682,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) hdev = hci_dev_get(index); if (!hdev) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_INDEX); goto done; } } @@ -2698,7 +2698,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if ((hdev && opcode < MGMT_OP_READ_INFO) || (!hdev && opcode >= MGMT_OP_READ_INFO)) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_INDEX); goto done; } @@ -2745,7 +2745,7 @@ int mgmt_index_added(struct hci_dev *hdev) int mgmt_index_removed(struct hci_dev *hdev) { - u8 status = MGMT_STATUS_INVALID_PARAMS; + u8 status = MGMT_STATUS_INVALID_INDEX; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); -- cgit v1.2.3-70-g09d2 From 2446ab6070861aba2dd9229463ffbc40016a9f33 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Mar 2012 17:00:56 -0500 Subject: SUNRPC: Use RCU to dereference the rpc_clnt.cl_xprt field A migration event will replace the rpc_xprt used by an rpc_clnt. To ensure this can be done safely, all references to cl_xprt must now use a form of rcu_dereference(). Special care is taken with rpc_peeraddr2str(), which returns a pointer to memory whose lifetime is the same as the rpc_xprt. Signed-off-by: Trond Myklebust [ cel: fix lockdep splats and layering violations ] [ cel: forward ported to 3.4 ] [ cel: remove rpc_max_reqs(), add rpc_net_ns() ] Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/callback_proc.c | 9 ++-- fs/nfs/client.c | 16 ++++-- fs/nfs/nfs4namespace.c | 2 +- fs/nfs/nfs4proc.c | 13 +++-- fs/nfs/nfs4state.c | 25 +++++++--- fs/nfs/super.c | 5 ++ include/linux/sunrpc/clnt.h | 4 +- include/linux/sunrpc/debug.h | 13 +++++ net/sunrpc/auth_gss/auth_gss.c | 4 +- net/sunrpc/clnt.c | 110 +++++++++++++++++++++++++++++++++-------- net/sunrpc/rpc_pipe.c | 3 ++ net/sunrpc/rpcb_clnt.c | 15 ++++-- net/sunrpc/stats.c | 6 ++- 13 files changed, 175 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 0e0865e3806..1bb29724362 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "nfs4_fs.h" #include "callback.h" #include "delegation.h" @@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, res->bitmap[0] = res->bitmap[1] = 0; res->status = htonl(NFS4ERR_BADHANDLE); - dprintk("NFS: GETATTR callback request from %s\n", + dprintk_rcu("NFS: GETATTR callback request from %s\n", rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); inode = nfs_delegation_find_inode(cps->clp, &args->fh); @@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ goto out; - dprintk("NFS: RECALL callback request from %s\n", + dprintk_rcu("NFS: RECALL callback request from %s\n", rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); res = htonl(NFS4ERR_BADHANDLE); @@ -533,7 +534,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy, if (!cps->clp) /* set in cb_sequence */ goto out; - dprintk("NFS: RECALL_ANY callback request from %s\n", + dprintk_rcu("NFS: RECALL_ANY callback request from %s\n", rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); status = cpu_to_be32(NFS4ERR_INVAL); @@ -568,7 +569,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, if (!cps->clp) /* set in cb_sequence */ goto out; - dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", + dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), args->crsa_target_max_slots); diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 1506adf4d4e..d038dc5916e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1284,16 +1284,18 @@ static int nfs4_init_callback(struct nfs_client *clp) int error; if (clp->rpc_ops->version == 4) { + struct rpc_xprt *xprt; + + xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); + if (nfs4_has_session(clp)) { - error = xprt_setup_backchannel( - clp->cl_rpcclient->cl_xprt, + error = xprt_setup_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); if (error < 0) return error; } - error = nfs_callback_up(clp->cl_mvops->minor_version, - clp->cl_rpcclient->cl_xprt); + error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); if (error < 0) { dprintk("%s: failed to start callback. Error = %d\n", __func__, error); @@ -1678,7 +1680,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, data->addrlen, parent_client->cl_ipaddr, data->authflavor, - parent_server->client->cl_xprt->prot, + rpc_protocol(parent_server->client), parent_server->client->cl_timeout, parent_client->cl_mvops->minor_version, parent_client->net); @@ -1905,12 +1907,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v) if (clp->cl_cons_state != NFS_CS_READY) return 0; + rcu_read_lock(); seq_printf(m, "v%u %s %s %3d %s\n", clp->rpc_ops->version, rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), atomic_read(&clp->cl_count), clp->cl_hostname); + rcu_read_unlock(); return 0; } @@ -1993,6 +1997,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) (unsigned long long) server->fsid.major, (unsigned long long) server->fsid.minor); + rcu_read_lock(); seq_printf(m, "v%u %s %s %-7s %-17s %s\n", clp->rpc_ops->version, rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), @@ -2000,6 +2005,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) dev, fsid, nfs_server_fscache_state(server)); + rcu_read_unlock(); return 0; } diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 667ea7406fd..9c8eca315f4 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -96,8 +96,8 @@ static int nfs4_validate_fspath(struct dentry *dentry, static size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr *sa, size_t salen, struct nfs_server *server) { + struct net *net = rpc_net_ns(server->client); ssize_t ret; - struct net *net = server->client->cl_xprt->xprt_net; ret = rpc_pton(net, string, len, sa, salen); if (ret == 0) { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6c8e170e2e6..671510cc14c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3833,6 +3833,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, *p = htonl((u32)clp->cl_boot_time.tv_nsec); for(;;) { + rcu_read_lock(); setclientid.sc_name_len = scnprintf(setclientid.sc_name, sizeof(setclientid.sc_name), "%s/%s %s %s %u", clp->cl_ipaddr, @@ -3849,6 +3850,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, sizeof(setclientid.sc_uaddr), "%s.%u.%u", clp->cl_ipaddr, port >> 8, port & 255); + rcu_read_unlock(); status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); if (status != -NFS4ERR_CLID_INUSE) @@ -5244,11 +5246,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) void nfs4_destroy_session(struct nfs4_session *session) { + struct rpc_xprt *xprt; + nfs4_proc_destroy_session(session); + + rcu_read_lock(); + xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); + rcu_read_unlock(); dprintk("%s Destroy backchannel for xprt %p\n", - __func__, session->clp->cl_rpcclient->cl_xprt); - xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, - NFS41_BC_MIN_CALLBACKS); + __func__, xprt); + xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); nfs4_destroy_slot_tables(session); kfree(session); } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index c1111a37dc1..bae959e294c 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1037,19 +1037,28 @@ static void nfs4_clear_state_manager_bit(struct nfs_client *clp) void nfs4_schedule_state_manager(struct nfs_client *clp) { struct task_struct *task; + char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1]; if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) return; __module_get(THIS_MODULE); atomic_inc(&clp->cl_count); - task = kthread_run(nfs4_run_state_manager, clp, "%s-manager", - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR)); - if (!IS_ERR(task)) - return; - nfs4_clear_state_manager_bit(clp); - nfs_put_client(clp); - module_put(THIS_MODULE); + + /* The rcu_read_lock() is not strictly necessary, as the state + * manager is the only thread that ever changes the rpc_xprt + * after it's initialized. At this point, we're single threaded. */ + rcu_read_lock(); + snprintf(buf, sizeof(buf), "%s-manager", + rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); + rcu_read_unlock(); + task = kthread_run(nfs4_run_state_manager, clp, buf); + if (IS_ERR(task)) { + printk(KERN_ERR "%s: kthread_run: %ld\n", + __func__, PTR_ERR(task)); + nfs4_clear_state_manager_bit(clp); + nfs_put_client(clp); + module_put(THIS_MODULE); + } } /* diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f4ccdae6a0c..7002be11d99 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -701,8 +702,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, else seq_puts(m, nfs_infop->nostr); } + rcu_read_lock(); seq_printf(m, ",proto=%s", rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); + rcu_read_unlock(); if (version == 4) { if (nfss->port != NFS_PORT) seq_printf(m, ",port=%u", nfss->port); @@ -751,9 +754,11 @@ static int nfs_show_options(struct seq_file *m, struct dentry *root) nfs_show_mount_options(m, nfss, 0); + rcu_read_lock(); seq_printf(m, ",addr=%s", rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, RPC_DISPLAY_ADDR)); + rcu_read_unlock(); return 0; } diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index a4c62e95c72..e3d12b4a031 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -35,7 +35,7 @@ struct rpc_clnt { struct list_head cl_clients; /* Global list of clients */ struct list_head cl_tasks; /* List of tasks */ spinlock_t cl_lock; /* spinlock */ - struct rpc_xprt * cl_xprt; /* transport */ + struct rpc_xprt __rcu * cl_xprt; /* transport */ struct rpc_procinfo * cl_procinfo; /* procedure info */ u32 cl_prog, /* RPC program number */ cl_vers, /* RPC version number */ @@ -156,6 +156,8 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int rpc_restart_call_prepare(struct rpc_task *); int rpc_restart_call(struct rpc_task *); void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); +int rpc_protocol(struct rpc_clnt *); +struct net * rpc_net_ns(struct rpc_clnt *); size_t rpc_max_payload(struct rpc_clnt *); void rpc_force_rebind(struct rpc_clnt *); size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index b506936f4ce..6cb2517bcf7 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -50,19 +50,32 @@ extern unsigned int nlm_debug; #endif #define dprintk(args...) dfprintk(FACILITY, ## args) +#define dprintk_rcu(args...) dfprintk_rcu(FACILITY, ## args) #undef ifdebug #ifdef RPC_DEBUG # define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) + # define dfprintk(fac, args...) \ do { \ ifdebug(fac) \ printk(KERN_DEFAULT args); \ } while (0) + +# define dfprintk_rcu(fac, args...) \ + do { \ + ifdebug(fac) { \ + rcu_read_lock(); \ + printk(KERN_DEFAULT args); \ + rcu_read_unlock(); \ + } \ + } while (0) + # define RPC_IFDEBUG(x) x #else # define ifdebug(fac) if (0) # define dfprintk(fac, args...) do ; while (0) +# define dfprintk_rcu(fac, args...) do ; while (0) # define RPC_IFDEBUG(x) #endif diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index cb2e5645274..d3ad81f8da5 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -799,7 +799,7 @@ err_unlink_pipe_1: static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, struct rpc_auth *auth) { - struct net *net = clnt->cl_xprt->xprt_net; + struct net *net = rpc_net_ns(clnt); struct super_block *sb; sb = rpc_get_sb_net(net); @@ -813,7 +813,7 @@ static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, struct rpc_auth *auth) { - struct net *net = clnt->cl_xprt->xprt_net; + struct net *net = rpc_net_ns(clnt); struct super_block *sb; int err = 0; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 25c3da53fb6..7783fc0e726 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -81,7 +82,8 @@ static int rpc_ping(struct rpc_clnt *clnt); static void rpc_register_client(struct rpc_clnt *clnt) { - struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); + struct net *net = rpc_net_ns(clnt); + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); spin_lock(&sn->rpc_client_lock); list_add(&clnt->cl_clients, &sn->all_clients); @@ -90,7 +92,8 @@ static void rpc_register_client(struct rpc_clnt *clnt) static void rpc_unregister_client(struct rpc_clnt *clnt) { - struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); + struct net *net = rpc_net_ns(clnt); + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); spin_lock(&sn->rpc_client_lock); list_del(&clnt->cl_clients); @@ -109,12 +112,13 @@ static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) { + struct net *net = rpc_net_ns(clnt); struct super_block *pipefs_sb; - pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); + pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { __rpc_clnt_remove_pipedir(clnt); - rpc_put_sb_net(clnt->cl_xprt->xprt_net); + rpc_put_sb_net(net); } } @@ -155,17 +159,18 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, static int rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) { + struct net *net = rpc_net_ns(clnt); struct super_block *pipefs_sb; struct dentry *dentry; clnt->cl_dentry = NULL; if (dir_name == NULL) return 0; - pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); + pipefs_sb = rpc_get_sb_net(net); if (!pipefs_sb) return 0; dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); - rpc_put_sb_net(clnt->cl_xprt->xprt_net); + rpc_put_sb_net(net); if (IS_ERR(dentry)) return PTR_ERR(dentry); clnt->cl_dentry = dentry; @@ -295,7 +300,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru if (clnt->cl_server == NULL) goto out_no_server; - clnt->cl_xprt = xprt; + rcu_assign_pointer(clnt->cl_xprt, xprt); clnt->cl_procinfo = version->procs; clnt->cl_maxproc = version->nrprocs; clnt->cl_protname = program->name; @@ -310,7 +315,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru INIT_LIST_HEAD(&clnt->cl_tasks); spin_lock_init(&clnt->cl_lock); - if (!xprt_bound(clnt->cl_xprt)) + if (!xprt_bound(xprt)) clnt->cl_autobind = 1; clnt->cl_timeout = xprt->timeout; @@ -477,6 +482,7 @@ struct rpc_clnt * rpc_clone_client(struct rpc_clnt *clnt) { struct rpc_clnt *new; + struct rpc_xprt *xprt; int err = -ENOMEM; new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); @@ -499,18 +505,25 @@ rpc_clone_client(struct rpc_clnt *clnt) if (new->cl_principal == NULL) goto out_no_principal; } + rcu_read_lock(); + xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); + rcu_read_unlock(); + if (xprt == NULL) + goto out_no_transport; + rcu_assign_pointer(new->cl_xprt, xprt); atomic_set(&new->cl_count, 1); err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); if (err != 0) goto out_no_path; if (new->cl_auth) atomic_inc(&new->cl_auth->au_count); - xprt_get(clnt->cl_xprt); atomic_inc(&clnt->cl_count); rpc_register_client(new); rpciod_up(); return new; out_no_path: + xprt_put(xprt); +out_no_transport: kfree(new->cl_principal); out_no_principal: rpc_free_iostats(new->cl_metrics); @@ -590,7 +603,7 @@ rpc_free_client(struct rpc_clnt *clnt) rpc_free_iostats(clnt->cl_metrics); kfree(clnt->cl_principal); clnt->cl_metrics = NULL; - xprt_put(clnt->cl_xprt); + xprt_put(rcu_dereference_raw(clnt->cl_xprt)); rpciod_down(); kfree(clnt); } @@ -879,13 +892,18 @@ EXPORT_SYMBOL_GPL(rpc_call_start); size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize) { size_t bytes; - struct rpc_xprt *xprt = clnt->cl_xprt; + struct rpc_xprt *xprt; + + rcu_read_lock(); + xprt = rcu_dereference(clnt->cl_xprt); - bytes = sizeof(xprt->addr); + bytes = xprt->addrlen; if (bytes > bufsize) bytes = bufsize; - memcpy(buf, &clnt->cl_xprt->addr, bytes); - return xprt->addrlen; + memcpy(buf, &xprt->addr, bytes); + rcu_read_unlock(); + + return bytes; } EXPORT_SYMBOL_GPL(rpc_peeraddr); @@ -894,11 +912,16 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr); * @clnt: RPC client structure * @format: address format * + * NB: the lifetime of the memory referenced by the returned pointer is + * the same as the rpc_xprt itself. As long as the caller uses this + * pointer, it must hold the RCU read lock. */ const char *rpc_peeraddr2str(struct rpc_clnt *clnt, enum rpc_display_format_t format) { - struct rpc_xprt *xprt = clnt->cl_xprt; + struct rpc_xprt *xprt; + + xprt = rcu_dereference(clnt->cl_xprt); if (xprt->address_strings[format] != NULL) return xprt->address_strings[format]; @@ -910,14 +933,51 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr2str); void rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) { - struct rpc_xprt *xprt = clnt->cl_xprt; + struct rpc_xprt *xprt; + + rcu_read_lock(); + xprt = rcu_dereference(clnt->cl_xprt); if (xprt->ops->set_buffer_size) xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(rpc_setbufsize); -/* - * Return size of largest payload RPC client can support, in bytes +/** + * rpc_protocol - Get transport protocol number for an RPC client + * @clnt: RPC client to query + * + */ +int rpc_protocol(struct rpc_clnt *clnt) +{ + int protocol; + + rcu_read_lock(); + protocol = rcu_dereference(clnt->cl_xprt)->prot; + rcu_read_unlock(); + return protocol; +} +EXPORT_SYMBOL_GPL(rpc_protocol); + +/** + * rpc_net_ns - Get the network namespace for this RPC client + * @clnt: RPC client to query + * + */ +struct net *rpc_net_ns(struct rpc_clnt *clnt) +{ + struct net *ret; + + rcu_read_lock(); + ret = rcu_dereference(clnt->cl_xprt)->xprt_net; + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(rpc_net_ns); + +/** + * rpc_max_payload - Get maximum payload size for a transport, in bytes + * @clnt: RPC client to query * * For stream transports, this is one RPC record fragment (see RFC * 1831), as we don't support multi-record requests yet. For datagram @@ -926,7 +986,12 @@ EXPORT_SYMBOL_GPL(rpc_setbufsize); */ size_t rpc_max_payload(struct rpc_clnt *clnt) { - return clnt->cl_xprt->max_payload; + size_t ret; + + rcu_read_lock(); + ret = rcu_dereference(clnt->cl_xprt)->max_payload; + rcu_read_unlock(); + return ret; } EXPORT_SYMBOL_GPL(rpc_max_payload); @@ -937,8 +1002,11 @@ EXPORT_SYMBOL_GPL(rpc_max_payload); */ void rpc_force_rebind(struct rpc_clnt *clnt) { - if (clnt->cl_autobind) - xprt_clear_bound(clnt->cl_xprt); + if (clnt->cl_autobind) { + rcu_read_lock(); + xprt_clear_bound(rcu_dereference(clnt->cl_xprt)); + rcu_read_unlock(); + } } EXPORT_SYMBOL_GPL(rpc_force_rebind); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index ac9ee159073..3d30943ed6d 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -402,12 +403,14 @@ rpc_show_info(struct seq_file *m, void *v) { struct rpc_clnt *clnt = m->private; + rcu_read_lock(); seq_printf(m, "RPC server: %s\n", clnt->cl_server); seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, clnt->cl_prog, clnt->cl_vers); seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); + rcu_read_unlock(); return 0; } diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index b1f08bd6788..4f8af63798a 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -620,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) { struct rpc_clnt *parent = clnt->cl_parent; + struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt); while (parent != clnt) { - if (parent->cl_xprt != clnt->cl_xprt) + if (rcu_dereference(parent->cl_xprt) != xprt) break; if (clnt->cl_autobind) break; @@ -653,8 +654,12 @@ void rpcb_getport_async(struct rpc_task *task) size_t salen; int status; - clnt = rpcb_find_transport_owner(task->tk_client); - xprt = clnt->cl_xprt; + rcu_read_lock(); + do { + clnt = rpcb_find_transport_owner(task->tk_client); + xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); + } while (xprt == NULL); + rcu_read_unlock(); dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", task->tk_pid, __func__, @@ -667,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task) if (xprt_test_and_set_binding(xprt)) { dprintk("RPC: %5u %s: waiting for another binder\n", task->tk_pid, __func__); + xprt_put(xprt); return; } @@ -734,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task) switch (bind_version) { case RPCBVERS_4: case RPCBVERS_3: - map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); + map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID]; map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC); map->r_owner = ""; break; @@ -763,6 +769,7 @@ bailout_release_client: bailout_nofree: rpcb_wake_rpcbind_waiters(xprt, status); task->tk_status = status; + xprt_put(xprt); } EXPORT_SYMBOL_GPL(rpcb_getport_async); diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 1eb3304bc10..bc2068ee795 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "netns.h" @@ -179,7 +180,7 @@ static void _print_name(struct seq_file *seq, unsigned int op, void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) { struct rpc_iostats *stats = clnt->cl_metrics; - struct rpc_xprt *xprt = clnt->cl_xprt; + struct rpc_xprt *xprt; unsigned int op, maxproc = clnt->cl_maxproc; if (!stats) @@ -189,8 +190,11 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) seq_printf(seq, "p/v: %u/%u (%s)\n", clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); + rcu_read_lock(); + xprt = rcu_dereference(clnt->cl_xprt); if (xprt) xprt->ops->print_stats(xprt, seq); + rcu_read_unlock(); seq_printf(seq, "\tper-op statistics\n"); for (op = 0; op < maxproc; op++) { -- cgit v1.2.3-70-g09d2 From 4e0038b6b246e4145fc4a53dca61a556d17bc52c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Mar 2012 17:01:05 -0500 Subject: SUNRPC: Move clnt->cl_server into struct rpc_xprt When the cl_xprt field is updated, the cl_server field will also have to change. Since the contents of cl_server follow the remote endpoint of cl_xprt, just move that field to the rpc_xprt. Signed-off-by: Trond Myklebust [ cel: simplify check_gss_callback_principal(), whitespace changes ] [ cel: forward ported to 3.4 ] Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/callback.c | 3 +- fs/nfs/nfs4proc.c | 3 +- include/linux/sunrpc/clnt.h | 1 - include/linux/sunrpc/xprt.h | 2 ++ net/sunrpc/clnt.c | 88 ++++++++++++++++++++++----------------------- net/sunrpc/rpc_pipe.c | 3 +- net/sunrpc/rpcb_clnt.c | 4 +-- net/sunrpc/xprt.c | 15 +++++++- 8 files changed, 66 insertions(+), 53 deletions(-) (limited to 'net') diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 4a122ae7176..2afe23349c7 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -332,7 +332,6 @@ void nfs_callback_down(int minorversion) int check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) { - struct rpc_clnt *r = clp->cl_rpcclient; char *p = svc_gss_principal(rqstp); if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) @@ -353,7 +352,7 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) if (memcmp(p, "nfs@", 4) != 0) return 0; p += 4; - if (strcmp(p, r->cl_server) != 0) + if (strcmp(p, clp->cl_hostname) != 0) return 0; return 1; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 671510cc14c..54767dd66cf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1100,6 +1100,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data if (state == NULL) goto err_put_inode; if (data->o_res.delegation_type != 0) { + struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; int delegation_flags = 0; rcu_read_lock(); @@ -1111,7 +1112,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data pr_err_ratelimited("NFS: Broken NFSv4 server %s is " "returning a delegation for " "OPEN(CLAIM_DELEGATE_CUR)\n", - NFS_CLIENT(inode)->cl_server); + clp->cl_hostname); } else if ((delegation_flags & 1UL<inode, data->owner->so_cred, diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index e3d12b4a031..acd5502a819 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -41,7 +41,6 @@ struct rpc_clnt { cl_vers, /* RPC version number */ cl_maxproc; /* max procedure number */ - const char * cl_server; /* server machine name */ const char * cl_protname; /* protocol name */ struct rpc_auth * cl_auth; /* authenticator */ struct rpc_stat * cl_stats; /* per-program statistics */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index ea712f97f4a..77d278defa7 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -229,6 +229,7 @@ struct rpc_xprt { } stat; struct net *xprt_net; + const char *servername; const char *address_strings[RPC_DISPLAY_MAX]; }; @@ -258,6 +259,7 @@ struct xprt_create { struct sockaddr * srcaddr; /* optional local address */ struct sockaddr * dstaddr; /* remote peer address */ size_t addrlen; + const char *servername; struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ }; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 7783fc0e726..e39ace9a4e1 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -265,15 +265,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru struct rpc_clnt *clnt = NULL; struct rpc_auth *auth; int err; - size_t len; /* sanity check the name before trying to print it */ - err = -EINVAL; - len = strlen(args->servername); - if (len > RPC_MAXNETNAMELEN) - goto out_no_rpciod; - len++; - dprintk("RPC: creating %s client for %s (xprt %p)\n", program->name, args->servername, xprt); @@ -296,10 +289,6 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru goto out_err; clnt->cl_parent = clnt; - clnt->cl_server = kstrdup(args->servername, GFP_KERNEL); - if (clnt->cl_server == NULL) - goto out_no_server; - rcu_assign_pointer(clnt->cl_xprt, xprt); clnt->cl_procinfo = version->procs; clnt->cl_maxproc = version->nrprocs; @@ -363,8 +352,6 @@ out_no_path: out_no_principal: rpc_free_iostats(clnt->cl_metrics); out_no_stats: - kfree(clnt->cl_server); -out_no_server: kfree(clnt); out_err: xprt_put(xprt); @@ -394,6 +381,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) .srcaddr = args->saddress, .dstaddr = args->address, .addrlen = args->addrsize, + .servername = args->servername, .bc_xprt = args->bc_xprt, }; char servername[48]; @@ -402,7 +390,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) * If the caller chooses not to specify a hostname, whip * up a string representation of the passed-in address. */ - if (args->servername == NULL) { + if (xprtargs.servername == NULL) { struct sockaddr_un *sun = (struct sockaddr_un *)args->address; struct sockaddr_in *sin = @@ -429,7 +417,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) * address family isn't recognized. */ return ERR_PTR(-EINVAL); } - args->servername = servername; + xprtargs.servername = servername; } xprt = xprt_create_transport(&xprtargs); @@ -488,9 +476,6 @@ rpc_clone_client(struct rpc_clnt *clnt) new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); if (!new) goto out_no_clnt; - new->cl_server = kstrdup(clnt->cl_server, GFP_KERNEL); - if (new->cl_server == NULL) - goto out_no_server; new->cl_parent = clnt; /* Turn off autobind on clones */ new->cl_autobind = 0; @@ -528,8 +513,6 @@ out_no_transport: out_no_principal: rpc_free_iostats(new->cl_metrics); out_no_stats: - kfree(new->cl_server); -out_no_server: kfree(new); out_no_clnt: dprintk("RPC: %s: returned error %d\n", __func__, err); @@ -574,8 +557,9 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks); */ void rpc_shutdown_client(struct rpc_clnt *clnt) { - dprintk("RPC: shutting down %s client for %s\n", - clnt->cl_protname, clnt->cl_server); + dprintk_rcu("RPC: shutting down %s client for %s\n", + clnt->cl_protname, + rcu_dereference(clnt->cl_xprt)->servername); while (!list_empty(&clnt->cl_tasks)) { rpc_killall_tasks(clnt); @@ -593,11 +577,11 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client); static void rpc_free_client(struct rpc_clnt *clnt) { - dprintk("RPC: destroying %s client for %s\n", - clnt->cl_protname, clnt->cl_server); + dprintk_rcu("RPC: destroying %s client for %s\n", + clnt->cl_protname, + rcu_dereference(clnt->cl_xprt)->servername); if (clnt->cl_parent != clnt) rpc_release_client(clnt->cl_parent); - kfree(clnt->cl_server); rpc_unregister_client(clnt); rpc_clnt_remove_pipedir(clnt); rpc_free_iostats(clnt->cl_metrics); @@ -1685,8 +1669,11 @@ call_timeout(struct rpc_task *task) } if (RPC_IS_SOFT(task)) { if (clnt->cl_chatty) + rcu_read_lock(); printk(KERN_NOTICE "%s: server %s not responding, timed out\n", - clnt->cl_protname, clnt->cl_server); + clnt->cl_protname, + rcu_dereference(clnt->cl_xprt)->servername); + rcu_read_unlock(); if (task->tk_flags & RPC_TASK_TIMEOUT) rpc_exit(task, -ETIMEDOUT); else @@ -1696,9 +1683,13 @@ call_timeout(struct rpc_task *task) if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) { task->tk_flags |= RPC_CALL_MAJORSEEN; - if (clnt->cl_chatty) + if (clnt->cl_chatty) { + rcu_read_lock(); printk(KERN_NOTICE "%s: server %s not responding, still trying\n", - clnt->cl_protname, clnt->cl_server); + clnt->cl_protname, + rcu_dereference(clnt->cl_xprt)->servername); + rcu_read_unlock(); + } } rpc_force_rebind(clnt); /* @@ -1727,9 +1718,13 @@ call_decode(struct rpc_task *task) dprint_status(task); if (task->tk_flags & RPC_CALL_MAJORSEEN) { - if (clnt->cl_chatty) + if (clnt->cl_chatty) { + rcu_read_lock(); printk(KERN_NOTICE "%s: server %s OK\n", - clnt->cl_protname, clnt->cl_server); + clnt->cl_protname, + rcu_dereference(clnt->cl_xprt)->servername); + rcu_read_unlock(); + } task->tk_flags &= ~RPC_CALL_MAJORSEEN; } @@ -1807,6 +1802,7 @@ rpc_encode_header(struct rpc_task *task) static __be32 * rpc_verify_header(struct rpc_task *task) { + struct rpc_clnt *clnt = task->tk_client; struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0]; int len = task->tk_rqstp->rq_rcv_buf.len >> 2; __be32 *p = iov->iov_base; @@ -1879,8 +1875,11 @@ rpc_verify_header(struct rpc_task *task) task->tk_action = call_bind; goto out_retry; case RPC_AUTH_TOOWEAK: + rcu_read_lock(); printk(KERN_NOTICE "RPC: server %s requires stronger " - "authentication.\n", task->tk_client->cl_server); + "authentication.\n", + rcu_dereference(clnt->cl_xprt)->servername); + rcu_read_unlock(); break; default: dprintk("RPC: %5u %s: unknown auth error: %x\n", @@ -1903,28 +1902,27 @@ rpc_verify_header(struct rpc_task *task) case RPC_SUCCESS: return p; case RPC_PROG_UNAVAIL: - dprintk("RPC: %5u %s: program %u is unsupported by server %s\n", - task->tk_pid, __func__, - (unsigned int)task->tk_client->cl_prog, - task->tk_client->cl_server); + dprintk_rcu("RPC: %5u %s: program %u is unsupported " + "by server %s\n", task->tk_pid, __func__, + (unsigned int)clnt->cl_prog, + rcu_dereference(clnt->cl_xprt)->servername); error = -EPFNOSUPPORT; goto out_err; case RPC_PROG_MISMATCH: - dprintk("RPC: %5u %s: program %u, version %u unsupported by " - "server %s\n", task->tk_pid, __func__, - (unsigned int)task->tk_client->cl_prog, - (unsigned int)task->tk_client->cl_vers, - task->tk_client->cl_server); + dprintk_rcu("RPC: %5u %s: program %u, version %u unsupported " + "by server %s\n", task->tk_pid, __func__, + (unsigned int)clnt->cl_prog, + (unsigned int)clnt->cl_vers, + rcu_dereference(clnt->cl_xprt)->servername); error = -EPROTONOSUPPORT; goto out_err; case RPC_PROC_UNAVAIL: - dprintk("RPC: %5u %s: proc %s unsupported by program %u, " + dprintk_rcu("RPC: %5u %s: proc %s unsupported by program %u, " "version %u on server %s\n", task->tk_pid, __func__, rpc_proc_name(task), - task->tk_client->cl_prog, - task->tk_client->cl_vers, - task->tk_client->cl_server); + clnt->cl_prog, clnt->cl_vers, + rcu_dereference(clnt->cl_xprt)->servername); error = -EOPNOTSUPP; goto out_err; case RPC_GARBAGE_ARGS: @@ -1938,7 +1936,7 @@ rpc_verify_header(struct rpc_task *task) } out_garbage: - task->tk_client->cl_stats->rpcgarbage++; + clnt->cl_stats->rpcgarbage++; if (task->tk_garb_retry) { task->tk_garb_retry--; dprintk("RPC: %5u %s: retrying\n", diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 3d30943ed6d..7d96e3cd57c 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -404,7 +404,8 @@ rpc_show_info(struct seq_file *m, void *v) struct rpc_clnt *clnt = m->private; rcu_read_lock(); - seq_printf(m, "RPC server: %s\n", clnt->cl_server); + seq_printf(m, "RPC server: %s\n", + rcu_dereference(clnt->cl_xprt)->servername); seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, clnt->cl_prog, clnt->cl_vers); seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 4f8af63798a..e699ff0ce90 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -663,7 +663,7 @@ void rpcb_getport_async(struct rpc_task *task) dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", task->tk_pid, __func__, - clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); + xprt->servername, clnt->cl_prog, clnt->cl_vers, xprt->prot); /* Put self on the wait queue to ensure we get notified if * some other task is already attempting to bind the port */ @@ -714,7 +714,7 @@ void rpcb_getport_async(struct rpc_task *task) dprintk("RPC: %5u %s: trying rpcbind version %u\n", task->tk_pid, __func__, bind_version); - rpcb_clnt = rpcb_create(xprt->xprt_net, clnt->cl_server, sap, salen, + rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen, xprt->prot, bind_version); if (IS_ERR(rpcb_clnt)) { status = PTR_ERR(rpcb_clnt); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 32e37945a84..0cbcd1ab49a 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -66,6 +66,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net); static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); static void xprt_connect_status(struct rpc_task *task); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); +static void xprt_destroy(struct rpc_xprt *xprt); static DEFINE_SPINLOCK(xprt_list_lock); static LIST_HEAD(xprt_list); @@ -751,7 +752,7 @@ static void xprt_connect_status(struct rpc_task *task) default: dprintk("RPC: %5u xprt_connect_status: error %d connecting to " "server %s\n", task->tk_pid, -task->tk_status, - task->tk_client->cl_server); + xprt->servername); xprt_release_write(xprt, task); task->tk_status = -EIO; } @@ -1229,6 +1230,17 @@ found: (unsigned long)xprt); else init_timer(&xprt->timer); + + if (strlen(args->servername) > RPC_MAXNETNAMELEN) { + xprt_destroy(xprt); + return ERR_PTR(-EINVAL); + } + xprt->servername = kstrdup(args->servername, GFP_KERNEL); + if (xprt->servername == NULL) { + xprt_destroy(xprt); + return ERR_PTR(-ENOMEM); + } + dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); out: @@ -1251,6 +1263,7 @@ static void xprt_destroy(struct rpc_xprt *xprt) rpc_destroy_wait_queue(&xprt->sending); rpc_destroy_wait_queue(&xprt->backlog); cancel_work_sync(&xprt->task_cleanup); + kfree(xprt->servername); /* * Tear down transport state and free the rpc_xprt */ -- cgit v1.2.3-70-g09d2 From 2e738fdce22f9a7edf20281fd2d768ef9785922e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Mar 2012 17:01:14 -0500 Subject: SUNRPC: Add API to acquire source address NFSv4.0 clients must send endpoint information for their callback service to NFSv4.0 servers during their first contact with a server. Traditionally on Linux, user space provides the callback endpoint IP address via the "clientaddr=" mount option. During an NFSv4 migration event, it is possible that an FSID may be migrated to a destination server that is accessible via a different source IP address than the source server was. The client must update callback endpoint information on the destination server so that it can maintain leases and allow delegation. Without a new "clientaddr=" option from user space, however, the kernel itself must construct an appropriate IP address for the callback update. Provide an API in the RPC client for upper layer RPC consumers to acquire a source address for a remote. The mechanism used by the mount.nfs command is copied: set up a connected UDP socket to the designated remote, then scrape the source address off the socket. We are careful to select the correct network namespace when setting up the temporary UDP socket. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/clnt.h | 1 + net/sunrpc/clnt.c | 149 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) (limited to 'net') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index acd5502a819..523547ecfee 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -161,6 +161,7 @@ size_t rpc_max_payload(struct rpc_clnt *); void rpc_force_rebind(struct rpc_clnt *); size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); +int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t); size_t rpc_ntop(const struct sockaddr *, char *, const size_t); size_t rpc_pton(struct net *, const char *, const size_t, diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e39ace9a4e1..7a4cb5fdc21 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -914,6 +914,155 @@ const char *rpc_peeraddr2str(struct rpc_clnt *clnt, } EXPORT_SYMBOL_GPL(rpc_peeraddr2str); +static const struct sockaddr_in rpc_inaddr_loopback = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_ANY), +}; + +static const struct sockaddr_in6 rpc_in6addr_loopback = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, +}; + +/* + * Try a getsockname() on a connected datagram socket. Using a + * connected datagram socket prevents leaving a socket in TIME_WAIT. + * This conserves the ephemeral port number space. + * + * Returns zero and fills in "buf" if successful; otherwise, a + * negative errno is returned. + */ +static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen, + struct sockaddr *buf, int buflen) +{ + struct socket *sock; + int err; + + err = __sock_create(net, sap->sa_family, + SOCK_DGRAM, IPPROTO_UDP, &sock, 1); + if (err < 0) { + dprintk("RPC: can't create UDP socket (%d)\n", err); + goto out; + } + + switch (sap->sa_family) { + case AF_INET: + err = kernel_bind(sock, + (struct sockaddr *)&rpc_inaddr_loopback, + sizeof(rpc_inaddr_loopback)); + break; + case AF_INET6: + err = kernel_bind(sock, + (struct sockaddr *)&rpc_in6addr_loopback, + sizeof(rpc_in6addr_loopback)); + break; + default: + err = -EAFNOSUPPORT; + goto out; + } + if (err < 0) { + dprintk("RPC: can't bind UDP socket (%d)\n", err); + goto out_release; + } + + err = kernel_connect(sock, sap, salen, 0); + if (err < 0) { + dprintk("RPC: can't connect UDP socket (%d)\n", err); + goto out_release; + } + + err = kernel_getsockname(sock, buf, &buflen); + if (err < 0) { + dprintk("RPC: getsockname failed (%d)\n", err); + goto out_release; + } + + err = 0; + if (buf->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf; + sin6->sin6_scope_id = 0; + } + dprintk("RPC: %s succeeded\n", __func__); + +out_release: + sock_release(sock); +out: + return err; +} + +/* + * Scraping a connected socket failed, so we don't have a useable + * local address. Fallback: generate an address that will prevent + * the server from calling us back. + * + * Returns zero and fills in "buf" if successful; otherwise, a + * negative errno is returned. + */ +static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen) +{ + switch (family) { + case AF_INET: + if (buflen < sizeof(rpc_inaddr_loopback)) + return -EINVAL; + memcpy(buf, &rpc_inaddr_loopback, + sizeof(rpc_inaddr_loopback)); + break; + case AF_INET6: + if (buflen < sizeof(rpc_in6addr_loopback)) + return -EINVAL; + memcpy(buf, &rpc_in6addr_loopback, + sizeof(rpc_in6addr_loopback)); + default: + dprintk("RPC: %s: address family not supported\n", + __func__); + return -EAFNOSUPPORT; + } + dprintk("RPC: %s: succeeded\n", __func__); + return 0; +} + +/** + * rpc_localaddr - discover local endpoint address for an RPC client + * @clnt: RPC client structure + * @buf: target buffer + * @buflen: size of target buffer, in bytes + * + * Returns zero and fills in "buf" and "buflen" if successful; + * otherwise, a negative errno is returned. + * + * This works even if the underlying transport is not currently connected, + * or if the upper layer never previously provided a source address. + * + * The result of this function call is transient: multiple calls in + * succession may give different results, depending on how local + * networking configuration changes over time. + */ +int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen) +{ + struct sockaddr_storage address; + struct sockaddr *sap = (struct sockaddr *)&address; + struct rpc_xprt *xprt; + struct net *net; + size_t salen; + int err; + + rcu_read_lock(); + xprt = rcu_dereference(clnt->cl_xprt); + salen = xprt->addrlen; + memcpy(sap, &xprt->addr, salen); + net = get_net(xprt->xprt_net); + rcu_read_unlock(); + + rpc_set_port(sap, 0); + err = rpc_sockname(net, sap, salen, buf, buflen); + put_net(net); + if (err != 0) + /* Couldn't discover local address, return ANYADDR */ + return rpc_anyaddr(sap->sa_family, buf, buflen); + return 0; +} +EXPORT_SYMBOL_GPL(rpc_localaddr); + void rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) { -- cgit v1.2.3-70-g09d2 From 4f87da80a5210e66fb47b0e839f4d05016986f78 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 19:55:56 +0200 Subject: Bluetooth: Remove HCI_PI_MGMT_INIT flag for sockets This flag is of no use right now and is in fact harmful in that it prevents the HCI_MGMT flag to be set for any controllers that may need it after the first one that bluetoothd takes into use (the flag is cleared for the first controller so any subsequent ones through the same bluetoothd mgmt socket never get the HCI_MGMT flag set). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ---- net/bluetooth/hci_sock.c | 1 - net/bluetooth/mgmt.c | 18 ++++++++---------- 3 files changed, 8 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index facd7ed32b7..25cb0a15b57 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1034,16 +1034,12 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) -/* HCI socket flags */ -#define HCI_PI_MGMT_INIT 0 - struct hci_pinfo { struct bt_sock bt; struct hci_dev *hdev; struct hci_filter filter; __u32 cmsg_mask; unsigned short channel; - unsigned long flags; }; /* HCI security filter */ diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 8a814bca00d..63afd234283 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -659,7 +659,6 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } - set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; case HCI_CHANNEL_MONITOR: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fa9a5896427..4b1efedc18c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -615,19 +615,17 @@ static void service_cache_off(struct work_struct *work) static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) { - if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) + if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) return; - if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) { - INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); - /* Non-mgmt controlled devices get this bit set - * implicitly so that pairing works for them, however - * for mgmt we require user-space to explicitly enable - * it - */ - clear_bit(HCI_PAIRABLE, &hdev->dev_flags); - } + /* Non-mgmt controlled devices get this bit set + * implicitly so that pairing works for them, however + * for mgmt we require user-space to explicitly enable + * it + */ + clear_bit(HCI_PAIRABLE, &hdev->dev_flags); } static int read_controller_info(struct sock *sk, struct hci_dev *hdev, -- cgit v1.2.3-70-g09d2 From 2b4bf3974249da74f4aef1e9180d4beaf6332515 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 3 Mar 2012 00:19:06 +0200 Subject: Bluetooth: mgmt: Fix updating local name when powering on When powering on we need to apply whatever name has been set through mgmt_set_local_name. The appropriate place for this is mgmt_powered() and not hci_setup() since this needs to be applied also if the HCI init sequence was already completed but the adapter was still "powered off" from a mgmt perspective due the the HCI_AUTO_OFF still being set. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 8 -------- net/bluetooth/mgmt.c | 22 ++++++++++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d6c41bbfe75..6a817daf095 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -552,14 +552,6 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - if (!test_bit(HCI_SETUP, &hdev->dev_flags) && - test_bit(HCI_MGMT, &hdev->dev_flags)) { - struct hci_cp_write_local_name cp; - - memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); - hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); - } - if (hdev->features[6] & LMP_SIMPLE_PAIR) { if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4b1efedc18c..4ca009268af 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2104,11 +2104,19 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } +static int update_name(struct hci_dev *hdev, const char *name) +{ + struct hci_cp_write_local_name cp; + + memcpy(cp.name, name, sizeof(cp.name)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); +} + static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { - struct mgmt_cp_set_local_name *mgmt_cp = data; - struct hci_cp_write_local_name hci_cp; + struct mgmt_cp_set_local_name *cp = data; struct pending_cmd *cmd; int err; @@ -2116,11 +2124,10 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); - memcpy(hdev->short_name, mgmt_cp->short_name, - sizeof(hdev->short_name)); + memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name)); if (!hdev_is_powered(hdev)) { - memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name)); + memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name)); err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, data, len); @@ -2139,9 +2146,7 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); - err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), - &hci_cp); + err = update_name(hdev, cp->name); if (err < 0) mgmt_pending_remove(cmd); @@ -2794,6 +2799,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); update_class(hdev); + update_name(hdev, hdev->dev_name); update_eir(hdev); } else { u8 status = MGMT_STATUS_NOT_POWERED; -- cgit v1.2.3-70-g09d2 From 74fe619ef96466d562a1a13e7cbab783624ec2f3 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 1 Mar 2012 18:19:57 -0300 Subject: Bluetooth: Don't force DISCOVERY_STOPPED state in inquiry_cache_flush We are not supposed to force DISCOVERY_STOPPED in inquiry_cache_flush because we may break the discovery state machine. For instance, during interleaved discovery, when we are about to start inquiry, the state machine forcibly goes to DISCOVERY_STOPPED while it should stay in DISCOVERY_FINDING state. This problem results in unexpected behaviors such as sending two mgmt_discovering events to userspace (when only one event is expected) and Stop Discovery failures. Signed-off-by: Andre Guedes Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d3ddc0ba9cd..661d65fc487 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -413,7 +413,6 @@ static void inquiry_cache_flush(struct hci_dev *hdev) INIT_LIST_HEAD(&cache->unknown); INIT_LIST_HEAD(&cache->resolve); - cache->state = DISCOVERY_STOPPED; } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) -- cgit v1.2.3-70-g09d2 From 793734b587a670e47a8d65f9e5211ba2188bb904 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 27 Feb 2012 12:29:44 -0700 Subject: dccp ccid-3: replace incorrect BUG_ON This replaces an unjustified BUG_ON(), which could get triggered under normal conditions: X_calc can be 0 when p > 0. X would in this case be set to the minimum, s/t_mbi. Its replacement avoids t_ipi = 0 (unbounded sending rate). Thanks to Jordi, Victor and Xavier who reported this. Signed-off-by: Gerrit Renker Acked-by: Ian McDonald --- net/dccp/ccids/ccid3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 56062730720..70bfaf2d196 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -98,6 +98,7 @@ static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hc) { hc->tx_t_ipi = scaled_div32(((u64)hc->tx_s) << 6, hc->tx_x); + DCCP_BUG_ON(hc->tx_t_ipi == 0); ccid3_pr_debug("t_ipi=%u, s=%u, X=%u\n", hc->tx_t_ipi, hc->tx_s, (unsigned)(hc->tx_x >> 6)); } @@ -236,8 +237,6 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) * * Note that X_recv is scaled by 2^6 while X_calc is not */ - BUG_ON(hc->tx_p && !hc->tx_x_calc); - if (hc->tx_x_calc > (hc->tx_x_recv >> 5)) hc->tx_x_recv = max(hc->tx_x_recv / 2, -- cgit v1.2.3-70-g09d2 From f541fb7e20c848f947ca65fbf169efe69400c942 Mon Sep 17 00:00:00 2001 From: Samuel Jero Date: Sun, 26 Feb 2012 18:22:02 -0700 Subject: dccp: fix bug in sequence number validation during connection setup This fixes a bug in the sequence number validation during the initial handshake. The code did not treat the initial sequence numbers ISS and ISR as read-only and did not keep state for GSR and GSS as required by the specification. This causes problems with retransmissions during the initial handshake, causing the budding connection to be reset. This patch now treats ISS/ISR as read-only and tracks GSS/GSR as required. Signed-off-by: Samuel Jero Signed-off-by: Gerrit Renker --- include/linux/dccp.h | 8 ++++++-- net/dccp/ipv4.c | 8 +++++--- net/dccp/ipv6.c | 8 +++++--- net/dccp/minisocks.c | 18 +++++++++++------- net/dccp/output.c | 10 +++++----- 5 files changed, 32 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 710c04302a1..eaf95a023af 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -376,8 +376,10 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) /** * struct dccp_request_sock - represent DCCP-specific connection request * @dreq_inet_rsk: structure inherited from - * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1) - * @dreq_isr: initial sequence number received on the Request + * @dreq_iss: initial sequence number, sent on the first Response (RFC 4340, 7.1) + * @dreq_gss: greatest sequence number sent (for retransmitted Responses) + * @dreq_isr: initial sequence number received in the first Request + * @dreq_gsr: greatest sequence number received (for retransmitted Request(s)) * @dreq_service: service code present on the Request (there is just one) * @dreq_featneg: feature negotiation options for this connection * The following two fields are analogous to the ones in dccp_sock: @@ -387,7 +389,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) struct dccp_request_sock { struct inet_request_sock dreq_inet_rsk; __u64 dreq_iss; + __u64 dreq_gss; __u64 dreq_isr; + __u64 dreq_gsr; __be32 dreq_service; struct list_head dreq_featneg; __u32 dreq_timestamp_echo; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 1c67fe8ff90..caf6e1734b6 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -300,7 +300,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) */ WARN_ON(req->sk); - if (seq != dccp_rsk(req)->dreq_iss) { + if (!between48(seq, dccp_rsk(req)->dreq_iss, + dccp_rsk(req)->dreq_gss)) { NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -639,11 +640,12 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie * - * In fact we defer setting S.GSR, S.SWL, S.SWH to - * dccp_create_openreq_child. + * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child(). */ dreq->dreq_isr = dcb->dccpd_seq; + dreq->dreq_gsr = dreq->dreq_isr; dreq->dreq_iss = dccp_v4_init_sequence(skb); + dreq->dreq_gss = dreq->dreq_iss; dreq->dreq_service = service; if (dccp_v4_send_response(sk, req, NULL)) diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index ce903f747e6..4dc588f520e 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -193,7 +193,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, */ WARN_ON(req->sk != NULL); - if (seq != dccp_rsk(req)->dreq_iss) { + if (!between48(seq, dccp_rsk(req)->dreq_iss, + dccp_rsk(req)->dreq_gss)) { NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); goto out; } @@ -440,11 +441,12 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) * * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie * - * In fact we defer setting S.GSR, S.SWL, S.SWH to - * dccp_create_openreq_child. + * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child(). */ dreq->dreq_isr = dcb->dccpd_seq; + dreq->dreq_gsr = dreq->dreq_isr; dreq->dreq_iss = dccp_v6_init_sequence(skb); + dreq->dreq_gss = dreq->dreq_iss; dreq->dreq_service = service; if (dccp_v6_send_response(sk, req, NULL)) diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 5a7f90bbffa..ea850ce35d4 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -127,9 +127,11 @@ struct sock *dccp_create_openreq_child(struct sock *sk, * activation below, as these windows all depend on the local * and remote Sequence Window feature values (7.5.2). */ - newdp->dccps_gss = newdp->dccps_iss = dreq->dreq_iss; + newdp->dccps_iss = dreq->dreq_iss; + newdp->dccps_gss = dreq->dreq_gss; newdp->dccps_gar = newdp->dccps_iss; - newdp->dccps_gsr = newdp->dccps_isr = dreq->dreq_isr; + newdp->dccps_isr = dreq->dreq_isr; + newdp->dccps_gsr = dreq->dreq_gsr; /* * Activate features: initialise CCIDs, sequence windows etc. @@ -164,9 +166,9 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, /* Check for retransmitted REQUEST */ if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) { - if (after48(DCCP_SKB_CB(skb)->dccpd_seq, dreq->dreq_isr)) { + if (after48(DCCP_SKB_CB(skb)->dccpd_seq, dreq->dreq_gsr)) { dccp_pr_debug("Retransmitted REQUEST\n"); - dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq; + dreq->dreq_gsr = DCCP_SKB_CB(skb)->dccpd_seq; /* * Send another RESPONSE packet * To protect against Request floods, increment retrans @@ -186,12 +188,14 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, goto drop; /* Invalid ACK */ - if (DCCP_SKB_CB(skb)->dccpd_ack_seq != dreq->dreq_iss) { + if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq, + dreq->dreq_iss, dreq->dreq_gss)) { dccp_pr_debug("Invalid ACK number: ack_seq=%llu, " - "dreq_iss=%llu\n", + "dreq_iss=%llu, dreq_gss=%llu\n", (unsigned long long) DCCP_SKB_CB(skb)->dccpd_ack_seq, - (unsigned long long) dreq->dreq_iss); + (unsigned long long) dreq->dreq_iss, + (unsigned long long) dreq->dreq_gss); goto drop; } diff --git a/net/dccp/output.c b/net/dccp/output.c index dede3edb884..78736730879 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -408,10 +408,10 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, skb_dst_set(skb, dst_clone(dst)); dreq = dccp_rsk(req); - if (inet_rsk(req)->acked) /* increase ISS upon retransmission */ - dccp_inc_seqno(&dreq->dreq_iss); + if (inet_rsk(req)->acked) /* increase GSS upon retransmission */ + dccp_inc_seqno(&dreq->dreq_gss); DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; - DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; + DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_gss; /* Resolve feature dependencies resulting from choice of CCID */ if (dccp_feat_server_ccid_dependencies(dreq)) @@ -429,8 +429,8 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; dh->dccph_type = DCCP_PKT_RESPONSE; dh->dccph_x = 1; - dccp_hdr_set_seq(dh, dreq->dreq_iss); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); + dccp_hdr_set_seq(dh, dreq->dreq_gss); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_gsr); dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; dccp_csum_outgoing(skb); -- cgit v1.2.3-70-g09d2 From c0638c247f559e1a16ee79e54df14bca2cb679ea Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Fri, 2 Mar 2012 21:36:51 +0000 Subject: tcp: don't fragment SACKed skbs in tcp_mark_head_lost() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In tcp_mark_head_lost() we should not attempt to fragment a SACKed skb to mark the first portion as lost. This is for two primary reasons: (1) tcp_shifted_skb() coalesces adjacent regions of SACKed skbs. When doing this, it preserves the sum of their packet counts in order to reflect the real-world dynamics on the wire. But given that skbs can have remainders that do not align to MSS boundaries, this packet count preservation means that for SACKed skbs there is not necessarily a direct linear relationship between tcp_skb_pcount(skb) and skb->len. Thus tcp_mark_head_lost()'s previous attempts to fragment off and mark as lost a prefix of length (packets - oldcnt)*mss from SACKed skbs were leading to occasional failures of the WARN_ON(len > skb->len) in tcp_fragment() (which used to be a BUG_ON(); see the recent "crash in tcp_fragment" thread on netdev). (2) there is no real point in fragmenting off part of a SACKed skb and calling tcp_skb_mark_lost() on it, since tcp_skb_mark_lost() is a NOP for SACKed skbs. Signed-off-by: Neal Cardwell Acked-by: Ilpo Järvinen Acked-by: Yuchung Cheng Acked-by: Nandita Dukkipati Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ee42d42b2f4..d9b83d198c3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2569,6 +2569,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) if (cnt > packets) { if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) || + (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) || (oldcnt >= packets)) break; -- cgit v1.2.3-70-g09d2 From 4b32da2bcf1de2b7a196a0e48389d231b4472c36 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 4 Mar 2012 12:56:55 +0000 Subject: ppp: Replace uses of with Since all that include/linux/if_ppp.h does is #include , this replaces the occurrences of #include with #include . It also corrects an error in Documentation/networking/l2tp.txt, where it referenced include/linux/if_ppp.h as the source of some definitions that are actually now defined in include/linux/if_pppol2tp.h. Signed-off-by: Paul Mackerras Signed-off-by: David S. Miller --- Documentation/networking/l2tp.txt | 2 +- drivers/isdn/capi/capi.c | 2 +- drivers/net/ppp/ppp_async.c | 2 +- drivers/net/ppp/ppp_synctty.c | 2 +- drivers/net/ppp/pppoe.c | 2 +- drivers/net/ppp/pppox.c | 2 +- drivers/tty/ipwireless/network.c | 2 +- drivers/tty/ipwireless/tty.c | 2 +- fs/compat_ioctl.c | 2 +- include/linux/isdn.h | 2 +- net/atm/pppoatm.c | 2 +- net/irda/irnet/irnet.h | 2 +- net/l2tp/l2tp_ppp.c | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/Documentation/networking/l2tp.txt b/Documentation/networking/l2tp.txt index e7bf3979fac..e63fc1f7bf8 100644 --- a/Documentation/networking/l2tp.txt +++ b/Documentation/networking/l2tp.txt @@ -111,7 +111,7 @@ When creating PPPoL2TP sockets, the application provides information to the driver about the socket in a socket connect() call. Source and destination tunnel and session ids are provided, as well as the file descriptor of a UDP socket. See struct pppol2tp_addr in -include/linux/if_ppp.h. Note that zero tunnel / session ids are +include/linux/if_pppol2tp.h. Note that zero tunnel / session ids are treated specially. When creating the per-tunnel PPPoL2TP management socket in Step 2 above, zero source and destination session ids are specified, which tells the driver to prepare the supplied UDP file diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index d33a70c4918..0cf05464bfb 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index c6ba6438082..af95a98fd86 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index 736a39ee05b..55e466c511d 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index bc9a4bb3198..2fa1a9b6f49 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -72,7 +72,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c index 8c0d170dabc..2940e9fe351 100644 --- a/drivers/net/ppp/pppox.c +++ b/drivers/net/ppp/pppox.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c index f7daeea598e..57c8b481113 100644 --- a/drivers/tty/ipwireless/network.c +++ b/drivers/tty/ipwireless/network.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include "network.h" diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index ef92869502a..2ffa0b77770 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index a26bea10e81..10d8cd90ca6 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 4ccf95d681b..292f27a793d 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -187,7 +187,7 @@ typedef struct { #endif #include -#include +#include #include #endif diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index df35d9a3b5f..614d3fc47ed 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h index 979ecb2435a..564eb0b8afa 100644 --- a/net/irda/irnet/irnet.h +++ b/net/irda/irnet/irnet.h @@ -254,7 +254,7 @@ #include #include -#include +#include #include #include diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 8a90d756c90..96bc7a67585 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -82,7 +82,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From aaca735f4f188641c4786af8f20ed39fcce3809c Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2012 08:12:18 +0000 Subject: bridge: Adjust min age inc for HZ > 256 min age increment needs to round up its min age tick for all HZ values to guarantee message age is increasing. Signed-off-by: Joakim Tjernlund Signed-off-by: David S. Miller --- net/bridge/br_stp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index dd147d78a58..c9ef3db737d 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -17,9 +17,9 @@ #include "br_private_stp.h" /* since time values in bpdu are in jiffies and then scaled (1/256) - * before sending, make sure that is at least one. + * before sending, make sure that is at least one STP tick. */ -#define MESSAGE_AGE_INCR ((HZ < 256) ? 1 : (HZ/256)) +#define MESSAGE_AGE_INCR ((HZ / 256) + 1) static const char *const br_port_state_names[] = { [BR_STATE_DISABLED] = "disabled", -- cgit v1.2.3-70-g09d2 From 709e1b5cd9e1915ad4f6c470ebf6b55d4a911d8c Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2012 08:12:19 +0000 Subject: bridge: message age needs to increase, not decrease. commit bridge: send proper message_age in config BPDU added this gem: bpdu.message_age = (jiffies - root->designated_age) p->designated_age = jiffies + bpdu->message_age; Notice how bpdu->message_age is negated when reassigned to bpdu.message_age. This causes message age to decrease breaking the STP protocol. Signed-off-by: Joakim Tjernlund Signed-off-by: David S. Miller --- net/bridge/br_stp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index c9ef3db737d..6751ed4e0c0 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -186,7 +186,7 @@ static void br_record_config_information(struct net_bridge_port *p, p->designated_cost = bpdu->root_path_cost; p->designated_bridge = bpdu->bridge_id; p->designated_port = bpdu->port_id; - p->designated_age = jiffies + bpdu->message_age; + p->designated_age = jiffies - bpdu->message_age; mod_timer(&p->message_age_timer, jiffies + (p->br->max_age - bpdu->message_age)); -- cgit v1.2.3-70-g09d2 From a4b64fbe482c7766f7925f03067fc637716bfa3f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 4 Mar 2012 12:32:10 +0000 Subject: rtnetlink: fix rtnl_calcit() and rtnl_dump_ifinfo() nlmsg_parse() might return an error, so test its return value before potential random memory accesses. Errors introduced in commit 115c9b81928 (rtnetlink: Fix problem with buffer allocation) Signed-off-by: Eric Dumazet Cc: Greg Rose Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 606a6e8f367..f965dce6f20 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1060,11 +1060,12 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock(); cb->seq = net->dev_base_seq; - nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, - ifla_policy); + if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, + ifla_policy) >= 0) { - if (tb[IFLA_EXT_MASK]) - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); + if (tb[IFLA_EXT_MASK]) + ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); + } for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; @@ -1900,10 +1901,11 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh) u32 ext_filter_mask = 0; u16 min_ifinfo_dump_size = 0; - nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, ifla_policy); - - if (tb[IFLA_EXT_MASK]) - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); + if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, + ifla_policy) >= 0) { + if (tb[IFLA_EXT_MASK]) + ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); + } if (!ext_filter_mask) return NLMSG_GOODSIZE; -- cgit v1.2.3-70-g09d2 From 3d045a54488b69b0024309b18da5024c036c3152 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Tue, 28 Feb 2012 22:00:06 +0800 Subject: mac80211: Fix the generation of PREQs in proactive RANN mechanism of HWMP According to Section Y.7.4 Actions on receipt of proactive RANN, an individually addressed PREQ should be generated towards the neighbor peer mesh STA indicated in the RANN Sender Address field in the forwarding information. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Javier Cardona Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh.h | 4 ++++ net/mac80211/mesh_hwmp.c | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index c7e5c49471e..8d53b71378e 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -85,6 +85,8 @@ enum mesh_deferred_task_flags { * @state_lock: mesh path state lock used to protect changes to the * mpath itself. No need to take this lock when adding or removing * an mpath to a hash bucket on a path table. + * @rann_snd_addr: the RANN sender address + * @is_root: the destination station of this path is a root node * @is_gate: the destination station of this path is a mesh gate * * @@ -109,6 +111,8 @@ struct mesh_path { u8 discovery_retries; enum mesh_path_flags flags; spinlock_t state_lock; + u8 rann_snd_addr[ETH_ALEN]; + bool is_root; bool is_gate; }; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 31bc762f209..639db14f43d 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -513,8 +513,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, u8 *preq_elem, u32 metric) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - struct mesh_path *mpath; + struct mesh_path *mpath = NULL; u8 *target_addr, *orig_addr; + const u8 *da; u8 target_flags, ttl; u32 orig_sn, target_sn, lifetime; bool reply = false; @@ -591,9 +592,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, flags = PREQ_IE_FLAGS(preq_elem); preq_id = PREQ_IE_PREQ_ID(preq_elem); hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; + da = (mpath && mpath->is_root) ? + mpath->rann_snd_addr : broadcast_addr; mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, cpu_to_le32(orig_sn), target_flags, target_addr, - cpu_to_le32(target_sn), broadcast_addr, + cpu_to_le32(target_sn), da, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); @@ -742,8 +745,8 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) return; - mhwmp_dbg("received RANN from %pM (is_gate=%d)", orig_addr, - root_is_gate); + mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)", + orig_addr, mgmt->sa, root_is_gate); rcu_read_lock(); mpath = mesh_path_lookup(orig_addr, sdata); @@ -774,6 +777,11 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, 0, sdata); mpath->sn = orig_sn; } + + /* Using individually addressed PREQ for root node */ + memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN); + mpath->is_root = true; + if (root_is_gate) mesh_path_add_gate(mpath); @@ -909,6 +917,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) struct mesh_preq_queue *preq_node; struct mesh_path *mpath; u8 ttl, target_flags; + const u8 *da; u32 lifetime; spin_lock_bh(&ifmsh->mesh_preq_queue_lock); @@ -971,9 +980,10 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) target_flags = MP_F_RF; spin_unlock_bh(&mpath->state_lock); + da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, - cpu_to_le32(mpath->sn), broadcast_addr, 0, + cpu_to_le32(mpath->sn), da, 0, ttl, cpu_to_le32(lifetime), 0, cpu_to_le32(ifmsh->preq_id++), sdata); mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); -- cgit v1.2.3-70-g09d2 From 5533513784a88049e19dd2ab380a452b61e5171e Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Tue, 28 Feb 2012 17:04:08 -0800 Subject: {nl,cfg,mac}80211: Implement RSSI threshold for mesh peering Mesh peer links are established only if average rssi of the peer candidate satisfies the threshold. This is not in 802.11s specification but was requested by David Fulgham, an open80211s user. This is a way to avoid marginal peer links with stations that are barely within range. This patch adds a new mesh configuration parameter, mesh_rssi_threshold. This feature is supported only for hardwares that report signal in dBm. Signed-off-by: Ashok Nagarajan Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- include/linux/nl80211.h | 5 +++++ include/net/cfg80211.h | 1 + net/mac80211/cfg.c | 8 ++++++++ net/mac80211/debugfs_netdev.c | 2 ++ net/mac80211/mesh_plink.c | 16 +++++++++++++++- net/wireless/mesh.c | 3 +++ net/wireless/nl80211.c | 5 +++++ 7 files changed, 39 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index be35a68746a..38fda5ee57f 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -2112,6 +2112,10 @@ enum nl80211_mntr_flags { * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding * or forwarding entity (default is TRUE - forwarding entity) * + * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the + * threshold for average signal strength of candidate station to establish + * a peer link. + * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use @@ -2137,6 +2141,7 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_GATE_ANNOUNCEMENTS, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, NL80211_MESHCONF_FORWARDING, + NL80211_MESHCONF_RSSI_THRESHOLD, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0178c748937..b4e015c9088 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -809,6 +809,7 @@ struct mesh_config { * Still keeping the same nomenclature to be in sync with the spec. */ bool dot11MeshGateAnnouncementProtocol; bool dot11MeshForwarding; + s32 rssi_threshold; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6a77d4c910f..ab31cc56a2f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1314,6 +1314,14 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, } if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask)) conf->dot11MeshForwarding = nconf->dot11MeshForwarding; + if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) { + /* our RSSI threshold implementation is supported only for + * devices that report signal in dBm. + */ + if (!(sdata->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)) + return -ENOTSUPP; + conf->rssi_threshold = nconf->rssi_threshold; + } return 0; } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 510ed1dab3c..9f484d8905f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -443,6 +443,7 @@ IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol, IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); +IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); #endif @@ -581,6 +582,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshHWMPRootMode); MESHPARAMS_ADD(dot11MeshHWMPRannInterval); MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol); + MESHPARAMS_ADD(rssi_threshold); #undef MESHPARAMS_ADD } #endif diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8806e5ef8ff..80ce5277253 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -31,6 +31,11 @@ #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout) #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) +#define sta_meets_rssi_threshold(sta, sdata) \ + (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ + (s8) -ewma_read(&sta->avg_signal) > \ + sdata->u.mesh.mshcfg.rssi_threshold) + enum plink_event { PLINK_UNDEFINED, OPN_ACPT, @@ -301,7 +306,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, if (mesh_peer_accepts_plinks(elems) && sta->plink_state == NL80211_PLINK_LISTEN && sdata->u.mesh.accepting_plinks && - sdata->u.mesh.mshcfg.auto_open_plinks) + sdata->u.mesh.mshcfg.auto_open_plinks && + sta_meets_rssi_threshold(sta, sdata)) mesh_plink_open(sta); rcu_read_unlock(); @@ -531,6 +537,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } + if (ftype == WLAN_SP_MESH_PEERING_OPEN && + !sta_meets_rssi_threshold(sta, sdata)) { + mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n", + sta->sta.addr); + rcu_read_unlock(); + return; + } + if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); rcu_read_unlock(); diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 9d3e3b6bfcf..ba21ab22187 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -23,6 +23,8 @@ #define MESH_PERR_MIN_INT 100 #define MESH_DIAM_TRAVERSAL_TIME 50 +#define MESH_RSSI_THRESHOLD 0 + /* * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds * before timing out. This way it will remain ACTIVE and no data frames @@ -56,6 +58,7 @@ const struct mesh_config default_mesh_config = { .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL, .dot11MeshGateAnnouncementProtocol = false, .dot11MeshForwarding = true, + .rssi_threshold = MESH_RSSI_THRESHOLD, }; const struct mesh_setup default_mesh_setup = { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1998c368277..25a470abd21 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3290,6 +3290,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, cur_params.dot11MeshGateAnnouncementProtocol); NLA_PUT_U8(msg, NL80211_MESHCONF_FORWARDING, cur_params.dot11MeshForwarding); + NLA_PUT_U32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, + cur_params.rssi_threshold); nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); return genlmsg_reply(msg, info); @@ -3322,6 +3324,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, + [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32}, }; static const struct nla_policy @@ -3413,6 +3416,8 @@ do {\ nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, + mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32); if (mask_out) *mask_out = mask; -- cgit v1.2.3-70-g09d2 From 4d196e4b2ffd734393b54f351507462f19d737b5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 1 Mar 2012 11:23:37 +0100 Subject: mac80211: use 16 bit alignment for the if_ibss bssid field Several MAC address comparison functions assume 16 bit alignment for pointers passed to them. Since the addition of the control_port field, alignment for the IBSS bssid was off by one, causing a severe performance hit on architectures without efficient unaligned access (e.g. MIPS). Signed-off-by: Felix Fietkau Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cee0c7493fd..c4130588b03 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -480,7 +480,7 @@ struct ieee80211_if_ibss { bool control_port; - u8 bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN] __aligned(2); u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len, ie_len; u8 *ie; -- cgit v1.2.3-70-g09d2 From 888d04dfbe7e09f930fdaafb257cce2c54c9c3f3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 1 Mar 2012 15:22:09 +0100 Subject: mac80211: use compare_ether_addr on MAC addresses instead of memcmp Because of the constant size and guaranteed 16 bit alignment, the inline compare_ether_addr function is much cheaper than calling memcmp. Signed-off-by: Felix Fietkau Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 10 +++++----- net/mac80211/mesh.c | 2 +- net/mac80211/mesh_hwmp.c | 19 +++++++++++-------- net/mac80211/mesh_pathtbl.c | 14 ++++++++------ net/mac80211/mlme.c | 30 ++++++++++++++++-------------- net/mac80211/rx.c | 6 +++--- net/mac80211/scan.c | 3 ++- net/mac80211/sta_info.c | 5 +++-- net/mac80211/sta_info.h | 3 ++- net/mac80211/status.c | 3 ++- 10 files changed, 53 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 7f9ac577600..33fd8d9f714 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -66,7 +66,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, skb_reset_tail_pointer(skb); skb_reserve(skb, sdata->local->hw.extra_tx_headroom); - if (memcmp(ifibss->bssid, bssid, ETH_ALEN)) + if (compare_ether_addr(ifibss->bssid, bssid)) sta_info_flush(sdata->local, sdata); /* if merging, indicate to driver that we leave the old IBSS */ @@ -403,7 +403,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, return; if (sdata->vif.type == NL80211_IFTYPE_ADHOC && - memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) { + compare_ether_addr(mgmt->bssid, sdata->u.ibss.bssid) == 0) { rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); @@ -508,7 +508,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* same BSSID */ - if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) + if (compare_ether_addr(cbss->bssid, sdata->u.ibss.bssid) == 0) goto put_bss; if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { @@ -831,8 +831,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) return; - if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && - memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) + if (compare_ether_addr(mgmt->bssid, ifibss->bssid) != 0 && + !is_broadcast_ether_addr(mgmt->bssid)) return; end = ((u8 *) mgmt) + len; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c707c8bf6d2..e5fbb7cf356 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -204,7 +204,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, kmem_cache_free(rm_cache, p); --entries; } else if ((seqnum == p->seqnum) && - (memcmp(sa, p->sa, ETH_ALEN) == 0)) + (compare_ether_addr(sa, p->sa) == 0)) return -1; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 639db14f43d..ae82ea75bc7 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -8,6 +8,7 @@ */ #include +#include #include #include "wme.h" #include "mesh.h" @@ -419,7 +420,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, new_metric = MAX_METRIC; exp_time = TU_TO_EXP_TIME(orig_lifetime); - if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) { + if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0) { /* This MP is the originator, we are not interested in this * frame, except for updating transmitter's path info. */ @@ -469,7 +470,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, /* Update and check transmitter routing info */ ta = mgmt->sa; - if (memcmp(orig_addr, ta, ETH_ALEN) == 0) + if (compare_ether_addr(orig_addr, ta) == 0) fresh_info = false; else { fresh_info = true; @@ -530,7 +531,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, mhwmp_dbg("received PREQ from %pM", orig_addr); - if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) { + if (compare_ether_addr(target_addr, sdata->vif.addr) == 0) { mhwmp_dbg("PREQ is for us"); forward = false; reply = true; @@ -627,7 +628,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem)); orig_addr = PREP_IE_ORIG_ADDR(prep_elem); - if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) + if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0) /* destination, no forwarding required */ return; @@ -697,10 +698,12 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); mpath = mesh_path_lookup(target_addr, sdata); if (mpath) { + struct sta_info *sta; + spin_lock_bh(&mpath->state_lock); + sta = next_hop_deref_protected(mpath); if (mpath->flags & MESH_PATH_ACTIVE && - memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, - ETH_ALEN) == 0 && + compare_ether_addr(ta, sta->sta.addr) == 0 && (!(mpath->flags & MESH_PATH_SN_VALID) || SN_GT(target_sn, mpath->sn))) { mpath->flags &= ~MESH_PATH_ACTIVE; @@ -742,7 +745,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, metric = rann->rann_metric; /* Ignore our own RANNs */ - if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) + if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0) return; mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)", @@ -1074,7 +1077,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, if (time_after(jiffies, mpath->exp_time - msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && - !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) && + !compare_ether_addr(sdata->vif.addr, hdr->addr4) && !(mpath->flags & MESH_PATH_RESOLVING) && !(mpath->flags & MESH_PATH_FIXED)) mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index dc51669e67d..157642f780b 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -348,7 +348,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst, hlist_for_each_entry_rcu(node, n, bucket, list) { mpath = node->mpath; if (mpath->sdata == sdata && - memcmp(dst, mpath->dst, ETH_ALEN) == 0) { + compare_ether_addr(dst, mpath->dst) == 0) { if (MPATH_EXPIRED(mpath)) { spin_lock_bh(&mpath->state_lock); mpath->flags &= ~MESH_PATH_ACTIVE; @@ -523,7 +523,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) + if (compare_ether_addr(dst, sdata->vif.addr) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -564,7 +564,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { mpath = node->mpath; - if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0) + if (mpath->sdata == sdata && + compare_ether_addr(dst, mpath->dst) == 0) goto err_exists; } @@ -655,7 +656,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0) + if (compare_ether_addr(dst, sdata->vif.addr) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -692,7 +693,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { mpath = node->mpath; - if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0) + if (mpath->sdata == sdata && + compare_ether_addr(dst, mpath->dst) == 0) goto err_exists; } @@ -886,7 +888,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) hlist_for_each_entry(node, n, bucket, list) { mpath = node->mpath; if (mpath->sdata == sdata && - memcmp(addr, mpath->dst, ETH_ALEN) == 0) { + compare_ether_addr(addr, mpath->dst) == 0) { __mesh_path_del(tbl, node); goto enddel; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index caf97f5a293..7190da4f213 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1822,7 +1822,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); - if (memcmp(bssid, mgmt->bssid, ETH_ALEN)) + if (compare_ether_addr(bssid, mgmt->bssid)) return RX_MGMT_NONE; auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); @@ -1903,7 +1903,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; if (!ifmgd->associated || - memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) + compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid)) return RX_MGMT_NONE; bssid = ifmgd->associated->bssid; @@ -1936,7 +1936,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; if (!ifmgd->associated || - memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) + compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid)) return RX_MGMT_NONE; reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); @@ -2203,7 +2203,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (!assoc_data) return RX_MGMT_NONE; - if (memcmp(assoc_data->bss->bssid, mgmt->bssid, ETH_ALEN)) + if (compare_ether_addr(assoc_data->bss->bssid, mgmt->bssid)) return RX_MGMT_NONE; /* @@ -2291,8 +2291,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bool need_ps = false; if (sdata->u.mgd.associated && - memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, - ETH_ALEN) == 0) { + compare_ether_addr(mgmt->bssid, sdata->u.mgd.associated->bssid) + == 0) { bss = (void *)sdata->u.mgd.associated->priv; /* not previously set so we may need to recalc */ need_ps = !bss->dtim_period; @@ -2347,7 +2347,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ASSERT_MGD_MTX(ifmgd); - if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) + if (compare_ether_addr(mgmt->da, sdata->vif.addr)) return; /* ignore ProbeResp to foreign address */ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; @@ -2360,11 +2360,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); if (ifmgd->associated && - memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) + compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid) == 0) ieee80211_reset_ap_probe(sdata); if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies && - memcmp(mgmt->bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN) == 0) { + compare_ether_addr(mgmt->bssid, ifmgd->auth_data->bss->bssid) + == 0) { /* got probe response, continue with auth */ printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); ifmgd->auth_data->tries = 0; @@ -2421,7 +2422,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, return; if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && - memcmp(mgmt->bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN) == 0) { + compare_ether_addr(mgmt->bssid, ifmgd->assoc_data->bss->bssid) + == 0) { ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); @@ -2436,7 +2438,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (!ifmgd->associated || - memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) + compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid)) return; bssid = ifmgd->associated->bssid; @@ -3299,7 +3301,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, bool match; /* keep sta info, bssid if matching */ - match = memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN) == 0; + match = compare_ether_addr(ifmgd->bssid, req->bss->bssid) == 0; ieee80211_destroy_auth_data(sdata, match); } @@ -3421,7 +3423,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, goto err_clear; } } else - WARN_ON_ONCE(memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN)); + WARN_ON_ONCE(compare_ether_addr(ifmgd->bssid, req->bss->bssid)); if (!bss->dtim_period && sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { @@ -3471,7 +3473,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, sdata->name, req->bssid, req->reason_code); if (ifmgd->associated && - memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) + compare_ether_addr(ifmgd->associated->bssid, req->bssid) == 0) ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, req->reason_code, true, frame_buf); else diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7a4ff02af26..3cf011fc97f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -489,12 +489,12 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_has_tods(hdr->frame_control) || !ieee80211_has_fromds(hdr->frame_control)) return RX_DROP_MONITOR; - if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0) + if (compare_ether_addr(hdr->addr3, dev_addr) == 0) return RX_DROP_MONITOR; } else { if (!ieee80211_has_a4(hdr->frame_control)) return RX_DROP_MONITOR; - if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0) + if (compare_ether_addr(hdr->addr4, dev_addr) == 0) return RX_DROP_MONITOR; } } @@ -2336,7 +2336,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (sdata->vif.type != NL80211_IFTYPE_STATION) break; - if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) + if (compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid)) break; goto queue; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 9270771702f..a9d7235df7c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -176,7 +177,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) presp = ieee80211_is_probe_resp(fc); if (presp) { /* ignore ProbeResp to foreign address */ - if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN)) + if (compare_ether_addr(mgmt->da, sdata->vif.addr)) return RX_DROP_MONITOR; presp = true; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cd0f265f42e..38137cb5f6f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -101,7 +102,7 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, lockdep_is_held(&local->sta_mtx)); while (sta) { if (sta->sdata == sdata && - memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) + compare_ether_addr(sta->sta.addr, addr) == 0) break; sta = rcu_dereference_check(sta->hnext, lockdep_is_held(&local->sta_mtx)); @@ -124,7 +125,7 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, while (sta) { if ((sta->sdata == sdata || (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && - memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) + compare_ether_addr(sta->sta.addr, addr) == 0) break; sta = rcu_dereference_check(sta->hnext, lockdep_is_held(&local->sta_mtx)); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 23a97c9dc04..3336d54e555 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "key.h" /** @@ -489,7 +490,7 @@ void for_each_sta_info_type_check(struct ieee80211_local *local, nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ ) \ /* compare address and run code only if it matches */ \ - if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0) + if (compare_ether_addr(_sta->sta.addr, (_addr)) == 0) /* * Get STA info by index, BROKEN! diff --git a/net/mac80211/status.c b/net/mac80211/status.c index c928e4a4eff..5f8f89e89d6 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include "ieee80211_i.h" @@ -377,7 +378,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) for_each_sta_info(local, hdr->addr1, sta, tmp) { /* skip wrong virtual interface */ - if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) + if (compare_ether_addr(hdr->addr2, sta->sdata->vif.addr)) continue; if (info->flags & IEEE80211_TX_STATUS_EOSP) -- cgit v1.2.3-70-g09d2 From fe8431f89e25de722610ee5beb2892bd019d1fed Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 1 Mar 2012 18:00:07 +0100 Subject: mac80211: add an rx flag for ignoring a packet's signal strength For A-MPDU rx it makes sense to only process the signal strength once per aggregate instead of once per subframe. Additonally, some hardware (e.g. Atheros) only provides valid signal strength information for the last subframe. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 +++ net/mac80211/rx.c | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7477f020ee7..c06974accfa 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -659,6 +659,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index * @RX_FLAG_40MHZ: HT40 (40 MHz) was used * @RX_FLAG_SHORT_GI: Short guard interval was used + * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present. + * Valid only for data frames (mainly A-MPDU) */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -672,6 +674,7 @@ enum mac80211_rx_flags { RX_FLAG_HT = 1<<9, RX_FLAG_40MHZ = 1<<10, RX_FLAG_SHORT_GI = 1<<11, + RX_FLAG_NO_SIGNAL_VAL = 1<<12, }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3cf011fc97f..f3b515d16f2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -177,7 +177,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos += 2; /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ - if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM && + !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { *pos = status->signal; rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); @@ -1309,8 +1310,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; - sta->last_signal = status->signal; - ewma_add(&sta->avg_signal, -status->signal); + if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { + sta->last_signal = status->signal; + ewma_add(&sta->avg_signal, -status->signal); + } /* * Change STA power saving mode only at the end of a frame -- cgit v1.2.3-70-g09d2 From 77a1abf54f4b003ad6e59c535045b2ad89fedfeb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 5 Mar 2012 04:50:09 +0000 Subject: net: export netdev_stats_to_stats64 Some drivers use internal netdev stats member to store part of their stats, yet advertize ndo_get_stats64() to implement some 64bit fields. Allow them to use netdev_stats_to_stats64() helper to make the copy of netdev stats before they compute their 64bit counters. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f1b7d037c2c..4d279c5287f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2557,6 +2557,8 @@ extern void dev_load(struct net *net, const char *name); extern void dev_mcast_init(void); extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, struct rtnl_link_stats64 *storage); +extern void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, + const struct net_device_stats *netdev_stats); extern int netdev_max_backlog; extern int netdev_tstamp_prequeue; diff --git a/net/core/dev.c b/net/core/dev.c index 763a0eda715..5ef3b65c368 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5834,12 +5834,12 @@ void netdev_run_todo(void) /* Convert net_device_stats to rtnl_link_stats64. They have the same * fields in the same order, with only the type differing. */ -static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, - const struct net_device_stats *netdev_stats) +void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, + const struct net_device_stats *netdev_stats) { #if BITS_PER_LONG == 64 - BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats)); - memcpy(stats64, netdev_stats, sizeof(*stats64)); + BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats)); + memcpy(stats64, netdev_stats, sizeof(*stats64)); #else size_t i, n = sizeof(*stats64) / sizeof(u64); const unsigned long *src = (const unsigned long *)netdev_stats; @@ -5851,6 +5851,7 @@ static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, dst[i] = src[i]; #endif } +EXPORT_SYMBOL(netdev_stats_to_stats64); /** * dev_get_stats - get network device statistics -- cgit v1.2.3-70-g09d2 From d665508b98d3cdbeb476e7d6848a513184a81ed0 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 2 Mar 2012 02:03:19 +0800 Subject: mac80211: fix the support of setting non-forwarding entity in Mesh RANN, PREP and PERR propagation should happen only if the dot11MeshForwarding is true. Besides, data frame should not be forwarded if dot11MeshForwarding is false. This redundant checking is necessary to avoid the broadcasted ARP breaking the non-forwarding rule. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 9 ++++++++- net/mac80211/rx.c | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index ae82ea75bc7..4a993f2d1ae 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -619,6 +619,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, u8 *prep_elem, u32 metric) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; u8 *target_addr, *orig_addr; u8 ttl, hopcount, flags; @@ -632,6 +633,9 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, /* destination, no forwarding required */ return; + if (!ifmsh->mshcfg.dot11MeshForwarding) + return; + ttl = PREP_IE_TTL(prep_elem); if (ttl <= 1) { sdata->u.mesh.mshstats.dropped_frames_ttl++; @@ -709,12 +713,15 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, mpath->flags &= ~MESH_PATH_ACTIVE; mpath->sn = target_sn; spin_unlock_bh(&mpath->state_lock); + if (!ifmsh->mshcfg.dot11MeshForwarding) + goto endperr; mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), cpu_to_le16(target_rcode), broadcast_addr, sdata); } else spin_unlock_bh(&mpath->state_lock); } +endperr: rcu_read_unlock(); } @@ -771,7 +778,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); } - if (mpath->sn < orig_sn) { + if (mpath->sn < orig_sn && ifmsh->mshcfg.dot11MeshForwarding) { mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, cpu_to_le32(orig_sn), 0, NULL, 0, broadcast_addr, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f3b515d16f2..c8166adcd60 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1960,6 +1960,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; } + if (!ifmsh->mshcfg.dot11MeshForwarding) + goto out; + fwd_skb = skb_copy(skb, GFP_ATOMIC); if (!fwd_skb) { if (net_ratelimit()) -- cgit v1.2.3-70-g09d2 From 1b658f118b11de3c4052ed8cbdd5803cd1fa5670 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 2 Mar 2012 15:50:02 +0530 Subject: cfg80211: Add an attribute to set inactivity timeout in AP mode This patch adds an attribute, NL80211_ATTR_INACTIVITY_TIMEOUT, to set the inactivity timeout which can be used to remove the station in AP mode. This can be passed in NL80211_CMD_START_AP and used by the drivers which have AP MLME in firmware but don't support get_station() properly. To disable inactivity timer in userspace, wpa_s for example, there is a new flag, NL80211_FEATURE_INACTIVITY_TIMER, in nl80211_feature_flags through which drivers can register their capability to use the inactivity timeout to free the stations. Signed-off-by: Vasanthakumar Thiagarajan Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 15 +++++++++++++-- include/net/cfg80211.h | 2 ++ net/wireless/nl80211.c | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 38fda5ee57f..9f46c62b1ee 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -168,8 +168,8 @@ * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID, * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, - * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY and - * %NL80211_ATTR_AUTH_TYPE. + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, + * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT. * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP @@ -1197,6 +1197,12 @@ enum nl80211_commands { * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of * up to 16 TIDs. * + * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be + * used by the drivers which has MLME in firmware and does not have support + * to report per station tx/rx activity to free up the staion entry from + * the list. This needs to be used when the driver advertises the + * capability to timeout the stations. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1442,6 +1448,8 @@ enum nl80211_attrs { NL80211_ATTR_NOACK_MAP, + NL80211_ATTR_INACTIVITY_TIMEOUT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2809,10 +2817,13 @@ enum nl80211_ap_sme_features { * TX status to the socket error queue when requested with the * socket option. * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates. + * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up + * the connected inactive stations in AP mode. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, NL80211_FEATURE_HT_IBSS = 1 << 1, + NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, }; /** diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d640a39d951..80480582773 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -413,6 +413,7 @@ struct cfg80211_beacon_data { * @crypto: crypto settings * @privacy: the BSS uses privacy * @auth_type: Authentication type (algorithm) + * @inactivity_timeout: time in seconds to determine station's inactivity. */ struct cfg80211_ap_settings { struct cfg80211_beacon_data beacon; @@ -424,6 +425,7 @@ struct cfg80211_ap_settings { struct cfg80211_crypto_settings crypto; bool privacy; enum nl80211_auth_type auth_type; + int inactivity_timeout; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 25a470abd21..4b6afc338aa 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -204,6 +204,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { .len = NL80211_HT_CAPABILITY_LEN }, [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, + [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, }; /* policy for the key attributes */ @@ -2214,6 +2215,13 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (err) return err; + if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) { + if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) + return -EOPNOTSUPP; + params.inactivity_timeout = nla_get_u16( + info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); + } + err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); if (!err) wdev->beacon_interval = params.beacon_interval; -- cgit v1.2.3-70-g09d2 From 293702a3fb75832613e2af097bdc3ac8ef775b33 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Mar 2012 13:18:19 +0100 Subject: mac80211: use common radiotap code for cooked monitors There's no need to hardcode a subset of the radiotap header for cooked monitor receive, we can just reuse the normal monitor mode radiotap code. This simplifies the code and extends the information available on cooked monitor interfaces. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c8166adcd60..10bbbd33b31 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -228,7 +228,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); struct ieee80211_sub_if_data *sdata; - int needed_headroom = 0; + int needed_headroom; struct sk_buff *skb, *skb2; struct net_device *prev_dev = NULL; int present_fcs_len = 0; @@ -2544,16 +2544,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, { struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = rx->local; - struct ieee80211_rtap_hdr { - struct ieee80211_radiotap_header hdr; - u8 flags; - u8 rate_or_pad; - __le16 chan_freq; - __le16 chan_flags; - } __packed *rthdr; struct sk_buff *skb = rx->skb, *skb2; struct net_device *prev_dev = NULL; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + int needed_headroom; /* * If cooked monitor has been processed already, then @@ -2567,30 +2561,15 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, if (!local->cooked_mntrs) goto out_free_skb; - if (skb_headroom(skb) < sizeof(*rthdr) && - pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) - goto out_free_skb; - - rthdr = (void *)skb_push(skb, sizeof(*rthdr)); - memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_CHANNEL)); + /* room for the radiotap header based on driver features */ + needed_headroom = ieee80211_rx_radiotap_len(local, status); - if (rate) { - rthdr->rate_or_pad = rate->bitrate / 5; - rthdr->hdr.it_present |= - cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); - } - rthdr->chan_freq = cpu_to_le16(status->freq); + if (skb_headroom(skb) < needed_headroom && + pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) + goto out_free_skb; - if (status->band == IEEE80211_BAND_5GHZ) - rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ); - else - rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN | - IEEE80211_CHAN_2GHZ); + /* prepend radiotap information */ + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); skb_set_mac_header(skb, 0); skb->ip_summed = CHECKSUM_UNNECESSARY; -- cgit v1.2.3-70-g09d2 From 3abead59fcdeb56df8b83288a2f5edbe6423b0bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Mar 2012 15:56:59 +0100 Subject: mac80211: combine QoS with other BSS changes When associating and particularly when disassociating there's no need to notify the driver about changes with multiple calls to bss_info_changed, we should combine the QoS enabling/disabling into the same call as otherwise the driver could get confused about QoS suddenly getting disabled while connected. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/iface.c | 2 +- net/mac80211/mlme.c | 12 ++++++++---- net/mac80211/util.c | 9 ++++++--- 4 files changed, 17 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c4130588b03..24cb1080e23 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1348,7 +1348,8 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, struct ieee80211_hdr *hdr, const u8 *tsc, gfp_t gfp); -void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); +void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, + bool bss_notify); void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 620ca8d2ad4..401c01f0731 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -304,7 +304,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) * need to initialise the hardware if the hardware * doesn't start up with sane defaults */ - ieee80211_set_wmm_default(sdata); + ieee80211_set_wmm_default(sdata, true); } set_bit(SDATA_STATE_RUNNING, &sdata->state); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7190da4f213..92c5eb124d6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1277,7 +1277,6 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, /* enable WMM or activate new settings */ sdata->vif.bss_conf.qos = true; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); } static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, @@ -1455,8 +1454,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ASSOC; sdata->vif.bss_conf.assoc = false; - ieee80211_set_wmm_default(sdata); - /* channel(_type) changes are handled by ieee80211_hw_config */ WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT)); @@ -1484,10 +1481,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ARP_FILTER; } + sdata->vif.bss_conf.qos = false; + changed |= BSS_CHANGED_QOS; + /* The BSSID (not really interesting) and HT changed */ changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); + /* disassociated - set to defaults now */ + ieee80211_set_wmm_default(sdata, false); + del_timer_sync(&sdata->u.mgd.conn_mon_timer); del_timer_sync(&sdata->u.mgd.bcn_mon_timer); del_timer_sync(&sdata->u.mgd.timer); @@ -2155,7 +2158,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, elems.wmm_param_len); else - ieee80211_set_wmm_default(sdata); + ieee80211_set_wmm_default(sdata, false); + changed |= BSS_CHANGED_QOS; if (elems.ht_info_elem && elems.wmm_param && (sdata->local->hw.queues >= 4) && diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f6e4cef9202..0a5ad95ac8b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -737,7 +737,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len, ieee802_11_parse_elems_crc(start, len, elems, 0, 0); } -void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) +void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, + bool bss_notify) { struct ieee80211_local *local = sdata->local; struct ieee80211_tx_queue_params qparam; @@ -807,7 +808,9 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { sdata->vif.bss_conf.qos = sdata->vif.type != NL80211_IFTYPE_STATION; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); + if (bss_notify) + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_QOS); } } @@ -829,7 +832,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - ieee80211_set_wmm_default(sdata); + ieee80211_set_wmm_default(sdata, true); } u32 ieee80211_mandatory_rates(struct ieee80211_local *local, -- cgit v1.2.3-70-g09d2 From d1d81d4c3dd886d5fa25a2c4fa1e39cb89613712 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Mon, 5 Mar 2012 04:52:44 +0000 Subject: bridge: check return value of ipv6_dev_get_saddr() otherwise source IPv6 address of ICMPV6_MGM_QUERY packet might be random junk if IPv6 is disabled on interface or link-local address is not yet ready (DAD). Signed-off-by: Ulrich Weber Signed-off-by: David S. Miller --- net/bridge/br_multicast.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 568d5bf1753..702a1ae9220 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -446,8 +446,11 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, ip6h->nexthdr = IPPROTO_HOPOPTS; ip6h->hop_limit = 1; ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1)); - ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, - &ip6h->saddr); + if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, + &ip6h->saddr)) { + kfree_skb(skb); + return NULL; + } ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); hopopt = (u8 *)(ip6h + 1); -- cgit v1.2.3-70-g09d2 From 4648dc97af9d496218a05353b0e442b3dfa6aaab Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Mon, 5 Mar 2012 19:35:04 +0000 Subject: tcp: fix tcp_shift_skb_data() to not shift SACKed data below snd_una This commit fixes tcp_shift_skb_data() so that it does not shift SACKed data below snd_una. This fixes an issue whose symptoms exactly match reports showing tp->sacked_out going negative since 3.3.0-rc4 (see "WARNING: at net/ipv4/tcp_input.c:3418" thread on netdev). Since 2008 (832d11c5cd076abc0aa1eaf7be96c81d1a59ce41) tcp_shift_skb_data() had been shifting SACKed ranges that were below snd_una. It checked that the *end* of the skb it was about to shift from was above snd_una, but did not check that the end of the actual shifted range was above snd_una; this commit adds that check. Shifting SACKed ranges below snd_una is problematic because for such ranges tcp_sacktag_one() short-circuits: it does not declare anything as SACKed and does not increase sacked_out. Before the fixes in commits cc9a672ee522d4805495b98680f4a3db5d0a0af9 and daef52bab1fd26e24e8e9578f8fb33ba1d0cb412, shifting SACKed ranges below snd_una happened to work because tcp_shifted_skb() was always (incorrectly) passing in to tcp_sacktag_one() an skb whose end_seq tcp_shift_skb_data() had already guaranteed was beyond snd_una. Hence tcp_sacktag_one() never short-circuited and always increased tp->sacked_out in this case. After those two fixes, my testing has verified that shifting SACKed ranges below snd_una could cause tp->sacked_out to go negative with the following sequence of events: (1) tcp_shift_skb_data() sees an skb whose end_seq is beyond snd_una, then shifts a prefix of that skb that is below snd_una (2) tcp_shifted_skb() increments the packet count of the already-SACKed prev sk_buff (3) tcp_sacktag_one() sees the end of the new SACKed range is below snd_una, so it short-circuits and doesn't increase tp->sacked_out (5) tcp_clean_rtx_queue() sees the SACKed skb has been ACKed, decrements tp->sacked_out by this "inflated" pcount that was missing a matching increase in tp->sacked_out, and hence tp->sacked_out underflows to a u32 like 0xFFFFFFFF, which casted to s32 is negative. (6) this leads to the warnings seen in the recent "WARNING: at net/ipv4/tcp_input.c:3418" thread on the netdev list; e.g.: tcp_input.c:3418 WARN_ON((int)tp->sacked_out < 0); More generally, I think this bug can be tickled in some cases where two or more ACKs from the receiver are lost and then a DSACK arrives that is immediately above an existing SACKed skb in the write queue. This fix changes tcp_shift_skb_data() to abort this sequence at step (1) in the scenario above by noticing that the bytes are below snd_una and not shifting them. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d9b83d198c3..b5e315f1364 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1585,6 +1585,10 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, } } + /* tcp_sacktag_one() won't SACK-tag ranges below snd_una */ + if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una)) + goto fallback; + if (!skb_shift(prev, skb, len)) goto fallback; if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack)) -- cgit v1.2.3-70-g09d2 From 848edc69192a38bf9d261032f248b14f47e6af8b Mon Sep 17 00:00:00 2001 From: Santosh Nayak Date: Tue, 6 Mar 2012 01:22:50 +0000 Subject: netfilter: ebtables: fix wrong name length while copying to user-space user-space ebtables expects 32 bytes-long names, but xt_match names use 29 bytes. We have to copy less 29 bytes and then, make sure we fill the remaining bytes with zeroes. Signed-off-by: Santosh Nayak Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/bridge/netfilter/ebtables.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 8aa4ad0e06a..15e9575f720 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1335,7 +1335,12 @@ static inline int ebt_make_matchname(const struct ebt_entry_match *m, const char *base, char __user *ubase) { char __user *hlp = ubase + ((char *)m - base); - if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) + char name[EBT_FUNCTION_MAXNAMELEN] = {}; + + /* ebtables expects 32 bytes long names but xt_match names are 29 bytes + long. Copy 29 bytes and fill remaining bytes with zeroes. */ + strncpy(name, m->u.match->name, sizeof(name)); + if (copy_to_user(hlp, name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; } @@ -1344,7 +1349,10 @@ static inline int ebt_make_watchername(const struct ebt_entry_watcher *w, const char *base, char __user *ubase) { char __user *hlp = ubase + ((char *)w - base); - if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) + char name[EBT_FUNCTION_MAXNAMELEN] = {}; + + strncpy(name, w->u.watcher->name, sizeof(name)); + if (copy_to_user(hlp , name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; } @@ -1355,10 +1363,12 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase) int ret; char __user *hlp; const struct ebt_entry_target *t; + char name[EBT_FUNCTION_MAXNAMELEN] = {}; if (e->bitmask == 0) return 0; + strncpy(name, t->u.target->name, sizeof(name)); hlp = ubase + (((char *)e + e->target_offset) - base); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); @@ -1368,7 +1378,7 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase) ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase); if (ret != 0) return ret; - if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN)) + if (copy_to_user(hlp, name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; } -- cgit v1.2.3-70-g09d2 From 8be619d1e430fd87a02587a2a6830b692cb91b84 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 6 Mar 2012 01:22:51 +0000 Subject: netfilter: ctnetlink: remove incorrect spin_[un]lock_bh on NAT module autoload Since 7d367e0, ctnetlink_new_conntrack is called without holding the nf_conntrack_lock spinlock. Thus, ctnetlink_parse_nat_setup does not require to release that spinlock anymore in the NAT module autoload case. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_netlink.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 30c9d4ca021..10687692831 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1041,16 +1041,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct, if (!parse_nat_setup) { #ifdef CONFIG_MODULES rcu_read_unlock(); - spin_unlock_bh(&nf_conntrack_lock); nfnl_unlock(); if (request_module("nf-nat-ipv4") < 0) { nfnl_lock(); - spin_lock_bh(&nf_conntrack_lock); rcu_read_lock(); return -EOPNOTSUPP; } nfnl_lock(); - spin_lock_bh(&nf_conntrack_lock); rcu_read_lock(); if (nfnetlink_parse_nat_setup_hook) return -EAGAIN; -- cgit v1.2.3-70-g09d2 From a157b9d5b5b626e46eba2ac4e342da8db25cabc4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 6 Mar 2012 01:22:53 +0000 Subject: netfilter: bridge: fix wrong pointer dereference In adf7ff8, a invalid dereference was added in ebt_make_names. CC [M] net/bridge/netfilter/ebtables.o net/bridge/netfilter/ebtables.c: In function `ebt_make_names': net/bridge/netfilter/ebtables.c:1371:20: warning: `t' may be used uninitialized in this function [-Wuninitialized] Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/bridge/netfilter/ebtables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 15e9575f720..5fe2ff3b01e 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1368,7 +1368,6 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase) if (e->bitmask == 0) return 0; - strncpy(name, t->u.target->name, sizeof(name)); hlp = ubase + (((char *)e + e->target_offset) - base); t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); @@ -1378,6 +1377,7 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase) ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase); if (ret != 0) return ret; + strncpy(name, t->u.target->name, sizeof(name)); if (copy_to_user(hlp, name, EBT_FUNCTION_MAXNAMELEN)) return -EFAULT; return 0; -- cgit v1.2.3-70-g09d2 From 739e4505a0e8209622dc71743bfa1c804eacf7f4 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Mar 2012 01:22:54 +0000 Subject: bridge: netfilter: don't call iptables on vlan packets if sysctl is off When net.bridge.bridge-nf-filter-vlan-tagged is 0 (default), vlan packets arriving should not be sent to ip(6)tables by bridge netfilter. However, it turns out that we currently always send VLAN packets to netfilter, if .. a), CONFIG_VLAN_8021Q is enabled ; or b), CONFIG_VLAN_8021Q is not set but rx vlan offload is enabled on the bridge port. This is because bridge netfilter treats skb with skb->protocol == ETH_P_IP{V6} as "non-vlan packet". With rx vlan offload on or CONFIG_VLAN_8021Q=y, the vlan header has already been removed here, and we cannot rely on skb->protocol alone. Fix this by only using skb->protocol if the skb has no vlan tag, or if a vlan tag is present and filter-vlan-tagged bridge netfilter sysctl is enabled. We cannot remove the skb->protocol == htons(ETH_P_8021Q) test because the vlan tag is still around in the CONFIG_VLAN_8021Q=n && "ethtool -K $itf rxvlan off" case. reproducer: iptables -t raw -I PREROUTING -i br0 iptables -t raw -I PREROUTING -i br0.1 Then send packets to an ip address configured on br0.1 interface. Even with net.bridge.bridge-nf-filter-vlan-tagged=0, the 1st rule will match instead of the 2nd one. With this patch applied, the 2nd rule will match instead. In the non-local address case, netfilter won't be consulted after this patch unless the sysctl is switched on. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/bridge/br_netfilter.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 84122472656..dec4f381713 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -62,6 +62,15 @@ static int brnf_filter_pppoe_tagged __read_mostly = 0; #define brnf_filter_pppoe_tagged 0 #endif +#define IS_IP(skb) \ + (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_IP)) + +#define IS_IPV6(skb) \ + (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_IPV6)) + +#define IS_ARP(skb) \ + (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_ARP)) + static inline __be16 vlan_proto(const struct sk_buff *skb) { if (vlan_tx_tag_present(skb)) @@ -639,8 +648,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, return NF_DROP; br = p->br; - if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || - IS_PPPOE_IPV6(skb)) { + if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) { if (!brnf_call_ip6tables && !br->nf_call_ip6tables) return NF_ACCEPT; @@ -651,8 +659,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, if (!brnf_call_iptables && !br->nf_call_iptables) return NF_ACCEPT; - if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) && - !IS_PPPOE_IP(skb)) + if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb)) return NF_ACCEPT; nf_bridge_pull_encap_header_rcsum(skb); @@ -701,7 +708,7 @@ static int br_nf_forward_finish(struct sk_buff *skb) struct nf_bridge_info *nf_bridge = skb->nf_bridge; struct net_device *in; - if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP(skb)) { + if (!IS_ARP(skb) && !IS_VLAN_ARP(skb)) { in = nf_bridge->physindev; if (nf_bridge->mask & BRNF_PKT_TYPE) { skb->pkt_type = PACKET_OTHERHOST; @@ -718,6 +725,7 @@ static int br_nf_forward_finish(struct sk_buff *skb) return 0; } + /* This is the 'purely bridged' case. For IP, we pass the packet to * netfilter with indev and outdev set to the bridge device, * but we are still able to filter on the 'real' indev/outdev @@ -744,11 +752,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, if (!parent) return NF_DROP; - if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) || - IS_PPPOE_IP(skb)) + if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb)) pf = PF_INET; - else if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || - IS_PPPOE_IPV6(skb)) + else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) pf = PF_INET6; else return NF_ACCEPT; @@ -795,7 +801,7 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb, if (!brnf_call_arptables && !br->nf_call_arptables) return NF_ACCEPT; - if (skb->protocol != htons(ETH_P_ARP)) { + if (!IS_ARP(skb)) { if (!IS_VLAN_ARP(skb)) return NF_ACCEPT; nf_bridge_pull_encap_header(skb); @@ -853,11 +859,9 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, if (!realoutdev) return NF_DROP; - if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) || - IS_PPPOE_IP(skb)) + if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb)) pf = PF_INET; - else if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || - IS_PPPOE_IPV6(skb)) + else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) pf = PF_INET6; else return NF_ACCEPT; -- cgit v1.2.3-70-g09d2 From 741385119706d4370eb7899c5ca96ad125c520e5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 6 Mar 2012 01:22:55 +0000 Subject: netfilter: nf_conntrack: fix early_drop with reliable event delivery If reliable event delivery is enabled and ctnetlink fails to deliver the destroy event in early_drop, the conntrack subsystem cannot drop any the candidate flow that was planned to be evicted. Reported-by: Kerin Millar Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index ed86a3be678..fa4b82c8ae8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -635,8 +635,12 @@ static noinline int early_drop(struct net *net, unsigned int hash) if (del_timer(&ct->timeout)) { death_by_timeout((unsigned long)ct); - dropped = 1; - NF_CT_STAT_INC_ATOMIC(net, early_drop); + /* Check if we indeed killed this entry. Reliable event + delivery may have inserted it into the dying list. */ + if (test_bit(IPS_DYING_BIT, &ct->status)) { + dropped = 1; + NF_CT_STAT_INC_ATOMIC(net, early_drop); + } } nf_ct_put(ct); return dropped; -- cgit v1.2.3-70-g09d2 From 804483e90794256f9ed53e795ffbf1e94de237c8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Mar 2012 22:18:41 +0100 Subject: cfg80211/mac80211: report signal strength for mgmt frames Add the signal strength (in dBm only for now) to frames that are received via nl80211's various frame APIs. Signed-off-by: Johannes Berg Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath6kl/wmi.c | 6 ++++-- include/linux/nl80211.h | 6 ++++++ include/net/cfg80211.h | 8 +++++--- net/mac80211/rx.c | 13 +++++++++++-- net/wireless/mlme.c | 7 ++++--- net/wireless/nl80211.c | 9 +++++++-- net/wireless/nl80211.h | 3 ++- 7 files changed, 39 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 18fa9aa8af9..97abf4699b4 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -556,7 +556,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, 0, + ev->data, dlen, GFP_ATOMIC); return 0; } @@ -595,7 +596,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, 0, + ev->data, dlen, GFP_ATOMIC); return 0; } diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 9f46c62b1ee..c37d67add09 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1203,6 +1203,10 @@ enum nl80211_commands { * the list. This needs to be used when the driver advertises the * capability to timeout the stations. * + * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int); + * this attribute is (depending on the driver capabilities) added to + * received frames indicated with %NL80211_CMD_FRAME. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1450,6 +1454,8 @@ enum nl80211_attrs { NL80211_ATTR_INACTIVITY_TIMEOUT, + NL80211_ATTR_RX_SIGNAL_DBM, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 80480582773..4682c35a92c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3189,6 +3189,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); * cfg80211_rx_mgmt - notification of received, unprocessed management frame * @dev: network device * @freq: Frequency on which the frame was received in MHz + * @sig_dbm: signal strength in mBm, or 0 if unknown * @buf: Management frame (header + body) * @len: length of the frame data * @gfp: context flags @@ -3201,8 +3202,8 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); * This function is called whenever an Action frame is received for a station * mode interface, but is not processed in kernel. */ -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, - size_t len, gfp_t gfp); +bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm, + const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_mgmt_tx_status - notification of TX status for management frame @@ -3315,6 +3316,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, * @frame: the frame * @len: length of the frame * @freq: frequency the frame was received on + * @sig_dbm: signal strength in mBm, or 0 if unknown * @gfp: allocation flags * * Use this function to report to userspace when a beacon was @@ -3323,7 +3325,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, */ void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, - int freq, gfp_t gfp); + int freq, int sig_dbm, gfp_t gfp); /* * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 10bbbd33b31..5f6e32ca085 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2188,9 +2188,14 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) if (rx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_beacon(mgmt->frame_control) && !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { + int sig = 0; + + if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + sig = status->signal; + cfg80211_report_obss_beacon(rx->local->hw.wiphy, rx->skb->data, rx->skb->len, - status->freq, GFP_ATOMIC); + status->freq, sig, GFP_ATOMIC); rx->flags |= IEEE80211_RX_BEACON_REPORTED; } @@ -2414,6 +2419,7 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + int sig = 0; /* skip known-bad action frames and return them in the next handler */ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) @@ -2426,7 +2432,10 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) * it transmitted were processed or returned. */ - if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, + if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + sig = status->signal; + + if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig, rx->skb->data, rx->skb->len, GFP_ATOMIC)) { if (rx->sta) diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index fb1e7217911..f5a7ac3a093 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -814,8 +814,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, cookie); } -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, - size_t len, gfp_t gfp) +bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, + const u8 *buf, size_t len, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -854,7 +854,8 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, /* found match! */ /* Indicate the received Action frame to user space */ - if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, + if (nl80211_send_mgmt(rdev, dev, reg->nlpid, + freq, sig_mbm, buf, len, gfp)) continue; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4b6afc338aa..39dbdf2adb1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7686,7 +7686,8 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 nlpid, - int freq, const u8 *buf, size_t len, gfp_t gfp) + int freq, int sig_dbm, + const u8 *buf, size_t len, gfp_t gfp) { struct sk_buff *msg; void *hdr; @@ -7704,6 +7705,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (sig_dbm) + NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm); NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); genlmsg_end(msg, hdr); @@ -7965,7 +7968,7 @@ EXPORT_SYMBOL(cfg80211_probe_status); void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, - int freq, gfp_t gfp) + int freq, int sig_dbm, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct sk_buff *msg; @@ -7988,6 +7991,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); if (freq) NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (sig_dbm) + NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm); NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame); genlmsg_end(msg, hdr); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 12bf4d185ab..4ffe50df9f3 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -92,7 +92,8 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, gfp_t gfp); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, int freq, + struct net_device *netdev, u32 nlpid, + int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, struct net_device *netdev, u64 cookie, -- cgit v1.2.3-70-g09d2 From 8097e1494459a4f9cdbaba7440334d9bd11a39f0 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 5 Mar 2012 15:31:47 -0800 Subject: cfg80211: expose cfg80211_calculate_bitrate() Signed-off-by: Thomas Pedersen Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 8 ++++++++ net/wireless/util.c | 1 + 2 files changed, 9 insertions(+) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4682c35a92c..57c9fddc2ac 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3337,6 +3337,14 @@ int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); +/* + * cfg80211_calculate_bitrate - calculate actual bitrate (in 100Kbps units) + * @rate: given rate_info to calculate bitrate from + * + * return 0 if MCS index >= 32 + */ +u16 cfg80211_calculate_bitrate(struct rate_info *rate); + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/net/wireless/util.c b/net/wireless/util.c index 9aa9db6c814..1b7a08df933 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -904,6 +904,7 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate) /* do NOT round down here */ return (bitrate + 50000) / 100000; } +EXPORT_SYMBOL(cfg80211_calculate_bitrate); int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, u32 beacon_int) -- cgit v1.2.3-70-g09d2 From 6b62bf326393deede630731a933713de9d574128 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 5 Mar 2012 15:31:48 -0800 Subject: mac80211: fix mesh airtime link metric estimating Airtime link metric estimation was broken in HT mesh, use cfg80211_calculate_bitrate to get the right rate value. Also factor out tx rate copying from sta_set_sinfo(). Signed-off-by: Thomas Pedersen Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 23 +++++++++++++++-------- net/mac80211/mesh_hwmp.c | 6 ++++-- net/mac80211/sta_info.h | 3 +++ 3 files changed, 22 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ab31cc56a2f..677d6592978 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -336,6 +336,20 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in rate->mcs = idx; } +void sta_set_rate_info_tx(struct sta_info *sta, + const struct ieee80211_tx_rate *rate, + struct rate_info *rinfo) +{ + rinfo->flags = 0; + if (rate->flags & IEEE80211_TX_RC_MCS) + rinfo->flags |= RATE_INFO_FLAGS_MCS; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; + rate_idx_to_bitrate(rinfo, sta, rate->idx); +} + static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; @@ -378,14 +392,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); } - sinfo->txrate.flags = 0; - if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) - sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; - if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; - if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) - sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx); + sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); sinfo->rxrate.flags = 0; if (sta->last_rx_rate_flag & RX_FLAG_HT) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 4a993f2d1ae..1c6f3d02aeb 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -324,6 +324,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_supported_band *sband; + struct rate_info rinfo; /* This should be adjusted for each device */ int device_constant = 1 << ARITH_SHIFT; int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT; @@ -337,7 +338,9 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (sta->fail_avg >= 100) return MAX_METRIC; - if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) + sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo); + rate = cfg80211_calculate_bitrate(&rinfo); + if (WARN_ON(!rate)) return MAX_METRIC; err = (sta->fail_avg << ARITH_SHIFT) / 100; @@ -345,7 +348,6 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, /* bitrate is in units of 100 Kbps, while we need rate in units of * 1Mbps. This will be corrected on tx_time computation. */ - rate = sband->bitrates[sta->last_tx_rate.idx].bitrate; tx_time = (device_constant + 10 * test_frame_len / rate); estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err)); result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3336d54e555..ab0576827ba 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -529,6 +529,9 @@ void sta_info_init(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); +void sta_set_rate_info_tx(struct sta_info *sta, + const struct ieee80211_tx_rate *rate, + struct rate_info *rinfo); void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); -- cgit v1.2.3-70-g09d2 From 12ce8ba3eb09bb83509a459835917a3100ad8db1 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 5 Mar 2012 17:20:38 -0800 Subject: mac80211: Modify tsf via debugfs in mesh interfaces Signed-off-by: Javier Cardona Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 18 ++++++++++++++++++ net/mac80211/debugfs_netdev.c | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 14a3cac19a3..b4f6cb3298a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -379,6 +379,22 @@ static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data) return cpu_to_le64(now + data->tsf_offset); } +static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = hw->priv; + return le64_to_cpu(__mac80211_hwsim_get_tsf(data)); +} + +static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) +{ + struct mac80211_hwsim_data *data = hw->priv; + struct timeval tv = ktime_to_timeval(ktime_get_real()); + u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec; + data->tsf_offset = tsf - now; +} + static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, struct sk_buff *tx_skb) { @@ -1224,6 +1240,8 @@ static struct ieee80211_ops mac80211_hwsim_ops = .sw_scan_start = mac80211_hwsim_sw_scan, .sw_scan_complete = mac80211_hwsim_sw_scan_complete, .flush = mac80211_hwsim_flush, + .get_tsf = mac80211_hwsim_get_tsf, + .set_tsf = mac80211_hwsim_set_tsf, }; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 9f484d8905f..f6de8a65f40 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -538,11 +538,15 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata) #ifdef CONFIG_MAC80211_MESH +static void add_mesh_files(struct ieee80211_sub_if_data *sdata) +{ + DEBUGFS_ADD_MODE(tsf, 0600); +} + static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) { struct dentry *dir = debugfs_create_dir("mesh_stats", sdata->debugfs.dir); - #define MESHSTATS_ADD(name)\ debugfs_create_file(#name, 0400, dir, sdata, &name##_ops); @@ -595,6 +599,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata) switch (sdata->vif.type) { case NL80211_IFTYPE_MESH_POINT: #ifdef CONFIG_MAC80211_MESH + add_mesh_files(sdata); add_mesh_stats(sdata); add_mesh_config(sdata); #endif -- cgit v1.2.3-70-g09d2 From c970a1ac4e75a5d31c7b6e8e9f0bb192b0a511e7 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:34 +0100 Subject: NFC: Add device powered netlink attribute For user space to know if a device is up or down. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/linux/nfc.h | 1 + net/nfc/netlink.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'net') diff --git a/include/linux/nfc.h b/include/linux/nfc.h index b4999abcb2a..39c1fcf089c 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h @@ -107,6 +107,7 @@ enum nfc_attrs { NFC_ATTR_TARGET_SENSF_RES, NFC_ATTR_COMM_MODE, NFC_ATTR_RF_MODE, + NFC_ATTR_DEVICE_POWERED, /* private: internal use only */ __NFC_ATTR_AFTER_LAST }; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 07f0348aabf..a1388e4efd6 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -48,6 +48,7 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 }, [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 }, [NFC_ATTR_RF_MODE] = { .type = NLA_U8 }, + [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 }, }; static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, @@ -200,6 +201,7 @@ int nfc_genl_device_added(struct nfc_dev *dev) NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)); NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols); + NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up); genlmsg_end(msg, hdr); @@ -261,6 +263,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)); NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols); + NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up); return genlmsg_end(msg, hdr); -- cgit v1.2.3-70-g09d2 From 4722d2b70b80098e1e429e093a7e04aad360260a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:35 +0100 Subject: NFC: Factorize the I frame queueing routine This one will be called from the I frame command sending. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 45 ++++++++++++++++++++++++++++----------------- net/nfc/llcp/llcp.h | 1 + 2 files changed, 29 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 1d32680807d..8510a2fb3da 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -616,6 +616,33 @@ fail: } +void nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) +{ + struct nfc_llcp_local *local = sock->local; + + pr_debug("Remote ready %d tx queue len %d remote rw %d", + sock->remote_ready, skb_queue_len(&sock->tx_pending_queue), + local->remote_rw); + + /* Try to queue some I frames for transmission */ + while (sock->remote_ready && + skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) { + struct sk_buff *pdu, *pending_pdu; + + pdu = skb_dequeue(&sock->tx_queue); + if (pdu == NULL) + break; + + /* Update N(S)/N(R) */ + nfc_llcp_set_nrns(sock, pdu); + + pending_pdu = skb_clone(pdu, GFP_KERNEL); + + skb_queue_tail(&local->tx_queue, pdu); + skb_queue_tail(&sock->tx_pending_queue, pending_pdu); + } +} + static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, struct sk_buff *skb) { @@ -673,23 +700,7 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, } } - /* Queue some I frames for transmission */ - while (llcp_sock->remote_ready && - skb_queue_len(&llcp_sock->tx_pending_queue) <= local->remote_rw) { - struct sk_buff *pdu, *pending_pdu; - - pdu = skb_dequeue(&llcp_sock->tx_queue); - if (pdu == NULL) - break; - - /* Update N(S)/N(R) */ - nfc_llcp_set_nrns(llcp_sock, pdu); - - pending_pdu = skb_clone(pdu, GFP_KERNEL); - - skb_queue_tail(&local->tx_queue, pdu); - skb_queue_tail(&llcp_sock->tx_pending_queue, pending_pdu); - } + nfc_llcp_queue_i_frames(llcp_sock); release_sock(sk); nfc_llcp_sock_put(llcp_sock); diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 0ad2e336158..0a72ee62764 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -165,6 +165,7 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, struct nfc_llcp_sock *sock); u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); +void nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); /* Sock API */ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); -- cgit v1.2.3-70-g09d2 From 53aef92054e7fbffe66d3e2f95d122f39a33c211 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:36 +0100 Subject: NFC: Handle Receiver Not Ready LLCP frame Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 8510a2fb3da..bbfaa2750ea 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -671,15 +671,15 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, nfc_llcp_sock_put(llcp_sock); } - if (ns == llcp_sock->recv_n) - llcp_sock->recv_n = (llcp_sock->recv_n + 1) % 16; - else - pr_err("Received out of sequence I PDU\n"); - /* Pass the payload upstream */ if (ptype == LLCP_PDU_I) { pr_debug("I frame, queueing on %p\n", &llcp_sock->sk); + if (ns == llcp_sock->recv_n) + llcp_sock->recv_n = (llcp_sock->recv_n + 1) % 16; + else + pr_err("Received out of sequence I PDU\n"); + skb_pull(skb, LLCP_HEADER_SIZE + LLCP_SEQUENCE_SIZE); if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) { pr_err("receive queue is full\n"); @@ -700,6 +700,11 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, } } + if (ptype == LLCP_PDU_RR) + llcp_sock->remote_ready = true; + else if (ptype == LLCP_PDU_RNR) + llcp_sock->remote_ready = false; + nfc_llcp_queue_i_frames(llcp_sock); release_sock(sk); @@ -813,6 +818,7 @@ static void nfc_llcp_rx_work(struct work_struct *work) case LLCP_PDU_I: case LLCP_PDU_RR: + case LLCP_PDU_RNR: pr_debug("I frame\n"); nfc_llcp_recv_hdlc(local, skb); break; -- cgit v1.2.3-70-g09d2 From 53a0ac2ee810cf82ec374b686a1dc3c32399265a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:37 +0100 Subject: NFC: LLCP socket sendmsg implemetation Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 31 +++++++++++++++++++++++++++++++ net/nfc/llcp/llcp.h | 2 ++ net/nfc/llcp/sock.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 151f2ef429c..f6c2257c11a 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -397,3 +397,34 @@ int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock) return 0; } + +int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, + struct msghdr *msg, size_t len) +{ + struct sk_buff *pdu; + struct sock *sk; + + pr_debug("Send I frame\n"); + + pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, len + LLCP_SEQUENCE_SIZE); + if (pdu == NULL) + return -ENOMEM; + + skb_put(pdu, LLCP_SEQUENCE_SIZE); + + if (memcpy_fromiovec(skb_put(pdu, len), msg->msg_iov, len)) { + kfree_skb(pdu); + return -EFAULT; + } + + skb_queue_head(&sock->tx_queue, pdu); + + sk = &sock->sk; + lock_sock(sk); + + nfc_llcp_queue_i_frames(sock); + + release_sock(sk); + + return 0; +} diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 0a72ee62764..36d8572c8be 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -188,6 +188,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); +int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, + struct msghdr *msg, size_t len); /* Socket API */ int __init nfc_llcp_sock_init(void); diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index f738ccd535f..b8bef367ee4 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -482,6 +482,34 @@ error: return ret; } +static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); + int ret; + + pr_debug("sock %p sk %p", sock, sk); + + ret = sock_error(sk); + if (ret) + return ret; + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + lock_sock(sk); + + if (sk->sk_state != LLCP_CONNECTED) { + release_sock(sk); + return -ENOTCONN; + } + + release_sock(sk); + + return nfc_llcp_send_i_frame(llcp_sock, msg, len); +} + static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags) { @@ -567,7 +595,7 @@ static const struct proto_ops llcp_sock_ops = { .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, .getsockopt = sock_no_getsockopt, - .sendmsg = sock_no_sendmsg, + .sendmsg = llcp_sock_sendmsg, .recvmsg = llcp_sock_recvmsg, .mmap = sock_no_mmap, }; -- cgit v1.2.3-70-g09d2 From 1762c17c9c38ed21090bee8cd02e2b470c5c2308 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:38 +0100 Subject: NFC: Fix bitops usage in LLCP Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index bbfaa2750ea..443407e964c 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -176,7 +176,7 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, return LLCP_SAP_MAX; } - set_bit(BIT(ssap), &local->local_wks); + set_bit(ssap, &local->local_wks); mutex_unlock(&local->sdp_lock); return ssap; @@ -195,25 +195,25 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); - set_bit(BIT(ssap), &local->local_sdp); + set_bit(ssap, &local->local_sdp); mutex_unlock(&local->sdp_lock); return LLCP_WKS_NUM_SAP + ssap; } else if (sock->ssap != 0) { if (sock->ssap < LLCP_WKS_NUM_SAP) { - if (!(local->local_wks & BIT(sock->ssap))) { - set_bit(BIT(sock->ssap), &local->local_wks); + if (!test_bit(sock->ssap, &local->local_wks)) { + set_bit(sock->ssap, &local->local_wks); mutex_unlock(&local->sdp_lock); return sock->ssap; } } else if (sock->ssap < LLCP_SDP_NUM_SAP) { - if (!(local->local_sdp & - BIT(sock->ssap - LLCP_WKS_NUM_SAP))) { - set_bit(BIT(sock->ssap - LLCP_WKS_NUM_SAP), - &local->local_sdp); + if (!test_bit(sock->ssap - LLCP_WKS_NUM_SAP, + &local->local_sdp)) { + set_bit(sock->ssap - LLCP_WKS_NUM_SAP, + &local->local_sdp); mutex_unlock(&local->sdp_lock); return sock->ssap; @@ -238,7 +238,7 @@ u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local) return LLCP_SAP_MAX; } - set_bit(BIT(local_ssap), &local->local_sap); + set_bit(local_ssap, &local->local_sap); mutex_unlock(&local->sdp_lock); @@ -265,7 +265,7 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) mutex_lock(&local->sdp_lock); - clear_bit(1 << local_ssap, sdp); + clear_bit(local_ssap, sdp); mutex_unlock(&local->sdp_lock); } -- cgit v1.2.3-70-g09d2 From b9a76f1d3c6da47b2fa115ff1c0de229e8d06f8f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:40 +0100 Subject: NFC: Clear LLCP SDPs whan MAC goes down Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 443407e964c..577bcb92ea9 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -97,6 +97,17 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) mutex_unlock(&local->socket_lock); } +static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local) +{ + mutex_lock(&local->sdp_lock); + + local->local_wks = 0; + local->local_sdp = 0; + local->local_sap = 0; + + mutex_unlock(&local->sdp_lock); +} + static void nfc_llcp_timeout_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, @@ -857,6 +868,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) if (local == NULL) return; + nfc_llcp_clear_sdp(local); + /* Close and purge all existing sockets */ nfc_llcp_socket_release(local); } -- cgit v1.2.3-70-g09d2 From 0767a7fa87ff18f6a11e3de954c5386a45b9d96e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:41 +0100 Subject: NFC: Set the right LLCP N(R) value for I frames Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 577bcb92ea9..2506810cd78 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -419,7 +419,7 @@ static u8 nfc_llcp_nr(struct sk_buff *pdu) static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu) { - pdu->data[2] = (sock->send_n << 4) | ((sock->recv_n - 1) % 16); + pdu->data[2] = (sock->send_n << 4) | (sock->recv_n % 16); sock->send_n = (sock->send_n + 1) % 16; sock->recv_ack_n = (sock->recv_n - 1) % 16; } -- cgit v1.2.3-70-g09d2 From d094afa155273e03b82981ea818d39c7a2dfba86 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:42 +0100 Subject: NFC: Send LLCP RR frames to acknowledge received I frames In order to acknowledge an I frame, we have to either queue pending local I frames or queue a receiver ready frame. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 24 ++++++++++++++++++++++++ net/nfc/llcp/llcp.c | 9 +++++++-- net/nfc/llcp/llcp.h | 3 ++- 3 files changed, 33 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index f6c2257c11a..8ebd322b11e 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -428,3 +428,27 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, return 0; } + +int nfc_llcp_send_rr(struct nfc_llcp_sock *sock) +{ + struct sk_buff *skb; + struct nfc_llcp_local *local; + + pr_debug("Send rr nr %d\n", sock->recv_n); + + local = sock->local; + if (local == NULL) + return -ENODEV; + + skb = llcp_allocate_pdu(sock, LLCP_PDU_RR, LLCP_SEQUENCE_SIZE); + if (skb == NULL) + return -ENOMEM; + + skb_put(skb, LLCP_SEQUENCE_SIZE); + + skb->data[2] = sock->recv_n % 16; + + skb_queue_head(&local->tx_queue, skb); + + return 0; +} diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 2506810cd78..a0cb133c610 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -627,8 +627,9 @@ fail: } -void nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) +int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) { + int nr_frames = 0; struct nfc_llcp_local *local = sock->local; pr_debug("Remote ready %d tx queue len %d remote rw %d", @@ -651,7 +652,10 @@ void nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) skb_queue_tail(&local->tx_queue, pdu); skb_queue_tail(&sock->tx_pending_queue, pending_pdu); + nr_frames++; } + + return nr_frames; } static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, @@ -716,7 +720,8 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, else if (ptype == LLCP_PDU_RNR) llcp_sock->remote_ready = false; - nfc_llcp_queue_i_frames(llcp_sock); + if (nfc_llcp_queue_i_frames(llcp_sock) == 0) + nfc_llcp_send_rr(llcp_sock); release_sock(sk); nfc_llcp_sock_put(llcp_sock); diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 36d8572c8be..054c64ffdaa 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -165,7 +165,7 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, struct nfc_llcp_sock *sock); u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); -void nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); +int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); /* Sock API */ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); @@ -190,6 +190,7 @@ int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, struct msghdr *msg, size_t len); +int nfc_llcp_send_rr(struct nfc_llcp_sock *sock); /* Socket API */ int __init nfc_llcp_sock_init(void); -- cgit v1.2.3-70-g09d2 From eda21f16a5ed2476c1740e83a7dfaae34d893d9b Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:43 +0100 Subject: NFC: Set MIU and RW values from CONNECT and CC LLCP frames We use the maximum values for the LLCP Maximum Information Unit and Receive Window Size. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- net/nfc/llcp/llcp.h | 4 ++++ 2 files changed, 49 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 8ebd322b11e..a02292ba25c 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -284,6 +284,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) struct nfc_llcp_local *local; struct sk_buff *skb; u8 *service_name_tlv = NULL, service_name_tlv_length; + u8 *miux_tlv = NULL, miux_tlv_length; + u8 *rw_tlv = NULL, rw_tlv_length, rw; + __be16 miux; int err; u16 size = 0; @@ -301,6 +304,14 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) size += service_name_tlv_length; } + miux = cpu_to_be16(LLCP_MAX_MIUX); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + size += miux_tlv_length; + + rw = LLCP_MAX_RW; + rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); + size += rw_tlv_length; + pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len); skb = llcp_allocate_pdu(sock, LLCP_PDU_CONNECT, size); @@ -313,6 +324,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) skb = llcp_add_tlv(skb, service_name_tlv, service_name_tlv_length); + skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length); + skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length); + skb_queue_tail(&local->tx_queue, skb); return 0; @@ -321,6 +335,8 @@ error_tlv: pr_err("error %d\n", err); kfree(service_name_tlv); + kfree(miux_tlv); + kfree(rw_tlv); return err; } @@ -329,6 +345,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) { struct nfc_llcp_local *local; struct sk_buff *skb; + u8 *miux_tlv = NULL, miux_tlv_length; + u8 *rw_tlv = NULL, rw_tlv_length, rw; + __be16 miux; + int err; + u16 size = 0; pr_debug("Sending CC\n"); @@ -336,13 +357,34 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) if (local == NULL) return -ENODEV; - skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, 0); - if (skb == NULL) - return -ENOMEM; + miux = cpu_to_be16(LLCP_MAX_MIUX); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + size += miux_tlv_length; + + rw = LLCP_MAX_RW; + rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); + size += rw_tlv_length; + + skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size); + if (skb == NULL) { + err = -ENOMEM; + goto error_tlv; + } + + skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length); + skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length); skb_queue_tail(&local->tx_queue, skb); return 0; + +error_tlv: + pr_err("error %d\n", err); + + kfree(miux_tlv); + kfree(rw_tlv); + + return err; } int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason) diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 054c64ffdaa..70e1762d6e8 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -28,6 +28,10 @@ enum llcp_state { #define LLCP_DEFAULT_RW 1 #define LLCP_DEFAULT_MIU 128 +#define LLCP_MAX_LTO 0xff +#define LLCP_MAX_RW 15 +#define LLCP_MAX_MIUX 0x7ff + #define LLCP_WKS_NUM_SAP 16 #define LLCP_SDP_NUM_SAP 16 #define LLCP_LOCAL_NUM_SAP 32 -- cgit v1.2.3-70-g09d2 From e65b0f46edfda746ba8c66ada28ccb97c682b7c0 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:44 +0100 Subject: NFC: Fragment LLCP I frames Based on the receiver MIU, we have to fragment the frame to be transmitted. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index a02292ba25c..bfe35b8f225 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -444,29 +444,58 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, struct msghdr *msg, size_t len) { struct sk_buff *pdu; - struct sock *sk; + struct sock *sk = &sock->sk; + struct nfc_llcp_local *local; + size_t frag_len = 0, remaining_len; + u8 *msg_data, *msg_ptr; - pr_debug("Send I frame\n"); + pr_debug("Send I frame len %zd\n", len); - pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, len + LLCP_SEQUENCE_SIZE); - if (pdu == NULL) - return -ENOMEM; + local = sock->local; + if (local == NULL) + return -ENODEV; - skb_put(pdu, LLCP_SEQUENCE_SIZE); + msg_data = kzalloc(len, GFP_KERNEL); + if (msg_data == NULL) + return -ENOMEM; - if (memcpy_fromiovec(skb_put(pdu, len), msg->msg_iov, len)) { - kfree_skb(pdu); - return -EFAULT; + if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) { + kfree(msg_data); + return -EFAULT; } - skb_queue_head(&sock->tx_queue, pdu); + remaining_len = len; + msg_ptr = msg_data; + + while (remaining_len > 0) { + + frag_len = min_t(u16, local->remote_miu, remaining_len); - sk = &sock->sk; - lock_sock(sk); + pr_debug("Fragment %zd bytes remaining %zd", + frag_len, remaining_len); - nfc_llcp_queue_i_frames(sock); + pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, + frag_len + LLCP_SEQUENCE_SIZE); + if (pdu == NULL) + return -ENOMEM; + + skb_put(pdu, LLCP_SEQUENCE_SIZE); + + memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); + + skb_queue_head(&sock->tx_queue, pdu); + + lock_sock(sk); + + nfc_llcp_queue_i_frames(sock); + + release_sock(sk); + + remaining_len -= frag_len; + msg_ptr += len; + } - release_sock(sk); + kfree(msg_data); return 0; } -- cgit v1.2.3-70-g09d2 From 0c31835993e622fa9d407807e384c0f9b971d53b Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:48 +0100 Subject: NFC: Unlink LLCP child sockets from llcp_sock_release The parent socket (the bound one) could be freed before its children, so we should unlink the children without trying to reach it through the parent. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/sock.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index b8bef367ee4..d3861773fab 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -327,20 +327,10 @@ static int llcp_sock_release(struct socket *sock) mutex_lock(&local->socket_lock); - if (llcp_sock == local->sockets[llcp_sock->ssap]) { + if (llcp_sock == local->sockets[llcp_sock->ssap]) local->sockets[llcp_sock->ssap] = NULL; - } else { - struct nfc_llcp_sock *parent, *s, *n; - - parent = local->sockets[llcp_sock->ssap]; - - list_for_each_entry_safe(s, n, &parent->list, list) - if (llcp_sock == s) { - list_del(&s->list); - break; - } - - } + else + list_del(&llcp_sock->list); mutex_unlock(&local->socket_lock); -- cgit v1.2.3-70-g09d2 From 9dda50f4c98f84e32a5f6dc4d9dd7af6085add43 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:49 +0100 Subject: NFC: SN is not an invalid GT value We just don't do anything with it when parsing the general bytes. We handle it from the CONNECT reception code. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index bfe35b8f225..7c74b82f216 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -152,6 +152,8 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local, case LLCP_TLV_RW: local->remote_rw = llcp_tlv_rw(tlv); break; + case LLCP_TLV_SN: + break; default: pr_err("Invalid gt tlv value 0x%x\n", type); break; -- cgit v1.2.3-70-g09d2 From 47807d3dbb62e93850cbcb797db1a9ee1806f986 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:50 +0100 Subject: NFC: Remove the rf mode parameter from the DEP link up routine When calling nfc_dep_link_up, we implicitely are in initiator mode. Which means we also can provide the general bytes as a function argument, as all drivers will eventually request them. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/nfc/pn533.c | 20 +++++--------------- include/net/nfc/nfc.h | 6 ++---- net/nfc/core.c | 22 +++++++++++----------- net/nfc/llcp/llcp.c | 2 +- net/nfc/netlink.c | 11 +++-------- net/nfc/nfc.h | 5 ++--- 6 files changed, 24 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index ef33f64143b..cb6204f7830 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1340,21 +1340,15 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, } static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, - u8 comm_mode, u8 rf_mode) + u8 comm_mode, u8* gb, size_t gb_len) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533_cmd_jump_dep *cmd; - u8 cmd_len, local_gt_len, *local_gt; + u8 cmd_len; int rc; nfc_dev_dbg(&dev->interface->dev, "%s", __func__); - if (rf_mode == NFC_RF_TARGET) { - nfc_dev_err(&dev->interface->dev, "Target mode not supported"); - return -EOPNOTSUPP; - } - - if (dev->poll_mod_count) { nfc_dev_err(&dev->interface->dev, "Cannot bring the DEP link up while polling"); @@ -1367,11 +1361,7 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, return -EBUSY; } - local_gt = nfc_get_local_general_bytes(dev->nfc_dev, &local_gt_len); - if (local_gt_len > NFC_MAX_GT_LEN) - return -EINVAL; - - cmd_len = sizeof(struct pn533_cmd_jump_dep) + local_gt_len; + cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len; cmd = kzalloc(cmd_len, GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1380,9 +1370,9 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, cmd->active = !comm_mode; cmd->baud = 0; - if (local_gt != NULL) { + if (gb != NULL && gb_len > 0) { cmd->next = 4; /* We have some Gi */ - memcpy(cmd->gt, local_gt, local_gt_len); + memcpy(cmd->gt, gb, gb_len); } else { cmd->next = 0; } diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index d253278e5a9..d608e4eac66 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -53,8 +53,8 @@ struct nfc_ops { int (*dev_down)(struct nfc_dev *dev); int (*start_poll)(struct nfc_dev *dev, u32 protocols); void (*stop_poll)(struct nfc_dev *dev); - int (*dep_link_up)(struct nfc_dev *dev, int target_idx, - u8 comm_mode, u8 rf_mode); + int (*dep_link_up)(struct nfc_dev *dev, int target_idx, u8 comm_mode, + u8 *gb, size_t gb_len); int (*dep_link_down)(struct nfc_dev *dev); int (*activate_target)(struct nfc_dev *dev, u32 target_idx, u32 protocol); @@ -179,8 +179,6 @@ struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp); int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gt, u8 gt_len); -u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, u8 *gt_len); - int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, int ntargets); diff --git a/net/nfc/core.c b/net/nfc/core.c index 6089aca67b1..f4f526f7321 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -181,13 +181,13 @@ error: return rc; } -int nfc_dep_link_up(struct nfc_dev *dev, int target_index, - u8 comm_mode, u8 rf_mode) +int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) { int rc = 0; + u8 *gb; + size_t gb_len; - pr_debug("dev_name=%s comm:%d rf:%d\n", - dev_name(&dev->dev), comm_mode, rf_mode); + pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode); if (!dev->ops->dep_link_up) return -EOPNOTSUPP; @@ -204,7 +204,13 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, goto error; } - rc = dev->ops->dep_link_up(dev, target_index, comm_mode, rf_mode); + gb = nfc_llcp_general_bytes(dev, &gb_len); + if (gb_len > NFC_MAX_GT_LEN) { + rc = -EINVAL; + goto error; + } + + rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len); error: device_unlock(&dev->dev); @@ -367,12 +373,6 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len) } EXPORT_SYMBOL(nfc_set_remote_general_bytes); -u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, u8 *gt_len) -{ - return nfc_llcp_general_bytes(dev, gt_len); -} -EXPORT_SYMBOL(nfc_get_local_general_bytes); - /** * nfc_alloc_send_skb - allocate a skb for data exchange responses * diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index a0cb133c610..3ce646e35f6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -281,7 +281,7 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) mutex_unlock(&local->sdp_lock); } -u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *general_bytes_len) +u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) { struct nfc_llcp_local *local; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index a1388e4efd6..fa620d03799 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -542,13 +542,12 @@ static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info) struct nfc_dev *dev; int rc, tgt_idx; u32 idx; - u8 comm, rf; + u8 comm; pr_debug("DEP link up\n"); if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || - !info->attrs[NFC_ATTR_COMM_MODE] || - !info->attrs[NFC_ATTR_RF_MODE]) + !info->attrs[NFC_ATTR_COMM_MODE]) return -EINVAL; idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); @@ -558,19 +557,15 @@ static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info) tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]); comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]); - rf = nla_get_u8(info->attrs[NFC_ATTR_RF_MODE]); if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE) return -EINVAL; - if (rf != NFC_RF_INITIATOR && comm != NFC_RF_TARGET) - return -EINVAL; - dev = nfc_get_device(idx); if (!dev) return -ENODEV; - rc = nfc_dep_link_up(dev, tgt_idx, comm, rf); + rc = nfc_dep_link_up(dev, tgt_idx, comm); nfc_put_device(dev); diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index 6d28d75995b..2fd83b16df6 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -54,7 +54,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, int nfc_llcp_register_device(struct nfc_dev *dev); void nfc_llcp_unregister_device(struct nfc_dev *dev); int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len); -u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *general_bytes_len); +u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len); int __init nfc_llcp_init(void); void nfc_llcp_exit(void); @@ -160,8 +160,7 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols); int nfc_stop_poll(struct nfc_dev *dev); -int nfc_dep_link_up(struct nfc_dev *dev, int target_idx, - u8 comm_mode, u8 rf_mode); +int nfc_dep_link_up(struct nfc_dev *dev, int target_idx, u8 comm_mode); int nfc_dep_link_down(struct nfc_dev *dev); -- cgit v1.2.3-70-g09d2 From 40c75f81d6852bb4fd08491074889187f77b8d1f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:51 +0100 Subject: NFC: Fix LLCP sockets releasing path The socket local pointer needs to be set to NULL when the adapter is removed or the MAC goes down. If the socket release code is called after such an event, the socket reference count still needs to be decreased in order for the socket to eventually be freed. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 15 +++++++++++---- net/nfc/llcp/sock.c | 23 +++++++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 3ce646e35f6..8af896dc759 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -47,7 +47,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) /* Release all child sockets */ list_for_each_entry_safe(s, n, &parent->list, list) { - list_del(&s->list); + list_del_init(&s->list); sk = &s->sk; lock_sock(sk); @@ -56,9 +56,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) nfc_put_device(s->dev); sk->sk_state = LLCP_CLOSED; - sock_set_flag(sk, SOCK_DEAD); release_sock(sk); + + sock_orphan(sk); + + s->local = NULL; } parent_sk = &parent->sk; @@ -77,11 +80,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) nfc_llcp_accept_unlink(accept_sk); accept_sk->sk_state = LLCP_CLOSED; - sock_set_flag(accept_sk, SOCK_DEAD); release_sock(accept_sk); sock_orphan(accept_sk); + + lsk->local = NULL; } } @@ -89,9 +93,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) nfc_put_device(parent->dev); parent_sk->sk_state = LLCP_CLOSED; - sock_set_flag(parent_sk, SOCK_DEAD); release_sock(parent_sk); + + sock_orphan(parent_sk); + + parent->local = NULL; } mutex_unlock(&local->socket_lock); diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index d3861773fab..35825e20163 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -315,6 +315,7 @@ static int llcp_sock_release(struct socket *sock) struct sock *sk = sock->sk; struct nfc_llcp_local *local; struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); + int err = 0; if (!sk) return 0; @@ -322,15 +323,17 @@ static int llcp_sock_release(struct socket *sock) pr_debug("%p\n", sk); local = llcp_sock->local; - if (local == NULL) - return -ENODEV; + if (local == NULL) { + err = -ENODEV; + goto out; + } mutex_lock(&local->socket_lock); if (llcp_sock == local->sockets[llcp_sock->ssap]) local->sockets[llcp_sock->ssap] = NULL; else - list_del(&llcp_sock->list); + list_del_init(&llcp_sock->list); mutex_unlock(&local->socket_lock); @@ -354,9 +357,7 @@ static int llcp_sock_release(struct socket *sock) release_sock(accept_sk); - sock_set_flag(sk, SOCK_DEAD); sock_orphan(accept_sk); - sock_put(accept_sk); } } @@ -367,14 +368,13 @@ static int llcp_sock_release(struct socket *sock) sk->sk_state == LLCP_LISTEN) nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); - sock_set_flag(sk, SOCK_DEAD); - release_sock(sk); +out: sock_orphan(sk); sock_put(sk); - return 0; + return err; } static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, @@ -645,6 +645,8 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) void nfc_llcp_sock_free(struct nfc_llcp_sock *sock) { + struct nfc_llcp_local *local = sock->local; + kfree(sock->service_name); skb_queue_purge(&sock->tx_queue); @@ -653,6 +655,11 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock) list_del_init(&sock->accept_queue); + if (local != NULL && sock == local->sockets[sock->ssap]) + local->sockets[sock->ssap] = NULL; + else + list_del_init(&sock->list); + sock->parent = NULL; } -- cgit v1.2.3-70-g09d2 From 427a2eb1f568c9c5934a36105232c94553db9b69 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:52 +0100 Subject: NFC: LLCP code identation fixes Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 39 +++++++++++---------- net/nfc/llcp/llcp.c | 93 +++++++++++++++++++++++++------------------------ net/nfc/llcp/llcp.h | 6 ++-- net/nfc/llcp/sock.c | 55 +++++++++++++++-------------- 4 files changed, 100 insertions(+), 93 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 7c74b82f216..7b76eb7192f 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -118,7 +118,7 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length) } int nfc_llcp_parse_tlv(struct nfc_llcp_local *local, - u8 *tlv_array, u16 tlv_array_len) + u8 *tlv_array, u16 tlv_array_len) { u8 *tlv = tlv_array, type, length, offset = 0; @@ -164,15 +164,15 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local, } pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x rw %d\n", - local->remote_version, local->remote_miu, - local->remote_lto, local->remote_opt, - local->remote_wks, local->remote_rw); + local->remote_version, local->remote_miu, + local->remote_lto, local->remote_opt, + local->remote_wks, local->remote_rw); return 0; } static struct sk_buff *llcp_add_header(struct sk_buff *pdu, - u8 dsap, u8 ssap, u8 ptype) + u8 dsap, u8 ssap, u8 ptype) { u8 header[2]; @@ -188,7 +188,8 @@ static struct sk_buff *llcp_add_header(struct sk_buff *pdu, return pdu; } -static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length) +static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, + u8 tlv_length) { /* XXX Add an skb length check */ @@ -201,7 +202,7 @@ static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length) } static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock, - u8 cmd, u16 size) + u8 cmd, u16 size) { struct sk_buff *skb; int err; @@ -210,7 +211,7 @@ static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock, return NULL; skb = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT, - size + LLCP_HEADER_SIZE, &err); + size + LLCP_HEADER_SIZE, &err); if (skb == NULL) { pr_err("Could not allocate PDU\n"); return NULL; @@ -278,7 +279,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); return nfc_data_exchange(dev, local->target_idx, skb, - nfc_llcp_recv, local); + nfc_llcp_recv, local); } int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) @@ -300,14 +301,15 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) if (sock->service_name != NULL) { service_name_tlv = nfc_llcp_build_tlv(LLCP_TLV_SN, - sock->service_name, - sock->service_name_len, - &service_name_tlv_length); + sock->service_name, + sock->service_name_len, + &service_name_tlv_length); size += service_name_tlv_length; } miux = cpu_to_be16(LLCP_MAX_MIUX); - miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, + &miux_tlv_length); size += miux_tlv_length; rw = LLCP_MAX_RW; @@ -324,7 +326,7 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) if (service_name_tlv != NULL) skb = llcp_add_tlv(skb, service_name_tlv, - service_name_tlv_length); + service_name_tlv_length); skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length); skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length); @@ -360,7 +362,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) return -ENODEV; miux = cpu_to_be16(LLCP_MAX_MIUX); - miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, + &miux_tlv_length); size += miux_tlv_length; rw = LLCP_MAX_RW; @@ -443,7 +446,7 @@ int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock) } int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, - struct msghdr *msg, size_t len) + struct msghdr *msg, size_t len) { struct sk_buff *pdu; struct sock *sk = &sock->sk; @@ -462,8 +465,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, return -ENOMEM; if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) { - kfree(msg_data); - return -EFAULT; + kfree(msg_data); + return -EFAULT; } remaining_len = len; diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 8af896dc759..17a578f641f 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -37,7 +37,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) struct sock *sk, *parent_sk; int i; - mutex_lock(&local->socket_lock); for (i = 0; i < LLCP_MAX_SAP; i++) { @@ -73,7 +72,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) struct sock *accept_sk; list_for_each_entry_safe(lsk, n, &parent->accept_queue, - accept_queue) { + accept_queue) { accept_sk = &lsk->sk; lock_sock(accept_sk); @@ -118,7 +117,7 @@ static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local) static void nfc_llcp_timeout_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, - timeout_work); + timeout_work); nfc_dep_link_down(local->dev); } @@ -164,7 +163,7 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len) num_wks = ARRAY_SIZE(wks); - for (sap = 0 ; sap < num_wks; sap++) { + for (sap = 0; sap < num_wks; sap++) { if (wks[sap] == NULL) continue; @@ -176,13 +175,13 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len) } u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, - struct nfc_llcp_sock *sock) + struct nfc_llcp_sock *sock) { mutex_lock(&local->sdp_lock); if (sock->service_name != NULL && sock->service_name_len > 0) { int ssap = nfc_llcp_wks_sap(sock->service_name, - sock->service_name_len); + sock->service_name_len); if (ssap > 0) { pr_debug("WKS %d\n", ssap); @@ -312,7 +311,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) version = LLCP_VERSION_11; version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version, - 1, &version_length); + 1, &version_length); gb_len += version_length; /* 1500 ms */ @@ -322,7 +321,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) pr_debug("Local wks 0x%lx\n", local->local_wks); wks_tlv = nfc_llcp_build_tlv(LLCP_TLV_WKS, (u8 *)&local->local_wks, 2, - &wks_length); + &wks_length); gb_len += wks_length; gb_len += ARRAY_SIZE(llcp_magic); @@ -367,8 +366,7 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) memcpy(local->remote_gb, gb, gb_len); local->remote_gb_len = gb_len; - if (local->remote_gb == NULL || - local->remote_gb_len == 0) + if (local->remote_gb == NULL || local->remote_gb_len == 0) return -ENODEV; if (memcmp(local->remote_gb, llcp_magic, 3)) { @@ -377,26 +375,27 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) } return nfc_llcp_parse_tlv(local, - &local->remote_gb[3], local->remote_gb_len - 3); + &local->remote_gb[3], + local->remote_gb_len - 3); } static void nfc_llcp_tx_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, - tx_work); + tx_work); struct sk_buff *skb; skb = skb_dequeue(&local->tx_queue); if (skb != NULL) { pr_debug("Sending pending skb\n"); nfc_data_exchange(local->dev, local->target_idx, - skb, nfc_llcp_recv, local); + skb, nfc_llcp_recv, local); } else { nfc_llcp_send_symm(local->dev); } mod_timer(&local->link_timer, - jiffies + msecs_to_jiffies(local->remote_lto)); + jiffies + msecs_to_jiffies(local->remote_lto)); } static u8 nfc_llcp_dsap(struct sk_buff *pdu) @@ -432,7 +431,7 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu) } static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, - u8 ssap, u8 dsap) + u8 ssap, u8 dsap) { struct nfc_llcp_sock *sock, *llcp_sock, *n; @@ -456,7 +455,7 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, list_for_each_entry_safe(llcp_sock, n, &sock->list, list) { pr_debug("llcp_sock %p sk %p dsap %d\n", llcp_sock, - &llcp_sock->sk, llcp_sock->dsap); + &llcp_sock->sk, llcp_sock->dsap); if (llcp_sock->dsap == dsap) { sock_hold(&llcp_sock->sk); mutex_unlock(&local->socket_lock); @@ -500,7 +499,7 @@ static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) } static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, - struct sk_buff *skb) + struct sk_buff *skb) { struct sock *new_sk, *parent; struct nfc_llcp_sock *sock, *new_sock; @@ -512,7 +511,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, pr_debug("%d %d\n", dsap, ssap); nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE], - skb->len - LLCP_HEADER_SIZE); + skb->len - LLCP_HEADER_SIZE); if (dsap != LLCP_SAP_SDP) { bound_sap = dsap; @@ -531,7 +530,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, lock_sock(&sock->sk); if (sock->dsap == LLCP_SAP_SDP && - sock->sk.sk_state == LLCP_LISTEN) + sock->sk.sk_state == LLCP_LISTEN) goto enqueue; } else { u8 *sn; @@ -547,23 +546,23 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, mutex_lock(&local->socket_lock); for (bound_sap = 0; bound_sap < LLCP_LOCAL_SAP_OFFSET; - bound_sap++) { + bound_sap++) { sock = local->sockets[bound_sap]; if (sock == NULL) continue; if (sock->service_name == NULL || - sock->service_name_len == 0) + sock->service_name_len == 0) continue; if (sock->service_name_len != sn_len) continue; if (sock->dsap == LLCP_SAP_SDP && - sock->sk.sk_state == LLCP_LISTEN && - !memcmp(sn, sock->service_name, sn_len)) { + sock->sk.sk_state == LLCP_LISTEN && + !memcmp(sn, sock->service_name, sn_len)) { pr_debug("Found service name at SAP %d\n", - bound_sap); + bound_sap); sock_hold(&sock->sk); mutex_unlock(&local->socket_lock); @@ -588,8 +587,7 @@ enqueue: goto fail; } - new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, - GFP_ATOMIC); + new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); if (new_sk == NULL) { reason = LLCP_DM_REJ; release_sock(&sock->sk); @@ -640,12 +638,12 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) struct nfc_llcp_local *local = sock->local; pr_debug("Remote ready %d tx queue len %d remote rw %d", - sock->remote_ready, skb_queue_len(&sock->tx_pending_queue), - local->remote_rw); + sock->remote_ready, skb_queue_len(&sock->tx_pending_queue), + local->remote_rw); /* Try to queue some I frames for transmission */ while (sock->remote_ready && - skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) { + skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) { struct sk_buff *pdu, *pending_pdu; pdu = skb_dequeue(&sock->tx_queue); @@ -666,7 +664,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) } static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, - struct sk_buff *skb) + struct sk_buff *skb) { struct nfc_llcp_sock *llcp_sock; struct sock *sk; @@ -724,7 +722,7 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, if (ptype == LLCP_PDU_RR) llcp_sock->remote_ready = true; - else if (ptype == LLCP_PDU_RNR) + else if (ptype == LLCP_PDU_RNR) llcp_sock->remote_ready = false; if (nfc_llcp_queue_i_frames(llcp_sock) == 0) @@ -735,7 +733,7 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, } static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, - struct sk_buff *skb) + struct sk_buff *skb) { struct nfc_llcp_sock *llcp_sock; struct sock *sk; @@ -757,7 +755,6 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, nfc_llcp_sock_put(llcp_sock); } - if (sk->sk_state == LLCP_CONNECTED) { nfc_put_device(local->dev); sk->sk_state = LLCP_CLOSED; @@ -770,13 +767,11 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, nfc_llcp_sock_put(llcp_sock); } -static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, - struct sk_buff *skb) +static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) { struct nfc_llcp_sock *llcp_sock; u8 dsap, ssap; - dsap = nfc_llcp_dsap(skb); ssap = nfc_llcp_ssap(skb); @@ -795,7 +790,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, llcp_sock->dsap = ssap; nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE], - skb->len - LLCP_HEADER_SIZE); + skb->len - LLCP_HEADER_SIZE); nfc_llcp_sock_put(llcp_sock); } @@ -803,7 +798,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, static void nfc_llcp_rx_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, - rx_work); + rx_work); u8 dsap, ssap, ptype; struct sk_buff *skb; @@ -861,7 +856,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err) pr_debug("Received an LLCP PDU\n"); if (err < 0) { - pr_err("err %d", err); + pr_err("err %d\n", err); return; } @@ -907,7 +902,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, queue_work(local->tx_wq, &local->tx_work); } else { mod_timer(&local->link_timer, - jiffies + msecs_to_jiffies(local->remote_lto)); + jiffies + msecs_to_jiffies(local->remote_lto)); } } @@ -933,8 +928,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) skb_queue_head_init(&local->tx_queue); INIT_WORK(&local->tx_work, nfc_llcp_tx_work); snprintf(name, sizeof(name), "%s_llcp_tx_wq", dev_name(dev)); - local->tx_wq = alloc_workqueue(name, - WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1); + local->tx_wq = + alloc_workqueue(name, + WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, + 1); if (local->tx_wq == NULL) { err = -ENOMEM; goto err_local; @@ -943,8 +940,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) local->rx_pending = NULL; INIT_WORK(&local->rx_work, nfc_llcp_rx_work); snprintf(name, sizeof(name), "%s_llcp_rx_wq", dev_name(dev)); - local->rx_wq = alloc_workqueue(name, - WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1); + local->rx_wq = + alloc_workqueue(name, + WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, + 1); if (local->rx_wq == NULL) { err = -ENOMEM; goto err_tx_wq; @@ -952,8 +951,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); snprintf(name, sizeof(name), "%s_llcp_timeout_wq", dev_name(dev)); - local->timeout_wq = alloc_workqueue(name, - WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1); + local->timeout_wq = + alloc_workqueue(name, + WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, + 1); if (local->timeout_wq == NULL) { err = -ENOMEM; goto err_rx_wq; diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 70e1762d6e8..50680ce5ae4 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -166,7 +166,7 @@ struct nfc_llcp_sock { struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, - struct nfc_llcp_sock *sock); + struct nfc_llcp_sock *sock); u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); @@ -180,7 +180,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *sk, struct socket *newsock); /* TLV API */ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local, - u8 *tlv_array, u16 tlv_array_len); + u8 *tlv_array, u16 tlv_array_len); /* Commands API */ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); @@ -193,7 +193,7 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, - struct msghdr *msg, size_t len); + struct msghdr *msg, size_t len); int nfc_llcp_send_rr(struct nfc_llcp_sock *sock); /* Socket API */ diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 35825e20163..c13e02ebdef 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -78,9 +78,11 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) llcp_sock->local = local; llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; llcp_sock->service_name_len = min_t(unsigned int, - llcp_addr.service_name_len, NFC_LLCP_MAX_SERVICE_NAME); + llcp_addr.service_name_len, + NFC_LLCP_MAX_SERVICE_NAME); llcp_sock->service_name = kmemdup(llcp_addr.service_name, - llcp_sock->service_name_len, GFP_KERNEL); + llcp_sock->service_name_len, + GFP_KERNEL); llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); if (llcp_sock->ssap == LLCP_MAX_SAP) @@ -110,7 +112,7 @@ static int llcp_sock_listen(struct socket *sock, int backlog) lock_sock(sk); if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) - || sk->sk_state != LLCP_BOUND) { + || sk->sk_state != LLCP_BOUND) { ret = -EBADFD; goto error; } @@ -149,13 +151,13 @@ void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk) sock_hold(sk); list_add_tail(&llcp_sock->accept_queue, - &llcp_sock_parent->accept_queue); + &llcp_sock_parent->accept_queue); llcp_sock->parent = parent; sk_acceptq_added(parent); } struct sock *nfc_llcp_accept_dequeue(struct sock *parent, - struct socket *newsock) + struct socket *newsock) { struct nfc_llcp_sock *lsk, *n, *llcp_parent; struct sock *sk; @@ -163,7 +165,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent, llcp_parent = nfc_llcp_sock(parent); list_for_each_entry_safe(lsk, n, &llcp_parent->accept_queue, - accept_queue) { + accept_queue) { sk = &lsk->sk; lock_sock(sk); @@ -192,7 +194,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent, } static int llcp_sock_accept(struct socket *sock, struct socket *newsock, - int flags) + int flags) { DECLARE_WAITQUEUE(wait, current); struct sock *sk = sock->sk, *new_sk; @@ -248,7 +250,7 @@ error: static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) { - struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *) addr; + struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *)addr; struct sock *sk = sock->sk; struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); @@ -262,7 +264,7 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr, llcp_addr->ssap = llcp_sock->ssap; llcp_addr->service_name_len = llcp_sock->service_name_len; memcpy(llcp_addr->service_name, llcp_sock->service_name, - llcp_addr->service_name_len); + llcp_addr->service_name_len); return 0; } @@ -275,7 +277,7 @@ static inline unsigned int llcp_accept_poll(struct sock *parent) parent_sock = nfc_llcp_sock(parent); list_for_each_entry_safe(llcp_sock, n, &parent_sock->accept_queue, - accept_queue) { + accept_queue) { sk = &llcp_sock->sk; if (sk->sk_state == LLCP_CONNECTED) @@ -286,7 +288,7 @@ static inline unsigned int llcp_accept_poll(struct sock *parent) } static unsigned int llcp_sock_poll(struct file *file, struct socket *sock, - poll_table *wait) + poll_table *wait) { struct sock *sk = sock->sk; unsigned int mask = 0; @@ -348,7 +350,7 @@ static int llcp_sock_release(struct socket *sock) struct sock *accept_sk; list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, - accept_queue) { + accept_queue) { accept_sk = &lsk->sk; lock_sock(accept_sk); @@ -363,9 +365,8 @@ static int llcp_sock_release(struct socket *sock) /* Freeing the SAP */ if ((sk->sk_state == LLCP_CONNECTED - && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) || - sk->sk_state == LLCP_BOUND || - sk->sk_state == LLCP_LISTEN) + && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) || + sk->sk_state == LLCP_BOUND || sk->sk_state == LLCP_LISTEN) nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); release_sock(sk); @@ -378,7 +379,7 @@ out: } static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, - int len, int flags) + int len, int flags) { struct sock *sk = sock->sk; struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); @@ -390,7 +391,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags); if (!addr || len < sizeof(struct sockaddr_nfc) || - addr->sa_family != AF_NFC) { + addr->sa_family != AF_NFC) { pr_err("Invalid socket\n"); return -EINVAL; } @@ -401,7 +402,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, } pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx, - addr->target_idx, addr->nfc_protocol); + addr->target_idx, addr->nfc_protocol); lock_sock(sk); @@ -431,7 +432,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, device_unlock(&dev->dev); if (local->rf_mode == NFC_RF_INITIATOR && - addr->target_idx != local->target_idx) { + addr->target_idx != local->target_idx) { ret = -ENOLINK; goto put_dev; } @@ -449,9 +450,11 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, llcp_sock->dsap = LLCP_SAP_SDP; llcp_sock->nfc_protocol = addr->nfc_protocol; llcp_sock->service_name_len = min_t(unsigned int, - addr->service_name_len, NFC_LLCP_MAX_SERVICE_NAME); + addr->service_name_len, + NFC_LLCP_MAX_SERVICE_NAME); llcp_sock->service_name = kmemdup(addr->service_name, - llcp_sock->service_name_len, GFP_KERNEL); + llcp_sock->service_name_len, + GFP_KERNEL); local->sockets[llcp_sock->ssap] = llcp_sock; @@ -473,7 +476,7 @@ error: } static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len) + struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); @@ -514,7 +517,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, lock_sock(sk); if (sk->sk_state == LLCP_CLOSED && - skb_queue_empty(&sk->sk_receive_queue)) { + skb_queue_empty(&sk->sk_receive_queue)) { release_sock(sk); return 0; } @@ -527,7 +530,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) { pr_err("Recv datagram failed state %d %d %d", - sk->sk_state, err, sock_error(sk)); + sk->sk_state, err, sock_error(sk)); if (sk->sk_shutdown & RCV_SHUTDOWN) return 0; @@ -535,7 +538,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, return err; } - rlen = skb->len; /* real length of skb */ + rlen = skb->len; /* real length of skb */ copied = min_t(unsigned int, rlen, len); cskb = skb; @@ -664,7 +667,7 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock) } static int llcp_sock_create(struct net *net, struct socket *sock, - const struct nfc_protocol *nfc_proto) + const struct nfc_protocol *nfc_proto) { struct sock *sk; -- cgit v1.2.3-70-g09d2 From 0a40acb24602783fcf6881f915659148aa9807d7 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:53 +0100 Subject: NFC: Core code identation fixes Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/nfc.h | 24 +++++++++++----------- net/nfc/af_nfc.c | 2 +- net/nfc/core.c | 28 +++++++++++-------------- net/nfc/netlink.c | 57 ++++++++++++++++++++++++--------------------------- net/nfc/nfc.h | 13 ++++++------ net/nfc/rawsock.c | 16 +++++++-------- 6 files changed, 66 insertions(+), 74 deletions(-) (limited to 'net') diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index d608e4eac66..bac070bf351 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -57,11 +57,11 @@ struct nfc_ops { u8 *gb, size_t gb_len); int (*dep_link_down)(struct nfc_dev *dev); int (*activate_target)(struct nfc_dev *dev, u32 target_idx, - u32 protocol); + u32 protocol); void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx); int (*data_exchange)(struct nfc_dev *dev, u32 target_idx, - struct sk_buff *skb, data_exchange_cb_t cb, - void *cb_context); + struct sk_buff *skb, data_exchange_cb_t cb, + void *cb_context); }; #define NFC_TARGET_IDX_ANY -1 @@ -110,9 +110,9 @@ struct nfc_dev { extern struct class nfc_class; struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, - u32 supported_protocols, - int tx_headroom, - int tx_tailroom); + u32 supported_protocols, + int tx_headroom, + int tx_tailroom); /** * nfc_free_device - free nfc device @@ -135,7 +135,7 @@ void nfc_unregister_device(struct nfc_dev *dev); * @dev: The parent device */ static inline void nfc_set_parent_dev(struct nfc_dev *nfc_dev, - struct device *dev) + struct device *dev) { nfc_dev->dev.parent = dev; } @@ -172,15 +172,15 @@ static inline const char *nfc_device_name(struct nfc_dev *dev) } struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk, - unsigned int flags, unsigned int size, - unsigned int *err); + unsigned int flags, unsigned int size, + unsigned int *err); struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp); int nfc_set_remote_general_bytes(struct nfc_dev *dev, - u8 *gt, u8 gt_len); + u8 *gt, u8 gt_len); -int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, - int ntargets); +int nfc_targets_found(struct nfc_dev *dev, + struct nfc_target *targets, int ntargets); int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx, u8 comm_mode, u8 rf_mode); diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c index da67756425c..9d68441e2a5 100644 --- a/net/nfc/af_nfc.c +++ b/net/nfc/af_nfc.c @@ -30,7 +30,7 @@ static DEFINE_RWLOCK(proto_tab_lock); static const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX]; static int nfc_sock_create(struct net *net, struct socket *sock, int proto, - int kern) + int kern) { int rc = -EPROTONOSUPPORT; diff --git a/net/nfc/core.c b/net/nfc/core.c index f4f526f7321..295d129864d 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -256,7 +256,7 @@ error: } int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx, - u8 comm_mode, u8 rf_mode) + u8 comm_mode, u8 rf_mode) { dev->dep_link_up = true; dev->dep_rf_mode = rf_mode; @@ -336,10 +336,8 @@ error: * * The user must wait for the callback before calling this function again. */ -int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, - struct sk_buff *skb, - data_exchange_cb_t cb, - void *cb_context) +int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context) { int rc; @@ -363,8 +361,7 @@ error: int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len) { - pr_debug("dev_name=%s gb_len=%d\n", - dev_name(&dev->dev), gb_len); + pr_debug("dev_name=%s gb_len=%d\n", dev_name(&dev->dev), gb_len); if (gb_len > NFC_MAX_GT_LEN) return -EINVAL; @@ -380,8 +377,8 @@ EXPORT_SYMBOL(nfc_set_remote_general_bytes); * @gfp: gfp flags */ struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk, - unsigned int flags, unsigned int size, - unsigned int *err) + unsigned int flags, unsigned int size, + unsigned int *err) { struct sk_buff *skb; unsigned int total_size; @@ -428,8 +425,8 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); * are found. After calling this function, the device driver must stop * polling for targets. */ -int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, - int n_targets) +int nfc_targets_found(struct nfc_dev *dev, + struct nfc_target *targets, int n_targets) { pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); @@ -441,7 +438,7 @@ int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, kfree(dev->targets); dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target), - GFP_ATOMIC); + GFP_ATOMIC); if (!dev->targets) { dev->n_targets = 0; @@ -501,15 +498,14 @@ struct nfc_dev *nfc_get_device(unsigned idx) * @supported_protocols: NFC protocols supported by the device */ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, - u32 supported_protocols, - int tx_headroom, - int tx_tailroom) + u32 supported_protocols, + int tx_headroom, int tx_tailroom) { static atomic_t dev_no = ATOMIC_INIT(0); struct nfc_dev *dev; if (!ops->start_poll || !ops->stop_poll || !ops->activate_target || - !ops->deactivate_target || !ops->data_exchange) + !ops->deactivate_target || !ops->data_exchange) return NULL; if (!supported_protocols) diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index fa620d03799..6404052d6c0 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -52,31 +52,30 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { }; static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, - struct netlink_callback *cb, int flags) + struct netlink_callback *cb, int flags) { void *hdr; hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, - &nfc_genl_family, flags, NFC_CMD_GET_TARGET); + &nfc_genl_family, flags, NFC_CMD_GET_TARGET); if (!hdr) return -EMSGSIZE; genl_dump_check_consistent(cb, hdr, &nfc_genl_family); NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target->idx); - NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, - target->supported_protocols); + NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols); NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res); NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res); if (target->nfcid1_len > 0) NLA_PUT(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len, - target->nfcid1); + target->nfcid1); if (target->sensb_res_len > 0) NLA_PUT(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len, - target->sensb_res); + target->sensb_res); if (target->sensf_res_len > 0) NLA_PUT(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len, - target->sensf_res); + target->sensf_res); return genlmsg_end(msg, hdr); @@ -92,9 +91,9 @@ static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb) u32 idx; rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize, - nfc_genl_family.attrbuf, - nfc_genl_family.maxattr, - nfc_genl_policy); + nfc_genl_family.attrbuf, + nfc_genl_family.maxattr, + nfc_genl_policy); if (rc < 0) return ERR_PTR(rc); @@ -111,7 +110,7 @@ static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb) } static int nfc_genl_dump_targets(struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb) { int i = cb->args[0]; struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; @@ -131,7 +130,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb, while (i < dev->n_targets) { rc = nfc_genl_send_target(skb, &dev->targets[i], cb, - NLM_F_MULTI); + NLM_F_MULTI); if (rc < 0) break; @@ -167,7 +166,7 @@ int nfc_genl_targets_found(struct nfc_dev *dev) return -ENOMEM; hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, - NFC_EVENT_TARGETS_FOUND); + NFC_EVENT_TARGETS_FOUND); if (!hdr) goto free_msg; @@ -194,7 +193,7 @@ int nfc_genl_device_added(struct nfc_dev *dev) return -ENOMEM; hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, - NFC_EVENT_DEVICE_ADDED); + NFC_EVENT_DEVICE_ADDED); if (!hdr) goto free_msg; @@ -226,7 +225,7 @@ int nfc_genl_device_removed(struct nfc_dev *dev) return -ENOMEM; hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, - NFC_EVENT_DEVICE_REMOVED); + NFC_EVENT_DEVICE_REMOVED); if (!hdr) goto free_msg; @@ -246,14 +245,14 @@ free_msg: } static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, - u32 pid, u32 seq, - struct netlink_callback *cb, - int flags) + u32 pid, u32 seq, + struct netlink_callback *cb, + int flags) { void *hdr; hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags, - NFC_CMD_GET_DEVICE); + NFC_CMD_GET_DEVICE); if (!hdr) return -EMSGSIZE; @@ -273,7 +272,7 @@ nla_put_failure: } static int nfc_genl_dump_devices(struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb) { struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; @@ -300,8 +299,7 @@ static int nfc_genl_dump_devices(struct sk_buff *skb, int rc; rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - cb, NLM_F_MULTI); + cb->nlh->nlmsg_seq, cb, NLM_F_MULTI); if (rc < 0) break; @@ -326,7 +324,7 @@ static int nfc_genl_dump_devices_done(struct netlink_callback *cb) } int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, - u8 comm_mode, u8 rf_mode) + u8 comm_mode, u8 rf_mode) { struct sk_buff *msg; void *hdr; @@ -337,8 +335,7 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, if (!msg) return -ENOMEM; - hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, - NFC_CMD_DEP_LINK_UP); + hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, NFC_CMD_DEP_LINK_UP); if (!hdr) goto free_msg; @@ -375,7 +372,7 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev) return -ENOMEM; hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, - NFC_CMD_DEP_LINK_DOWN); + NFC_CMD_DEP_LINK_DOWN); if (!hdr) goto free_msg; @@ -417,7 +414,7 @@ static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info) } rc = nfc_genl_send_device(msg, dev, info->snd_pid, info->snd_seq, - NULL, 0); + NULL, 0); if (rc < 0) goto out_free; @@ -484,7 +481,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info) pr_debug("Poll start\n"); if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || - !info->attrs[NFC_ATTR_PROTOCOLS]) + !info->attrs[NFC_ATTR_PROTOCOLS]) return -EINVAL; idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); @@ -640,7 +637,7 @@ static struct genl_ops nfc_genl_ops[] = { }; static int nfc_genl_rcv_nl_event(struct notifier_block *this, - unsigned long event, void *ptr) + unsigned long event, void *ptr) { struct netlink_notify *n = ptr; struct class_dev_iter iter; @@ -693,7 +690,7 @@ int __init nfc_genl_init(void) int rc; rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops, - ARRAY_SIZE(nfc_genl_ops)); + ARRAY_SIZE(nfc_genl_ops)); if (rc) return rc; diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index 2fd83b16df6..ec8794c1099 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -32,7 +32,7 @@ struct nfc_protocol { struct proto *proto; struct module *owner; int (*create)(struct net *net, struct socket *sock, - const struct nfc_protocol *nfc_proto); + const struct nfc_protocol *nfc_proto); }; struct nfc_rawsock { @@ -65,7 +65,7 @@ static inline void nfc_llcp_mac_is_down(struct nfc_dev *dev) } static inline void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, - u8 comm_mode, u8 rf_mode) + u8 comm_mode, u8 rf_mode) { } @@ -78,7 +78,8 @@ static inline void nfc_llcp_unregister_device(struct nfc_dev *dev) { } -static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) +static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev, + u8 *gb, u8 gb_len) { return 0; } @@ -168,9 +169,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol); int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx); -int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, - struct sk_buff *skb, - data_exchange_cb_t cb, - void *cb_context); +int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context); #endif /* __LOCAL_NFC_H */ diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 5325439b0c6..5a839ceb2e8 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -63,7 +63,7 @@ static int rawsock_release(struct socket *sock) } static int rawsock_connect(struct socket *sock, struct sockaddr *_addr, - int len, int flags) + int len, int flags) { struct sock *sk = sock->sk; struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr; @@ -73,7 +73,7 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr, pr_debug("sock=%p sk=%p flags=%d\n", sock, sk, flags); if (!addr || len < sizeof(struct sockaddr_nfc) || - addr->sa_family != AF_NFC) + addr->sa_family != AF_NFC) return -EINVAL; pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", @@ -120,7 +120,7 @@ static int rawsock_add_header(struct sk_buff *skb) } static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb, - int err) + int err) { struct sock *sk = (struct sock *) context; @@ -173,7 +173,7 @@ static void rawsock_tx_work(struct work_struct *work) sock_hold(sk); rc = nfc_data_exchange(dev, target_idx, skb, - rawsock_data_exchange_complete, sk); + rawsock_data_exchange_complete, sk); if (rc) { rawsock_report_error(sk, rc); sock_put(sk); @@ -181,7 +181,7 @@ static void rawsock_tx_work(struct work_struct *work) } static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len) + struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct nfc_dev *dev = nfc_rawsock(sk)->dev; @@ -218,7 +218,7 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock, } static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len, int flags) + struct msghdr *msg, size_t len, int flags) { int noblock = flags & MSG_DONTWAIT; struct sock *sk = sock->sk; @@ -274,7 +274,7 @@ static void rawsock_destruct(struct sock *sk) if (sk->sk_state == TCP_ESTABLISHED) { nfc_deactivate_target(nfc_rawsock(sk)->dev, - nfc_rawsock(sk)->target_idx); + nfc_rawsock(sk)->target_idx); nfc_put_device(nfc_rawsock(sk)->dev); } @@ -287,7 +287,7 @@ static void rawsock_destruct(struct sock *sk) } static int rawsock_create(struct net *net, struct socket *sock, - const struct nfc_protocol *nfc_proto) + const struct nfc_protocol *nfc_proto) { struct sock *sk; -- cgit v1.2.3-70-g09d2 From eb9bc6e9a0ac668d2283b8fea1534f8ba31d1692 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:54 +0100 Subject: NFC: NCI code identation fixes Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/nci_core.h | 10 ++-- net/nfc/nci/core.c | 113 ++++++++++++++++++++++----------------------- net/nfc/nci/data.c | 28 +++++------ net/nfc/nci/ntf.c | 75 ++++++++++++++---------------- net/nfc/nci/rsp.c | 17 ++++--- 5 files changed, 116 insertions(+), 127 deletions(-) (limited to 'net') diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 86fee8b5c65..feba74027ff 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -141,17 +141,17 @@ struct nci_dev { /* ----- NCI Devices ----- */ struct nci_dev *nci_allocate_device(struct nci_ops *ops, - __u32 supported_protocols, - int tx_headroom, - int tx_tailroom); + __u32 supported_protocols, + int tx_headroom, + int tx_tailroom); void nci_free_device(struct nci_dev *ndev); int nci_register_device(struct nci_dev *ndev); void nci_unregister_device(struct nci_dev *ndev); int nci_recv_frame(struct sk_buff *skb); static inline struct sk_buff *nci_skb_alloc(struct nci_dev *ndev, - unsigned int len, - gfp_t how) + unsigned int len, + gfp_t how) { struct sk_buff *skb; diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index a47e90c7d9d..9ec065bb9ee 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -66,9 +66,8 @@ static void nci_req_cancel(struct nci_dev *ndev, int err) /* Execute request and wait for completion. */ static int __nci_request(struct nci_dev *ndev, - void (*req)(struct nci_dev *ndev, unsigned long opt), - unsigned long opt, - __u32 timeout) + void (*req)(struct nci_dev *ndev, unsigned long opt), + unsigned long opt, __u32 timeout) { int rc = 0; long completion_rc; @@ -77,9 +76,9 @@ static int __nci_request(struct nci_dev *ndev, init_completion(&ndev->req_completion); req(ndev, opt); - completion_rc = wait_for_completion_interruptible_timeout( - &ndev->req_completion, - timeout); + completion_rc = + wait_for_completion_interruptible_timeout(&ndev->req_completion, + timeout); pr_debug("wait_for_completion return %ld\n", completion_rc); @@ -110,8 +109,9 @@ static int __nci_request(struct nci_dev *ndev, } static inline int nci_request(struct nci_dev *ndev, - void (*req)(struct nci_dev *ndev, unsigned long opt), - unsigned long opt, __u32 timeout) + void (*req)(struct nci_dev *ndev, + unsigned long opt), + unsigned long opt, __u32 timeout) { int rc; @@ -152,14 +152,14 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt) /* by default mapping is set to NCI_RF_INTERFACE_FRAME */ for (i = 0; i < ndev->num_supported_rf_interfaces; i++) { if (ndev->supported_rf_interfaces[i] == - NCI_RF_INTERFACE_ISO_DEP) { + NCI_RF_INTERFACE_ISO_DEP) { cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; cfg[*num].mode = NCI_DISC_MAP_MODE_POLL | NCI_DISC_MAP_MODE_LISTEN; cfg[*num].rf_interface = NCI_RF_INTERFACE_ISO_DEP; (*num)++; } else if (ndev->supported_rf_interfaces[i] == - NCI_RF_INTERFACE_NFC_DEP) { + NCI_RF_INTERFACE_NFC_DEP) { cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; cfg[*num].mode = NCI_DISC_MAP_MODE_POLL | NCI_DISC_MAP_MODE_LISTEN; @@ -172,8 +172,7 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt) } nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD, - (1 + ((*num)*sizeof(struct disc_map_config))), - &cmd); + (1 + ((*num) * sizeof(struct disc_map_config))), &cmd); } static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) @@ -184,36 +183,36 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) cmd.num_disc_configs = 0; if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && - (protocols & NFC_PROTO_JEWEL_MASK - || protocols & NFC_PROTO_MIFARE_MASK - || protocols & NFC_PROTO_ISO14443_MASK - || protocols & NFC_PROTO_NFC_DEP_MASK)) { + (protocols & NFC_PROTO_JEWEL_MASK + || protocols & NFC_PROTO_MIFARE_MASK + || protocols & NFC_PROTO_ISO14443_MASK + || protocols & NFC_PROTO_NFC_DEP_MASK)) { cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = - NCI_NFC_A_PASSIVE_POLL_MODE; + NCI_NFC_A_PASSIVE_POLL_MODE; cmd.disc_configs[cmd.num_disc_configs].frequency = 1; cmd.num_disc_configs++; } if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && - (protocols & NFC_PROTO_ISO14443_MASK)) { + (protocols & NFC_PROTO_ISO14443_MASK)) { cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = - NCI_NFC_B_PASSIVE_POLL_MODE; + NCI_NFC_B_PASSIVE_POLL_MODE; cmd.disc_configs[cmd.num_disc_configs].frequency = 1; cmd.num_disc_configs++; } if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && - (protocols & NFC_PROTO_FELICA_MASK - || protocols & NFC_PROTO_NFC_DEP_MASK)) { + (protocols & NFC_PROTO_FELICA_MASK + || protocols & NFC_PROTO_NFC_DEP_MASK)) { cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = - NCI_NFC_F_PASSIVE_POLL_MODE; + NCI_NFC_F_PASSIVE_POLL_MODE; cmd.disc_configs[cmd.num_disc_configs].frequency = 1; cmd.num_disc_configs++; } nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD, - (1 + (cmd.num_disc_configs*sizeof(struct disc_config))), - &cmd); + (1 + (cmd.num_disc_configs * sizeof(struct disc_config))), + &cmd); } struct nci_rf_discover_select_param { @@ -224,7 +223,7 @@ struct nci_rf_discover_select_param { static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt) { struct nci_rf_discover_select_param *param = - (struct nci_rf_discover_select_param *)opt; + (struct nci_rf_discover_select_param *)opt; struct nci_rf_discover_select_cmd cmd; cmd.rf_discovery_id = param->rf_discovery_id; @@ -245,8 +244,7 @@ static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt) } nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD, - sizeof(struct nci_rf_discover_select_cmd), - &cmd); + sizeof(struct nci_rf_discover_select_cmd), &cmd); } static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt) @@ -256,8 +254,7 @@ static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt) cmd.type = NCI_DEACTIVATE_TYPE_IDLE_MODE; nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD, - sizeof(struct nci_rf_deactivate_cmd), - &cmd); + sizeof(struct nci_rf_deactivate_cmd), &cmd); } static int nci_open_device(struct nci_dev *ndev) @@ -281,16 +278,16 @@ static int nci_open_device(struct nci_dev *ndev) set_bit(NCI_INIT, &ndev->flags); rc = __nci_request(ndev, nci_reset_req, 0, - msecs_to_jiffies(NCI_RESET_TIMEOUT)); + msecs_to_jiffies(NCI_RESET_TIMEOUT)); if (!rc) { rc = __nci_request(ndev, nci_init_req, 0, - msecs_to_jiffies(NCI_INIT_TIMEOUT)); + msecs_to_jiffies(NCI_INIT_TIMEOUT)); } if (!rc) { rc = __nci_request(ndev, nci_init_complete_req, 0, - msecs_to_jiffies(NCI_INIT_TIMEOUT)); + msecs_to_jiffies(NCI_INIT_TIMEOUT)); } clear_bit(NCI_INIT, &ndev->flags); @@ -340,7 +337,7 @@ static int nci_close_device(struct nci_dev *ndev) set_bit(NCI_INIT, &ndev->flags); __nci_request(ndev, nci_reset_req, 0, - msecs_to_jiffies(NCI_RESET_TIMEOUT)); + msecs_to_jiffies(NCI_RESET_TIMEOUT)); clear_bit(NCI_INIT, &ndev->flags); /* Flush cmd wq */ @@ -396,7 +393,7 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) int rc; if ((atomic_read(&ndev->state) == NCI_DISCOVERY) || - (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) { + (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) { pr_err("unable to start poll, since poll is already active\n"); return -EBUSY; } @@ -407,17 +404,17 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols) } if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) || - (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) { + (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) { pr_debug("target active or w4 select, implicitly deactivate\n"); rc = nci_request(ndev, nci_rf_deactivate_req, 0, - msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); + msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); if (rc) return -EBUSY; } rc = nci_request(ndev, nci_rf_discover_req, protocols, - msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); + msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); if (!rc) ndev->poll_prots = protocols; @@ -430,17 +427,17 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); if ((atomic_read(&ndev->state) != NCI_DISCOVERY) && - (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) { + (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) { pr_err("unable to stop poll, since poll is not active\n"); return; } nci_request(ndev, nci_rf_deactivate_req, 0, - msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); + msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); } static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, - __u32 protocol) + __u32 protocol) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); struct nci_rf_discover_select_param param; @@ -451,7 +448,7 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) && - (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { + (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { pr_err("there is no available target to activate\n"); return -EINVAL; } @@ -494,8 +491,8 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; rc = nci_request(ndev, nci_rf_discover_select_req, - (unsigned long)¶m, - msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT)); + (unsigned long)¶m, + msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT)); } if (!rc) @@ -519,14 +516,13 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) { nci_request(ndev, nci_rf_deactivate_req, 0, - msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); + msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); } } static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx, - struct sk_buff *skb, - data_exchange_cb_t cb, - void *cb_context) + struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); int rc; @@ -571,9 +567,8 @@ static struct nfc_ops nci_nfc_ops = { * @supported_protocols: NFC protocols supported by the device */ struct nci_dev *nci_allocate_device(struct nci_ops *ops, - __u32 supported_protocols, - int tx_headroom, - int tx_tailroom) + __u32 supported_protocols, + int tx_headroom, int tx_tailroom) { struct nci_dev *ndev; @@ -594,9 +589,9 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops, ndev->tx_tailroom = tx_tailroom; ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops, - supported_protocols, - tx_headroom + NCI_DATA_HDR_SIZE, - tx_tailroom); + supported_protocols, + tx_headroom + NCI_DATA_HDR_SIZE, + tx_tailroom); if (!ndev->nfc_dev) goto free_exit; @@ -668,9 +663,9 @@ int nci_register_device(struct nci_dev *ndev) skb_queue_head_init(&ndev->tx_q); setup_timer(&ndev->cmd_timer, nci_cmd_timer, - (unsigned long) ndev); + (unsigned long) ndev); setup_timer(&ndev->data_timer, nci_data_timer, - (unsigned long) ndev); + (unsigned long) ndev); mutex_init(&ndev->req_lock); @@ -719,7 +714,7 @@ int nci_recv_frame(struct sk_buff *skb) pr_debug("len %d\n", skb->len); if (!ndev || (!test_bit(NCI_UP, &ndev->flags) - && !test_bit(NCI_INIT, &ndev->flags))) { + && !test_bit(NCI_INIT, &ndev->flags))) { kfree_skb(skb); return -ENXIO; } @@ -799,7 +794,7 @@ static void nci_tx_work(struct work_struct *work) /* Check if data flow control is used */ if (atomic_read(&ndev->credits_cnt) != - NCI_DATA_FLOW_CONTROL_NOT_USED) + NCI_DATA_FLOW_CONTROL_NOT_USED) atomic_dec(&ndev->credits_cnt); pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n", @@ -810,7 +805,7 @@ static void nci_tx_work(struct work_struct *work) nci_send_frame(skb); mod_timer(&ndev->data_timer, - jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT)); + jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT)); } } @@ -879,6 +874,6 @@ static void nci_cmd_work(struct work_struct *work) nci_send_frame(skb); mod_timer(&ndev->cmd_timer, - jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT)); + jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT)); } } diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index 7880ae924d5..a0bc326308a 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c @@ -35,8 +35,7 @@ #include /* Complete data exchange transaction and forward skb to nfc core */ -void nci_data_exchange_complete(struct nci_dev *ndev, - struct sk_buff *skb, +void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb, int err) { data_exchange_cb_t cb = ndev->data_exchange_cb; @@ -67,9 +66,9 @@ void nci_data_exchange_complete(struct nci_dev *ndev, /* ----------------- NCI TX Data ----------------- */ static inline void nci_push_data_hdr(struct nci_dev *ndev, - __u8 conn_id, - struct sk_buff *skb, - __u8 pbf) + __u8 conn_id, + struct sk_buff *skb, + __u8 pbf) { struct nci_data_hdr *hdr; int plen = skb->len; @@ -86,8 +85,8 @@ static inline void nci_push_data_hdr(struct nci_dev *ndev, } static int nci_queue_tx_data_frags(struct nci_dev *ndev, - __u8 conn_id, - struct sk_buff *skb) { + __u8 conn_id, + struct sk_buff *skb) { int total_len = skb->len; unsigned char *data = skb->data; unsigned long flags; @@ -105,8 +104,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev, min_t(int, total_len, ndev->max_data_pkt_payload_size); skb_frag = nci_skb_alloc(ndev, - (NCI_DATA_HDR_SIZE + frag_len), - GFP_KERNEL); + (NCI_DATA_HDR_SIZE + frag_len), + GFP_KERNEL); if (skb_frag == NULL) { rc = -ENOMEM; goto free_exit; @@ -118,7 +117,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev, /* second, set the header */ nci_push_data_hdr(ndev, conn_id, skb_frag, - ((total_len == frag_len) ? (NCI_PBF_LAST) : (NCI_PBF_CONT))); + ((total_len == frag_len) ? + (NCI_PBF_LAST) : (NCI_PBF_CONT))); __skb_queue_tail(&frags_q, skb_frag); @@ -186,8 +186,8 @@ exit: /* ----------------- NCI RX Data ----------------- */ static void nci_add_rx_data_frag(struct nci_dev *ndev, - struct sk_buff *skb, - __u8 pbf) + struct sk_buff *skb, + __u8 pbf) { int reassembly_len; int err = 0; @@ -211,8 +211,8 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev, /* second, combine the two fragments */ memcpy(skb_push(skb, reassembly_len), - ndev->rx_data_reassembly->data, - reassembly_len); + ndev->rx_data_reassembly->data, + reassembly_len); /* third, free old reassembly */ kfree_skb(ndev->rx_data_reassembly); diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 03e7b4626a3..2e3dee42196 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -40,7 +40,7 @@ /* Handle NCI Notification packets */ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { struct nci_core_conn_credit_ntf *ntf = (void *) skb->data; int i; @@ -62,7 +62,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev, if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) { /* found static rf connection */ atomic_add(ntf->conn_entries[i].credits, - &ndev->credits_cnt); + &ndev->credits_cnt); } } @@ -72,7 +72,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev, } static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { __u8 status = skb->data[0]; @@ -80,7 +80,7 @@ static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev, if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { /* Activation failed, so complete the request - (the state remains the same) */ + (the state remains the same) */ nci_req_complete(ndev, status); } } @@ -101,7 +101,7 @@ static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev, static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, struct rf_tech_specific_params_nfca_poll *nfca_poll, - __u8 *data) + __u8 *data) { nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); data += 2; @@ -128,7 +128,7 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, struct rf_tech_specific_params_nfcb_poll *nfcb_poll, - __u8 *data) + __u8 *data) { nfcb_poll->sensb_res_len = *data++; @@ -142,13 +142,13 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, struct rf_tech_specific_params_nfcf_poll *nfcf_poll, - __u8 *data) + __u8 *data) { nfcf_poll->bit_rate = *data++; nfcf_poll->sensf_res_len = *data++; pr_debug("bit_rate %d, sensf_res_len %d\n", - nfcf_poll->bit_rate, nfcf_poll->sensf_res_len); + nfcf_poll->bit_rate, nfcf_poll->sensf_res_len); memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len); data += nfcf_poll->sensf_res_len; @@ -189,7 +189,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev, target->nfcid1_len = nfca_poll->nfcid1_len; if (target->nfcid1_len > 0) { memcpy(target->nfcid1, nfca_poll->nfcid1, - target->nfcid1_len); + target->nfcid1_len); } } else if (rf_tech_and_mode == NCI_NFC_B_PASSIVE_POLL_MODE) { nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params; @@ -197,7 +197,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev, target->sensb_res_len = nfcb_poll->sensb_res_len; if (target->sensb_res_len > 0) { memcpy(target->sensb_res, nfcb_poll->sensb_res, - target->sensb_res_len); + target->sensb_res_len); } } else if (rf_tech_and_mode == NCI_NFC_F_PASSIVE_POLL_MODE) { nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params; @@ -205,7 +205,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev, target->sensf_res_len = nfcf_poll->sensf_res_len; if (target->sensf_res_len > 0) { memcpy(target->sensf_res, nfcf_poll->sensf_res, - target->sensf_res_len); + target->sensf_res_len); } } else { pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode); @@ -220,7 +220,7 @@ static int nci_add_new_protocol(struct nci_dev *ndev, } static void nci_add_new_target(struct nci_dev *ndev, - struct nci_rf_discover_ntf *ntf) + struct nci_rf_discover_ntf *ntf) { struct nfc_target *target; int i, rc; @@ -230,8 +230,8 @@ static void nci_add_new_target(struct nci_dev *ndev, if (target->idx == ntf->rf_discovery_id) { /* This target already exists, add the new protocol */ nci_add_new_protocol(ndev, target, ntf->rf_protocol, - ntf->rf_tech_and_mode, - &ntf->rf_tech_specific_params); + ntf->rf_tech_and_mode, + &ntf->rf_tech_specific_params); return; } } @@ -245,27 +245,27 @@ static void nci_add_new_target(struct nci_dev *ndev, target = &ndev->targets[ndev->n_targets]; rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, - ntf->rf_tech_and_mode, - &ntf->rf_tech_specific_params); + ntf->rf_tech_and_mode, + &ntf->rf_tech_specific_params); if (!rc) { target->idx = ntf->rf_discovery_id; ndev->n_targets++; pr_debug("target_idx %d, n_targets %d\n", target->idx, - ndev->n_targets); + ndev->n_targets); } } void nci_clear_target_list(struct nci_dev *ndev) { memset(ndev->targets, 0, - (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS)); + (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS)); ndev->n_targets = 0; } static void nci_rf_discover_ntf_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { struct nci_rf_discover_ntf ntf; __u8 *data = skb->data; @@ -280,7 +280,7 @@ static void nci_rf_discover_ntf_packet(struct nci_dev *ndev, pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol); pr_debug("rf_tech_and_mode 0x%x\n", ntf.rf_tech_and_mode); pr_debug("rf_tech_specific_params_len %d\n", - ntf.rf_tech_specific_params_len); + ntf.rf_tech_specific_params_len); if (ntf.rf_tech_specific_params_len > 0) { switch (ntf.rf_tech_and_mode) { @@ -318,7 +318,7 @@ static void nci_rf_discover_ntf_packet(struct nci_dev *ndev, } else { atomic_set(&ndev->state, NCI_W4_HOST_SELECT); nfc_targets_found(ndev->nfc_dev, ndev->targets, - ndev->n_targets); + ndev->n_targets); } } @@ -335,20 +335,17 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len); if (nfca_poll->rats_res_len > 0) { memcpy(nfca_poll->rats_res, - data, - nfca_poll->rats_res_len); + data, nfca_poll->rats_res_len); } break; case NCI_NFC_B_PASSIVE_POLL_MODE: nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep; nfcb_poll->attrib_res_len = *data++; - pr_debug("attrib_res_len %d\n", - nfcb_poll->attrib_res_len); + pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len); if (nfcb_poll->attrib_res_len > 0) { memcpy(nfcb_poll->attrib_res, - data, - nfcb_poll->attrib_res_len); + data, nfcb_poll->attrib_res_len); } break; @@ -362,7 +359,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, } static void nci_target_auto_activated(struct nci_dev *ndev, - struct nci_rf_intf_activated_ntf *ntf) + struct nci_rf_intf_activated_ntf *ntf) { struct nfc_target *target; int rc; @@ -370,8 +367,8 @@ static void nci_target_auto_activated(struct nci_dev *ndev, target = &ndev->targets[ndev->n_targets]; rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol, - ntf->activation_rf_tech_and_mode, - &ntf->rf_tech_specific_params); + ntf->activation_rf_tech_and_mode, + &ntf->rf_tech_specific_params); if (rc) return; @@ -384,7 +381,7 @@ static void nci_target_auto_activated(struct nci_dev *ndev, } static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { struct nci_rf_intf_activated_ntf ntf; __u8 *data = skb->data; @@ -405,7 +402,8 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, ntf.activation_rf_tech_and_mode); pr_debug("max_data_pkt_payload_size 0x%x\n", ntf.max_data_pkt_payload_size); - pr_debug("initial_num_credits 0x%x\n", ntf.initial_num_credits); + pr_debug("initial_num_credits 0x%x\n", + ntf.initial_num_credits); pr_debug("rf_tech_specific_params_len %d\n", ntf.rf_tech_specific_params_len); @@ -441,18 +439,15 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, pr_debug("data_exch_rf_tech_and_mode 0x%x\n", ntf.data_exch_rf_tech_and_mode); - pr_debug("data_exch_tx_bit_rate 0x%x\n", - ntf.data_exch_tx_bit_rate); - pr_debug("data_exch_rx_bit_rate 0x%x\n", - ntf.data_exch_rx_bit_rate); - pr_debug("activation_params_len %d\n", - ntf.activation_params_len); + pr_debug("data_exch_tx_bit_rate 0x%x\n", ntf.data_exch_tx_bit_rate); + pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate); + pr_debug("activation_params_len %d\n", ntf.activation_params_len); if (ntf.activation_params_len > 0) { switch (ntf.rf_interface) { case NCI_RF_INTERFACE_ISO_DEP: err = nci_extract_activation_params_iso_dep(ndev, - &ntf, data); + &ntf, data); break; case NCI_RF_INTERFACE_FRAME: @@ -489,7 +484,7 @@ exit: } static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { struct nci_rf_deactivate_ntf *ntf = (void *) skb->data; diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index aa63b1e9918..3003c3390e4 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -67,19 +67,18 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces; if (ndev->num_supported_rf_interfaces > - NCI_MAX_SUPPORTED_RF_INTERFACES) { + NCI_MAX_SUPPORTED_RF_INTERFACES) { ndev->num_supported_rf_interfaces = NCI_MAX_SUPPORTED_RF_INTERFACES; } memcpy(ndev->supported_rf_interfaces, - rsp_1->supported_rf_interfaces, - ndev->num_supported_rf_interfaces); + rsp_1->supported_rf_interfaces, + ndev->num_supported_rf_interfaces); rsp_2 = (void *) (skb->data + 6 + rsp_1->num_supported_rf_interfaces); - ndev->max_logical_connections = - rsp_2->max_logical_connections; + ndev->max_logical_connections = rsp_2->max_logical_connections; ndev->max_routing_table_size = __le16_to_cpu(rsp_2->max_routing_table_size); ndev->max_ctrl_pkt_payload_len = @@ -121,7 +120,7 @@ exit: } static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { __u8 status = skb->data[0]; @@ -143,7 +142,7 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) } static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { __u8 status = skb->data[0]; @@ -155,7 +154,7 @@ static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev, } static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, - struct sk_buff *skb) + struct sk_buff *skb) { __u8 status = skb->data[0]; @@ -163,7 +162,7 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, /* If target was active, complete the request only in deactivate_ntf */ if ((status != NCI_STATUS_OK) || - (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { + (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { nci_clear_target_list(ndev); atomic_set(&ndev->state, NCI_IDLE); nci_req_complete(ndev, status); -- cgit v1.2.3-70-g09d2 From 95f050bf7f64be5168ae2e2c715bb0b0ded141d1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 6 Mar 2012 16:12:15 -0500 Subject: net: Use bool for return value of dev_valid_name(). Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- net/core/dev.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4d279c5287f..a89933bc4f2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2122,7 +2122,7 @@ extern int netdev_rx_handler_register(struct net_device *dev, void *rx_handler_data); extern void netdev_rx_handler_unregister(struct net_device *dev); -extern int dev_valid_name(const char *name); +extern bool dev_valid_name(const char *name); extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); extern int dev_ethtool(struct net *net, struct ifreq *); extern unsigned dev_get_flags(const struct net_device *); diff --git a/net/core/dev.c b/net/core/dev.c index 5ef3b65c368..0090809af7b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -848,21 +848,21 @@ EXPORT_SYMBOL(dev_get_by_flags_rcu); * to allow sysfs to work. We also disallow any kind of * whitespace. */ -int dev_valid_name(const char *name) +bool dev_valid_name(const char *name) { if (*name == '\0') - return 0; + return false; if (strlen(name) >= IFNAMSIZ) - return 0; + return false; if (!strcmp(name, ".") || !strcmp(name, "..")) - return 0; + return false; while (*name) { if (*name == '/' || isspace(*name)) - return 0; + return false; name++; } - return 1; + return true; } EXPORT_SYMBOL(dev_valid_name); -- cgit v1.2.3-70-g09d2 From d6ddef9e641d1229d4ec841dc75ae703171c3e92 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Mon, 5 Mar 2012 14:45:17 +0000 Subject: IPv6: Fix not join all-router mcast group when forwarding set. When forwarding was set and a new net device is register, we need add this device to the all-router mcast group. Signed-off-by: Li Wei Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c02280a4d12..6b8ebc5da0e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -434,6 +434,10 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) /* Join all-node multicast group */ ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); + /* Join all-router multicast group if forwarding is set */ + if (ndev->cnf.forwarding && dev && (dev->flags & IFF_MULTICAST)) + ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); + return ndev; } -- cgit v1.2.3-70-g09d2 From 651a68ea2ce9738b84e928836053b2e0fb5db2ba Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 6 Mar 2012 15:04:04 -0800 Subject: openvswitch: Honor dp_ifindex, when specified, for vport lookup by name. When OVS_VPORT_ATTR_NAME is specified and dp_ifindex is nonzero, the logical behavior would be for the vport name lookup scope to be limited to the specified datapath, but in fact the dp_ifindex value was ignored. This commit causes the search scope to be honored. Signed-off-by: Ben Pfaff Signed-off-by: Jesse Gross --- net/openvswitch/datapath.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index ce64c18b8c7..2c030505b33 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -1521,6 +1521,9 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header, vport = ovs_vport_locate(nla_data(a[OVS_VPORT_ATTR_NAME])); if (!vport) return ERR_PTR(-ENODEV); + if (ovs_header->dp_ifindex && + ovs_header->dp_ifindex != get_dpifindex(vport->dp)) + return ERR_PTR(-ENODEV); return vport; } else if (a[OVS_VPORT_ATTR_PORT_NO]) { u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]); -- cgit v1.2.3-70-g09d2 From c15f1c83251049182b1771da004d14f29683ab97 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 14 Feb 2012 00:24:10 +0100 Subject: netfilter: ipset: use NFPROTO_ constants ipset is actually using NFPROTO values rather than AF (xt_set passes that along). Signed-off-by: Jan Engelhardt Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/ipset/ip_set.h | 5 ++++- net/netfilter/ipset/ip_set_bitmap_ip.c | 4 ++-- net/netfilter/ipset/ip_set_bitmap_ipmac.c | 4 ++-- net/netfilter/ipset/ip_set_bitmap_port.c | 4 ++-- net/netfilter/ipset/ip_set_core.c | 16 ++++++++-------- net/netfilter/ipset/ip_set_getport.c | 4 ++-- net/netfilter/ipset/ip_set_hash_ip.c | 18 +++++++++--------- net/netfilter/ipset/ip_set_hash_ipport.c | 10 +++++----- net/netfilter/ipset/ip_set_hash_ipportip.c | 10 +++++----- net/netfilter/ipset/ip_set_hash_ipportnet.c | 12 ++++++------ net/netfilter/ipset/ip_set_hash_net.c | 12 ++++++------ net/netfilter/ipset/ip_set_hash_netiface.c | 12 ++++++------ net/netfilter/ipset/ip_set_hash_netport.c | 12 ++++++------ net/netfilter/ipset/ip_set_list_set.c | 2 +- 14 files changed, 64 insertions(+), 61 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 3540c6e262f..e7b06f52be8 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -288,7 +288,10 @@ struct ip_set_type { u8 features; /* Set type dimension */ u8 dimension; - /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ + /* + * Supported family: may be NFPROTO_UNSPEC for both + * NFPROTO_IPV4/NFPROTO_IPV6. + */ u8 family; /* Type revisions */ u8 revision_min, revision_max; diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index e3e73997c3b..a72a4dff003 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c @@ -442,7 +442,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, map->timeout = IPSET_NO_TIMEOUT; set->data = map; - set->family = AF_INET; + set->family = NFPROTO_IPV4; return true; } @@ -550,7 +550,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP, .dimension = IPSET_DIM_ONE, - .family = AF_INET, + .family = NFPROTO_IPV4, .revision_min = 0, .revision_max = 0, .create = bitmap_ip_create, diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 56096f54497..81324c12c5b 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -543,7 +543,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, map->timeout = IPSET_NO_TIMEOUT; set->data = map; - set->family = AF_INET; + set->family = NFPROTO_IPV4; return true; } @@ -623,7 +623,7 @@ static struct ip_set_type bitmap_ipmac_type = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP | IPSET_TYPE_MAC, .dimension = IPSET_DIM_TWO, - .family = AF_INET, + .family = NFPROTO_IPV4, .revision_min = 0, .revision_max = 0, .create = bitmap_ipmac_create, diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 29ba93bb94b..382ec28ba72 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c @@ -422,7 +422,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, map->timeout = IPSET_NO_TIMEOUT; set->data = map; - set->family = AF_UNSPEC; + set->family = NFPROTO_UNSPEC; return true; } @@ -483,7 +483,7 @@ static struct ip_set_type bitmap_port_type = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_PORT, .dimension = IPSET_DIM_ONE, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, .revision_max = 0, .create = bitmap_port_create, diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index e7f90e7082b..e6c1c9605a5 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -69,7 +69,7 @@ find_set_type(const char *name, u8 family, u8 revision) list_for_each_entry_rcu(type, &ip_set_type_list, list) if (STREQ(type->name, name) && - (type->family == family || type->family == AF_UNSPEC) && + (type->family == family || type->family == NFPROTO_UNSPEC) && revision >= type->revision_min && revision <= type->revision_max) return type; @@ -149,7 +149,7 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max, rcu_read_lock(); list_for_each_entry_rcu(type, &ip_set_type_list, list) if (STREQ(type->name, name) && - (type->family == family || type->family == AF_UNSPEC)) { + (type->family == family || type->family == NFPROTO_UNSPEC)) { found = true; if (type->revision_min < *min) *min = type->revision_min; @@ -164,8 +164,8 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max, __find_set_type_minmax(name, family, min, max, true); } -#define family_name(f) ((f) == AF_INET ? "inet" : \ - (f) == AF_INET6 ? "inet6" : "any") +#define family_name(f) ((f) == NFPROTO_IPV4 ? "inet" : \ + (f) == NFPROTO_IPV6 ? "inet6" : "any") /* Register a set type structure. The type is identified by * the unique triple of name, family and revision. @@ -354,7 +354,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, pr_debug("set %s, index %u\n", set->name, index); if (opt->dim < set->type->dimension || - !(opt->family == set->family || set->family == AF_UNSPEC)) + !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) return 0; read_lock_bh(&set->lock); @@ -387,7 +387,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, pr_debug("set %s, index %u\n", set->name, index); if (opt->dim < set->type->dimension || - !(opt->family == set->family || set->family == AF_UNSPEC)) + !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) return 0; write_lock_bh(&set->lock); @@ -410,7 +410,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, pr_debug("set %s, index %u\n", set->name, index); if (opt->dim < set->type->dimension || - !(opt->family == set->family || set->family == AF_UNSPEC)) + !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) return 0; write_lock_bh(&set->lock); @@ -575,7 +575,7 @@ start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags, return NULL; nfmsg = nlmsg_data(nlh); - nfmsg->nfgen_family = AF_INET; + nfmsg->nfgen_family = NFPROTO_IPV4; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; diff --git a/net/netfilter/ipset/ip_set_getport.c b/net/netfilter/ipset/ip_set_getport.c index 1f03556666f..6fdf88ae235 100644 --- a/net/netfilter/ipset/ip_set_getport.c +++ b/net/netfilter/ipset/ip_set_getport.c @@ -136,10 +136,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) u8 proto; switch (pf) { - case AF_INET: + case NFPROTO_IPV4: ret = ip_set_get_ip4_port(skb, src, port, &proto); break; - case AF_INET6: + case NFPROTO_IPV6: ret = ip_set_get_ip6_port(skb, src, port, &proto); break; default: diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index 4015fcaf87b..5139dea6019 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c @@ -366,11 +366,11 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) u8 netmask, hbits; struct ip_set_hash *h; - if (!(set->family == AF_INET || set->family == AF_INET6)) + if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; - netmask = set->family == AF_INET ? 32 : 128; + netmask = set->family == NFPROTO_IPV4 ? 32 : 128; pr_debug("Create set %s with family %s\n", - set->name, set->family == AF_INET ? "inet" : "inet6"); + set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6"); if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || @@ -389,8 +389,8 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_NETMASK]) { netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); - if ((set->family == AF_INET && netmask > 32) || - (set->family == AF_INET6 && netmask > 128) || + if ((set->family == NFPROTO_IPV4 && netmask > 32) || + (set->family == NFPROTO_IPV6 && netmask > 128) || netmask == 0) return -IPSET_ERR_INVALID_NETMASK; } @@ -419,15 +419,15 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ip4_tvariant : &hash_ip6_tvariant; - if (set->family == AF_INET) + if (set->family == NFPROTO_IPV4) hash_ip4_gc_init(set); else hash_ip6_gc_init(set); } else { - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ip4_variant : &hash_ip6_variant; } @@ -443,7 +443,7 @@ static struct ip_set_type hash_ip_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP, .dimension = IPSET_DIM_ONE, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, .revision_max = 0, .create = hash_ip_create, diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 37d667e3f6f..9c27e249c17 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -450,7 +450,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; - if (!(set->family == AF_INET || set->family == AF_INET6)) + if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || @@ -490,15 +490,15 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ipport4_tvariant : &hash_ipport6_tvariant; - if (set->family == AF_INET) + if (set->family == NFPROTO_IPV4) hash_ipport4_gc_init(set); else hash_ipport6_gc_init(set); } else { - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ipport4_variant : &hash_ipport6_variant; } @@ -514,7 +514,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .dimension = IPSET_DIM_TWO, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, .revision_max = 1, /* SCTP and UDPLITE support added */ .create = hash_ipport_create, diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index e69e2718fbe..9134057c072 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -468,7 +468,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; - if (!(set->family == AF_INET || set->family == AF_INET6)) + if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || @@ -508,15 +508,15 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant; - if (set->family == AF_INET) + if (set->family == NFPROTO_IPV4) hash_ipportip4_gc_init(set); else hash_ipportip6_gc_init(set); } else { - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ipportip4_variant : &hash_ipportip6_variant; } @@ -532,7 +532,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .dimension = IPSET_DIM_THREE, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, .revision_max = 1, /* SCTP and UDPLITE support added */ .create = hash_ipportip_create, diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 64199b4e93c..0edb35b81e3 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -554,7 +554,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; - if (!(set->family == AF_INET || set->family == AF_INET6)) + if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || @@ -573,7 +573,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) h = kzalloc(sizeof(*h) + sizeof(struct ip_set_hash_nets) - * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); + * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); if (!h) return -ENOMEM; @@ -596,16 +596,16 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ipportnet4_tvariant : &hash_ipportnet6_tvariant; - if (set->family == AF_INET) + if (set->family == NFPROTO_IPV4) hash_ipportnet4_gc_init(set); else hash_ipportnet6_gc_init(set); } else { - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_ipportnet4_variant : &hash_ipportnet6_variant; } @@ -621,7 +621,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .dimension = IPSET_DIM_THREE, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, /* 1 SCTP and UDPLITE support added */ .revision_max = 2, /* Range as input support for IPv4 added */ diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 28988196775..5a4457adaf8 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c @@ -406,7 +406,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) struct ip_set_hash *h; u8 hbits; - if (!(set->family == AF_INET || set->family == AF_INET6)) + if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || @@ -425,7 +425,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) h = kzalloc(sizeof(*h) + sizeof(struct ip_set_hash_nets) - * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); + * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); if (!h) return -ENOMEM; @@ -448,15 +448,15 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_net4_tvariant : &hash_net6_tvariant; - if (set->family == AF_INET) + if (set->family == NFPROTO_IPV4) hash_net4_gc_init(set); else hash_net6_gc_init(set); } else { - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_net4_variant : &hash_net6_variant; } @@ -472,7 +472,7 @@ static struct ip_set_type hash_net_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP, .dimension = IPSET_DIM_ONE, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, .revision_max = 1, /* Range as input support for IPv4 added */ .create = hash_net_create, diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index e13095deb50..a9fb4afafa8 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c @@ -678,7 +678,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; - if (!(set->family == AF_INET || set->family == AF_INET6)) + if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || @@ -697,7 +697,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) h = kzalloc(sizeof(*h) + sizeof(struct ip_set_hash_nets) - * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); + * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); if (!h) return -ENOMEM; @@ -722,15 +722,15 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_netiface4_tvariant : &hash_netiface6_tvariant; - if (set->family == AF_INET) + if (set->family == NFPROTO_IPV4) hash_netiface4_gc_init(set); else hash_netiface6_gc_init(set); } else { - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_netiface4_variant : &hash_netiface6_variant; } @@ -746,7 +746,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE, .dimension = IPSET_DIM_TWO, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, .create = hash_netiface_create, .create_policy = { diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 8f9de7207ec..1fcc1020eaa 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c @@ -507,7 +507,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; - if (!(set->family == AF_INET || set->family == AF_INET6)) + if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || @@ -526,7 +526,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) h = kzalloc(sizeof(*h) + sizeof(struct ip_set_hash_nets) - * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); + * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); if (!h) return -ENOMEM; @@ -549,15 +549,15 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_netport4_tvariant : &hash_netport6_tvariant; - if (set->family == AF_INET) + if (set->family == NFPROTO_IPV4) hash_netport4_gc_init(set); else hash_netport6_gc_init(set); } else { - set->variant = set->family == AF_INET + set->variant = set->family == NFPROTO_IPV4 ? &hash_netport4_variant : &hash_netport6_variant; } @@ -573,7 +573,7 @@ static struct ip_set_type hash_netport_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .dimension = IPSET_DIM_TWO, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, /* 1 SCTP and UDPLITE support added */ .revision_max = 2, /* Range as input support for IPv4 added */ diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index 4d10819d462..7e095f9005f 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -575,7 +575,7 @@ static struct ip_set_type list_set_type __read_mostly = { .protocol = IPSET_PROTOCOL, .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, .dimension = IPSET_DIM_ONE, - .family = AF_UNSPEC, + .family = NFPROTO_UNSPEC, .revision_min = 0, .revision_max = 0, .create = list_set_create, -- cgit v1.2.3-70-g09d2 From 2a7cef2a4ba64b9bf0ff9aeaa364554716c06669 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 14 Jan 2012 17:16:36 +0100 Subject: netfilter: ipset: Exceptions support added to hash:*net* types The "nomatch" keyword and option is added to the hash:*net* types, by which one can add exception entries to sets. Example: ipset create test hash:net ipset add test 192.168.0/24 ipset add test 192.168.0/30 nomatch In this case the IP addresses from 192.168.0/24 except 192.168.0/30 match the elements of the set. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/ipset/ip_set.h | 4 + include/linux/netfilter/ipset/ip_set_ahash.h | 89 ++++++++++++----- net/netfilter/ipset/ip_set_hash_ipportnet.c | 135 +++++++++++++++++++------- net/netfilter/ipset/ip_set_hash_net.c | 77 +++++++++++++-- net/netfilter/ipset/ip_set_hash_netiface.c | 72 +++++++++++--- net/netfilter/ipset/ip_set_hash_netport.c | 138 ++++++++++++++++++++------- 6 files changed, 399 insertions(+), 116 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index e921766d3af..2f8e18a2322 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -150,6 +150,7 @@ enum ipset_cmd_flags { IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME), IPSET_FLAG_BIT_LIST_HEADER = 2, IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER), + IPSET_FLAG_CMD_MAX = 15, /* Lower half */ }; /* Flags at CADT attribute level */ @@ -158,6 +159,9 @@ enum ipset_cadt_flags { IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), IPSET_FLAG_BIT_PHYSDEV = 1, IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV), + IPSET_FLAG_BIT_NOMATCH = 2, + IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH), + IPSET_FLAG_CADT_MAX = 15, /* Upper half */ }; /* Commands with settype-specific attributes */ diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h index bd1fc8d1685..0e5c3cf7618 100644 --- a/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/include/linux/netfilter/ipset/ip_set_ahash.h @@ -113,6 +113,12 @@ htable_bits(u32 hashsize) } #ifdef IP_SET_HASH_WITH_NETS +#ifdef IP_SET_HASH_WITH_NETS_PACKED +/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */ +#define CIDR(cidr) (cidr + 1) +#else +#define CIDR(cidr) (cidr) +#endif #define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) @@ -262,6 +268,12 @@ ip_set_hash_destroy(struct ip_set *set) #define type_pf_data_list TOKEN(TYPE, PF, _data_list) #define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) #define type_pf_data_next TOKEN(TYPE, PF, _data_next) +#define type_pf_data_flags TOKEN(TYPE, PF, _data_flags) +#ifdef IP_SET_HASH_WITH_NETS +#define type_pf_data_match TOKEN(TYPE, PF, _data_match) +#else +#define type_pf_data_match(d) 1 +#endif #define type_pf_elem TOKEN(TYPE, PF, _elem) #define type_pf_telem TOKEN(TYPE, PF, _telem) @@ -308,8 +320,10 @@ ip_set_hash_destroy(struct ip_set *set) * we spare the maintenance of the internal counters. */ static int type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value, - u8 ahash_max) + u8 ahash_max, u32 cadt_flags) { + struct type_pf_elem *data; + if (n->pos >= n->size) { void *tmp; @@ -330,7 +344,13 @@ type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value, n->value = tmp; n->size += AHASH_INIT_SIZE; } - type_pf_data_copy(ahash_data(n, n->pos++), value); + data = ahash_data(n, n->pos++); + type_pf_data_copy(data, value); +#ifdef IP_SET_HASH_WITH_NETS + /* Resizing won't overwrite stored flags */ + if (cadt_flags) + type_pf_data_flags(data, cadt_flags); +#endif return 0; } @@ -371,7 +391,7 @@ retry: for (j = 0; j < n->pos; j++) { data = ahash_data(n, j); m = hbucket(t, HKEY(data, h->initval, htable_bits)); - ret = type_pf_elem_add(m, data, AHASH_MAX(h)); + ret = type_pf_elem_add(m, data, AHASH_MAX(h), 0); if (ret < 0) { read_unlock_bh(&set->lock); ahash_destroy(t); @@ -409,6 +429,7 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags) struct hbucket *n; int i, ret = 0; u32 key, multi = 0; + u32 cadt_flags = flags >> 16; if (h->elements >= h->maxelem) { if (net_ratelimit()) @@ -423,11 +444,17 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags) n = hbucket(t, key); for (i = 0; i < n->pos; i++) if (type_pf_data_equal(ahash_data(n, i), d, &multi)) { +#ifdef IP_SET_HASH_WITH_NETS + if (flags & IPSET_FLAG_EXIST) + /* Support overwriting just the flags */ + type_pf_data_flags(ahash_data(n, i), + cadt_flags); +#endif ret = -IPSET_ERR_EXIST; goto out; } TUNE_AHASH_MAX(h, multi); - ret = type_pf_elem_add(n, value, AHASH_MAX(h)); + ret = type_pf_elem_add(n, value, AHASH_MAX(h), cadt_flags); if (ret != 0) { if (ret == -EAGAIN) type_pf_data_next(h, d); @@ -435,7 +462,7 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags) } #ifdef IP_SET_HASH_WITH_NETS - add_cidr(h, d->cidr, HOST_MASK); + add_cidr(h, CIDR(d->cidr), HOST_MASK); #endif h->elements++; out: @@ -470,7 +497,7 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags) n->pos--; h->elements--; #ifdef IP_SET_HASH_WITH_NETS - del_cidr(h, d->cidr, HOST_MASK); + del_cidr(h, CIDR(d->cidr), HOST_MASK); #endif if (n->pos + AHASH_INIT_SIZE < n->size) { void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) @@ -513,7 +540,7 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) for (i = 0; i < n->pos; i++) { data = ahash_data(n, i); if (type_pf_data_equal(data, d, &multi)) - return 1; + return type_pf_data_match(data); } } return 0; @@ -535,7 +562,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags) #ifdef IP_SET_HASH_WITH_NETS /* If we test an IP address and not a network address, * try all possible network sizes */ - if (d->cidr == SET_HOST_MASK(set->family)) + if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) return type_pf_test_cidrs(set, d, timeout); #endif @@ -544,7 +571,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags) for (i = 0; i < n->pos; i++) { data = ahash_data(n, i); if (type_pf_data_equal(data, d, &multi)) - return 1; + return type_pf_data_match(data); } return 0; } @@ -700,7 +727,7 @@ type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout) static int type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value, - u8 ahash_max, u32 timeout) + u8 ahash_max, u32 cadt_flags, u32 timeout) { struct type_pf_elem *data; @@ -727,6 +754,11 @@ type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value, data = ahash_tdata(n, n->pos++); type_pf_data_copy(data, value); type_pf_data_timeout_set(data, timeout); +#ifdef IP_SET_HASH_WITH_NETS + /* Resizing won't overwrite stored flags */ + if (cadt_flags) + type_pf_data_flags(data, cadt_flags); +#endif return 0; } @@ -747,7 +779,7 @@ type_pf_expire(struct ip_set_hash *h) if (type_pf_data_expired(data)) { pr_debug("expired %u/%u\n", i, j); #ifdef IP_SET_HASH_WITH_NETS - del_cidr(h, data->cidr, HOST_MASK); + del_cidr(h, CIDR(data->cidr), HOST_MASK); #endif if (j != n->pos - 1) /* Not last one */ @@ -815,7 +847,7 @@ retry: for (j = 0; j < n->pos; j++) { data = ahash_tdata(n, j); m = hbucket(t, HKEY(data, h->initval, htable_bits)); - ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), + ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), 0, type_pf_data_timeout(data)); if (ret < 0) { read_unlock_bh(&set->lock); @@ -849,6 +881,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) int ret = 0, i, j = AHASH_MAX(h) + 1; bool flag_exist = flags & IPSET_FLAG_EXIST; u32 key, multi = 0; + u32 cadt_flags = flags >> 16; if (h->elements >= h->maxelem) /* FIXME: when set is full, we slow down here */ @@ -868,6 +901,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) data = ahash_tdata(n, i); if (type_pf_data_equal(data, d, &multi)) { if (type_pf_data_expired(data) || flag_exist) + /* Just timeout value may be updated */ j = i; else { ret = -IPSET_ERR_EXIST; @@ -880,15 +914,18 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) if (j != AHASH_MAX(h) + 1) { data = ahash_tdata(n, j); #ifdef IP_SET_HASH_WITH_NETS - del_cidr(h, data->cidr, HOST_MASK); - add_cidr(h, d->cidr, HOST_MASK); + del_cidr(h, CIDR(data->cidr), HOST_MASK); + add_cidr(h, CIDR(d->cidr), HOST_MASK); #endif type_pf_data_copy(data, d); type_pf_data_timeout_set(data, timeout); +#ifdef IP_SET_HASH_WITH_NETS + type_pf_data_flags(data, cadt_flags); +#endif goto out; } TUNE_AHASH_MAX(h, multi); - ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), timeout); + ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), cadt_flags, timeout); if (ret != 0) { if (ret == -EAGAIN) type_pf_data_next(h, d); @@ -896,7 +933,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags) } #ifdef IP_SET_HASH_WITH_NETS - add_cidr(h, d->cidr, HOST_MASK); + add_cidr(h, CIDR(d->cidr), HOST_MASK); #endif h->elements++; out: @@ -930,7 +967,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags) n->pos--; h->elements--; #ifdef IP_SET_HASH_WITH_NETS - del_cidr(h, d->cidr, HOST_MASK); + del_cidr(h, CIDR(d->cidr), HOST_MASK); #endif if (n->pos + AHASH_INIT_SIZE < n->size) { void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) @@ -968,8 +1005,9 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) n = hbucket(t, key); for (i = 0; i < n->pos; i++) { data = ahash_tdata(n, i); - if (type_pf_data_equal(data, d, &multi)) - return !type_pf_data_expired(data); + if (type_pf_data_equal(data, d, &multi) && + !type_pf_data_expired(data)) + return type_pf_data_match(data); } } return 0; @@ -987,15 +1025,16 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags) u32 key, multi = 0; #ifdef IP_SET_HASH_WITH_NETS - if (d->cidr == SET_HOST_MASK(set->family)) + if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) return type_pf_ttest_cidrs(set, d, timeout); #endif key = HKEY(d, h->initval, t->htable_bits); n = hbucket(t, key); for (i = 0; i < n->pos; i++) { data = ahash_tdata(n, i); - if (type_pf_data_equal(data, d, &multi)) - return !type_pf_data_expired(data); + if (type_pf_data_equal(data, d, &multi) && + !type_pf_data_expired(data)) + return type_pf_data_match(data); } return 0; } @@ -1108,14 +1147,17 @@ type_pf_gc_init(struct ip_set *set) #undef type_pf_data_isnull #undef type_pf_data_copy #undef type_pf_data_zero_out +#undef type_pf_data_netmask #undef type_pf_data_list #undef type_pf_data_tlist +#undef type_pf_data_next +#undef type_pf_data_flags +#undef type_pf_data_match #undef type_pf_elem #undef type_pf_telem #undef type_pf_data_timeout #undef type_pf_data_expired -#undef type_pf_data_netmask #undef type_pf_data_timeout_set #undef type_pf_elem_add @@ -1125,6 +1167,7 @@ type_pf_gc_init(struct ip_set *set) #undef type_pf_test #undef type_pf_elem_tadd +#undef type_pf_del_telem #undef type_pf_expire #undef type_pf_tadd #undef type_pf_tdel diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 0edb35b81e3..5d05e696986 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -41,12 +41,19 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b); /* The type variant functions: IPv4 */ +/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0 + * However this way we have to store internally cidr - 1, + * dancing back and forth. + */ +#define IP_SET_HASH_WITH_NETS_PACKED + /* Member elements without timeout */ struct hash_ipportnet4_elem { __be32 ip; __be32 ip2; __be16 port; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; u8 proto; }; @@ -55,7 +62,8 @@ struct hash_ipportnet4_telem { __be32 ip; __be32 ip2; __be16 port; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; u8 proto; unsigned long timeout; }; @@ -85,11 +93,23 @@ hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst, memcpy(dst, src, sizeof(*dst)); } +static inline void +hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags) +{ + dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); +} + +static inline bool +hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem) +{ + return !elem->nomatch; +} + static inline void hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr) { elem->ip2 &= ip_set_netmask(cidr); - elem->cidr = cidr; + elem->cidr = cidr - 1; } static inline void @@ -102,11 +122,15 @@ static bool hash_ipportnet4_data_list(struct sk_buff *skb, const struct hash_ipportnet4_elem *data) { + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -119,14 +143,17 @@ hash_ipportnet4_data_tlist(struct sk_buff *skb, { const struct hash_ipportnet4_telem *tdata = (const struct hash_ipportnet4_telem *)data; + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; @@ -158,13 +185,11 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet4_elem data = { - .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK + .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 }; - if (data.cidr == 0) - return -EINVAL; if (adt == IPSET_TEST) - data.cidr = HOST_MASK; + data.cidr = HOST_MASK - 1; if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) @@ -172,7 +197,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip); ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2); - data.ip2 &= ip_set_netmask(data.cidr); + data.ip2 &= ip_set_netmask(data.cidr + 1); return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); } @@ -183,17 +208,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], { const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; + struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 }; u32 ip, ip_to = 0, p = 0, port, port_to; u32 ip2_from = 0, ip2_to, ip2_last, ip2; u32 timeout = h->timeout; bool with_ports = false; + u8 cidr; int ret; if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -208,9 +235,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], return ret; if (tb[IPSET_ATTR_CIDR2]) { - data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); - if (!data.cidr) + cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); + if (!cidr || cidr > HOST_MASK) return -IPSET_ERR_INVALID_CIDR; + data.cidr = cidr - 1; } if (tb[IPSET_ATTR_PORT]) @@ -236,12 +264,18 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } + if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { + u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); + if (cadt_flags & IPSET_FLAG_NOMATCH) + flags |= (cadt_flags << 16); + } + with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; if (adt == IPSET_TEST || !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports || tb[IPSET_ATTR_IP2_TO])) { data.ip = htonl(ip); - data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr)); + data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr + 1)); ret = adtfn(set, &data, timeout, flags); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -275,7 +309,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], if (ip2_from + UINT_MAX == ip2_to) return -IPSET_ERR_HASH_RANGE; } else { - ip_set_mask_from_to(ip2_from, ip2_to, data.cidr); + ip_set_mask_from_to(ip2_from, ip2_to, data.cidr + 1); } if (retried) @@ -290,7 +324,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], while (!after(ip2, ip2_to)) { data.ip2 = htonl(ip2); ip2_last = ip_set_range_to_cidr(ip2, ip2_to, - &data.cidr); + &cidr); + data.cidr = cidr - 1; ret = adtfn(set, &data, timeout, flags); if (ret && !ip_set_eexist(ret, flags)) @@ -321,7 +356,8 @@ struct hash_ipportnet6_elem { union nf_inet_addr ip; union nf_inet_addr ip2; __be16 port; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; u8 proto; }; @@ -329,7 +365,8 @@ struct hash_ipportnet6_telem { union nf_inet_addr ip; union nf_inet_addr ip2; __be16 port; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; u8 proto; unsigned long timeout; }; @@ -359,6 +396,18 @@ hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst, memcpy(dst, src, sizeof(*dst)); } +static inline void +hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags) +{ + dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); +} + +static inline bool +hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem) +{ + return !elem->nomatch; +} + static inline void hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem) { @@ -378,18 +427,22 @@ static inline void hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr) { ip6_netmask(&elem->ip2, cidr); - elem->cidr = cidr; + elem->cidr = cidr - 1; } static bool hash_ipportnet6_data_list(struct sk_buff *skb, const struct hash_ipportnet6_elem *data) { + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -402,14 +455,17 @@ hash_ipportnet6_data_tlist(struct sk_buff *skb, { const struct hash_ipportnet6_telem *e = (const struct hash_ipportnet6_telem *)data; + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -438,13 +494,11 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet6_elem data = { - .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK + .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 }; - if (data.cidr == 0) - return -EINVAL; if (adt == IPSET_TEST) - data.cidr = HOST_MASK; + data.cidr = HOST_MASK - 1; if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) @@ -452,7 +506,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6); ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6); - ip6_netmask(&data.ip2, data.cidr); + ip6_netmask(&data.ip2, data.cidr + 1); return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); } @@ -463,16 +517,18 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], { const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportnet6_elem data = { .cidr = HOST_MASK }; + struct hash_ipportnet6_elem data = { .cidr = HOST_MASK - 1 }; u32 port, port_to; u32 timeout = h->timeout; bool with_ports = false; + u8 cidr; int ret; if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) return -IPSET_ERR_PROTOCOL; @@ -490,13 +546,14 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], if (ret) return ret; - if (tb[IPSET_ATTR_CIDR2]) - data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); - - if (!data.cidr) - return -IPSET_ERR_INVALID_CIDR; + if (tb[IPSET_ATTR_CIDR2]) { + cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); + if (!cidr || cidr > HOST_MASK) + return -IPSET_ERR_INVALID_CIDR; + data.cidr = cidr - 1; + } - ip6_netmask(&data.ip2, data.cidr); + ip6_netmask(&data.ip2, data.cidr + 1); if (tb[IPSET_ATTR_PORT]) data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); @@ -521,6 +578,12 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } + if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { + u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); + if (cadt_flags & IPSET_FLAG_NOMATCH) + flags |= (cadt_flags << 16); + } + if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { ret = adtfn(set, &data, timeout, flags); return ip_set_eexist(ret, flags) ? 0 : ret; @@ -624,7 +687,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { .family = NFPROTO_UNSPEC, .revision_min = 0, /* 1 SCTP and UDPLITE support added */ - .revision_max = 2, /* Range as input support for IPv4 added */ + /* 2 Range as input support for IPv4 added */ + .revision_max = 3, /* nomatch flag support added */ .create = hash_ipportnet_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, @@ -643,6 +707,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, }, diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 5a4457adaf8..7c3d945517c 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c @@ -43,7 +43,7 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b); struct hash_net4_elem { __be32 ip; u16 padding0; - u8 padding1; + u8 nomatch; u8 cidr; }; @@ -51,7 +51,7 @@ struct hash_net4_elem { struct hash_net4_telem { __be32 ip; u16 padding0; - u8 padding1; + u8 nomatch; u8 cidr; unsigned long timeout; }; @@ -61,7 +61,8 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1, const struct hash_net4_elem *ip2, u32 *multi) { - return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; + return ip1->ip == ip2->ip && + ip1->cidr == ip2->cidr; } static inline bool @@ -76,6 +77,19 @@ hash_net4_data_copy(struct hash_net4_elem *dst, { dst->ip = src->ip; dst->cidr = src->cidr; + dst->nomatch = src->nomatch; +} + +static inline void +hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags) +{ + dst->nomatch = flags & IPSET_FLAG_NOMATCH; +} + +static inline bool +hash_net4_data_match(const struct hash_net4_elem *elem) +{ + return !elem->nomatch; } static inline void @@ -95,8 +109,12 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem) static bool hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data) { + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -108,11 +126,14 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data) { const struct hash_net4_telem *tdata = (const struct hash_net4_telem *)data; + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; @@ -167,7 +188,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], int ret; if (unlikely(!tb[IPSET_ATTR_IP] || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -179,7 +201,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_CIDR]) { data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - if (!data.cidr) + if (!data.cidr || data.cidr > HOST_MASK) return -IPSET_ERR_INVALID_CIDR; } @@ -189,6 +211,12 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } + if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { + u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); + if (cadt_flags & IPSET_FLAG_NOMATCH) + flags |= (cadt_flags << 16); + } + if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { data.ip = htonl(ip & ip_set_hostmask(data.cidr)); ret = adtfn(set, &data, timeout, flags); @@ -236,14 +264,14 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b) struct hash_net6_elem { union nf_inet_addr ip; u16 padding0; - u8 padding1; + u8 nomatch; u8 cidr; }; struct hash_net6_telem { union nf_inet_addr ip; u16 padding0; - u8 padding1; + u8 nomatch; u8 cidr; unsigned long timeout; }; @@ -269,6 +297,19 @@ hash_net6_data_copy(struct hash_net6_elem *dst, { dst->ip.in6 = src->ip.in6; dst->cidr = src->cidr; + dst->nomatch = src->nomatch; +} + +static inline void +hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags) +{ + dst->nomatch = flags & IPSET_FLAG_NOMATCH; +} + +static inline bool +hash_net6_data_match(const struct hash_net6_elem *elem) +{ + return !elem->nomatch; } static inline void @@ -296,8 +337,12 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr) static bool hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data) { + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -309,11 +354,14 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data) { const struct hash_net6_telem *e = (const struct hash_net6_telem *)data; + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -366,7 +414,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], int ret; if (unlikely(!tb[IPSET_ATTR_IP] || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; if (unlikely(tb[IPSET_ATTR_IP_TO])) return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; @@ -381,7 +430,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_CIDR]) data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - if (!data.cidr) + if (!data.cidr || data.cidr > HOST_MASK) return -IPSET_ERR_INVALID_CIDR; ip6_netmask(&data.ip, data.cidr); @@ -392,6 +441,12 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } + if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { + u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); + if (cadt_flags & IPSET_FLAG_NOMATCH) + flags |= (cadt_flags << 16); + } + ret = adtfn(set, &data, timeout, flags); return ip_set_eexist(ret, flags) ? 0 : ret; @@ -474,7 +529,8 @@ static struct ip_set_type hash_net_type __read_mostly = { .dimension = IPSET_DIM_ONE, .family = NFPROTO_UNSPEC, .revision_min = 0, - .revision_max = 1, /* Range as input support for IPv4 added */ + /* = 1 Range as input support for IPv4 added */ + .revision_max = 2, /* nomatch flag support added */ .create = hash_net_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, @@ -488,6 +544,7 @@ static struct ip_set_type hash_net_type __read_mostly = { [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, }, .me = THIS_MODULE, }; diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index a9fb4afafa8..f24037ff432 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c @@ -163,7 +163,8 @@ struct hash_netiface4_elem_hashed { __be32 ip; u8 physdev; u8 cidr; - u16 padding; + u8 nomatch; + u8 padding; }; #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) @@ -173,7 +174,8 @@ struct hash_netiface4_elem { __be32 ip; u8 physdev; u8 cidr; - u16 padding; + u8 nomatch; + u8 padding; const char *iface; }; @@ -182,7 +184,8 @@ struct hash_netiface4_telem { __be32 ip; u8 physdev; u8 cidr; - u16 padding; + u8 nomatch; + u8 padding; const char *iface; unsigned long timeout; }; @@ -207,11 +210,25 @@ hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem) static inline void hash_netiface4_data_copy(struct hash_netiface4_elem *dst, - const struct hash_netiface4_elem *src) { + const struct hash_netiface4_elem *src) +{ dst->ip = src->ip; dst->cidr = src->cidr; dst->physdev = src->physdev; dst->iface = src->iface; + dst->nomatch = src->nomatch; +} + +static inline void +hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags) +{ + dst->nomatch = flags & IPSET_FLAG_NOMATCH; +} + +static inline bool +hash_netiface4_data_match(const struct hash_netiface4_elem *elem) +{ + return !elem->nomatch; } static inline void @@ -233,11 +250,13 @@ hash_netiface4_data_list(struct sk_buff *skb, { u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; + if (data->nomatch) + flags |= IPSET_FLAG_NOMATCH; NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); if (flags) - NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -252,11 +271,13 @@ hash_netiface4_data_tlist(struct sk_buff *skb, (const struct hash_netiface4_telem *)data; u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; + if (data->nomatch) + flags |= IPSET_FLAG_NOMATCH; NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); if (flags) - NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); @@ -361,7 +382,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_CIDR]) { data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - if (!data.cidr) + if (!data.cidr || data.cidr > HOST_MASK) return -IPSET_ERR_INVALID_CIDR; } @@ -387,6 +408,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); if (cadt_flags & IPSET_FLAG_PHYSDEV) data.physdev = 1; + if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH)) + flags |= (cadt_flags << 16); } if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { @@ -440,7 +463,8 @@ struct hash_netiface6_elem_hashed { union nf_inet_addr ip; u8 physdev; u8 cidr; - u16 padding; + u8 nomatch; + u8 padding; }; #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed) @@ -449,7 +473,8 @@ struct hash_netiface6_elem { union nf_inet_addr ip; u8 physdev; u8 cidr; - u16 padding; + u8 nomatch; + u8 padding; const char *iface; }; @@ -457,7 +482,8 @@ struct hash_netiface6_telem { union nf_inet_addr ip; u8 physdev; u8 cidr; - u16 padding; + u8 nomatch; + u8 padding; const char *iface; unsigned long timeout; }; @@ -487,9 +513,22 @@ hash_netiface6_data_copy(struct hash_netiface6_elem *dst, memcpy(dst, src, sizeof(*dst)); } +static inline void +hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags) +{ + dst->nomatch = flags & IPSET_FLAG_NOMATCH; +} + +static inline bool +hash_netiface6_data_match(const struct hash_netiface6_elem *elem) +{ + return !elem->nomatch; +} + static inline void hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem) { + elem->cidr = 0; } static inline void @@ -514,11 +553,13 @@ hash_netiface6_data_list(struct sk_buff *skb, { u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; + if (data->nomatch) + flags |= IPSET_FLAG_NOMATCH; NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); if (flags) - NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -533,11 +574,13 @@ hash_netiface6_data_tlist(struct sk_buff *skb, (const struct hash_netiface6_telem *)data; u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; + if (data->nomatch) + flags |= IPSET_FLAG_NOMATCH; NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); if (flags) - NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); return 0; @@ -636,7 +679,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_CIDR]) data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - if (!data.cidr) + if (!data.cidr || data.cidr > HOST_MASK) return -IPSET_ERR_INVALID_CIDR; ip6_netmask(&data.ip, data.cidr); @@ -662,6 +705,8 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); if (cadt_flags & IPSET_FLAG_PHYSDEV) data.physdev = 1; + if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH)) + flags |= (cadt_flags << 16); } ret = adtfn(set, &data, timeout, flags); @@ -748,6 +793,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = { .dimension = IPSET_DIM_TWO, .family = NFPROTO_UNSPEC, .revision_min = 0, + .revision_max = 1, /* nomatch flag support added */ .create = hash_netiface_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 1fcc1020eaa..ce2e77100b6 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c @@ -40,12 +40,19 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b); /* The type variant functions: IPv4 */ +/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0 + * However this way we have to store internally cidr - 1, + * dancing back and forth. + */ +#define IP_SET_HASH_WITH_NETS_PACKED + /* Member elements without timeout */ struct hash_netport4_elem { __be32 ip; __be16 port; u8 proto; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; }; /* Member elements with timeout support */ @@ -53,7 +60,8 @@ struct hash_netport4_telem { __be32 ip; __be16 port; u8 proto; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; unsigned long timeout; }; @@ -82,13 +90,26 @@ hash_netport4_data_copy(struct hash_netport4_elem *dst, dst->port = src->port; dst->proto = src->proto; dst->cidr = src->cidr; + dst->nomatch = src->nomatch; +} + +static inline void +hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags) +{ + dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); +} + +static inline bool +hash_netport4_data_match(const struct hash_netport4_elem *elem) +{ + return !elem->nomatch; } static inline void hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr) { elem->ip &= ip_set_netmask(cidr); - elem->cidr = cidr; + elem->cidr = cidr - 1; } static inline void @@ -101,10 +122,14 @@ static bool hash_netport4_data_list(struct sk_buff *skb, const struct hash_netport4_elem *data) { + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -117,13 +142,16 @@ hash_netport4_data_tlist(struct sk_buff *skb, { const struct hash_netport4_telem *tdata = (const struct hash_netport4_telem *)data; + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; @@ -154,20 +182,18 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_netport4_elem data = { - .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK + .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 }; - if (data.cidr == 0) - return -EINVAL; if (adt == IPSET_TEST) - data.cidr = HOST_MASK; + data.cidr = HOST_MASK - 1; if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) return -EINVAL; ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip); - data.ip &= ip_set_netmask(data.cidr); + data.ip &= ip_set_netmask(data.cidr + 1); return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); } @@ -178,16 +204,18 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], { const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_netport4_elem data = { .cidr = HOST_MASK }; + struct hash_netport4_elem data = { .cidr = HOST_MASK - 1 }; u32 port, port_to, p = 0, ip = 0, ip_to, last; u32 timeout = h->timeout; bool with_ports = false; + u8 cidr; int ret; if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -198,9 +226,10 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], return ret; if (tb[IPSET_ATTR_CIDR]) { - data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - if (!data.cidr) + cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); + if (!cidr || cidr > HOST_MASK) return -IPSET_ERR_INVALID_CIDR; + data.cidr = cidr - 1; } if (tb[IPSET_ATTR_PORT]) @@ -227,8 +256,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], } with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; + + if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { + u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); + if (cadt_flags & IPSET_FLAG_NOMATCH) + flags |= (cadt_flags << 16); + } + if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) { - data.ip = htonl(ip & ip_set_hostmask(data.cidr)); + data.ip = htonl(ip & ip_set_hostmask(data.cidr + 1)); ret = adtfn(set, &data, timeout, flags); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -248,14 +284,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], if (ip + UINT_MAX == ip_to) return -IPSET_ERR_HASH_RANGE; } else { - ip_set_mask_from_to(ip, ip_to, data.cidr); + ip_set_mask_from_to(ip, ip_to, data.cidr + 1); } if (retried) ip = h->next.ip; while (!after(ip, ip_to)) { data.ip = htonl(ip); - last = ip_set_range_to_cidr(ip, ip_to, &data.cidr); + last = ip_set_range_to_cidr(ip, ip_to, &cidr); + data.cidr = cidr - 1; p = retried && ip == h->next.ip ? h->next.port : port; for (; p <= port_to; p++) { data.port = htons(p); @@ -288,14 +325,16 @@ struct hash_netport6_elem { union nf_inet_addr ip; __be16 port; u8 proto; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; }; struct hash_netport6_telem { union nf_inet_addr ip; __be16 port; u8 proto; - u8 cidr; + u8 cidr:7; + u8 nomatch:1; unsigned long timeout; }; @@ -323,6 +362,18 @@ hash_netport6_data_copy(struct hash_netport6_elem *dst, memcpy(dst, src, sizeof(*dst)); } +static inline void +hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags) +{ + dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); +} + +static inline bool +hash_netport6_data_match(const struct hash_netport6_elem *elem) +{ + return !elem->nomatch; +} + static inline void hash_netport6_data_zero_out(struct hash_netport6_elem *elem) { @@ -342,17 +393,21 @@ static inline void hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr) { ip6_netmask(&elem->ip, cidr); - elem->cidr = cidr; + elem->cidr = cidr - 1; } static bool hash_netport6_data_list(struct sk_buff *skb, const struct hash_netport6_elem *data) { + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -365,13 +420,16 @@ hash_netport6_data_tlist(struct sk_buff *skb, { const struct hash_netport6_telem *e = (const struct hash_netport6_telem *)data; + u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); + if (flags) + NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); return 0; nla_put_failure: @@ -400,20 +458,18 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_netport6_elem data = { - .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK + .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1, }; - if (data.cidr == 0) - return -EINVAL; if (adt == IPSET_TEST) - data.cidr = HOST_MASK; + data.cidr = HOST_MASK - 1; if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) return -EINVAL; ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6); - ip6_netmask(&data.ip, data.cidr); + ip6_netmask(&data.ip, data.cidr + 1); return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); } @@ -424,16 +480,18 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], { const struct ip_set_hash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_netport6_elem data = { .cidr = HOST_MASK }; + struct hash_netport6_elem data = { .cidr = HOST_MASK - 1 }; u32 port, port_to; u32 timeout = h->timeout; bool with_ports = false; + u8 cidr; int ret; if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; if (unlikely(tb[IPSET_ATTR_IP_TO])) return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; @@ -445,11 +503,13 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], if (ret) return ret; - if (tb[IPSET_ATTR_CIDR]) - data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - if (!data.cidr) - return -IPSET_ERR_INVALID_CIDR; - ip6_netmask(&data.ip, data.cidr); + if (tb[IPSET_ATTR_CIDR]) { + cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); + if (!cidr || cidr > HOST_MASK) + return -IPSET_ERR_INVALID_CIDR; + data.cidr = cidr - 1; + } + ip6_netmask(&data.ip, data.cidr + 1); if (tb[IPSET_ATTR_PORT]) data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); @@ -474,6 +534,12 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } + if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { + u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); + if (cadt_flags & IPSET_FLAG_NOMATCH) + flags |= (cadt_flags << 16); + } + if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { ret = adtfn(set, &data, timeout, flags); return ip_set_eexist(ret, flags) ? 0 : ret; @@ -576,7 +642,8 @@ static struct ip_set_type hash_netport_type __read_mostly = { .family = NFPROTO_UNSPEC, .revision_min = 0, /* 1 SCTP and UDPLITE support added */ - .revision_max = 2, /* Range as input support for IPv4 added */ + /* 2, Range as input support for IPv4 added */ + .revision_max = 3, /* nomatch flag support added */ .create = hash_netport_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, @@ -595,6 +662,7 @@ static struct ip_set_type hash_netport_type __read_mostly = { [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, }, .me = THIS_MODULE, }; -- cgit v1.2.3-70-g09d2 From 660fdb2a0f5f670da4728d7028d3227296e0226c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 5 Feb 2012 02:34:16 +0100 Subject: netfilter: ctnetlink: allow to set helper for new expectations This patch allow you to set the helper for newly created expectations based of the CTA_EXPECT_HELP_NAME attribute. Before this, the helper set was NULL. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 04fb409623d..1b0aea620d6 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2042,6 +2042,7 @@ ctnetlink_create_expect(struct net *net, u16 zone, struct nf_conntrack_expect *exp; struct nf_conn *ct; struct nf_conn_help *help; + struct nf_conntrack_helper *helper = NULL; int err = 0; /* caller guarantees that those three CTA_EXPECT_* exist */ @@ -2060,6 +2061,33 @@ ctnetlink_create_expect(struct net *net, u16 zone, if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); + + /* Look for helper of this expectation */ + if (cda[CTA_EXPECT_HELP_NAME]) { + const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); + + helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), + nf_ct_protonum(ct)); + if (helper == NULL) { +#ifdef CONFIG_MODULES + if (request_module("nfct-helper-%s", helpname) < 0) { + err = -EOPNOTSUPP; + goto out; + } + + helper = __nf_conntrack_helper_find(helpname, + nf_ct_l3num(ct), + nf_ct_protonum(ct)); + if (helper) { + err = -EAGAIN; + goto out; + } +#endif + err = -EOPNOTSUPP; + goto out; + } + } + exp = nf_ct_expect_alloc(ct); if (!exp) { err = -ENOMEM; @@ -2090,7 +2118,7 @@ ctnetlink_create_expect(struct net *net, u16 zone, exp->class = 0; exp->expectfn = NULL; exp->master = ct; - exp->helper = NULL; + exp->helper = helper; memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3)); exp->mask.src.u.all = mask.src.u.all; -- cgit v1.2.3-70-g09d2 From b8c5e52c13edc99ce192d78c8a7fe2fd626ac643 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 5 Feb 2012 03:21:12 +0100 Subject: netfilter: ctnetlink: allow to set expectation class This patch allows you to set the expectation class. Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/nfnetlink_conntrack.h | 1 + net/netfilter/nf_conntrack_netlink.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index d498a4426eb..557a0cfb143 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -173,6 +173,7 @@ enum ctattr_expect { CTA_EXPECT_HELP_NAME, CTA_EXPECT_ZONE, CTA_EXPECT_FLAGS, + CTA_EXPECT_CLASS, __CTA_EXPECT_MAX }; #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 1b0aea620d6..b6ea39770c8 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1691,6 +1691,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); + NLA_PUT_BE32(skb, CTA_EXPECT_CLASS, htonl(exp->class)); help = nfct_help(master); if (help) { struct nf_conntrack_helper *helper; @@ -1856,6 +1857,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, [CTA_EXPECT_ZONE] = { .type = NLA_U16 }, [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, + [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, }; static int @@ -2043,6 +2045,7 @@ ctnetlink_create_expect(struct net *net, u16 zone, struct nf_conn *ct; struct nf_conn_help *help; struct nf_conntrack_helper *helper = NULL; + u_int32_t class = 0; int err = 0; /* caller guarantees that those three CTA_EXPECT_* exist */ @@ -2088,6 +2091,13 @@ ctnetlink_create_expect(struct net *net, u16 zone, } } + if (cda[CTA_EXPECT_CLASS] && helper) { + class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS])); + if (class > helper->expect_class_max) { + err = -EINVAL; + goto out; + } + } exp = nf_ct_expect_alloc(ct); if (!exp) { err = -ENOMEM; @@ -2115,7 +2125,7 @@ ctnetlink_create_expect(struct net *net, u16 zone, exp->flags = 0; } - exp->class = 0; + exp->class = class; exp->expectfn = NULL; exp->master = ct; exp->helper = helper; -- cgit v1.2.3-70-g09d2 From 076a0ca02644657b13e4af363f487ced2942e9cb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 5 Feb 2012 03:41:52 +0100 Subject: netfilter: ctnetlink: add NAT support for expectations This patch adds the missing bits to create expectations that are created in NAT setups. --- include/linux/netfilter/nfnetlink_conntrack.h | 9 ++++ net/netfilter/nf_conntrack_netlink.c | 68 ++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 557a0cfb143..a2f1f483ecc 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -174,10 +174,19 @@ enum ctattr_expect { CTA_EXPECT_ZONE, CTA_EXPECT_FLAGS, CTA_EXPECT_CLASS, + CTA_EXPECT_NAT, __CTA_EXPECT_MAX }; #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) +enum ctattr_expect_nat { + CTA_EXPECT_NAT_UNSPEC, + CTA_EXPECT_NAT_DIR, + CTA_EXPECT_NAT_TUPLE, + __CTA_EXPECT_NAT_MAX +}; +#define CTA_EXPECT_NAT_MAX (__CTA_EXPECT_NAT_MAX - 1) + enum ctattr_help { CTA_HELP_UNSPEC, CTA_HELP_NAME, diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b6ea39770c8..845c8ca2856 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1675,7 +1675,10 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, struct nf_conn *master = exp->master; long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ; struct nf_conn_help *help; - +#ifdef CONFIG_NF_NAT_NEEDED + struct nlattr *nest_parms; + struct nf_conntrack_tuple nat_tuple = {}; +#endif if (timeout < 0) timeout = 0; @@ -1688,6 +1691,25 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, CTA_EXPECT_MASTER) < 0) goto nla_put_failure; +#ifdef CONFIG_NF_NAT_NEEDED + if (exp->saved_ip || exp->saved_proto.all) { + nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + + NLA_PUT_BE32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)); + + nat_tuple.src.l3num = nf_ct_l3num(master); + nat_tuple.src.u3.ip = exp->saved_ip; + nat_tuple.dst.protonum = nf_ct_protonum(master); + nat_tuple.src.u = exp->saved_proto; + + if (ctnetlink_exp_dump_tuple(skb, &nat_tuple, + CTA_EXPECT_NAT_TUPLE) < 0) + goto nla_put_failure; + nla_nest_end(skb, nest_parms); + } +#endif NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); @@ -1858,6 +1880,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { [CTA_EXPECT_ZONE] = { .type = NLA_U16 }, [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, + [CTA_EXPECT_NAT] = { .type = NLA_NESTED }, }; static int @@ -2033,6 +2056,41 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, return -EOPNOTSUPP; } +static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = { + [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 }, + [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED }, +}; + +static int +ctnetlink_parse_expect_nat(const struct nlattr *attr, + struct nf_conntrack_expect *exp, + u_int8_t u3) +{ +#ifdef CONFIG_NF_NAT_NEEDED + struct nlattr *tb[CTA_EXPECT_NAT_MAX+1]; + struct nf_conntrack_tuple nat_tuple = {}; + int err; + + nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy); + + if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE]) + return -EINVAL; + + err = ctnetlink_parse_tuple((const struct nlattr * const *)tb, + &nat_tuple, CTA_EXPECT_NAT_TUPLE, u3); + if (err < 0) + return err; + + exp->saved_ip = nat_tuple.src.u3.ip; + exp->saved_proto = nat_tuple.src.u; + exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR])); + + return 0; +#else + return -EOPNOTSUPP; +#endif +} + static int ctnetlink_create_expect(struct net *net, u16 zone, const struct nlattr * const cda[], @@ -2133,9 +2191,15 @@ ctnetlink_create_expect(struct net *net, u16 zone, memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3)); exp->mask.src.u.all = mask.src.u.all; + if (cda[CTA_EXPECT_NAT]) { + err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT], + exp, u3); + if (err < 0) + goto err_out; + } err = nf_ct_expect_related_report(exp, pid, report); +err_out: nf_ct_expect_put(exp); - out: nf_ct_put(nf_ct_tuplehash_to_ctrack(h)); return err; -- cgit v1.2.3-70-g09d2 From 544d5c7d9f4d1ec4f170bc5bcc522012cb7704bc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 5 Feb 2012 03:44:51 +0100 Subject: netfilter: ctnetlink: allow to set expectfn for expectations This patch allows you to set expectfn which is specifically used by the NAT side of most of the existing conntrack helpers. I have added a symbol map that uses a string as key to look up for the function that is attached to the expectation object. This is the best solution I came out with to solve this issue. Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/nfnetlink_conntrack.h | 1 + include/net/netfilter/nf_conntrack_helper.h | 13 +++++++ net/ipv4/netfilter/nf_nat_core.c | 8 ++++ net/ipv4/netfilter/nf_nat_h323.c | 14 +++++++ net/ipv4/netfilter/nf_nat_sip.c | 7 ++++ net/netfilter/nf_conntrack_helper.c | 54 +++++++++++++++++++++++++++ net/netfilter/nf_conntrack_netlink.c | 19 +++++++++- 7 files changed, 115 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index a2f1f483ecc..e58e4b93c10 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -175,6 +175,7 @@ enum ctattr_expect { CTA_EXPECT_FLAGS, CTA_EXPECT_CLASS, CTA_EXPECT_NAT, + CTA_EXPECT_FN, __CTA_EXPECT_MAX }; #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index f1c1311adc2..5767dc242de 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -69,4 +69,17 @@ extern int nf_conntrack_broadcast_help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, unsigned int timeout); +struct nf_ct_helper_expectfn { + struct list_head head; + const char *name; + void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); +}; + +void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); +void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); +struct nf_ct_helper_expectfn * +nf_ct_helper_expectfn_find_by_name(const char *name); +struct nf_ct_helper_expectfn * +nf_ct_helper_expectfn_find_by_symbol(const void *symbol); + #endif /*_NF_CONNTRACK_HELPER_H*/ diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index a708933dc23..abb52adf5ac 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -686,6 +686,11 @@ static struct pernet_operations nf_nat_net_ops = { .exit = nf_nat_net_exit, }; +static struct nf_ct_helper_expectfn follow_master_nat = { + .name = "nat-follow-master", + .expectfn = nf_nat_follow_master, +}; + static int __init nf_nat_init(void) { size_t i; @@ -717,6 +722,8 @@ static int __init nf_nat_init(void) l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + nf_ct_helper_expectfn_register(&follow_master_nat); + BUG_ON(nf_nat_seq_adjust_hook != NULL); RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); @@ -736,6 +743,7 @@ static void __exit nf_nat_cleanup(void) unregister_pernet_subsys(&nf_nat_net_ops); nf_ct_l3proto_put(l3proto); nf_ct_extend_unregister(&nat_extend); + nf_ct_helper_expectfn_unregister(&follow_master_nat); RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); RCU_INIT_POINTER(nf_ct_nat_offset, NULL); diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c index dc1dd912baf..82536701e3a 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -568,6 +568,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, return 0; } +static struct nf_ct_helper_expectfn q931_nat = { + .name = "Q.931", + .expectfn = ip_nat_q931_expect, +}; + +static struct nf_ct_helper_expectfn callforwarding_nat = { + .name = "callforwarding", + .expectfn = ip_nat_callforwarding_expect, +}; + /****************************************************************************/ static int __init init(void) { @@ -590,6 +600,8 @@ static int __init init(void) RCU_INIT_POINTER(nat_h245_hook, nat_h245); RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding); RCU_INIT_POINTER(nat_q931_hook, nat_q931); + nf_ct_helper_expectfn_register(&q931_nat); + nf_ct_helper_expectfn_register(&callforwarding_nat); return 0; } @@ -605,6 +617,8 @@ static void __exit fini(void) RCU_INIT_POINTER(nat_h245_hook, NULL); RCU_INIT_POINTER(nat_callforwarding_hook, NULL); RCU_INIT_POINTER(nat_q931_hook, NULL); + nf_ct_helper_expectfn_unregister(&q931_nat); + nf_ct_helper_expectfn_unregister(&callforwarding_nat); synchronize_rcu(); } diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index d0319f96269..57932c43960 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -526,6 +526,11 @@ err1: return NF_DROP; } +static struct nf_ct_helper_expectfn sip_nat = { + .name = "sip", + .expectfn = ip_nat_sip_expected, +}; + static void __exit nf_nat_sip_fini(void) { RCU_INIT_POINTER(nf_nat_sip_hook, NULL); @@ -535,6 +540,7 @@ static void __exit nf_nat_sip_fini(void) RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); + nf_ct_helper_expectfn_unregister(&sip_nat); synchronize_rcu(); } @@ -554,6 +560,7 @@ static int __init nf_nat_sip_init(void) RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port); RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session); RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media); + nf_ct_helper_expectfn_register(&sip_nat); return 0; } diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index bbe23baa19b..436b7cb79ba 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -181,6 +181,60 @@ void nf_ct_helper_destroy(struct nf_conn *ct) } } +static LIST_HEAD(nf_ct_helper_expectfn_list); + +void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n) +{ + spin_lock_bh(&nf_conntrack_lock); + list_add_rcu(&n->head, &nf_ct_helper_expectfn_list); + spin_unlock_bh(&nf_conntrack_lock); +} +EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register); + +void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) +{ + spin_lock_bh(&nf_conntrack_lock); + list_del_rcu(&n->head); + spin_unlock_bh(&nf_conntrack_lock); +} +EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); + +struct nf_ct_helper_expectfn * +nf_ct_helper_expectfn_find_by_name(const char *name) +{ + struct nf_ct_helper_expectfn *cur; + bool found = false; + + rcu_read_lock(); + list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { + if (!strcmp(cur->name, name)) { + found = true; + break; + } + } + rcu_read_unlock(); + return found ? cur : NULL; +} +EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name); + +struct nf_ct_helper_expectfn * +nf_ct_helper_expectfn_find_by_symbol(const void *symbol) +{ + struct nf_ct_helper_expectfn *cur; + bool found = false; + + rcu_read_lock(); + list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { + if (cur->expectfn == symbol) { + found = true; + break; + } + } + rcu_read_unlock(); + return found ? cur : NULL; +} +EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol); + int nf_conntrack_helper_register(struct nf_conntrack_helper *me) { unsigned int h = helper_hash(&me->tuple); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 845c8ca2856..b8827e8a11f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1679,6 +1679,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, struct nlattr *nest_parms; struct nf_conntrack_tuple nat_tuple = {}; #endif + struct nf_ct_helper_expectfn *expfn; + if (timeout < 0) timeout = 0; @@ -1722,6 +1724,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, if (helper) NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); } + expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn); + if (expfn != NULL) + NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name); return 0; @@ -1881,6 +1886,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, [CTA_EXPECT_NAT] = { .type = NLA_NESTED }, + [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING }, }; static int @@ -2182,9 +2188,20 @@ ctnetlink_create_expect(struct net *net, u16 zone, } else exp->flags = 0; } + if (cda[CTA_EXPECT_FN]) { + const char *name = nla_data(cda[CTA_EXPECT_FN]); + struct nf_ct_helper_expectfn *expfn; + + expfn = nf_ct_helper_expectfn_find_by_name(name); + if (expfn == NULL) { + err = -EINVAL; + goto err_out; + } + exp->expectfn = expfn->expectfn; + } else + exp->expectfn = NULL; exp->class = class; - exp->expectfn = NULL; exp->master = ct; exp->helper = helper; memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); -- cgit v1.2.3-70-g09d2 From 6939c33a757bd006c5e0b8b5fd429fc587a4d0f4 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 10 Feb 2012 23:10:52 +0100 Subject: netfilter: merge ipt_LOG and ip6_LOG into xt_LOG ipt_LOG and ip6_LOG have a lot of common code, merge them to reduce duplicate code. Signed-off-by: Richard Weinberger Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/xt_LOG.h | 19 + include/linux/netfilter_ipv4/ipt_LOG.h | 2 + include/linux/netfilter_ipv6/ip6t_LOG.h | 2 + net/ipv4/netfilter/Kconfig | 9 - net/ipv4/netfilter/Makefile | 1 - net/ipv4/netfilter/ipt_LOG.c | 516 ------------------ net/ipv6/netfilter/Kconfig | 9 - net/ipv6/netfilter/Makefile | 1 - net/ipv6/netfilter/ip6t_LOG.c | 527 ------------------ net/netfilter/Kconfig | 9 + net/netfilter/Makefile | 1 + net/netfilter/xt_LOG.c | 921 ++++++++++++++++++++++++++++++++ 13 files changed, 955 insertions(+), 1063 deletions(-) create mode 100644 include/linux/netfilter/xt_LOG.h delete mode 100644 net/ipv4/netfilter/ipt_LOG.c delete mode 100644 net/ipv6/netfilter/ip6t_LOG.c create mode 100644 net/netfilter/xt_LOG.c (limited to 'net') diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index e144f54185c..aaa72aaa21d 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -22,6 +22,7 @@ header-y += xt_CT.h header-y += xt_DSCP.h header-y += xt_IDLETIMER.h header-y += xt_LED.h +header-y += xt_LOG.h header-y += xt_MARK.h header-y += xt_nfacct.h header-y += xt_NFLOG.h diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h new file mode 100644 index 00000000000..cac07909530 --- /dev/null +++ b/include/linux/netfilter/xt_LOG.h @@ -0,0 +1,19 @@ +#ifndef _XT_LOG_H +#define _XT_LOG_H + +/* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */ +#define XT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define XT_LOG_TCPOPT 0x02 /* Log TCP options */ +#define XT_LOG_IPOPT 0x04 /* Log IP options */ +#define XT_LOG_UID 0x08 /* Log UID owning local socket */ +#define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ +#define XT_LOG_MACDECODE 0x20 /* Decode MAC header */ +#define XT_LOG_MASK 0x2f + +struct xt_log_info { + unsigned char level; + unsigned char logflags; + char prefix[30]; +}; + +#endif /* _XT_LOG_H */ diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h index dcdbadf9fd4..5d8152077d7 100644 --- a/include/linux/netfilter_ipv4/ipt_LOG.h +++ b/include/linux/netfilter_ipv4/ipt_LOG.h @@ -1,6 +1,8 @@ #ifndef _IPT_LOG_H #define _IPT_LOG_H +#warning "Please update iptables, this file will be removed soon!" + /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ #define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ #define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h index 9dd5579e02e..3dd0bc4e073 100644 --- a/include/linux/netfilter_ipv6/ip6t_LOG.h +++ b/include/linux/netfilter_ipv6/ip6t_LOG.h @@ -1,6 +1,8 @@ #ifndef _IP6T_LOG_H #define _IP6T_LOG_H +#warning "Please update iptables, this file will be removed soon!" + /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ #define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ #define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 74dfc9e5211..fcc543cd987 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -123,15 +123,6 @@ config IP_NF_TARGET_REJECT To compile it as a module, choose M here. If unsure, say N. -config IP_NF_TARGET_LOG - tristate "LOG target support" - default m if NETFILTER_ADVANCED=n - help - This option adds a `LOG' target, which allows you to create rules in - any iptables table which records the packet header to the syslog. - - To compile it as a module, choose M here. If unsure, say N. - config IP_NF_TARGET_ULOG tristate "ULOG target support" default m if NETFILTER_ADVANCED=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 213a462b739..240b68469a7 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -54,7 +54,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o # targets obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o -obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c deleted file mode 100644 index d76d6c9ed94..00000000000 --- a/net/ipv4/netfilter/ipt_LOG.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * This is a module which is used for logging packets. - */ - -/* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Netfilter Core Team "); -MODULE_DESCRIPTION("Xtables: IPv4 packet logging to syslog"); - -/* One level of recursion won't kill us */ -static void dump_packet(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb, - unsigned int iphoff) -{ - struct iphdr _iph; - const struct iphdr *ih; - unsigned int logflags; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - else - logflags = NF_LOG_MASK; - - ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); - if (ih == NULL) { - sb_add(m, "TRUNCATED"); - return; - } - - /* Important fields: - * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ - /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ - sb_add(m, "SRC=%pI4 DST=%pI4 ", - &ih->saddr, &ih->daddr); - - /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ - sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", - ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, - ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); - - /* Max length: 6 "CE DF MF " */ - if (ntohs(ih->frag_off) & IP_CE) - sb_add(m, "CE "); - if (ntohs(ih->frag_off) & IP_DF) - sb_add(m, "DF "); - if (ntohs(ih->frag_off) & IP_MF) - sb_add(m, "MF "); - - /* Max length: 11 "FRAG:65535 " */ - if (ntohs(ih->frag_off) & IP_OFFSET) - sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); - - if ((logflags & IPT_LOG_IPOPT) && - ih->ihl * 4 > sizeof(struct iphdr)) { - const unsigned char *op; - unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; - unsigned int i, optsize; - - optsize = ih->ihl * 4 - sizeof(struct iphdr); - op = skb_header_pointer(skb, iphoff+sizeof(_iph), - optsize, _opt); - if (op == NULL) { - sb_add(m, "TRUNCATED"); - return; - } - - /* Max length: 127 "OPT (" 15*4*2chars ") " */ - sb_add(m, "OPT ("); - for (i = 0; i < optsize; i++) - sb_add(m, "%02X", op[i]); - sb_add(m, ") "); - } - - switch (ih->protocol) { - case IPPROTO_TCP: { - struct tcphdr _tcph; - const struct tcphdr *th; - - /* Max length: 10 "PROTO=TCP " */ - sb_add(m, "PROTO=TCP "); - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - th = skb_header_pointer(skb, iphoff + ih->ihl * 4, - sizeof(_tcph), &_tcph); - if (th == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Max length: 20 "SPT=65535 DPT=65535 " */ - sb_add(m, "SPT=%u DPT=%u ", - ntohs(th->source), ntohs(th->dest)); - /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ - if (logflags & IPT_LOG_TCPSEQ) - sb_add(m, "SEQ=%u ACK=%u ", - ntohl(th->seq), ntohl(th->ack_seq)); - /* Max length: 13 "WINDOW=65535 " */ - sb_add(m, "WINDOW=%u ", ntohs(th->window)); - /* Max length: 9 "RES=0x3F " */ - sb_add(m, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); - /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ - if (th->cwr) - sb_add(m, "CWR "); - if (th->ece) - sb_add(m, "ECE "); - if (th->urg) - sb_add(m, "URG "); - if (th->ack) - sb_add(m, "ACK "); - if (th->psh) - sb_add(m, "PSH "); - if (th->rst) - sb_add(m, "RST "); - if (th->syn) - sb_add(m, "SYN "); - if (th->fin) - sb_add(m, "FIN "); - /* Max length: 11 "URGP=65535 " */ - sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); - - if ((logflags & IPT_LOG_TCPOPT) && - th->doff * 4 > sizeof(struct tcphdr)) { - unsigned char _opt[4 * 15 - sizeof(struct tcphdr)]; - const unsigned char *op; - unsigned int i, optsize; - - optsize = th->doff * 4 - sizeof(struct tcphdr); - op = skb_header_pointer(skb, - iphoff+ih->ihl*4+sizeof(_tcph), - optsize, _opt); - if (op == NULL) { - sb_add(m, "TRUNCATED"); - return; - } - - /* Max length: 127 "OPT (" 15*4*2chars ") " */ - sb_add(m, "OPT ("); - for (i = 0; i < optsize; i++) - sb_add(m, "%02X", op[i]); - sb_add(m, ") "); - } - break; - } - case IPPROTO_UDP: - case IPPROTO_UDPLITE: { - struct udphdr _udph; - const struct udphdr *uh; - - if (ih->protocol == IPPROTO_UDP) - /* Max length: 10 "PROTO=UDP " */ - sb_add(m, "PROTO=UDP " ); - else /* Max length: 14 "PROTO=UDPLITE " */ - sb_add(m, "PROTO=UDPLITE "); - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - uh = skb_header_pointer(skb, iphoff+ih->ihl*4, - sizeof(_udph), &_udph); - if (uh == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Max length: 20 "SPT=65535 DPT=65535 " */ - sb_add(m, "SPT=%u DPT=%u LEN=%u ", - ntohs(uh->source), ntohs(uh->dest), - ntohs(uh->len)); - break; - } - case IPPROTO_ICMP: { - struct icmphdr _icmph; - const struct icmphdr *ich; - static const size_t required_len[NR_ICMP_TYPES+1] - = { [ICMP_ECHOREPLY] = 4, - [ICMP_DEST_UNREACH] - = 8 + sizeof(struct iphdr), - [ICMP_SOURCE_QUENCH] - = 8 + sizeof(struct iphdr), - [ICMP_REDIRECT] - = 8 + sizeof(struct iphdr), - [ICMP_ECHO] = 4, - [ICMP_TIME_EXCEEDED] - = 8 + sizeof(struct iphdr), - [ICMP_PARAMETERPROB] - = 8 + sizeof(struct iphdr), - [ICMP_TIMESTAMP] = 20, - [ICMP_TIMESTAMPREPLY] = 20, - [ICMP_ADDRESS] = 12, - [ICMP_ADDRESSREPLY] = 12 }; - - /* Max length: 11 "PROTO=ICMP " */ - sb_add(m, "PROTO=ICMP "); - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, - sizeof(_icmph), &_icmph); - if (ich == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Max length: 18 "TYPE=255 CODE=255 " */ - sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - if (ich->type <= NR_ICMP_TYPES && - required_len[ich->type] && - skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - switch (ich->type) { - case ICMP_ECHOREPLY: - case ICMP_ECHO: - /* Max length: 19 "ID=65535 SEQ=65535 " */ - sb_add(m, "ID=%u SEQ=%u ", - ntohs(ich->un.echo.id), - ntohs(ich->un.echo.sequence)); - break; - - case ICMP_PARAMETERPROB: - /* Max length: 14 "PARAMETER=255 " */ - sb_add(m, "PARAMETER=%u ", - ntohl(ich->un.gateway) >> 24); - break; - case ICMP_REDIRECT: - /* Max length: 24 "GATEWAY=255.255.255.255 " */ - sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); - /* Fall through */ - case ICMP_DEST_UNREACH: - case ICMP_SOURCE_QUENCH: - case ICMP_TIME_EXCEEDED: - /* Max length: 3+maxlen */ - if (!iphoff) { /* Only recurse once. */ - sb_add(m, "["); - dump_packet(m, info, skb, - iphoff + ih->ihl*4+sizeof(_icmph)); - sb_add(m, "] "); - } - - /* Max length: 10 "MTU=65535 " */ - if (ich->type == ICMP_DEST_UNREACH && - ich->code == ICMP_FRAG_NEEDED) - sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); - } - break; - } - /* Max Length */ - case IPPROTO_AH: { - struct ip_auth_hdr _ahdr; - const struct ip_auth_hdr *ah; - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 9 "PROTO=AH " */ - sb_add(m, "PROTO=AH "); - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - ah = skb_header_pointer(skb, iphoff+ih->ihl*4, - sizeof(_ahdr), &_ahdr); - if (ah == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Length: 15 "SPI=0xF1234567 " */ - sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); - break; - } - case IPPROTO_ESP: { - struct ip_esp_hdr _esph; - const struct ip_esp_hdr *eh; - - /* Max length: 10 "PROTO=ESP " */ - sb_add(m, "PROTO=ESP "); - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - eh = skb_header_pointer(skb, iphoff+ih->ihl*4, - sizeof(_esph), &_esph); - if (eh == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Length: 15 "SPI=0xF1234567 " */ - sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); - break; - } - /* Max length: 10 "PROTO 255 " */ - default: - sb_add(m, "PROTO=%u ", ih->protocol); - } - - /* Max length: 15 "UID=4294967295 " */ - if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) { - read_lock_bh(&skb->sk->sk_callback_lock); - if (skb->sk->sk_socket && skb->sk->sk_socket->file) - sb_add(m, "UID=%u GID=%u ", - skb->sk->sk_socket->file->f_cred->fsuid, - skb->sk->sk_socket->file->f_cred->fsgid); - read_unlock_bh(&skb->sk->sk_callback_lock); - } - - /* Max length: 16 "MARK=0xFFFFFFFF " */ - if (!iphoff && skb->mark) - sb_add(m, "MARK=0x%x ", skb->mark); - - /* Proto Max log string length */ - /* IP: 40+46+6+11+127 = 230 */ - /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ - /* UDP: 10+max(25,20) = 35 */ - /* UDPLITE: 14+max(25,20) = 39 */ - /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ - /* ESP: 10+max(25)+15 = 50 */ - /* AH: 9+max(25)+15 = 49 */ - /* unknown: 10 */ - - /* (ICMP allows recursion one level deep) */ - /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ - /* maxlen = 230+ 91 + 230 + 252 = 803 */ -} - -static void dump_mac_header(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - unsigned int logflags = 0; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - - if (!(logflags & IPT_LOG_MACDECODE)) - goto fallback; - - switch (dev->type) { - case ARPHRD_ETHER: - sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", - eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, - ntohs(eth_hdr(skb)->h_proto)); - return; - default: - break; - } - -fallback: - sb_add(m, "MAC="); - if (dev->hard_header_len && - skb->mac_header != skb->network_header) { - const unsigned char *p = skb_mac_header(skb); - unsigned int i; - - sb_add(m, "%02x", *p++); - for (i = 1; i < dev->hard_header_len; i++, p++) - sb_add(m, ":%02x", *p); - } - sb_add(m, " "); -} - -static struct nf_loginfo default_loginfo = { - .type = NF_LOG_TYPE_LOG, - .u = { - .log = { - .level = 5, - .logflags = NF_LOG_MASK, - }, - }, -}; - -static void -ipt_log_packet(u_int8_t pf, - unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix) -{ - struct sbuff *m = sb_open(); - - if (!loginfo) - loginfo = &default_loginfo; - - sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, - prefix, - in ? in->name : "", - out ? out->name : ""); -#ifdef CONFIG_BRIDGE_NETFILTER - if (skb->nf_bridge) { - const struct net_device *physindev; - const struct net_device *physoutdev; - - physindev = skb->nf_bridge->physindev; - if (physindev && in != physindev) - sb_add(m, "PHYSIN=%s ", physindev->name); - physoutdev = skb->nf_bridge->physoutdev; - if (physoutdev && out != physoutdev) - sb_add(m, "PHYSOUT=%s ", physoutdev->name); - } -#endif - - if (in != NULL) - dump_mac_header(m, loginfo, skb); - - dump_packet(m, loginfo, skb, 0); - - sb_close(m); -} - -static unsigned int -log_tg(struct sk_buff *skb, const struct xt_action_param *par) -{ - const struct ipt_log_info *loginfo = par->targinfo; - struct nf_loginfo li; - - li.type = NF_LOG_TYPE_LOG; - li.u.log.level = loginfo->level; - li.u.log.logflags = loginfo->logflags; - - ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li, - loginfo->prefix); - return XT_CONTINUE; -} - -static int log_tg_check(const struct xt_tgchk_param *par) -{ - const struct ipt_log_info *loginfo = par->targinfo; - - if (loginfo->level >= 8) { - pr_debug("level %u >= 8\n", loginfo->level); - return -EINVAL; - } - if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { - pr_debug("prefix is not null-terminated\n"); - return -EINVAL; - } - return 0; -} - -static struct xt_target log_tg_reg __read_mostly = { - .name = "LOG", - .family = NFPROTO_IPV4, - .target = log_tg, - .targetsize = sizeof(struct ipt_log_info), - .checkentry = log_tg_check, - .me = THIS_MODULE, -}; - -static struct nf_logger ipt_log_logger __read_mostly = { - .name = "ipt_LOG", - .logfn = &ipt_log_packet, - .me = THIS_MODULE, -}; - -static int __init log_tg_init(void) -{ - int ret; - - ret = xt_register_target(&log_tg_reg); - if (ret < 0) - return ret; - nf_log_register(NFPROTO_IPV4, &ipt_log_logger); - return 0; -} - -static void __exit log_tg_exit(void) -{ - nf_log_unregister(&ipt_log_logger); - xt_unregister_target(&log_tg_reg); -} - -module_init(log_tg_init); -module_exit(log_tg_exit); diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 9a68fb5b9e7..d33cddd16fb 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -154,15 +154,6 @@ config IP6_NF_TARGET_HL (e.g. when running oldconfig). It selects CONFIG_NETFILTER_XT_TARGET_HL. -config IP6_NF_TARGET_LOG - tristate "LOG target support" - default m if NETFILTER_ADVANCED=n - help - This option adds a `LOG' target, which allows you to create rules in - any iptables table which records the packet header to the syslog. - - To compile it as a module, choose M here. If unsure, say N. - config IP6_NF_FILTER tristate "Packet filtering" default m if NETFILTER_ADVANCED=n diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 2eaed96db02..d4dfd0a2109 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -31,5 +31,4 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o # targets -obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c deleted file mode 100644 index e6af8d72f26..00000000000 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * This is a module which is used for logging packets. - */ - -/* (C) 2001 Jan Rekorajski - * (C) 2002-2004 Netfilter Core Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Jan Rekorajski "); -MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog"); -MODULE_LICENSE("GPL"); - -struct in_device; -#include -#include - -/* One level of recursion won't kill us */ -static void dump_packet(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb, unsigned int ip6hoff, - int recurse) -{ - u_int8_t currenthdr; - int fragment; - struct ipv6hdr _ip6h; - const struct ipv6hdr *ih; - unsigned int ptr; - unsigned int hdrlen = 0; - unsigned int logflags; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - else - logflags = NF_LOG_MASK; - - ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); - if (ih == NULL) { - sb_add(m, "TRUNCATED"); - return; - } - - /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ - sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); - - /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ - sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", - ntohs(ih->payload_len) + sizeof(struct ipv6hdr), - (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, - ih->hop_limit, - (ntohl(*(__be32 *)ih) & 0x000fffff)); - - fragment = 0; - ptr = ip6hoff + sizeof(struct ipv6hdr); - currenthdr = ih->nexthdr; - while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { - struct ipv6_opt_hdr _hdr; - const struct ipv6_opt_hdr *hp; - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - if (hp == NULL) { - sb_add(m, "TRUNCATED"); - return; - } - - /* Max length: 48 "OPT (...) " */ - if (logflags & IP6T_LOG_IPOPT) - sb_add(m, "OPT ( "); - - switch (currenthdr) { - case IPPROTO_FRAGMENT: { - struct frag_hdr _fhdr; - const struct frag_hdr *fh; - - sb_add(m, "FRAG:"); - fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), - &_fhdr); - if (fh == NULL) { - sb_add(m, "TRUNCATED "); - return; - } - - /* Max length: 6 "65535 " */ - sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); - - /* Max length: 11 "INCOMPLETE " */ - if (fh->frag_off & htons(0x0001)) - sb_add(m, "INCOMPLETE "); - - sb_add(m, "ID:%08x ", ntohl(fh->identification)); - - if (ntohs(fh->frag_off) & 0xFFF8) - fragment = 1; - - hdrlen = 8; - - break; - } - case IPPROTO_DSTOPTS: - case IPPROTO_ROUTING: - case IPPROTO_HOPOPTS: - if (fragment) { - if (logflags & IP6T_LOG_IPOPT) - sb_add(m, ")"); - return; - } - hdrlen = ipv6_optlen(hp); - break; - /* Max Length */ - case IPPROTO_AH: - if (logflags & IP6T_LOG_IPOPT) { - struct ip_auth_hdr _ahdr; - const struct ip_auth_hdr *ah; - - /* Max length: 3 "AH " */ - sb_add(m, "AH "); - - if (fragment) { - sb_add(m, ")"); - return; - } - - ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), - &_ahdr); - if (ah == NULL) { - /* - * Max length: 26 "INCOMPLETE [65535 - * bytes] )" - */ - sb_add(m, "INCOMPLETE [%u bytes] )", - skb->len - ptr); - return; - } - - /* Length: 15 "SPI=0xF1234567 */ - sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); - - } - - hdrlen = (hp->hdrlen+2)<<2; - break; - case IPPROTO_ESP: - if (logflags & IP6T_LOG_IPOPT) { - struct ip_esp_hdr _esph; - const struct ip_esp_hdr *eh; - - /* Max length: 4 "ESP " */ - sb_add(m, "ESP "); - - if (fragment) { - sb_add(m, ")"); - return; - } - - /* - * Max length: 26 "INCOMPLETE [65535 bytes] )" - */ - eh = skb_header_pointer(skb, ptr, sizeof(_esph), - &_esph); - if (eh == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] )", - skb->len - ptr); - return; - } - - /* Length: 16 "SPI=0xF1234567 )" */ - sb_add(m, "SPI=0x%x )", ntohl(eh->spi) ); - - } - return; - default: - /* Max length: 20 "Unknown Ext Hdr 255" */ - sb_add(m, "Unknown Ext Hdr %u", currenthdr); - return; - } - if (logflags & IP6T_LOG_IPOPT) - sb_add(m, ") "); - - currenthdr = hp->nexthdr; - ptr += hdrlen; - } - - switch (currenthdr) { - case IPPROTO_TCP: { - struct tcphdr _tcph; - const struct tcphdr *th; - - /* Max length: 10 "PROTO=TCP " */ - sb_add(m, "PROTO=TCP "); - - if (fragment) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); - if (th == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); - return; - } - - /* Max length: 20 "SPT=65535 DPT=65535 " */ - sb_add(m, "SPT=%u DPT=%u ", - ntohs(th->source), ntohs(th->dest)); - /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ - if (logflags & IP6T_LOG_TCPSEQ) - sb_add(m, "SEQ=%u ACK=%u ", - ntohl(th->seq), ntohl(th->ack_seq)); - /* Max length: 13 "WINDOW=65535 " */ - sb_add(m, "WINDOW=%u ", ntohs(th->window)); - /* Max length: 9 "RES=0x3C " */ - sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); - /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ - if (th->cwr) - sb_add(m, "CWR "); - if (th->ece) - sb_add(m, "ECE "); - if (th->urg) - sb_add(m, "URG "); - if (th->ack) - sb_add(m, "ACK "); - if (th->psh) - sb_add(m, "PSH "); - if (th->rst) - sb_add(m, "RST "); - if (th->syn) - sb_add(m, "SYN "); - if (th->fin) - sb_add(m, "FIN "); - /* Max length: 11 "URGP=65535 " */ - sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); - - if ((logflags & IP6T_LOG_TCPOPT) && - th->doff * 4 > sizeof(struct tcphdr)) { - u_int8_t _opt[60 - sizeof(struct tcphdr)]; - const u_int8_t *op; - unsigned int i; - unsigned int optsize = th->doff * 4 - - sizeof(struct tcphdr); - - op = skb_header_pointer(skb, - ptr + sizeof(struct tcphdr), - optsize, _opt); - if (op == NULL) { - sb_add(m, "OPT (TRUNCATED)"); - return; - } - - /* Max length: 127 "OPT (" 15*4*2chars ") " */ - sb_add(m, "OPT ("); - for (i =0; i < optsize; i++) - sb_add(m, "%02X", op[i]); - sb_add(m, ") "); - } - break; - } - case IPPROTO_UDP: - case IPPROTO_UDPLITE: { - struct udphdr _udph; - const struct udphdr *uh; - - if (currenthdr == IPPROTO_UDP) - /* Max length: 10 "PROTO=UDP " */ - sb_add(m, "PROTO=UDP " ); - else /* Max length: 14 "PROTO=UDPLITE " */ - sb_add(m, "PROTO=UDPLITE "); - - if (fragment) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); - if (uh == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); - return; - } - - /* Max length: 20 "SPT=65535 DPT=65535 " */ - sb_add(m, "SPT=%u DPT=%u LEN=%u ", - ntohs(uh->source), ntohs(uh->dest), - ntohs(uh->len)); - break; - } - case IPPROTO_ICMPV6: { - struct icmp6hdr _icmp6h; - const struct icmp6hdr *ic; - - /* Max length: 13 "PROTO=ICMPv6 " */ - sb_add(m, "PROTO=ICMPv6 "); - - if (fragment) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); - if (ic == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); - return; - } - - /* Max length: 18 "TYPE=255 CODE=255 " */ - sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); - - switch (ic->icmp6_type) { - case ICMPV6_ECHO_REQUEST: - case ICMPV6_ECHO_REPLY: - /* Max length: 19 "ID=65535 SEQ=65535 " */ - sb_add(m, "ID=%u SEQ=%u ", - ntohs(ic->icmp6_identifier), - ntohs(ic->icmp6_sequence)); - break; - case ICMPV6_MGM_QUERY: - case ICMPV6_MGM_REPORT: - case ICMPV6_MGM_REDUCTION: - break; - - case ICMPV6_PARAMPROB: - /* Max length: 17 "POINTER=ffffffff " */ - sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); - /* Fall through */ - case ICMPV6_DEST_UNREACH: - case ICMPV6_PKT_TOOBIG: - case ICMPV6_TIME_EXCEED: - /* Max length: 3+maxlen */ - if (recurse) { - sb_add(m, "["); - dump_packet(m, info, skb, - ptr + sizeof(_icmp6h), 0); - sb_add(m, "] "); - } - - /* Max length: 10 "MTU=65535 " */ - if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) - sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); - } - break; - } - /* Max length: 10 "PROTO=255 " */ - default: - sb_add(m, "PROTO=%u ", currenthdr); - } - - /* Max length: 15 "UID=4294967295 " */ - if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { - read_lock_bh(&skb->sk->sk_callback_lock); - if (skb->sk->sk_socket && skb->sk->sk_socket->file) - sb_add(m, "UID=%u GID=%u ", - skb->sk->sk_socket->file->f_cred->fsuid, - skb->sk->sk_socket->file->f_cred->fsgid); - read_unlock_bh(&skb->sk->sk_callback_lock); - } - - /* Max length: 16 "MARK=0xFFFFFFFF " */ - if (!recurse && skb->mark) - sb_add(m, "MARK=0x%x ", skb->mark); -} - -static void dump_mac_header(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - unsigned int logflags = 0; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - - if (!(logflags & IP6T_LOG_MACDECODE)) - goto fallback; - - switch (dev->type) { - case ARPHRD_ETHER: - sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", - eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, - ntohs(eth_hdr(skb)->h_proto)); - return; - default: - break; - } - -fallback: - sb_add(m, "MAC="); - if (dev->hard_header_len && - skb->mac_header != skb->network_header) { - const unsigned char *p = skb_mac_header(skb); - unsigned int len = dev->hard_header_len; - unsigned int i; - - if (dev->type == ARPHRD_SIT && - (p -= ETH_HLEN) < skb->head) - p = NULL; - - if (p != NULL) { - sb_add(m, "%02x", *p++); - for (i = 1; i < len; i++) - sb_add(m, ":%02x", *p++); - } - sb_add(m, " "); - - if (dev->type == ARPHRD_SIT) { - const struct iphdr *iph = - (struct iphdr *)skb_mac_header(skb); - sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); - } - } else - sb_add(m, " "); -} - -static struct nf_loginfo default_loginfo = { - .type = NF_LOG_TYPE_LOG, - .u = { - .log = { - .level = 5, - .logflags = NF_LOG_MASK, - }, - }, -}; - -static void -ip6t_log_packet(u_int8_t pf, - unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix) -{ - struct sbuff *m = sb_open(); - - if (!loginfo) - loginfo = &default_loginfo; - - sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, - prefix, - in ? in->name : "", - out ? out->name : ""); - - if (in != NULL) - dump_mac_header(m, loginfo, skb); - - dump_packet(m, loginfo, skb, skb_network_offset(skb), 1); - - sb_close(m); -} - -static unsigned int -log_tg6(struct sk_buff *skb, const struct xt_action_param *par) -{ - const struct ip6t_log_info *loginfo = par->targinfo; - struct nf_loginfo li; - - li.type = NF_LOG_TYPE_LOG; - li.u.log.level = loginfo->level; - li.u.log.logflags = loginfo->logflags; - - ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out, - &li, loginfo->prefix); - return XT_CONTINUE; -} - - -static int log_tg6_check(const struct xt_tgchk_param *par) -{ - const struct ip6t_log_info *loginfo = par->targinfo; - - if (loginfo->level >= 8) { - pr_debug("level %u >= 8\n", loginfo->level); - return -EINVAL; - } - if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { - pr_debug("prefix not null-terminated\n"); - return -EINVAL; - } - return 0; -} - -static struct xt_target log_tg6_reg __read_mostly = { - .name = "LOG", - .family = NFPROTO_IPV6, - .target = log_tg6, - .targetsize = sizeof(struct ip6t_log_info), - .checkentry = log_tg6_check, - .me = THIS_MODULE, -}; - -static struct nf_logger ip6t_logger __read_mostly = { - .name = "ip6t_LOG", - .logfn = &ip6t_log_packet, - .me = THIS_MODULE, -}; - -static int __init log_tg6_init(void) -{ - int ret; - - ret = xt_register_target(&log_tg6_reg); - if (ret < 0) - return ret; - nf_log_register(NFPROTO_IPV6, &ip6t_logger); - return 0; -} - -static void __exit log_tg6_exit(void) -{ - nf_log_unregister(&ip6t_logger); - xt_unregister_target(&log_tg6_reg); -} - -module_init(log_tg6_init); -module_exit(log_tg6_exit); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f8ac4ef0b79..b895d8b1321 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -524,6 +524,15 @@ config NETFILTER_XT_TARGET_LED For more information on the LEDs available on your system, see Documentation/leds/leds-class.txt +config NETFILTER_XT_TARGET_LOG + tristate "LOG target support" + default m if NETFILTER_ADVANCED=n + help + This option adds a `LOG' target, which allows you to create rules in + any iptables table which records the packet header to the syslog. + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_TARGET_MARK tristate '"MARK" target support' depends on NETFILTER_ADVANCED diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 40f4c3d636c..a28c2a6563f 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o +obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c new file mode 100644 index 00000000000..1595608a892 --- /dev/null +++ b/net/netfilter/xt_LOG.c @@ -0,0 +1,921 @@ +/* + * This is a module which is used for logging packets. + */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2004 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static struct nf_loginfo default_loginfo = { + .type = NF_LOG_TYPE_LOG, + .u = { + .log = { + .level = 5, + .logflags = NF_LOG_MASK, + }, + }, +}; + +static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset) +{ + struct udphdr _udph; + const struct udphdr *uh; + + if (proto == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + sb_add(m, "PROTO=UDP "); + else /* Max length: 14 "PROTO=UDPLITE " */ + sb_add(m, "PROTO=UDPLITE "); + + if (fragment) + goto out; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); + if (uh == NULL) { + sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); + + return 1; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ + sb_add(m, "SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), + ntohs(uh->len)); + +out: + return 0; +} + +static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset, + unsigned int logflags) +{ + struct tcphdr _tcph; + const struct tcphdr *th; + + /* Max length: 10 "PROTO=TCP " */ + sb_add(m, "PROTO=TCP "); + + if (fragment) + return 0; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); + if (th == NULL) { + sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); + return 1; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ + sb_add(m, "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); + /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ + if (logflags & XT_LOG_TCPSEQ) + sb_add(m, "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); + + /* Max length: 13 "WINDOW=65535 " */ + sb_add(m, "WINDOW=%u ", ntohs(th->window)); + /* Max length: 9 "RES=0x3C " */ + sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & + TCP_RESERVED_BITS) >> 22)); + /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ + if (th->cwr) + sb_add(m, "CWR "); + if (th->ece) + sb_add(m, "ECE "); + if (th->urg) + sb_add(m, "URG "); + if (th->ack) + sb_add(m, "ACK "); + if (th->psh) + sb_add(m, "PSH "); + if (th->rst) + sb_add(m, "RST "); + if (th->syn) + sb_add(m, "SYN "); + if (th->fin) + sb_add(m, "FIN "); + /* Max length: 11 "URGP=65535 " */ + sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); + + if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { + u_int8_t _opt[60 - sizeof(struct tcphdr)]; + const u_int8_t *op; + unsigned int i; + unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); + + op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), + optsize, _opt); + if (op == NULL) { + sb_add(m, "OPT (TRUNCATED)"); + return 1; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + sb_add(m, "OPT ("); + for (i = 0; i < optsize; i++) + sb_add(m, "%02X", op[i]); + + sb_add(m, ") "); + } + + return 0; +} + +/* One level of recursion won't kill us */ +static void dump_ipv4_packet(struct sbuff *m, + const struct nf_loginfo *info, + const struct sk_buff *skb, + unsigned int iphoff) +{ + struct iphdr _iph; + const struct iphdr *ih; + unsigned int logflags; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + else + logflags = NF_LOG_MASK; + + ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); + if (ih == NULL) { + sb_add(m, "TRUNCATED"); + return; + } + + /* Important fields: + * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ + /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ + sb_add(m, "SRC=%pI4 DST=%pI4 ", + &ih->saddr, &ih->daddr); + + /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ + sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", + ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, + ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); + + /* Max length: 6 "CE DF MF " */ + if (ntohs(ih->frag_off) & IP_CE) + sb_add(m, "CE "); + if (ntohs(ih->frag_off) & IP_DF) + sb_add(m, "DF "); + if (ntohs(ih->frag_off) & IP_MF) + sb_add(m, "MF "); + + /* Max length: 11 "FRAG:65535 " */ + if (ntohs(ih->frag_off) & IP_OFFSET) + sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); + + if ((logflags & XT_LOG_IPOPT) && + ih->ihl * 4 > sizeof(struct iphdr)) { + const unsigned char *op; + unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; + unsigned int i, optsize; + + optsize = ih->ihl * 4 - sizeof(struct iphdr); + op = skb_header_pointer(skb, iphoff+sizeof(_iph), + optsize, _opt); + if (op == NULL) { + sb_add(m, "TRUNCATED"); + return; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + sb_add(m, "OPT ("); + for (i = 0; i < optsize; i++) + sb_add(m, "%02X", op[i]); + sb_add(m, ") "); + } + + switch (ih->protocol) { + case IPPROTO_TCP: + if (dump_tcp_header(m, skb, ih->protocol, + ntohs(ih->frag_off) & IP_OFFSET, + iphoff+ih->ihl*4, logflags)) + return; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + if (dump_udp_header(m, skb, ih->protocol, + ntohs(ih->frag_off) & IP_OFFSET, + iphoff+ih->ihl*4)) + return; + case IPPROTO_ICMP: { + struct icmphdr _icmph; + const struct icmphdr *ich; + static const size_t required_len[NR_ICMP_TYPES+1] + = { [ICMP_ECHOREPLY] = 4, + [ICMP_DEST_UNREACH] + = 8 + sizeof(struct iphdr), + [ICMP_SOURCE_QUENCH] + = 8 + sizeof(struct iphdr), + [ICMP_REDIRECT] + = 8 + sizeof(struct iphdr), + [ICMP_ECHO] = 4, + [ICMP_TIME_EXCEEDED] + = 8 + sizeof(struct iphdr), + [ICMP_PARAMETERPROB] + = 8 + sizeof(struct iphdr), + [ICMP_TIMESTAMP] = 20, + [ICMP_TIMESTAMPREPLY] = 20, + [ICMP_ADDRESS] = 12, + [ICMP_ADDRESSREPLY] = 12 }; + + /* Max length: 11 "PROTO=ICMP " */ + sb_add(m, "PROTO=ICMP "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, + sizeof(_icmph), &_icmph); + if (ich == NULL) { + sb_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Max length: 18 "TYPE=255 CODE=255 " */ + sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (ich->type <= NR_ICMP_TYPES && + required_len[ich->type] && + skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { + sb_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + switch (ich->type) { + case ICMP_ECHOREPLY: + case ICMP_ECHO: + /* Max length: 19 "ID=65535 SEQ=65535 " */ + sb_add(m, "ID=%u SEQ=%u ", + ntohs(ich->un.echo.id), + ntohs(ich->un.echo.sequence)); + break; + + case ICMP_PARAMETERPROB: + /* Max length: 14 "PARAMETER=255 " */ + sb_add(m, "PARAMETER=%u ", + ntohl(ich->un.gateway) >> 24); + break; + case ICMP_REDIRECT: + /* Max length: 24 "GATEWAY=255.255.255.255 " */ + sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); + /* Fall through */ + case ICMP_DEST_UNREACH: + case ICMP_SOURCE_QUENCH: + case ICMP_TIME_EXCEEDED: + /* Max length: 3+maxlen */ + if (!iphoff) { /* Only recurse once. */ + sb_add(m, "["); + dump_ipv4_packet(m, info, skb, + iphoff + ih->ihl*4+sizeof(_icmph)); + sb_add(m, "] "); + } + + /* Max length: 10 "MTU=65535 " */ + if (ich->type == ICMP_DEST_UNREACH && + ich->code == ICMP_FRAG_NEEDED) + sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); + } + break; + } + /* Max Length */ + case IPPROTO_AH: { + struct ip_auth_hdr _ahdr; + const struct ip_auth_hdr *ah; + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + + /* Max length: 9 "PROTO=AH " */ + sb_add(m, "PROTO=AH "); + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ah = skb_header_pointer(skb, iphoff+ih->ihl*4, + sizeof(_ahdr), &_ahdr); + if (ah == NULL) { + sb_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ + sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); + break; + } + case IPPROTO_ESP: { + struct ip_esp_hdr _esph; + const struct ip_esp_hdr *eh; + + /* Max length: 10 "PROTO=ESP " */ + sb_add(m, "PROTO=ESP "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + eh = skb_header_pointer(skb, iphoff+ih->ihl*4, + sizeof(_esph), &_esph); + if (eh == NULL) { + sb_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ + sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); + break; + } + /* Max length: 10 "PROTO 255 " */ + default: + sb_add(m, "PROTO=%u ", ih->protocol); + } + + /* Max length: 15 "UID=4294967295 " */ + if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) { + read_lock_bh(&skb->sk->sk_callback_lock); + if (skb->sk->sk_socket && skb->sk->sk_socket->file) + sb_add(m, "UID=%u GID=%u ", + skb->sk->sk_socket->file->f_cred->fsuid, + skb->sk->sk_socket->file->f_cred->fsgid); + read_unlock_bh(&skb->sk->sk_callback_lock); + } + + /* Max length: 16 "MARK=0xFFFFFFFF " */ + if (!iphoff && skb->mark) + sb_add(m, "MARK=0x%x ", skb->mark); + + /* Proto Max log string length */ + /* IP: 40+46+6+11+127 = 230 */ + /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ + /* UDP: 10+max(25,20) = 35 */ + /* UDPLITE: 14+max(25,20) = 39 */ + /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ + /* ESP: 10+max(25)+15 = 50 */ + /* AH: 9+max(25)+15 = 49 */ + /* unknown: 10 */ + + /* (ICMP allows recursion one level deep) */ + /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ + /* maxlen = 230+ 91 + 230 + 252 = 803 */ +} + +static void dump_ipv4_mac_header(struct sbuff *m, + const struct nf_loginfo *info, + const struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + unsigned int logflags = 0; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + + if (!(logflags & XT_LOG_MACDECODE)) + goto fallback; + + switch (dev->type) { + case ARPHRD_ETHER: + sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, + ntohs(eth_hdr(skb)->h_proto)); + return; + default: + break; + } + +fallback: + sb_add(m, "MAC="); + if (dev->hard_header_len && + skb->mac_header != skb->network_header) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + + sb_add(m, "%02x", *p++); + for (i = 1; i < dev->hard_header_len; i++, p++) + sb_add(m, ":%02x", *p); + } + sb_add(m, " "); +} + +static void +log_packet_common(struct sbuff *m, + u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) +{ + sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, + prefix, + in ? in->name : "", + out ? out->name : ""); +#ifdef CONFIG_BRIDGE_NETFILTER + if (skb->nf_bridge) { + const struct net_device *physindev; + const struct net_device *physoutdev; + + physindev = skb->nf_bridge->physindev; + if (physindev && in != physindev) + sb_add(m, "PHYSIN=%s ", physindev->name); + physoutdev = skb->nf_bridge->physoutdev; + if (physoutdev && out != physoutdev) + sb_add(m, "PHYSOUT=%s ", physoutdev->name); + } +#endif +} + + +static void +ipt_log_packet(u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) +{ + struct sbuff *m = sb_open(); + + if (!loginfo) + loginfo = &default_loginfo; + + log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); + + if (in != NULL) + dump_ipv4_mac_header(m, loginfo, skb); + + dump_ipv4_packet(m, loginfo, skb, 0); + + sb_close(m); +} + +#if IS_ENABLED(CONFIG_IPV6) +/* One level of recursion won't kill us */ +static void dump_ipv6_packet(struct sbuff *m, + const struct nf_loginfo *info, + const struct sk_buff *skb, unsigned int ip6hoff, + int recurse) +{ + u_int8_t currenthdr; + int fragment; + struct ipv6hdr _ip6h; + const struct ipv6hdr *ih; + unsigned int ptr; + unsigned int hdrlen = 0; + unsigned int logflags; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + else + logflags = NF_LOG_MASK; + + ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); + if (ih == NULL) { + sb_add(m, "TRUNCATED"); + return; + } + + /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ + sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); + + /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ + sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", + ntohs(ih->payload_len) + sizeof(struct ipv6hdr), + (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, + ih->hop_limit, + (ntohl(*(__be32 *)ih) & 0x000fffff)); + + fragment = 0; + ptr = ip6hoff + sizeof(struct ipv6hdr); + currenthdr = ih->nexthdr; + while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { + struct ipv6_opt_hdr _hdr; + const struct ipv6_opt_hdr *hp; + + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + if (hp == NULL) { + sb_add(m, "TRUNCATED"); + return; + } + + /* Max length: 48 "OPT (...) " */ + if (logflags & XT_LOG_IPOPT) + sb_add(m, "OPT ( "); + + switch (currenthdr) { + case IPPROTO_FRAGMENT: { + struct frag_hdr _fhdr; + const struct frag_hdr *fh; + + sb_add(m, "FRAG:"); + fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), + &_fhdr); + if (fh == NULL) { + sb_add(m, "TRUNCATED "); + return; + } + + /* Max length: 6 "65535 " */ + sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); + + /* Max length: 11 "INCOMPLETE " */ + if (fh->frag_off & htons(0x0001)) + sb_add(m, "INCOMPLETE "); + + sb_add(m, "ID:%08x ", ntohl(fh->identification)); + + if (ntohs(fh->frag_off) & 0xFFF8) + fragment = 1; + + hdrlen = 8; + + break; + } + case IPPROTO_DSTOPTS: + case IPPROTO_ROUTING: + case IPPROTO_HOPOPTS: + if (fragment) { + if (logflags & XT_LOG_IPOPT) + sb_add(m, ")"); + return; + } + hdrlen = ipv6_optlen(hp); + break; + /* Max Length */ + case IPPROTO_AH: + if (logflags & XT_LOG_IPOPT) { + struct ip_auth_hdr _ahdr; + const struct ip_auth_hdr *ah; + + /* Max length: 3 "AH " */ + sb_add(m, "AH "); + + if (fragment) { + sb_add(m, ")"); + return; + } + + ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), + &_ahdr); + if (ah == NULL) { + /* + * Max length: 26 "INCOMPLETE [65535 + * bytes] )" + */ + sb_add(m, "INCOMPLETE [%u bytes] )", + skb->len - ptr); + return; + } + + /* Length: 15 "SPI=0xF1234567 */ + sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); + + } + + hdrlen = (hp->hdrlen+2)<<2; + break; + case IPPROTO_ESP: + if (logflags & XT_LOG_IPOPT) { + struct ip_esp_hdr _esph; + const struct ip_esp_hdr *eh; + + /* Max length: 4 "ESP " */ + sb_add(m, "ESP "); + + if (fragment) { + sb_add(m, ")"); + return; + } + + /* + * Max length: 26 "INCOMPLETE [65535 bytes] )" + */ + eh = skb_header_pointer(skb, ptr, sizeof(_esph), + &_esph); + if (eh == NULL) { + sb_add(m, "INCOMPLETE [%u bytes] )", + skb->len - ptr); + return; + } + + /* Length: 16 "SPI=0xF1234567 )" */ + sb_add(m, "SPI=0x%x )", ntohl(eh->spi)); + + } + return; + default: + /* Max length: 20 "Unknown Ext Hdr 255" */ + sb_add(m, "Unknown Ext Hdr %u", currenthdr); + return; + } + if (logflags & XT_LOG_IPOPT) + sb_add(m, ") "); + + currenthdr = hp->nexthdr; + ptr += hdrlen; + } + + switch (currenthdr) { + case IPPROTO_TCP: + if (dump_tcp_header(m, skb, currenthdr, fragment, ptr, + logflags)) + return; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + if (dump_udp_header(m, skb, currenthdr, fragment, ptr)) + return; + case IPPROTO_ICMPV6: { + struct icmp6hdr _icmp6h; + const struct icmp6hdr *ic; + + /* Max length: 13 "PROTO=ICMPv6 " */ + sb_add(m, "PROTO=ICMPv6 "); + + if (fragment) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); + if (ic == NULL) { + sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); + return; + } + + /* Max length: 18 "TYPE=255 CODE=255 " */ + sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); + + switch (ic->icmp6_type) { + case ICMPV6_ECHO_REQUEST: + case ICMPV6_ECHO_REPLY: + /* Max length: 19 "ID=65535 SEQ=65535 " */ + sb_add(m, "ID=%u SEQ=%u ", + ntohs(ic->icmp6_identifier), + ntohs(ic->icmp6_sequence)); + break; + case ICMPV6_MGM_QUERY: + case ICMPV6_MGM_REPORT: + case ICMPV6_MGM_REDUCTION: + break; + + case ICMPV6_PARAMPROB: + /* Max length: 17 "POINTER=ffffffff " */ + sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); + /* Fall through */ + case ICMPV6_DEST_UNREACH: + case ICMPV6_PKT_TOOBIG: + case ICMPV6_TIME_EXCEED: + /* Max length: 3+maxlen */ + if (recurse) { + sb_add(m, "["); + dump_ipv6_packet(m, info, skb, + ptr + sizeof(_icmp6h), 0); + sb_add(m, "] "); + } + + /* Max length: 10 "MTU=65535 " */ + if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) + sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); + } + break; + } + /* Max length: 10 "PROTO=255 " */ + default: + sb_add(m, "PROTO=%u ", currenthdr); + } + + /* Max length: 15 "UID=4294967295 " */ + if ((logflags & XT_LOG_UID) && recurse && skb->sk) { + read_lock_bh(&skb->sk->sk_callback_lock); + if (skb->sk->sk_socket && skb->sk->sk_socket->file) + sb_add(m, "UID=%u GID=%u ", + skb->sk->sk_socket->file->f_cred->fsuid, + skb->sk->sk_socket->file->f_cred->fsgid); + read_unlock_bh(&skb->sk->sk_callback_lock); + } + + /* Max length: 16 "MARK=0xFFFFFFFF " */ + if (!recurse && skb->mark) + sb_add(m, "MARK=0x%x ", skb->mark); +} + +static void dump_ipv6_mac_header(struct sbuff *m, + const struct nf_loginfo *info, + const struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + unsigned int logflags = 0; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + + if (!(logflags & XT_LOG_MACDECODE)) + goto fallback; + + switch (dev->type) { + case ARPHRD_ETHER: + sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, + ntohs(eth_hdr(skb)->h_proto)); + return; + default: + break; + } + +fallback: + sb_add(m, "MAC="); + if (dev->hard_header_len && + skb->mac_header != skb->network_header) { + const unsigned char *p = skb_mac_header(skb); + unsigned int len = dev->hard_header_len; + unsigned int i; + + if (dev->type == ARPHRD_SIT) { + p -= ETH_HLEN; + + if (p < skb->head) + p = NULL; + } + + if (p != NULL) { + sb_add(m, "%02x", *p++); + for (i = 1; i < len; i++) + sb_add(m, ":%02x", *p++); + } + sb_add(m, " "); + + if (dev->type == ARPHRD_SIT) { + const struct iphdr *iph = + (struct iphdr *)skb_mac_header(skb); + sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, + &iph->daddr); + } + } else + sb_add(m, " "); +} + +static void +ip6t_log_packet(u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) +{ + struct sbuff *m = sb_open(); + + if (!loginfo) + loginfo = &default_loginfo; + + log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); + + if (in != NULL) + dump_ipv6_mac_header(m, loginfo, skb); + + dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); + + sb_close(m); +} +#endif + +static unsigned int +log_tg(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_log_info *loginfo = par->targinfo; + struct nf_loginfo li; + + li.type = NF_LOG_TYPE_LOG; + li.u.log.level = loginfo->level; + li.u.log.logflags = loginfo->logflags; + + if (par->family == NFPROTO_IPV4) + ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, + par->out, &li, loginfo->prefix); +#if IS_ENABLED(CONFIG_IPV6) + else if (par->family == NFPROTO_IPV6) + ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, + par->out, &li, loginfo->prefix); +#endif + else + WARN_ON_ONCE(1); + + return XT_CONTINUE; +} + +static int log_tg_check(const struct xt_tgchk_param *par) +{ + const struct xt_log_info *loginfo = par->targinfo; + + if (par->family != NFPROTO_IPV4 && par->family != NFPROTO_IPV6) + return -EINVAL; + + if (loginfo->level >= 8) { + pr_debug("level %u >= 8\n", loginfo->level); + return -EINVAL; + } + + if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { + pr_debug("prefix is not null-terminated\n"); + return -EINVAL; + } + + return 0; +} + +static struct xt_target log_tg_regs[] __read_mostly = { + { + .name = "LOG", + .family = NFPROTO_IPV4, + .target = log_tg, + .targetsize = sizeof(struct xt_log_info), + .checkentry = log_tg_check, + .me = THIS_MODULE, + }, +#if IS_ENABLED(CONFIG_IPV6) + { + .name = "LOG", + .family = NFPROTO_IPV6, + .target = log_tg, + .targetsize = sizeof(struct xt_log_info), + .checkentry = log_tg_check, + .me = THIS_MODULE, + }, +#endif +}; + +static struct nf_logger ipt_log_logger __read_mostly = { + .name = "ipt_LOG", + .logfn = &ipt_log_packet, + .me = THIS_MODULE, +}; + +#if IS_ENABLED(CONFIG_IPV6) +static struct nf_logger ip6t_log_logger __read_mostly = { + .name = "ip6t_LOG", + .logfn = &ip6t_log_packet, + .me = THIS_MODULE, +}; +#endif + +static int __init log_tg_init(void) +{ + int ret; + + ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); + if (ret < 0) + return ret; + + nf_log_register(NFPROTO_IPV4, &ipt_log_logger); +#if IS_ENABLED(CONFIG_IPV6) + nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); +#endif + return 0; +} + +static void __exit log_tg_exit(void) +{ + nf_log_unregister(&ipt_log_logger); +#if IS_ENABLED(CONFIG_IPV6) + nf_log_unregister(&ip6t_log_logger); +#endif + xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); +} + +module_init(log_tg_init); +module_exit(log_tg_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_AUTHOR("Jan Rekorajski "); +MODULE_DESCRIPTION("Xtables: IPv4/IPv6 packet logging"); +MODULE_ALIAS("ipt_LOG"); +MODULE_ALIAS("ip6t_LOG"); -- cgit v1.2.3-70-g09d2 From 93326ae31222ddb8f4835e0461d3eb9959482ffd Mon Sep 17 00:00:00 2001 From: Tony Zelenoff Date: Wed, 22 Feb 2012 10:47:59 +0400 Subject: netfilter: nf_ct_ecache: trailing whitespace removed Signed-off-by: Tony Zelenoff Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_ecache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index 14af6329bdd..aa15977b178 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -70,7 +70,7 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct) else e->missed &= ~missed; spin_unlock_bh(&ct->lock); - } + } } out_unlock: -- cgit v1.2.3-70-g09d2 From 58020f77612747271ffa13e63cbff6ba12f49c2e Mon Sep 17 00:00:00 2001 From: Tony Zelenoff Date: Wed, 22 Feb 2012 10:48:01 +0400 Subject: netfilter: nf_ct_ecache: refactor nf_ct_deliver_cached_events * identation lowered * some CPU cycles saved at delayed item variable initialization Signed-off-by: Tony Zelenoff Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_ecache.c | 55 +++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index aa15977b178..5bd3047ddee 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -32,9 +32,11 @@ static DEFINE_MUTEX(nf_ct_ecache_mutex); void nf_ct_deliver_cached_events(struct nf_conn *ct) { struct net *net = nf_ct_net(ct); - unsigned long events; + unsigned long events, missed; struct nf_ct_event_notifier *notify; struct nf_conntrack_ecache *e; + struct nf_ct_event item; + int ret; rcu_read_lock(); notify = rcu_dereference(net->ct.nf_conntrack_event_cb); @@ -47,31 +49,32 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct) events = xchg(&e->cache, 0); - if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) { - struct nf_ct_event item = { - .ct = ct, - .pid = 0, - .report = 0 - }; - int ret; - /* We make a copy of the missed event cache without taking - * the lock, thus we may send missed events twice. However, - * this does not harm and it happens very rarely. */ - unsigned long missed = e->missed; - - if (!((events | missed) & e->ctmask)) - goto out_unlock; - - ret = notify->fcn(events | missed, &item); - if (unlikely(ret < 0 || missed)) { - spin_lock_bh(&ct->lock); - if (ret < 0) - e->missed |= events; - else - e->missed &= ~missed; - spin_unlock_bh(&ct->lock); - } - } + if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events) + goto out_unlock; + + /* We make a copy of the missed event cache without taking + * the lock, thus we may send missed events twice. However, + * this does not harm and it happens very rarely. */ + missed = e->missed; + + if (!((events | missed) & e->ctmask)) + goto out_unlock; + + item.ct = ct; + item.pid = 0; + item.report = 0; + + ret = notify->fcn(events | missed, &item); + + if (likely(ret >= 0 && !missed)) + goto out_unlock; + + spin_lock_bh(&ct->lock); + if (ret < 0) + e->missed |= events; + else + e->missed &= ~missed; + spin_unlock_bh(&ct->lock); out_unlock: rcu_read_unlock(); -- cgit v1.2.3-70-g09d2 From 417e02bf4280f001464ca55a36e9b3acad94eca4 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Thu, 1 Mar 2012 11:39:15 +0000 Subject: netfilter: xt_LOG: fix bogus extra layer-4 logging information In 16059b5 netfilter: merge ipt_LOG and ip6_LOG into xt_LOG, we have merged ipt_LOG and ip6t_LOG. However: IN=wlan0 OUT= MAC=xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx SRC=213.150.61.61 DST=192.168.1.133 LEN=40 TOS=0x00 PREC=0x00 TTL=117 ID=10539 DF PROTO=TCP SPT=80 DPT=49013 WINDOW=0 RES=0x00 ACK RST URGP=0 PROTO=UDPLITE SPT=80 DPT=49013 LEN=45843 PROTO=ICMP TYPE=0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Several missing break in the code led to including bogus layer-4 information. This patch fixes this problem. Signed-off-by: Richard Weinberger Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_LOG.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index 1595608a892..f99f8dee238 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -216,12 +216,14 @@ static void dump_ipv4_packet(struct sbuff *m, ntohs(ih->frag_off) & IP_OFFSET, iphoff+ih->ihl*4, logflags)) return; + break; case IPPROTO_UDP: case IPPROTO_UDPLITE: if (dump_udp_header(m, skb, ih->protocol, ntohs(ih->frag_off) & IP_OFFSET, iphoff+ih->ihl*4)) return; + break; case IPPROTO_ICMP: { struct icmphdr _icmph; const struct icmphdr *ich; @@ -649,10 +651,12 @@ static void dump_ipv6_packet(struct sbuff *m, if (dump_tcp_header(m, skb, currenthdr, fragment, ptr, logflags)) return; + break; case IPPROTO_UDP: case IPPROTO_UDPLITE: if (dump_udp_header(m, skb, currenthdr, fragment, ptr)) return; + break; case IPPROTO_ICMPV6: { struct icmp6hdr _icmp6h; const struct icmp6hdr *ic; -- cgit v1.2.3-70-g09d2 From 3b988ece9b42452c59da5844942661cd782b2473 Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Mon, 5 Mar 2012 02:24:29 +0000 Subject: netfilter: ctnetlink: fix lockep splats net/netfilter/nf_conntrack_proto.c:70 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 3 locks held by conntrack/3235: nfnl_lock+0x17/0x20 netlink_dump+0x32/0x240 ctnetlink_dump_table+0x3e/0x170 [nf_conntrack_netlink] stack backtrace: Pid: 3235, comm: conntrack Tainted: G W 3.2.0+ #511 Call Trace: [] lockdep_rcu_suspicious+0xe5/0x100 [] __nf_ct_l4proto_find+0x81/0xb0 [nf_conntrack] [] ctnetlink_fill_info+0x215/0x5f0 [nf_conntrack_netlink] [] ctnetlink_dump_table+0xd1/0x170 [nf_conntrack_netlink] [] netlink_dump+0x7f/0x240 [] ? trace_hardirqs_on+0xd/0x10 [] netlink_dump_start+0xdf/0x190 [] ? ctnetlink_change_nat_seq_adj+0x160/0x160 [nf_conntrack_netlink] [] ? ctnetlink_get_conntrack+0x2a0/0x2a0 [nf_conntrack_netlink] [] ctnetlink_get_conntrack+0x89/0x2a0 [nf_conntrack_netlink] [] nfnetlink_rcv_msg+0x467/0x5f0 [] ? nfnetlink_rcv_msg+0x49c/0x5f0 [] ? nfnetlink_rcv_msg+0x342/0x5f0 [] ? get_parent_ip+0x11/0x50 [] ? nfnetlink_subsys_register+0x60/0x60 [] netlink_rcv_skb+0xa9/0xd0 [] nfnetlink_rcv+0x15/0x20 [] netlink_unicast+0x1ae/0x1f0 [] netlink_sendmsg+0x2c6/0x320 [] sock_sendmsg+0x117/0x130 [] ? might_fault+0x53/0xb0 [] ? might_fault+0x9c/0xb0 [] ? might_fault+0x53/0xb0 [] ? move_addr_to_kernel+0x71/0x80 [] sys_sendto+0xfe/0x130 [] ? sys_bind+0xb4/0xd0 [] ? retint_swapgs+0xe/0x13 [] system_call_fastpath+0x16/0x1b Reported-by: Hans Schillstrom Signed-off-by: Eric Dumazet Signed-off-by: Hans Schillstrom --- net/netfilter/nf_conntrack_netlink.c | 40 +++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b8827e8a11f..c1ea64c6c70 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -110,15 +110,16 @@ ctnetlink_dump_tuples(struct sk_buff *skb, struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; + rcu_read_lock(); l3proto = __nf_ct_l3proto_find(tuple->src.l3num); ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); - if (unlikely(ret < 0)) - return ret; - - l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); - ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); - + if (ret >= 0) { + l4proto = __nf_ct_l4proto_find(tuple->src.l3num, + tuple->dst.protonum); + ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); + } + rcu_read_unlock(); return ret; } @@ -712,9 +713,11 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct hlist_nulls_node *n; struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; + int res; #ifdef CONFIG_NF_CONNTRACK_MARK const struct ctnetlink_dump_filter *filter = cb->data; #endif + spin_lock_bh(&nf_conntrack_lock); last = (struct nf_conn *)cb->args[1]; for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) { @@ -740,11 +743,14 @@ restart: continue; } #endif - if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - NFNL_MSG_TYPE( - cb->nlh->nlmsg_type), - ct) < 0) { + rcu_read_lock(); + res = + ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + NFNL_MSG_TYPE(cb->nlh->nlmsg_type), + ct); + rcu_read_unlock(); + if (res < 0) { nf_conntrack_get(&ct->ct_general); cb->args[1] = (unsigned long)ct; goto out; @@ -1649,14 +1655,16 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb, if (!nest_parms) goto nla_put_failure; + rcu_read_lock(); l3proto = __nf_ct_l3proto_find(tuple->src.l3num); ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto); - - if (unlikely(ret < 0)) - goto nla_put_failure; - - l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); + if (ret >= 0) { + l4proto = __nf_ct_l4proto_find(tuple->src.l3num, + tuple->dst.protonum); ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); + } + rcu_read_unlock(); + if (unlikely(ret < 0)) goto nla_put_failure; -- cgit v1.2.3-70-g09d2 From 5a41db94c60ac2a12b5a559de658a10d174b046d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 28 Feb 2012 02:23:28 +0100 Subject: netfilter: nf_ct_udp[lite]: convert UDP[lite] timeouts to array Use one array to store the UDP timeouts instead of two variables. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_proto_udp.c | 30 ++++++++++++++++++++---------- net/netfilter/nf_conntrack_proto_udplite.c | 25 +++++++++++++++++-------- 2 files changed, 37 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 5f35757fbff..5b24ff882f9 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -25,8 +25,16 @@ #include #include -static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; -static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; +enum udp_conntrack { + UDP_CT_UNREPLIED, + UDP_CT_REPLIED, + UDP_CT_MAX +}; + +static unsigned int udp_timeouts[UDP_CT_MAX] = { + [UDP_CT_UNREPLIED] = 30*HZ, + [UDP_CT_REPLIED] = 180*HZ, +}; static bool udp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, @@ -74,13 +82,15 @@ static int udp_packet(struct nf_conn *ct, /* If we've seen traffic both ways, this is some kind of UDP stream. Extend timeout. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream); + nf_ct_refresh_acct(ct, ctinfo, skb, + udp_timeouts[UDP_CT_REPLIED]); /* Also, more likely to be important, and not a probe */ if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) nf_conntrack_event_cache(IPCT_ASSURED, ct); - } else - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout); - + } else { + nf_ct_refresh_acct(ct, ctinfo, skb, + udp_timeouts[UDP_CT_UNREPLIED]); + } return NF_ACCEPT; } @@ -142,14 +152,14 @@ static struct ctl_table_header *udp_sysctl_header; static struct ctl_table udp_sysctl_table[] = { { .procname = "nf_conntrack_udp_timeout", - .data = &nf_ct_udp_timeout, + .data = &udp_timeouts[UDP_CT_UNREPLIED], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_udp_timeout_stream", - .data = &nf_ct_udp_timeout_stream, + .data = &udp_timeouts[UDP_CT_REPLIED], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, @@ -160,14 +170,14 @@ static struct ctl_table udp_sysctl_table[] = { static struct ctl_table udp_compat_sysctl_table[] = { { .procname = "ip_conntrack_udp_timeout", - .data = &nf_ct_udp_timeout, + .data = &udp_timeouts[UDP_CT_UNREPLIED], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_udp_timeout_stream", - .data = &nf_ct_udp_timeout_stream, + .data = &udp_timeouts[UDP_CT_REPLIED], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index f52ca118101..e73071743e0 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -24,8 +24,16 @@ #include #include -static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ; -static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ; +enum udplite_conntrack { + UDPLITE_CT_UNREPLIED, + UDPLITE_CT_REPLIED, + UDPLITE_CT_MAX +}; + +static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = { + [UDPLITE_CT_UNREPLIED] = 30*HZ, + [UDPLITE_CT_REPLIED] = 180*HZ, +}; static bool udplite_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, @@ -72,13 +80,14 @@ static int udplite_packet(struct nf_conn *ct, stream. Extend timeout. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { nf_ct_refresh_acct(ct, ctinfo, skb, - nf_ct_udplite_timeout_stream); + udplite_timeouts[UDPLITE_CT_REPLIED]); /* Also, more likely to be important, and not a probe */ if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) nf_conntrack_event_cache(IPCT_ASSURED, ct); - } else - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout); - + } else { + nf_ct_refresh_acct(ct, ctinfo, skb, + udplite_timeouts[UDPLITE_CT_UNREPLIED]); + } return NF_ACCEPT; } @@ -147,14 +156,14 @@ static struct ctl_table_header *udplite_sysctl_header; static struct ctl_table udplite_sysctl_table[] = { { .procname = "nf_conntrack_udplite_timeout", - .data = &nf_ct_udplite_timeout, + .data = &udplite_timeouts[UDPLITE_CT_UNREPLIED], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_udplite_timeout_stream", - .data = &nf_ct_udplite_timeout_stream, + .data = &udplite_timeouts[UDPLITE_CT_REPLIED], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, -- cgit v1.2.3-70-g09d2 From 33ee44643f10638f0ce6a96d11e30d1fbe877024 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 28 Feb 2012 16:56:31 +0100 Subject: netfilter: nf_ct_tcp: move retransmission and unacknowledged timeout to array This patch moves the retransmission and unacknowledged timeouts to the tcp_timeouts array. This change is required by follow-up patches. Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/nf_conntrack_tcp.h | 5 ++++- net/netfilter/nf_conntrack_proto_tcp.c | 27 +++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h index 6e135f97e59..e59868ae12d 100644 --- a/include/linux/netfilter/nf_conntrack_tcp.h +++ b/include/linux/netfilter/nf_conntrack_tcp.h @@ -18,7 +18,10 @@ enum tcp_conntrack { TCP_CONNTRACK_LISTEN, /* obsolete */ #define TCP_CONNTRACK_SYN_SENT2 TCP_CONNTRACK_LISTEN TCP_CONNTRACK_MAX, - TCP_CONNTRACK_IGNORE + TCP_CONNTRACK_IGNORE, + TCP_CONNTRACK_RETRANS, + TCP_CONNTRACK_UNACK, + TCP_CONNTRACK_TIMEOUT_MAX }; /* Window scaling is advertised by the sender */ diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 97b9f3ebf28..57c77854609 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -64,13 +64,7 @@ static const char *const tcp_conntrack_names[] = { #define HOURS * 60 MINS #define DAYS * 24 HOURS -/* RFC1122 says the R2 limit should be at least 100 seconds. - Linux uses 15 packets as limit, which corresponds - to ~13-30min depending on RTO. */ -static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; -static unsigned int nf_ct_tcp_timeout_unacknowledged __read_mostly = 5 MINS; - -static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { +static unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] __read_mostly = { [TCP_CONNTRACK_SYN_SENT] = 2 MINS, [TCP_CONNTRACK_SYN_RECV] = 60 SECS, [TCP_CONNTRACK_ESTABLISHED] = 5 DAYS, @@ -80,6 +74,11 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { [TCP_CONNTRACK_TIME_WAIT] = 2 MINS, [TCP_CONNTRACK_CLOSE] = 10 SECS, [TCP_CONNTRACK_SYN_SENT2] = 2 MINS, +/* RFC1122 says the R2 limit should be at least 100 seconds. + Linux uses 15 packets as limit, which corresponds + to ~13-30min depending on RTO. */ + [TCP_CONNTRACK_RETRANS] = 5 MINS, + [TCP_CONNTRACK_UNACK] = 5 MINS, }; #define sNO TCP_CONNTRACK_NONE @@ -1015,12 +1014,12 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && - tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans) - timeout = nf_ct_tcp_timeout_max_retrans; + tcp_timeouts[new_state] > tcp_timeouts[TCP_CONNTRACK_RETRANS]) + timeout = tcp_timeouts[TCP_CONNTRACK_RETRANS]; else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && - tcp_timeouts[new_state] > nf_ct_tcp_timeout_unacknowledged) - timeout = nf_ct_tcp_timeout_unacknowledged; + tcp_timeouts[new_state] > tcp_timeouts[TCP_CONNTRACK_UNACK]) + timeout = tcp_timeouts[TCP_CONNTRACK_UNACK]; else timeout = tcp_timeouts[new_state]; spin_unlock_bh(&ct->lock); @@ -1301,14 +1300,14 @@ static struct ctl_table tcp_sysctl_table[] = { }, { .procname = "nf_conntrack_tcp_timeout_max_retrans", - .data = &nf_ct_tcp_timeout_max_retrans, + .data = &tcp_timeouts[TCP_CONNTRACK_RETRANS], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_unacknowledged", - .data = &nf_ct_tcp_timeout_unacknowledged, + .data = &tcp_timeouts[TCP_CONNTRACK_UNACK], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, @@ -1404,7 +1403,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = { }, { .procname = "ip_conntrack_tcp_timeout_max_retrans", - .data = &nf_ct_tcp_timeout_max_retrans, + .data = &tcp_timeouts[TCP_CONNTRACK_RETRANS], .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, -- cgit v1.2.3-70-g09d2 From b888341c7f33035694f70428d7001d73f0b2a3b1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 28 Feb 2012 18:56:39 +0100 Subject: netfilter: nf_ct_gre: add unsigned int array to define timeouts This patch adds an array to define the default GRE timeouts. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_proto_gre.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index f0338791b82..8144f22d159 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -41,8 +41,16 @@ #include #include -#define GRE_TIMEOUT (30 * HZ) -#define GRE_STREAM_TIMEOUT (180 * HZ) +enum grep_conntrack { + GRE_CT_UNREPLIED, + GRE_CT_REPLIED, + GRE_CT_MAX +}; + +static unsigned int gre_timeouts[GRE_CT_MAX] = { + [GRE_CT_UNREPLIED] = 30*HZ, + [GRE_CT_REPLIED] = 180*HZ, +}; static int proto_gre_net_id __read_mostly; struct netns_proto_gre { @@ -259,8 +267,8 @@ static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, /* initialize to sane value. Ideally a conntrack helper * (e.g. in case of pptp) is increasing them */ - ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; - ct->proto.gre.timeout = GRE_TIMEOUT; + ct->proto.gre.stream_timeout = gre_timeouts[GRE_CT_REPLIED]; + ct->proto.gre.timeout = gre_timeouts[GRE_CT_UNREPLIED]; return true; } -- cgit v1.2.3-70-g09d2 From 2c8503f55fbdfbeff4164f133df804cf4d316290 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 28 Feb 2012 18:23:31 +0100 Subject: netfilter: nf_conntrack: pass timeout array to l4->new and l4->packet This patch defines a new interface for l4 protocol trackers: unsigned int *(*get_timeouts)(struct net *net); that is used to return the array of unsigned int that contains the timeouts that will be applied for this flow. This is passed to the l4proto->new(...) and l4proto->packet(...) functions to specify the timeout policy. This interface allows per-net global timeout configuration (although only DCCP supports this by now) and it will allow custom custom timeout configuration by means of follow-up patches. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 8 +++++-- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 13 +++++++++--- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 13 +++++++++--- net/netfilter/nf_conntrack_core.c | 18 ++++++++++------ net/netfilter/nf_conntrack_proto_dccp.c | 16 +++++++++----- net/netfilter/nf_conntrack_proto_generic.c | 29 ++++++++++++++++---------- net/netfilter/nf_conntrack_proto_gre.c | 15 +++++++++---- net/netfilter/nf_conntrack_proto_sctp.c | 14 ++++++++++--- net/netfilter/nf_conntrack_proto_tcp.c | 22 ++++++++++++------- net/netfilter/nf_conntrack_proto_udp.c | 16 ++++++++++---- net/netfilter/nf_conntrack_proto_udplite.c | 16 ++++++++++---- 11 files changed, 128 insertions(+), 52 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index e3d3ee3c06a..c48b67405aa 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -39,12 +39,13 @@ struct nf_conntrack_l4proto { unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum); + unsigned int hooknum, + unsigned int *timeouts); /* Called when a new connection for this protocol found; * returns TRUE if it's OK. If so, packet() called next. */ bool (*new)(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff); + unsigned int dataoff, unsigned int *timeouts); /* Called when a conntrack entry is destroyed */ void (*destroy)(struct nf_conn *ct); @@ -60,6 +61,9 @@ struct nf_conntrack_l4proto { /* Print out the private part of the conntrack. */ int (*print_conntrack)(struct seq_file *s, struct nf_conn *); + /* Return the array of timeouts for this protocol. */ + unsigned int *(*get_timeouts)(struct net *net); + /* convert protoinfo to nfnetink attributes */ int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, struct nf_conn *ct); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index ab5b27a2916..6b801124b31 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -75,25 +75,31 @@ static int icmp_print_tuple(struct seq_file *s, ntohs(tuple->src.u.icmp.id)); } +static unsigned int *icmp_get_timeouts(struct net *net) +{ + return &nf_ct_icmp_timeout; +} + /* Returns verdict for packet, or -1 for invalid. */ static int icmp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum) + unsigned int hooknum, + unsigned int *timeout) { /* Do not immediately delete the connection after the first successful reply to avoid excessive conntrackd traffic and also to handle correctly ICMP echo reply duplicates. */ - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); + nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); return NF_ACCEPT; } /* Called when a new connection for this protocol found. */ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { static const u_int8_t valid_new[] = { [ICMP_ECHO] = 1, @@ -298,6 +304,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = .invert_tuple = icmp_invert_tuple, .print_tuple = icmp_print_tuple, .packet = icmp_packet, + .get_timeouts = icmp_get_timeouts, .new = icmp_new, .error = icmp_error, .destroy = NULL, diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 7c05e7eacbc..2eb9751eb7a 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -88,25 +88,31 @@ static int icmpv6_print_tuple(struct seq_file *s, ntohs(tuple->src.u.icmp.id)); } +static unsigned int *icmpv6_get_timeouts(struct net *net) +{ + return &nf_ct_icmpv6_timeout; +} + /* Returns verdict for packet, or -1 for invalid. */ static int icmpv6_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum) + unsigned int hooknum, + unsigned int *timeout) { /* Do not immediately delete the connection after the first successful reply to avoid excessive conntrackd traffic and also to handle correctly ICMP echo reply duplicates. */ - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); + nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); return NF_ACCEPT; } /* Called when a new connection for this protocol found. */ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { static const u_int8_t valid_new[] = { [ICMPV6_ECHO_REQUEST - 128] = 1, @@ -293,6 +299,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = .invert_tuple = icmpv6_invert_tuple, .print_tuple = icmpv6_print_tuple, .packet = icmpv6_packet, + .get_timeouts = icmpv6_get_timeouts, .new = icmpv6_new, .error = icmpv6_error, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index ed86a3be678..d18995eea1c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -763,7 +763,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, struct sk_buff *skb, - unsigned int dataoff, u32 hash) + unsigned int dataoff, u32 hash, + unsigned int *timeouts) { struct nf_conn *ct; struct nf_conn_help *help; @@ -782,7 +783,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, if (IS_ERR(ct)) return (struct nf_conntrack_tuple_hash *)ct; - if (!l4proto->new(ct, skb, dataoff)) { + if (!l4proto->new(ct, skb, dataoff, timeouts)) { nf_conntrack_free(ct); pr_debug("init conntrack: can't track with proto module\n"); return NULL; @@ -848,7 +849,8 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, int *set_reply, - enum ip_conntrack_info *ctinfo) + enum ip_conntrack_info *ctinfo, + unsigned int *timeouts) { struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple_hash *h; @@ -868,7 +870,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, h = __nf_conntrack_find_get(net, zone, &tuple, hash); if (!h) { h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, - skb, dataoff, hash); + skb, dataoff, hash, timeouts); if (!h) return NULL; if (IS_ERR(h)) @@ -909,6 +911,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, enum ip_conntrack_info ctinfo; struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; + unsigned int *timeouts; unsigned int dataoff; u_int8_t protonum; int set_reply = 0; @@ -955,8 +958,11 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, goto out; } + timeouts = l4proto->get_timeouts(net); + ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, - l3proto, l4proto, &set_reply, &ctinfo); + l3proto, l4proto, &set_reply, &ctinfo, + timeouts); if (!ct) { /* Not valid part of a connection */ NF_CT_STAT_INC_ATOMIC(net, invalid); @@ -973,7 +979,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, NF_CT_ASSERT(skb->nfct); - ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum); + ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts); if (ret <= 0) { /* Invalid: inverse of the return code tells * the netfilter core what to do */ diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index d6dde6dc09e..8ea33598a0a 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -423,7 +423,7 @@ static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv, } static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { struct net *net = nf_ct_net(ct); struct dccp_net *dn; @@ -472,12 +472,17 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh) ntohl(dhack->dccph_ack_nr_low); } +static unsigned int *dccp_get_timeouts(struct net *net) +{ + return dccp_pernet(net)->dccp_timeout; +} + static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, - u_int8_t pf, unsigned int hooknum) + u_int8_t pf, unsigned int hooknum, + unsigned int *timeouts) { struct net *net = nf_ct_net(ct); - struct dccp_net *dn; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); struct dccp_hdr _dh, *dh; u_int8_t type, old_state, new_state; @@ -559,8 +564,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, if (new_state != old_state) nf_conntrack_event_cache(IPCT_PROTOINFO, ct); - dn = dccp_pernet(net); - nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]); + nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); return NF_ACCEPT; } @@ -767,6 +771,7 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { .invert_tuple = dccp_invert_tuple, .new = dccp_new, .packet = dccp_packet, + .get_timeouts = dccp_get_timeouts, .error = dccp_error, .print_tuple = dccp_print_tuple, .print_conntrack = dccp_print_conntrack, @@ -789,6 +794,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { .invert_tuple = dccp_invert_tuple, .new = dccp_new, .packet = dccp_packet, + .get_timeouts = dccp_get_timeouts, .error = dccp_error, .print_tuple = dccp_print_tuple, .print_conntrack = dccp_print_conntrack, diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index e2091d0c7a2..0e6c5451db8 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -40,21 +40,27 @@ static int generic_print_tuple(struct seq_file *s, return 0; } +static unsigned int *generic_get_timeouts(struct net *net) +{ + return &nf_ct_generic_timeout; +} + /* Returns verdict for packet, or -1 for invalid. */ -static int packet(struct nf_conn *ct, - const struct sk_buff *skb, - unsigned int dataoff, - enum ip_conntrack_info ctinfo, - u_int8_t pf, - unsigned int hooknum) +static int generic_packet(struct nf_conn *ct, + const struct sk_buff *skb, + unsigned int dataoff, + enum ip_conntrack_info ctinfo, + u_int8_t pf, + unsigned int hooknum, + unsigned int *timeout) { - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout); + nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); return NF_ACCEPT; } /* Called when a new connection for this protocol found. */ -static bool new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff, unsigned int *timeouts) { return true; } @@ -93,8 +99,9 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = .pkt_to_tuple = generic_pkt_to_tuple, .invert_tuple = generic_invert_tuple, .print_tuple = generic_print_tuple, - .packet = packet, - .new = new, + .packet = generic_packet, + .get_timeouts = generic_get_timeouts, + .new = generic_new, #ifdef CONFIG_SYSCTL .ctl_table_header = &generic_sysctl_header, .ctl_table = generic_sysctl_table, diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 8144f22d159..1bf01c95658 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -235,13 +235,19 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) (ct->proto.gre.stream_timeout / HZ)); } +static unsigned int *gre_get_timeouts(struct net *net) +{ + return gre_timeouts; +} + /* Returns verdict for packet, and may modify conntrack */ static int gre_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum) + unsigned int hooknum, + unsigned int *timeouts) { /* If we've seen traffic both ways, this is a GRE connection. * Extend timeout. */ @@ -260,15 +266,15 @@ static int gre_packet(struct nf_conn *ct, /* Called when a new connection for this protocol found. */ static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { pr_debug(": "); nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); /* initialize to sane value. Ideally a conntrack helper * (e.g. in case of pptp) is increasing them */ - ct->proto.gre.stream_timeout = gre_timeouts[GRE_CT_REPLIED]; - ct->proto.gre.timeout = gre_timeouts[GRE_CT_UNREPLIED]; + ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED]; + ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED]; return true; } @@ -295,6 +301,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { .invert_tuple = gre_invert_tuple, .print_tuple = gre_print_tuple, .print_conntrack = gre_print_conntrack, + .get_timeouts = gre_get_timeouts, .packet = gre_packet, .new = gre_new, .destroy = gre_destroy, diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index afa69136061..2a0703371e2 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -279,13 +279,19 @@ static int sctp_new_state(enum ip_conntrack_dir dir, return sctp_conntracks[dir][i][cur_state]; } +static unsigned int *sctp_get_timeouts(struct net *net) +{ + return sctp_timeouts; +} + /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ static int sctp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum) + unsigned int hooknum, + unsigned int *timeouts) { enum sctp_conntrack new_state, old_state; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); @@ -370,7 +376,7 @@ static int sctp_packet(struct nf_conn *ct, } spin_unlock_bh(&ct->lock); - nf_ct_refresh_acct(ct, ctinfo, skb, sctp_timeouts[new_state]); + nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && dir == IP_CT_DIR_REPLY && @@ -390,7 +396,7 @@ out: /* Called when a new connection for this protocol found. */ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { enum sctp_conntrack new_state; const struct sctphdr *sh; @@ -664,6 +670,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { .print_tuple = sctp_print_tuple, .print_conntrack = sctp_print_conntrack, .packet = sctp_packet, + .get_timeouts = sctp_get_timeouts, .new = sctp_new, .me = THIS_MODULE, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) @@ -694,6 +701,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { .print_tuple = sctp_print_tuple, .print_conntrack = sctp_print_conntrack, .packet = sctp_packet, + .get_timeouts = sctp_get_timeouts, .new = sctp_new, .me = THIS_MODULE, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 57c77854609..8372bb43feb 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -813,13 +813,19 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl, return NF_ACCEPT; } +static unsigned int *tcp_get_timeouts(struct net *net) +{ + return tcp_timeouts; +} + /* Returns verdict for packet, or -1 for invalid. */ static int tcp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum) + unsigned int hooknum, + unsigned int *timeouts) { struct net *net = nf_ct_net(ct); struct nf_conntrack_tuple *tuple; @@ -1014,14 +1020,14 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && - tcp_timeouts[new_state] > tcp_timeouts[TCP_CONNTRACK_RETRANS]) - timeout = tcp_timeouts[TCP_CONNTRACK_RETRANS]; + timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) + timeout = timeouts[TCP_CONNTRACK_RETRANS]; else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && - tcp_timeouts[new_state] > tcp_timeouts[TCP_CONNTRACK_UNACK]) - timeout = tcp_timeouts[TCP_CONNTRACK_UNACK]; + timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK]) + timeout = timeouts[TCP_CONNTRACK_UNACK]; else - timeout = tcp_timeouts[new_state]; + timeout = timeouts[new_state]; spin_unlock_bh(&ct->lock); if (new_state != old_state) @@ -1053,7 +1059,7 @@ static int tcp_packet(struct nf_conn *ct, /* Called when a new connection for this protocol found. */ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { enum tcp_conntrack new_state; const struct tcphdr *th; @@ -1444,6 +1450,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = .print_tuple = tcp_print_tuple, .print_conntrack = tcp_print_conntrack, .packet = tcp_packet, + .get_timeouts = tcp_get_timeouts, .new = tcp_new, .error = tcp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) @@ -1476,6 +1483,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = .print_tuple = tcp_print_tuple, .print_conntrack = tcp_print_conntrack, .packet = tcp_packet, + .get_timeouts = tcp_get_timeouts, .new = tcp_new, .error = tcp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 5b24ff882f9..70e005992d5 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -71,32 +71,38 @@ static int udp_print_tuple(struct seq_file *s, ntohs(tuple->dst.u.udp.port)); } +static unsigned int *udp_get_timeouts(struct net *net) +{ + return udp_timeouts; +} + /* Returns verdict for packet, and may modify conntracktype */ static int udp_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum) + unsigned int hooknum, + unsigned int *timeouts) { /* If we've seen traffic both ways, this is some kind of UDP stream. Extend timeout. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { nf_ct_refresh_acct(ct, ctinfo, skb, - udp_timeouts[UDP_CT_REPLIED]); + timeouts[UDP_CT_REPLIED]); /* Also, more likely to be important, and not a probe */ if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) nf_conntrack_event_cache(IPCT_ASSURED, ct); } else { nf_ct_refresh_acct(ct, ctinfo, skb, - udp_timeouts[UDP_CT_UNREPLIED]); + timeouts[UDP_CT_UNREPLIED]); } return NF_ACCEPT; } /* Called when a new connection for this protocol found. */ static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { return true; } @@ -196,6 +202,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = .invert_tuple = udp_invert_tuple, .print_tuple = udp_print_tuple, .packet = udp_packet, + .get_timeouts = udp_get_timeouts, .new = udp_new, .error = udp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) @@ -224,6 +231,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = .invert_tuple = udp_invert_tuple, .print_tuple = udp_print_tuple, .packet = udp_packet, + .get_timeouts = udp_get_timeouts, .new = udp_new, .error = udp_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index e73071743e0..0b32ccb1d51 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -68,32 +68,38 @@ static int udplite_print_tuple(struct seq_file *s, ntohs(tuple->dst.u.udp.port)); } +static unsigned int *udplite_get_timeouts(struct net *net) +{ + return udplite_timeouts; +} + /* Returns verdict for packet, and may modify conntracktype */ static int udplite_packet(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, u_int8_t pf, - unsigned int hooknum) + unsigned int hooknum, + unsigned int *timeouts) { /* If we've seen traffic both ways, this is some kind of UDP stream. Extend timeout. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { nf_ct_refresh_acct(ct, ctinfo, skb, - udplite_timeouts[UDPLITE_CT_REPLIED]); + timeouts[UDPLITE_CT_REPLIED]); /* Also, more likely to be important, and not a probe */ if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) nf_conntrack_event_cache(IPCT_ASSURED, ct); } else { nf_ct_refresh_acct(ct, ctinfo, skb, - udplite_timeouts[UDPLITE_CT_UNREPLIED]); + timeouts[UDPLITE_CT_UNREPLIED]); } return NF_ACCEPT; } /* Called when a new connection for this protocol found. */ static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) + unsigned int dataoff, unsigned int *timeouts) { return true; } @@ -181,6 +187,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = .invert_tuple = udplite_invert_tuple, .print_tuple = udplite_print_tuple, .packet = udplite_packet, + .get_timeouts = udplite_get_timeouts, .new = udplite_new, .error = udplite_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) @@ -205,6 +212,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = .invert_tuple = udplite_invert_tuple, .print_tuple = udplite_print_tuple, .packet = udplite_packet, + .get_timeouts = udplite_get_timeouts, .new = udplite_new, .error = udplite_error, #if IS_ENABLED(CONFIG_NF_CT_NETLINK) -- cgit v1.2.3-70-g09d2 From 50978462300f74dc48aea4a38471cb69bdf741a5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 28 Feb 2012 19:13:48 +0100 Subject: netfilter: add cttimeout infrastructure for fine timeout tuning This patch adds the infrastructure to add fine timeout tuning over nfnetlink. Now you can use the NFNL_SUBSYS_CTNETLINK_TIMEOUT subsystem to create/delete/dump timeout objects that contain some specific timeout policy for one flow. The follow up patches will allow you attach timeout policy object to conntrack via the CT target and the conntrack extension infrastructure. Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/nfnetlink.h | 3 +- include/linux/netfilter/nfnetlink_cttimeout.h | 114 +++++++ include/net/netfilter/nf_conntrack_l4proto.h | 11 + net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 47 +++ net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 47 +++ net/netfilter/Kconfig | 11 + net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_proto_dccp.c | 70 +++++ net/netfilter/nf_conntrack_proto_generic.c | 48 +++ net/netfilter/nf_conntrack_proto_gre.c | 55 ++++ net/netfilter/nf_conntrack_proto_sctp.c | 69 +++++ net/netfilter/nf_conntrack_proto_tcp.c | 127 ++++++++ net/netfilter/nf_conntrack_proto_udp.c | 64 ++++ net/netfilter/nf_conntrack_proto_udplite.c | 66 ++++ net/netfilter/nfnetlink_cttimeout.c | 398 +++++++++++++++++++++++++ 16 files changed, 1131 insertions(+), 1 deletion(-) create mode 100644 include/linux/netfilter/nfnetlink_cttimeout.h create mode 100644 net/netfilter/nfnetlink_cttimeout.c (limited to 'net') diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index aaa72aaa21d..1697036336b 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -10,6 +10,7 @@ header-y += nfnetlink.h header-y += nfnetlink_acct.h header-y += nfnetlink_compat.h header-y += nfnetlink_conntrack.h +header-y += nfnetlink_cttimeout.h header-y += nfnetlink_log.h header-y += nfnetlink_queue.h header-y += x_tables.h diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index b64454c2f79..6fd1f0d07e6 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -49,7 +49,8 @@ struct nfgenmsg { #define NFNL_SUBSYS_OSF 5 #define NFNL_SUBSYS_IPSET 6 #define NFNL_SUBSYS_ACCT 7 -#define NFNL_SUBSYS_COUNT 8 +#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 +#define NFNL_SUBSYS_COUNT 9 #ifdef __KERNEL__ diff --git a/include/linux/netfilter/nfnetlink_cttimeout.h b/include/linux/netfilter/nfnetlink_cttimeout.h new file mode 100644 index 00000000000..a2810a7c5e3 --- /dev/null +++ b/include/linux/netfilter/nfnetlink_cttimeout.h @@ -0,0 +1,114 @@ +#ifndef _CTTIMEOUT_NETLINK_H +#define _CTTIMEOUT_NETLINK_H +#include + +enum ctnl_timeout_msg_types { + IPCTNL_MSG_TIMEOUT_NEW, + IPCTNL_MSG_TIMEOUT_GET, + IPCTNL_MSG_TIMEOUT_DELETE, + + IPCTNL_MSG_TIMEOUT_MAX +}; + +enum ctattr_timeout { + CTA_TIMEOUT_UNSPEC, + CTA_TIMEOUT_NAME, + CTA_TIMEOUT_L3PROTO, + CTA_TIMEOUT_L4PROTO, + CTA_TIMEOUT_DATA, + CTA_TIMEOUT_USE, + __CTA_TIMEOUT_MAX +}; +#define CTA_TIMEOUT_MAX (__CTA_TIMEOUT_MAX - 1) + +enum ctattr_timeout_generic { + CTA_TIMEOUT_GENERIC_UNSPEC, + CTA_TIMEOUT_GENERIC_TIMEOUT, + __CTA_TIMEOUT_GENERIC_MAX +}; +#define CTA_TIMEOUT_GENERIC_MAX (__CTA_TIMEOUT_GENERIC_MAX - 1) + +enum ctattr_timeout_tcp { + CTA_TIMEOUT_TCP_UNSPEC, + CTA_TIMEOUT_TCP_SYN_SENT, + CTA_TIMEOUT_TCP_SYN_RECV, + CTA_TIMEOUT_TCP_ESTABLISHED, + CTA_TIMEOUT_TCP_FIN_WAIT, + CTA_TIMEOUT_TCP_CLOSE_WAIT, + CTA_TIMEOUT_TCP_LAST_ACK, + CTA_TIMEOUT_TCP_TIME_WAIT, + CTA_TIMEOUT_TCP_CLOSE, + CTA_TIMEOUT_TCP_SYN_SENT2, + CTA_TIMEOUT_TCP_RETRANS, + CTA_TIMEOUT_TCP_UNACK, + __CTA_TIMEOUT_TCP_MAX +}; +#define CTA_TIMEOUT_TCP_MAX (__CTA_TIMEOUT_TCP_MAX - 1) + +enum ctattr_timeout_udp { + CTA_TIMEOUT_UDP_UNSPEC, + CTA_TIMEOUT_UDP_UNREPLIED, + CTA_TIMEOUT_UDP_REPLIED, + __CTA_TIMEOUT_UDP_MAX +}; +#define CTA_TIMEOUT_UDP_MAX (__CTA_TIMEOUT_UDP_MAX - 1) + +enum ctattr_timeout_udplite { + CTA_TIMEOUT_UDPLITE_UNSPEC, + CTA_TIMEOUT_UDPLITE_UNREPLIED, + CTA_TIMEOUT_UDPLITE_REPLIED, + __CTA_TIMEOUT_UDPLITE_MAX +}; +#define CTA_TIMEOUT_UDPLITE_MAX (__CTA_TIMEOUT_UDPLITE_MAX - 1) + +enum ctattr_timeout_icmp { + CTA_TIMEOUT_ICMP_UNSPEC, + CTA_TIMEOUT_ICMP_TIMEOUT, + __CTA_TIMEOUT_ICMP_MAX +}; +#define CTA_TIMEOUT_ICMP_MAX (__CTA_TIMEOUT_ICMP_MAX - 1) + +enum ctattr_timeout_dccp { + CTA_TIMEOUT_DCCP_UNSPEC, + CTA_TIMEOUT_DCCP_REQUEST, + CTA_TIMEOUT_DCCP_RESPOND, + CTA_TIMEOUT_DCCP_PARTOPEN, + CTA_TIMEOUT_DCCP_OPEN, + CTA_TIMEOUT_DCCP_CLOSEREQ, + CTA_TIMEOUT_DCCP_CLOSING, + CTA_TIMEOUT_DCCP_TIMEWAIT, + __CTA_TIMEOUT_DCCP_MAX +}; +#define CTA_TIMEOUT_DCCP_MAX (__CTA_TIMEOUT_DCCP_MAX - 1) + +enum ctattr_timeout_sctp { + CTA_TIMEOUT_SCTP_UNSPEC, + CTA_TIMEOUT_SCTP_CLOSED, + CTA_TIMEOUT_SCTP_COOKIE_WAIT, + CTA_TIMEOUT_SCTP_COOKIE_ECHOED, + CTA_TIMEOUT_SCTP_ESTABLISHED, + CTA_TIMEOUT_SCTP_SHUTDOWN_SENT, + CTA_TIMEOUT_SCTP_SHUTDOWN_RECD, + CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT, + __CTA_TIMEOUT_SCTP_MAX +}; +#define CTA_TIMEOUT_SCTP_MAX (__CTA_TIMEOUT_SCTP_MAX - 1) + +enum ctattr_timeout_icmpv6 { + CTA_TIMEOUT_ICMPV6_UNSPEC, + CTA_TIMEOUT_ICMPV6_TIMEOUT, + __CTA_TIMEOUT_ICMPV6_MAX +}; +#define CTA_TIMEOUT_ICMPV6_MAX (__CTA_TIMEOUT_ICMPV6_MAX - 1) + +enum ctattr_timeout_gre { + CTA_TIMEOUT_GRE_UNSPEC, + CTA_TIMEOUT_GRE_UNREPLIED, + CTA_TIMEOUT_GRE_REPLIED, + __CTA_TIMEOUT_GRE_MAX +}; +#define CTA_TIMEOUT_GRE_MAX (__CTA_TIMEOUT_GRE_MAX - 1) + +#define CTNL_TIMEOUT_NAME_MAX 32 + +#endif diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index c48b67405aa..90c67c7db7e 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -83,6 +83,17 @@ struct nf_conntrack_l4proto { size_t nla_size; +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + struct { + size_t obj_size; + int (*nlattr_to_obj)(struct nlattr *tb[], void *data); + int (*obj_to_nlattr)(struct sk_buff *skb, const void *data); + + unsigned int nlattr_max; + const struct nla_policy *nla_policy; + } ctnl_timeout; +#endif + #ifdef CONFIG_SYSCTL struct ctl_table_header **ctl_table_header; struct ctl_table *ctl_table; diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 6b801124b31..7cbe9cb261c 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -269,6 +269,44 @@ static int icmp_nlattr_tuple_size(void) } #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + +#include +#include + +static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeout = data; + + if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) { + *timeout = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ; + } else { + /* Set default ICMP timeout. */ + *timeout = nf_ct_icmp_timeout; + } + return 0; +} + +static int +icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) +{ + const unsigned int *timeout = data; + + NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ)); + + return 0; + +nla_put_failure: + return -ENOSPC; +} + +static const struct nla_policy +icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = { + [CTA_TIMEOUT_ICMP_TIMEOUT] = { .type = NLA_U32 }, +}; +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ + #ifdef CONFIG_SYSCTL static struct ctl_table_header *icmp_sysctl_header; static struct ctl_table icmp_sysctl_table[] = { @@ -315,6 +353,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = .nlattr_to_tuple = icmp_nlattr_to_tuple, .nla_policy = icmp_nla_policy, #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = icmp_timeout_nlattr_to_obj, + .obj_to_nlattr = icmp_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_ICMP_MAX, + .obj_size = sizeof(unsigned int), + .nla_policy = icmp_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #ifdef CONFIG_SYSCTL .ctl_table_header = &icmp_sysctl_header, .ctl_table = icmp_sysctl_table, diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 2eb9751eb7a..92cc9f2931a 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -276,6 +276,44 @@ static int icmpv6_nlattr_tuple_size(void) } #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + +#include +#include + +static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeout = data; + + if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) { + *timeout = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ; + } else { + /* Set default ICMPv6 timeout. */ + *timeout = nf_ct_icmpv6_timeout; + } + return 0; +} + +static int +icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) +{ + const unsigned int *timeout = data; + + NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ)); + + return 0; + +nla_put_failure: + return -ENOSPC; +} + +static const struct nla_policy +icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = { + [CTA_TIMEOUT_ICMPV6_TIMEOUT] = { .type = NLA_U32 }, +}; +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ + #ifdef CONFIG_SYSCTL static struct ctl_table_header *icmpv6_sysctl_header; static struct ctl_table icmpv6_sysctl_table[] = { @@ -308,6 +346,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = .nlattr_to_tuple = icmpv6_nlattr_to_tuple, .nla_policy = icmpv6_nla_policy, #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = icmpv6_timeout_nlattr_to_obj, + .obj_to_nlattr = icmpv6_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_ICMP_MAX, + .obj_size = sizeof(unsigned int), + .nla_policy = icmpv6_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #ifdef CONFIG_SYSCTL .ctl_table_header = &icmpv6_sysctl_header, .ctl_table = icmpv6_sysctl_table, diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index b895d8b1321..f3efb6570dd 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -314,6 +314,17 @@ config NF_CT_NETLINK help This option enables support for a netlink-based userspace interface +config NF_CT_NETLINK_TIMEOUT + tristate 'Connection tracking timeout tuning via Netlink' + select NETFILTER_NETLINK + depends on NETFILTER_ADVANCED + help + This option enables support for connection tracking timeout + fine-grain tuning. This allows you to attach specific timeout + policies to flows, instead of using the global timeout policy. + + If unsure, say `N'. + endif # NF_CONNTRACK # transparent proxy support diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index a28c2a6563f..cf7cdd630bd 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o # netlink interface for nf_conntrack obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o +obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o # connection tracking helpers nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 8ea33598a0a..24fdce256cb 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -706,8 +706,60 @@ static int dccp_nlattr_size(void) return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); } + #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + +#include +#include + +static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + struct dccp_net *dn = dccp_pernet(&init_net); + unsigned int *timeouts = data; + int i; + + /* set default DCCP timeouts. */ + for (i=0; idccp_timeout[i]; + + /* there's a 1:1 mapping between attributes and protocol states. */ + for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i +#include + +static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeout = data; + + if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT]) + *timeout = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ; + else { + /* Set default generic timeout. */ + *timeout = nf_ct_generic_timeout; + } + + return 0; +} + +static int +generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) +{ + const unsigned int *timeout = data; + + NLA_PUT_BE32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ)); + + return 0; + +nla_put_failure: + return -ENOSPC; +} + +static const struct nla_policy +generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = { + [CTA_TIMEOUT_GENERIC_TIMEOUT] = { .type = NLA_U32 }, +}; +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ + #ifdef CONFIG_SYSCTL static struct ctl_table_header *generic_sysctl_header; static struct ctl_table generic_sysctl_table[] = { @@ -102,6 +141,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = .packet = generic_packet, .get_timeouts = generic_get_timeouts, .new = generic_new, +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = generic_timeout_nlattr_to_obj, + .obj_to_nlattr = generic_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_GENERIC_MAX, + .obj_size = sizeof(unsigned int), + .nla_policy = generic_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #ifdef CONFIG_SYSCTL .ctl_table_header = &generic_sysctl_header, .ctl_table = generic_sysctl_table, diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 1bf01c95658..659648c4b14 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -292,6 +292,52 @@ static void gre_destroy(struct nf_conn *ct) nf_ct_gre_keymap_destroy(master); } +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + +#include +#include + +static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeouts = data; + + /* set default timeouts for GRE. */ + timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED]; + timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED]; + + if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) { + timeouts[GRE_CT_UNREPLIED] = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_UNREPLIED])) * HZ; + } + if (tb[CTA_TIMEOUT_GRE_REPLIED]) { + timeouts[GRE_CT_REPLIED] = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_REPLIED])) * HZ; + } + return 0; +} + +static int +gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) +{ + const unsigned int *timeouts = data; + + NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_UNREPLIED, + htonl(timeouts[GRE_CT_UNREPLIED] / HZ)); + NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_REPLIED, + htonl(timeouts[GRE_CT_REPLIED] / HZ)); + return 0; + +nla_put_failure: + return -ENOSPC; +} + +static const struct nla_policy +gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = { + [CTA_TIMEOUT_GRE_UNREPLIED] = { .type = NLA_U32 }, + [CTA_TIMEOUT_GRE_REPLIED] = { .type = NLA_U32 }, +}; +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ + /* protocol helper struct */ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { .l3proto = AF_INET, @@ -312,6 +358,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nla_policy = nf_ct_port_nla_policy, #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = gre_timeout_nlattr_to_obj, + .obj_to_nlattr = gre_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_GRE_MAX, + .obj_size = sizeof(unsigned int) * GRE_CT_MAX, + .nla_policy = gre_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ }; static int proto_gre_net_init(struct net *net) diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 2a0703371e2..72b5088592d 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -549,6 +549,57 @@ static int sctp_nlattr_size(void) } #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + +#include +#include + +static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeouts = data; + int i; + + /* set default SCTP timeouts. */ + for (i=0; i +#include + +static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeouts = data; + int i; + + /* set default TCP timeouts. */ + for (i=0; i +#include + +static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeouts = data; + + /* set default timeouts for UDP. */ + timeouts[UDP_CT_UNREPLIED] = udp_timeouts[UDP_CT_UNREPLIED]; + timeouts[UDP_CT_REPLIED] = udp_timeouts[UDP_CT_REPLIED]; + + if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) { + timeouts[UDP_CT_UNREPLIED] = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ; + } + if (tb[CTA_TIMEOUT_UDP_REPLIED]) { + timeouts[UDP_CT_REPLIED] = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ; + } + return 0; +} + +static int +udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) +{ + const unsigned int *timeouts = data; + + NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_UNREPLIED, + htonl(timeouts[UDP_CT_UNREPLIED] / HZ)); + NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_REPLIED, + htonl(timeouts[UDP_CT_REPLIED] / HZ)); + return 0; + +nla_put_failure: + return -ENOSPC; +} + +static const struct nla_policy +udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = { + [CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 }, + [CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 }, +}; +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ + #ifdef CONFIG_SYSCTL static unsigned int udp_sysctl_table_users; static struct ctl_table_header *udp_sysctl_header; @@ -211,6 +257,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nla_policy = nf_ct_port_nla_policy, #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = udp_timeout_nlattr_to_obj, + .obj_to_nlattr = udp_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_UDP_MAX, + .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, + .nla_policy = udp_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #ifdef CONFIG_SYSCTL .ctl_table_users = &udp_sysctl_table_users, .ctl_table_header = &udp_sysctl_header, @@ -240,6 +295,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nla_policy = nf_ct_port_nla_policy, #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = udp_timeout_nlattr_to_obj, + .obj_to_nlattr = udp_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_UDP_MAX, + .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, + .nla_policy = udp_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #ifdef CONFIG_SYSCTL .ctl_table_users = &udp_sysctl_table_users, .ctl_table_header = &udp_sysctl_header, diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 0b32ccb1d51..e0606392cda 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -156,6 +156,52 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl, return NF_ACCEPT; } +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + +#include +#include + +static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) +{ + unsigned int *timeouts = data; + + /* set default timeouts for UDPlite. */ + timeouts[UDPLITE_CT_UNREPLIED] = udplite_timeouts[UDPLITE_CT_UNREPLIED]; + timeouts[UDPLITE_CT_REPLIED] = udplite_timeouts[UDPLITE_CT_REPLIED]; + + if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) { + timeouts[UDPLITE_CT_UNREPLIED] = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_UNREPLIED])) * HZ; + } + if (tb[CTA_TIMEOUT_UDPLITE_REPLIED]) { + timeouts[UDPLITE_CT_REPLIED] = + ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_REPLIED])) * HZ; + } + return 0; +} + +static int +udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) +{ + const unsigned int *timeouts = data; + + NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED, + htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ)); + NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_REPLIED, + htonl(timeouts[UDPLITE_CT_REPLIED] / HZ)); + return 0; + +nla_put_failure: + return -ENOSPC; +} + +static const struct nla_policy +udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = { + [CTA_TIMEOUT_UDPLITE_UNREPLIED] = { .type = NLA_U32 }, + [CTA_TIMEOUT_UDPLITE_REPLIED] = { .type = NLA_U32 }, +}; +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ + #ifdef CONFIG_SYSCTL static unsigned int udplite_sysctl_table_users; static struct ctl_table_header *udplite_sysctl_header; @@ -196,6 +242,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nla_policy = nf_ct_port_nla_policy, #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = udplite_timeout_nlattr_to_obj, + .obj_to_nlattr = udplite_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX, + .obj_size = sizeof(unsigned int) * + CTA_TIMEOUT_UDPLITE_MAX, + .nla_policy = udplite_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #ifdef CONFIG_SYSCTL .ctl_table_users = &udplite_sysctl_table_users, .ctl_table_header = &udplite_sysctl_header, @@ -221,6 +277,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nla_policy = nf_ct_port_nla_policy, #endif +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + .ctnl_timeout = { + .nlattr_to_obj = udplite_timeout_nlattr_to_obj, + .obj_to_nlattr = udplite_timeout_obj_to_nlattr, + .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX, + .obj_size = sizeof(unsigned int) * + CTA_TIMEOUT_UDPLITE_MAX, + .nla_policy = udplite_timeout_nla_policy, + }, +#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #ifdef CONFIG_SYSCTL .ctl_table_users = &udplite_sysctl_table_users, .ctl_table_header = &udplite_sysctl_header, diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c new file mode 100644 index 00000000000..b860d521718 --- /dev/null +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -0,0 +1,398 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * (C) 2012 by Vyatta Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation (or any later at your option). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pablo Neira Ayuso "); +MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning"); + +struct ctnl_timeout { + struct list_head head; + struct rcu_head rcu_head; + atomic_t refcnt; + char name[CTNL_TIMEOUT_NAME_MAX]; + __u16 l3num; + __u8 l4num; + char data[0]; +}; + +static LIST_HEAD(cttimeout_list); + +static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { + [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING }, + [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, + [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, + [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, +}; + +static int +ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, + struct nf_conntrack_l4proto *l4proto, + const struct nlattr *attr) +{ + int ret = 0; + + if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) { + struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1]; + + nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, + attr, l4proto->ctnl_timeout.nla_policy); + + ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, &timeout->data); + } + return ret; +} + +static int +cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) +{ + __u16 l3num; + __u8 l4num; + struct nf_conntrack_l4proto *l4proto; + struct ctnl_timeout *timeout, *matching = NULL; + char *name; + int ret; + + if (!cda[CTA_TIMEOUT_NAME] || + !cda[CTA_TIMEOUT_L3PROTO] || + !cda[CTA_TIMEOUT_L4PROTO] || + !cda[CTA_TIMEOUT_DATA]) + return -EINVAL; + + name = nla_data(cda[CTA_TIMEOUT_NAME]); + l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); + l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); + + list_for_each_entry(timeout, &cttimeout_list, head) { + if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) + continue; + + if (nlh->nlmsg_flags & NLM_F_EXCL) + return -EEXIST; + + matching = timeout; + break; + } + + l4proto = __nf_ct_l4proto_find(l3num, l4num); + + /* This protocol is not supportted, skip. */ + if (l4proto->l4proto != l4num) + return -EOPNOTSUPP; + + if (matching) { + if (nlh->nlmsg_flags & NLM_F_REPLACE) { + /* You cannot replace one timeout policy by another of + * different kind, sorry. + */ + if (matching->l3num != l3num || + matching->l4num != l4num) + return -EINVAL; + + ret = ctnl_timeout_parse_policy(matching, l4proto, + cda[CTA_TIMEOUT_DATA]); + return ret; + } + return -EBUSY; + } + + timeout = kzalloc(sizeof(struct ctnl_timeout) + + l4proto->ctnl_timeout.obj_size, GFP_KERNEL); + if (timeout == NULL) + return -ENOMEM; + + ret = ctnl_timeout_parse_policy(timeout, l4proto, + cda[CTA_TIMEOUT_DATA]); + if (ret < 0) + goto err; + + strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); + timeout->l3num = l3num; + timeout->l4num = l4num; + atomic_set(&timeout->refcnt, 1); + list_add_tail_rcu(&timeout->head, &cttimeout_list); + + return 0; +err: + kfree(timeout); + return ret; +} + +static int +ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, + int event, struct ctnl_timeout *timeout) +{ + struct nlmsghdr *nlh; + struct nfgenmsg *nfmsg; + unsigned int flags = pid ? NLM_F_MULTI : 0; + struct nf_conntrack_l4proto *l4proto; + + event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; + + nfmsg = nlmsg_data(nlh); + nfmsg->nfgen_family = AF_UNSPEC; + nfmsg->version = NFNETLINK_V0; + nfmsg->res_id = 0; + + NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); + NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); + NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); + NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, + htonl(atomic_read(&timeout->refcnt))); + + l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); + + /* If the timeout object does not match the layer 4 protocol tracker, + * then skip dumping the data part since we don't know how to + * interpret it. This may happen for UPDlite, SCTP and DCCP since + * you can unload the module. + */ + if (timeout->l4num != l4proto->l4proto) + goto out; + + if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { + struct nlattr *nest_parms; + int ret; + + nest_parms = nla_nest_start(skb, + CTA_TIMEOUT_DATA | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + + ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data); + if (ret < 0) + goto nla_put_failure; + + nla_nest_end(skb, nest_parms); + } +out: + nlmsg_end(skb, nlh); + return skb->len; + +nlmsg_failure: +nla_put_failure: + nlmsg_cancel(skb, nlh); + return -1; +} + +static int +ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct ctnl_timeout *cur, *last; + + if (cb->args[2]) + return 0; + + last = (struct ctnl_timeout *)cb->args[1]; + if (cb->args[1]) + cb->args[1] = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(cur, &cttimeout_list, head) { + if (last && cur != last) + continue; + + if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + NFNL_MSG_TYPE(cb->nlh->nlmsg_type), + IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) { + cb->args[1] = (unsigned long)cur; + break; + } + } + if (!cb->args[1]) + cb->args[2] = 1; + rcu_read_unlock(); + return skb->len; +} + +static int +cttimeout_get_timeout(struct sock *ctnl, struct sk_buff *skb, + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) +{ + int ret = -ENOENT; + char *name; + struct ctnl_timeout *cur; + + if (nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { + .dump = ctnl_timeout_dump, + }; + return netlink_dump_start(ctnl, skb, nlh, &c); + } + + if (!cda[CTA_TIMEOUT_NAME]) + return -EINVAL; + name = nla_data(cda[CTA_TIMEOUT_NAME]); + + list_for_each_entry(cur, &cttimeout_list, head) { + struct sk_buff *skb2; + + if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) + continue; + + skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb2 == NULL) { + ret = -ENOMEM; + break; + } + + ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).pid, + nlh->nlmsg_seq, + NFNL_MSG_TYPE(nlh->nlmsg_type), + IPCTNL_MSG_TIMEOUT_NEW, cur); + if (ret <= 0) { + kfree_skb(skb2); + break; + } + ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, + MSG_DONTWAIT); + if (ret > 0) + ret = 0; + + /* this avoids a loop in nfnetlink. */ + return ret == -EAGAIN ? -ENOBUFS : ret; + } + return ret; +} + +/* try to delete object, fail if it is still in use. */ +static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) +{ + int ret = 0; + + /* we want to avoid races with nf_ct_timeout_find_get. */ + if (atomic_dec_and_test(&timeout->refcnt)) { + /* We are protected by nfnl mutex. */ + list_del_rcu(&timeout->head); + kfree_rcu(timeout, rcu_head); + } else { + /* still in use, restore reference counter. */ + atomic_inc(&timeout->refcnt); + ret = -EBUSY; + } + return ret; +} + +static int +cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) +{ + char *name; + struct ctnl_timeout *cur; + int ret = -ENOENT; + + if (!cda[CTA_TIMEOUT_NAME]) { + list_for_each_entry(cur, &cttimeout_list, head) + ctnl_timeout_try_del(cur); + + return 0; + } + name = nla_data(cda[CTA_TIMEOUT_NAME]); + + list_for_each_entry(cur, &cttimeout_list, head) { + if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) + continue; + + ret = ctnl_timeout_try_del(cur); + if (ret < 0) + return ret; + + break; + } + return ret; +} + +static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { + [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, + .attr_count = CTA_TIMEOUT_MAX, + .policy = cttimeout_nla_policy }, + [IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout, + .attr_count = CTA_TIMEOUT_MAX, + .policy = cttimeout_nla_policy }, + [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, + .attr_count = CTA_TIMEOUT_MAX, + .policy = cttimeout_nla_policy }, +}; + +static const struct nfnetlink_subsystem cttimeout_subsys = { + .name = "conntrack_timeout", + .subsys_id = NFNL_SUBSYS_CTNETLINK_TIMEOUT, + .cb_count = IPCTNL_MSG_TIMEOUT_MAX, + .cb = cttimeout_cb, +}; + +MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT); + +static int __init cttimeout_init(void) +{ + int ret; + + ret = nfnetlink_subsys_register(&cttimeout_subsys); + if (ret < 0) { + pr_err("cttimeout_init: cannot register cttimeout with " + "nfnetlink.\n"); + goto err_out; + } + return 0; + +err_out: + return ret; +} + +static void __exit cttimeout_exit(void) +{ + struct ctnl_timeout *cur, *tmp; + + pr_info("cttimeout: unregistering from nfnetlink.\n"); + + nfnetlink_subsys_unregister(&cttimeout_subsys); + list_for_each_entry_safe(cur, tmp, &cttimeout_list, head) { + list_del_rcu(&cur->head); + /* We are sure that our objects have no clients at this point, + * it's safe to release them all without checking refcnt. + */ + kfree_rcu(cur, rcu_head); + } +} + +module_init(cttimeout_init); +module_exit(cttimeout_exit); -- cgit v1.2.3-70-g09d2 From dd705072412225a97784fe38feee2ebf8d14814d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 28 Feb 2012 23:36:48 +0100 Subject: netfilter: nf_ct_ext: add timeout extension This patch adds the timeout extension, which allows you to attach specific timeout policies to flows. This extension is only used by the template conntrack. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_extend.h | 4 ++ include/net/netfilter/nf_conntrack_timeout.h | 78 ++++++++++++++++++++++++++++ net/netfilter/Kconfig | 10 ++++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_core.c | 7 +++ net/netfilter/nf_conntrack_timeout.c | 60 +++++++++++++++++++++ net/netfilter/nfnetlink_cttimeout.c | 10 ---- 7 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 include/net/netfilter/nf_conntrack_timeout.h create mode 100644 net/netfilter/nf_conntrack_timeout.c (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h index 2dcf31703ac..96755c3798a 100644 --- a/include/net/netfilter/nf_conntrack_extend.h +++ b/include/net/netfilter/nf_conntrack_extend.h @@ -19,6 +19,9 @@ enum nf_ct_ext_id { #endif #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP NF_CT_EXT_TSTAMP, +#endif +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + NF_CT_EXT_TIMEOUT, #endif NF_CT_EXT_NUM, }; @@ -29,6 +32,7 @@ enum nf_ct_ext_id { #define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache #define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone #define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp +#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout /* Extensions: optional stuff which isn't permanently in struct. */ struct nf_ct_ext { diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h new file mode 100644 index 00000000000..0e04db4a086 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_timeout.h @@ -0,0 +1,78 @@ +#ifndef _NF_CONNTRACK_TIMEOUT_H +#define _NF_CONNTRACK_TIMEOUT_H + +#include +#include +#include +#include +#include + +#define CTNL_TIMEOUT_NAME_MAX 32 + +struct ctnl_timeout { + struct list_head head; + struct rcu_head rcu_head; + atomic_t refcnt; + char name[CTNL_TIMEOUT_NAME_MAX]; + __u16 l3num; + __u8 l4num; + char data[0]; +}; + +struct nf_conn_timeout { + struct ctnl_timeout *timeout; +}; + +#define NF_CT_TIMEOUT_EXT_DATA(__t) (unsigned int *) &((__t)->timeout->data) + +static inline +struct nf_conn_timeout *nf_ct_timeout_find(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + return nf_ct_ext_find(ct, NF_CT_EXT_TIMEOUT); +#else + return NULL; +#endif +} + +static inline +struct nf_conn_timeout *nf_ct_timeout_ext_add(struct nf_conn *ct, + struct ctnl_timeout *timeout, + gfp_t gfp) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + struct nf_conn_timeout *timeout_ext; + + timeout_ext = nf_ct_ext_add(ct, NF_CT_EXT_TIMEOUT, gfp); + if (timeout_ext == NULL) + return NULL; + + timeout_ext->timeout = timeout; + + return timeout_ext; +#else + return NULL; +#endif +}; + +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT +extern int nf_conntrack_timeout_init(struct net *net); +extern void nf_conntrack_timeout_fini(struct net *net); +#else +static inline int nf_conntrack_timeout_init(struct net *net) +{ + return 0; +} + +static inline void nf_conntrack_timeout_fini(struct net *net) +{ + return; +} +#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ + +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT +extern struct ctnl_timeout *(*nf_ct_timeout_find_get_hook)(const char *name); +extern void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout); +#endif + +#endif /* _NF_CONNTRACK_TIMEOUT_H */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f3efb6570dd..0c6f67e8f2e 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -103,6 +103,16 @@ config NF_CONNTRACK_EVENTS If unsure, say `N'. +config NF_CONNTRACK_TIMEOUT + bool 'Connection tracking timeout' + depends on NETFILTER_ADVANCED + help + This option enables support for connection tracking timeout + extension. This allows you to attach timeout policies to flow + via the CT target. + + If unsure, say `N'. + config NF_CONNTRACK_TIMESTAMP bool 'Connection tracking timestamping' depends on NETFILTER_ADVANCED diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index cf7cdd630bd..ca3676586f5 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -1,6 +1,7 @@ netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o +nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index d18995eea1c..75398c53571 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -1333,6 +1334,7 @@ static void nf_conntrack_cleanup_net(struct net *net) } nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); + nf_conntrack_timeout_fini(net); nf_conntrack_ecache_fini(net); nf_conntrack_tstamp_fini(net); nf_conntrack_acct_fini(net); @@ -1564,9 +1566,14 @@ static int nf_conntrack_init_net(struct net *net) ret = nf_conntrack_ecache_init(net); if (ret < 0) goto err_ecache; + ret = nf_conntrack_timeout_init(net); + if (ret < 0) + goto err_timeout; return 0; +err_timeout: + nf_conntrack_timeout_fini(net); err_ecache: nf_conntrack_tstamp_fini(net); err_tstamp: diff --git a/net/netfilter/nf_conntrack_timeout.c b/net/netfilter/nf_conntrack_timeout.c new file mode 100644 index 00000000000..a878ce5b252 --- /dev/null +++ b/net/netfilter/nf_conntrack_timeout.c @@ -0,0 +1,60 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * (C) 2012 by Vyatta Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation (or any later at your option). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct ctnl_timeout * +(*nf_ct_timeout_find_get_hook)(const char *name) __read_mostly; +EXPORT_SYMBOL_GPL(nf_ct_timeout_find_get_hook); + +void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout) __read_mostly; +EXPORT_SYMBOL_GPL(nf_ct_timeout_put_hook); + +static struct nf_ct_ext_type timeout_extend __read_mostly = { + .len = sizeof(struct nf_conn_timeout), + .align = __alignof__(struct nf_conn_timeout), + .id = NF_CT_EXT_TIMEOUT, +}; + +int nf_conntrack_timeout_init(struct net *net) +{ + int ret = 0; + + if (net_eq(net, &init_net)) { + ret = nf_ct_extend_register(&timeout_extend); + if (ret < 0) { + printk(KERN_ERR "nf_ct_timeout: Unable to register " + "timeout extension.\n"); + return ret; + } + } + + return 0; +} + +void nf_conntrack_timeout_fini(struct net *net) +{ + if (net_eq(net, &init_net)) + nf_ct_extend_unregister(&timeout_extend); +} diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index b860d521718..29b98971516 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -37,16 +37,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pablo Neira Ayuso "); MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning"); -struct ctnl_timeout { - struct list_head head; - struct rcu_head rcu_head; - atomic_t refcnt; - char name[CTNL_TIMEOUT_NAME_MAX]; - __u16 l3num; - __u8 l4num; - char data[0]; -}; - static LIST_HEAD(cttimeout_list); static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { -- cgit v1.2.3-70-g09d2 From 24de58f465165298aaa8f286b2592f0163706cfe Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 29 Feb 2012 02:19:19 +0100 Subject: netfilter: xt_CT: allow to attach timeout policy + glue code This patch allows you to attach the timeout policy via the CT target, it adds a new revision of the target to ensure backward compatibility. Moreover, it also contains the glue code to stick the timeout object defined via nfnetlink_cttimeout to the given flow. Example usage (it requires installing the nfct tool and libnetfilter_cttimeout): 1) create the timeout policy: nfct timeout add tcp-policy0 inet tcp \ established 1000 close 10 time_wait 10 last_ack 10 2) attach the timeout policy to the packet: iptables -I PREROUTING -t raw -p tcp -j CT --timeout tcp-policy0 You have to install the following user-space software: a) libnetfilter_cttimeout: git://git.netfilter.org/libnetfilter_cttimeout b) nfct: git://git.netfilter.org/nfct You also have to get iptables with -j CT --timeout support. Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/xt_CT.h | 12 ++ net/netfilter/nf_conntrack_core.c | 11 +- net/netfilter/nfnetlink_cttimeout.c | 41 +++++++ net/netfilter/xt_CT.c | 220 +++++++++++++++++++++++++++++++++--- 4 files changed, 268 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/xt_CT.h b/include/linux/netfilter/xt_CT.h index b56e76811c0..a064b8af360 100644 --- a/include/linux/netfilter/xt_CT.h +++ b/include/linux/netfilter/xt_CT.h @@ -16,4 +16,16 @@ struct xt_ct_target_info { struct nf_conn *ct __attribute__((aligned(8))); }; +struct xt_ct_target_info_v1 { + __u16 flags; + __u16 zone; + __u32 ct_events; + __u32 exp_events; + char helper[16]; + char timeout[32]; + + /* Used internally by the kernel */ + struct nf_conn *ct __attribute__((aligned(8))); +}; + #endif /* _XT_CT_H */ diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 75398c53571..81e2aa4ca1f 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -912,6 +912,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, enum ip_conntrack_info ctinfo; struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; + struct nf_conn_timeout *timeout_ext; unsigned int *timeouts; unsigned int dataoff; u_int8_t protonum; @@ -959,7 +960,15 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, goto out; } - timeouts = l4proto->get_timeouts(net); + /* Decide what timeout policy we want to apply to this flow. */ + if (tmpl) { + timeout_ext = nf_ct_timeout_find(tmpl); + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + } else + timeouts = l4proto->get_timeouts(net); ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, l3proto, l4proto, &set_reply, &ctinfo, diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 29b98971516..fec29a43de4 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -331,6 +332,38 @@ cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, return ret; } +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT +static struct ctnl_timeout *ctnl_timeout_find_get(const char *name) +{ + struct ctnl_timeout *timeout, *matching = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(timeout, &cttimeout_list, head) { + if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) + continue; + + if (!try_module_get(THIS_MODULE)) + goto err; + + if (!atomic_inc_not_zero(&timeout->refcnt)) { + module_put(THIS_MODULE); + goto err; + } + matching = timeout; + break; + } +err: + rcu_read_unlock(); + return matching; +} + +static void ctnl_timeout_put(struct ctnl_timeout *timeout) +{ + atomic_dec(&timeout->refcnt); + module_put(THIS_MODULE); +} +#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ + static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, .attr_count = CTA_TIMEOUT_MAX, @@ -362,6 +395,10 @@ static int __init cttimeout_init(void) "nfnetlink.\n"); goto err_out; } +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get); + RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put); +#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ return 0; err_out: @@ -382,6 +419,10 @@ static void __exit cttimeout_exit(void) */ kfree_rcu(cur, rcu_head); } +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); + RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); +#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ } module_init(cttimeout_init); diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 0221d10de75..b873445df44 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -16,10 +16,11 @@ #include #include #include +#include #include -static unsigned int xt_ct_target(struct sk_buff *skb, - const struct xt_action_param *par) +static unsigned int xt_ct_target_v0(struct sk_buff *skb, + const struct xt_action_param *par) { const struct xt_ct_target_info *info = par->targinfo; struct nf_conn *ct = info->ct; @@ -35,6 +36,23 @@ static unsigned int xt_ct_target(struct sk_buff *skb, return XT_CONTINUE; } +static unsigned int xt_ct_target_v1(struct sk_buff *skb, + const struct xt_action_param *par) +{ + const struct xt_ct_target_info_v1 *info = par->targinfo; + struct nf_conn *ct = info->ct; + + /* Previously seen (loopback)? Ignore. */ + if (skb->nfct != NULL) + return XT_CONTINUE; + + atomic_inc(&ct->ct_general.use); + skb->nfct = &ct->ct_general; + skb->nfctinfo = IP_CT_NEW; + + return XT_CONTINUE; +} + static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) { if (par->family == NFPROTO_IPV4) { @@ -53,7 +71,7 @@ static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) return 0; } -static int xt_ct_tg_check(const struct xt_tgchk_param *par) +static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par) { struct xt_ct_target_info *info = par->targinfo; struct nf_conntrack_tuple t; @@ -130,7 +148,137 @@ err1: return ret; } -static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) +static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) +{ + struct xt_ct_target_info_v1 *info = par->targinfo; + struct nf_conntrack_tuple t; + struct nf_conn_help *help; + struct nf_conn *ct; + int ret = 0; + u8 proto; + + if (info->flags & ~XT_CT_NOTRACK) + return -EINVAL; + + if (info->flags & XT_CT_NOTRACK) { + ct = nf_ct_untracked_get(); + atomic_inc(&ct->ct_general.use); + goto out; + } + +#ifndef CONFIG_NF_CONNTRACK_ZONES + if (info->zone) + goto err1; +#endif + + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) + goto err1; + + memset(&t, 0, sizeof(t)); + ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); + ret = PTR_ERR(ct); + if (IS_ERR(ct)) + goto err2; + + ret = 0; + if ((info->ct_events || info->exp_events) && + !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, + GFP_KERNEL)) + goto err3; + + if (info->helper[0]) { + ret = -ENOENT; + proto = xt_ct_find_proto(par); + if (!proto) { + pr_info("You must specify a L4 protocol, " + "and not use inversions on it.\n"); + goto err3; + } + + ret = -ENOMEM; + help = nf_ct_helper_ext_add(ct, GFP_KERNEL); + if (help == NULL) + goto err3; + + ret = -ENOENT; + help->helper = nf_conntrack_helper_try_module_get(info->helper, + par->family, + proto); + if (help->helper == NULL) { + pr_info("No such helper \"%s\"\n", info->helper); + goto err3; + } + } + +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + if (info->timeout) { + typeof(nf_ct_timeout_find_get_hook) timeout_find_get; + struct ctnl_timeout *timeout; + struct nf_conn_timeout *timeout_ext; + + timeout_find_get = + rcu_dereference(nf_ct_timeout_find_get_hook); + + if (timeout_find_get) { + const struct ipt_entry *e = par->entryinfo; + + if (e->ip.invflags & IPT_INV_PROTO) { + ret = -EINVAL; + pr_info("You cannot use inversion on " + "L4 protocol\n"); + goto err3; + } + timeout = timeout_find_get(info->timeout); + if (timeout == NULL) { + ret = -ENOENT; + pr_info("No such timeout policy \"%s\"\n", + info->timeout); + goto err3; + } + if (timeout->l3num != par->family) { + ret = -EINVAL; + pr_info("Timeout policy `%s' can only be " + "used by L3 protocol number %d\n", + info->timeout, timeout->l3num); + goto err3; + } + if (timeout->l4num != e->ip.proto) { + ret = -EINVAL; + pr_info("Timeout policy `%s' can only be " + "used by L4 protocol number %d\n", + info->timeout, timeout->l4num); + goto err3; + } + timeout_ext = nf_ct_timeout_ext_add(ct, timeout, + GFP_KERNEL); + if (timeout_ext == NULL) { + ret = -ENOMEM; + goto err3; + } + } else { + ret = -ENOENT; + pr_info("Timeout policy base is empty\n"); + goto err3; + } + } +#endif + + __set_bit(IPS_TEMPLATE_BIT, &ct->status); + __set_bit(IPS_CONFIRMED_BIT, &ct->status); +out: + info->ct = ct; + return 0; + +err3: + nf_conntrack_free(ct); +err2: + nf_ct_l3proto_module_put(par->family); +err1: + return ret; +} + +static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) { struct xt_ct_target_info *info = par->targinfo; struct nf_conn *ct = info->ct; @@ -146,25 +294,67 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) nf_ct_put(info->ct); } -static struct xt_target xt_ct_tg __read_mostly = { - .name = "CT", - .family = NFPROTO_UNSPEC, - .targetsize = sizeof(struct xt_ct_target_info), - .checkentry = xt_ct_tg_check, - .destroy = xt_ct_tg_destroy, - .target = xt_ct_target, - .table = "raw", - .me = THIS_MODULE, +static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) +{ + struct xt_ct_target_info_v1 *info = par->targinfo; + struct nf_conn *ct = info->ct; + struct nf_conn_help *help; +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + struct nf_conn_timeout *timeout_ext; + typeof(nf_ct_timeout_put_hook) timeout_put; +#endif + if (!nf_ct_is_untracked(ct)) { + help = nfct_help(ct); + if (help) + module_put(help->helper->me); + + nf_ct_l3proto_module_put(par->family); + +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + timeout_put = rcu_dereference(nf_ct_timeout_put_hook); + + if (timeout_put) { + timeout_ext = nf_ct_timeout_find(ct); + if (timeout_ext) + timeout_put(timeout_ext->timeout); + } +#endif + } + nf_ct_put(info->ct); +} + +static struct xt_target xt_ct_tg_reg[] __read_mostly = { + { + .name = "CT", + .family = NFPROTO_UNSPEC, + .targetsize = sizeof(struct xt_ct_target_info), + .checkentry = xt_ct_tg_check_v0, + .destroy = xt_ct_tg_destroy_v0, + .target = xt_ct_target_v0, + .table = "raw", + .me = THIS_MODULE, + }, + { + .name = "CT", + .family = NFPROTO_UNSPEC, + .revision = 1, + .targetsize = sizeof(struct xt_ct_target_info_v1), + .checkentry = xt_ct_tg_check_v1, + .destroy = xt_ct_tg_destroy_v1, + .target = xt_ct_target_v1, + .table = "raw", + .me = THIS_MODULE, + }, }; static int __init xt_ct_tg_init(void) { - return xt_register_target(&xt_ct_tg); + return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); } static void __exit xt_ct_tg_exit(void) { - xt_unregister_target(&xt_ct_tg); + xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); } module_init(xt_ct_tg_init); -- cgit v1.2.3-70-g09d2 From fcff4f108dce0692410f390a05565f4b1b84577f Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Thu, 23 Feb 2012 17:59:53 -0800 Subject: mac80211: Filter duplicate IE ids mac80211 is lenient with respect to reception of corrupted beacons. Even if the frame is corrupted as a whole, the available IE elements are still passed back and accepted, sometimes replacing legitimate data. It is unknown to what extent this "feature" is made use of, but it is clear that in some cases, this is detrimental. One such case is reported in http://crosbug.com/26832 where an AP corrupts its beacons but not its probe responses. One approach would be to completely reject frames with invaid data (for example, if the last tag extends beyond the end of the enclosing PDU). The enclosed approach is much more conservative: we simply prevent later IEs from overwriting the state from previous ones. This approach hopes that there might be some salient data in the IE stream before the corruption, and seeks to at least prevent that data from being overwritten. This approach will fix the case above. Further, we flag element structures that contain data we think might be corrupted, so that as we fill the mac80211 BSS structure, we try not to replace data from an un-corrupted probe response with that of a corrupted beacon, for example. Short of any statistics gathering in the various forms of AP breakage, it's not possible to ascertain the side effects of more stringent discarding of data. Signed-off-by: Paul Stewart Cc: Sam Leffler Cc: Eliad Peller Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 41 ++++++++++++++++++++++++++ net/mac80211/mlme.c | 14 +++++++++ net/mac80211/scan.c | 71 +++++++++++++++++++++++++++++++++------------- net/mac80211/util.c | 37 ++++++++++++++++++++++-- 4 files changed, 141 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 24cb1080e23..796b13bfc95 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -105,6 +105,44 @@ struct ieee80211_bss { */ bool has_erp_value; u8 erp_value; + + /* Keep track of the corruption of the last beacon/probe response. */ + u8 corrupt_data; + + /* Keep track of what bits of information we have valid info for. */ + u8 valid_data; +}; + +/** + * enum ieee80211_corrupt_data_flags - BSS data corruption flags + * @IEEE80211_BSS_CORRUPT_BEACON: last beacon frame received was corrupted + * @IEEE80211_BSS_CORRUPT_PROBE_RESP: last probe response received was corrupted + * + * These are bss flags that are attached to a bss in the + * @corrupt_data field of &struct ieee80211_bss. + */ +enum ieee80211_bss_corrupt_data_flags { + IEEE80211_BSS_CORRUPT_BEACON = BIT(0), + IEEE80211_BSS_CORRUPT_PROBE_RESP = BIT(1) +}; + +/** + * enum ieee80211_valid_data_flags - BSS valid data flags + * @IEEE80211_BSS_VALID_DTIM: DTIM data was gathered from non-corrupt IE + * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE + * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE + * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE + * + * These are bss flags that are attached to a bss in the + * @valid_data field of &struct ieee80211_bss. They show which parts + * of the data structure were recieved as a result of an un-corrupted + * beacon/probe response. + */ +enum ieee80211_bss_valid_data_flags { + IEEE80211_BSS_VALID_DTIM = BIT(0), + IEEE80211_BSS_VALID_WMM = BIT(1), + IEEE80211_BSS_VALID_RATES = BIT(2), + IEEE80211_BSS_VALID_ERP = BIT(3) }; static inline u8 *bss_mesh_cfg(struct ieee80211_bss *bss) @@ -1120,6 +1158,9 @@ struct ieee802_11_elems { u8 quiet_elem_len; u8 num_of_quiet_elem; /* can be more the one */ u8 timeout_int_len; + + /* whether a parse error occurred while retrieving these elements */ + bool parse_error; }; static inline struct ieee80211_local *hw_to_local( diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 92c5eb124d6..c08924aeac0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3446,6 +3446,20 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } run_again(ifmgd, assoc_data->timeout); + if (bss->corrupt_data) { + char *corrupt_type = "data"; + if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_BEACON) { + if (bss->corrupt_data & + IEEE80211_BSS_CORRUPT_PROBE_RESP) + corrupt_type = "beacon and probe response"; + else + corrupt_type = "beacon"; + } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) + corrupt_type = "probe response"; + printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n", + sdata->name, corrupt_type); + } + err = 0; goto out; err_clear: diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index a9d7235df7c..33cd1690137 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -104,16 +104,35 @@ ieee80211_bss_info_update(struct ieee80211_local *local, cbss->free_priv = ieee80211_rx_bss_free; bss = (void *)cbss->priv; + if (elems->parse_error) { + if (beacon) + bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; + else + bss->corrupt_data |= IEEE80211_BSS_CORRUPT_PROBE_RESP; + } else { + if (beacon) + bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON; + else + bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP; + } + /* save the ERP value so that it is available at association time */ - if (elems->erp_info && elems->erp_info_len >= 1) { + if (elems->erp_info && elems->erp_info_len >= 1 && + (!elems->parse_error || + !(bss->valid_data & IEEE80211_BSS_VALID_ERP))) { bss->erp_value = elems->erp_info[0]; bss->has_erp_value = true; + if (!elems->parse_error) + bss->valid_data |= IEEE80211_BSS_VALID_ERP; } - if (elems->tim) { + if (elems->tim && (!elems->parse_error || + !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) { struct ieee80211_tim_ie *tim_ie = (struct ieee80211_tim_ie *)elems->tim; bss->dtim_period = tim_ie->dtim_period; + if (!elems->parse_error) + bss->valid_data |= IEEE80211_BSS_VALID_DTIM; } /* If the beacon had no TIM IE, or it was invalid, use 1 */ @@ -121,26 +140,38 @@ ieee80211_bss_info_update(struct ieee80211_local *local, bss->dtim_period = 1; /* replace old supported rates if we get new values */ - srlen = 0; - if (elems->supp_rates) { - clen = IEEE80211_MAX_SUPP_RATES; - if (clen > elems->supp_rates_len) - clen = elems->supp_rates_len; - memcpy(bss->supp_rates, elems->supp_rates, clen); - srlen += clen; - } - if (elems->ext_supp_rates) { - clen = IEEE80211_MAX_SUPP_RATES - srlen; - if (clen > elems->ext_supp_rates_len) - clen = elems->ext_supp_rates_len; - memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, clen); - srlen += clen; + if (!elems->parse_error || + !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) { + srlen = 0; + if (elems->supp_rates) { + clen = IEEE80211_MAX_SUPP_RATES; + if (clen > elems->supp_rates_len) + clen = elems->supp_rates_len; + memcpy(bss->supp_rates, elems->supp_rates, clen); + srlen += clen; + } + if (elems->ext_supp_rates) { + clen = IEEE80211_MAX_SUPP_RATES - srlen; + if (clen > elems->ext_supp_rates_len) + clen = elems->ext_supp_rates_len; + memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, + clen); + srlen += clen; + } + if (srlen) { + bss->supp_rates_len = srlen; + if (!elems->parse_error) + bss->valid_data |= IEEE80211_BSS_VALID_RATES; + } } - if (srlen) - bss->supp_rates_len = srlen; - bss->wmm_used = elems->wmm_param || elems->wmm_info; - bss->uapsd_supported = is_uapsd_supported(elems); + if (!elems->parse_error || + !(bss->valid_data & IEEE80211_BSS_VALID_WMM)) { + bss->wmm_used = elems->wmm_param || elems->wmm_info; + bss->uapsd_supported = is_uapsd_supported(elems); + if (!elems->parse_error) + bss->valid_data |= IEEE80211_BSS_VALID_WMM; + } if (!beacon) bss->last_probe_resp = jiffies; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0a5ad95ac8b..32f7a3b3d43 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -572,24 +572,40 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, size_t left = len; u8 *pos = start; bool calc_crc = filter != 0; + DECLARE_BITMAP(seen_elems, 256); + bitmap_zero(seen_elems, 256); memset(elems, 0, sizeof(*elems)); elems->ie_start = start; elems->total_len = len; while (left >= 2) { u8 id, elen; + bool elem_parse_failed; id = *pos++; elen = *pos++; left -= 2; - if (elen > left) + if (elen > left) { + elems->parse_error = true; break; + } + + if (id != WLAN_EID_VENDOR_SPECIFIC && + id != WLAN_EID_QUIET && + test_bit(id, seen_elems)) { + elems->parse_error = true; + left -= elen; + pos += elen; + continue; + } if (calc_crc && id < 64 && (filter & (1ULL << id))) crc = crc32_be(crc, pos - 2, elen + 2); + elem_parse_failed = false; + switch (id) { case WLAN_EID_SSID: elems->ssid = pos; @@ -615,7 +631,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, if (elen >= sizeof(struct ieee80211_tim_ie)) { elems->tim = (void *)pos; elems->tim_len = elen; - } + } else + elem_parse_failed = true; break; case WLAN_EID_IBSS_PARAMS: elems->ibss_params = pos; @@ -664,10 +681,14 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, case WLAN_EID_HT_CAPABILITY: if (elen >= sizeof(struct ieee80211_ht_cap)) elems->ht_cap_elem = (void *)pos; + else + elem_parse_failed = true; break; case WLAN_EID_HT_INFORMATION: if (elen >= sizeof(struct ieee80211_ht_info)) elems->ht_info_elem = (void *)pos; + else + elem_parse_failed = true; break; case WLAN_EID_MESH_ID: elems->mesh_id = pos; @@ -676,6 +697,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, case WLAN_EID_MESH_CONFIG: if (elen >= sizeof(struct ieee80211_meshconf_ie)) elems->mesh_config = (void *)pos; + else + elem_parse_failed = true; break; case WLAN_EID_PEER_MGMT: elems->peering = pos; @@ -696,6 +719,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, case WLAN_EID_RANN: if (elen >= sizeof(struct ieee80211_rann_ie)) elems->rann = (void *)pos; + else + elem_parse_failed = true; break; case WLAN_EID_CHANNEL_SWITCH: elems->ch_switch_elem = pos; @@ -724,10 +749,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, break; } + if (elem_parse_failed) + elems->parse_error = true; + else + set_bit(id, seen_elems); + left -= elen; pos += elen; } + if (left != 0) + elems->parse_error = true; + return crc; } -- cgit v1.2.3-70-g09d2 From 3d4f96997263d97cd4d60373f1ed8184ee6df31b Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Tue, 6 Mar 2012 12:48:30 -0800 Subject: mac80211: Fix potential null pointer dereferencing The patch "{nl,cfg,mac}80211: Implement RSSI threshold for mesh peering" has a potential null pointer dereferencing problem. Thanks to Dan Carpenter for pointing out. This patch will fix the issue. Signed-off-by: Ashok Nagarajan Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 80ce5277253..4e53c4cbca9 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -31,10 +31,11 @@ #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout) #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) -#define sta_meets_rssi_threshold(sta, sdata) \ +/* We only need a valid sta if user configured a minimum rssi_threshold. */ +#define rssi_threshold_check(sta, sdata) \ (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ - (s8) -ewma_read(&sta->avg_signal) > \ - sdata->u.mesh.mshcfg.rssi_threshold) + (sta && (s8) -ewma_read(&sta->avg_signal) > \ + sdata->u.mesh.mshcfg.rssi_threshold)) enum plink_event { PLINK_UNDEFINED, @@ -307,7 +308,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, sta->plink_state == NL80211_PLINK_LISTEN && sdata->u.mesh.accepting_plinks && sdata->u.mesh.mshcfg.auto_open_plinks && - sta_meets_rssi_threshold(sta, sdata)) + rssi_threshold_check(sta, sdata)) mesh_plink_open(sta); rcu_read_unlock(); @@ -538,9 +539,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } if (ftype == WLAN_SP_MESH_PEERING_OPEN && - !sta_meets_rssi_threshold(sta, sdata)) { + !rssi_threshold_check(sta, sdata)) { mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n", - sta->sta.addr); + mgmt->sa); rcu_read_unlock(); return; } -- cgit v1.2.3-70-g09d2 From f06c7885c3dd3db8eb771e10615ee41425607e95 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 6 Mar 2012 16:42:09 -0800 Subject: mac80211: fix smatch lock errors in mesh smatch was complaining: CHECK net/mac80211/mesh_pathtbl.c net/mac80211/mesh_pathtbl.c:562 mesh_path_add() error: double lock 'bottom_half:' net/mac80211/mesh_pathtbl.c:580 mesh_path_add() error: double unlock 'bottom_half:' net/mac80211/mesh_pathtbl.c:589 mesh_path_add() error: double unlock 'bottom_half:' net/mac80211/mesh_pathtbl.c:691 mpp_path_add() error: double lock 'bottom_half:' net/mac80211/mesh_pathtbl.c:707 mpp_path_add() error: double unlock 'bottom_half:' net/mac80211/mesh_pathtbl.c:716 mpp_path_add() error: double unlock 'bottom_half:' net/mac80211/mesh_pathtbl.c:814 mesh_path_flush_by_nexthop() error: double lock 'bottom_half:' net/mac80211/mesh_pathtbl.c:819 mesh_path_flush_by_nexthop() error: double unlock 'bottom_half:' net/mac80211/mesh_pathtbl.c:887 mesh_path_del() error: double lock 'bottom_half:' net/mac80211/mesh_pathtbl.c:901 mesh_path_del() error: double unlock 'bottom_half:' So don't lock / unlock with _bh() while bottom halves are already disabled. Reported-by: Johannes Berg Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 157642f780b..be1361b5f7a 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -559,7 +559,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) hash_idx = mesh_table_hash(dst, sdata, tbl); bucket = &tbl->hash_buckets[hash_idx]; - spin_lock_bh(&tbl->hashwlock[hash_idx]); + spin_lock(&tbl->hashwlock[hash_idx]); err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { @@ -576,7 +576,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) mesh_paths_generation++; - spin_unlock_bh(&tbl->hashwlock[hash_idx]); + spin_unlock(&tbl->hashwlock[hash_idx]); read_unlock_bh(&pathtbl_resize_lock); if (grow) { set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); @@ -585,7 +585,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) return 0; err_exists: - spin_unlock_bh(&tbl->hashwlock[hash_idx]); + spin_unlock(&tbl->hashwlock[hash_idx]); read_unlock_bh(&pathtbl_resize_lock); kfree(new_node); err_node_alloc: @@ -688,7 +688,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) hash_idx = mesh_table_hash(dst, sdata, tbl); bucket = &tbl->hash_buckets[hash_idx]; - spin_lock_bh(&tbl->hashwlock[hash_idx]); + spin_lock(&tbl->hashwlock[hash_idx]); err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { @@ -703,7 +703,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) tbl->mean_chain_len * (tbl->hash_mask + 1)) grow = 1; - spin_unlock_bh(&tbl->hashwlock[hash_idx]); + spin_unlock(&tbl->hashwlock[hash_idx]); read_unlock_bh(&pathtbl_resize_lock); if (grow) { set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); @@ -712,7 +712,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) return 0; err_exists: - spin_unlock_bh(&tbl->hashwlock[hash_idx]); + spin_unlock(&tbl->hashwlock[hash_idx]); read_unlock_bh(&pathtbl_resize_lock); kfree(new_node); err_node_alloc: @@ -811,9 +811,9 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) for_each_mesh_entry(tbl, p, node, i) { mpath = node->mpath; if (rcu_dereference(mpath->next_hop) == sta) { - spin_lock_bh(&tbl->hashwlock[i]); + spin_lock(&tbl->hashwlock[i]); __mesh_path_del(tbl, node); - spin_unlock_bh(&tbl->hashwlock[i]); + spin_unlock(&tbl->hashwlock[i]); } } read_unlock_bh(&pathtbl_resize_lock); @@ -884,7 +884,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) hash_idx = mesh_table_hash(addr, sdata, tbl); bucket = &tbl->hash_buckets[hash_idx]; - spin_lock_bh(&tbl->hashwlock[hash_idx]); + spin_lock(&tbl->hashwlock[hash_idx]); hlist_for_each_entry(node, n, bucket, list) { mpath = node->mpath; if (mpath->sdata == sdata && @@ -897,7 +897,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) err = -ENXIO; enddel: mesh_paths_generation++; - spin_unlock_bh(&tbl->hashwlock[hash_idx]); + spin_unlock(&tbl->hashwlock[hash_idx]); read_unlock_bh(&pathtbl_resize_lock); return err; } -- cgit v1.2.3-70-g09d2 From b4fb05ea402cb6930b40d3152d8acabc391b23e2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Mar 2012 04:45:43 +0000 Subject: tcp: md5: correct a RCU lockdep splat commit a8afca0329 (tcp: md5: protects md5sig_info with RCU) added a lockdep splat in tcp_md5_do_lookup() in case a timer fires a tcp retransmit. At this point, socket lock is owned by the sofirq handler, not the user, so we should adjust a bit the lockdep condition, as we dont hold rcu_read_lock(). Signed-off-by: Eric Dumazet Reported-by: Valdis Kletnieks Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 94abee8cf56..507924b640e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -927,7 +927,8 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk, /* caller either holds rcu_read_lock() or socket lock */ md5sig = rcu_dereference_check(tp->md5sig_info, - sock_owned_by_user(sk)); + sock_owned_by_user(sk) || + lockdep_is_held(&sk->sk_lock.slock)); if (!md5sig) return NULL; #if IS_ENABLED(CONFIG_IPV6) -- cgit v1.2.3-70-g09d2 From 81e5d41d7ed4f6c61ba3d2414f4f9ddf6d934ebb Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 6 Mar 2012 15:05:46 -0800 Subject: openvswitch: Fix checksum update for actions on UDP packets. When modifying IP addresses or ports on a UDP packet we don't correctly follow the rules for unchecksummed packets. This meant that packets without a checksum can be given a incorrect new checksum and packets with a checksum can become marked as being unchecksummed. This fixes it to handle those requirements. Signed-off-by: Jesse Gross --- net/openvswitch/actions.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 2725d1bdf29..48badffaafc 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Nicira Networks. + * Copyright (c) 2007-2012 Nicira Networks. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -145,9 +145,16 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb, *addr, new_addr, 1); } else if (nh->protocol == IPPROTO_UDP) { - if (likely(transport_len >= sizeof(struct udphdr))) - inet_proto_csum_replace4(&udp_hdr(skb)->check, skb, - *addr, new_addr, 1); + if (likely(transport_len >= sizeof(struct udphdr))) { + struct udphdr *uh = udp_hdr(skb); + + if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { + inet_proto_csum_replace4(&uh->check, skb, + *addr, new_addr, 1); + if (!uh->check) + uh->check = CSUM_MANGLED_0; + } + } } csum_replace4(&nh->check, *addr, new_addr); @@ -197,8 +204,22 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port, skb->rxhash = 0; } -static int set_udp_port(struct sk_buff *skb, - const struct ovs_key_udp *udp_port_key) +static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port) +{ + struct udphdr *uh = udp_hdr(skb); + + if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) { + set_tp_port(skb, port, new_port, &uh->check); + + if (!uh->check) + uh->check = CSUM_MANGLED_0; + } else { + *port = new_port; + skb->rxhash = 0; + } +} + +static int set_udp(struct sk_buff *skb, const struct ovs_key_udp *udp_port_key) { struct udphdr *uh; int err; @@ -210,16 +231,15 @@ static int set_udp_port(struct sk_buff *skb, uh = udp_hdr(skb); if (udp_port_key->udp_src != uh->source) - set_tp_port(skb, &uh->source, udp_port_key->udp_src, &uh->check); + set_udp_port(skb, &uh->source, udp_port_key->udp_src); if (udp_port_key->udp_dst != uh->dest) - set_tp_port(skb, &uh->dest, udp_port_key->udp_dst, &uh->check); + set_udp_port(skb, &uh->dest, udp_port_key->udp_dst); return 0; } -static int set_tcp_port(struct sk_buff *skb, - const struct ovs_key_tcp *tcp_port_key) +static int set_tcp(struct sk_buff *skb, const struct ovs_key_tcp *tcp_port_key) { struct tcphdr *th; int err; @@ -328,11 +348,11 @@ static int execute_set_action(struct sk_buff *skb, break; case OVS_KEY_ATTR_TCP: - err = set_tcp_port(skb, nla_data(nested_attr)); + err = set_tcp(skb, nla_data(nested_attr)); break; case OVS_KEY_ATTR_UDP: - err = set_udp_port(skb, nla_data(nested_attr)); + err = set_udp(skb, nla_data(nested_attr)); break; } -- cgit v1.2.3-70-g09d2 From 04124681f104c1980024ff249a34a77a249fd2bc Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 8 Mar 2012 01:25:00 -0300 Subject: Bluetooth: fix conding style issues all over the tree Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btmrvl_debugfs.c | 23 +- include/net/bluetooth/hci_core.h | 67 +++-- net/bluetooth/hci_core.c | 49 ++-- net/bluetooth/hci_event.c | 110 ++++----- net/bluetooth/l2cap_core.c | 11 +- net/bluetooth/l2cap_sock.c | 3 +- net/bluetooth/mgmt.c | 489 ++++++++++++++++++------------------- net/bluetooth/smp.c | 30 +-- 8 files changed, 384 insertions(+), 398 deletions(-) (limited to 'net') diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 3497347e6db..6c20bbb54b7 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -401,28 +401,29 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, - priv, &btmrvl_psmode_fops); + priv, &btmrvl_psmode_fops); dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, - priv, &btmrvl_pscmd_fops); + priv, &btmrvl_pscmd_fops); dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, - priv, &btmrvl_gpiogap_fops); + priv, &btmrvl_gpiogap_fops); dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, - priv, &btmrvl_hsmode_fops); + priv, &btmrvl_hsmode_fops); dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, - priv, &btmrvl_hscmd_fops); + priv, &btmrvl_hscmd_fops); dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, - priv, &btmrvl_hscfgcmd_fops); + priv, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); dbg->curpsmode = debugfs_create_file("curpsmode", 0444, - dbg->status_dir, priv, &btmrvl_curpsmode_fops); + dbg->status_dir, priv, + &btmrvl_curpsmode_fops); dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, - priv, &btmrvl_psstate_fops); + priv, &btmrvl_psstate_fops); dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, - priv, &btmrvl_hsstate_fops); + priv, &btmrvl_hsstate_fops); dbg->txdnldready = debugfs_create_file("txdnldready", 0444, - dbg->status_dir, priv, - &btmrvl_txdnldready_fops); + dbg->status_dir, priv, + &btmrvl_txdnldready_fops); } void btmrvl_debugfs_remove(struct hci_dev *hdev) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cbbf68a8510..daefaac5113 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -398,16 +398,16 @@ static inline long inquiry_entry_age(struct inquiry_entry *e) } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, - bdaddr_t *bdaddr); + bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, - bdaddr_t *bdaddr); + bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, - bdaddr_t *bdaddr, - int state); + bdaddr_t *bdaddr, + int state); void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, - struct inquiry_entry *ie); + struct inquiry_entry *ie); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known, bool *ssp); + bool name_known, bool *ssp); /* ----- HCI Connections ----- */ enum { @@ -669,13 +669,13 @@ int hci_uuids_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, - bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], - u8 enc_size, u16 ediv, u8 rand[8]); + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv, + u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type); + u8 addr_type); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); @@ -931,7 +931,7 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) } static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, - u8 data_len) + u8 data_len) { eir[eir_len++] = sizeof(type) + data_len; eir[eir_len++] = type; @@ -978,50 +978,49 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); int mgmt_connectable(struct hci_dev *hdev, u8 connectable); int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, - u8 persistent); + u8 persistent); int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u32 flags, u8 *name, - u8 name_len, u8 *dev_class); + u8 addr_type, u32 flags, u8 *name, u8 name_len, + u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type); + u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status); + u8 addr_type, u8 status); int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure); int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); + u8 status); int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); + u8 status); int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, __le32 value, - u8 confirm_hint); + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint); int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type); + u8 link_type, u8 addr_type); int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status); + u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, - u8 status); + u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, - u8 *randomizer, u8 status); + u8 *randomizer, u8 status); int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 ssp, u8 *eir, - u16 eir_len); + u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, + u8 ssp, u8 *eir, u16 eir_len); int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, s8 rssi, u8 *name, u8 name_len); + u8 addr_type, s8 rssi, u8 *name, u8 name_len); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); @@ -1071,6 +1070,6 @@ void hci_le_ltk_neg_reply(struct hci_conn *conn); int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, - int timeout); + int timeout); #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 661d65fc487..59ec99eb739 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -431,7 +431,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b } struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, - bdaddr_t *bdaddr) + bdaddr_t *bdaddr) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; @@ -447,8 +447,8 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, } struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, - bdaddr_t *bdaddr, - int state) + bdaddr_t *bdaddr, + int state) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; @@ -466,7 +466,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, } void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, - struct inquiry_entry *ie) + struct inquiry_entry *ie) { struct discovery_state *cache = &hdev->discovery; struct list_head *pos = &cache->resolve; @@ -485,7 +485,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, } bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known, bool *ssp) + bool name_known, bool *ssp) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; @@ -1264,7 +1264,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) EXPORT_SYMBOL(hci_find_ltk); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type) + u8 addr_type) { struct smp_ltk *k; @@ -1278,7 +1278,7 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, EXPORT_SYMBOL(hci_find_ltk_by_addr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, - bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; u8 old_key_type, persistent; @@ -1333,8 +1333,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, } int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], - u8 enc_size, u16 ediv, u8 rand[8]) + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 + ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; @@ -1413,7 +1413,7 @@ static void hci_cmd_timer(unsigned long arg) } struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, - bdaddr_t *bdaddr) + bdaddr_t *bdaddr) { struct oob_data *data; @@ -1453,7 +1453,7 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev) } int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, - u8 *randomizer) + u8 *randomizer) { struct oob_data *data; @@ -1476,8 +1476,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, return 0; } -struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, - bdaddr_t *bdaddr) +struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct bdaddr_list *b; @@ -1545,7 +1544,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) static void hci_clear_adv_cache(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, - adv_work.work); + adv_work.work); hci_dev_lock(hdev); @@ -1588,11 +1587,7 @@ static inline int is_connectable_adv(u8 evt_type) } int hci_add_adv_entry(struct hci_dev *hdev, - struct hci_ev_le_advertising_info *ev) -{ - struct adv_entry *entry; - - if (!is_connectable_adv(ev->evt_type)) + struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type)) return -EINVAL; /* Only new entries should be added to adv_entries. So, if @@ -1639,7 +1634,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) } static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, - u16 window, int timeout) + u16 window, int timeout) { long timeo = msecs_to_jiffies(3000); struct le_scan_params param; @@ -1657,7 +1652,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, hci_req_lock(hdev); err = __hci_request(hdev, le_scan_param_req, (unsigned long) ¶m, - timeo); + timeo); if (!err) err = __hci_request(hdev, le_scan_enable_req, 0, timeo); @@ -1667,7 +1662,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, return err; schedule_delayed_work(&hdev->le_scan_disable, - msecs_to_jiffies(timeout)); + msecs_to_jiffies(timeout)); return 0; } @@ -1675,7 +1670,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, static void le_scan_disable_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, - le_scan_disable.work); + le_scan_disable.work); struct hci_cp_le_set_scan_enable cp; BT_DBG("%s", hdev->name); @@ -1692,12 +1687,12 @@ static void le_scan_work(struct work_struct *work) BT_DBG("%s", hdev->name); - hci_do_le_scan(hdev, param->type, param->interval, - param->window, param->timeout); + hci_do_le_scan(hdev, param->type, param->interval, param->window, + param->timeout); } int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, - int timeout) + int timeout) { struct le_scan_params *param = &hdev->le_scan_params; @@ -2558,7 +2553,7 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev) skb = skb_dequeue(&chan->data_q); hci_conn_enter_active_mode(chan->conn, - bt_cb(skb)->force_active); + bt_cb(skb)->force_active); hci_send_frame(skb); hdev->acl_last_tx = jiffies; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6a817daf095..badb7851d11 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -556,7 +556,7 @@ static void hci_setup(struct hci_dev *hdev) if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, - sizeof(mode), &mode); + sizeof(mode), &mode); } else { struct hci_cp_write_eir cp; @@ -577,14 +577,14 @@ static void hci_setup(struct hci_dev *hdev) struct hci_cp_read_local_ext_features cp; cp.page = 0x01; - hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), + &cp); } if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) { u8 enable = 1; - hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, - sizeof(enable), &enable); + hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable), + &enable); } } @@ -628,8 +628,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev) link_policy |= HCI_LP_PARK; link_policy = cpu_to_le16(link_policy); - hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, - sizeof(link_policy), &link_policy); + hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy), + &link_policy); } static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb) @@ -717,8 +717,8 @@ static void hci_set_le_support(struct hci_dev *hdev) } if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE)) - hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), + &cp); } static void hci_cc_read_local_ext_features(struct hci_dev *hdev, @@ -976,8 +976,8 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, - 0, rp->status); + mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0, + rp->status); hci_dev_unlock(hdev); } @@ -993,8 +993,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr, - ACL_LINK, 0, - rp->status); + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); } @@ -1009,7 +1008,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK, - 0, rp->status); + 0, rp->status); hci_dev_unlock(hdev); } @@ -1025,8 +1024,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr, - ACL_LINK, 0, - rp->status); + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); } @@ -1337,7 +1335,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, } static inline int hci_resolve_name(struct hci_dev *hdev, - struct inquiry_entry *e) + struct inquiry_entry *e) { struct hci_cp_remote_name_req cp; @@ -1369,14 +1367,14 @@ static bool hci_resolve_next_name(struct hci_dev *hdev) } static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, - bdaddr_t *bdaddr, u8 *name, u8 name_len) + bdaddr_t *bdaddr, u8 *name, u8 name_len) { struct discovery_state *discov = &hdev->discovery; struct inquiry_entry *e; if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) - mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, - name, name_len, conn->dev_class); + mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name, + name_len, conn->dev_class); if (discov->state == DISCOVERY_STOPPED) return; @@ -1393,7 +1391,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, list_del(&e->list); if (name) mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, - e->data.rssi, name, name_len); + e->data.rssi, name, name_len); } if (hci_resolve_next_name(hdev)) @@ -1602,7 +1600,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) mgmt_disconnect_failed(hdev, &conn->dst, conn->type, - conn->dst_type, status); + conn->dst_type, status); hci_dev_unlock(hdev); } @@ -1718,8 +1716,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, !name_known, ssp, - NULL, 0); + info->dev_class, 0, !name_known, ssp, NULL, + 0); } hci_dev_unlock(hdev); @@ -1770,7 +1768,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s struct hci_cp_read_remote_features cp; cp.handle = ev->handle; hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, - sizeof(cp), &cp); + sizeof(cp), &cp); } /* Set packet type for incoming connection */ @@ -1778,14 +1776,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s struct hci_cp_change_conn_ptype cp; cp.handle = ev->handle; cp.pkt_type = cpu_to_le16(conn->pkt_type); - hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), + &cp); } } else { conn->state = BT_CLOSED; if (conn->type == ACL_LINK) mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, - conn->dst_type, ev->status); + conn->dst_type, ev->status); } if (conn->type == ACL_LINK) @@ -1850,8 +1848,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk else cp.role = 0x01; /* Remain slave */ - hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), + &cp); } else { struct hci_cp_accept_sync_conn_req cp; @@ -1865,7 +1863,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk cp.retrans_effort = 0xff; hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, - sizeof(cp), &cp); + sizeof(cp), &cp); } } else { /* Connection rejected */ @@ -1900,7 +1898,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff conn->dst_type, ev->status); else mgmt_device_disconnected(hdev, &conn->dst, conn->type, - conn->dst_type); + conn->dst_type); } if (ev->status == 0) { @@ -1935,7 +1933,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s } } else { mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, - ev->status); + ev->status); } clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); @@ -1996,7 +1994,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb if (ev->status == 0) hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name, - strnlen(ev->name, HCI_MAX_NAME_LENGTH)); + strnlen(ev->name, HCI_MAX_NAME_LENGTH)); else hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0); @@ -2111,8 +2109,8 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, 0, NULL, 0, - conn->dev_class); + conn->dst_type, 0, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -2524,7 +2522,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s } static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_ev_num_comp_blocks *ev = (void *) skb->data; int i; @@ -2816,10 +2814,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false, &ssp); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, - !name_known, ssp, NULL, 0); + info->dev_class, info->rssi, + !name_known, ssp, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2834,10 +2832,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.rssi = info->rssi; data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false, &ssp); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, - !name_known, ssp, NULL, 0); + info->dev_class, info->rssi, + !name_known, ssp, NULL, 0); } } @@ -2879,8 +2877,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, 0, NULL, 0, - conn->dev_class); + conn->dst_type, 0, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -2986,17 +2984,16 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct if (test_bit(HCI_MGMT, &hdev->dev_flags)) name_known = eir_has_data_type(info->data, - sizeof(info->data), - EIR_NAME_COMPLETE); + sizeof(info->data), + EIR_NAME_COMPLETE); else name_known = true; name_known = hci_inquiry_cache_update(hdev, &data, name_known, - &ssp); + &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, - !name_known, ssp, info->data, - sizeof(info->data)); + info->dev_class, info->rssi, !name_known, + ssp, info->data, sizeof(info->data)); } hci_dev_unlock(hdev); @@ -3157,7 +3154,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, confirm: mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey, - confirm_hint); + confirm_hint); unlock: hci_dev_unlock(hdev); @@ -3198,7 +3195,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_ * the mgmt_auth_failed event */ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, - ev->status); + ev->status); hci_conn_put(conn); @@ -3223,7 +3220,7 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ } static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_ev_remote_oob_data_request *ev = (void *) skb->data; struct oob_data *data; @@ -3289,7 +3286,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type, 0, NULL, 0, NULL); + conn->dst_type, 0, NULL, 0, NULL); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); @@ -3320,8 +3317,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, - NULL, rssi, 0, 1, ev->data, - ev->length); + NULL, rssi, 0, 1, ev->data, ev->length); ptr += sizeof(*ev) + ev->length + 1; } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0b1aabff864..3e450f4a312 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1546,7 +1546,9 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } -static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb) +static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, + struct msghdr *msg, int len, + int count, struct sk_buff *skb) { struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; @@ -1564,7 +1566,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr count = min_t(unsigned int, conn->mtu, len); *frag = chan->ops->alloc_skb(chan, count, - msg->msg_flags & MSG_DONTWAIT, &err); + msg->msg_flags & MSG_DONTWAIT, + &err); if (!*frag) return err; @@ -1596,7 +1599,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return ERR_PTR(err); @@ -1631,7 +1634,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return ERR_PTR(err); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3da56c5c1fc..c4fe583b0af 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -926,7 +926,8 @@ static void l2cap_sock_state_change_cb(void *data, int state) } static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, - unsigned long len, int nb, int *err) + unsigned long len, int nb, + int *err) { struct sock *sk = chan->sk; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4ca009268af..7fcff888713 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -234,7 +234,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) } static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, - void *rp, size_t rp_len) + void *rp, size_t rp_len) { struct sk_buff *skb; struct mgmt_hdr *hdr; @@ -267,8 +267,8 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, return err; } -static int read_version(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_read_version rp; @@ -278,11 +278,11 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, put_unaligned_le16(MGMT_REVISION, &rp.revision); return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp, - sizeof(rp)); + sizeof(rp)); } -static int read_commands(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_read_commands *rp; u16 num_commands = ARRAY_SIZE(mgmt_commands); @@ -309,14 +309,14 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, put_unaligned_le16(mgmt_events[i], opcode); err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp, - rp_size); + rp_size); kfree(rp); return err; } -static int read_index_list(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_read_index_list *rp; struct list_head *p; @@ -355,7 +355,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, read_unlock(&hci_dev_list_lock); err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp, - rp_len); + rp_len); kfree(rp); @@ -600,7 +600,7 @@ static int update_class(struct hci_dev *hdev) static void service_cache_off(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, - service_cache.work); + service_cache.work); if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return; @@ -629,7 +629,7 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) } static int read_controller_info(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) + void *data, u16 data_len) { struct mgmt_rp_read_info rp; @@ -656,7 +656,7 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev, hci_dev_unlock(hdev); return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp, - sizeof(rp)); + sizeof(rp)); } static void mgmt_pending_free(struct pending_cmd *cmd) @@ -667,8 +667,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd) } static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, - struct hci_dev *hdev, - void *data, u16 len) + struct hci_dev *hdev, void *data, + u16 len) { struct pending_cmd *cmd; @@ -697,8 +697,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, } static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, - void (*cb)(struct pending_cmd *cmd, void *data), - void *data) + void (*cb)(struct pending_cmd *cmd, void *data), + void *data) { struct list_head *p, *n; @@ -737,11 +737,11 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) __le32 settings = cpu_to_le32(get_current_settings(hdev)); return cmd_complete(sk, hdev->id, opcode, 0, &settings, - sizeof(settings)); + sizeof(settings)); } static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; @@ -768,7 +768,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -790,8 +790,8 @@ failed: return err; } -static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, - u16 data_len, struct sock *skip_sk) +static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, + struct sock *skip_sk) { struct sk_buff *skb; struct mgmt_hdr *hdr; @@ -830,7 +830,7 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip) } static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_set_discoverable *cp = data; struct pending_cmd *cmd; @@ -843,26 +843,26 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, timeout = get_unaligned_le16(&cp->timeout); if (!cp->val && timeout > 0) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev) && timeout > 0) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_REJECTED); + MGMT_STATUS_REJECTED); goto failed; } @@ -926,7 +926,7 @@ failed: } static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; @@ -963,7 +963,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -998,7 +998,7 @@ failed: } static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_mode *cp = data; int err; @@ -1023,8 +1023,8 @@ failed: return err; } -static int set_link_security(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; @@ -1056,7 +1056,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -1097,7 +1097,7 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); goto failed; } @@ -1122,8 +1122,8 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, + MGMT_STATUS_BUSY); goto failed; } @@ -1157,7 +1157,7 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!enable_hs) return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); if (cp->val) set_bit(HCI_HS_ENABLED, &hdev->dev_flags); @@ -1181,7 +1181,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!enable_le || !(hdev->features[4] & LMP_LE)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); goto unlock; } @@ -1208,7 +1208,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -1225,8 +1225,8 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); } - err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, - sizeof(hci_cp), &hci_cp); + err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), + &hci_cp); if (err < 0) { mgmt_pending_remove(cmd); goto unlock; @@ -1250,7 +1250,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -1275,7 +1275,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto failed; } @@ -1318,7 +1318,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -1327,7 +1327,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, if (enable_service_cache(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, - 0, hdev->dev_class, 3); + 0, hdev->dev_class, 3); goto unlock; } @@ -1348,7 +1348,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, if (found == 0) { err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -1363,7 +1363,7 @@ update_class: if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto unlock; } @@ -1379,7 +1379,7 @@ unlock: } static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_set_dev_class *cp = data; struct pending_cmd *cmd; @@ -1391,7 +1391,7 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -1400,7 +1400,7 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto unlock; } @@ -1417,7 +1417,7 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto unlock; } @@ -1447,7 +1447,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, BT_ERR("load_link_keys: expected %u bytes, got %u bytes", len, expected_len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); } BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, @@ -1468,7 +1468,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, struct mgmt_link_key_info *key = &cp->keys[i]; hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val, - key->type, key->pin_len); + key->type, key->pin_len); } cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); @@ -1479,7 +1479,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, } static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, struct sock *skip_sk) + u8 addr_type, struct sock *skip_sk) { struct mgmt_ev_device_unpaired ev; @@ -1487,11 +1487,11 @@ static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, ev.addr.type = addr_type; return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev), - skip_sk); + skip_sk); } static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_unpair_device *cp = data; struct mgmt_rp_unpair_device rp; @@ -1508,8 +1508,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_NOT_POWERED, - &rp, sizeof(rp)); + MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); goto unlock; } @@ -1520,8 +1519,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (err < 0) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_NOT_PAIRED, - &rp, sizeof(rp)); + MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp)); goto unlock; } @@ -1538,13 +1536,13 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (!conn) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0, - &rp, sizeof(rp)); + &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp, - sizeof(*cp)); + sizeof(*cp)); if (!cmd) { err = -ENOMEM; goto unlock; @@ -1562,7 +1560,7 @@ unlock: } static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_disconnect *cp = data; struct hci_cp_disconnect dc; @@ -1576,13 +1574,13 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -1593,7 +1591,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, if (!conn) { err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_NOT_CONNECTED); + MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1634,8 +1632,8 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) } } -static int get_connections(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_get_connections *rp; struct hci_conn *c; @@ -1649,7 +1647,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -1683,7 +1681,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp, - rp_len); + rp_len); kfree(rp); @@ -1693,18 +1691,18 @@ unlock: } static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, - struct mgmt_cp_pin_code_neg_reply *cp) + struct mgmt_cp_pin_code_neg_reply *cp) { struct pending_cmd *cmd; int err; cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp, - sizeof(*cp)); + sizeof(*cp)); if (!cmd) return -ENOMEM; err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, - sizeof(cp->addr.bdaddr), &cp->addr.bdaddr); + sizeof(cp->addr.bdaddr), &cp->addr.bdaddr); if (err < 0) mgmt_pending_remove(cmd); @@ -1712,7 +1710,7 @@ static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, } static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct hci_conn *conn; struct mgmt_cp_pin_code_reply *cp = data; @@ -1726,14 +1724,14 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); if (!conn) { err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_NOT_CONNECTED); + MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1747,7 +1745,7 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, err = send_pin_code_neg_reply(sk, hdev, &ncp); if (err >= 0) err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto failed; } @@ -1772,7 +1770,7 @@ failed: } static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_pin_code_neg_reply *cp = data; int err; @@ -1783,7 +1781,7 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } @@ -1794,8 +1792,8 @@ failed: return err; } -static int set_io_capability(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_set_io_capability *cp = data; @@ -1810,8 +1808,8 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, hci_dev_unlock(hdev); - return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, - NULL, 0); + return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, + 0); } static inline struct pending_cmd *find_pairing(struct hci_conn *conn) @@ -1841,7 +1839,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) rp.addr.type = link_to_mgmt(conn->type, conn->dst_type); cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status, - &rp, sizeof(rp)); + &rp, sizeof(rp)); /* So we don't get further callbacks for this connection */ conn->connect_cfm_cb = NULL; @@ -1867,7 +1865,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) } static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_pair_device *cp = data; struct mgmt_rp_pair_device rp; @@ -1882,7 +1880,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -1894,10 +1892,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->addr.type == MGMT_ADDR_BREDR) conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + auth_type); else conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + auth_type); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -1905,15 +1903,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (IS_ERR(conn)) { err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_CONNECT_FAILED, - &rp, sizeof(rp)); + MGMT_STATUS_CONNECT_FAILED, &rp, + sizeof(rp)); goto unlock; } if (conn->connect_cfm_cb) { hci_conn_put(conn); err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_BUSY, &rp, sizeof(rp)); + MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } @@ -1944,8 +1942,8 @@ unlock: return err; } -static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_addr_info *addr = data; struct pending_cmd *cmd; @@ -1958,14 +1956,14 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); if (!cmd) { err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -1973,22 +1971,22 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, if (bacmp(&addr->bdaddr, &conn->dst) != 0) { err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto unlock; } pairing_complete(cmd, MGMT_STATUS_CANCELLED); err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0, - addr, sizeof(*addr)); + addr, sizeof(*addr)); unlock: hci_dev_unlock(hdev); return err; } static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type, u16 mgmt_op, - u16 hci_op, __le32 passkey) + bdaddr_t *bdaddr, u8 type, u16 mgmt_op, + u16 hci_op, __le32 passkey) { struct pending_cmd *cmd; struct hci_conn *conn; @@ -1998,7 +1996,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto done; } @@ -2009,7 +2007,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, if (!conn) { err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_NOT_CONNECTED); + MGMT_STATUS_NOT_CONNECTED); goto done; } @@ -2019,10 +2017,10 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, if (!err) err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_SUCCESS); + MGMT_STATUS_SUCCESS); else err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto done; } @@ -2051,8 +2049,8 @@ done: return err; } -static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_user_confirm_reply *cp = data; @@ -2060,48 +2058,47 @@ static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, if (len != sizeof(*cp)) return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_CONFIRM_REPLY, - HCI_OP_USER_CONFIRM_REPLY, 0); + MGMT_OP_USER_CONFIRM_REPLY, + HCI_OP_USER_CONFIRM_REPLY, 0); } static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_user_confirm_neg_reply *cp = data; BT_DBG(""); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_CONFIRM_NEG_REPLY, - HCI_OP_USER_CONFIRM_NEG_REPLY, 0); + MGMT_OP_USER_CONFIRM_NEG_REPLY, + HCI_OP_USER_CONFIRM_NEG_REPLY, 0); } -static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_user_passkey_reply *cp = data; BT_DBG(""); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_PASSKEY_REPLY, - HCI_OP_USER_PASSKEY_REPLY, - cp->passkey); + MGMT_OP_USER_PASSKEY_REPLY, + HCI_OP_USER_PASSKEY_REPLY, cp->passkey); } static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_user_passkey_neg_reply *cp = data; BT_DBG(""); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_PASSKEY_NEG_REPLY, - HCI_OP_USER_PASSKEY_NEG_REPLY, 0); + MGMT_OP_USER_PASSKEY_NEG_REPLY, + HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } static int update_name(struct hci_dev *hdev, const char *name) @@ -2114,7 +2111,7 @@ static int update_name(struct hci_dev *hdev, const char *name) } static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_set_local_name *cp = data; struct pending_cmd *cmd; @@ -2130,12 +2127,12 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name)); err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, - data, len); + data, len); if (err < 0) goto failed; err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len, - sk); + sk); goto failed; } @@ -2156,7 +2153,7 @@ failed: } static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) + void *data, u16 data_len) { struct pending_cmd *cmd; int err; @@ -2167,19 +2164,19 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); goto unlock; } if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -2199,7 +2196,7 @@ unlock: } static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_add_remote_oob_data *cp = data; u8 status; @@ -2211,20 +2208,20 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_NOT_POWERED, - &cp->addr, sizeof(cp->addr)); + MGMT_STATUS_NOT_POWERED, &cp->addr, + sizeof(cp->addr)); goto unlock; } err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, - cp->randomizer); + cp->randomizer); if (err < 0) status = MGMT_STATUS_FAILED; else status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, - &cp->addr, sizeof(cp->addr)); + &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); @@ -2244,9 +2241,9 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, - MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_NOT_POWERED, - &cp->addr, sizeof(cp->addr)); + MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, &cp->addr, + sizeof(cp->addr)); goto unlock; } @@ -2257,7 +2254,7 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - status, &cp->addr, sizeof(cp->addr)); + status, &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); @@ -2282,7 +2279,7 @@ int mgmt_interleaved_discovery(struct hci_dev *hdev) } static int start_discovery(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; struct pending_cmd *cmd; @@ -2294,13 +2291,13 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } if (hdev->discovery.state != DISCOVERY_STOPPED) { err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -2323,7 +2320,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, case DISCOV_TYPE_LE: if (lmp_host_le_capable(hdev)) err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, - LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); else err = -ENOTSUPP; break; @@ -2331,7 +2328,8 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, case DISCOV_TYPE_INTERLEAVED: if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev)) err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, - LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE); + LE_SCAN_WIN, + LE_SCAN_TIMEOUT_BREDR_LE); else err = -ENOTSUPP; break; @@ -2351,7 +2349,7 @@ failed: } static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_stop_discovery *mgmt_cp = data; struct pending_cmd *cmd; @@ -2365,15 +2363,15 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, if (!hci_discovery_active(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_REJECTED, - &mgmt_cp->type, sizeof(mgmt_cp->type)); + MGMT_STATUS_REJECTED, &mgmt_cp->type, + sizeof(mgmt_cp->type)); goto unlock; } if (hdev->discovery.type != mgmt_cp->type) { err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS, - &mgmt_cp->type, sizeof(mgmt_cp->type)); + MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type, + sizeof(mgmt_cp->type)); goto unlock; } @@ -2396,14 +2394,14 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, if (!e) { mgmt_pending_remove(cmd); err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0, - &mgmt_cp->type, sizeof(mgmt_cp->type)); + &mgmt_cp->type, sizeof(mgmt_cp->type)); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; } bacpy(&cp.bdaddr, &e->data.bdaddr); - err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, - sizeof(cp), &cp); + err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp), + &cp); if (err < 0) mgmt_pending_remove(cmd); else @@ -2415,7 +2413,7 @@ unlock: } static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_confirm_name *cp = data; struct inquiry_entry *e; @@ -2427,14 +2425,14 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, if (!hci_discovery_active(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto failed; } e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto failed; } @@ -2454,7 +2452,7 @@ failed: } static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_block_device *cp = data; u8 status; @@ -2471,7 +2469,7 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, - &cp->addr, sizeof(cp->addr)); + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); @@ -2479,7 +2477,7 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, } static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_unblock_device *cp = data; u8 status; @@ -2496,7 +2494,7 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, - &cp->addr, sizeof(cp->addr)); + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); @@ -2504,7 +2502,7 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, } static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_mode *cp = data; struct hci_cp_write_page_scan_activity acp; @@ -2515,11 +2513,11 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_REJECTED); + MGMT_STATUS_REJECTED); hci_dev_lock(hdev); @@ -2533,30 +2531,30 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, acp.window = 0x0012; /* default 11.25 msec page scan window */ - err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, - sizeof(acp), &acp); + err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp), + &acp); if (err < 0) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto done; } err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); if (err < 0) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto done; } err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0, - NULL, 0); + NULL, 0); done: hci_dev_unlock(hdev); return err; } static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, - void *cp_data, u16 len) + void *cp_data, u16 len) { struct mgmt_cp_load_long_term_keys *cp = cp_data; u16 key_count, expected_len; @@ -2570,7 +2568,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, BT_ERR("load_keys: expected %u bytes, got %u bytes", len, expected_len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, - EINVAL); + EINVAL); } BT_DBG("%s key_count %u", hdev->name, key_count); @@ -2589,8 +2587,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, type = HCI_SMP_LTK_SLAVE; hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type, - type, 0, key->authenticated, key->val, - key->enc_size, key->ediv, key->rand); + type, 0, key->authenticated, key->val, + key->enc_size, key->ediv, key->rand); } hci_dev_unlock(hdev); @@ -2599,8 +2597,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, } struct mgmt_handler { - int (*func) (struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len); + int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len); bool var_len; size_t data_len; } mgmt_handlers[] = { @@ -2685,7 +2683,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) hdev = hci_dev_get(index); if (!hdev) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_INDEX); + MGMT_STATUS_INVALID_INDEX); goto done; } } @@ -2694,14 +2692,14 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) mgmt_handlers[opcode].func == NULL) { BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, - MGMT_STATUS_UNKNOWN_COMMAND); + MGMT_STATUS_UNKNOWN_COMMAND); goto done; } if ((hdev && opcode < MGMT_OP_READ_INFO) || (!hdev && opcode >= MGMT_OP_READ_INFO)) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_INDEX); + MGMT_STATUS_INVALID_INDEX); goto done; } @@ -2710,7 +2708,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if ((handler->var_len && len < handler->data_len) || (!handler->var_len && len != handler->data_len)) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto done; } @@ -2829,7 +2827,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) } mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, - &match); + &match); if (changed) err = new_settings(hdev, match.sk); @@ -2855,7 +2853,7 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) } mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, - &match); + &match); if (changed) err = new_settings(hdev, match.sk); @@ -2872,17 +2870,16 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) if (scan & SCAN_PAGE) mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); if (scan & SCAN_INQUIRY) mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); return 0; } -int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, - u8 persistent) +int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent) { struct mgmt_ev_new_link_key ev; @@ -2917,13 +2914,13 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) memcpy(ev.key.rand, key->rand, sizeof(key->rand)); memcpy(ev.key.val, key->val, sizeof(key->val)); - return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, - &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), + NULL); } int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u32 flags, u8 *name, - u8 name_len, u8 *dev_class) + u8 addr_type, u32 flags, u8 *name, u8 name_len, + u8 *dev_class) { char buf[512]; struct mgmt_ev_device_connected *ev = (void *) buf; @@ -2936,16 +2933,16 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, if (name_len > 0) eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, - name, name_len); + name, name_len); if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0) eir_len = eir_append_data(&ev->eir[eir_len], eir_len, - EIR_CLASS_OF_DEV, dev_class, 3); + EIR_CLASS_OF_DEV, dev_class, 3); put_unaligned_le16(eir_len, &ev->eir_len); return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, - sizeof(*ev) + eir_len, NULL); + sizeof(*ev) + eir_len, NULL); } static void disconnect_rsp(struct pending_cmd *cmd, void *data) @@ -2958,7 +2955,7 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) rp.addr.type = cp->addr.type; cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp, - sizeof(rp)); + sizeof(rp)); *sk = cmd->sk; sock_hold(*sk); @@ -2984,7 +2981,7 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) } int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type) + u8 link_type, u8 addr_type) { struct mgmt_addr_info ev; struct sock *sk = NULL; @@ -2996,19 +2993,19 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, ev.type = link_to_mgmt(link_type, addr_type); err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), - sk); + sk); if (sk) - sock_put(sk); + sock_put(sk); mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, - hdev); + hdev); return err; } int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { struct mgmt_rp_disconnect rp; struct pending_cmd *cmd; @@ -3022,7 +3019,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, rp.addr.type = link_to_mgmt(link_type, addr_type); err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3032,7 +3029,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status) + u8 addr_type, u8 status) { struct mgmt_ev_connect_failed ev; @@ -3052,11 +3049,11 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), - NULL); + NULL); } int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 status) { struct pending_cmd *cmd; struct mgmt_rp_pin_code_reply rp; @@ -3070,7 +3067,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, rp.addr.type = MGMT_ADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3078,7 +3075,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 status) { struct pending_cmd *cmd; struct mgmt_rp_pin_code_reply rp; @@ -3092,7 +3089,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, rp.addr.type = MGMT_ADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3100,8 +3097,8 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, __le32 value, - u8 confirm_hint) + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint) { struct mgmt_ev_user_confirm_request ev; @@ -3113,7 +3110,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, put_unaligned_le32(value, &ev.value); return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev), - NULL); + NULL); } int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -3127,7 +3124,7 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, ev.addr.type = link_to_mgmt(link_type, addr_type); return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev), - NULL); + NULL); } static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -3145,7 +3142,7 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = link_to_mgmt(link_type, addr_type); err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status), - &rp, sizeof(rp)); + &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3153,35 +3150,35 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_CONFIRM_REPLY); + status, MGMT_OP_USER_CONFIRM_REPLY); } int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_CONFIRM_NEG_REPLY); + status, MGMT_OP_USER_CONFIRM_NEG_REPLY); } int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_PASSKEY_REPLY); + status, MGMT_OP_USER_PASSKEY_REPLY); } int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_PASSKEY_NEG_REPLY); + status, MGMT_OP_USER_PASSKEY_NEG_REPLY); } int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status) + u8 addr_type, u8 status) { struct mgmt_ev_auth_failed ev; @@ -3201,7 +3198,7 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) if (status) { u8 mgmt_err = mgmt_status(status); mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); return 0; } @@ -3214,7 +3211,7 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) } mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, - &match); + &match); if (changed) err = new_settings(hdev, match.sk); @@ -3249,11 +3246,11 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) u8 mgmt_err = mgmt_status(status); if (enable && test_and_clear_bit(HCI_SSP_ENABLED, - &hdev->dev_flags)) + &hdev->dev_flags)) err = new_settings(hdev, NULL); - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, - cmd_status_rsp, &mgmt_err); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, + &mgmt_err); return err; } @@ -3287,7 +3284,7 @@ static void class_rsp(struct pending_cmd *cmd, void *data) struct cmd_lookup *match = data; cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status, - match->hdev->dev_class, 3); + match->hdev->dev_class, 3); list_del(&cmd->list); @@ -3300,7 +3297,7 @@ static void class_rsp(struct pending_cmd *cmd, void *data) } int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, - u8 status) + u8 status) { struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; int err = 0; @@ -3312,8 +3309,8 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match); if (!status) - err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, - dev_class, 3, NULL); + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, + 3, NULL); if (match.sk) sock_put(match.sk); @@ -3347,19 +3344,19 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) if (status) { err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, - mgmt_status(status)); + mgmt_status(status)); goto failed; } err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev, - sizeof(ev)); + sizeof(ev)); if (err < 0) goto failed; send_event: if (changed) err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, - sizeof(ev), cmd ? cmd->sk : NULL); + sizeof(ev), cmd ? cmd->sk : NULL); update_eir(hdev); @@ -3370,7 +3367,7 @@ failed: } int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, - u8 *randomizer, u8 status) + u8 *randomizer, u8 status) { struct pending_cmd *cmd; int err; @@ -3382,9 +3379,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, return -ENOENT; if (status) { - err = cmd_status(cmd->sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_DATA, - mgmt_status(status)); + err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, + mgmt_status(status)); } else { struct mgmt_rp_read_local_oob_data rp; @@ -3392,8 +3388,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); err = cmd_complete(cmd->sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_DATA, - 0, &rp, sizeof(rp)); + MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp, + sizeof(rp)); } mgmt_pending_remove(cmd); @@ -3411,11 +3407,11 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) u8 mgmt_err = mgmt_status(status); if (enable && test_and_clear_bit(HCI_LE_ENABLED, - &hdev->dev_flags)) - err = new_settings(hdev, NULL); + &hdev->dev_flags)) + err = new_settings(hdev, NULL); mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); return err; } @@ -3440,8 +3436,8 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) } int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *dev_class, s8 rssi, - u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len) + u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 + ssp, u8 *eir, u16 eir_len) { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; @@ -3466,7 +3462,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV)) eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, - dev_class, 3); + dev_class, 3); put_unaligned_le16(eir_len, &ev->eir_len); @@ -3476,7 +3472,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, } int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, s8 rssi, u8 *name, u8 name_len) + u8 addr_type, s8 rssi, u8 *name, u8 name_len) { struct mgmt_ev_device_found *ev; char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2]; @@ -3491,12 +3487,12 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev->rssi = rssi; eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, - name_len); + name_len); put_unaligned_le16(eir_len, &ev->eir_len); return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, - sizeof(*ev) + eir_len, NULL); + sizeof(*ev) + eir_len, NULL); } int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) @@ -3514,7 +3510,7 @@ int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) type = hdev->discovery.type; err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), - &type, sizeof(type)); + &type, sizeof(type)); mgmt_pending_remove(cmd); return err; @@ -3530,8 +3526,7 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status) return -ENOENT; err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), - &hdev->discovery.type, - sizeof(hdev->discovery.type)); + &hdev->discovery.type, sizeof(hdev->discovery.type)); mgmt_pending_remove(cmd); return err; @@ -3552,8 +3547,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) if (cmd != NULL) { u8 type = hdev->discovery.type; - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, - &type, sizeof(type)); + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type, + sizeof(type)); mgmt_pending_remove(cmd); } @@ -3575,7 +3570,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); + cmd ? cmd->sk : NULL); } int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) @@ -3589,7 +3584,7 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); + cmd ? cmd->sk : NULL); } module_param(enable_hs, bool, 0644); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 75937d73d8a..8f56282c247 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -264,7 +264,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, - hcon->dst_type, reason); + hcon->dst_type, reason); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { cancel_delayed_work_sync(&conn->security_timer); @@ -384,12 +384,11 @@ static void confirm_work(struct work_struct *work) if (conn->hcon->out) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0, - conn->src, conn->hcon->dst_type, conn->dst, - res); + conn->src, conn->hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, - conn->hcon->dst_type, conn->dst, 0, conn->src, - res); + conn->hcon->dst_type, conn->dst, 0, conn->src, + res); if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -424,12 +423,10 @@ static void random_work(struct work_struct *work) if (hcon->out) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0, - conn->src, hcon->dst_type, conn->dst, - res); + conn->src, hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, - hcon->dst_type, conn->dst, 0, conn->src, - res); + hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -454,7 +451,7 @@ static void random_work(struct work_struct *work) swap128(key, stk); memset(stk + smp->enc_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); + SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; @@ -480,8 +477,8 @@ static void random_work(struct work_struct *work) SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type, - HCI_SMP_STK_SLAVE, 0, 0, stk, - smp->enc_key_size, ediv, rand); + HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size, + ediv, rand); } return; @@ -829,8 +826,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_dev_lock(hdev); authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH); hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, - HCI_SMP_LTK, 1, authenticated, smp->tk, - smp->enc_key_size, rp->ediv, rp->rand); + HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size, + rp->ediv, rp->rand); smp_distribute_keys(conn, 1); hci_dev_unlock(hdev); @@ -954,9 +951,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) authenticated = hcon->sec_level == BT_SECURITY_HIGH; hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, - HCI_SMP_LTK_SLAVE, 1, authenticated, - enc.ltk, smp->enc_key_size, - ediv, ident.rand); + HCI_SMP_LTK_SLAVE, 1, authenticated, + enc.ltk, smp->enc_key_size, ediv, ident.rand); ident.ediv = cpu_to_le16(ediv); -- cgit v1.2.3-70-g09d2 From e57d758ae8e8f00e80f233c823aeeef34bd92796 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 7 Mar 2012 20:20:14 +0200 Subject: Bluetooth: Fix using uninitialized variable + src/net/bluetooth/rfcomm/tty.c: warning: 'p' is used uninitialized in this function: => 218 + src/net/bluetooth/rfcomm/tty.c: warning: 'p' may be used uninitialized in this function: => 218 Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Gustavo F. Padovan --- net/bluetooth/rfcomm/tty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a2d4f5122a6..c179734f143 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -196,7 +196,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL); static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) { struct rfcomm_dev *dev, *entry; - struct list_head *head = &rfcomm_dev_list, *p; + struct list_head *head = &rfcomm_dev_list; int err = 0; BT_DBG("id %d channel %d", req->dev_id, req->channel); @@ -215,7 +215,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) break; dev->id++; - head = p; + head = &entry->list; } } else { dev->id = req->dev_id; @@ -229,7 +229,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) if (entry->id > dev->id - 1) break; - head = p; + head = &entry->list; } } -- cgit v1.2.3-70-g09d2 From b3ff53ff006b7906c88adf9d0fccc06a8877fae1 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 5 Mar 2012 20:07:08 +0200 Subject: Bluetooth: Fix access to the STK generation methods matrix The major index of the table is actually the remote I/O capabilities, not the local ones. As a result, devices with different I/O capabilities could have used wrong or even unsupported generation methods. Signed-off-by: Ido Yariv CC: Brian Gix Acked-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8f56282c247..9883d673873 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -310,7 +310,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, remote_io > SMP_IO_KEYBOARD_DISPLAY) method = JUST_WORKS; else - method = gen_method[local_io][remote_io]; + method = gen_method[remote_io][local_io]; /* If not bonding, don't ask user to confirm a Zero TK */ if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) -- cgit v1.2.3-70-g09d2 From fdde0a26a218d95e2ea38c0838ab6f24040af14c Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 5 Mar 2012 20:09:38 +0200 Subject: Bluetooth: Set security level on incoming pairing request If a master would like to raise the security level, it will send a pairing request. While the pending security level is set on an incoming security request (from a slave), it is not set on a pairing request. As a result, the security level would not be raised on the slave in such case. Fix this by setting the pending security when receiving pairing requests according to the requested authorization. Signed-off-by: Ido Yariv Acked-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan --- net/bluetooth/smp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9883d673873..deb119875fd 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -589,6 +589,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (req->auth_req & SMP_AUTH_BONDING) auth = req->auth_req; + conn->hcon->pending_sec_level = authreq_to_seclevel(auth); + build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); -- cgit v1.2.3-70-g09d2 From 9fbd87d413921f36d2f55cee1d082323e6eb1d5f Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 7 Mar 2012 02:06:23 +0000 Subject: af_iucv: handle netdev events In case of transport through HiperSockets the underlying network interface may switch to DOWN state or the underlying network device may recover. In both cases the socket must change to IUCV_DISCONN state. If the interface goes down, af_iucv has a chance to notify its connection peer in addition. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 106 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 44 deletions(-) (limited to 'net') diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 98d1f0ba7fe..31537c5eb17 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -453,14 +453,28 @@ static void iucv_sever_path(struct sock *sk, int with_user_data) } } +/* Send FIN through an IUCV socket for HIPER transport */ +static int iucv_send_ctrl(struct sock *sk, u8 flags) +{ + int err = 0; + int blen; + struct sk_buff *skb; + + blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; + skb = sock_alloc_send_skb(sk, blen, 1, &err); + if (skb) { + skb_reserve(skb, blen); + err = afiucv_hs_send(NULL, sk, skb, flags); + } + return err; +} + /* Close an IUCV socket */ static void iucv_sock_close(struct sock *sk) { struct iucv_sock *iucv = iucv_sk(sk); unsigned long timeo; int err = 0; - int blen; - struct sk_buff *skb; lock_sock(sk); @@ -471,14 +485,7 @@ static void iucv_sock_close(struct sock *sk) case IUCV_CONNECTED: if (iucv->transport == AF_IUCV_TRANS_HIPER) { - /* send fin */ - blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; - skb = sock_alloc_send_skb(sk, blen, 1, &err); - if (skb) { - skb_reserve(skb, blen); - err = afiucv_hs_send(NULL, sk, skb, - AF_IUCV_FLAG_FIN); - } + err = iucv_send_ctrl(sk, AF_IUCV_FLAG_FIN); sk->sk_state = IUCV_DISCONN; sk->sk_state_change(sk); } @@ -782,26 +789,6 @@ static int iucv_sock_autobind(struct sock *sk) return err; } -static int afiucv_hs_connect(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct sk_buff *skb; - int blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN; - int err = 0; - - /* send syn */ - skb = sock_alloc_send_skb(sk, blen, 1, &err); - if (!skb) { - err = -ENOMEM; - goto done; - } - skb->dev = NULL; - skb_reserve(skb, blen); - err = afiucv_hs_send(NULL, sk, skb, AF_IUCV_FLAG_SYN); -done: - return err; -} - static int afiucv_path_connect(struct socket *sock, struct sockaddr *addr) { struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr; @@ -882,7 +869,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, memcpy(iucv->dst_name, sa->siucv_name, 8); if (iucv->transport == AF_IUCV_TRANS_HIPER) - err = afiucv_hs_connect(sock); + err = iucv_send_ctrl(sock->sk, AF_IUCV_FLAG_SYN); else err = afiucv_path_connect(sock, addr); if (err) @@ -1332,8 +1319,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk); unsigned int copied, rlen; - struct sk_buff *skb, *rskb, *cskb, *sskb; - int blen; + struct sk_buff *skb, *rskb, *cskb; int err = 0; if ((sk->sk_state == IUCV_DISCONN) && @@ -1422,15 +1408,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, iucv_process_message_q(sk); if (atomic_read(&iucv->msg_recv) >= iucv->msglimit / 2) { - /* send WIN to peer */ - blen = sizeof(struct af_iucv_trans_hdr) + - ETH_HLEN; - sskb = sock_alloc_send_skb(sk, blen, 1, &err); - if (sskb) { - skb_reserve(sskb, blen); - err = afiucv_hs_send(NULL, sk, sskb, - AF_IUCV_FLAG_WIN); - } + err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN); if (err) { sk->sk_state = IUCV_DISCONN; sk->sk_state_change(sk); @@ -2289,6 +2267,44 @@ out_unlock: } } + +/* + * afiucv_netdev_event: handle netdev notifier chain events + */ +static int afiucv_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *event_dev = (struct net_device *)ptr; + struct hlist_node *node; + struct sock *sk; + struct iucv_sock *iucv; + + switch (event) { + case NETDEV_REBOOT: + case NETDEV_GOING_DOWN: + sk_for_each(sk, node, &iucv_sk_list.head) { + iucv = iucv_sk(sk); + if ((iucv->hs_dev == event_dev) && + (sk->sk_state == IUCV_CONNECTED)) { + if (event == NETDEV_GOING_DOWN) + iucv_send_ctrl(sk, AF_IUCV_FLAG_FIN); + sk->sk_state = IUCV_DISCONN; + sk->sk_state_change(sk); + } + } + break; + case NETDEV_DOWN: + case NETDEV_UNREGISTER: + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block afiucv_netdev_notifier = { + .notifier_call = afiucv_netdev_event, +}; + static const struct proto_ops iucv_sock_ops = { .family = PF_IUCV, .owner = THIS_MODULE, @@ -2388,7 +2404,8 @@ static int __init afiucv_init(void) err = afiucv_iucv_init(); if (err) goto out_sock; - } + } else + register_netdevice_notifier(&afiucv_netdev_notifier); dev_add_pack(&iucv_packet_type); return 0; @@ -2409,7 +2426,8 @@ static void __exit afiucv_exit(void) driver_unregister(&af_iucv_driver); pr_iucv->iucv_unregister(&af_iucv_handler, 0); symbol_put(iucv_if); - } + } else + unregister_netdevice_notifier(&afiucv_netdev_notifier); dev_remove_pack(&iucv_packet_type); sock_unregister(PF_IUCV); proto_unregister(&iucv_proto); -- cgit v1.2.3-70-g09d2 From 82492a355fac112908271faa74f473a38c1fb647 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 7 Mar 2012 02:06:24 +0000 Subject: af_iucv: add shutdown for HS transport AF_IUCV sockets offer a shutdown function. This patch makes sure shutdown works for HS transport as well. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- include/net/iucv/af_iucv.h | 1 + net/iucv/af_iucv.c | 79 ++++++++++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index 2e1d5ecc2d1..cc7c1973238 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -62,6 +62,7 @@ struct sock_msg_q { #define AF_IUCV_FLAG_SYN 0x2 #define AF_IUCV_FLAG_FIN 0x4 #define AF_IUCV_FLAG_WIN 0x8 +#define AF_IUCV_FLAG_SHT 0x10 struct af_iucv_trans_hdr { u16 magic; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 31537c5eb17..07d7d55a1b9 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -165,8 +165,6 @@ static int afiucv_pm_freeze(struct device *dev) read_lock(&iucv_sk_list.lock); sk_for_each(sk, node, &iucv_sk_list.head) { iucv = iucv_sk(sk); - skb_queue_purge(&iucv->send_skb_q); - skb_queue_purge(&iucv->backlog_skb_q); switch (sk->sk_state) { case IUCV_DISCONN: case IUCV_CLOSING: @@ -405,7 +403,19 @@ static struct sock *__iucv_get_sock_by_name(char *nm) static void iucv_sock_destruct(struct sock *sk) { skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sk->sk_write_queue); + skb_queue_purge(&sk->sk_error_queue); + + sk_mem_reclaim(sk); + + if (!sock_flag(sk, SOCK_DEAD)) { + pr_err("Attempt to release alive iucv socket %p\n", sk); + return; + } + + WARN_ON(atomic_read(&sk->sk_rmem_alloc)); + WARN_ON(atomic_read(&sk->sk_wmem_alloc)); + WARN_ON(sk->sk_wmem_queued); + WARN_ON(sk->sk_forward_alloc); } /* Cleanup Listen */ @@ -1342,6 +1352,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, rlen = skb->len; /* real length of skb */ copied = min_t(unsigned int, rlen, len); + if (!rlen) + sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN; cskb = skb; if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) { @@ -1493,42 +1505,47 @@ static int iucv_sock_shutdown(struct socket *sock, int how) lock_sock(sk); switch (sk->sk_state) { + case IUCV_LISTEN: case IUCV_DISCONN: case IUCV_CLOSING: case IUCV_CLOSED: err = -ENOTCONN; goto fail; - default: - sk->sk_shutdown |= how; break; } if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) { - txmsg.class = 0; - txmsg.tag = 0; - err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA, - 0, (void *) iprm_shutdown, 8); - if (err) { - switch (err) { - case 1: - err = -ENOTCONN; - break; - case 2: - err = -ECONNRESET; - break; - default: - err = -ENOTCONN; - break; + if (iucv->transport == AF_IUCV_TRANS_IUCV) { + txmsg.class = 0; + txmsg.tag = 0; + err = pr_iucv->message_send(iucv->path, &txmsg, + IUCV_IPRMDATA, 0, (void *) iprm_shutdown, 8); + if (err) { + switch (err) { + case 1: + err = -ENOTCONN; + break; + case 2: + err = -ECONNRESET; + break; + default: + err = -ENOTCONN; + break; + } } - } + } else + iucv_send_ctrl(sk, AF_IUCV_FLAG_SHT); } + sk->sk_shutdown |= how; if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) { - err = pr_iucv->path_quiesce(iucv->path, NULL); - if (err) - err = -ENOTCONN; - + if (iucv->transport == AF_IUCV_TRANS_IUCV) { + err = pr_iucv->path_quiesce(iucv->path, NULL); + if (err) + err = -ENOTCONN; +/* skb_queue_purge(&sk->sk_receive_queue); */ + } skb_queue_purge(&sk->sk_receive_queue); } @@ -2066,8 +2083,13 @@ static int afiucv_hs_callback_rx(struct sock *sk, struct sk_buff *skb) return NET_RX_SUCCESS; } + if (sk->sk_shutdown & RCV_SHUTDOWN) { + kfree_skb(skb); + return NET_RX_SUCCESS; + } + /* write stuff from iucv_msg to skb cb */ - if (skb->len <= sizeof(struct af_iucv_trans_hdr)) { + if (skb->len < sizeof(struct af_iucv_trans_hdr)) { kfree_skb(skb); return NET_RX_SUCCESS; } @@ -2173,7 +2195,10 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev, kfree_skb(skb); break; } - /* fall through */ + /* fall through and receive non-zero length data */ + case (AF_IUCV_FLAG_SHT): + /* shutdown request */ + /* fall through and receive zero length data */ case 0: /* plain data frame */ memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class, -- cgit v1.2.3-70-g09d2 From d9e179ecec0805c41b17f9a0c3b925d415677772 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Tue, 6 Mar 2012 22:25:14 +0000 Subject: bridge: br_log_state() s/entering/entered/ When br_log_state() is reporting state it should say "entered" istead of "entering" since state at this point is already changed. Signed-off-by: Paulius Zaleckas Signed-off-by: David S. Miller --- net/bridge/br_stp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 6751ed4e0c0..8c836d96ba7 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -31,7 +31,7 @@ static const char *const br_port_state_names[] = { void br_log_state(const struct net_bridge_port *p) { - br_info(p->br, "port %u(%s) entering %s state\n", + br_info(p->br, "port %u(%s) entered %s state\n", (unsigned) p->port_no, p->dev->name, br_port_state_names[p->state]); } -- cgit v1.2.3-70-g09d2 From 5200959b833ddacf28b6ffce8c331dfd6e0ca797 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Tue, 6 Mar 2012 22:25:22 +0000 Subject: bridge: fix state reporting when port is disabled Now we have: eth0: link *down* br0: port 1(eth0) entered *forwarding* state br_log_state(p) should be called *after* p->state is set to BR_STATE_DISABLED. Reported-by: Zilvinas Valinskas Signed-off-by: Paulius Zaleckas Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_stp_if.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 19308e305d8..f494496373d 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -98,14 +98,13 @@ void br_stp_disable_port(struct net_bridge_port *p) struct net_bridge *br = p->br; int wasroot; - br_log_state(p); - wasroot = br_is_root_bridge(br); br_become_designated_port(p); p->state = BR_STATE_DISABLED; p->topology_change_ack = 0; p->config_pending = 0; + br_log_state(p); br_ifinfo_notify(RTM_NEWLINK, p); del_timer(&p->message_age_timer); -- cgit v1.2.3-70-g09d2 From 5faa5df1fa2024bd750089ff21dcc4191798263d Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Tue, 6 Mar 2012 21:20:26 +0000 Subject: inetpeer: Invalidate the inetpeer tree along with the routing cache We initialize the routing metrics with the values cached on the inetpeer in rt_init_metrics(). So if we have the metrics cached on the inetpeer, we ignore the user configured fib_metrics. To fix this issue, we replace the old tree with a fresh initialized inet_peer_base. The old tree is removed later with a delayed work queue. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- include/net/inetpeer.h | 3 ++ net/ipv4/inetpeer.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++- net/ipv4/route.c | 1 + 3 files changed, 83 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 06b795dd590..ff04a33acf0 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -41,6 +41,7 @@ struct inet_peer { u32 pmtu_orig; u32 pmtu_learned; struct inetpeer_addr_base redirect_learned; + struct list_head gc_list; /* * Once inet_peer is queued for deletion (refcnt == -1), following fields * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp @@ -96,6 +97,8 @@ static inline struct inet_peer *inet_getpeer_v6(const struct in6_addr *v6daddr, extern void inet_putpeer(struct inet_peer *p); extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); +extern void inetpeer_invalidate_tree(int family); + /* * temporary check to make sure we dont access rid, ip_id_count, tcp_ts, * tcp_ts_stamp if no refcount is taken on inet_peer diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index bf4a9c4808e..deea2e96b7f 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,11 @@ static struct kmem_cache *peer_cachep __read_mostly; +static LIST_HEAD(gc_list); +static const int gc_delay = 60 * HZ; +static struct delayed_work gc_work; +static DEFINE_SPINLOCK(gc_lock); + #define node_height(x) x->avl_height #define peer_avl_empty ((struct inet_peer *)&peer_fake_node) @@ -102,6 +108,50 @@ int inet_peer_threshold __read_mostly = 65536 + 128; /* start to throw entries m int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */ int inet_peer_maxttl __read_mostly = 10 * 60 * HZ; /* usual time to live: 10 min */ +static void inetpeer_gc_worker(struct work_struct *work) +{ + struct inet_peer *p, *n; + LIST_HEAD(list); + + spin_lock_bh(&gc_lock); + list_replace_init(&gc_list, &list); + spin_unlock_bh(&gc_lock); + + if (list_empty(&list)) + return; + + list_for_each_entry_safe(p, n, &list, gc_list) { + + if(need_resched()) + cond_resched(); + + if (p->avl_left != peer_avl_empty) { + list_add_tail(&p->avl_left->gc_list, &list); + p->avl_left = peer_avl_empty; + } + + if (p->avl_right != peer_avl_empty) { + list_add_tail(&p->avl_right->gc_list, &list); + p->avl_right = peer_avl_empty; + } + + n = list_entry(p->gc_list.next, struct inet_peer, gc_list); + + if (!atomic_read(&p->refcnt)) { + list_del(&p->gc_list); + kmem_cache_free(peer_cachep, p); + } + } + + if (list_empty(&list)) + return; + + spin_lock_bh(&gc_lock); + list_splice(&list, &gc_list); + spin_unlock_bh(&gc_lock); + + schedule_delayed_work(&gc_work, gc_delay); +} /* Called from ip_output.c:ip_init */ void __init inet_initpeers(void) @@ -126,6 +176,7 @@ void __init inet_initpeers(void) 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); + INIT_DELAYED_WORK_DEFERRABLE(&gc_work, inetpeer_gc_worker); } static int addr_compare(const struct inetpeer_addr *a, @@ -449,7 +500,7 @@ relookup: p->pmtu_orig = 0; p->redirect_genid = 0; memset(&p->redirect_learned, 0, sizeof(p->redirect_learned)); - + INIT_LIST_HEAD(&p->gc_list); /* Link the node. */ link_to_pool(p, base); @@ -509,3 +560,30 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout) return rc; } EXPORT_SYMBOL(inet_peer_xrlim_allow); + +void inetpeer_invalidate_tree(int family) +{ + struct inet_peer *old, *new, *prev; + struct inet_peer_base *base = family_to_base(family); + + write_seqlock_bh(&base->lock); + + old = base->root; + if (old == peer_avl_empty_rcu) + goto out; + + new = peer_avl_empty_rcu; + + prev = cmpxchg(&base->root, old, new); + if (prev == old) { + base->total = 0; + spin_lock(&gc_lock); + list_add_tail(&prev->gc_list, &gc_list); + spin_unlock(&gc_lock); + schedule_delayed_work(&gc_work, gc_delay); + } + +out: + write_sequnlock_bh(&base->lock); +} +EXPORT_SYMBOL(inetpeer_invalidate_tree); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bcacf54e541..23ce0c1287a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -938,6 +938,7 @@ static void rt_cache_invalidate(struct net *net) get_random_bytes(&shuffle, sizeof(shuffle)); atomic_add(shuffle + 1U, &net->ipv4.rt_genid); redirect_genid++; + inetpeer_invalidate_tree(AF_INET); } /* -- cgit v1.2.3-70-g09d2 From ac3f48de09d8f4b73397047e413fadff7f65cfa7 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Tue, 6 Mar 2012 21:21:10 +0000 Subject: route: Remove redirect_genid As we invalidate the inetpeer tree along with the routing cache now, we don't need a genid to reset the redirect handling when the routing cache is flushed. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- include/net/inetpeer.h | 1 - net/ipv4/inetpeer.c | 1 - net/ipv4/route.c | 11 ++--------- 3 files changed, 2 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index ff04a33acf0..b94765e38e8 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -35,7 +35,6 @@ struct inet_peer { u32 metrics[RTAX_MAX]; u32 rate_tokens; /* rate limiting for ICMP */ - int redirect_genid; unsigned long rate_last; unsigned long pmtu_expires; u32 pmtu_orig; diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index deea2e96b7f..d4d61b694fa 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -498,7 +498,6 @@ relookup: p->rate_last = 0; p->pmtu_expires = 0; p->pmtu_orig = 0; - p->redirect_genid = 0; memset(&p->redirect_learned, 0, sizeof(p->redirect_learned)); INIT_LIST_HEAD(&p->gc_list); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 23ce0c1287a..01977479617 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -132,7 +132,6 @@ static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; static int ip_rt_min_advmss __read_mostly = 256; static int rt_chain_length_max __read_mostly = 20; -static int redirect_genid; static struct delayed_work expires_work; static unsigned long expires_ljiffies; @@ -937,7 +936,6 @@ static void rt_cache_invalidate(struct net *net) get_random_bytes(&shuffle, sizeof(shuffle)); atomic_add(shuffle + 1U, &net->ipv4.rt_genid); - redirect_genid++; inetpeer_invalidate_tree(AF_INET); } @@ -1486,10 +1484,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, peer = rt->peer; if (peer) { - if (peer->redirect_learned.a4 != new_gw || - peer->redirect_genid != redirect_genid) { + if (peer->redirect_learned.a4 != new_gw) { peer->redirect_learned.a4 = new_gw; - peer->redirect_genid = redirect_genid; atomic_inc(&__rt_peer_genid); } check_peer_redir(&rt->dst, peer); @@ -1794,8 +1790,6 @@ static void ipv4_validate_peer(struct rtable *rt) if (peer) { check_peer_pmtu(&rt->dst, peer); - if (peer->redirect_genid != redirect_genid) - peer->redirect_learned.a4 = 0; if (peer->redirect_learned.a4 && peer->redirect_learned.a4 != rt->rt_gateway) check_peer_redir(&rt->dst, peer); @@ -1959,8 +1953,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4, dst_init_metrics(&rt->dst, peer->metrics, false); check_peer_pmtu(&rt->dst, peer); - if (peer->redirect_genid != redirect_genid) - peer->redirect_learned.a4 = 0; + if (peer->redirect_learned.a4 && peer->redirect_learned.a4 != rt->rt_gateway) { rt->rt_gateway = peer->redirect_learned.a4; -- cgit v1.2.3-70-g09d2 From 2f16669d322e05171c9e1cfd94f402f7399bd2a3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:52 +0100 Subject: TTY: remove re-assignments to tty_driver members All num, magic and owner are set by alloc_tty_driver. No need to re-set them on each allocation site. pti driver sets something different to what it passes to alloc_tty_driver. It is not a bug, since we don't use the lines parameter in any way. Anyway this is fixed, and now we do the right thing. Signed-off-by: Jiri Slaby Acked-by: Tilman Schmidt Signed-off-by: Greg Kroah-Hartman --- arch/ia64/hp/sim/simserial.c | 1 - arch/m68k/emu/nfcon.c | 1 - arch/xtensa/platforms/iss/console.c | 1 - drivers/char/pcmcia/synclink_cs.c | 1 - drivers/char/ttyprintk.c | 2 -- drivers/isdn/capi/capi.c | 1 - drivers/isdn/gigaset/interface.c | 7 +------ drivers/misc/pti.c | 5 +---- drivers/mmc/card/sdio_uart.c | 1 - drivers/net/usb/hso.c | 2 -- drivers/s390/char/con3215.c | 1 - drivers/s390/char/sclp_tty.c | 1 - drivers/s390/char/sclp_vt220.c | 1 - drivers/s390/char/tty3270.c | 1 - drivers/tty/amiserial.c | 1 - drivers/tty/bfin_jtag_comm.c | 1 - drivers/tty/cyclades.c | 1 - drivers/tty/ehv_bytechan.c | 1 - drivers/tty/hvc/hvc_console.c | 1 - drivers/tty/hvc/hvcs.c | 2 -- drivers/tty/hvc/hvsi.c | 1 - drivers/tty/ipwireless/tty.c | 1 - drivers/tty/isicom.c | 1 - drivers/tty/moxa.c | 1 - drivers/tty/mxser.c | 3 --- drivers/tty/n_gsm.c | 1 - drivers/tty/nozomi.c | 1 - drivers/tty/pty.c | 4 ---- drivers/tty/rocket.c | 1 - drivers/tty/serial/ifx6x60.c | 3 --- drivers/tty/serial/msm_smd_tty.c | 1 - drivers/tty/serial/serial_core.c | 1 - drivers/tty/synclink.c | 1 - drivers/tty/synclink_gt.c | 1 - drivers/tty/synclinkmp.c | 1 - drivers/tty/vt/vt.c | 2 +- drivers/usb/class/cdc-acm.c | 1 - drivers/usb/gadget/u_serial.c | 1 - drivers/usb/serial/usb-serial.c | 1 - net/bluetooth/rfcomm/tty.c | 1 - net/irda/ircomm/ircomm_tty.c | 1 - 41 files changed, 3 insertions(+), 59 deletions(-) (limited to 'net') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index bff0824cf8a..f513dc02bb8 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -928,7 +928,6 @@ simrs_init (void) /* Initialize the tty_driver structure */ - hp_simserial_driver->owner = THIS_MODULE; hp_simserial_driver->driver_name = "simserial"; hp_simserial_driver->name = "ttyS"; hp_simserial_driver->major = TTY_MAJOR; diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c index ab20dc0ff63..8db25e80694 100644 --- a/arch/m68k/emu/nfcon.c +++ b/arch/m68k/emu/nfcon.c @@ -127,7 +127,6 @@ static int __init nfcon_init(void) if (!nfcon_tty_driver) return -ENOMEM; - nfcon_tty_driver->owner = THIS_MODULE; nfcon_tty_driver->driver_name = "nfcon"; nfcon_tty_driver->name = "nfcon"; nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 2c723e8b30d..247e9d40a52 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -216,7 +216,6 @@ int __init rs_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "iss_serial"; serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 07f6a5abe37..c3bcb1221e6 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2836,7 +2836,6 @@ static int __init synclink_cs_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "synclink_cs"; serial_driver->name = "ttySLP"; serial_driver->major = ttymajor; diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index eedd5474850..46b77ede84c 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -184,12 +184,10 @@ static int __init ttyprintk_init(void) if (!ttyprintk_driver) return ret; - ttyprintk_driver->owner = THIS_MODULE; ttyprintk_driver->driver_name = "ttyprintk"; ttyprintk_driver->name = "ttyprintk"; ttyprintk_driver->major = TTYAUX_MAJOR; ttyprintk_driver->minor_start = 3; - ttyprintk_driver->num = 1; ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; ttyprintk_driver->init_termios = tty_std_termios; ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 94948be5d36..baf08eba495 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1287,7 +1287,6 @@ static int __init capinc_tty_init(void) kfree(capiminors); return -ENOMEM; } - drv->owner = THIS_MODULE; drv->driver_name = "capi_nc"; drv->name = "capi"; drv->major = 0; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index ee0a549a933..648260b07f1 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -669,17 +669,15 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive); void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, const char *devname) { - unsigned minors = drv->minors; int ret; struct tty_driver *tty; drv->have_tty = 0; - drv->tty = tty = alloc_tty_driver(minors); + drv->tty = tty = alloc_tty_driver(drv->minors); if (tty == NULL) goto enomem; - tty->magic = TTY_DRIVER_MAGIC, tty->type = TTY_DRIVER_TYPE_SERIAL, tty->subtype = SERIAL_TYPE_NORMAL, tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; @@ -687,9 +685,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, tty->driver_name = procname; tty->name = devname; tty->minor_start = drv->minor; - tty->num = drv->minors; - - tty->owner = THIS_MODULE; tty->init_termios = tty_std_termios; tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 9a35db3d27f..383133b201a 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -907,20 +907,17 @@ static int __init pti_init(void) /* First register module as tty device */ - pti_tty_driver = alloc_tty_driver(1); + pti_tty_driver = alloc_tty_driver(PTITTY_MINOR_NUM); if (pti_tty_driver == NULL) { pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n", __func__, __LINE__); return -ENOMEM; } - pti_tty_driver->owner = THIS_MODULE; - pti_tty_driver->magic = TTY_DRIVER_MAGIC; pti_tty_driver->driver_name = DRIVERNAME; pti_tty_driver->name = TTYNAME; pti_tty_driver->major = 0; pti_tty_driver->minor_start = PTITTY_MINOR_START; - pti_tty_driver->num = PTITTY_MINOR_NUM; pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS; pti_tty_driver->flags = TTY_DRIVER_REAL_RAW | diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index bd4a67cdac3..5a2cbfac66d 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -1175,7 +1175,6 @@ static int __init sdio_uart_init(void) if (!tty_drv) return -ENOMEM; - tty_drv->owner = THIS_MODULE; tty_drv->driver_name = "sdio_uart"; tty_drv->name = "ttySDIO"; tty_drv->major = 0; /* dynamically allocated */ diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 304fe78ff60..a73090f4c68 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -3313,7 +3313,6 @@ static int __init hso_init(void) /* fill in all needed values */ tty_drv->magic = TTY_DRIVER_MAGIC; - tty_drv->owner = THIS_MODULE; tty_drv->driver_name = driver_name; tty_drv->name = tty_filename; @@ -3322,7 +3321,6 @@ static int __init hso_init(void) tty_drv->major = tty_major; tty_drv->minor_start = 0; - tty_drv->num = HSO_SERIAL_TTY_MINORS; tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->subtype = SERIAL_TYPE_NORMAL; tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 934458ad55e..fe916bfd60f 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1137,7 +1137,6 @@ static int __init tty3215_init(void) * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc */ - driver->owner = THIS_MODULE; driver->driver_name = "tty3215"; driver->name = "ttyS"; driver->major = TTY_MAJOR; diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index a879c139926..40a9d69c898 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -551,7 +551,6 @@ sclp_tty_init(void) return rc; } - driver->owner = THIS_MODULE; driver->driver_name = "sclp_line"; driver->name = "sclp_line"; driver->major = TTY_MAJOR; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 5d706e6c946..b635472ae66 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -685,7 +685,6 @@ static int __init sclp_vt220_tty_init(void) if (rc) goto out_driver; - driver->owner = THIS_MODULE; driver->driver_name = SCLP_VT220_DRIVER_NAME; driver->name = SCLP_VT220_DEVICE_NAME; driver->major = SCLP_VT220_MAJOR; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 2db1482b406..b43445a55cb 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1784,7 +1784,6 @@ static int __init tty3270_init(void) * Entries in tty3270_driver that are NOT initialized: * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc */ - driver->owner = THIS_MODULE; driver->driver_name = "ttyTUB"; driver->name = "ttyTUB"; driver->major = IBM_TTY3270_MAJOR; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b84c83456dc..b42f00d987a 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1974,7 +1974,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "amiserial"; serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 3a997760ec3..946f799861f 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -257,7 +257,6 @@ static int __init bfin_jc_init(void) if (!bfin_jc_driver) goto err_driver; - bfin_jc_driver->owner = THIS_MODULE; bfin_jc_driver->driver_name = DRV_NAME; bfin_jc_driver->name = DEV_NAME; bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 5575fee7a55..bc7b5a5650b 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -4090,7 +4090,6 @@ static int __init cy_init(void) /* Initialize the tty_driver structure */ - cy_serial_driver->owner = THIS_MODULE; cy_serial_driver->driver_name = "cyclades"; cy_serial_driver->name = "ttyC"; cy_serial_driver->major = CYCLADES_MAJOR; diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 1595dba0072..4813684cb63 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -825,7 +825,6 @@ static int __init ehv_bc_init(void) goto error; } - ehv_bc_driver->owner = THIS_MODULE; ehv_bc_driver->driver_name = "ehv-bc"; ehv_bc_driver->name = ehv_bc_console.name; ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE; diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index b6b2d18fa38..8880adf5fc6 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -917,7 +917,6 @@ static int hvc_init(void) goto out; } - drv->owner = THIS_MODULE; drv->driver_name = "hvc"; drv->name = "hvc"; drv->major = HVC_MAJOR; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index df7e7a0a5e6..da0aa476804 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1499,8 +1499,6 @@ static int __devinit hvcs_initialize(void) goto index_fail; } - hvcs_tty_driver->owner = THIS_MODULE; - hvcs_tty_driver->driver_name = hvcs_driver_name; hvcs_tty_driver->name = hvcs_device_node; diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 1b5f28bd793..60bc4516418 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -1088,7 +1088,6 @@ static int __init hvsi_init(void) if (!hvsi_driver) return -ENOMEM; - hvsi_driver->owner = THIS_MODULE; hvsi_driver->driver_name = "hvsi"; hvsi_driver->name = "hvsi"; hvsi_driver->major = HVSI_MAJOR; diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index ef92869502a..6990b3b649d 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -614,7 +614,6 @@ int ipwireless_tty_init(void) if (!ipw_tty_driver) return -ENOMEM; - ipw_tty_driver->owner = THIS_MODULE; ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; ipw_tty_driver->name = "ttyIPWp"; ipw_tty_driver->major = 0; diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index e5c295ab5de..b3a28b5f02a 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -1678,7 +1678,6 @@ static int __init isicom_init(void) goto error; } - isicom_normal->owner = THIS_MODULE; isicom_normal->name = "ttyM"; isicom_normal->major = ISICOM_NMAJOR; isicom_normal->minor_start = 0; diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index d15a071b1a5..4a26323a926 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1036,7 +1036,6 @@ static int __init moxa_init(void) if (!moxaDriver) return -ENOMEM; - moxaDriver->owner = THIS_MODULE; moxaDriver->name = "ttyMX"; moxaDriver->major = ttymajor; moxaDriver->minor_start = 0; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8998d527232..260d0312352 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -2658,12 +2658,9 @@ static int __init mxser_module_init(void) MXSER_VERSION); /* Initialize the tty_driver structure */ - mxvar_sdriver->owner = THIS_MODULE; - mxvar_sdriver->magic = TTY_DRIVER_MAGIC; mxvar_sdriver->name = "ttyMI"; mxvar_sdriver->major = ttymajor; mxvar_sdriver->minor_start = 0; - mxvar_sdriver->num = MXSER_PORTS + 1; mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL; mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; mxvar_sdriver->init_termios = tty_std_termios; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index fc7bbba585c..c43b683b6eb 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3120,7 +3120,6 @@ static int __init gsm_init(void) pr_err("gsm_init: tty allocation failed.\n"); return -EINVAL; } - gsm_tty_driver->owner = THIS_MODULE; gsm_tty_driver->driver_name = "gsmtty"; gsm_tty_driver->name = "gsmtty"; gsm_tty_driver->major = 0; /* Dynamic */ diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 580da78b2d8..e7592f9037d 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1916,7 +1916,6 @@ static __init int nozomi_init(void) if (!ntty_driver) return -ENOMEM; - ntty_driver->owner = THIS_MODULE; ntty_driver->driver_name = NOZOMI_NAME_TTY; ntty_driver->name = "noz"; ntty_driver->major = 0; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index d505837b347..f96ecaec24f 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -393,7 +393,6 @@ static void __init legacy_pty_init(void) if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); - pty_driver->owner = THIS_MODULE; pty_driver->driver_name = "pty_master"; pty_driver->name = "pty"; pty_driver->major = PTY_MASTER_MAJOR; @@ -411,7 +410,6 @@ static void __init legacy_pty_init(void) pty_driver->other = pty_slave_driver; tty_set_operations(pty_driver, &master_pty_ops_bsd); - pty_slave_driver->owner = THIS_MODULE; pty_slave_driver->driver_name = "pty_slave"; pty_slave_driver->name = "ttyp"; pty_slave_driver->major = PTY_SLAVE_MAJOR; @@ -671,7 +669,6 @@ static void __init unix98_pty_init(void) if (!pts_driver) panic("Couldn't allocate Unix98 pts driver"); - ptm_driver->owner = THIS_MODULE; ptm_driver->driver_name = "pty_master"; ptm_driver->name = "ptm"; ptm_driver->major = UNIX98_PTY_MASTER_MAJOR; @@ -690,7 +687,6 @@ static void __init unix98_pty_init(void) ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &ptm_unix98_ops); - pts_driver->owner = THIS_MODULE; pts_driver->driver_name = "pty_slave"; pts_driver->name = "pts"; pts_driver->major = UNIX98_PTY_SLAVE_MAJOR; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index de88aa5566e..b088e1ea433 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -2277,7 +2277,6 @@ static int __init rp_init(void) * driver with the tty layer. */ - rocket_driver->owner = THIS_MODULE; rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; rocket_driver->name = "ttyR"; rocket_driver->driver_name = "Comtrol RocketPort"; diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 7e925e20cba..144cd3987d4 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1375,12 +1375,9 @@ static int __init ifx_spi_init(void) return -ENOMEM; } - tty_drv->magic = TTY_DRIVER_MAGIC; - tty_drv->owner = THIS_MODULE; tty_drv->driver_name = DRVNAME; tty_drv->name = TTYNAME; tty_drv->minor_start = IFX_SPI_TTY_ID; - tty_drv->num = 1; tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->subtype = SERIAL_TYPE_NORMAL; tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c index 4f41dcdcb77..b25e6ee7144 100644 --- a/drivers/tty/serial/msm_smd_tty.c +++ b/drivers/tty/serial/msm_smd_tty.c @@ -203,7 +203,6 @@ static int __init smd_tty_init(void) if (smd_tty_driver == 0) return -ENOMEM; - smd_tty_driver->owner = THIS_MODULE; smd_tty_driver->driver_name = "smd_tty_driver"; smd_tty_driver->name = "smd"; smd_tty_driver->major = 0; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 13056180adf..9c4c05b2825 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2230,7 +2230,6 @@ int uart_register_driver(struct uart_driver *drv) drv->tty_driver = normal; - normal->owner = drv->owner; normal->driver_name = drv->driver_name; normal->name = drv->dev_name; normal->major = drv->major; diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index ff8017f8791..2b2988c779c 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -4333,7 +4333,6 @@ static int mgsl_init_tty(void) if (!serial_driver) return -ENOMEM; - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "synclink"; serial_driver->name = "ttySL"; serial_driver->major = ttymajor; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 18b48cd3b41..a8b66be37e6 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3795,7 +3795,6 @@ static int __init slgt_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = tty_driver_name; serial_driver->name = tty_dev_prefix; serial_driver->major = ttymajor; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index a7efe538df0..ddabb61c85b 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -3977,7 +3977,6 @@ static int __init synclinkmp_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "synclinkmp"; serial_driver->name = "ttySLM"; serial_driver->major = ttymajor; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e5abceacc2d..84c4a7d5603 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2994,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops) console_driver = alloc_tty_driver(MAX_NR_CONSOLES); if (!console_driver) panic("Couldn't allocate console driver\n"); - console_driver->owner = THIS_MODULE; + console_driver->name = "tty"; console_driver->name_base = 1; console_driver->major = TTY_MAJOR; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 11a1130319d..6bb8472155c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1670,7 +1670,6 @@ static int __init acm_init(void) acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); if (!acm_tty_driver) return -ENOMEM; - acm_tty_driver->owner = THIS_MODULE, acm_tty_driver->driver_name = "acm", acm_tty_driver->name = "ttyACM", acm_tty_driver->major = ACM_TTY_MAJOR, diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 6597a6813e4..490b01dd5d6 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1087,7 +1087,6 @@ int __init gserial_setup(struct usb_gadget *g, unsigned count) if (!gs_tty_driver) return -ENOMEM; - gs_tty_driver->owner = THIS_MODULE; gs_tty_driver->driver_name = "g_serial"; gs_tty_driver->name = PREFIX; /* uses dynamically assigned dev_t values */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 1e30cc92719..d4e724d9b1f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1235,7 +1235,6 @@ static int __init usb_serial_init(void) goto exit_bus; } - usb_serial_tty_driver->owner = THIS_MODULE; usb_serial_tty_driver->driver_name = "usbserial"; usb_serial_tty_driver->name = "ttyUSB"; usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a2d4f5122a6..7adb03ca51c 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1157,7 +1157,6 @@ int __init rfcomm_init_ttys(void) if (!rfcomm_tty_driver) return -ENOMEM; - rfcomm_tty_driver->owner = THIS_MODULE; rfcomm_tty_driver->driver_name = "rfcomm"; rfcomm_tty_driver->name = "rfcomm"; rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 253695d43fd..828f88603d6 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -122,7 +122,6 @@ static int __init ircomm_tty_init(void) return -ENOMEM; } - driver->owner = THIS_MODULE; driver->driver_name = "ircomm"; driver->name = "ircomm"; driver->major = IRCOMM_TTY_MAJOR; -- cgit v1.2.3-70-g09d2 From 410235fd4d20b8feaf8930a0575d23acc088aa87 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:01 +0100 Subject: TTY: remove unneeded tty->index checks Checking if tty->index is in bounds is not needed. The tty has the index set in the initial open. This is done in get_tty_driver. And it can be only in interval <0,driver->num). So remove the tests which check exactly this interval. Some are left untouched as they check against the current backing device count. (Leaving apart that the check is racy in most of the cases.) Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- arch/ia64/hp/sim/simserial.c | 9 +++------ arch/xtensa/platforms/iss/console.c | 8 ++------ drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/isdn/capi/capi.c | 3 +-- drivers/isdn/gigaset/common.c | 2 -- drivers/isdn/i4l/isdn_tty.c | 7 ++----- drivers/s390/char/con3215.c | 8 ++------ drivers/tty/amiserial.c | 10 +++------- drivers/tty/cyclades.c | 6 +----- drivers/tty/hvc/hvcs.c | 24 ++++++++++-------------- drivers/tty/hvc/hvsi.c | 5 +---- drivers/tty/isicom.c | 2 -- drivers/tty/mxser.c | 2 -- drivers/tty/rocket.c | 6 +++--- drivers/tty/serial/68328serial.c | 9 ++------- drivers/tty/serial/crisv10.c | 15 +++------------ drivers/tty/synclink.c | 2 +- drivers/tty/synclink_gt.c | 2 +- drivers/tty/synclinkmp.c | 2 +- drivers/usb/gadget/u_serial.c | 3 --- net/irda/ircomm/ircomm_tty.c | 6 +----- 21 files changed, 38 insertions(+), 95 deletions(-) (limited to 'net') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index f513dc02bb8..2a2fe0c5611 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -769,13 +769,10 @@ errout: static int rs_open(struct tty_struct *tty, struct file * filp) { struct async_struct *info; - int retval, line; + int retval; unsigned long page; - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - retval = get_async_struct(line, &info); + retval = get_async_struct(tty->index, &info); if (retval) return retval; tty->driver_data = info; @@ -920,7 +917,7 @@ simrs_init (void) if (!ia64_platform_is("hpsim")) return -ENODEV; - hp_simserial_driver = alloc_tty_driver(1); + hp_simserial_driver = alloc_tty_driver(NR_PORTS); if (!hp_simserial_driver) return -ENOMEM; diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 247e9d40a52..19a802a1309 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -68,11 +68,6 @@ static void rs_poll(unsigned long); static int rs_open(struct tty_struct *tty, struct file * filp) { - int line = tty->index; - - if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES)) - return -ENODEV; - spin_lock(&timer_lock); if (tty->count == 1) { @@ -101,6 +96,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) { spin_lock(&timer_lock); if (tty->count == 1) + /* this will cause a deadlock if the timer ticks right now */ del_timer_sync(&serial_timer); spin_unlock(&timer_lock); } @@ -210,7 +206,7 @@ static const struct tty_operations serial_ops = { int __init rs_init(void) { - serial_driver = alloc_tty_driver(1); + serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES); printk ("%s %s\n", serial_name, serial_version); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index c3bcb1221e6..f6453df4921 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2484,7 +2484,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) /* verify range of specified line number */ line = tty->index; - if ((line < 0) || (line >= mgslpc_device_count)) { + if (line >= mgslpc_device_count) { printk("%s(%d):mgslpc_open with invalid line #%d.\n", __FILE__,__LINE__,line); return -ENODEV; diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index baf08eba495..3a7905b06e5 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1013,8 +1013,7 @@ static const struct file_operations capi_fops = static int capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty) { - int idx = tty->index; - struct capiminor *mp = capiminor_get(idx); + struct capiminor *mp = capiminor_get(tty->index); int ret = tty_standard_install(driver, tty); if (ret == 0) diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index db621db67f6..ac0186e54bf 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -1051,8 +1051,6 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) { - if (tty->index < 0 || tty->index >= tty->driver->num) - return NULL; return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); } diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 2c26b64ebbe..ac4840124bc 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1590,12 +1590,9 @@ static int isdn_tty_open(struct tty_struct *tty, struct file *filp) { modem_info *info; - int retval, line; + int retval; - line = tty->index; - if (line < 0 || line >= ISDN_MAX_CHANNELS) - return -ENODEV; - info = &dev->mdm.info[line]; + info = &dev->mdm.info[tty->index]; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) return -ENODEV; if (!try_module_get(info->owner)) { diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index fe916bfd60f..ed23fec7abb 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -926,13 +926,9 @@ console_initcall(con3215_init); static int tty3215_open(struct tty_struct *tty, struct file * filp) { struct raw3215_info *raw; - int retval, line; + int retval; - line = tty->index; - if ((line < 0) || (line >= NR_3215)) - return -ENODEV; - - raw = raw3215[line]; + raw = raw3215[tty->index]; if (raw == NULL) return -ENODEV; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b42f00d987a..75328625755 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1768,13 +1768,9 @@ static int get_async_struct(int line, struct async_struct **ret_info) static int rs_open(struct tty_struct *tty, struct file * filp) { struct async_struct *info; - int retval, line; + int retval; - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) { - return -ENODEV; - } - retval = get_async_struct(line, &info); + retval = get_async_struct(tty->index, &info); if (retval) { return retval; } @@ -1964,7 +1960,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev) struct serial_state * state; int error; - serial_driver = alloc_tty_driver(1); + serial_driver = alloc_tty_driver(NR_PORTS); if (!serial_driver) return -ENOMEM; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index bc7b5a5650b..e61cabdd69d 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1515,13 +1515,9 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) static int cy_open(struct tty_struct *tty, struct file *filp) { struct cyclades_port *info; - unsigned int i, line; + unsigned int i, line = tty->index; int retval; - line = tty->index; - if (tty->index < 0 || NR_PORTS <= line) - return -ENODEV; - for (i = 0; i < NR_CARDS; i++) if (line < cy_card[i].first_line + cy_card[i].nports && line >= cy_card[i].first_line) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index da0aa476804..d23759183b4 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1090,27 +1090,23 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, */ static struct hvcs_struct *hvcs_get_by_index(int index) { - struct hvcs_struct *hvcsd = NULL; + struct hvcs_struct *hvcsd; unsigned long flags; spin_lock(&hvcs_structs_lock); - /* We can immediately discard OOB requests */ - if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { - list_for_each_entry(hvcsd, &hvcs_structs, next) { - spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->index == index) { - kref_get(&hvcsd->kref); - spin_unlock_irqrestore(&hvcsd->lock, flags); - spin_unlock(&hvcs_structs_lock); - return hvcsd; - } + list_for_each_entry(hvcsd, &hvcs_structs, next) { + spin_lock_irqsave(&hvcsd->lock, flags); + if (hvcsd->index == index) { + kref_get(&hvcsd->kref); spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcs_structs_lock); + return hvcsd; } - hvcsd = NULL; + spin_unlock_irqrestore(&hvcsd->lock, flags); } - spin_unlock(&hvcs_structs_lock); - return hvcsd; + + return NULL; } /* diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 60bc4516418..a7488b74864 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -737,14 +737,11 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) { struct hvsi_struct *hp; unsigned long flags; - int line = tty->index; int ret; pr_debug("%s\n", __func__); - if (line < 0 || line >= hvsi_count) - return -ENODEV; - hp = &hvsi_ports[line]; + hp = &hvsi_ports[tty->index]; tty->driver_data = hp; diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index b3a28b5f02a..03c14979acc 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -849,8 +849,6 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty) unsigned int board; int line = tty->index; - if (line < 0 || line > PORT_COUNT-1) - return NULL; board = BOARD(line); card = &isi_card[board]; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 260d0312352..17ff377e412 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1010,8 +1010,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) line = tty->index; if (line == MXSER_PORTS) return 0; - if (line < 0 || line > MXSER_PORTS) - return -ENODEV; info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD]; if (!info->ioaddr) return -ENODEV; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index b088e1ea433..777d5f9cf6c 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -892,12 +892,12 @@ static int rp_open(struct tty_struct *tty, struct file *filp) { struct r_port *info; struct tty_port *port; - int line = 0, retval; + int retval; CHANNEL_t *cp; unsigned long page; - line = tty->index; - if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL)) + info = rp_table[tty->index]; + if (info == NULL) return -ENXIO; port = &info->port; diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index a88ef9782a4..7398390e7e6 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -1190,14 +1190,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, int rs_open(struct tty_struct *tty, struct file * filp) { struct m68k_serial *info; - int retval, line; - - line = tty->index; - - if (line >= NR_PORTS || line < 0) /* we have exactly one */ - return -ENODEV; + int retval; - info = &m68k_soft[line]; + info = &m68k_soft[tty->index]; if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 1dfba7b779c..23d79169687 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -4105,20 +4105,11 @@ static int rs_open(struct tty_struct *tty, struct file * filp) { struct e100_serial *info; - int retval, line; + int retval; unsigned long page; int allocated_resources = 0; - /* find which port we want to open */ - line = tty->index; - - if (line < 0 || line >= NR_PORTS) - return -ENODEV; - - /* find the corresponding e100_serial struct in the table */ - info = rs_table + line; - - /* don't allow the opening of ports that are not enabled in the HW config */ + info = rs_table + tty->index; if (!info->enabled) return -ENODEV; @@ -4131,7 +4122,7 @@ rs_open(struct tty_struct *tty, struct file * filp) tty->driver_data = info; info->port.tty = tty; - info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 2b2988c779c..8e518da85fd 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3381,7 +3381,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) /* verify range of specified line number */ line = tty->index; - if ((line < 0) || (line >= mgsl_device_count)) { + if (line >= mgsl_device_count) { printk("%s(%d):mgsl_open with invalid line #%d.\n", __FILE__,__LINE__,line); return -ENODEV; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index a8b66be37e6..6bee4907c6a 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -654,7 +654,7 @@ static int open(struct tty_struct *tty, struct file *filp) unsigned long flags; line = tty->index; - if ((line < 0) || (line >= slgt_device_count)) { + if (line >= slgt_device_count) { DBGERR(("%s: open with invalid line #%d.\n", driver_name, line)); return -ENODEV; } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index ddabb61c85b..4fb6c4b31b7 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -721,7 +721,7 @@ static int open(struct tty_struct *tty, struct file *filp) unsigned long flags; line = tty->index; - if ((line < 0) || (line >= synclinkmp_device_count)) { + if (line >= synclinkmp_device_count) { printk("%s(%d): open with invalid line #%d.\n", __FILE__,__LINE__,line); return -ENODEV; diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 490b01dd5d6..6c23938d271 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -725,9 +725,6 @@ static int gs_open(struct tty_struct *tty, struct file *file) struct gs_port *port; int status; - if (port_num < 0 || port_num >= n_ports) - return -ENXIO; - do { mutex_lock(&ports[port_num].lock); port = ports[port_num].port; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 828f88603d6..6b9d5a0e42f 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -365,16 +365,12 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) { struct ircomm_tty_cb *self; - unsigned int line; + unsigned int line = tty->index; unsigned long flags; int ret; IRDA_DEBUG(2, "%s()\n", __func__ ); - line = tty->index; - if (line >= IRCOMM_TTY_PORTS) - return -ENODEV; - /* Check if instance already exists */ self = hashbin_lock_find(ircomm_tty, line, NULL); if (!self) { -- cgit v1.2.3-70-g09d2 From 0343c5543b1d3ffa08e6716d82afb62648b80eba Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 8 Mar 2012 05:55:58 +0000 Subject: sctp: Export sctp_do_peeloff lookup sctp_association within sctp_do_peeloff() to enable its use outside of the sctp code with minimal knowledge of the former. Signed-off-by: Benjamin Poirier Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 1 + net/sctp/socket.c | 24 +++++++++--------------- 2 files changed, 10 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index d3685615a8b..6ee44b24864 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -413,6 +413,7 @@ static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc) /* Look up the association by its id. */ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); +int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp); /* A macro to walk a list of skbs. */ #define sctp_skb_for_each(pos, head, tmp) \ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 408ebd0e733..06b42b7f5a0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4170,14 +4170,16 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv } /* Helper routine to branch off an association to a new socket. */ -SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, - struct socket **sockp) +int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) { - struct sock *sk = asoc->base.sk; + struct sctp_association *asoc = sctp_id2assoc(sk, id); struct socket *sock; struct sctp_af *af; int err = 0; + if (!asoc) + return -EINVAL; + /* An association cannot be branched off from an already peeled-off * socket, nor is this supported for tcp style sockets. */ @@ -4206,13 +4208,13 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, return err; } +EXPORT_SYMBOL(sctp_do_peeloff); static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) { sctp_peeloff_arg_t peeloff; struct socket *newsock; int retval = 0; - struct sctp_association *asoc; if (len < sizeof(sctp_peeloff_arg_t)) return -EINVAL; @@ -4220,15 +4222,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval if (copy_from_user(&peeloff, optval, len)) return -EFAULT; - asoc = sctp_id2assoc(sk, peeloff.associd); - if (!asoc) { - retval = -EINVAL; - goto out; - } - - SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc); - - retval = sctp_do_peeloff(asoc, &newsock); + retval = sctp_do_peeloff(sk, peeloff.associd, &newsock); if (retval < 0) goto out; @@ -4239,8 +4233,8 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval goto out; } - SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n", - __func__, sk, asoc, newsock->sk, retval); + SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n", + __func__, sk, newsock->sk, retval); /* Return the fd mapped to the new socket. */ peeloff.sd = retval; -- cgit v1.2.3-70-g09d2 From ba57b4db2624793c6eb8f2c051c9f7b8a6e7b6a6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 7 Mar 2012 20:45:32 -0500 Subject: ipv4: Make ip_call_ra_chain() return bool. Signed-off-by: David S. Miller --- include/net/ip.h | 2 +- net/ipv4/ip_input.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/ip.h b/include/net/ip.h index 775009f9eab..b53d65f24f7 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -388,7 +388,7 @@ static inline int sk_mc_loop(struct sock *sk) return 1; } -extern int ip_call_ra_chain(struct sk_buff *skb); +extern bool ip_call_ra_chain(struct sk_buff *skb); /* * Functions provided by ip_fragment.c diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 073a9b01c40..70afe5bf194 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -148,7 +148,7 @@ /* * Process Router Attention IP option (RFC 2113) */ -int ip_call_ra_chain(struct sk_buff *skb) +bool ip_call_ra_chain(struct sk_buff *skb) { struct ip_ra_chain *ra; u8 protocol = ip_hdr(skb)->protocol; @@ -167,7 +167,7 @@ int ip_call_ra_chain(struct sk_buff *skb) net_eq(sock_net(sk), dev_net(dev))) { if (ip_is_fragment(ip_hdr(skb))) { if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) - return 1; + return true; } if (last) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); @@ -180,9 +180,9 @@ int ip_call_ra_chain(struct sk_buff *skb) if (last) { raw_rcv(last, skb); - return 1; + return true; } - return 0; + return false; } static int ip_local_deliver_finish(struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 6a91395f20119d696330e2604451614a64369d1b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 7 Mar 2012 20:48:08 -0500 Subject: ipv4: Make ip_rcv_options() return bool. Signed-off-by: David S. Miller --- net/ipv4/ip_input.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 70afe5bf194..bdaa2c5c28e 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -265,7 +265,7 @@ int ip_local_deliver(struct sk_buff *skb) ip_local_deliver_finish); } -static inline int ip_rcv_options(struct sk_buff *skb) +static inline bool ip_rcv_options(struct sk_buff *skb) { struct ip_options *opt; const struct iphdr *iph; @@ -309,9 +309,9 @@ static inline int ip_rcv_options(struct sk_buff *skb) goto drop; } - return 0; + return false; drop: - return -1; + return true; } static int ip_rcv_finish(struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 86ceb360565d06fcee96be85c4bafe9264756eca Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 7 Mar 2012 09:07:45 +0100 Subject: batman-adv: Ignore 80-chars per line limits for strings Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/bat_iv_ogm.c | 54 ++++++++++------------- net/batman-adv/bat_sysfs.c | 16 +++---- net/batman-adv/gateway_client.c | 31 ++++++------- net/batman-adv/gateway_common.c | 8 ++-- net/batman-adv/hard-interface.c | 36 +++++---------- net/batman-adv/icmp_socket.c | 12 ++--- net/batman-adv/main.c | 8 ++-- net/batman-adv/originator.c | 14 +++--- net/batman-adv/routing.c | 27 +++++------- net/batman-adv/send.c | 4 +- net/batman-adv/soft-interface.c | 15 +++---- net/batman-adv/translation-table.c | 89 ++++++++++++++++++-------------------- 12 files changed, 137 insertions(+), 177 deletions(-) (limited to 'net') diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 2b66daef1ef..677997b5c48 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -132,8 +132,7 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet, "Sending own" : "Forwarding")); bat_dbg(DBG_BATMAN, bat_priv, - "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," - " IDF %s, ttvn %d) on interface %s [%pM]\n", + "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n", fwd_str, (packet_num > 0 ? "aggregated " : ""), batman_ogm_packet->orig, ntohl(batman_ogm_packet->seqno), @@ -171,8 +170,7 @@ static void bat_iv_ogm_emit(struct forw_packet *forw_packet) directlink = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0); if (!forw_packet->if_incoming) { - pr_err("Error - can't forward packet: incoming iface not " - "specified\n"); + pr_err("Error - can't forward packet: incoming iface not specified\n"); goto out; } @@ -193,8 +191,7 @@ static void bat_iv_ogm_emit(struct forw_packet *forw_packet) /* FIXME: what about aggregated packets ? */ bat_dbg(DBG_BATMAN, bat_priv, - "%s packet (originator %pM, seqno %d, TTL %d) " - "on interface %s [%pM]\n", + "%s packet (originator %pM, seqno %d, TTL %d) on interface %s [%pM]\n", (forw_packet->own ? "Sending own" : "Forwarding"), batman_ogm_packet->orig, ntohl(batman_ogm_packet->seqno), @@ -508,8 +505,7 @@ static void bat_iv_ogm_forward(struct orig_node *orig_node, batman_ogm_packet->tq = hop_penalty(batman_ogm_packet->tq, bat_priv); bat_dbg(DBG_BATMAN, bat_priv, - "Forwarding packet: tq_orig: %i, tq_avg: %i, " - "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", + "Forwarding packet: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", in_tq, tq_avg, batman_ogm_packet->tq, in_ttl - 1, batman_ogm_packet->header.ttl); @@ -589,8 +585,8 @@ static void bat_iv_ogm_orig_update(struct bat_priv *bat_priv, struct hlist_node *node; uint8_t bcast_own_sum_orig, bcast_own_sum_neigh; - bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " - "Searching and updating originator entry of received packet\n"); + bat_dbg(DBG_BATMAN, bat_priv, + "update_originator(): Searching and updating originator entry of received packet\n"); rcu_read_lock(); hlist_for_each_entry_rcu(tmp_neigh_node, node, @@ -802,10 +798,7 @@ static int bat_iv_ogm_calc_tq(struct orig_node *orig_node, (TQ_MAX_VALUE * TQ_MAX_VALUE)); bat_dbg(DBG_BATMAN, bat_priv, - "bidirectional: " - "orig = %-15pM neigh = %-15pM => own_bcast = %2i, " - "real recv = %2i, local tq: %3i, asym_penalty: %3i, " - "total tq: %3i\n", + "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n", orig_node->orig, orig_neigh_node->orig, total_count, neigh_rq_count, tq_own, tq_asym_penalty, batman_ogm_packet->tq); @@ -933,9 +926,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr, batman_ogm_packet->orig) ? 1 : 0); bat_dbg(DBG_BATMAN, bat_priv, - "Received BATMAN packet via NB: %pM, IF: %s [%pM] " - "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, " - "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n", + "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n", ethhdr->h_source, if_incoming->net_dev->name, if_incoming->net_dev->dev_addr, batman_ogm_packet->orig, batman_ogm_packet->prev_sender, batman_ogm_packet->seqno, @@ -978,16 +969,15 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr, if (is_my_addr) { bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: received my own broadcast (sender: %pM" - ")\n", + "Drop packet: received my own broadcast (sender: %pM)\n", ethhdr->h_source); return; } if (is_broadcast) { - bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " - "ignoring all packets with broadcast source addr (sender: %pM" - ")\n", ethhdr->h_source); + bat_dbg(DBG_BATMAN, bat_priv, + "Drop packet: ignoring all packets with broadcast source addr (sender: %pM)\n", + ethhdr->h_source); return; } @@ -1017,16 +1007,16 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr, spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock); } - bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " - "originator packet from myself (via neighbor)\n"); + bat_dbg(DBG_BATMAN, bat_priv, + "Drop packet: originator packet from myself (via neighbor)\n"); orig_node_free_ref(orig_neigh_node); return; } if (is_my_oldorig) { bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: ignoring all rebroadcast echos (sender: " - "%pM)\n", ethhdr->h_source); + "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n", + ethhdr->h_source); return; } @@ -1039,8 +1029,8 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr, if (is_duplicate == -1) { bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: packet within seqno protection time " - "(sender: %pM)\n", ethhdr->h_source); + "Drop packet: packet within seqno protection time (sender: %pM)\n", + ethhdr->h_source); goto out; } @@ -1061,8 +1051,8 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr, batman_ogm_packet->prev_sender)) && (compare_eth(router->addr, router_router->addr))) { bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: ignoring all rebroadcast packets that " - "may make me loop (sender: %pM)\n", ethhdr->h_source); + "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", + ethhdr->h_source); goto out; } @@ -1106,8 +1096,8 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr, bat_iv_ogm_forward(orig_node, ethhdr, batman_ogm_packet, 1, if_incoming); - bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " - "rebroadcast neighbor packet with direct link flag\n"); + bat_dbg(DBG_BATMAN, bat_priv, + "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); goto out_neigh; } diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c index b00101db5cc..68ff759fc30 100644 --- a/net/batman-adv/bat_sysfs.c +++ b/net/batman-adv/bat_sysfs.c @@ -255,8 +255,8 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, buff[count - 1] = '\0'; bat_info(net_dev, - "Invalid parameter for 'vis mode' setting received: " - "%s\n", buff); + "Invalid parameter for 'vis mode' setting received: %s\n", + buff); return -EINVAL; } @@ -330,8 +330,8 @@ static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, if (gw_mode_tmp < 0) { bat_info(net_dev, - "Invalid parameter for 'gw mode' setting received: " - "%s\n", buff); + "Invalid parameter for 'gw mode' setting received: %s\n", + buff); return -EINVAL; } @@ -502,8 +502,8 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, buff[count - 1] = '\0'; if (strlen(buff) >= IFNAMSIZ) { - pr_err("Invalid parameter for 'mesh_iface' setting received: " - "interface name too long '%s'\n", buff); + pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n", + buff); hardif_free_ref(hard_iface); return -EINVAL; } @@ -677,8 +677,8 @@ out: hardif_free_ref(primary_if); if (ret) - bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send " - "uevent for (%s,%s,%s) event (err: %d)\n", + bat_dbg(DBG_BATMAN, bat_priv, + "Impossible to send uevent for (%s,%s,%s) event (err: %d)\n", uev_type_str[type], uev_action_str[action], (action == UEV_DEL ? "NULL" : data), ret); return ret; diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 0fa8e2d7c46..6f9b9b78f77 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -224,16 +224,13 @@ void gw_election(struct bat_priv *bat_priv) } else if ((!curr_gw) && (next_gw)) { bat_dbg(DBG_BATMAN, bat_priv, "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n", - next_gw->orig_node->orig, - next_gw->orig_node->gw_flags, + next_gw->orig_node->orig, next_gw->orig_node->gw_flags, router->tq_avg); throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr); } else { bat_dbg(DBG_BATMAN, bat_priv, - "Changing route to gateway %pM " - "(gw_flags: %i, tq: %i)\n", - next_gw->orig_node->orig, - next_gw->orig_node->gw_flags, + "Changing route to gateway %pM (gw_flags: %i, tq: %i)\n", + next_gw->orig_node->orig, next_gw->orig_node->gw_flags, router->tq_avg); throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr); } @@ -287,8 +284,7 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) goto out; bat_dbg(DBG_BATMAN, bat_priv, - "Restarting gateway selection: better gateway found (tq curr: " - "%i, tq new: %i)\n", + "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n", gw_tq_avg, orig_tq_avg); deselect: @@ -352,8 +348,7 @@ void gw_node_update(struct bat_priv *bat_priv, continue; bat_dbg(DBG_BATMAN, bat_priv, - "Gateway class of originator %pM changed from " - "%i to %i\n", + "Gateway class of originator %pM changed from %i to %i\n", orig_node->orig, gw_node->orig_node->gw_flags, new_gwflags); @@ -474,23 +469,23 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) primary_if = primary_if_get_selected(bat_priv); if (!primary_if) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - please " - "specify interfaces to enable it\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - please specify interfaces to enable it\n", net_dev->name); goto out; } if (primary_if->if_status != IF_ACTIVE) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - " - "primary interface not active\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - primary interface not active\n", net_dev->name); goto out; } - seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " - "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n", - "Gateway", "#", TQ_MAX_VALUE, "Nexthop", - "outgoingIF", SOURCE_VERSION, primary_if->net_dev->name, + seq_printf(seq, + " %-12s (%s/%i) %17s [%10s]: gw_class ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n", + "Gateway", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", + SOURCE_VERSION, primary_if->net_dev->name, primary_if->net_dev->dev_addr, net_dev->name); rcu_read_lock(); diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 3ccb9c87fd1..ca57ac7d73b 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -125,8 +125,8 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, ret = kstrtol(slash_ptr + 1, 10, &lup); if (ret) { bat_err(net_dev, - "Upload speed of gateway mode invalid: " - "%s\n", slash_ptr + 1); + "Upload speed of gateway mode invalid: %s\n", + slash_ptr + 1); return false; } @@ -163,8 +163,8 @@ ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up); gw_deselect(bat_priv); - bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' " - "(propagating: %d%s/%d%s)\n", + bat_info(net_dev, + "Changing gateway bandwidth from: '%i' to: '%ld' (propagating: %d%s/%d%s)\n", atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, (down > 2048 ? down / 1024 : down), (down > 2048 ? "MBit" : "KBit"), diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 409d0273c9d..377897701a8 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -175,11 +175,9 @@ static void check_known_mac_addr(const struct net_device *net_dev) net_dev->dev_addr)) continue; - pr_warning("The newly added mac address (%pM) already exists " - "on: %s\n", net_dev->dev_addr, - hard_iface->net_dev->name); - pr_warning("It is strongly recommended to keep mac addresses " - "unique to avoid problems!\n"); + pr_warning("The newly added mac address (%pM) already exists on: %s\n", + net_dev->dev_addr, hard_iface->net_dev->name); + pr_warning("It is strongly recommended to keep mac addresses unique to avoid problems!\n"); } rcu_read_unlock(); } @@ -282,10 +280,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface, /* hard-interface is part of a bridge */ if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT) - pr_err("You are about to enable batman-adv on '%s' which " - "already is part of a bridge. Unless you know exactly " - "what you are doing this is probably wrong and won't " - "work the way you think it would.\n", + pr_err("You are about to enable batman-adv on '%s' which already is part of a bridge. Unless you know exactly what you are doing this is probably wrong and won't work the way you think it would.\n", hard_iface->net_dev->name); soft_iface = dev_get_by_name(&init_net, iface_name); @@ -303,8 +298,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface, } if (!softif_is_valid(soft_iface)) { - pr_err("Can't create batman mesh interface %s: " - "already exists as regular interface\n", + pr_err("Can't create batman mesh interface %s: already exists as regular interface\n", soft_iface->name); dev_put(soft_iface); ret = -EINVAL; @@ -317,8 +311,9 @@ int hardif_enable_interface(struct hard_iface *hard_iface, bat_priv->bat_algo_ops->bat_ogm_init(hard_iface); if (!hard_iface->packet_buff) { - bat_err(hard_iface->soft_iface, "Can't add interface packet " - "(%s): out of memory\n", hard_iface->net_dev->name); + bat_err(hard_iface->soft_iface, + "Can't add interface packet (%s): out of memory\n", + hard_iface->net_dev->name); ret = -ENOMEM; goto err; } @@ -341,29 +336,22 @@ int hardif_enable_interface(struct hard_iface *hard_iface, if (atomic_read(&bat_priv->fragmentation) && hard_iface->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(hard_iface->soft_iface, - "The MTU of interface %s is too small (%i) to handle " - "the transport of batman-adv packets. Packets going " - "over this interface will be fragmented on layer2 " - "which could impact the performance. Setting the MTU " - "to %zi would solve the problem.\n", + "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %zi would solve the problem.\n", hard_iface->net_dev->name, hard_iface->net_dev->mtu, ETH_DATA_LEN + BAT_HEADER_LEN); if (!atomic_read(&bat_priv->fragmentation) && hard_iface->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(hard_iface->soft_iface, - "The MTU of interface %s is too small (%i) to handle " - "the transport of batman-adv packets. If you " - "experience problems getting traffic through try " - "increasing the MTU to %zi.\n", + "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %zi.\n", hard_iface->net_dev->name, hard_iface->net_dev->mtu, ETH_DATA_LEN + BAT_HEADER_LEN); if (hardif_is_iface_up(hard_iface)) hardif_activate_interface(hard_iface); else - bat_err(hard_iface->soft_iface, "Not using interface %s " - "(retrying later): interface not active\n", + bat_err(hard_iface->soft_iface, + "Not using interface %s (retrying later): interface not active\n", hard_iface->net_dev->name); /* begin scheduling originator messages on that interface */ diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 9b755f9eb18..b87518edcef 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -59,8 +59,7 @@ static int bat_socket_open(struct inode *inode, struct file *file) } if (i == ARRAY_SIZE(socket_client_hash)) { - pr_err("Error - can't add another packet client: " - "maximum number of clients reached\n"); + pr_err("Error - can't add another packet client: maximum number of clients reached\n"); kfree(socket_client); return -EXFULL; } @@ -162,8 +161,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (len < sizeof(struct icmp_packet)) { bat_dbg(DBG_BATMAN, bat_priv, - "Error - can't send packet from char device: " - "invalid packet size\n"); + "Error - can't send packet from char device: invalid packet size\n"); return -EINVAL; } @@ -193,16 +191,14 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (icmp_packet->header.packet_type != BAT_ICMP) { bat_dbg(DBG_BATMAN, bat_priv, - "Error - can't send packet from char device: " - "got bogus packet type (expected: BAT_ICMP)\n"); + "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); len = -EINVAL; goto free_skb; } if (icmp_packet->msg_type != ECHO_REQUEST) { bat_dbg(DBG_BATMAN, bat_priv, - "Error - can't send packet from char device: " - "got bogus message type (expected: ECHO_REQUEST)\n"); + "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); len = -EINVAL; goto free_skb; } diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 08f3b3a8e88..6d51caaf8ce 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -64,8 +64,8 @@ static int __init batman_init(void) register_netdevice_notifier(&hard_if_notifier); - pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) " - "loaded\n", SOURCE_VERSION, COMPAT_VERSION); + pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n", + SOURCE_VERSION, COMPAT_VERSION); return 0; } @@ -201,8 +201,8 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops) bat_algo_ops_tmp = bat_algo_get(bat_algo_ops->name); if (bat_algo_ops_tmp) { - pr_info("Trying to register already registered routing " - "algorithm: %s\n", bat_algo_ops->name); + pr_info("Trying to register already registered routing algorithm: %s\n", + bat_algo_ops->name); goto out; } diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 371cc93d8e1..43c0a4f1399 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -294,14 +294,12 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv, (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) bat_dbg(DBG_BATMAN, bat_priv, - "neighbor purge: originator %pM, " - "neighbor: %pM, iface: %s\n", + "neighbor purge: originator %pM, neighbor: %pM, iface: %s\n", orig_node->orig, neigh_node->addr, neigh_node->if_incoming->net_dev->name); else bat_dbg(DBG_BATMAN, bat_priv, - "neighbor timeout: originator %pM, " - "neighbor: %pM, last_valid: %lu\n", + "neighbor timeout: originator %pM, neighbor: %pM, last_valid: %lu\n", orig_node->orig, neigh_node->addr, (neigh_node->last_valid / HZ)); @@ -416,15 +414,15 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) primary_if = primary_if_get_selected(bat_priv); if (!primary_if) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - please specify interfaces to enable it\n", net_dev->name); goto out; } if (primary_if->if_status != IF_ACTIVE) { - ret = seq_printf(seq, "BATMAN mesh %s " - "disabled - primary interface not active\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - primary interface not active\n", net_dev->name); goto out; } diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index f53515562a4..01b66d4a5aa 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -83,8 +83,7 @@ static void _update_route(struct bat_priv *bat_priv, /* route changed */ } else if (neigh_node && curr_router) { bat_dbg(DBG_ROUTES, bat_priv, - "Changing route towards: %pM " - "(now via %pM - was via %pM)\n", + "Changing route towards: %pM (now via %pM - was via %pM)\n", orig_node->orig, neigh_node->addr, curr_router->addr); } @@ -345,9 +344,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, /* send TTL exceeded if packet is an echo request (traceroute) */ if (icmp_packet->msg_type != ECHO_REQUEST) { - pr_debug("Warning - can't forward icmp packet from %pM to " - "%pM: ttl exceeded\n", icmp_packet->orig, - icmp_packet->dst); + pr_debug("Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n", + icmp_packet->orig, icmp_packet->dst); goto out; } @@ -674,9 +672,9 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if) if (!orig_node) goto out; - bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM " - "(client %pM)\n", roam_adv_packet->src, - roam_adv_packet->client); + bat_dbg(DBG_TT, bat_priv, + "Received ROAMING_ADV from %pM (client %pM)\n", + roam_adv_packet->src, roam_adv_packet->client); tt_global_add(bat_priv, orig_node, roam_adv_packet->client, atomic_read(&orig_node->last_ttvn) + 1, true, false); @@ -813,9 +811,8 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) /* TTL exceeded */ if (unicast_packet->header.ttl < 2) { - pr_debug("Warning - can't forward unicast packet from %pM to " - "%pM: ttl exceeded\n", ethhdr->h_source, - unicast_packet->dest); + pr_debug("Warning - can't forward unicast packet from %pM to %pM: ttl exceeded\n", + ethhdr->h_source, unicast_packet->dest); goto out; } @@ -934,10 +931,10 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv, orig_node_free_ref(orig_node); } - bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u " - "new_ttvn %u)! Rerouting unicast packet (for %pM) to " - "%pM\n", unicast_packet->ttvn, curr_ttvn, - ethhdr->h_dest, unicast_packet->dest); + bat_dbg(DBG_ROUTES, bat_priv, + "TTVN mismatch (old_ttvn %u new_ttvn %u)! Rerouting unicast packet (for %pM) to %pM\n", + unicast_packet->ttvn, curr_ttvn, ethhdr->h_dest, + unicast_packet->dest); unicast_packet->ttvn = curr_ttvn; } diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 41375806532..f261ccffbd9 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -45,8 +45,8 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface, goto send_skb_err; if (!(hard_iface->net_dev->flags & IFF_UP)) { - pr_warning("Interface %s is not up - can't send packet via " - "that interface!\n", hard_iface->net_dev->name); + pr_warning("Interface %s is not up - can't send packet via that interface!\n", + hard_iface->net_dev->name); goto send_skb_err; } diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index c39c120e117..3ba057d9352 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -252,8 +252,8 @@ static void softif_neigh_vid_select(struct bat_priv *bat_priv, vid, curr_neigh->addr); else if ((curr_neigh) && (new_neigh)) bat_dbg(DBG_ROUTES, bat_priv, - "Changing mesh exit point on vid: %d from %pM " - "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr); + "Changing mesh exit point on vid: %d from %pM to %pM.\n", + vid, curr_neigh->addr, new_neigh->addr); else if ((!curr_neigh) && (new_neigh)) bat_dbg(DBG_ROUTES, bat_priv, "Setting mesh exit point on vid: %d to %pM.\n", @@ -327,15 +327,15 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) primary_if = primary_if_get_selected(bat_priv); if (!primary_if) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - please specify interfaces to enable it\n", net_dev->name); goto out; } if (primary_if->if_status != IF_ACTIVE) { - ret = seq_printf(seq, "BATMAN mesh %s " - "disabled - primary interface not active\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - primary interface not active\n", net_dev->name); goto out; } @@ -403,8 +403,7 @@ void softif_neigh_purge(struct bat_priv *bat_priv) if (curr_softif_neigh == softif_neigh) { bat_dbg(DBG_ROUTES, bat_priv, - "Current mesh exit point on vid: %d " - "'%pM' vanished.\n", + "Current mesh exit point on vid: %d '%pM' vanished.\n", softif_neigh_vid->vid, softif_neigh->addr); do_deselect = 1; diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index c9507057c98..1f869212784 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -309,21 +309,21 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset) primary_if = primary_if_get_selected(bat_priv); if (!primary_if) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - please specify interfaces to enable it\n", net_dev->name); goto out; } if (primary_if->if_status != IF_ACTIVE) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - " - "primary interface not active\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - primary interface not active\n", net_dev->name); goto out; } - seq_printf(seq, "Locally retrieved addresses (from %s) " - "announced via TT (TTVN: %u):\n", + seq_printf(seq, + "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn)); for (i = 0; i < hash->size; i++) { @@ -365,8 +365,9 @@ static void tt_local_set_pending(struct bat_priv *bat_priv, * response issued before the net ttvn increment (consistency check) */ tt_local_entry->common.flags |= TT_CLIENT_PENDING; - bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: " - "%s\n", tt_local_entry->common.addr, message); + bat_dbg(DBG_TT, bat_priv, + "Local tt entry (%pM) pending to be removed: %s\n", + tt_local_entry->common.addr, message); } void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr, @@ -574,15 +575,15 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) primary_if = primary_if_get_selected(bat_priv); if (!primary_if) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - please " - "specify interfaces to enable it\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - please specify interfaces to enable it\n", net_dev->name); goto out; } if (primary_if->if_status != IF_ACTIVE) { - ret = seq_printf(seq, "BATMAN mesh %s disabled - " - "primary interface not active\n", + ret = seq_printf(seq, + "BATMAN mesh %s disabled - primary interface not active\n", net_dev->name); goto out; } @@ -602,18 +603,18 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) tt_global_entry = container_of(tt_common_entry, struct tt_global_entry, common); - seq_printf(seq, " * %pM (%3u) via %pM (%3u) " - "[%c%c]\n", - tt_global_entry->common.addr, - tt_global_entry->ttvn, - tt_global_entry->orig_node->orig, - (uint8_t) atomic_read( + seq_printf(seq, + " * %pM (%3u) via %pM (%3u) [%c%c]\n", + tt_global_entry->common.addr, + tt_global_entry->ttvn, + tt_global_entry->orig_node->orig, + (uint8_t) atomic_read( &tt_global_entry->orig_node-> last_ttvn), - (tt_global_entry->common.flags & - TT_CLIENT_ROAM ? 'R' : '.'), - (tt_global_entry->common.flags & - TT_CLIENT_WIFI ? 'W' : '.')); + (tt_global_entry->common.flags & + TT_CLIENT_ROAM ? 'R' : '.'), + (tt_global_entry->common.flags & + TT_CLIENT_WIFI ? 'W' : '.')); } rcu_read_unlock(); } @@ -710,8 +711,7 @@ void tt_global_del_orig(struct bat_priv *bat_priv, common); if (tt_global_entry->orig_node == orig_node) { bat_dbg(DBG_TT, bat_priv, - "Deleting global tt entry %pM " - "(via %pM): %s\n", + "Deleting global tt entry %pM (via %pM): %s\n", tt_global_entry->common.addr, tt_global_entry->orig_node->orig, message); @@ -751,8 +751,8 @@ static void tt_global_roam_purge(struct bat_priv *bat_priv) TT_CLIENT_ROAM_TIMEOUT)) continue; - bat_dbg(DBG_TT, bat_priv, "Deleting global " - "tt entry (%pM): Roaming timeout\n", + bat_dbg(DBG_TT, bat_priv, + "Deleting global tt entry (%pM): Roaming timeout\n", tt_global_entry->common.addr); atomic_dec(&tt_global_entry->orig_node->tt_size); hlist_del_rcu(node); @@ -1134,8 +1134,9 @@ static int send_tt_request(struct bat_priv *bat_priv, if (!neigh_node) goto out; - bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM " - "[%c]\n", dst_orig_node->orig, neigh_node->addr, + bat_dbg(DBG_TT, bat_priv, + "Sending TT_REQUEST to %pM via %pM [%c]\n", + dst_orig_node->orig, neigh_node->addr, (full_table ? 'F' : '.')); send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); @@ -1172,9 +1173,8 @@ static bool send_other_tt_response(struct bat_priv *bat_priv, struct tt_query_packet *tt_response; bat_dbg(DBG_TT, bat_priv, - "Received TT_REQUEST from %pM for " - "ttvn: %u (%pM) [%c]\n", tt_request->src, - tt_request->ttvn, tt_request->dst, + "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", + tt_request->src, tt_request->ttvn, tt_request->dst, (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); /* Let's get the orig node of the REAL destination */ @@ -1299,9 +1299,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv, struct tt_query_packet *tt_response; bat_dbg(DBG_TT, bat_priv, - "Received TT_REQUEST from %pM for " - "ttvn: %u (me) [%c]\n", tt_request->src, - tt_request->ttvn, + "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", + tt_request->src, tt_request->ttvn, (tt_request->flags & TT_FULL_TABLE ? 'F' : '.')); @@ -1504,10 +1503,9 @@ void handle_tt_response(struct bat_priv *bat_priv, struct tt_req_node *node, *safe; struct orig_node *orig_node = NULL; - bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for " - "ttvn %d t_size: %d [%c]\n", - tt_response->src, tt_response->ttvn, - tt_response->tt_data, + bat_dbg(DBG_TT, bat_priv, + "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", + tt_response->src, tt_response->ttvn, tt_response->tt_data, (tt_response->flags & TT_FULL_TABLE ? 'F' : '.')); orig_node = orig_hash_find(bat_priv, tt_response->src); @@ -1771,8 +1769,9 @@ static void tt_local_purge_pending_clients(struct bat_priv *bat_priv) if (!(tt_common_entry->flags & TT_CLIENT_PENDING)) continue; - bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry " - "(%pM): pending\n", tt_common_entry->addr); + bat_dbg(DBG_TT, bat_priv, + "Deleting local tt entry (%pM): pending\n", + tt_common_entry->addr); atomic_dec(&bat_priv->num_local_tt); hlist_del_rcu(node); @@ -1877,12 +1876,10 @@ void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, if (!orig_node->tt_initialised || ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) { request_table: - bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. " - "Need to retrieve the correct information " - "(ttvn: %u last_ttvn: %u crc: %u last_crc: " - "%u num_changes: %u)\n", orig_node->orig, ttvn, - orig_ttvn, tt_crc, orig_node->tt_crc, - tt_num_changes); + bat_dbg(DBG_TT, bat_priv, + "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %u last_crc: %u num_changes: %u)\n", + orig_node->orig, ttvn, orig_ttvn, tt_crc, + orig_node->tt_crc, tt_num_changes); send_tt_request(bat_priv, orig_node, ttvn, tt_crc, full_table); return; -- cgit v1.2.3-70-g09d2 From 21a1236bc3155c0c2efcce8ba03540fdf979ac00 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 7 Mar 2012 09:07:46 +0100 Subject: batman-adv: Don't begin block comments with only a /* line Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/bat_iv_ogm.c | 3 +-- net/batman-adv/main.h | 13 ++----------- 2 files changed, 3 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 677997b5c48..a6d5d63fb6a 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -779,8 +779,7 @@ static int bat_iv_ogm_calc_tq(struct orig_node *orig_node, * information */ tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count; - /* - * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does + /* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does * affect the nearly-symmetric links only a little, but * punishes asymmetric links more. This will give a value * between 0 and TQ_MAX_VALUE diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 1468788a9d6..94fa1c2393a 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -107,9 +107,7 @@ enum uev_type { #define GW_THRESHOLD 50 -/* - * Debug Messages - */ +/* Debug Messages */ #ifdef pr_fmt #undef pr_fmt #endif @@ -124,14 +122,7 @@ enum dbg_level { DBG_ALL = 7 }; - -/* - * Vis - */ - -/* - * Kernel headers - */ +/* Kernel headers */ #include /* mutex */ #include /* needed by all modules */ -- cgit v1.2.3-70-g09d2 From 96741ade15187bfde3dddc4092a88ba7a7c9183c Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 7 Mar 2012 09:07:47 +0100 Subject: batman-adv: Use {} braces consistent on the arms of a statement Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/routing.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 01b66d4a5aa..7f8e1589941 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -237,8 +237,9 @@ int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff, "old packet received, start protection\n"); return 0; - } else + } else { return 1; + } } return 0; } -- cgit v1.2.3-70-g09d2 From 40e0c4f51d3fc3fd54edc797adae314fbe2b96a6 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 7 Mar 2012 09:07:48 +0100 Subject: batman-adv: Remove spaces after a cast Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner --- net/batman-adv/send.c | 2 +- net/batman-adv/unicast.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index f261ccffbd9..af7a6741a68 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -56,7 +56,7 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface, skb_reset_mac_header(skb); - ethhdr = (struct ethhdr *) skb_mac_header(skb); + ethhdr = (struct ethhdr *)skb_mac_header(skb); memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN); memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index 0897dfa72c5..676f6a626b2 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -66,7 +66,7 @@ static struct sk_buff *frag_merge_packet(struct list_head *head, kfree_skb(tmp_skb); memmove(skb->data + uni_diff, skb->data, hdr_len); - unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); + unicast_packet = (struct unicast_packet *)skb_pull(skb, uni_diff); unicast_packet->header.packet_type = BAT_UNICAST; return skb; @@ -238,7 +238,7 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, goto dropped; skb_reserve(frag_skb, ucf_hdr_len); - unicast_packet = (struct unicast_packet *) skb->data; + unicast_packet = (struct unicast_packet *)skb->data; memcpy(&tmp_uc, unicast_packet, uc_hdr_len); skb_split(skb, frag_skb, data_len / 2 + uc_hdr_len); -- cgit v1.2.3-70-g09d2 From fde15c3a3adc7b65cd0610dd6bca4804ee7ffd38 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sun, 11 Mar 2012 11:59:31 -0400 Subject: [S390] irq: external interrupt code passing The external interrupt handlers have a parameter called ext_int_code. Besides the name this paramter does not only contain the ext_int_code but in addition also the "cpu address" (POP) which caused the external interrupt. To make the code a bit more obvious pass a struct instead so the called function can easily distinguish between external interrupt code and cpu address. The cpu address field however is named "subcode" since some external interrupt sources do not pass a cpu address but a different parameter (or none at all). Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/irq.h | 7 ++++++- arch/s390/kernel/entry.h | 3 ++- arch/s390/kernel/irq.c | 12 +++++------- arch/s390/kernel/smp.c | 4 ++-- arch/s390/kernel/time.c | 4 ++-- arch/s390/kernel/vtime.c | 2 +- arch/s390/mm/fault.c | 4 ++-- arch/s390/oprofile/hwsampler.c | 6 +++--- drivers/s390/block/dasd_diag.c | 8 ++++---- drivers/s390/char/sclp.c | 4 ++-- drivers/s390/kvm/kvm_virtio.c | 6 ++---- net/iucv/iucv.c | 2 +- 12 files changed, 32 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index ba6d85f88d5..acee1806f61 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -34,7 +34,12 @@ enum interruption_class { NR_IRQS, }; -typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long); +struct ext_code { + unsigned short subcode; + unsigned short code; +}; + +typedef void (*ext_int_handler_t)(struct ext_code, unsigned int, unsigned long); int register_external_interrupt(u16 code, ext_int_handler_t handler); int unregister_external_interrupt(u16 code, ext_int_handler_t handler); diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 4984785e307..6cdddac93a2 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -35,7 +35,8 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs); void do_notify_resume(struct pt_regs *regs); -void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long); +struct ext_code; +void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long); void do_restart(void); void __init startup_init(void); void die(struct pt_regs *regs, const char *str); diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 09a014c6253..7a97d57f707 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -209,29 +209,27 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler) } EXPORT_SYMBOL(unregister_external_interrupt); -void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code, +void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct pt_regs *old_regs; - unsigned short code; struct ext_int_info *p; int index; - code = (unsigned short) ext_int_code; old_regs = set_irq_regs(regs); irq_enter(); if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) /* Serve timer interrupts first. */ clock_comparator_work(); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; - if (code != 0x1004) + if (ext_code.code != 0x1004) __get_cpu_var(s390_idle).nohz_delay = 1; - index = ext_hash(code); + index = ext_hash(ext_code.code); rcu_read_lock(); list_for_each_entry_rcu(p, &ext_int_hash[index], entry) - if (likely(p->code == code)) - p->handler(ext_int_code, param32, param64); + if (likely(p->code == ext_code.code)) + p->handler(ext_code, param32, param64); rcu_read_unlock(); irq_exit(); set_irq_regs(old_regs); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index afd6e5113a9..734e644972a 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -434,14 +434,14 @@ void smp_stop_cpu(void) * This is the main routine where commands issued by other * cpus are handled. */ -static void do_ext_call_interrupt(unsigned int ext_int_code, +static void do_ext_call_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { unsigned long bits; int cpu; cpu = smp_processor_id(); - if ((ext_int_code & 0xffff) == 0x1202) + if (ext_code.code == 0x1202) kstat_cpu(cpu).irqs[EXTINT_EXC]++; else kstat_cpu(cpu).irqs[EXTINT_EMS]++; diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 14da278febb..d4e1cb1dbcd 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -165,7 +165,7 @@ void init_cpu_timer(void) __ctl_set_bit(0, 4); } -static void clock_comparator_interrupt(unsigned int ext_int_code, +static void clock_comparator_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { @@ -177,7 +177,7 @@ static void clock_comparator_interrupt(unsigned int ext_int_code, static void etr_timing_alert(struct etr_irq_parm *); static void stp_timing_alert(struct stp_irq_parm *); -static void timing_alert_interrupt(unsigned int ext_int_code, +static void timing_alert_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { kstat_cpu(smp_processor_id()).irqs[EXTINT_TLA]++; diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 277ea712b23..39ebff50694 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -220,7 +220,7 @@ static void do_callbacks(struct list_head *cb_list) /* * Handler for the virtual CPU timer. */ -static void do_cpu_timer_interrupt(unsigned int ext_int_code, +static void do_cpu_timer_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct vtimer_queue *vq; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index e8fcd928dc7..b17c42df61c 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -532,7 +532,7 @@ void pfault_fini(void) static DEFINE_SPINLOCK(pfault_lock); static LIST_HEAD(pfault_list); -static void pfault_interrupt(unsigned int ext_int_code, +static void pfault_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct task_struct *tsk; @@ -545,7 +545,7 @@ static void pfault_interrupt(unsigned int ext_int_code, * in the 'cpu address' field associated with the * external interrupt. */ - subcode = ext_int_code >> 16; + subcode = ext_code.subcode; if ((subcode & 0xff00) != __SUBCODE_MASK) return; kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index 9daee91e6c3..12bea05a0fc 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c @@ -233,8 +233,8 @@ static inline unsigned long *trailer_entry_ptr(unsigned long v) } /* prototypes for external interrupt handler and worker */ -static void hws_ext_handler(unsigned int ext_int_code, - unsigned int param32, unsigned long param64); +static void hws_ext_handler(struct ext_code ext_code, + unsigned int param32, unsigned long param64); static void worker(struct work_struct *work); @@ -673,7 +673,7 @@ int hwsampler_activate(unsigned int cpu) return rc; } -static void hws_ext_handler(unsigned int ext_int_code, +static void hws_ext_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct hws_cpu_buffer *cb; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 46784b83c5c..0cea7e98f46 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -229,7 +229,7 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr) } /* Handle external interruption. */ -static void dasd_ext_handler(unsigned int ext_int_code, +static void dasd_ext_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct dasd_ccw_req *cqr, *next; @@ -239,7 +239,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, addr_t ip; int rc; - switch (ext_int_code >> 24) { + switch (ext_code.subcode >> 8) { case DASD_DIAG_CODE_31BIT: ip = (addr_t) param32; break; @@ -280,7 +280,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, cqr->stopclk = get_clock(); expires = 0; - if ((ext_int_code & 0xff0000) == 0) { + if ((ext_code.subcode & 0xff) == 0) { cqr->status = DASD_CQR_SUCCESS; /* Start first request on queue if possible -> fast_io. */ if (!list_empty(&device->ccw_queue)) { @@ -296,7 +296,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, cqr->status = DASD_CQR_QUEUED; DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for " "request %p was %d (%d retries left)", cqr, - (ext_int_code >> 16) & 0xff, cqr->retries); + ext_code.subcode & 0xff, cqr->retries); dasd_diag_erp(device); } diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index eaa7e78186f..30f29a0020a 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -393,7 +393,7 @@ __sclp_find_req(u32 sccb) /* Handler for external interruption. Perform request post-processing. * Prepare read event data request if necessary. Start processing of next * request on queue. */ -static void sclp_interrupt_handler(unsigned int ext_int_code, +static void sclp_interrupt_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct sclp_req *req; @@ -818,7 +818,7 @@ EXPORT_SYMBOL(sclp_reactivate); /* Handler for external interruption used during initialization. Modify * request state to done. */ -static void sclp_check_handler(unsigned int ext_int_code, +static void sclp_check_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { u32 finished_sccb; diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 7bc1955337e..d74e9ae6dfb 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -380,15 +380,13 @@ static void hotplug_devices(struct work_struct *dummy) /* * we emulate the request_irq behaviour on top of s390 extints */ -static void kvm_extint_handler(unsigned int ext_int_code, +static void kvm_extint_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct virtqueue *vq; - u16 subcode; u32 param; - subcode = ext_int_code >> 16; - if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) + if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64) return; kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 403be43b793..3ad1f9db5f8 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -1800,7 +1800,7 @@ static void iucv_work_fn(struct work_struct *work) * Handles external interrupts coming in from CP. * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn(). */ -static void iucv_external_interrupt(unsigned int ext_int_code, +static void iucv_external_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct iucv_irq_data *p; -- cgit v1.2.3-70-g09d2 From 51990e825431089747f8896244b5c17d3a6423f1 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 22 Jan 2012 11:23:42 -0500 Subject: device.h: cleanup users outside of linux/include (C files) For files that are actively using linux/device.h, make sure that they call it out. This will allow us to clean up some of the implicit uses of linux/device.h within include/* without introducing build regressions. Yes, this was created by "cheating" -- i.e. the headers were cleaned up, and then the fallout was found and fixed, and then the two commits were reordered. This ensures we don't introduce build regressions into the git history. Signed-off-by: Paul Gortmaker --- drivers/base/power/clock_ops.c | 1 + drivers/base/power/common.c | 1 + drivers/base/power/opp.c | 1 + drivers/base/regmap/regcache-lzo.c | 1 + drivers/base/regmap/regcache-rbtree.c | 1 + drivers/base/regmap/regcache.c | 1 + drivers/base/regmap/regmap-debugfs.c | 1 + drivers/base/regmap/regmap-irq.c | 1 + drivers/base/regmap/regmap.c | 1 + drivers/edac/edac_stub.c | 1 + drivers/edac/mce_amd_inj.c | 1 + drivers/mfd/wm8994-regmap.c | 1 + drivers/power/apm_power.c | 1 + drivers/power/power_supply.h | 4 ++++ drivers/power/power_supply_leds.c | 1 + drivers/power/power_supply_sysfs.c | 1 + net/rfkill/core.c | 1 + sound/core/init.c | 1 + sound/core/pcm.c | 1 + sound/core/seq/seq.c | 1 + sound/core/timer.c | 1 + 21 files changed, 24 insertions(+) (limited to 'net') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 428e55e012d..869d7ff2227 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index 4af7c1cbf90..a14085cc613 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 95706fa24c7..ac993eafec8 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c index b7d16143ede..51f6f28dadf 100644 --- a/drivers/base/regmap/regcache-lzo.c +++ b/drivers/base/regmap/regcache-lzo.c @@ -11,6 +11,7 @@ */ #include +#include #include #include "internal.h" diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 32620c4f168..b487c29a67d 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 1ead66186b7..214f704c34d 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 6f397476e27..8c90a83ae24 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "internal.h" diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 428836fc583..1befaa7a31c 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index be10a4ff660..87f9e1129ae 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index 670c4481453..6c86f6e5455 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c @@ -15,6 +15,7 @@ #include #include #include +#include #include int edac_op_state = EDAC_OPSTATE_INVAL; diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 885e8ad8fdc..66b5151c108 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c index c598ae69b8f..0c0a215f3fd 100644 --- a/drivers/mfd/wm8994-regmap.c +++ b/drivers/mfd/wm8994-regmap.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "wm8994.h" diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index 8a612dec913..39763015b36 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c @@ -10,6 +10,7 @@ */ #include +#include #include #include diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h index 018de2b2699..cc439fd89d8 100644 --- a/drivers/power/power_supply.h +++ b/drivers/power/power_supply.h @@ -10,6 +10,10 @@ * You may use this code as per GPL version 2 */ +struct device; +struct device_type; +struct power_supply; + #ifdef CONFIG_SYSFS extern void power_supply_init_attrs(struct device_type *dev_type); diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index da25eb94e5c..995f966ed5b 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c @@ -11,6 +11,7 @@ */ #include +#include #include #include diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index b52b57ca308..4368e7d6131 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 354760ebbbd..f974961754c 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/core/init.c b/sound/core/init.c index 3ac49b1b7cb..995fc5d4b1a 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8928ca871c2..1888a90bd5b 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index 9d8379aedf4..71211056108 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/sound/core/timer.c b/sound/core/timer.c index 8e7561dfc5f..6ddcf06f52f 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 374458b3fe4288f820dbf3de0728e314d969f9e4 Mon Sep 17 00:00:00 2001 From: Dmitry Tarnyagin Date: Sun, 11 Mar 2012 10:28:31 +0000 Subject: caif: Fix for a race in socket transmit with flow control. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kill faulty checks on flow-off leading to connection drop at race conditions. caif_socket checks for flow-on before transmitting and goes to sleep or return -EAGAIN upon flow stop. Remove faulty subsequent checks on flow-off leading to connection drop. Also fix memory leaks on some of the errors paths. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller --- net/caif/cfdbgl.c | 4 +++- net/caif/cfdgml.c | 9 +++++++-- net/caif/cfrfml.c | 25 +++++++++++-------------- net/caif/cfsrvl.c | 6 +----- net/caif/cfutill.c | 5 ++++- net/caif/cfvidl.c | 6 +++++- 6 files changed, 31 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c index 65d6ef3cf9a..2914659eb9b 100644 --- a/net/caif/cfdbgl.c +++ b/net/caif/cfdbgl.c @@ -41,8 +41,10 @@ static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt) struct caif_payload_info *info; int ret; - if (!cfsrvl_ready(service, &ret)) + if (!cfsrvl_ready(service, &ret)) { + cfpkt_destroy(pkt); return ret; + } /* Add info for MUX-layer to route the packet out */ info = cfpkt_info(pkt); diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c index 0f5ff27aa41..a63f4a5f5af 100644 --- a/net/caif/cfdgml.c +++ b/net/caif/cfdgml.c @@ -86,12 +86,17 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) struct caif_payload_info *info; struct cfsrvl *service = container_obj(layr); int ret; - if (!cfsrvl_ready(service, &ret)) + + if (!cfsrvl_ready(service, &ret)) { + cfpkt_destroy(pkt); return ret; + } /* STE Modem cannot handle more than 1500 bytes datagrams */ - if (cfpkt_getlen(pkt) > DGM_MTU) + if (cfpkt_getlen(pkt) > DGM_MTU) { + cfpkt_destroy(pkt); return -EMSGSIZE; + } cfpkt_add_head(pkt, &zero, 3); packet_type = 0x08; /* B9 set - UNCLASSIFIED */ diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index 6dc75d4f8d9..2b563ad0459 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c @@ -184,6 +184,11 @@ out: rfml->serv.dev_info.id); } spin_unlock(&rfml->sync); + + if (unlikely(err == -EAGAIN)) + /* It is not possible to recover after drop of a fragment */ + err = -EIO; + return err; } @@ -218,7 +223,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) caif_assert(layr->dn->transmit != NULL); if (!cfsrvl_ready(&rfml->serv, &err)) - return err; + goto out; err = -EPROTO; if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1) @@ -251,8 +256,11 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) err = cfrfml_transmit_segment(rfml, frontpkt); - if (err != 0) + if (err != 0) { + frontpkt = NULL; goto out; + } + frontpkt = rearpkt; rearpkt = NULL; @@ -286,19 +294,8 @@ out: if (rearpkt) cfpkt_destroy(rearpkt); - if (frontpkt && frontpkt != pkt) { - + if (frontpkt) cfpkt_destroy(frontpkt); - /* - * Socket layer will free the original packet, - * but this packet may already be sent and - * freed. So we have to return 0 in this case - * to avoid socket layer to re-free this packet. - * The return of shutdown indication will - * cause connection to be invalidated anyhow. - */ - err = 0; - } } return err; diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c index b99f5b22689..4aa33d4496b 100644 --- a/net/caif/cfsrvl.c +++ b/net/caif/cfsrvl.c @@ -174,15 +174,11 @@ void cfsrvl_init(struct cfsrvl *service, bool cfsrvl_ready(struct cfsrvl *service, int *err) { - if (service->open && service->modem_flow_on && service->phy_flow_on) - return true; if (!service->open) { *err = -ENOTCONN; return false; } - caif_assert(!(service->modem_flow_on && service->phy_flow_on)); - *err = -EAGAIN; - return false; + return true; } u8 cfsrvl_getphyid(struct cflayer *layer) diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c index 53e49f3e3af..86d2dadb4b7 100644 --- a/net/caif/cfutill.c +++ b/net/caif/cfutill.c @@ -84,8 +84,11 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt) caif_assert(layr != NULL); caif_assert(layr->dn != NULL); caif_assert(layr->dn->transmit != NULL); - if (!cfsrvl_ready(service, &ret)) + + if (!cfsrvl_ready(service, &ret)) { + cfpkt_destroy(pkt); return ret; + } cfpkt_add_head(pkt, &zero, 1); /* Add info for MUX-layer to route the packet out. */ diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c index e3f37db40ac..a8e2a2d758a 100644 --- a/net/caif/cfvidl.c +++ b/net/caif/cfvidl.c @@ -50,8 +50,12 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt) struct caif_payload_info *info; u32 videoheader = 0; int ret; - if (!cfsrvl_ready(service, &ret)) + + if (!cfsrvl_ready(service, &ret)) { + cfpkt_destroy(pkt); return ret; + } + cfpkt_add_head(pkt, &videoheader, 4); /* Add info for MUX-layer to route the packet out */ info = cfpkt_info(pkt); -- cgit v1.2.3-70-g09d2 From e3abcc2a8538f7d5f64dbf85404bdf8a1d1581b3 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Sun, 11 Mar 2012 10:28:32 +0000 Subject: caif: make zero a legal caif connetion id. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Connection ID configured through RTNL must allow zero as connection id. If connection-id is not given when creating the interface, configure a loopback interface using ifindex as connection-id. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller --- net/caif/chnl_net.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index e866234d0e5..20618dd3088 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -28,6 +28,7 @@ /* 5 sec. connect timeout */ #define CONNECT_TIMEOUT (5 * HZ) #define CAIF_NET_DEFAULT_QUEUE_LEN 500 +#define UNDEF_CONNID 0xffffffff /*This list is protected by the rtnl lock. */ static LIST_HEAD(chnl_net_list); @@ -408,7 +409,7 @@ static void ipcaif_net_setup(struct net_device *dev) priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW; priv->conn_req.priority = CAIF_PRIO_LOW; /* Insert illegal value */ - priv->conn_req.sockaddr.u.dgm.connection_id = 0; + priv->conn_req.sockaddr.u.dgm.connection_id = UNDEF_CONNID; priv->flowenabled = false; init_waitqueue_head(&priv->netmgmt_wq); @@ -471,9 +472,11 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev, else list_add(&caifdev->list_field, &chnl_net_list); - /* Take ifindex as connection-id if null */ - if (caifdev->conn_req.sockaddr.u.dgm.connection_id == 0) + /* Use ifindex as connection id, and use loopback channel default. */ + if (caifdev->conn_req.sockaddr.u.dgm.connection_id == UNDEF_CONNID) { caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex; + caifdev->conn_req.protocol = CAIFPROTO_DATAGRAM_LOOP; + } return ret; } -- cgit v1.2.3-70-g09d2 From dfd25ffffc132c00070eed64200e8950da5d7e9d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 10 Mar 2012 09:20:21 +0000 Subject: tcp: fix syncookie regression commit ea4fc0d619 (ipv4: Don't use rt->rt_{src,dst} in ip_queue_xmit()) added a serious regression on synflood handling. Simon Kirby discovered a successful connection was delayed by 20 seconds before being responsive. In my tests, I discovered that xmit frames were lost, and needed ~4 retransmits and a socket dst rebuild before being really sent. In case of syncookie initiated connection, we use a different path to initialize the socket dst, and inet->cork.fl.u.ip4 is left cleared. As ip_queue_xmit() now depends on inet flow being setup, fix this by copying the temp flowi4 we use in cookie_v4_check(). Reported-by: Simon Kirby Bisected-by: Simon Kirby Signed-off-by: Eric Dumazet Tested-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/syncookies.c | 30 ++++++++++++++++-------------- net/ipv4/tcp_ipv4.c | 10 +++++++--- 2 files changed, 23 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 51fdbb49043..eab2a7fb15d 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -278,6 +278,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct rtable *rt; __u8 rcv_wscale; bool ecn_ok = false; + struct flowi4 fl4; if (!sysctl_tcp_syncookies || !th->ack || th->rst) goto out; @@ -346,20 +347,16 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, * hasn't changed since we received the original syn, but I see * no easy way to do this. */ - { - struct flowi4 fl4; - - flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk), - RT_SCOPE_UNIVERSE, IPPROTO_TCP, - inet_sk_flowi_flags(sk), - (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, - ireq->loc_addr, th->source, th->dest); - security_req_classify_flow(req, flowi4_to_flowi(&fl4)); - rt = ip_route_output_key(sock_net(sk), &fl4); - if (IS_ERR(rt)) { - reqsk_free(req); - goto out; - } + flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk), + RT_SCOPE_UNIVERSE, IPPROTO_TCP, + inet_sk_flowi_flags(sk), + (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, + ireq->loc_addr, th->source, th->dest); + security_req_classify_flow(req, flowi4_to_flowi(&fl4)); + rt = ip_route_output_key(sock_net(sk), &fl4); + if (IS_ERR(rt)) { + reqsk_free(req); + goto out; } /* Try to redo what tcp_v4_send_synack did. */ @@ -373,5 +370,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ireq->rcv_wscale = rcv_wscale; ret = get_cookie_sock(sk, skb, req, &rt->dst); + /* ip_queue_xmit() depends on our flow being setup + * Normal sockets get it right from inet_csk_route_child_sock() + */ + if (ret) + inet_sk(ret)->cork.fl.u.ip4 = fl4; out: return ret; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 94d683a61cb..fd54c5f8a25 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1466,9 +1466,13 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; newinet->inet_id = newtp->write_seq ^ jiffies; - if (!dst && (dst = inet_csk_route_child_sock(sk, newsk, req)) == NULL) - goto put_and_exit; - + if (!dst) { + dst = inet_csk_route_child_sock(sk, newsk, req); + if (!dst) + goto put_and_exit; + } else { + /* syncookie case : see end of cookie_v4_check() */ + } sk_setup_caps(newsk, dst); tcp_mtup_init(newsk); -- cgit v1.2.3-70-g09d2 From 8b2aaedee4eaa94e816144ed54b9707b96be29f8 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Wed, 7 Mar 2012 14:58:07 +0000 Subject: ipv6: Fix Smatch warning. With commit d6ddef9e641d(IPv6: Fix not join all-router mcast group when forwarding set.) I check 'dev' after it's dereference that leads to a Smatch complaint: net/ipv6/addrconf.c:438 ipv6_add_dev() warn: variable dereferenced before check 'dev' (see line 432) net/ipv6/addrconf.c 431 /* protected by rtnl_lock */ 432 rcu_assign_pointer(dev->ip6_ptr, ndev); ^^^^^^^^^^^^ Old dereference. 433 434 /* Join all-node multicast group */ 435 ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); 436 437 /* Join all-router multicast group if forwarding is set */ 438 if (ndev->cnf.forwarding && dev && (dev->flags & IFF_MULTICAST)) ^^^ Remove the check to avoid the complaint as 'dev' can't be NULL. Reported-by: Dan Carpenter Signed-off-by: Li Wei Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6b8ebc5da0e..6a3bb6077e1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -435,7 +435,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); /* Join all-router multicast group if forwarding is set */ - if (ndev->cnf.forwarding && dev && (dev->flags & IFF_MULTICAST)) + if (ndev->cnf.forwarding && (dev->flags & IFF_MULTICAST)) ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); return ndev; -- cgit v1.2.3-70-g09d2 From 09acfea5d8de419ebe84be43b08f7b79c965215f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 11 Mar 2012 15:22:54 -0400 Subject: SUNRPC: Fix a few sparse warnings net/sunrpc/svcsock.c:412:22: warning: incorrect type in assignment (different address spaces) - svc_partial_recvfrom now takes a struct kvec, so the variable save_iovbase needs to be an ordinary (void *) Make a bunch of variables in net/sunrpc/xprtsock.c static Fix a couple of "warning: symbol 'foo' was not declared. Should it be static?" reports. Fix a couple of conflicting function declarations. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/bc_xprt.h | 2 +- include/linux/sunrpc/svcauth.h | 3 +++ include/linux/sunrpc/xprtsock.h | 12 ------------ net/sunrpc/auth_gss/gss_krb5_mech.c | 2 +- net/sunrpc/auth_gss/gss_krb5_seal.c | 2 +- net/sunrpc/backchannel_rqst.c | 1 + net/sunrpc/rpc_pipe.c | 2 +- net/sunrpc/sunrpc_syms.c | 3 --- net/sunrpc/svcsock.c | 2 +- net/sunrpc/xprtsock.c | 10 +++++----- 10 files changed, 14 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h index f7f3ce340c0..969c0a671db 100644 --- a/include/linux/sunrpc/bc_xprt.h +++ b/include/linux/sunrpc/bc_xprt.h @@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt); void xprt_free_bc_request(struct rpc_rqst *req); int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); -void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs); +void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs); int bc_send(struct rpc_rqst *req); /* diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 25d333c1b57..548790e9113 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h @@ -135,6 +135,9 @@ extern void svcauth_unix_purge(void); extern void svcauth_unix_info_release(struct svc_xprt *xpt); extern int svcauth_unix_set_client(struct svc_rqst *rqstp); +extern int unix_gid_cache_create(struct net *net); +extern void unix_gid_cache_destroy(struct net *net); + static inline unsigned long hash_str(char *name, int bits) { unsigned long hash = 0; diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index 3f14a02e9cc..1ad36cc25b2 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -12,18 +12,6 @@ int init_socket_xprt(void); void cleanup_socket_xprt(void); -/* - * RPC slot table sizes for UDP, TCP transports - */ -extern unsigned int xprt_udp_slot_table_entries; -extern unsigned int xprt_tcp_slot_table_entries; - -/* - * Parameters for choosing a free port - */ -extern unsigned int xprt_min_resvport; -extern unsigned int xprt_max_resvport; - #define RPC_MIN_RESVPORT (1U) #define RPC_MAX_RESVPORT (65535U) #define RPC_DEF_MIN_RESVPORT (665U) diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 8c67890de42..8eff8c32d1b 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -344,7 +344,7 @@ out_err: return PTR_ERR(p); } -struct crypto_blkcipher * +static struct crypto_blkcipher * context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) { struct crypto_blkcipher *cp; diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index d7941eab779..62ae3273186 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -159,7 +159,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; } -u32 +static u32 gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, struct xdr_netobj *token) { diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 3ad435a14ad..31def68a0f6 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -25,6 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef RPC_DEBUG #define RPCDBG_FACILITY RPCDBG_TRANS diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 7d96e3cd57c..8584ec068e9 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1149,7 +1149,7 @@ rpc_mount(struct file_system_type *fs_type, return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super); } -void rpc_kill_sb(struct super_block *sb) +static void rpc_kill_sb(struct super_block *sb) { struct net *net = sb->s_fs_info; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 21d106e2ca0..8adfc88e793 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -27,9 +27,6 @@ int sunrpc_net_id; EXPORT_SYMBOL_GPL(sunrpc_net_id); -extern int unix_gid_cache_create(struct net *net); -extern int unix_gid_cache_destroy(struct net *net); - static __net_init int sunrpc_init_net(struct net *net) { int err; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index e088b1633d3..40ae884db86 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -396,7 +396,7 @@ static int svc_partial_recvfrom(struct svc_rqst *rqstp, int buflen, unsigned int base) { size_t save_iovlen; - void __user *save_iovbase; + void *save_iovbase; unsigned int i; int ret; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 4c8281d29e2..92bc5181dbe 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -53,12 +53,12 @@ static void xs_close(struct rpc_xprt *xprt); /* * xprtsock tunables */ -unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; -unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE; -unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE; +static unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; +static unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE; +static unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE; -unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; -unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; +static unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; +static unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; #define XS_TCP_LINGER_TO (15U * HZ) static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO; -- cgit v1.2.3-70-g09d2 From 43db362d3adda9e0a915ddb9a8d1a41186e19179 Mon Sep 17 00:00:00 2001 From: Maciej Żenczykowski Date: Sun, 11 Mar 2012 12:51:50 +0000 Subject: net: get rid of some pointless casts to sockaddr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following 4 functions: move_addr_to_kernel move_addr_to_user verify_iovec verify_compat_iovec are always effectively called with a sockaddr_storage. Make this explicit by changing their signature. This removes a large number of casts from sockaddr_storage to sockaddr. Signed-off-by: Maciej Żenczykowski Signed-off-by: David S. Miller --- include/linux/socket.h | 4 ++-- include/net/compat.h | 2 +- net/compat.c | 2 +- net/core/iovec.c | 2 +- net/socket.c | 36 ++++++++++++++---------------------- 5 files changed, 19 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/include/linux/socket.h b/include/linux/socket.h index d0e77f607a7..da2d3e2543f 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -326,11 +326,11 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata, int offset, unsigned int len, __wsum *csump); -extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode); +extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode); extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata, int offset, int len); -extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr); +extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); struct timespec; diff --git a/include/net/compat.h b/include/net/compat.h index 9ee75edcc29..a974ae92d18 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -41,7 +41,7 @@ extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *); #endif /* defined(CONFIG_COMPAT) */ extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); -extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr *, int); +extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr_storage *, int); extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned); extern asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, unsigned, unsigned); diff --git a/net/compat.c b/net/compat.c index 6def90e0a11..64b4515a64e 100644 --- a/net/compat.c +++ b/net/compat.c @@ -79,7 +79,7 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) /* I've named the args so it is easy to tell whose space the pointers are in. */ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, - struct sockaddr *kern_address, int mode) + struct sockaddr_storage *kern_address, int mode) { int tot_len; diff --git a/net/core/iovec.c b/net/core/iovec.c index c40f27e7d20..7e7aeb01de4 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -35,7 +35,7 @@ * in any case. */ -int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) +int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode) { int size, ct, err; diff --git a/net/socket.c b/net/socket.c index 28a96af484b..12a48d84622 100644 --- a/net/socket.c +++ b/net/socket.c @@ -181,7 +181,7 @@ static DEFINE_PER_CPU(int, sockets_in_use); * invalid addresses -EFAULT is returned. On a success 0 is returned. */ -int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr) +int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr) { if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) return -EINVAL; @@ -209,7 +209,7 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr) * specified. Zero is returned for a success. */ -static int move_addr_to_user(struct sockaddr *kaddr, int klen, +static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, void __user *uaddr, int __user *ulen) { int err; @@ -1449,7 +1449,7 @@ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { - err = move_addr_to_kernel(umyaddr, addrlen, (struct sockaddr *)&address); + err = move_addr_to_kernel(umyaddr, addrlen, &address); if (err >= 0) { err = security_socket_bind(sock, (struct sockaddr *)&address, @@ -1556,7 +1556,7 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, err = -ECONNABORTED; goto out_fd; } - err = move_addr_to_user((struct sockaddr *)&address, + err = move_addr_to_user(&address, len, upeer_sockaddr, upeer_addrlen); if (err < 0) goto out_fd; @@ -1605,7 +1605,7 @@ SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; - err = move_addr_to_kernel(uservaddr, addrlen, (struct sockaddr *)&address); + err = move_addr_to_kernel(uservaddr, addrlen, &address); if (err < 0) goto out_put; @@ -1645,7 +1645,7 @@ SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); if (err) goto out_put; - err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, usockaddr_len); + err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); out_put: fput_light(sock->file, fput_needed); @@ -1677,7 +1677,7 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, sock->ops->getname(sock, (struct sockaddr *)&address, &len, 1); if (!err) - err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, + err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); fput_light(sock->file, fput_needed); } @@ -1716,7 +1716,7 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, msg.msg_controllen = 0; msg.msg_namelen = 0; if (addr) { - err = move_addr_to_kernel(addr, addr_len, (struct sockaddr *)&address); + err = move_addr_to_kernel(addr, addr_len, &address); if (err < 0) goto out_put; msg.msg_name = (struct sockaddr *)&address; @@ -1779,7 +1779,7 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, err = sock_recvmsg(sock, &msg, size, flags); if (err >= 0 && addr != NULL) { - err2 = move_addr_to_user((struct sockaddr *)&address, + err2 = move_addr_to_user(&address, msg.msg_namelen, addr, addr_len); if (err2 < 0) err = err2; @@ -1933,13 +1933,9 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, /* This will also move the address data into kernel space */ if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(msg_sys, iov, - (struct sockaddr *)&address, - VERIFY_READ); + err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ); } else - err = verify_iovec(msg_sys, iov, - (struct sockaddr *)&address, - VERIFY_READ); + err = verify_iovec(msg_sys, iov, &address, VERIFY_READ); if (err < 0) goto out_freeiov; total_len = err; @@ -2143,13 +2139,9 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg, uaddr = (__force void __user *)msg_sys->msg_name; uaddr_len = COMPAT_NAMELEN(msg); if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(msg_sys, iov, - (struct sockaddr *)&addr, - VERIFY_WRITE); + err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); } else - err = verify_iovec(msg_sys, iov, - (struct sockaddr *)&addr, - VERIFY_WRITE); + err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); if (err < 0) goto out_freeiov; total_len = err; @@ -2166,7 +2158,7 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg, len = err; if (uaddr != NULL) { - err = move_addr_to_user((struct sockaddr *)&addr, + err = move_addr_to_user(&addr, msg_sys->msg_namelen, uaddr, uaddr_len); if (err < 0) -- cgit v1.2.3-70-g09d2 From 058bd4d2a4ff0aaa4a5381c67e776729d840c785 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 11 Mar 2012 18:36:11 +0000 Subject: net: Convert printks to pr_ Use a more current kernel messaging style. Convert a printk block to print_hex_dump. Coalesce formats, align arguments. Use %s, __func__ instead of embedding function names. Some messages that were prefixed with _close are now prefixed with _fini. Some ah4 and esp messages are now not prefixed with "ip ". The intent of this patch is to later add something like #define pr_fmt(fmt) "IPv4: " fmt. to standardize the output messages. Text size is trivially reduced. (x86-32 allyesconfig) $ size net/ipv4/built-in.o* text data bss dec hex filename 887888 31558 249696 1169142 11d6f6 net/ipv4/built-in.o.new 887934 31558 249800 1169292 11d78c net/ipv4/built-in.o.old Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 25 +++++------ net/ipv4/ah4.c | 14 +++--- net/ipv4/esp4.c | 8 ++-- net/ipv4/fib_frontend.c | 6 +-- net/ipv4/fib_semantics.c | 2 +- net/ipv4/fib_trie.c | 5 +-- net/ipv4/icmp.c | 19 ++++---- net/ipv4/ip_fragment.c | 3 +- net/ipv4/ip_gre.c | 6 +-- net/ipv4/ip_input.c | 4 +- net/ipv4/ip_options.c | 2 +- net/ipv4/ipcomp.c | 8 ++-- net/ipv4/ipconfig.c | 110 +++++++++++++++++++++++------------------------ net/ipv4/ipip.c | 4 +- net/ipv4/ipmr.c | 4 +- net/ipv4/ping.c | 18 ++++---- net/ipv4/raw.c | 7 +-- net/ipv4/route.c | 43 ++++++++---------- net/ipv4/tcp.c | 7 ++- net/ipv4/tcp_cong.c | 7 ++- net/ipv4/tcp_input.c | 8 ++-- net/ipv4/tcp_ipv4.c | 8 ++-- net/ipv4/tunnel4.c | 8 ++-- net/ipv4/udplite.c | 4 +- net/ipv4/xfrm4_tunnel.c | 14 +++--- 25 files changed, 163 insertions(+), 181 deletions(-) (limited to 'net') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index e588a34e85c..b7a946611f2 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1085,13 +1085,11 @@ out: return; out_permanent: - printk(KERN_ERR "Attempt to override permanent protocol %d.\n", - protocol); + pr_err("Attempt to override permanent protocol %d\n", protocol); goto out; out_illegal: - printk(KERN_ERR - "Ignoring attempt to register invalid socket type %d.\n", + pr_err("Ignoring attempt to register invalid socket type %d\n", p->type); goto out; } @@ -1100,8 +1098,7 @@ EXPORT_SYMBOL(inet_register_protosw); void inet_unregister_protosw(struct inet_protosw *p) { if (INET_PROTOSW_PERMANENT & p->flags) { - printk(KERN_ERR - "Attempt to unregister permanent protocol %d.\n", + pr_err("Attempt to unregister permanent protocol %d\n", p->protocol); } else { spin_lock_bh(&inetsw_lock); @@ -1150,8 +1147,8 @@ static int inet_sk_reselect_saddr(struct sock *sk) return 0; if (sysctl_ip_dynaddr > 1) { - printk(KERN_INFO "%s(): shifting inet->saddr from %pI4 to %pI4\n", - __func__, &old_saddr, &new_saddr); + pr_info("%s(): shifting inet->saddr from %pI4 to %pI4\n", + __func__, &old_saddr, &new_saddr); } inet->inet_saddr = inet->inet_rcv_saddr = new_saddr; @@ -1680,14 +1677,14 @@ static int __init inet_init(void) */ if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) - printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n"); + pr_crit("%s: Cannot add ICMP protocol\n", __func__); if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) - printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n"); + pr_crit("%s: Cannot add UDP protocol\n", __func__); if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) - printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n"); + pr_crit("%s: Cannot add TCP protocol\n", __func__); #ifdef CONFIG_IP_MULTICAST if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) - printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n"); + pr_crit("%s: Cannot add IGMP protocol\n", __func__); #endif /* Register the socket-side information for inet_create. */ @@ -1734,14 +1731,14 @@ static int __init inet_init(void) */ #if defined(CONFIG_IP_MROUTE) if (ip_mr_init()) - printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n"); + pr_crit("%s: Cannot init ipv4 mroute\n", __func__); #endif /* * Initialise per-cpu ipv4 mibs */ if (init_ipv4_mibs()) - printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); + pr_crit("%s: Cannot init ipv4 mibs\n", __func__); ipv4_proc_init(); diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 36d14406261..b5524660c81 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -445,9 +445,9 @@ static int ah_init_state(struct xfrm_state *x) if (aalg_desc->uinfo.auth.icv_fullbits/8 != crypto_ahash_digestsize(ahash)) { - printk(KERN_INFO "AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_ahash_digestsize(ahash), - aalg_desc->uinfo.auth.icv_fullbits/8); + pr_info("AH: %s digestsize %u != %hu\n", + x->aalg->alg_name, crypto_ahash_digestsize(ahash), + aalg_desc->uinfo.auth.icv_fullbits/8); goto error; } @@ -510,11 +510,11 @@ static const struct net_protocol ah4_protocol = { static int __init ah4_init(void) { if (xfrm_register_type(&ah_type, AF_INET) < 0) { - printk(KERN_INFO "ip ah init: can't add xfrm type\n"); + pr_info("%s: can't add xfrm type\n", __func__); return -EAGAIN; } if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) { - printk(KERN_INFO "ip ah init: can't add protocol\n"); + pr_info("%s: can't add protocol\n", __func__); xfrm_unregister_type(&ah_type, AF_INET); return -EAGAIN; } @@ -524,9 +524,9 @@ static int __init ah4_init(void) static void __exit ah4_fini(void) { if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0) - printk(KERN_INFO "ip ah close: can't remove protocol\n"); + pr_info("%s: can't remove protocol\n", __func__); if (xfrm_unregister_type(&ah_type, AF_INET) < 0) - printk(KERN_INFO "ip ah close: can't remove xfrm type\n"); + pr_info("%s: can't remove xfrm type\n", __func__); } module_init(ah4_init); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index a5b413416da..0a86dbe9454 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -706,11 +706,11 @@ static const struct net_protocol esp4_protocol = { static int __init esp4_init(void) { if (xfrm_register_type(&esp_type, AF_INET) < 0) { - printk(KERN_INFO "ip esp init: can't add xfrm type\n"); + pr_info("%s: can't add xfrm type\n", __func__); return -EAGAIN; } if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { - printk(KERN_INFO "ip esp init: can't add protocol\n"); + pr_info("%s: can't add protocol\n", __func__); xfrm_unregister_type(&esp_type, AF_INET); return -EAGAIN; } @@ -720,9 +720,9 @@ static int __init esp4_init(void) static void __exit esp4_fini(void) { if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) - printk(KERN_INFO "ip esp close: can't remove protocol\n"); + pr_info("%s: can't remove protocol\n", __func__); if (xfrm_unregister_type(&esp_type, AF_INET) < 0) - printk(KERN_INFO "ip esp close: can't remove xfrm type\n"); + pr_info("%s: can't remove xfrm type\n", __func__); } module_init(esp4_init); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 92fc5f69f5d..76e72bacc21 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -695,7 +695,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) if (ifa->ifa_flags & IFA_F_SECONDARY) { prim = inet_ifa_byprefix(in_dev, prefix, mask); if (prim == NULL) { - printk(KERN_WARNING "fib_add_ifaddr: bug: prim == NULL\n"); + pr_warn("%s: bug: prim == NULL\n", __func__); return; } } @@ -749,11 +749,11 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) if (ifa->ifa_flags & IFA_F_SECONDARY) { prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); if (prim == NULL) { - printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL\n"); + pr_warn("%s: bug: prim == NULL\n", __func__); return; } if (iprim && iprim != prim) { - printk(KERN_WARNING "fib_del_ifaddr: bug: iprim != prim\n"); + pr_warn("%s: bug: iprim != prim\n", __func__); return; } } else if (!ipv4_is_zeronet(any) && diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 80106d89d54..a8c5c1d6715 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -154,7 +154,7 @@ static void free_fib_info_rcu(struct rcu_head *head) void free_fib_info(struct fib_info *fi) { if (fi->fib_dead == 0) { - pr_warning("Freeing alive fib_info %p\n", fi); + pr_warn("Freeing alive fib_info %p\n", fi); return; } change_nexthops(fi) { diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 2b555a5521e..da9b9cb2282 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1170,9 +1170,8 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) } if (tp && tp->pos + tp->bits > 32) - pr_warning("fib_trie" - " tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", - tp, tp->pos, tp->bits, key, plen); + pr_warn("fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", + tp, tp->pos, tp->bits, key, plen); /* Rebalance the trie */ diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index ab188ae12fd..5c7323b7810 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -670,7 +670,7 @@ static void icmp_unreach(struct sk_buff *skb) break; case ICMP_FRAG_NEEDED: if (ipv4_config.no_pmtu_disc) { - LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: fragmentation needed and DF set.\n", + LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: fragmentation needed and DF set\n", &iph->daddr); } else { info = ip_rt_frag_needed(net, iph, @@ -681,7 +681,7 @@ static void icmp_unreach(struct sk_buff *skb) } break; case ICMP_SR_FAILED: - LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: Source Route Failed.\n", + LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: Source Route Failed\n", &iph->daddr); break; default: @@ -713,13 +713,10 @@ static void icmp_unreach(struct sk_buff *skb) if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses && inet_addr_type(net, iph->daddr) == RTN_BROADCAST) { if (net_ratelimit()) - printk(KERN_WARNING "%pI4 sent an invalid ICMP " - "type %u, code %u " - "error to a broadcast: %pI4 on %s\n", - &ip_hdr(skb)->saddr, - icmph->type, icmph->code, - &iph->daddr, - skb->dev->name); + pr_warn("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n", + &ip_hdr(skb)->saddr, + icmph->type, icmph->code, + &iph->daddr, skb->dev->name); goto out; } @@ -946,8 +943,8 @@ static void icmp_address_reply(struct sk_buff *skb) break; } if (!ifa && net_ratelimit()) { - printk(KERN_INFO "Wrong address mask %pI4 from %s/%pI4\n", - mp, dev->name, &ip_hdr(skb)->saddr); + pr_info("Wrong address mask %pI4 from %s/%pI4\n", + mp, dev->name, &ip_hdr(skb)->saddr); } } } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 1f23a57aa9e..b2fd333abd5 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -643,8 +643,7 @@ out_nomem: goto out_fail; out_oversize: if (net_ratelimit()) - printk(KERN_INFO "Oversized IP packet from %pI4.\n", - &qp->saddr); + pr_info("Oversized IP packet from %pI4\n", &qp->saddr); out_fail: IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); return err; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 6ef66af1229..185e0a75ece 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1716,7 +1716,7 @@ static int __init ipgre_init(void) { int err; - printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); + pr_info("GRE over IPv4 tunneling driver\n"); err = register_pernet_device(&ipgre_net_ops); if (err < 0) @@ -1724,7 +1724,7 @@ static int __init ipgre_init(void) err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO); if (err < 0) { - printk(KERN_INFO "ipgre init: can't add protocol\n"); + pr_info("%s: can't add protocol\n", __func__); goto add_proto_failed; } @@ -1753,7 +1753,7 @@ static void __exit ipgre_fini(void) rtnl_link_unregister(&ipgre_tap_ops); rtnl_link_unregister(&ipgre_link_ops); if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) - printk(KERN_INFO "ipgre close: can't remove protocol\n"); + pr_info("%s: can't remove protocol\n", __func__); unregister_pernet_device(&ipgre_net_ops); } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index bdaa2c5c28e..de8e9be4aac 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -299,8 +299,8 @@ static inline bool ip_rcv_options(struct sk_buff *skb) if (!IN_DEV_SOURCE_ROUTE(in_dev)) { if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "source route option %pI4 -> %pI4\n", - &iph->saddr, &iph->daddr); + pr_info("source route option %pI4 -> %pI4\n", + &iph->saddr, &iph->daddr); goto drop; } } diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 42dd1a90ede..e25ee7c8bdd 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -577,7 +577,7 @@ void ip_forward_options(struct sk_buff *skb) ip_rt_get_source(&optptr[srrptr-1], skb, rt); optptr[2] = srrptr+4; } else if (net_ratelimit()) - printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); + pr_crit("%s(): Argh! Destination lost!\n", __func__); if (opt->ts_needaddr) { optptr = raw + opt->ts; ip_rt_get_source(&optptr[optptr[2]-9], skb, rt); diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index c857f6f49b0..63b64c45a82 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -156,11 +156,11 @@ static const struct net_protocol ipcomp4_protocol = { static int __init ipcomp4_init(void) { if (xfrm_register_type(&ipcomp_type, AF_INET) < 0) { - printk(KERN_INFO "ipcomp init: can't add xfrm type\n"); + pr_info("%s: can't add xfrm type\n", __func__); return -EAGAIN; } if (inet_add_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0) { - printk(KERN_INFO "ipcomp init: can't add protocol\n"); + pr_info("%s: can't add protocol\n", __func__); xfrm_unregister_type(&ipcomp_type, AF_INET); return -EAGAIN; } @@ -170,9 +170,9 @@ static int __init ipcomp4_init(void) static void __exit ipcomp4_fini(void) { if (inet_del_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0) - printk(KERN_INFO "ip ipcomp close: can't remove protocol\n"); + pr_info("%s: can't remove protocol\n", __func__); if (xfrm_unregister_type(&ipcomp_type, AF_INET) < 0) - printk(KERN_INFO "ip ipcomp close: can't remove xfrm type\n"); + pr_info("%s: can't remove xfrm type\n", __func__); } module_init(ipcomp4_init); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 6e412a60a91..92ac7e7363a 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -214,7 +214,7 @@ static int __init ic_open_devs(void) if (!(dev->flags & IFF_LOOPBACK)) continue; if (dev_change_flags(dev, dev->flags | IFF_UP) < 0) - printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name); + pr_err("IP-Config: Failed to open %s\n", dev->name); } for_each_netdev(&init_net, dev) { @@ -223,7 +223,8 @@ static int __init ic_open_devs(void) if (dev->mtu >= 364) able |= IC_BOOTP; else - printk(KERN_WARNING "DHCP/BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu); + pr_warn("DHCP/BOOTP: Ignoring device %s, MTU %d too small", + dev->name, dev->mtu); if (!(dev->flags & IFF_NOARP)) able |= IC_RARP; able &= ic_proto_enabled; @@ -231,7 +232,8 @@ static int __init ic_open_devs(void) continue; oflags = dev->flags; if (dev_change_flags(dev, oflags | IFF_UP) < 0) { - printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name); + pr_err("IP-Config: Failed to open %s\n", + dev->name); continue; } if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) { @@ -273,9 +275,10 @@ have_carrier: if (!ic_first_dev) { if (user_dev_name[0]) - printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name); + pr_err("IP-Config: Device `%s' not found\n", + user_dev_name); else - printk(KERN_ERR "IP-Config: No network devices available.\n"); + pr_err("IP-Config: No network devices available\n"); return -ENODEV; } return 0; @@ -359,17 +362,20 @@ static int __init ic_setup_if(void) strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name); set_sockaddr(sin, ic_myaddr, 0); if ((err = ic_devinet_ioctl(SIOCSIFADDR, &ir)) < 0) { - printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err); + pr_err("IP-Config: Unable to set interface address (%d)\n", + err); return -1; } set_sockaddr(sin, ic_netmask, 0); if ((err = ic_devinet_ioctl(SIOCSIFNETMASK, &ir)) < 0) { - printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err); + pr_err("IP-Config: Unable to set interface netmask (%d)\n", + err); return -1; } set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { - printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err); + pr_err("IP-Config: Unable to set interface broadcast address (%d)\n", + err); return -1; } /* Handle the case where we need non-standard MTU on the boot link (a network @@ -380,8 +386,8 @@ static int __init ic_setup_if(void) strcpy(ir.ifr_name, ic_dev->name); ir.ifr_mtu = ic_dev_mtu; if ((err = ic_dev_ioctl(SIOCSIFMTU, &ir)) < 0) - printk(KERN_ERR "IP-Config: Unable to set interface mtu to %d (%d).\n", - ic_dev_mtu, err); + pr_err("IP-Config: Unable to set interface mtu to %d (%d)\n", + ic_dev_mtu, err); } return 0; } @@ -396,7 +402,7 @@ static int __init ic_setup_routes(void) memset(&rm, 0, sizeof(rm)); if ((ic_gateway ^ ic_myaddr) & ic_netmask) { - printk(KERN_ERR "IP-Config: Gateway not on directly connected network.\n"); + pr_err("IP-Config: Gateway not on directly connected network\n"); return -1; } set_sockaddr((struct sockaddr_in *) &rm.rt_dst, 0, 0); @@ -404,7 +410,8 @@ static int __init ic_setup_routes(void) set_sockaddr((struct sockaddr_in *) &rm.rt_gateway, ic_gateway, 0); rm.rt_flags = RTF_UP | RTF_GATEWAY; if ((err = ic_route_ioctl(SIOCADDRT, &rm)) < 0) { - printk(KERN_ERR "IP-Config: Cannot add default route (%d).\n", err); + pr_err("IP-Config: Cannot add default route (%d)\n", + err); return -1; } } @@ -437,8 +444,8 @@ static int __init ic_defaults(void) else if (IN_CLASSC(ntohl(ic_myaddr))) ic_netmask = htonl(IN_CLASSC_NET); else { - printk(KERN_ERR "IP-Config: Unable to guess netmask for address %pI4\n", - &ic_myaddr); + pr_err("IP-Config: Unable to guess netmask for address %pI4\n", + &ic_myaddr); return -1; } printk("IP-Config: Guessing netmask %pI4\n", &ic_netmask); @@ -688,8 +695,8 @@ ic_dhcp_init_options(u8 *options) e += len; } if (*vendor_class_identifier) { - printk(KERN_INFO "DHCP: sending class identifier \"%s\"\n", - vendor_class_identifier); + pr_info("DHCP: sending class identifier \"%s\"\n", + vendor_class_identifier); *e++ = 60; /* Class-identifier */ len = strlen(vendor_class_identifier); *e++ = len; @@ -949,8 +956,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str /* Fragments are not supported */ if (ip_is_fragment(h)) { if (net_ratelimit()) - printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented " - "reply.\n"); + pr_err("DHCP/BOOTP: Ignoring fragmented reply\n"); goto drop; } @@ -999,8 +1005,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str if (b->op != BOOTP_REPLY || b->xid != d->xid) { if (net_ratelimit()) - printk(KERN_ERR "DHCP/BOOTP: Reply not for us, " - "op[%x] xid[%x]\n", + pr_err("DHCP/BOOTP: Reply not for us, op[%x] xid[%x]\n", b->op, b->xid); goto drop_unlock; } @@ -1008,7 +1013,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str /* Is it a reply for the device we are configuring? */ if (b->xid != ic_dev_xid) { if (net_ratelimit()) - printk(KERN_ERR "DHCP/BOOTP: Ignoring delayed packet\n"); + pr_err("DHCP/BOOTP: Ignoring delayed packet\n"); goto drop_unlock; } @@ -1146,17 +1151,17 @@ static int __init ic_dynamic(void) * are missing, and without DHCP/BOOTP/RARP we are unable to get it. */ if (!ic_proto_enabled) { - printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n"); + pr_err("IP-Config: Incomplete network configuration information\n"); return -1; } #ifdef IPCONFIG_BOOTP if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP) - printk(KERN_ERR "DHCP/BOOTP: No suitable device found.\n"); + pr_err("DHCP/BOOTP: No suitable device found\n"); #endif #ifdef IPCONFIG_RARP if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP) - printk(KERN_ERR "RARP: No suitable device found.\n"); + pr_err("RARP: No suitable device found\n"); #endif if (!ic_proto_have_if) @@ -1183,11 +1188,11 @@ static int __init ic_dynamic(void) * [Actually we could now, but the nothing else running note still * applies.. - AC] */ - printk(KERN_NOTICE "Sending %s%s%s requests .", - do_bootp - ? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "", - (do_bootp && do_rarp) ? " and " : "", - do_rarp ? "RARP" : ""); + pr_notice("Sending %s%s%s requests .", + do_bootp + ? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "", + (do_bootp && do_rarp) ? " and " : "", + do_rarp ? "RARP" : ""); start_jiffies = jiffies; d = ic_first_dev; @@ -1216,13 +1221,13 @@ static int __init ic_dynamic(void) (ic_proto_enabled & IC_USE_DHCP) && ic_dhcp_msgtype != DHCPACK) { ic_got_reply = 0; - printk(KERN_CONT ","); + pr_cont(","); continue; } #endif /* IPCONFIG_DHCP */ if (ic_got_reply) { - printk(KERN_CONT " OK\n"); + pr_cont(" OK\n"); break; } @@ -1230,7 +1235,7 @@ static int __init ic_dynamic(void) continue; if (! --retries) { - printk(KERN_CONT " timed out!\n"); + pr_cont(" timed out!\n"); break; } @@ -1240,7 +1245,7 @@ static int __init ic_dynamic(void) if (timeout > CONF_TIMEOUT_MAX) timeout = CONF_TIMEOUT_MAX; - printk(KERN_CONT "."); + pr_cont("."); } #ifdef IPCONFIG_BOOTP @@ -1260,8 +1265,8 @@ static int __init ic_dynamic(void) printk("IP-Config: Got %s answer from %pI4, ", ((ic_got_reply & IC_RARP) ? "RARP" : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), - &ic_servaddr); - printk(KERN_CONT "my address is %pI4\n", &ic_myaddr); + &ic_servaddr); + pr_cont("my address is %pI4\n", &ic_myaddr); return 0; } @@ -1437,24 +1442,22 @@ static int __init ip_auto_config(void) */ #ifdef CONFIG_ROOT_NFS if (ROOT_DEV == Root_NFS) { - printk(KERN_ERR - "IP-Config: Retrying forever (NFS root)...\n"); + pr_err("IP-Config: Retrying forever (NFS root)...\n"); goto try_try_again; } #endif if (--retries) { - printk(KERN_ERR - "IP-Config: Reopening network devices...\n"); + pr_err("IP-Config: Reopening network devices...\n"); goto try_try_again; } /* Oh, well. At least we tried. */ - printk(KERN_ERR "IP-Config: Auto-configuration of network failed.\n"); + pr_err("IP-Config: Auto-configuration of network failed\n"); return -1; } #else /* !DYNAMIC */ - printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n"); + pr_err("IP-Config: Incomplete network configuration information\n"); ic_close_devs(); return -1; #endif /* IPCONFIG_DYNAMIC */ @@ -1492,19 +1495,16 @@ static int __init ip_auto_config(void) /* * Clue in the operator. */ - printk("IP-Config: Complete:\n"); - printk(" device=%s", ic_dev->name); - printk(KERN_CONT ", addr=%pI4", &ic_myaddr); - printk(KERN_CONT ", mask=%pI4", &ic_netmask); - printk(KERN_CONT ", gw=%pI4", &ic_gateway); - printk(KERN_CONT ",\n host=%s, domain=%s, nis-domain=%s", - utsname()->nodename, ic_domain, utsname()->domainname); - printk(KERN_CONT ",\n bootserver=%pI4", &ic_servaddr); - printk(KERN_CONT ", rootserver=%pI4", &root_server_addr); - printk(KERN_CONT ", rootpath=%s", root_server_path); + pr_info("IP-Config: Complete:\n"); + pr_info(" device=%s, addr=%pI4, mask=%pI4, gw=%pI4\n", + ic_dev->name, &ic_myaddr, &ic_netmask, &ic_gateway); + pr_info(" host=%s, domain=%s, nis-domain=%s\n", + utsname()->nodename, ic_domain, utsname()->domainname); + pr_info(" bootserver=%pI4, rootserver=%pI4, rootpath=%s", + &ic_servaddr, &root_server_addr, root_server_path); if (ic_dev_mtu) - printk(KERN_CONT ", mtu=%d", ic_dev_mtu); - printk(KERN_CONT "\n"); + pr_cont(", mtu=%d", ic_dev_mtu); + pr_cont("\n"); #endif /* !SILENT */ return 0; @@ -1637,8 +1637,8 @@ static int __init vendor_class_identifier_setup(char *addrs) if (strlcpy(vendor_class_identifier, addrs, sizeof(vendor_class_identifier)) >= sizeof(vendor_class_identifier)) - printk(KERN_WARNING "DHCP: vendorclass too long, truncated to \"%s\"", - vendor_class_identifier); + pr_warn("DHCP: vendorclass too long, truncated to \"%s\"", + vendor_class_identifier); return 1; } diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index f84ebff5cdb..ae1413e3f2f 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -892,7 +892,7 @@ static int __init ipip_init(void) err = xfrm4_tunnel_register(&ipip_handler, AF_INET); if (err < 0) { unregister_pernet_device(&ipip_net_ops); - printk(KERN_INFO "ipip init: can't register tunnel\n"); + pr_info("%s: can't register tunnel\n", __func__); } return err; } @@ -900,7 +900,7 @@ static int __init ipip_init(void) static void __exit ipip_fini(void) { if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) - printk(KERN_INFO "ipip close: can't deregister tunnel\n"); + pr_info("%s: can't deregister tunnel\n", __func__); unregister_pernet_device(&ipip_net_ops); } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 7bc2db6db8d..0518a4fb177 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -951,7 +951,7 @@ static int ipmr_cache_report(struct mr_table *mrt, rcu_read_unlock(); if (ret < 0) { if (net_ratelimit()) - printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n"); + pr_warn("mroute: pending queue full, dropping entries\n"); kfree_skb(skb); } @@ -2538,7 +2538,7 @@ int __init ip_mr_init(void) goto reg_notif_fail; #ifdef CONFIG_IP_PIMSM_V2 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) { - printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n"); + pr_err("%s: can't add PIM protocol\n", __func__); err = -EAGAIN; goto add_proto_fail; } diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 4398a45a960..ab6b36e6da1 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -156,7 +156,7 @@ static struct sock *ping_v4_lookup(struct net *net, __be32 saddr, __be32 daddr, struct hlist_nulls_node *hnode; pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n", - (int)ident, &daddr, dif); + (int)ident, &daddr, dif); read_lock_bh(&ping_table.lock); ping_portaddr_for_each_entry(sk, hnode, hslot) { @@ -229,7 +229,7 @@ static int ping_init_sock(struct sock *sk) static void ping_close(struct sock *sk, long timeout) { pr_debug("ping_close(sk=%p,sk->num=%u)\n", - inet_sk(sk), inet_sk(sk)->inet_num); + inet_sk(sk), inet_sk(sk)->inet_num); pr_debug("isk->refcnt = %d\n", sk->sk_refcnt.counter); sk_common_release(sk); @@ -252,7 +252,7 @@ static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) return -EINVAL; pr_debug("ping_v4_bind(sk=%p,sa_addr=%08x,sa_port=%d)\n", - sk, addr->sin_addr.s_addr, ntohs(addr->sin_port)); + sk, addr->sin_addr.s_addr, ntohs(addr->sin_port)); chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); if (addr->sin_addr.s_addr == htonl(INADDR_ANY)) @@ -280,9 +280,9 @@ static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) } pr_debug("after bind(): num = %d, daddr = %pI4, dif = %d\n", - (int)isk->inet_num, - &isk->inet_rcv_saddr, - (int)sk->sk_bound_dev_if); + (int)isk->inet_num, + &isk->inet_rcv_saddr, + (int)sk->sk_bound_dev_if); err = 0; if (isk->inet_rcv_saddr) @@ -335,7 +335,7 @@ void ping_err(struct sk_buff *skb, u32 info) return; pr_debug("ping_err(type=%04x,code=%04x,id=%04x,seq=%04x)\n", type, - code, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence)); + code, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence)); sk = ping_v4_lookup(net, iph->daddr, iph->saddr, ntohs(icmph->un.echo.id), skb->dev->ifindex); @@ -679,7 +679,7 @@ out: static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n", - inet_sk(sk), inet_sk(sk)->inet_num, skb); + inet_sk(sk), inet_sk(sk)->inet_num, skb); if (sock_queue_rcv_skb(sk, skb) < 0) { kfree_skb(skb); pr_debug("ping_queue_rcv_skb -> failed\n"); @@ -705,7 +705,7 @@ void ping_rcv(struct sk_buff *skb) /* We assume the packet has already been checked by icmp_rcv */ pr_debug("ping_rcv(skb=%p,id=%04x,seq=%04x)\n", - skb, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence)); + skb, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence)); /* Push ICMP header back */ skb_push(skb, skb->data - (u8 *)icmph); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index ab466305b62..bbd604c68e6 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -491,11 +491,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (msg->msg_namelen < sizeof(*usin)) goto out; if (usin->sin_family != AF_INET) { - static int complained; - if (!complained++) - printk(KERN_INFO "%s forgot to set AF_INET in " - "raw sendmsg. Fix it!\n", - current->comm); + pr_info_once("%s: %s forgot to set AF_INET. Fix it!\n", + __func__, current->comm); err = -EAFNOSUPPORT; if (usin->sin_family) goto out; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 815989b90de..cbda6de0a77 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -959,7 +959,7 @@ void rt_cache_flush_batch(struct net *net) static void rt_emergency_hash_rebuild(struct net *net) { if (net_ratelimit()) - printk(KERN_WARNING "Route hash chain too long!\n"); + pr_warn("Route hash chain too long!\n"); rt_cache_invalidate(net); } @@ -1083,7 +1083,7 @@ static int rt_garbage_collect(struct dst_ops *ops) if (dst_entries_get_slow(&ipv4_dst_ops) < ip_rt_max_size) goto out; if (net_ratelimit()) - printk(KERN_WARNING "dst cache overflow\n"); + pr_warn("dst cache overflow\n"); RT_CACHE_STAT_INC(gc_dst_overflow); return 1; @@ -1181,8 +1181,7 @@ restart: int err = rt_bind_neighbour(rt); if (err) { if (net_ratelimit()) - printk(KERN_WARNING - "Neighbour table failure & not caching routes.\n"); + pr_warn("Neighbour table failure & not caching routes\n"); ip_rt_put(rt); return ERR_PTR(err); } @@ -1258,7 +1257,7 @@ restart: struct net *net = dev_net(rt->dst.dev); int num = ++net->ipv4.current_rt_cache_rebuild_count; if (!rt_caching(net)) { - printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n", + pr_warn("%s: %d rebuilds is over limit, route caching disabled\n", rt->dst.dev->name, num); } rt_emergency_hash_rebuild(net); @@ -1299,7 +1298,7 @@ restart: } if (net_ratelimit()) - printk(KERN_WARNING "ipv4: Neighbour table overflow.\n"); + pr_warn("ipv4: Neighbour table overflow\n"); rt_drop(rt); return ERR_PTR(-ENOBUFS); } @@ -1503,10 +1502,10 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, reject_redirect: #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "Redirect from %pI4 on %s about %pI4 ignored.\n" + pr_info("Redirect from %pI4 on %s about %pI4 ignored\n" " Advised path = %pI4 -> %pI4\n", - &old_gw, dev->name, &new_gw, - &saddr, &daddr); + &old_gw, dev->name, &new_gw, + &saddr, &daddr); #endif ; } @@ -1618,8 +1617,8 @@ void ip_rt_send_redirect(struct sk_buff *skb) if (log_martians && peer->rate_tokens == ip_rt_redirect_number && net_ratelimit()) - printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.\n", - &ip_hdr(skb)->saddr, rt->rt_iif, + pr_warn("host %pI4/if%d ignores redirects for %pI4 to %pI4\n", + &ip_hdr(skb)->saddr, rt->rt_iif, &rt->rt_dst, &rt->rt_gateway); #endif } @@ -2105,18 +2104,13 @@ static void ip_handle_martian_source(struct net_device *dev, * RFC1812 recommendation, if source is martian, * the only hint is MAC header. */ - printk(KERN_WARNING "martian source %pI4 from %pI4, on dev %s\n", + pr_warn("martian source %pI4 from %pI4, on dev %s\n", &daddr, &saddr, dev->name); if (dev->hard_header_len && skb_mac_header_was_set(skb)) { - int i; - const unsigned char *p = skb_mac_header(skb); - printk(KERN_WARNING "ll header: "); - for (i = 0; i < dev->hard_header_len; i++, p++) { - printk("%02x", *p); - if (i < (dev->hard_header_len - 1)) - printk(":"); - } - printk("\n"); + print_hex_dump(KERN_WARNING, "ll header: ", + DUMP_PREFIX_OFFSET, 16, 1, + skb_mac_header(skb), + dev->hard_header_len, true); } } #endif @@ -2140,8 +2134,7 @@ static int __mkroute_input(struct sk_buff *skb, out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res)); if (out_dev == NULL) { if (net_ratelimit()) - printk(KERN_CRIT "Bug in ip_route_input" \ - "_slow(). Please, report\n"); + pr_crit("Bug in ip_route_input_slow(). Please report.\n"); return -EINVAL; } @@ -2413,7 +2406,7 @@ martian_destination: RT_CACHE_STAT_INC(in_martian_dst); #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_WARNING "martian destination %pI4 from %pI4, dev %s\n", + pr_warn("martian destination %pI4 from %pI4, dev %s\n", &daddr, &saddr, dev->name); #endif @@ -3490,7 +3483,7 @@ int __init ip_rt_init(void) net_random() % ip_rt_gc_interval + ip_rt_gc_interval); if (ip_rt_proc_init()) - printk(KERN_ERR "Unable to create route proc files\n"); + pr_err("Unable to create route proc files\n"); #ifdef CONFIG_XFRM xfrm_init(); xfrm4_init(ip_rt_max_size); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 22ef5f9fd2f..2baba1bed81 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1675,7 +1675,7 @@ do_prequeue: if (tp->ucopy.dma_cookie < 0) { - printk(KERN_ALERT "dma_cookie < 0\n"); + pr_alert("dma_cookie < 0\n"); /* Exception. Bailout! */ if (!copied) @@ -3311,9 +3311,8 @@ void __init tcp_init(void) sysctl_tcp_rmem[1] = 87380; sysctl_tcp_rmem[2] = max(87380, max_share); - printk(KERN_INFO "TCP: Hash tables configured " - "(established %u bind %u)\n", - tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); + pr_info("TCP: Hash tables configured (established %u bind %u)\n", + tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); tcp_register_congestion_control(&tcp_reno); diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index fc6d475f488..67bab75f441 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -41,18 +41,17 @@ int tcp_register_congestion_control(struct tcp_congestion_ops *ca) /* all algorithms must implement ssthresh and cong_avoid ops */ if (!ca->ssthresh || !ca->cong_avoid) { - printk(KERN_ERR "TCP %s does not implement required ops\n", - ca->name); + pr_err("TCP %s does not implement required ops\n", ca->name); return -EINVAL; } spin_lock(&tcp_cong_list_lock); if (tcp_ca_find(ca->name)) { - printk(KERN_NOTICE "TCP %s already registered\n", ca->name); + pr_notice("TCP %s already registered\n", ca->name); ret = -EEXIST; } else { list_add_tail_rcu(&ca->list, &tcp_cong_list); - printk(KERN_INFO "TCP %s registered\n", ca->name); + pr_info("TCP %s registered\n", ca->name); } spin_unlock(&tcp_cong_list_lock); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b5e315f1364..23ca3663d1e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3867,9 +3867,9 @@ void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *o opt_rx->wscale_ok = 1; if (snd_wscale > 14) { if (net_ratelimit()) - printk(KERN_INFO "tcp_parse_options: Illegal window " - "scaling value %d >14 received.\n", - snd_wscale); + pr_info("%s: Illegal window scaling value %d >14 received\n", + __func__, + snd_wscale); snd_wscale = 14; } opt_rx->snd_wscale = snd_wscale; @@ -4191,7 +4191,7 @@ static void tcp_fin(struct sock *sk) /* Only TCP_LISTEN and TCP_CLOSE are left, in these * cases we should never reach this piece of code. */ - printk(KERN_ERR "%s: Impossible, sk->sk_state=%d\n", + pr_err("%s: Impossible, sk->sk_state=%d\n", __func__, sk->sk_state); break; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 507924b640e..257dba66eac 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1227,10 +1227,10 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (net_ratelimit()) { - printk(KERN_INFO "MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s\n", - &iph->saddr, ntohs(th->source), - &iph->daddr, ntohs(th->dest), - genhash ? " tcp_v4_calc_md5_hash failed" : ""); + pr_info("MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s\n", + &iph->saddr, ntohs(th->source), + &iph->daddr, ntohs(th->dest), + genhash ? " tcp_v4_calc_md5_hash failed" : ""); } return 1; } diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index 01775983b99..0d017183062 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -164,12 +164,12 @@ static const struct net_protocol tunnel64_protocol = { static int __init tunnel4_init(void) { if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { - printk(KERN_ERR "tunnel4 init: can't add protocol\n"); + pr_err("%s: can't add protocol\n", __func__); return -EAGAIN; } #if IS_ENABLED(CONFIG_IPV6) if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { - printk(KERN_ERR "tunnel64 init: can't add protocol\n"); + pr_err("tunnel64 init: can't add protocol\n"); inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); return -EAGAIN; } @@ -181,10 +181,10 @@ static void __exit tunnel4_fini(void) { #if IS_ENABLED(CONFIG_IPV6) if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) - printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); + pr_err("tunnel64 close: can't remove protocol\n"); #endif if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) - printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); + pr_err("tunnel4 close: can't remove protocol\n"); } module_init(tunnel4_init); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 12e9499a1a6..280bfb12adc 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -129,11 +129,11 @@ void __init udplite4_register(void) inet_register_protosw(&udplite4_protosw); if (udplite4_proc_init()) - printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); + pr_err("%s: Cannot register /proc!\n", __func__); return; out_unregister_proto: proto_unregister(&udplite_prot); out_register_err: - printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__); + pr_crit("%s: Cannot add UDP-Lite protocol\n", __func__); } diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 9247d9d70e9..5b48f49df0b 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -75,18 +75,18 @@ static struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = { static int __init ipip_init(void) { if (xfrm_register_type(&ipip_type, AF_INET) < 0) { - printk(KERN_INFO "ipip init: can't add xfrm type\n"); + pr_info("%s: can't add xfrm type\n", __func__); return -EAGAIN; } if (xfrm4_tunnel_register(&xfrm_tunnel_handler, AF_INET)) { - printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET\n"); + pr_info("%s: can't add xfrm handler for AF_INET\n", __func__); xfrm_unregister_type(&ipip_type, AF_INET); return -EAGAIN; } #if IS_ENABLED(CONFIG_IPV6) if (xfrm4_tunnel_register(&xfrm64_tunnel_handler, AF_INET6)) { - printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET6\n"); + pr_info("%s: can't add xfrm handler for AF_INET6\n", __func__); xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET); xfrm_unregister_type(&ipip_type, AF_INET); return -EAGAIN; @@ -99,12 +99,14 @@ static void __exit ipip_fini(void) { #if IS_ENABLED(CONFIG_IPV6) if (xfrm4_tunnel_deregister(&xfrm64_tunnel_handler, AF_INET6)) - printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET6\n"); + pr_info("%s: can't remove xfrm handler for AF_INET6\n", + __func__); #endif if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET)) - printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET\n"); + pr_info("%s: can't remove xfrm handler for AF_INET\n", + __func__); if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) - printk(KERN_INFO "ipip close: can't remove xfrm type\n"); + pr_info("%s: can't remove xfrm type\n", __func__); } module_init(ipip_init); -- cgit v1.2.3-70-g09d2 From 0097143c12e279f5d454e0f636a02afff102cc6a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Mar 2012 13:29:05 -0400 Subject: SUNRPC: Don't use variable length automatic arrays in kernel code Replace the variable length array in the RPCSEC_GSS crypto code with a fixed length one. The size should be bounded by the variable GSS_KRB5_MAX_BLOCKSIZE, so use that. Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_krb5_crypto.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 9576f35ab70..0f43e894bc0 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -600,11 +600,14 @@ gss_krb5_cts_crypt(struct crypto_blkcipher *cipher, struct xdr_buf *buf, u32 ret; struct scatterlist sg[1]; struct blkcipher_desc desc = { .tfm = cipher, .info = iv }; - u8 data[crypto_blkcipher_blocksize(cipher) * 2]; + u8 data[GSS_KRB5_MAX_BLOCKSIZE * 2]; struct page **save_pages; u32 len = buf->len - offset; - BUG_ON(len > crypto_blkcipher_blocksize(cipher) * 2); + if (len > ARRAY_SIZE(data)) { + WARN_ON(0); + return -ENOMEM; + } /* * For encryption, we want to read from the cleartext -- cgit v1.2.3-70-g09d2 From 4486ea987efdaa546bdda569e3dfacdc14a9fb13 Mon Sep 17 00:00:00 2001 From: Bala Shanmugam Date: Wed, 7 Mar 2012 17:27:12 +0530 Subject: cfg80211: Add background scan period attribute. Receive background scan period as part of connect command and pass the same to the driver. Signed-off-by: Bala Shanmugam Signed-off-by: John W. Linville --- include/linux/nl80211.h | 10 ++++++++++ include/net/cfg80211.h | 3 +++ net/wireless/nl80211.c | 8 ++++++++ net/wireless/wext-sme.c | 3 +++ 4 files changed, 24 insertions(+) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c37d67add09..e474f6e780c 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -369,6 +369,11 @@ * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. + * Background scan period can optionally be + * specified in %NL80211_ATTR_BG_SCAN_PERIOD, + * if not specified default background scan configuration + * in driver is used and if period value is 0, bg scan will be disabled. + * This attribute is ignored if driver does not support roam scan. * It is also sent as an event, with the BSSID and response IEs when the * connection is established or failed to be established. This can be * determined by the STATUS_CODE attribute. @@ -1207,6 +1212,9 @@ enum nl80211_commands { * this attribute is (depending on the driver capabilities) added to * received frames indicated with %NL80211_CMD_FRAME. * + * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds + * or 0 to disable background scan. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1456,6 +1464,8 @@ enum nl80211_attrs { NL80211_ATTR_RX_SIGNAL_DBM, + NL80211_ATTR_BG_SCAN_PERIOD, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 57c9fddc2ac..66f460325e2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1203,6 +1203,8 @@ struct cfg80211_ibss_params { * @key_idx: index of WEP key for shared key authentication * @key: WEP key for shared key authentication * @flags: See &enum cfg80211_assoc_req_flags + * @bg_scan_period: Background scan period in seconds + * or -1 to indicate that default value is to be used. * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask * will be used in ht_capa. Un-supported values will be ignored. * @ht_capa_mask: The bits of ht_capa which are to be used. @@ -1220,6 +1222,7 @@ struct cfg80211_connect_params { const u8 *key; u8 key_len, key_idx; u32 flags; + int bg_scan_period; struct ieee80211_ht_cap ht_capa; struct ieee80211_ht_cap ht_capa_mask; }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 39dbdf2adb1..4c1eb9472dd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -205,6 +205,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { }, [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, }; /* policy for the key attributes */ @@ -5116,6 +5117,13 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) wiphy = &rdev->wiphy; + connect.bg_scan_period = -1; + if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] && + (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) { + connect.bg_scan_period = + nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]); + } + if (info->attrs[NL80211_ATTR_MAC]) connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 326750b9915..7c01c2f3b6c 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -30,6 +30,9 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, wdev->wext.connect.ie = wdev->wext.ie; wdev->wext.connect.ie_len = wdev->wext.ie_len; + /* Use default background scan period */ + wdev->wext.connect.bg_scan_period = -1; + if (wdev->wext.keys) { wdev->wext.keys->def = wdev->wext.default_key; wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; -- cgit v1.2.3-70-g09d2 From aa4545806025c63ec12cfe17528de16dca36b785 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 7 Mar 2012 17:20:30 +0100 Subject: mac80211: Limit TID buffering during BA session setup/teardown While setting up or tearing down a BA session mac80211 is buffering pending frames for the according TID. However, there's currently no limit on how many frames are buffered possibly leading to an out-of- memory situation. This can happen on systems with little memory when the CPU is fully loaded since the BA session work is executed in process context while frames can still come via softirq. Apply a limitation to the TIDs pending queue to avoid consuming too much memory in this situation. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/tx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 570737df2d2..d9e791d2b54 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1065,6 +1065,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, { bool queued = false; bool reset_agg_timer = false; + struct sk_buff *purge_skb = NULL; if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { info->flags |= IEEE80211_TX_CTL_AMPDU; @@ -1106,8 +1107,13 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, info->control.vif = &tx->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; __skb_queue_tail(&tid_tx->pending, skb); + if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER) + purge_skb = __skb_dequeue(&tid_tx->pending); } spin_unlock(&tx->sta->lock); + + if (purge_skb) + dev_kfree_skb(purge_skb); } /* reset session timer */ -- cgit v1.2.3-70-g09d2 From 177958e9679c23537411066cc41b205635dacb14 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 9 Mar 2012 12:49:21 +0100 Subject: mac80211: remove tx_sync When the station state callback was added, this was no longer needed in theory. With the iwlwifi changes to remove use of it landing, we can kill the entire tx-sync framework again, RIP. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 41 ----------------------------------------- net/mac80211/driver-ops.h | 35 ----------------------------------- net/mac80211/driver-trace.h | 43 ------------------------------------------- net/mac80211/ieee80211_i.h | 1 - net/mac80211/mlme.c | 41 ----------------------------------------- 5 files changed, 161 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f7917f765cb..44e4dfcb572 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1765,20 +1765,6 @@ enum ieee80211_ampdu_mlme_action { IEEE80211_AMPDU_TX_OPERATIONAL, }; -/** - * enum ieee80211_tx_sync_type - TX sync type - * @IEEE80211_TX_SYNC_AUTH: sync TX for authentication - * (and possibly also before direct probe) - * @IEEE80211_TX_SYNC_ASSOC: sync TX for association - * @IEEE80211_TX_SYNC_ACTION: sync TX for action frame - * (not implemented yet) - */ -enum ieee80211_tx_sync_type { - IEEE80211_TX_SYNC_AUTH, - IEEE80211_TX_SYNC_ASSOC, - IEEE80211_TX_SYNC_ACTION, -}; - /** * enum ieee80211_frame_release_type - frame release reason * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll @@ -1889,26 +1875,6 @@ enum ieee80211_frame_release_type { * of the bss parameters has changed when a call is made. The callback * can sleep. * - * @tx_sync: Called before a frame is sent to an AP/GO. In the GO case, the - * driver should sync with the GO's powersaving so the device doesn't - * transmit the frame while the GO is asleep. In the regular AP case - * it may be used by drivers for devices implementing other restrictions - * on talking to APs, e.g. due to regulatory enforcement or just HW - * restrictions. - * This function is called for every authentication, association and - * action frame separately since applications might attempt to auth - * with multiple APs before chosing one to associate to. If it returns - * an error, the corresponding authentication, association or frame - * transmission is aborted and reported as having failed. It is always - * called after tuning to the correct channel. - * The callback might be called multiple times before @finish_tx_sync - * (but @finish_tx_sync will be called once for each) but in practice - * this is unlikely to happen. It can also refuse in that case if the - * driver cannot handle that situation. - * This callback can sleep. - * @finish_tx_sync: Called as a counterpart to @tx_sync, unless that returned - * an error. This callback can sleep. - * * @prepare_multicast: Prepare for multicast filter configuration. * This callback is optional, and its return value is passed * to configure_filter(). This callback must be atomic. @@ -2180,13 +2146,6 @@ struct ieee80211_ops { struct ieee80211_bss_conf *info, u32 changed); - int (*tx_sync)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - const u8 *bssid, enum ieee80211_tx_sync_type type); - void (*finish_tx_sync)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const u8 *bssid, - enum ieee80211_tx_sync_type type); - u64 (*prepare_multicast)(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); void (*configure_filter)(struct ieee80211_hw *hw, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 70dfb6415c2..af4691fed64 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -168,41 +168,6 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, trace_drv_return_void(local); } -static inline int drv_tx_sync(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - const u8 *bssid, - enum ieee80211_tx_sync_type type) -{ - int ret = 0; - - might_sleep(); - - check_sdata_in_driver(sdata); - - trace_drv_tx_sync(local, sdata, bssid, type); - if (local->ops->tx_sync) - ret = local->ops->tx_sync(&local->hw, &sdata->vif, - bssid, type); - trace_drv_return_int(local, ret); - return ret; -} - -static inline void drv_finish_tx_sync(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - const u8 *bssid, - enum ieee80211_tx_sync_type type) -{ - might_sleep(); - - check_sdata_in_driver(sdata); - - trace_drv_finish_tx_sync(local, sdata, bssid, type); - if (local->ops->finish_tx_sync) - local->ops->finish_tx_sync(&local->hw, &sdata->vif, - bssid, type); - trace_drv_return_void(local); -} - static inline u64 drv_prepare_multicast(struct ieee80211_local *local, struct netdev_hw_addr_list *mc_list) { diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 384e2f08c18..7034209ad3f 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -308,49 +308,6 @@ TRACE_EVENT(drv_bss_info_changed, ) ); -DECLARE_EVENT_CLASS(tx_sync_evt, - TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - const u8 *bssid, - enum ieee80211_tx_sync_type type), - TP_ARGS(local, sdata, bssid, type), - - TP_STRUCT__entry( - LOCAL_ENTRY - VIF_ENTRY - __array(char, bssid, ETH_ALEN) - __field(u32, sync_type) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - VIF_ASSIGN; - memcpy(__entry->bssid, bssid, ETH_ALEN); - __entry->sync_type = type; - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " bssid:%pM type:%d", - LOCAL_PR_ARG, VIF_PR_ARG, __entry->bssid, __entry->sync_type - ) -); - -DEFINE_EVENT(tx_sync_evt, drv_tx_sync, - TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - const u8 *bssid, - enum ieee80211_tx_sync_type type), - TP_ARGS(local, sdata, bssid, type) -); - -DEFINE_EVENT(tx_sync_evt, drv_finish_tx_sync, - TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - const u8 *bssid, - enum ieee80211_tx_sync_type type), - TP_ARGS(local, sdata, bssid, type) -); - TRACE_EVENT(drv_prepare_multicast, TP_PROTO(struct ieee80211_local *local, int mc_count), diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 796b13bfc95..3c62ded64e3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -388,7 +388,6 @@ struct ieee80211_mgd_auth_data { u8 key[WLAN_KEY_LEN_WEP104]; u8 key_len, key_idx; - bool synced; bool done; size_t ie_len; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c08924aeac0..1d09df248c5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1770,11 +1770,6 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, lockdep_assert_held(&sdata->u.mgd.mtx); - if (auth_data->synced) - drv_finish_tx_sync(sdata->local, sdata, - auth_data->bss->bssid, - IEEE80211_TX_SYNC_AUTH); - if (!assoc) { sta_info_destroy_addr(sdata, auth_data->bss->bssid); @@ -1862,10 +1857,6 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: authenticated\n", sdata->name); out: - if (ifmgd->auth_data->synced) - drv_finish_tx_sync(sdata->local, sdata, bssid, - IEEE80211_TX_SYNC_AUTH); - ifmgd->auth_data->synced = false; ifmgd->auth_data->done = true; ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; run_again(ifmgd, ifmgd->auth_data->timeout); @@ -2005,11 +1996,6 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, lockdep_assert_held(&sdata->u.mgd.mtx); - if (assoc_data->synced) - drv_finish_tx_sync(sdata->local, sdata, - assoc_data->bss->bssid, - IEEE80211_TX_SYNC_ASSOC); - if (!assoc) { sta_info_destroy_addr(sdata, assoc_data->bss->bssid); @@ -2255,14 +2241,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } else { printk(KERN_DEBUG "%s: associated\n", sdata->name); - /* tell driver about sync done first */ - if (assoc_data->synced) { - drv_finish_tx_sync(sdata->local, sdata, - assoc_data->bss->bssid, - IEEE80211_TX_SYNC_ASSOC); - assoc_data->synced = false; - } - if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { /* oops -- internal error -- send timeout for now */ ieee80211_destroy_assoc_data(sdata, true); @@ -2747,14 +2725,6 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) if (WARN_ON_ONCE(!auth_data)) return -EINVAL; - if (!auth_data->synced) { - int ret = drv_tx_sync(local, sdata, auth_data->bss->bssid, - IEEE80211_TX_SYNC_AUTH); - if (ret) - return ret; - } - auth_data->synced = true; - auth_data->tries++; if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { @@ -2811,14 +2781,6 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&sdata->u.mgd.mtx); - if (!assoc_data->synced) { - int ret = drv_tx_sync(local, sdata, assoc_data->bss->bssid, - IEEE80211_TX_SYNC_ASSOC); - if (ret) - return ret; - } - assoc_data->synced = true; - assoc_data->tries++; if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { printk(KERN_DEBUG "%s: association with %pM timed out\n", @@ -3245,9 +3207,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, err = ieee80211_probe_auth(sdata); if (err) { - if (auth_data->synced) - drv_finish_tx_sync(local, sdata, req->bss->bssid, - IEEE80211_TX_SYNC_AUTH); sta_info_destroy_addr(sdata, req->bss->bssid); goto err_clear; } -- cgit v1.2.3-70-g09d2 From 3cc5240b5e036abb565c8ac7cffdcceb06a13517 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 9 Mar 2012 13:12:35 +0100 Subject: mac80211: set channel back after disassociating As we've discussed, we want to avoid channel changes while associated. While the part when we actually associate needs a bit more work, the bit that happens on disassociating can be changed quite easily. Move the channel type change later in the disassociate process to set the channel only after the driver was told that it's now disassociated. As the driver could expect powersave to be enabled only when associated, this thus results in splitting the config call, but overall what happens makes more sense this way. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1d09df248c5..5c2ba80c293 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1394,7 +1394,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct sta_info *sta; - u32 changed = 0, config_changed = 0; + u32 changed = 0; u8 bssid[ETH_ALEN]; ASSERT_MGD_MTX(ifmgd); @@ -1454,9 +1454,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ASSOC; sdata->vif.bss_conf.assoc = false; - /* channel(_type) changes are handled by ieee80211_hw_config */ - WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT)); - /* on the next assoc, re-program HT parameters */ sdata->ht_opmode_valid = false; memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); @@ -1469,12 +1466,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, if (local->hw.conf.flags & IEEE80211_CONF_PS) { local->hw.conf.flags &= ~IEEE80211_CONF_PS; - config_changed |= IEEE80211_CONF_CHANGE_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } local->ps_sdata = NULL; - ieee80211_hw_config(local, config_changed); - /* Disable ARP filtering */ if (sdata->vif.bss_conf.arp_filter_enabled) { sdata->vif.bss_conf.arp_filter_enabled = false; @@ -1488,6 +1483,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; ieee80211_bss_info_change_notify(sdata, changed); + /* channel(_type) changes are handled by ieee80211_hw_config */ + WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT)); + ieee80211_hw_config(local, 0); + /* disassociated - set to defaults now */ ieee80211_set_wmm_default(sdata, false); -- cgit v1.2.3-70-g09d2 From e9219779f943dfa1010ccbb63de14d49a47c43ee Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 9 Mar 2012 14:13:45 +0100 Subject: mac80211: Disable MCS > 7 in minstrel_ht when STA uses static SMPS Disable multi stream rates (MCS > 7) when a STA is in static SMPS mode since it has only one active rx chain. Hence, it doesn't even make sense to sample multi stream rates. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel_ht.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net') diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index ff5f7b84e82..2b42564d6e2 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -692,6 +692,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, int ack_dur; int stbc; int i; + unsigned int smps; /* fall back to the old minstrel for legacy stations */ if (!sta->ht_cap.ht_supported) @@ -731,6 +732,9 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, oper_chan_type != NL80211_CHAN_HT40PLUS) sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >> + IEEE80211_HT_CAP_SM_PS_SHIFT; + for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { u16 req = 0; @@ -748,6 +752,11 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, if ((sta_cap & req) != req) continue; + /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ + if (smps == WLAN_HT_CAP_SM_PS_STATIC && + minstrel_mcs_groups[i].streams > 1) + continue; + mi->groups[i].supported = mcs->rx_mask[minstrel_mcs_groups[i].streams - 1]; -- cgit v1.2.3-70-g09d2 From de5036aae635b7ea5a920e56fcf074a333b325ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Mar 2012 15:02:03 +0100 Subject: mac80211: move misplaced comment Looks like some changes in this area moved the code but not the comment that belongs to the code, move it to the right place. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5c2ba80c293..059a4eba9fe 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3274,6 +3274,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->beacon_crc_valid = false; + /* + * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. + * We still associate in non-HT mode (11a/b/g) if any one of these + * ciphers is configured as pairwise. + * We can set this to true for non-11n hardware, that'll be checked + * separately along with the peer capabilities. + */ for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || @@ -3302,13 +3309,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } else ifmgd->ap_smps = ifmgd->req_smps; - /* - * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. - * We still associate in non-HT mode (11a/b/g) if any one of these - * ciphers is configured as pairwise. - * We can set this to true for non-11n hardware, that'll be checked - * separately along with the peer capabilities. - */ assoc_data->capability = req->bss->capability; assoc_data->wmm_used = bss->wmm_used; assoc_data->supp_rates = bss->supp_rates; -- cgit v1.2.3-70-g09d2 From 4e74bfdb30f79e9bf87aa359eff29fbdb93cc12a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Mar 2012 15:02:04 +0100 Subject: mac80211: simplify HT checks Always set/use IEEE80211_STA_DISABLE_11N instead of duplicating the queue, WMM and HT checks in all places. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 57 ++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 059a4eba9fe..5dfc1e8a1a2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -192,33 +192,27 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - prev_chantype = sdata->vif.bss_conf.channel_type; - /* HT is not supported */ - if (!sband->ht_cap.ht_supported) - enable_ht = false; - if (enable_ht) { - hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan, - sband->band); - /* check that channel matches the right operating channel */ - if (local->hw.conf.channel->center_freq != hti_cfreq) { - /* Some APs mess this up, evidently. - * Netgear WNDR3700 sometimes reports 4 higher than - * the actual channel, for instance. - */ - printk(KERN_DEBUG - "%s: Wrong control channel in association" - " response: configured center-freq: %d" - " hti-cfreq: %d hti->control_chan: %d" - " band: %d. Disabling HT.\n", - sdata->name, - local->hw.conf.channel->center_freq, - hti_cfreq, hti->control_chan, - sband->band); - enable_ht = false; - } + hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan, + sband->band); + /* check that channel matches the right operating channel */ + if (local->hw.conf.channel->center_freq != hti_cfreq) { + /* Some APs mess this up, evidently. + * Netgear WNDR3700 sometimes reports 4 higher than + * the actual channel, for instance. + */ + printk(KERN_DEBUG + "%s: Wrong control channel in association" + " response: configured center-freq: %d" + " hti-cfreq: %d hti->control_chan: %d" + " band: %d. Disabling HT.\n", + sdata->name, + local->hw.conf.channel->center_freq, + hti_cfreq, hti->control_chan, + sband->band); + enable_ht = false; } if (enable_ht) { @@ -335,9 +329,6 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); - if (!sband->ht_cap.ht_supported) - return; - if (!ht_info_ie) return; @@ -405,7 +396,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) u16 capab; struct ieee80211_supported_band *sband; u32 rates = 0; - struct ieee80211_bss *bss = (void *)assoc_data->bss->priv; lockdep_assert_held(&ifmgd->mtx); @@ -566,8 +556,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) offset = noffset; } - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N) && - bss->wmm_used && local->hw.queues >= 4) + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie, sband, local->oper_channel, ifmgd->ap_smps); @@ -2147,7 +2136,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_QOS; if (elems.ht_info_elem && elems.wmm_param && - (sdata->local->hw.queues >= 4) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, cbss->bssid, ap_ht_cap_flags, @@ -3232,6 +3220,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_mgd_assoc_data *assoc_data; + struct ieee80211_supported_band *sband; struct sta_info *sta; const u8 *ssidie; int i, err; @@ -3290,6 +3279,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (req->flags & ASSOC_REQ_DISABLE_HT) ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + /* Also disable HT if we don't support it or the AP doesn't use WMM */ + sband = local->hw.wiphy->bands[req->bss->channel->band]; + if (!sband->ht_cap.ht_supported || + local->hw.queues < 4 || !bss->wmm_used) + ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, sizeof(ifmgd->ht_capa_mask)); -- cgit v1.2.3-70-g09d2 From 76f0303d61b3c7f1918ab63a64e77450a4418a60 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Mar 2012 15:02:05 +0100 Subject: mac80211: simplify wmm check during association Instead of setting assoc_data->wmm_used solely based on the BSS also take into account our own capabilities and later check those. Also rename "wmm_used" and "uapsd_used" to just "wmm" and "uapsd". Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mlme.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3c62ded64e3..173c1396070 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -407,7 +407,7 @@ struct ieee80211_mgd_assoc_data { u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; u8 supp_rates_len; - bool wmm_used, uapsd_used; + bool wmm, uapsd; bool have_beacon; bool sent_assoc; bool synced; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5dfc1e8a1a2..b60768368ce 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -570,8 +570,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) offset = noffset; } - if (assoc_data->wmm_used && local->hw.queues >= 4) { - if (assoc_data->uapsd_used) { + if (assoc_data->wmm) { + if (assoc_data->uapsd) { qos_info = local->uapsd_queues; qos_info |= (local->uapsd_max_sp_len << IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); @@ -3305,7 +3305,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->ap_smps = ifmgd->req_smps; assoc_data->capability = req->bss->capability; - assoc_data->wmm_used = bss->wmm_used; + assoc_data->wmm = bss->wmm_used && (local->hw.queues >= 4); assoc_data->supp_rates = bss->supp_rates; assoc_data->supp_rates_len = bss->supp_rates_len; assoc_data->ht_information_ie = @@ -3313,10 +3313,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, if (bss->wmm_used && bss->uapsd_supported && (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { - assoc_data->uapsd_used = true; + assoc_data->uapsd = true; ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; } else { - assoc_data->uapsd_used = false; + assoc_data->uapsd = false; ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; } -- cgit v1.2.3-70-g09d2 From 0775f9f90cdaf40fbf69b3192b3dddb2b3436f45 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Mar 2012 15:02:06 +0100 Subject: mac80211: remove spurious BSSID change flag The BSSID has been set a lot earlier already and didn't change again in ieee80211_set_associated(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b60768368ce..5c82354d18c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1351,9 +1351,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, */ bss_info_changed |= BSS_CHANGED_BASIC_RATES; - /* And the BSSID changed - we're associated now */ - bss_info_changed |= BSS_CHANGED_BSSID; - /* Tell the driver to monitor connection quality (if supported) */ if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI && bss_conf->cqm_rssi_thold) -- cgit v1.2.3-70-g09d2 From a1cf775deae9d0f1e5475337ab13c593ad427cee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Mar 2012 15:02:07 +0100 Subject: mac80211: refactor common auth/assoc setup code As associating is possible without first authenticating (for FT over DS) association also has to be able to switch to the right channel, insert the station entry etc. Factor out this common code into a new function called ieee80211_prep_connection(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 121 +++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 62 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5c82354d18c..81e0124e68c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3089,6 +3089,60 @@ int ieee80211_max_network_latency(struct notifier_block *nb, return 0; } +static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *bss, bool assoc) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct sta_info *sta; + bool have_sta = false; + int err; + + if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) + return -EINVAL; + + if (assoc) { + rcu_read_lock(); + have_sta = sta_info_get(sdata, bss->bssid); + rcu_read_unlock(); + } + + if (!have_sta) { + sta = sta_info_alloc(sdata, bss->bssid, GFP_KERNEL); + if (!sta) + return -ENOMEM; + } + + mutex_lock(&local->mtx); + ieee80211_recalc_idle(sdata->local); + mutex_unlock(&local->mtx); + + /* switch to the right channel */ + local->oper_channel = bss->channel; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + if (!have_sta) { + /* set BSSID - if STA already there this will be set too */ + memcpy(ifmgd->bssid, bss->bssid, ETH_ALEN); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + + if (assoc) + sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); + + err = sta_info_insert(sta); + sta = NULL; + if (err) { + printk(KERN_DEBUG + "%s: failed to insert STA entry for the AP (error %d)\n", + sdata->name, err); + return err; + } + } else + WARN_ON_ONCE(compare_ether_addr(ifmgd->bssid, bss->bssid)); + + return 0; +} + /* config hooks */ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct cfg80211_auth_request *req) @@ -3096,7 +3150,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_auth_data *auth_data; - struct sta_info *sta; u16 auth_alg; int err; @@ -3162,32 +3215,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: authenticate with %pM\n", sdata->name, req->bss->bssid); - mutex_lock(&local->mtx); - ieee80211_recalc_idle(sdata->local); - mutex_unlock(&local->mtx); - - /* switch to the right channel */ - local->oper_channel = req->bss->channel; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - - /* set BSSID */ - memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); - - /* add station entry */ - sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); - if (!sta) { - err = -ENOMEM; - goto err_clear; - } - - err = sta_info_insert(sta); - if (err) { - printk(KERN_DEBUG - "%s: failed to insert STA entry for the AP %pM (error %d)\n", - sdata->name, req->bss->bssid, err); + err = ieee80211_prep_connection(sdata, req->bss, false); + if (err) goto err_clear; - } err = ieee80211_probe_auth(sdata); if (err) { @@ -3218,7 +3248,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_mgd_assoc_data *assoc_data; struct ieee80211_supported_band *sband; - struct sta_info *sta; const u8 *ssidie; int i, err; @@ -3343,41 +3372,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->assoc_data = assoc_data; - mutex_lock(&local->mtx); - ieee80211_recalc_idle(sdata->local); - mutex_unlock(&local->mtx); - - /* switch to the right channel */ - local->oper_channel = req->bss->channel; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - - rcu_read_lock(); - sta = sta_info_get(sdata, req->bss->bssid); - rcu_read_unlock(); - - if (!sta) { - /* set BSSID */ - memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); - - sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); - if (!sta) { - err = -ENOMEM; - goto err_clear; - } - - sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); - - err = sta_info_insert(sta); - sta = NULL; - if (err) { - printk(KERN_DEBUG - "%s: failed to insert STA entry for the AP (error %d)\n", - sdata->name, err); - goto err_clear; - } - } else - WARN_ON_ONCE(compare_ether_addr(ifmgd->bssid, req->bss->bssid)); + err = ieee80211_prep_connection(sdata, req->bss, true); + if (err) + goto err_clear; if (!bss->dtim_period && sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { -- cgit v1.2.3-70-g09d2 From 5d6a1b069b7f72298aff2306a2d02b0188668218 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Mar 2012 15:02:08 +0100 Subject: mac80211: set basic rates earlier The authentication and association handshake already happens in the context of the new BSS, and the basic rates are needed at least for the ACK response frame to the authentication or association response frames. Therefore the basic rates should already be configured into the driver when those frames are sent. Change the logic to set up the basic rates in the connection preparation that happens for authentication and association (if needed). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 97 +++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 48 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 81e0124e68c..39c13939008 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1344,12 +1344,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_conf->dtim_period = 0; bss_conf->assoc = 1; - /* - * For now just always ask the driver to update the basic rateset - * when we have associated, we aren't checking whether it actually - * changed or not. - */ - bss_info_changed |= BSS_CHANGED_BASIC_RATES; /* Tell the driver to monitor connection quality (if supported) */ if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI && @@ -2001,15 +1995,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband; struct sta_info *sta; u8 *pos; - u32 rates, basic_rates; u16 capab_info, aid; struct ieee802_11_elems elems; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; u32 changed = 0; int err; - bool have_higher_than_11mbit = false; u16 ap_ht_cap_flags; - int min_rate = INT_MAX, min_rate_index = -1; /* AssocResp and ReassocResp have identical structure */ @@ -2054,39 +2045,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, return false; } - rates = 0; - basic_rates = 0; sband = local->hw.wiphy->bands[local->oper_channel->band]; - ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, - &rates, &basic_rates, &have_higher_than_11mbit, - &min_rate, &min_rate_index); - - ieee80211_get_rates(sband, elems.ext_supp_rates, - elems.ext_supp_rates_len, &rates, &basic_rates, - &have_higher_than_11mbit, - &min_rate, &min_rate_index); - - /* - * some buggy APs don't advertise basic_rates. use the lowest - * supported rate instead. - */ - if (unlikely(!basic_rates) && min_rate_index >= 0) { - printk(KERN_DEBUG "%s: No basic rates in AssocResp. " - "Using min supported rate instead.\n", sdata->name); - basic_rates = BIT(min_rate_index); - } - - sta->sta.supp_rates[local->oper_channel->band] = rates; - sdata->vif.bss_conf.basic_rates = basic_rates; - - /* cf. IEEE 802.11 9.2.12 */ - if (local->oper_channel->band == IEEE80211_BAND_2GHZ && - have_higher_than_11mbit) - sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; - else - sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems.ht_cap_elem, &sta->sta.ht_cap); @@ -3090,10 +3050,11 @@ int ieee80211_max_network_latency(struct notifier_block *nb, } static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, - struct cfg80211_bss *bss, bool assoc) + struct cfg80211_bss *cbss, bool assoc) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_bss *bss = (void *)cbss->priv; struct sta_info *sta; bool have_sta = false; int err; @@ -3103,12 +3064,12 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, if (assoc) { rcu_read_lock(); - have_sta = sta_info_get(sdata, bss->bssid); + have_sta = sta_info_get(sdata, cbss->bssid); rcu_read_unlock(); } if (!have_sta) { - sta = sta_info_alloc(sdata, bss->bssid, GFP_KERNEL); + sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); if (!sta) return -ENOMEM; } @@ -3118,13 +3079,53 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->mtx); /* switch to the right channel */ - local->oper_channel = bss->channel; + local->oper_channel = cbss->channel; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); if (!have_sta) { - /* set BSSID - if STA already there this will be set too */ - memcpy(ifmgd->bssid, bss->bssid, ETH_ALEN); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + struct ieee80211_supported_band *sband; + u32 rates = 0, basic_rates = 0; + bool have_higher_than_11mbit; + int min_rate = INT_MAX, min_rate_index = -1; + + sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; + + ieee80211_get_rates(sband, bss->supp_rates, + bss->supp_rates_len, + &rates, &basic_rates, + &have_higher_than_11mbit, + &min_rate, &min_rate_index); + + /* + * This used to be a workaround for basic rates missing + * in the association response frame. Now that we no + * longer use the basic rates from there, it probably + * doesn't happen any more, but keep the workaround so + * in case some *other* APs are buggy in different ways + * we can connect -- with a warning. + */ + if (!basic_rates && min_rate_index >= 0) { + printk(KERN_DEBUG + "%s: No basic rates, using min rate instead.\n", + sdata->name); + basic_rates = BIT(min_rate_index); + } + + sta->sta.supp_rates[cbss->channel->band] = rates; + sdata->vif.bss_conf.basic_rates = basic_rates; + + /* cf. IEEE 802.11 9.2.12 */ + if (local->oper_channel->band == IEEE80211_BAND_2GHZ && + have_higher_than_11mbit) + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + else + sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + + memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN); + + /* tell driver about BSSID and basic rates */ + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES); if (assoc) sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); @@ -3138,7 +3139,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, return err; } } else - WARN_ON_ONCE(compare_ether_addr(ifmgd->bssid, bss->bssid)); + WARN_ON_ONCE(compare_ether_addr(ifmgd->bssid, cbss->bssid)); return 0; } -- cgit v1.2.3-70-g09d2 From afd465030acb4098abcb6b965a5aebc7ea2209e0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 12 Mar 2012 07:03:32 +0000 Subject: net: ipv4: Standardize prefixes for message logging Add #define pr_fmt(fmt) as appropriate. Add "IPv4: ", "TCP: ", and "IPsec: " to appropriate files. Standardize on "UDPLite: " for appropriate uses. Some prefixes were previously "UDPLITE: " and "UDP-Lite: ". Add KBUILD_MODNAME ": " to icmp and gre. Remove embedded prefixes as appropriate. Add missing "\n" to pr_info in gre.c. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/net/udplite.h | 4 ++-- net/ipv4/af_inet.c | 2 ++ net/ipv4/ah4.c | 9 ++++++--- net/ipv4/esp4.c | 2 ++ net/ipv4/gre.c | 6 ++++-- net/ipv4/icmp.c | 6 ++++-- net/ipv4/ip_fragment.c | 8 +++++--- net/ipv4/ip_gre.c | 2 ++ net/ipv4/ip_input.c | 2 ++ net/ipv4/ip_options.c | 2 ++ net/ipv4/route.c | 4 +++- net/ipv4/tcp.c | 11 +++++++---- net/ipv4/tcp_cong.c | 8 +++++--- net/ipv4/tcp_input.c | 2 ++ net/ipv4/tcp_ipv4.c | 6 +++--- net/ipv4/tcp_probe.c | 4 +++- net/ipv4/tcp_timer.c | 14 ++++++++------ net/ipv4/udp.c | 34 ++++++++++++++-------------------- net/ipv4/udplite.c | 3 +++ net/ipv4/xfrm4_tunnel.c | 2 ++ 20 files changed, 81 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/include/net/udplite.h b/include/net/udplite.h index 5f097ca7d5c..71375459a88 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -40,7 +40,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets * with a zero checksum field are illegal. */ if (uh->check == 0) { - LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: zeroed checksum field\n"); + LIMIT_NETDEBUG(KERN_DEBUG "UDPLite: zeroed checksum field\n"); return 1; } @@ -52,7 +52,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) /* * Coverage length violates RFC 3828: log and discard silently. */ - LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: bad csum coverage %d/%d\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDPLite: bad csum coverage %d/%d\n", cscov, skb->len); return 1; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index b7a946611f2..fdf49fd44bb 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -65,6 +65,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) "IPv4: " fmt + #include #include #include diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index b5524660c81..fd508b52601 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) "IPsec: " fmt + #include #include #include @@ -445,9 +447,10 @@ static int ah_init_state(struct xfrm_state *x) if (aalg_desc->uinfo.auth.icv_fullbits/8 != crypto_ahash_digestsize(ahash)) { - pr_info("AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_ahash_digestsize(ahash), - aalg_desc->uinfo.auth.icv_fullbits/8); + pr_info("%s: %s digestsize %u != %hu\n", + __func__, x->aalg->alg_name, + crypto_ahash_digestsize(ahash), + aalg_desc->uinfo.auth.icv_fullbits / 8); goto error; } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 0a86dbe9454..89a47b35905 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) "IPsec: " fmt + #include #include #include diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c index 8cb1ebb7cd7..42a491055c7 100644 --- a/net/ipv4/gre.c +++ b/net/ipv4/gre.c @@ -10,6 +10,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -118,10 +120,10 @@ static const struct net_protocol net_gre_protocol = { static int __init gre_init(void) { - pr_info("GRE over IPv4 demultiplexor driver"); + pr_info("GRE over IPv4 demultiplexor driver\n"); if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { - pr_err("gre: can't add protocol\n"); + pr_err("can't add protocol\n"); return -EAGAIN; } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5c7323b7810..9664d353ccd 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -62,6 +62,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -670,7 +672,7 @@ static void icmp_unreach(struct sk_buff *skb) break; case ICMP_FRAG_NEEDED: if (ipv4_config.no_pmtu_disc) { - LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: fragmentation needed and DF set\n", + LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"), &iph->daddr); } else { info = ip_rt_frag_needed(net, iph, @@ -681,7 +683,7 @@ static void icmp_unreach(struct sk_buff *skb) } break; case ICMP_SR_FAILED: - LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: Source Route Failed\n", + LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: Source Route Failed\n"), &iph->daddr); break; default: diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b2fd333abd5..3727e234c88 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -20,6 +20,8 @@ * Patrick McHardy : LRU queue of frag heads for evictor. */ +#define pr_fmt(fmt) "IPv4: " fmt + #include #include #include @@ -299,7 +301,7 @@ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user) return container_of(q, struct ipq, q); out_nomem: - LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); + LIMIT_NETDEBUG(KERN_ERR pr_fmt("ip_frag_create: no memory left !\n")); return NULL; } @@ -637,8 +639,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, return 0; out_nomem: - LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing " - "queue %p\n", qp); + LIMIT_NETDEBUG(KERN_ERR pr_fmt("queue_glue: no memory for gluing queue %p\n"), + qp); err = -ENOMEM; goto out_fail; out_oversize: diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 185e0a75ece..b57532d4742 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -10,6 +10,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index de8e9be4aac..f3f1108940f 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -113,6 +113,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) "IPv4: " fmt + #include #include #include diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index e25ee7c8bdd..a0d0d9d9b87 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -9,6 +9,8 @@ * */ +#define pr_fmt(fmt) "IPv4: " fmt + #include #include #include diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cbda6de0a77..12ccf880eb8 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -62,6 +62,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) "IPv4: " fmt + #include #include #include @@ -1298,7 +1300,7 @@ restart: } if (net_ratelimit()) - pr_warn("ipv4: Neighbour table overflow\n"); + pr_warn("Neighbour table overflow\n"); rt_drop(rt); return ERR_PTR(-ENOBUFS); } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 2baba1bed81..cfd7edda0a8 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -245,6 +245,8 @@ * TCP_CLOSE socket is finished */ +#define pr_fmt(fmt) "TCP: " fmt + #include #include #include @@ -1675,7 +1677,8 @@ do_prequeue: if (tp->ucopy.dma_cookie < 0) { - pr_alert("dma_cookie < 0\n"); + pr_alert("%s: dma_cookie < 0\n", + __func__); /* Exception. Bailout! */ if (!copied) @@ -1884,9 +1887,9 @@ bool tcp_check_oom(struct sock *sk, int shift) out_of_socket_memory = tcp_out_of_memory(sk); if (too_many_orphans && net_ratelimit()) - pr_info("TCP: too many orphaned sockets\n"); + pr_info("too many orphaned sockets\n"); if (out_of_socket_memory && net_ratelimit()) - pr_info("TCP: out of memory -- consider tuning tcp_mem\n"); + pr_info("out of memory -- consider tuning tcp_mem\n"); return too_many_orphans || out_of_socket_memory; } @@ -3311,7 +3314,7 @@ void __init tcp_init(void) sysctl_tcp_rmem[1] = 87380; sysctl_tcp_rmem[2] = max(87380, max_share); - pr_info("TCP: Hash tables configured (established %u bind %u)\n", + pr_info("Hash tables configured (established %u bind %u)\n", tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); tcp_register_congestion_control(&tcp_reno); diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 67bab75f441..272a84593c8 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -6,6 +6,8 @@ * Copyright (C) 2005 Stephen Hemminger */ +#define pr_fmt(fmt) "TCP: " fmt + #include #include #include @@ -41,17 +43,17 @@ int tcp_register_congestion_control(struct tcp_congestion_ops *ca) /* all algorithms must implement ssthresh and cong_avoid ops */ if (!ca->ssthresh || !ca->cong_avoid) { - pr_err("TCP %s does not implement required ops\n", ca->name); + pr_err("%s does not implement required ops\n", ca->name); return -EINVAL; } spin_lock(&tcp_cong_list_lock); if (tcp_ca_find(ca->name)) { - pr_notice("TCP %s already registered\n", ca->name); + pr_notice("%s already registered\n", ca->name); ret = -EEXIST; } else { list_add_tail_rcu(&ca->list, &tcp_cong_list); - pr_info("TCP %s registered\n", ca->name); + pr_info("%s registered\n", ca->name); } spin_unlock(&tcp_cong_list_lock); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 23ca3663d1e..68d4057cba0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -61,6 +61,8 @@ * Pasi Sarolahti: F-RTO for dealing with spurious RTOs */ +#define pr_fmt(fmt) "TCP: " fmt + #include #include #include diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 257dba66eac..fe9f604ed1e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -50,6 +50,7 @@ * a single port at the same time. */ +#define pr_fmt(fmt) "TCP: " fmt #include #include @@ -876,8 +877,7 @@ int tcp_syn_flood_action(struct sock *sk, lopt = inet_csk(sk)->icsk_accept_queue.listen_opt; if (!lopt->synflood_warned) { lopt->synflood_warned = 1; - pr_info("%s: Possible SYN flooding on port %d. %s. " - " Check SNMP counters.\n", + pr_info("%s: Possible SYN flooding on port %d. %s. Check SNMP counters.\n", proto, ntohs(tcp_hdr(skb)->dest), msg); } return want_cookie; @@ -1399,7 +1399,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * to destinations, already remembered * to the moment of synflood. */ - LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI4/%u\n", + LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), &saddr, ntohs(tcp_hdr(skb)->source)); goto drop_and_release; } diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 85ee7eb7e38..a981cdc0a6e 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -18,6 +18,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -239,7 +241,7 @@ static __init int tcpprobe_init(void) if (ret) goto err1; - pr_info("TCP probe registered (port=%d) bufsize=%u\n", port, bufsize); + pr_info("probe registered (port=%d) bufsize=%u\n", port, bufsize); return 0; err1: proc_net_remove(&init_net, procname); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index cd2e0723266..34d4a02c2f1 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -333,16 +333,18 @@ void tcp_retransmit_timer(struct sock *sk) */ struct inet_sock *inet = inet_sk(sk); if (sk->sk_family == AF_INET) { - LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", - &inet->inet_daddr, ntohs(inet->inet_dport), - inet->inet_num, tp->snd_una, tp->snd_nxt); + LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n"), + &inet->inet_daddr, + ntohs(inet->inet_dport), inet->inet_num, + tp->snd_una, tp->snd_nxt); } #if IS_ENABLED(CONFIG_IPV6) else if (sk->sk_family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); - LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", - &np->daddr, ntohs(inet->inet_dport), - inet->inet_num, tp->snd_una, tp->snd_nxt); + LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n"), + &np->daddr, + ntohs(inet->inet_dport), inet->inet_num, + tp->snd_una, tp->snd_nxt); } #endif if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7c41ab84e72..d6f5feeb3ea 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -77,6 +77,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) "UDP: " fmt + #include #include #include @@ -975,7 +977,7 @@ back_from_confirm: /* ... which is an evident application bug. --ANK */ release_sock(sk); - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("cork app bug 2\n")); err = -EINVAL; goto out; } @@ -1054,7 +1056,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset, if (unlikely(!up->pending)) { release_sock(sk); - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); + LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("udp cork app bug 3\n")); return -EINVAL; } @@ -1447,9 +1449,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) * provided by the application." */ if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " - "%d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); + LIMIT_NETDEBUG(KERN_WARNING "UDPLite: partial coverage %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); goto drop; } /* The next case involves violating the min. coverage requested @@ -1459,9 +1460,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) * Therefore the above ...()->partial_cov statement is essential. */ if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING - "UDPLITE: coverage %d too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); + LIMIT_NETDEBUG(KERN_WARNING "UDPLite: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); goto drop; } } @@ -1689,13 +1689,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, short_packet: LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", - &saddr, - ntohs(uh->source), - ulen, - skb->len, - &daddr, - ntohs(uh->dest)); + proto == IPPROTO_UDPLITE ? "Lite" : "", + &saddr, ntohs(uh->source), + ulen, skb->len, + &daddr, ntohs(uh->dest)); goto drop; csum_error: @@ -1704,11 +1701,8 @@ csum_error: * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", - &saddr, - ntohs(uh->source), - &daddr, - ntohs(uh->dest), + proto == IPPROTO_UDPLITE ? "Lite" : "", + &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest), ulen); drop: UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 280bfb12adc..2c46acd4cc3 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -10,6 +10,9 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ + +#define pr_fmt(fmt) "UDPLite: " fmt + #include #include "udp_impl.h" diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 5b48f49df0b..05a5df2febc 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -3,6 +3,8 @@ * Copyright (C) 2003 David S. Miller (davem@redhat.com) */ +#define pr_fmt(fmt) "IPsec: " fmt + #include #include #include -- cgit v1.2.3-70-g09d2 From 617bbde878604adfcd557fc2a8952f77ab4ebd95 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Mar 2012 13:49:13 +0100 Subject: mac80211: move RX WEP weak IV counting This is better done inside the WEP decrypt function where it doesn't have to check all the conditions any more since they've been tested already. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 7 ------- net/mac80211/wep.c | 10 ++++++---- net/mac80211/wep.h | 1 - 3 files changed, 6 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5f6e32ca085..b38da13e2a8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1070,13 +1070,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) switch (rx->key->conf.cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - /* Check for weak IVs if possible */ - if (rx->sta && ieee80211_is_data(fc) && - (!(status->flag & RX_FLAG_IV_STRIPPED) || - !(status->flag & RX_FLAG_DECRYPTED)) && - ieee80211_wep_is_weak_iv(rx->skb, rx->key)) - rx->sta->wep_weak_iv_count++; - result = ieee80211_crypto_wep_decrypt(rx); break; case WLAN_CIPHER_SUITE_TKIP: diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 68ad351479d..5cd87ba11bb 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -263,16 +263,14 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, } -bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) +static bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, + struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; unsigned int hdrlen; u8 *ivpos; u32 iv; - if (!ieee80211_has_protected(hdr->frame_control)) - return false; - hdrlen = ieee80211_hdrlen(hdr->frame_control); ivpos = skb->data + hdrlen; iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; @@ -292,9 +290,13 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (!(status->flag & RX_FLAG_DECRYPTED)) { + if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) + rx->sta->wep_weak_iv_count++; if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) return RX_DROP_UNUSABLE; } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { + if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) + rx->sta->wep_weak_iv_count++; ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN); diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 01e54840a62..9615749d1f6 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -25,7 +25,6 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, const u8 *key, int keylen, int keyidx); int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); -bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx); -- cgit v1.2.3-70-g09d2 From a8286911881948c7a2ecc63ee4224c258cce2da3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Mar 2012 13:49:14 +0100 Subject: mac80211: linearize SKBs as needed for crypto Not linearizing every SKB will help actually pass non-linear SKBs all the way up when on an encrypted connection. For now, linearize TKIP completely as it is lower performance and I don't quite grok all the details. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 6 ++---- net/mac80211/wep.c | 11 ++++++++--- net/mac80211/wpa.c | 22 +++++++++++++++++++++- 3 files changed, 31 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b38da13e2a8..53c88d14547 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1063,10 +1063,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; } - if (skb_linearize(rx->skb)) - return RX_DROP_UNUSABLE; - /* the hdr variable is invalid now! */ - switch (rx->key->conf.cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -1089,6 +1085,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; } + /* the hdr variable is invalid after the decrypt handlers */ + /* either the frame has been decrypted or will be dropped */ status->flag |= RX_FLAG_DECRYPTED; diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 5cd87ba11bb..7aa31bbfaa3 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -284,22 +284,27 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + __le16 fc = hdr->frame_control; - if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_auth(hdr->frame_control)) + if (!ieee80211_is_data(fc) && !ieee80211_is_auth(fc)) return RX_CONTINUE; if (!(status->flag & RX_FLAG_DECRYPTED)) { + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) return RX_DROP_UNUSABLE; } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { + if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + WEP_IV_LEN)) + return RX_DROP_UNUSABLE; if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ - skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN); + if (pskb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN)) + return RX_DROP_UNUSABLE; } return RX_CONTINUE; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b758350919f..0ae23c60968 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -138,6 +138,10 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) if (skb->len < hdrlen + MICHAEL_MIC_LEN) return RX_DROP_UNUSABLE; + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; + hdr = (void *)skb->data; + data = skb->data + hdrlen; data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; @@ -253,6 +257,11 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) if (!rx->sta || skb->len - hdrlen < 12) return RX_DROP_UNUSABLE; + /* it may be possible to optimize this a bit more */ + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; + hdr = (void *)skb->data; + /* * Let TKIP code verify IV, but skip decryption. * In the case where hardware checks the IV as well, @@ -484,6 +493,14 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) if (!rx->sta || data_len < 0) return RX_DROP_UNUSABLE; + if (status->flag & RX_FLAG_DECRYPTED) { + if (!pskb_may_pull(rx->skb, hdrlen + CCMP_HDR_LEN)) + return RX_DROP_UNUSABLE; + } else { + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; + } + ccmp_hdr2pn(pn, skb->data + hdrlen); queue = rx->security_idx; @@ -509,7 +526,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN); /* Remove CCMP header and MIC */ - skb_trim(skb, skb->len - CCMP_MIC_LEN); + if (pskb_trim(skb, skb->len - CCMP_MIC_LEN)) + return RX_DROP_UNUSABLE; memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen); skb_pull(skb, CCMP_HDR_LEN); @@ -609,6 +627,8 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) if (!ieee80211_is_mgmt(hdr->frame_control)) return RX_CONTINUE; + /* management frames are already linear */ + if (skb->len < 24 + sizeof(*mmie)) return RX_DROP_UNUSABLE; -- cgit v1.2.3-70-g09d2 From 7b8bcff2e0f11981dd6840f9feefe0914e4ea521 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Mar 2012 13:57:04 +0100 Subject: cfg80211: clarify timestamp in cfg80211_inform_bss This is intended to be the timestamp sent by the peer in the beacon/probe response, not any form of host timestamp. Clarify the documentation and variable names. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 7 +++---- net/wireless/scan.c | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 66f460325e2..69b7ad3a992 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2697,7 +2697,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, * @wiphy: the wiphy reporting the BSS * @channel: The channel the frame was received on * @bssid: the BSSID of the BSS - * @timestamp: the TSF timestamp sent by the peer + * @tsf: the TSF sent by the peer in the beacon/probe response (or 0) * @capability: the capability field sent by the peer * @beacon_interval: the beacon interval announced by the peer * @ie: additional IEs sent by the peer @@ -2713,9 +2713,8 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, struct cfg80211_bss * __must_check cfg80211_inform_bss(struct wiphy *wiphy, struct ieee80211_channel *channel, - const u8 *bssid, - u64 timestamp, u16 capability, u16 beacon_interval, - const u8 *ie, size_t ielen, + const u8 *bssid, u64 tsf, u16 capability, + u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp); struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index afde7e5f001..70faadf16a3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -734,9 +734,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, struct cfg80211_bss* cfg80211_inform_bss(struct wiphy *wiphy, struct ieee80211_channel *channel, - const u8 *bssid, - u64 timestamp, u16 capability, u16 beacon_interval, - const u8 *ie, size_t ielen, + const u8 *bssid, u64 tsf, u16 capability, + u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp) { struct cfg80211_internal_bss *res; @@ -758,7 +757,7 @@ cfg80211_inform_bss(struct wiphy *wiphy, memcpy(res->pub.bssid, bssid, ETH_ALEN); res->pub.channel = channel; res->pub.signal = signal; - res->pub.tsf = timestamp; + res->pub.tsf = tsf; res->pub.beacon_interval = beacon_interval; res->pub.capability = capability; /* -- cgit v1.2.3-70-g09d2 From e9ac0745c734d39cb55ce45f1fb03a85c972b35a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Mar 2012 14:29:30 +0100 Subject: mac80211: rename bss_conf timestamp to last_tsf This value is not really very useful by itself, yet some drivers (including iwlwifi until I can figure out what it should do) use it. At least rename it to "last_tsf" to indicate the meaning and add a note that it may be really old. I suspect the value may become useful combined with the rx_status->mactime, but we don't (yet) store that value and pass it to the driver. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/common.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 2 +- drivers/net/wireless/rt2x00/rt2x00config.c | 2 +- include/net/mac80211.h | 5 +++-- net/mac80211/driver-trace.h | 2 +- net/mac80211/mlme.c | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index b42052b47d8..e5ac04739bc 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -5355,7 +5355,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_ASSOC) { D_MAC80211("ASSOC %d\n", bss_conf->assoc); if (bss_conf->assoc) { - il->timestamp = bss_conf->timestamp; + il->timestamp = bss_conf->last_tsf; if (!il_is_rfkill(il)) il->ops->post_associate(il); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 36909077f99..2e1a31797a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -822,7 +822,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { - priv->timestamp = bss_conf->timestamp; + priv->timestamp = bss_conf->last_tsf; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { /* diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index d7c0f86c9e4..293676bfa57 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -102,7 +102,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, /* Update the AID, this is needed for dynamic PS support */ rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; - rt2x00dev->last_beacon = bss_conf->timestamp; + rt2x00dev->last_beacon = bss_conf->last_tsf; /* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 44e4dfcb572..9a012be615f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -229,7 +229,8 @@ enum ieee80211_rssi_event { * valid in station mode only while @assoc is true and if also * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf * @ps_dtim_period) - * @timestamp: beacon timestamp + * @last_tsf: last beacon's/probe response's TSF timestamp (could be old + * as it may have been received during scanning long ago) * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp * @basic_rates: bitmap of basic rates, each bit stands for an @@ -276,7 +277,7 @@ struct ieee80211_bss_conf { u8 dtim_period; u16 beacon_int; u16 assoc_capability; - u64 timestamp; + u64 last_tsf; u32 basic_rates; int mcast_rate[IEEE80211_NUM_BANDS]; u16 ht_operation_mode; diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 7034209ad3f..21d6f5290a1 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -296,7 +296,7 @@ TRACE_EVENT(drv_bss_info_changed, __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; __entry->assoc_cap = info->assoc_capability; - __entry->timestamp = info->timestamp; + __entry->timestamp = info->last_tsf; __entry->basic_rates = info->basic_rates; __entry->enable_beacon = info->enable_beacon; __entry->ht_operation_mode = info->ht_operation_mode; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 39c13939008..90d1db36cde 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1318,7 +1318,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= BSS_CHANGED_ASSOC; /* set timing information */ bss_conf->beacon_int = cbss->beacon_interval; - bss_conf->timestamp = cbss->tsf; + bss_conf->last_tsf = cbss->tsf; bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, -- cgit v1.2.3-70-g09d2 From 3117bbdb7899d43927c8ce4fe885ab7c1231c121 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Tue, 13 Mar 2012 07:46:18 -0700 Subject: mac80211: Don't let regulatory make us deaf When regulatory information changes our HT behavior (e.g, when we get a country code from the AP we have just associated with), we should use this information to change the power with which we transmit, and what channels we transmit. Sometimes the channel parameters we derive from regulatory information contradicts the parameters we used in association. For example, we could have associated specifying HT40, but the regulatory rules we apply may forbid HT40 operation. In the situation above, we should reconfigure ourselves to transmit in HT20 only, however it makes no sense for us to disable receive in HT40, since if we associated with these parameters, the AP has every reason to expect we can and will receive packets this way. The code in mac80211 does not have the capability of sending the appropriate action frames to signal a change in HT behaviour so the AP has no clue we can no longer receive frames encoded this way. In some broken AP implementations, this can leave us effectively deaf if the AP never retries in lower HT rates. This change breaks up the channel_type parameter in the ieee80211_enable_ht function into a separate receive and transmit part. It honors the channel flags set by regulatory in order to configure the rate control algorithm, but uses the capability flags to configure the channel on the radio, since these were used in association to set the AP's transmit rate. Signed-off-by: Paul Stewart Cc: Sam Leffler Cc: Johannes Berg Reviewed-by: Luis R Rodriguez Signed-off-by: John W. Linville --- net/mac80211/chan.c | 27 +++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/mlme.c | 32 ++++++++++++++++---------------- net/mac80211/rx.c | 8 +++++--- 4 files changed, 51 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index d1f7abddb18..e00ce8c3e28 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -3,6 +3,7 @@ */ #include +#include #include "ieee80211_i.h" static enum ieee80211_chan_mode @@ -134,3 +135,29 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, return result; } + +/* + * ieee80211_get_tx_channel_type returns the channel type we should + * use for packet transmission, given the channel capability and + * whatever regulatory flags we have been given. + */ +enum nl80211_channel_type ieee80211_get_tx_channel_type( + struct ieee80211_local *local, + enum nl80211_channel_type channel_type) +{ + switch (channel_type) { + case NL80211_CHAN_HT40PLUS: + if (local->hw.conf.channel->flags & + IEEE80211_CHAN_NO_HT40PLUS) + return NL80211_CHAN_HT20; + break; + case NL80211_CHAN_HT40MINUS: + if (local->hw.conf.channel->flags & + IEEE80211_CHAN_NO_HT40MINUS) + return NL80211_CHAN_HT20; + break; + default: + break; + } + return channel_type; +} diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 173c1396070..63fb0eb79d8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1502,6 +1502,9 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, enum nl80211_channel_type chantype); enum nl80211_channel_type ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info); +enum nl80211_channel_type ieee80211_get_tx_channel_type( + struct ieee80211_local *local, + enum nl80211_channel_type channel_type); #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 90d1db36cde..0df22372af8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -189,7 +189,8 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, u16 ht_opmode; bool enable_ht = true; enum nl80211_channel_type prev_chantype; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT; + enum nl80211_channel_type tx_channel_type; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; prev_chantype = sdata->vif.bss_conf.channel_type; @@ -216,7 +217,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, } if (enable_ht) { - channel_type = NL80211_CHAN_HT20; + rx_channel_type = NL80211_CHAN_HT20; if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && !ieee80111_cfg_override_disables_ht40(sdata) && @@ -224,29 +225,28 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (!(local->hw.conf.channel->flags & - IEEE80211_CHAN_NO_HT40PLUS)) - channel_type = NL80211_CHAN_HT40PLUS; + rx_channel_type = NL80211_CHAN_HT40PLUS; break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (!(local->hw.conf.channel->flags & - IEEE80211_CHAN_NO_HT40MINUS)) - channel_type = NL80211_CHAN_HT40MINUS; + rx_channel_type = NL80211_CHAN_HT40MINUS; break; } } } + tx_channel_type = ieee80211_get_tx_channel_type(local, rx_channel_type); + if (local->tmp_channel) - local->tmp_channel_type = channel_type; + local->tmp_channel_type = rx_channel_type; - if (!ieee80211_set_channel_type(local, sdata, channel_type)) { + if (!ieee80211_set_channel_type(local, sdata, rx_channel_type)) { /* can only fail due to HT40+/- mismatch */ - channel_type = NL80211_CHAN_HT20; - WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type)); + rx_channel_type = NL80211_CHAN_HT20; + WARN_ON(!ieee80211_set_channel_type(local, sdata, + rx_channel_type)); } - if (beacon_htcap_ie && (prev_chantype != channel_type)) { + if (beacon_htcap_ie && (prev_chantype != rx_channel_type)) { /* * Whenever the AP announces the HT mode change that can be * 40MHz intolerant or etc., it would be safer to stop tx @@ -264,13 +264,13 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* channel_type change automatically detected */ ieee80211_hw_config(local, 0); - if (prev_chantype != channel_type) { + if (prev_chantype != tx_channel_type) { rcu_read_lock(); sta = sta_info_get(sdata, bssid); if (sta) rate_control_rate_update(local, sband, sta, IEEE80211_RC_HT_CHANGED, - channel_type); + tx_channel_type); rcu_read_unlock(); if (beacon_htcap_ie) @@ -283,7 +283,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* if bss configuration changed store the new one */ if (sdata->ht_opmode_valid != enable_ht || sdata->vif.bss_conf.ht_operation_mode != ht_opmode || - prev_chantype != channel_type) { + prev_chantype != rx_channel_type) { changed |= BSS_CHANGED_HT; sdata->vif.bss_conf.ht_operation_mode = ht_opmode; sdata->ht_opmode_valid = enable_ht; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 53c88d14547..bcfe8c77c83 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2269,9 +2269,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sband = rx->local->hw.wiphy->bands[status->band]; - rate_control_rate_update(local, sband, rx->sta, - IEEE80211_RC_SMPS_CHANGED, - local->_oper_channel_type); + rate_control_rate_update( + local, sband, rx->sta, + IEEE80211_RC_SMPS_CHANGED, + ieee80211_get_tx_channel_type( + local, local->_oper_channel_type)); goto handled; } default: -- cgit v1.2.3-70-g09d2 From ba6fa29c6dd51a1245a109f4b460092b51cad0f0 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 14 Mar 2012 13:31:11 +0100 Subject: mac80211: Don't sample max throughput rate in minstrel_ht The current max throughput rate is known to be good as otherwise it wouldn't be the max throughput rate. Since rate sampling can introduce some overhead (by adding RTS for example or due to not aggregating the frame) don't sample the max throughput rate. Signed-off-by: Helmut Schaa Acked-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel_ht.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net') diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 2b42564d6e2..16e0b277b9a 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -567,6 +567,13 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) sample_idx += mi->sample_group * MCS_GROUP_RATES; minstrel_next_sample_idx(mi); + /* + * Sampling might add some overhead (RTS, no aggregation) + * to the frame. Hence, don't use sampling for the currently + * used max TP rate. + */ + if (sample_idx == mi->max_tp_rate) + return -1; /* * When not using MRR, do not sample if the probability is already * higher than 95% to avoid wasting airtime -- cgit v1.2.3-70-g09d2 From ada577c12f7cd8851c999a9f19f62df06df7c39a Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 14 Mar 2012 16:15:02 +0200 Subject: mac80211: add NULL terminator to debugfs_netdev write buf Some debugfs write functions call kstrto* functions, which assume the string is null-terminated. Make it valid by changing ieee80211_if_write() to use static buffer instead of allocating one, and set the last char to NULL. (The write functions try to parse some integer/mac address, so 64 bytes buffer should be enough) Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index f6de8a65f40..ef5cf268565 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -49,16 +49,15 @@ static ssize_t ieee80211_if_write( size_t count, loff_t *ppos, ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int)) { - u8 *buf; + char buf[64]; ssize_t ret; - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (count >= sizeof(buf)) + return -E2BIG; - ret = -EFAULT; if (copy_from_user(buf, userbuf, count)) - goto freebuf; + return -EFAULT; + buf[count] = '\0'; ret = -ENODEV; rtnl_lock(); @@ -66,8 +65,6 @@ static ssize_t ieee80211_if_write( ret = (*write)(sdata, buf, count); rtnl_unlock(); -freebuf: - kfree(buf); return ret; } -- cgit v1.2.3-70-g09d2 From dc41e4d474bb18e60bc6678e58adc52ed227f105 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 14 Mar 2012 16:15:03 +0200 Subject: mac80211: make uapsd_* keys per-vif uapsd_queues and uapsd_max_sp_len are relevant only for managed interfaces, and can be configured differently for each vif. Move them from the local struct to sdata->u.mgd, and update the debugfs functions accordingly. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- net/mac80211/debugfs.c | 81 ------------------------------------------- net/mac80211/debugfs_netdev.c | 58 +++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 28 +++++++-------- net/mac80211/main.c | 2 -- net/mac80211/mlme.c | 8 +++-- net/mac80211/tx.c | 4 +-- 6 files changed, 79 insertions(+), 102 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 483e96ed95c..cc5b7a6e7e0 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -97,85 +97,6 @@ static const struct file_operations reset_ops = { .llseek = noop_llseek, }; -static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n", - local->uapsd_queues); -} - -static ssize_t uapsd_queues_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - u8 val; - int ret; - - ret = kstrtou8_from_user(user_buf, count, 0, &val); - if (ret) - return ret; - - if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) - return -ERANGE; - - local->uapsd_queues = val; - - return count; -} - -static const struct file_operations uapsd_queues_ops = { - .read = uapsd_queues_read, - .write = uapsd_queues_write, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; - -static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - - return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n", - local->uapsd_max_sp_len); -} - -static ssize_t uapsd_max_sp_len_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - unsigned long val; - char buf[10]; - size_t len; - int ret; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &val); - - if (ret) - return -EINVAL; - - if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) - return -ERANGE; - - local->uapsd_max_sp_len = val; - - return count; -} - -static const struct file_operations uapsd_max_sp_len_ops = { - .read = uapsd_max_sp_len_read, - .write = uapsd_max_sp_len_write, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; - static ssize_t channel_type_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -362,8 +283,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(wep_iv); DEBUGFS_ADD(queues); DEBUGFS_ADD_MODE(reset, 0200); - DEBUGFS_ADD(uapsd_queues); - DEBUGFS_ADD(uapsd_max_sp_len); DEBUGFS_ADD(channel_type); DEBUGFS_ADD(hwflags); DEBUGFS_ADD(user_power); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ef5cf268565..a32eeda04aa 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -337,6 +337,62 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( __IEEE80211_IF_FILE_W(tkip_mic_test); +static ssize_t ieee80211_if_fmt_uapsd_queues( + const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) +{ + const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_queues); +} + +static ssize_t ieee80211_if_parse_uapsd_queues( + struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + u8 val; + int ret; + + ret = kstrtou8(buf, 0, &val); + if (ret) + return ret; + + if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) + return -ERANGE; + + ifmgd->uapsd_queues = val; + + return buflen; +} +__IEEE80211_IF_FILE_W(uapsd_queues); + +static ssize_t ieee80211_if_fmt_uapsd_max_sp_len( + const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) +{ + const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_max_sp_len); +} + +static ssize_t ieee80211_if_parse_uapsd_max_sp_len( + struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 0, &val); + if (ret) + return -EINVAL; + + if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) + return -ERANGE; + + ifmgd->uapsd_max_sp_len = val; + + return buflen; +} +__IEEE80211_IF_FILE_W(uapsd_max_sp_len); + /* AP attributes */ IEEE80211_IF_FILE(num_sta_authorized, u.ap.num_sta_authorized, ATOMIC); IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); @@ -469,6 +525,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(ave_beacon); DEBUGFS_ADD_MODE(smps, 0600); DEBUGFS_ADD_MODE(tkip_mic_test, 0200); + DEBUGFS_ADD_MODE(uapsd_queues, 0600); + DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 63fb0eb79d8..d9798a307f2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -459,6 +459,20 @@ struct ieee80211_if_managed { IEEE80211_MFP_REQUIRED } mfp; /* management frame protection */ + /* + * Bitmask of enabled u-apsd queues, + * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association + * to take effect. + */ + unsigned int uapsd_queues; + + /* + * Maximum number of buffered frames AP can deliver during a + * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar. + * Needs a new association to take effect. + */ + unsigned int uapsd_max_sp_len; + int wmm_last_param_set; u8 use_4addr; @@ -1017,20 +1031,6 @@ struct ieee80211_local { */ unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - /* - * Bitmask of enabled u-apsd queues, - * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association - * to take effect. - */ - unsigned int uapsd_queues; - - /* - * Maximum number of buffered frames AP can deliver during a - * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar. - * Needs a new association to take effect. - */ - unsigned int uapsd_max_sp_len; - bool pspolling; bool offchannel_ps_enabled; /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 36fa8051296..b581a24fa15 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -595,8 +595,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; local->user_power_level = -1; - local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; - local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; INIT_LIST_HEAD(&local->interfaces); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0df22372af8..576fb25456d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -572,8 +572,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) if (assoc_data->wmm) { if (assoc_data->uapsd) { - qos_info = local->uapsd_queues; - qos_info |= (local->uapsd_max_sp_len << + qos_info = ifmgd->uapsd_queues; + qos_info |= (ifmgd->uapsd_max_sp_len << IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); } else { qos_info = 0; @@ -1192,7 +1192,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, return; if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) - uapsd_queues = local->uapsd_queues; + uapsd_queues = ifmgd->uapsd_queues; count = wmm_param[6] & 0x0f; if (count == ifmgd->wmm_last_param_set) @@ -3013,6 +3013,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ifmgd->flags = 0; ifmgd->powersave = sdata->wdev.ps; + ifmgd->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; + ifmgd->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; mutex_init(&ifmgd->mtx); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d9e791d2b54..782a60198df 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -226,12 +226,12 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) * have correct qos tag for some reason, due the network or the * peer application. * - * Note: local->uapsd_queues access is racy here. If the value is + * Note: ifmgd->uapsd_queues access is racy here. If the value is * changed via debugfs, user needs to reassociate manually to have * everything in sync. */ if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) - && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) + && (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) && skb_get_queue_mapping(tx->skb) == 0) return TX_CONTINUE; -- cgit v1.2.3-70-g09d2 From 122bdf67f15a22bcabf6c2cab3a545d17ccf68dc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 14 Mar 2012 21:13:11 +0000 Subject: ipv6: fix icmp6_dst_alloc() commit 87a115783 ( ipv6: Move xfrm_lookup() call down into icmp6_dst_alloc().) forgot to convert one error path, leading to crashes in mld_sendpack() Many thanks to Dave Jones for providing a very complete bug report. Reported-by: Dave Jones Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8c2e3ab58f2..22b766407de 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1077,7 +1077,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct net *net = dev_net(dev); if (unlikely(!idev)) - return NULL; + return ERR_PTR(-ENODEV); rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0); if (unlikely(!rt)) { -- cgit v1.2.3-70-g09d2 From cc34eb672eedb5ff248ac3bf9971a76f141fd141 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Mar 2012 18:04:25 +0000 Subject: sch_sfq: revert dont put new flow at the end of flows This reverts commit d47a0ac7b6 (sch_sfq: dont put new flow at the end of flows) As Jesper found out, patch sounded great but has bad side effects. In stress situation, pushing new flows in front of the queue can prevent old flows doing any progress. Packets can stay in SFQ queue for unlimited amount of time. It's possible to add heuristics to limit this problem, but this would add complexity outside of SFQ scope. A more sensible answer to Dave Taht concerns (who reported the issued I tried to solve in original commit) is probably to use a qdisc hierarchy so that high prio packets dont enter a potentially crowded SFQ qdisc. Reported-by: Jesper Dangaard Brouer Cc: Dave Taht Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_sfq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 60d47180f04..02a21abea65 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -469,11 +469,15 @@ enqueue: if (slot->qlen == 1) { /* The flow is new */ if (q->tail == NULL) { /* It is the first flow */ slot->next = x; - q->tail = slot; } else { slot->next = q->tail->next; q->tail->next = x; } + /* We put this flow at the end of our flow list. + * This might sound unfair for a new flow to wait after old ones, + * but we could endup servicing new flows only, and freeze old ones. + */ + q->tail = slot; /* We could use a bigger initial quantum for new flows */ slot->allot = q->scaled_quantum; } -- cgit v1.2.3-70-g09d2 From c577923756b7fe9071f28a76b66b83b306d1d001 Mon Sep 17 00:00:00 2001 From: "RongQing.Li" Date: Thu, 15 Mar 2012 22:54:14 +0000 Subject: ipv6: Don't dev_hold(dev) in ip6_mc_find_dev_rcu. ip6_mc_find_dev_rcu() is called with rcu_read_lock(), so don't need to dev_hold(). With dev_hold(), not corresponding dev_put(), will lead to leak. [ bug introduced in 96b52e61be1 (ipv6: mcast: RCU conversions) ] Signed-off-by: RongQing.Li Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/mcast.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index b853f06cc14..16c33e30812 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -257,7 +257,6 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, if (rt) { dev = rt->dst.dev; - dev_hold(dev); dst_release(&rt->dst); } } else -- cgit v1.2.3-70-g09d2 From 124d37e9f088a8f56494b0264d63d22555f53fef Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 15 Mar 2012 05:25:58 +0000 Subject: arp: allow arp processing to honor per interface arp_accept sysctl I found recently that the arp_process function which handles all of our received arp frames, is using IPV4_DEVCONF_ALL macro to check the state of the arp_process flag. This seems wrong, as it implies that either none or all of the network interfaces accept gratuitous arps. This patch corrects that, allowing per-interface arp_accept configuration to deviate from the all setting. Note this also brings us into line with the way the arp_filter setting is handled during arp_process execution. Tested this myself on my home network, and confirmed it works as expected. Signed-off-by: Neil Horman CC: "David S. Miller" Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 1 + net/ipv4/arp.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 5f8146695b7..597f4a9f324 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -139,6 +139,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) IN_DEV_ORCONF((in_dev), ACCEPT_REDIRECTS))) #define IN_DEV_ARPFILTER(in_dev) IN_DEV_ORCONF((in_dev), ARPFILTER) +#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_ORCONF((in_dev), ARP_ACCEPT) #define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE) #define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE) #define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 63e49890ad3..73f46d691ab 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -889,7 +889,7 @@ static int arp_process(struct sk_buff *skb) n = __neigh_lookup(&arp_tbl, &sip, dev, 0); - if (IPV4_DEVCONF_ALL(dev_net(dev), ARP_ACCEPT)) { + if (IN_DEV_ARP_ACCEPT(in_dev)) { /* Unsolicited ARP is not accepted by default. It is possible, that this option should be enabled for some devices (strip is candidate) -- cgit v1.2.3-70-g09d2 From a16a1647fa6b6783c2e91623e72e86f0c2adac5e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 16 Mar 2012 02:00:34 +0000 Subject: netfilter: ctnetlink: fix race between delete and timeout expiration Kerin Millar reported hardlockups while running `conntrackd -c' in a busy firewall. That system (with several processors) was acting as backup in a primary-backup setup. After several tries, I found a race condition between the deletion operation of ctnetlink and timeout expiration. This patch fixes this problem. Tested-by: Kerin Millar Reported-by: Kerin Millar Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_netlink.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 10687692831..b49da6c925b 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -943,20 +943,21 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, } } - if (nf_conntrack_event_report(IPCT_DESTROY, ct, - NETLINK_CB(skb).pid, - nlmsg_report(nlh)) < 0) { + if (del_timer(&ct->timeout)) { + if (nf_conntrack_event_report(IPCT_DESTROY, ct, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)) < 0) { + nf_ct_delete_from_lists(ct); + /* we failed to report the event, try later */ + nf_ct_insert_dying_list(ct); + nf_ct_put(ct); + return 0; + } + /* death_by_timeout would report the event again */ + set_bit(IPS_DYING_BIT, &ct->status); nf_ct_delete_from_lists(ct); - /* we failed to report the event, try later */ - nf_ct_insert_dying_list(ct); nf_ct_put(ct); - return 0; } - - /* death_by_timeout would report the event again */ - set_bit(IPS_DYING_BIT, &ct->status); - - nf_ct_kill(ct); nf_ct_put(ct); return 0; -- cgit v1.2.3-70-g09d2 From 540a0f7584169651f485e8ab67461fcb06934e38 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 19 Mar 2012 13:39:35 -0400 Subject: SUNRPC: We must not use list_for_each_entry_safe() in rpc_wake_up() The problem is that for the case of priority queues, we have to assume that __rpc_remove_wait_queue_priority will move new elements from the tk_wait.links lists into the queue->tasks[] list. We therefore cannot use list_for_each_entry_safe() on queue->tasks[], since that will skip these new tasks that __rpc_remove_wait_queue_priority is adding. Without this fix, rpc_wake_up and rpc_wake_up_status will both fail to wake up all functions on priority wait queues, which can result in some nasty hangs. Reported-by: Andy Adamson Signed-off-by: Trond Myklebust Cc: stable@vger.kernel.org --- net/sunrpc/sched.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 1c570a81096..994cfea2bad 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -534,14 +534,18 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_next); */ void rpc_wake_up(struct rpc_wait_queue *queue) { - struct rpc_task *task, *next; struct list_head *head; spin_lock_bh(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { - list_for_each_entry_safe(task, next, head, u.tk_wait.list) + while (!list_empty(head)) { + struct rpc_task *task; + task = list_first_entry(head, + struct rpc_task, + u.tk_wait.list); rpc_wake_up_task_queue_locked(queue, task); + } if (head == &queue->tasks[0]) break; head--; @@ -559,13 +563,16 @@ EXPORT_SYMBOL_GPL(rpc_wake_up); */ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) { - struct rpc_task *task, *next; struct list_head *head; spin_lock_bh(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { - list_for_each_entry_safe(task, next, head, u.tk_wait.list) { + while (!list_empty(head)) { + struct rpc_task *task; + task = list_first_entry(head, + struct rpc_task, + u.tk_wait.list); task->tk_status = status; rpc_wake_up_task_queue_locked(queue, task); } -- cgit v1.2.3-70-g09d2 From e86b291962cbf477e35d983d312428cf737bc0f8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 18 Mar 2012 11:06:44 +0000 Subject: tcp: introduce tcp_data_queue_ofo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split tcp_data_queue() in two parts for better readability. tcp_data_queue_ofo() is responsible for queueing incoming skb into out of order queue. Change code layout so that the skb_set_owner_r() is performed only if skb is not dropped. This is a preliminary patch before "reduce out_of_order memory use" following patch. Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Cc: H.K. Jerry Chu Cc: Tom Herbert Cc: Ilpo Järvinen Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 214 +++++++++++++++++++++++++++------------------------ 1 file changed, 115 insertions(+), 99 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 68d4057cba0..fa7de12c4a5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4446,6 +4446,120 @@ static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size) return 0; } +static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb1; + u32 seq, end_seq; + + TCP_ECN_check_ce(tp, skb); + + if (tcp_try_rmem_schedule(sk, skb->truesize)) { + /* TODO: should increment a counter */ + __kfree_skb(skb); + return; + } + + /* Disable header prediction. */ + tp->pred_flags = 0; + inet_csk_schedule_ack(sk); + + SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", + tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); + + skb1 = skb_peek_tail(&tp->out_of_order_queue); + if (!skb1) { + /* Initial out of order segment, build 1 SACK. */ + if (tcp_is_sack(tp)) { + tp->rx_opt.num_sacks = 1; + tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq; + tp->selective_acks[0].end_seq = + TCP_SKB_CB(skb)->end_seq; + } + __skb_queue_head(&tp->out_of_order_queue, skb); + goto end; + } + + seq = TCP_SKB_CB(skb)->seq; + end_seq = TCP_SKB_CB(skb)->end_seq; + + if (seq == TCP_SKB_CB(skb1)->end_seq) { + __skb_queue_after(&tp->out_of_order_queue, skb1, skb); + + if (!tp->rx_opt.num_sacks || + tp->selective_acks[0].end_seq != seq) + goto add_sack; + + /* Common case: data arrive in order after hole. */ + tp->selective_acks[0].end_seq = end_seq; + goto end; + } + + /* Find place to insert this segment. */ + while (1) { + if (!after(TCP_SKB_CB(skb1)->seq, seq)) + break; + if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) { + skb1 = NULL; + break; + } + skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1); + } + + /* Do skb overlap to previous one? */ + if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { + if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { + /* All the bits are present. Drop. */ + __kfree_skb(skb); + skb = NULL; + tcp_dsack_set(sk, seq, end_seq); + goto add_sack; + } + if (after(seq, TCP_SKB_CB(skb1)->seq)) { + /* Partial overlap. */ + tcp_dsack_set(sk, seq, + TCP_SKB_CB(skb1)->end_seq); + } else { + if (skb_queue_is_first(&tp->out_of_order_queue, + skb1)) + skb1 = NULL; + else + skb1 = skb_queue_prev( + &tp->out_of_order_queue, + skb1); + } + } + if (!skb1) + __skb_queue_head(&tp->out_of_order_queue, skb); + else + __skb_queue_after(&tp->out_of_order_queue, skb1, skb); + + /* And clean segments covered by new one as whole. */ + while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) { + skb1 = skb_queue_next(&tp->out_of_order_queue, skb); + + if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) + break; + if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) { + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, + end_seq); + break; + } + __skb_unlink(skb1, &tp->out_of_order_queue); + tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, + TCP_SKB_CB(skb1)->end_seq); + __kfree_skb(skb1); + } + +add_sack: + if (tcp_is_sack(tp)) + tcp_sack_new_ofo_skb(sk, seq, end_seq); +end: + if (skb) + skb_set_owner_r(skb, sk); +} + + static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) { const struct tcphdr *th = tcp_hdr(skb); @@ -4561,105 +4675,7 @@ drop: goto queue_and_out; } - TCP_ECN_check_ce(tp, skb); - - if (tcp_try_rmem_schedule(sk, skb->truesize)) - goto drop; - - /* Disable header prediction. */ - tp->pred_flags = 0; - inet_csk_schedule_ack(sk); - - SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", - tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); - - skb_set_owner_r(skb, sk); - - if (!skb_peek(&tp->out_of_order_queue)) { - /* Initial out of order segment, build 1 SACK. */ - if (tcp_is_sack(tp)) { - tp->rx_opt.num_sacks = 1; - tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq; - tp->selective_acks[0].end_seq = - TCP_SKB_CB(skb)->end_seq; - } - __skb_queue_head(&tp->out_of_order_queue, skb); - } else { - struct sk_buff *skb1 = skb_peek_tail(&tp->out_of_order_queue); - u32 seq = TCP_SKB_CB(skb)->seq; - u32 end_seq = TCP_SKB_CB(skb)->end_seq; - - if (seq == TCP_SKB_CB(skb1)->end_seq) { - __skb_queue_after(&tp->out_of_order_queue, skb1, skb); - - if (!tp->rx_opt.num_sacks || - tp->selective_acks[0].end_seq != seq) - goto add_sack; - - /* Common case: data arrive in order after hole. */ - tp->selective_acks[0].end_seq = end_seq; - return; - } - - /* Find place to insert this segment. */ - while (1) { - if (!after(TCP_SKB_CB(skb1)->seq, seq)) - break; - if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) { - skb1 = NULL; - break; - } - skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1); - } - - /* Do skb overlap to previous one? */ - if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { - if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { - /* All the bits are present. Drop. */ - __kfree_skb(skb); - tcp_dsack_set(sk, seq, end_seq); - goto add_sack; - } - if (after(seq, TCP_SKB_CB(skb1)->seq)) { - /* Partial overlap. */ - tcp_dsack_set(sk, seq, - TCP_SKB_CB(skb1)->end_seq); - } else { - if (skb_queue_is_first(&tp->out_of_order_queue, - skb1)) - skb1 = NULL; - else - skb1 = skb_queue_prev( - &tp->out_of_order_queue, - skb1); - } - } - if (!skb1) - __skb_queue_head(&tp->out_of_order_queue, skb); - else - __skb_queue_after(&tp->out_of_order_queue, skb1, skb); - - /* And clean segments covered by new one as whole. */ - while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) { - skb1 = skb_queue_next(&tp->out_of_order_queue, skb); - - if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) - break; - if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) { - tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, - end_seq); - break; - } - __skb_unlink(skb1, &tp->out_of_order_queue); - tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, - TCP_SKB_CB(skb1)->end_seq); - __kfree_skb(skb1); - } - -add_sack: - if (tcp_is_sack(tp)) - tcp_sack_new_ofo_skb(sk, seq, end_seq); - } + tcp_data_queue_ofo(sk, skb); } static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, -- cgit v1.2.3-70-g09d2 From c8628155ece363487b57d33441ea0359018c0fa7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 18 Mar 2012 11:07:47 +0000 Subject: tcp: reduce out_of_order memory use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With increasing receive window sizes, but speed of light not improved that much, out of order queue can contain a huge number of skbs, waiting to be moved to receive_queue when missing packets can fill the holes. Some devices happen to use fat skbs (truesize of 4096 + sizeof(struct sk_buff)) to store regular (MTU <= 1500) frames. This makes highly probable sk_rmem_alloc hits sk_rcvbuf limit, which can be 4Mbytes in many cases. When limit is hit, tcp stack calls tcp_collapse_ofo_queue(), a true latency killer and cpu cache blower. Doing the coalescing attempt each time we add a frame in ofo queue permits to keep memory use tight and in many cases avoid the tcp_collapse() thing later. Tested on various wireless setups (b43, ath9k, ...) known to use big skb truesize, this patch removed the "packets collapsed in receive queue due to low socket buffer" I had before. This also reduced average memory used by tcp sockets. With help from Neal Cardwell. Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Cc: H.K. Jerry Chu Cc: Tom Herbert Cc: Ilpo Järvinen Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- include/linux/snmp.h | 1 + net/ipv4/proc.c | 1 + net/ipv4/tcp_input.c | 19 ++++++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 8ee8af4e6da..2e68f5ba038 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -233,6 +233,7 @@ enum LINUX_MIB_TCPREQQFULLDOCOOKIES, /* TCPReqQFullDoCookies */ LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */ LINUX_MIB_TCPRETRANSFAIL, /* TCPRetransFail */ + LINUX_MIB_TCPRCVCOALESCE, /* TCPRcvCoalesce */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 02d61079f08..8af0d44e4e2 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -257,6 +257,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES), SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP), SNMP_MIB_ITEM("TCPRetransFail", LINUX_MIB_TCPRETRANSFAIL), + SNMP_MIB_ITEM("TCPRcvCoalesce", LINUX_MIB_TCPRCVCOALESCE), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fa7de12c4a5..e886e2f7fa8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4484,7 +4484,24 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) end_seq = TCP_SKB_CB(skb)->end_seq; if (seq == TCP_SKB_CB(skb1)->end_seq) { - __skb_queue_after(&tp->out_of_order_queue, skb1, skb); + /* Packets in ofo can stay in queue a long time. + * Better try to coalesce them right now + * to avoid future tcp_collapse_ofo_queue(), + * probably the most expensive function in tcp stack. + */ + if (skb->len <= skb_tailroom(skb1) && !tcp_hdr(skb)->fin) { + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPRCVCOALESCE); + BUG_ON(skb_copy_bits(skb, 0, + skb_put(skb1, skb->len), + skb->len)); + TCP_SKB_CB(skb1)->end_seq = end_seq; + TCP_SKB_CB(skb1)->ack_seq = TCP_SKB_CB(skb)->ack_seq; + __kfree_skb(skb); + skb = NULL; + } else { + __skb_queue_after(&tp->out_of_order_queue, skb1, skb); + } if (!tp->rx_opt.num_sacks || tp->selective_acks[0].end_seq != seq) -- cgit v1.2.3-70-g09d2 From 1f85851e17b64cabd089a8a8839dddebc627948c Mon Sep 17 00:00:00 2001 From: Gao feng Date: Mon, 19 Mar 2012 22:36:10 +0000 Subject: ipv6: fix incorrent ipv6 ipsec packet fragment Since commit 299b0767(ipv6: Fix IPsec slowpath fragmentation problem) In func ip6_append_data,after call skb_put(skb, fraglen + dst_exthdrlen) the skb->len contains dst_exthdrlen,and we don't reduce dst_exthdrlen at last This will make fraggap>0 in next "while cycle",and cause the size of skb incorrent Fix this by reserve headroom for dst_exthdrlen. Signed-off-by: Gao feng Acked-by: Steffen Klassert Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7a98fc2a5d9..b7ca46161cb 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1414,8 +1414,9 @@ alloc_new_skb: */ skb->ip_summed = csummode; skb->csum = 0; - /* reserve for fragmentation */ - skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); + /* reserve for fragmentation and ipsec header */ + skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + + dst_exthdrlen); if (sk->sk_type == SOCK_DGRAM) skb_shinfo(skb)->tx_flags = tx_flags; @@ -1423,9 +1424,9 @@ alloc_new_skb: /* * Find where to start putting bytes */ - data = skb_put(skb, fraglen + dst_exthdrlen); - skb_set_network_header(skb, exthdrlen + dst_exthdrlen); - data += fragheaderlen + dst_exthdrlen; + data = skb_put(skb, fraglen); + skb_set_network_header(skb, exthdrlen); + data += fragheaderlen; skb->transport_header = (skb->network_header + fragheaderlen); if (fraggap) { -- cgit v1.2.3-70-g09d2 From 0352bc550cfa536e4fa2c0e906359bcd5687afff Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Nov 2011 23:14:39 +0800 Subject: net: remove the second argument of k[un]map_atomic() Acked-by: David S. Miller Signed-off-by: Cong Wang --- net/core/kmap_skb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/kmap_skb.h b/net/core/kmap_skb.h index 81e1ed7c838..52d0a445904 100644 --- a/net/core/kmap_skb.h +++ b/net/core/kmap_skb.h @@ -7,12 +7,12 @@ static inline void *kmap_skb_frag(const skb_frag_t *frag) local_bh_disable(); #endif - return kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ); + return kmap_atomic(skb_frag_page(frag)); } static inline void kunmap_skb_frag(void *vaddr) { - kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(vaddr); #ifdef CONFIG_HIGHMEM local_bh_enable(); #endif -- cgit v1.2.3-70-g09d2 From 6114eab535ab49239e0a6ce08eb9243664aef993 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Nov 2011 23:14:40 +0800 Subject: rds: remove the second argument of k[un]map_atomic() Acked-by: David S. Miller Signed-off-by: Cong Wang --- net/rds/ib_recv.c | 7 +++---- net/rds/info.c | 6 +++--- net/rds/iw_recv.c | 7 +++---- net/rds/loop.c | 2 +- net/rds/rds.h | 2 +- net/rds/recv.c | 2 +- net/rds/tcp_recv.c | 11 ++++------- 7 files changed, 16 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index e29e0ca32f7..744a00dd29c 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -763,7 +763,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn, to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off); BUG_ON(to_copy & 7); /* Must be 64bit aligned. */ - addr = kmap_atomic(sg_page(&frag->f_sg), KM_SOFTIRQ0); + addr = kmap_atomic(sg_page(&frag->f_sg)); src = addr + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; @@ -773,7 +773,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn, uncongested |= ~(*src) & *dst; *dst++ = *src++; } - kunmap_atomic(addr, KM_SOFTIRQ0); + kunmap_atomic(addr); copied += to_copy; @@ -919,8 +919,7 @@ static void rds_ib_process_recv(struct rds_connection *conn, rds_ib_cong_recv(conn, ibinc); else { rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr, - &ibinc->ii_inc, GFP_ATOMIC, - KM_SOFTIRQ0); + &ibinc->ii_inc, GFP_ATOMIC); state->ack_next = be64_to_cpu(hdr->h_sequence); state->ack_next_valid = 1; } diff --git a/net/rds/info.c b/net/rds/info.c index f1c016c4146..9a6b4f66187 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -104,7 +104,7 @@ EXPORT_SYMBOL_GPL(rds_info_deregister_func); void rds_info_iter_unmap(struct rds_info_iterator *iter) { if (iter->addr) { - kunmap_atomic(iter->addr, KM_USER0); + kunmap_atomic(iter->addr); iter->addr = NULL; } } @@ -119,7 +119,7 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data, while (bytes) { if (!iter->addr) - iter->addr = kmap_atomic(*iter->pages, KM_USER0); + iter->addr = kmap_atomic(*iter->pages); this = min(bytes, PAGE_SIZE - iter->offset); @@ -134,7 +134,7 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data, iter->offset += this; if (iter->offset == PAGE_SIZE) { - kunmap_atomic(iter->addr, KM_USER0); + kunmap_atomic(iter->addr); iter->addr = NULL; iter->offset = 0; iter->pages++; diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 5e57347f49f..0bd9b5e7520 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -598,7 +598,7 @@ static void rds_iw_cong_recv(struct rds_connection *conn, to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off); BUG_ON(to_copy & 7); /* Must be 64bit aligned. */ - addr = kmap_atomic(frag->f_page, KM_SOFTIRQ0); + addr = kmap_atomic(frag->f_page); src = addr + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; @@ -608,7 +608,7 @@ static void rds_iw_cong_recv(struct rds_connection *conn, uncongested |= ~(*src) & *dst; *dst++ = *src++; } - kunmap_atomic(addr, KM_SOFTIRQ0); + kunmap_atomic(addr); copied += to_copy; @@ -754,8 +754,7 @@ static void rds_iw_process_recv(struct rds_connection *conn, rds_iw_cong_recv(conn, iwinc); else { rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr, - &iwinc->ii_inc, GFP_ATOMIC, - KM_SOFTIRQ0); + &iwinc->ii_inc, GFP_ATOMIC); state->ack_next = be64_to_cpu(hdr->h_sequence); state->ack_next_valid = 1; } diff --git a/net/rds/loop.c b/net/rds/loop.c index bca6761a3ca..87ff2a8a454 100644 --- a/net/rds/loop.c +++ b/net/rds/loop.c @@ -79,7 +79,7 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm, rds_message_addref(rm); rds_recv_incoming(conn, conn->c_laddr, conn->c_faddr, &rm->m_inc, - GFP_KERNEL, KM_USER0); + GFP_KERNEL); rds_send_drop_acked(conn, be64_to_cpu(rm->m_inc.i_hdr.h_sequence), NULL); diff --git a/net/rds/rds.h b/net/rds/rds.h index 7eaba1831f0..ec1d731ecff 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -704,7 +704,7 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn, __be32 saddr); void rds_inc_put(struct rds_incoming *inc); void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr, - struct rds_incoming *inc, gfp_t gfp, enum km_type km); + struct rds_incoming *inc, gfp_t gfp); int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int msg_flags); void rds_clear_recv_queue(struct rds_sock *rs); diff --git a/net/rds/recv.c b/net/rds/recv.c index bc3f8cd6d07..5c6e9f13202 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -155,7 +155,7 @@ static void rds_recv_incoming_exthdrs(struct rds_incoming *inc, struct rds_sock * tell us which roles the addrs in the conn are playing for this message. */ void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr, - struct rds_incoming *inc, gfp_t gfp, enum km_type km) + struct rds_incoming *inc, gfp_t gfp) { struct rds_sock *rs = NULL; struct sock *sk; diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c index 78205e25500..6243258f840 100644 --- a/net/rds/tcp_recv.c +++ b/net/rds/tcp_recv.c @@ -169,7 +169,6 @@ static void rds_tcp_cong_recv(struct rds_connection *conn, struct rds_tcp_desc_arg { struct rds_connection *conn; gfp_t gfp; - enum km_type km; }; static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb, @@ -255,7 +254,7 @@ static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb, else rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr, &tinc->ti_inc, - arg->gfp, arg->km); + arg->gfp); tc->t_tinc_hdr_rem = sizeof(struct rds_header); tc->t_tinc_data_rem = 0; @@ -272,8 +271,7 @@ out: } /* the caller has to hold the sock lock */ -static int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp, - enum km_type km) +static int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp) { struct rds_tcp_connection *tc = conn->c_transport_data; struct socket *sock = tc->t_sock; @@ -283,7 +281,6 @@ static int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp, /* It's like glib in the kernel! */ arg.conn = conn; arg.gfp = gfp; - arg.km = km; desc.arg.data = &arg; desc.error = 0; desc.count = 1; /* give more than one skb per call */ @@ -311,7 +308,7 @@ int rds_tcp_recv(struct rds_connection *conn) rdsdebug("recv worker conn %p tc %p sock %p\n", conn, tc, sock); lock_sock(sock->sk); - ret = rds_tcp_read_sock(conn, GFP_KERNEL, KM_USER0); + ret = rds_tcp_read_sock(conn, GFP_KERNEL); release_sock(sock->sk); return ret; @@ -336,7 +333,7 @@ void rds_tcp_data_ready(struct sock *sk, int bytes) ready = tc->t_orig_data_ready; rds_tcp_stats_inc(s_tcp_data_ready_calls); - if (rds_tcp_read_sock(conn, GFP_ATOMIC, KM_SOFTIRQ0) == -ENOMEM) + if (rds_tcp_read_sock(conn, GFP_ATOMIC) == -ENOMEM) queue_delayed_work(rds_wq, &conn->c_recv_w, 0); out: read_unlock_bh(&sk->sk_callback_lock); -- cgit v1.2.3-70-g09d2 From b85417860172ff693dc115d7999805fc240cec1c Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Nov 2011 23:14:40 +0800 Subject: sunrpc: remove the second argument of k[un]map_atomic() Signed-off-by: Cong Wang --- net/sunrpc/auth_gss/gss_krb5_wrap.c | 4 ++-- net/sunrpc/socklib.c | 4 ++-- net/sunrpc/xdr.c | 20 ++++++++++---------- net/sunrpc/xprtrdma/rpc_rdma.c | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 2763e3e48db..38f388c39dc 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -82,9 +82,9 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize) >>PAGE_CACHE_SHIFT; unsigned int offset = (buf->page_base + len - 1) & (PAGE_CACHE_SIZE - 1); - ptr = kmap_atomic(buf->pages[last], KM_USER0); + ptr = kmap_atomic(buf->pages[last]); pad = *(ptr + offset); - kunmap_atomic(ptr, KM_USER0); + kunmap_atomic(ptr); goto out; } else len -= buf->page_len; diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 145e6784f50..0a648c502fc 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -114,7 +114,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct } len = PAGE_CACHE_SIZE; - kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); + kaddr = kmap_atomic(*ppage); if (base) { len -= base; if (pglen < len) @@ -127,7 +127,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct ret = copy_actor(desc, kaddr, len); } flush_dcache_page(*ppage); - kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); + kunmap_atomic(kaddr); copied += ret; if (ret != len || !desc->count) goto out; diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 593f4c60530..b97a3dd9a60 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -122,9 +122,9 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len) { char *kaddr; - kaddr = kmap_atomic(buf->pages[0], KM_USER0); + kaddr = kmap_atomic(buf->pages[0]); kaddr[buf->page_base + len] = '\0'; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } EXPORT_SYMBOL_GPL(xdr_terminate_string); @@ -232,12 +232,12 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base, pgto_base -= copy; pgfrom_base -= copy; - vto = kmap_atomic(*pgto, KM_USER0); - vfrom = kmap_atomic(*pgfrom, KM_USER1); + vto = kmap_atomic(*pgto); + vfrom = kmap_atomic(*pgfrom); memmove(vto + pgto_base, vfrom + pgfrom_base, copy); flush_dcache_page(*pgto); - kunmap_atomic(vfrom, KM_USER1); - kunmap_atomic(vto, KM_USER0); + kunmap_atomic(vfrom); + kunmap_atomic(vto); } while ((len -= copy) != 0); } @@ -267,9 +267,9 @@ _copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len) if (copy > len) copy = len; - vto = kmap_atomic(*pgto, KM_USER0); + vto = kmap_atomic(*pgto); memcpy(vto + pgbase, p, copy); - kunmap_atomic(vto, KM_USER0); + kunmap_atomic(vto); len -= copy; if (len == 0) @@ -311,9 +311,9 @@ _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len) if (copy > len) copy = len; - vfrom = kmap_atomic(*pgfrom, KM_USER0); + vfrom = kmap_atomic(*pgfrom); memcpy(p, vfrom + pgbase, copy); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); pgbase += copy; if (pgbase == PAGE_CACHE_SIZE) { diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 554d0814c87..1776e5731dc 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -338,9 +338,9 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) curlen = copy_len; dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n", __func__, i, destp, copy_len, curlen); - srcp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); + srcp = kmap_atomic(ppages[i]); memcpy(destp, srcp+page_base, curlen); - kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA); + kunmap_atomic(srcp); rqst->rq_svec[0].iov_len += curlen; destp += curlen; copy_len -= curlen; @@ -639,10 +639,10 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) dprintk("RPC: %s: page %d" " srcp 0x%p len %d curlen %d\n", __func__, i, srcp, copy_len, curlen); - destp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); + destp = kmap_atomic(ppages[i]); memcpy(destp + page_base, srcp, curlen); flush_dcache_page(ppages[i]); - kunmap_atomic(destp, KM_SKB_SUNRPC_DATA); + kunmap_atomic(destp); srcp += curlen; copy_len -= curlen; if (copy_len == 0) -- cgit v1.2.3-70-g09d2 From e27d359e9b7e446190362cd5c8fe281d02194896 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 18 Mar 2012 14:07:42 -0400 Subject: SUNRPC/NFS: Add Kbuild dependencies for NFS_DEBUG/RPC_DEBUG This allows us to turn on/off the dprintk() debugging interfaces for those distributions that don't ship the 'rpcdebug' utility. It also allows us to add Kbuild dependencies. Specifically, we already know that dprintk() in general relies on CONFIG_SYSCTL. Now it turns out that the NFS dprintks depend on CONFIG_CRC32 after we added support for the filehandle hash. Reported-by: Paul Gortmaker Signed-off-by: Trond Myklebust --- fs/nfs/Kconfig | 6 ++++++ fs/nfs/inode.c | 2 +- fs/nfs/mount_clnt.c | 2 +- fs/nfs/nfsroot.c | 2 +- include/linux/nfs_fs.h | 17 ++++++++--------- include/linux/sunrpc/debug.h | 2 +- net/sunrpc/Kconfig | 13 +++++++++++++ 7 files changed, 31 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 7bce64c7060..2a0e6c59914 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -144,3 +144,9 @@ config NFS_USE_KERNEL_DNS depends on NFS_V4 && !NFS_USE_LEGACY_DNS select DNS_RESOLVER default y + +config NFS_DEBUG + bool + depends on NFS_FS && SUNRPC_DEBUG + select CRC32 + default y diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 1a19f8d30c1..7bb4d13c1cd 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1047,7 +1047,7 @@ struct nfs_fh *nfs_alloc_fhandle(void) return fh; } -#ifdef RPC_DEBUG +#ifdef NFS_DEBUG /* * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle * in the same way that wireshark does diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index b37ca34af90..8e65c7f1f87 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -16,7 +16,7 @@ #include #include "internal.h" -#ifdef RPC_DEBUG +#ifdef NFS_DEBUG # define NFSDBG_FACILITY NFSDBG_MOUNT #endif diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index c4744e1d513..cd3c910d2d1 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -104,7 +104,7 @@ static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = ""; /* server:export path string passed to super.c */ static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = ""; -#ifdef RPC_DEBUG +#ifdef NFS_DEBUG /* * When the "nfsrootdebug" kernel command line option is specified, * enable debugging messages for NFSROOT. diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0a63ab2b5a7..8f27c2e36dd 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -38,6 +38,13 @@ #ifdef __KERNEL__ +/* + * Enable dprintk() debugging support for nfs client. + */ +#ifdef CONFIG_NFS_DEBUG +# define NFS_DEBUG +#endif + #include #include #include @@ -391,7 +398,7 @@ static inline void nfs_free_fhandle(const struct nfs_fh *fh) kfree(fh); } -#ifdef RPC_DEBUG +#ifdef NFS_DEBUG extern u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh); static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh) { @@ -650,14 +657,6 @@ nfs_fileid_to_ino_t(u64 fileid) #ifdef __KERNEL__ -/* - * Enable debugging support for nfs client. - * Requires RPC_DEBUG. - */ -#ifdef RPC_DEBUG -# define NFS_DEBUG -#endif - # undef ifdebug # ifdef NFS_DEBUG # define ifdebug(fac) if (unlikely(nfs_debug & NFSDBG_##fac)) diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index 6cb2517bcf7..9448eb5e426 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -31,7 +31,7 @@ /* * Enable RPC debugging/profiling. */ -#ifdef CONFIG_SYSCTL +#ifdef CONFIG_SUNRPC_DEBUG #define RPC_DEBUG #endif #ifdef CONFIG_TRACEPOINTS diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index ffd243d0918..9fe8857d8d5 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig @@ -39,3 +39,16 @@ config RPCSEC_GSS_KRB5 Kerberos support should be installed. If unsure, say Y. + +config SUNRPC_DEBUG + bool "RPC: Enable dprintk debugging" + depends on SUNRPC && SYSCTL + help + This option enables a sysctl-based debugging interface + that is be used by the 'rpcdebug' utility to turn on or off + logging of different aspects of the kernel RPC activity. + + Disabling this option will make your kernel slightly smaller, + but makes troubleshooting NFS issues significantly harder. + + If unsure, say Y. -- cgit v1.2.3-70-g09d2 From a6506e1486181975d318344143aca722b2b91621 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 19 Mar 2012 13:01:07 +0000 Subject: Remove printk from rds_sendmsg no socket layer outputs a message for this error and neither should rds. Signed-off-by: Dave Jones Signed-off-by: David S. Miller --- net/rds/send.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/rds/send.c b/net/rds/send.c index e2d63c59e7c..96531d4033a 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -935,7 +935,6 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, /* Mirror Linux UDP mirror of BSD error message compatibility */ /* XXX: Perhaps MSG_MORE someday */ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) { - printk(KERN_INFO "msg_flags 0x%08X\n", msg->msg_flags); ret = -EOPNOTSUPP; goto out; } -- cgit v1.2.3-70-g09d2 From bbdb32cb5b73597386913d052165423b9d736145 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 20 Mar 2012 03:57:54 +0000 Subject: Fix pppol2tp getsockname() While testing L2TP functionality, I came across a bug in getsockname(). The IP address returned within the pppol2tp_addr's addr memember was not being set to the IP address in use. This bug is caused by using inet_sk() on the wrong socket (the L2TP socket rather than the underlying UDP socket), and was likely introduced during the addition of L2TPv3 support. Signed-off-by: Benjamin LaHaise Signed-off-by: James Chapman Signed-off-by: David S. Miller --- net/l2tp/l2tp_ppp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 96bc7a67585..9b071910b4b 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -915,7 +915,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, goto end_put_sess; } - inet = inet_sk(sk); + inet = inet_sk(tunnel->sock); if (tunnel->version == 2) { struct sockaddr_pppol2tp sp; len = sizeof(sp); -- cgit v1.2.3-70-g09d2 From 48fde701aff662559b38d9a609574068f22d00fe Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Jan 2012 22:15:13 -0500 Subject: switch open-coded instances of d_make_root() to new helper Signed-off-by: Al Viro --- arch/powerpc/platforms/cell/spufs/inode.c | 4 ++-- arch/s390/hypfs/inode.c | 6 ++---- drivers/misc/ibmasm/ibmasmfs.c | 6 ++---- drivers/oprofile/oprofilefs.c | 6 ++---- drivers/usb/core/inode.c | 9 +-------- drivers/usb/gadget/f_fs.c | 8 ++------ drivers/usb/gadget/inode.c | 4 +--- fs/9p/vfs_super.c | 3 +-- fs/adfs/super.c | 3 +-- fs/affs/super.c | 7 ++----- fs/afs/super.c | 7 ++----- fs/autofs4/inode.c | 10 ++-------- fs/befs/linuxvfs.c | 3 +-- fs/bfs/inode.c | 3 +-- fs/btrfs/super.c | 8 ++------ fs/ceph/super.c | 3 +-- fs/cifs/cifsfs.c | 4 +--- fs/coda/inode.c | 3 +-- fs/configfs/mount.c | 3 +-- fs/cramfs/inode.c | 6 ++---- fs/devpts/inode.c | 3 +-- fs/ecryptfs/main.c | 3 +-- fs/efs/super.c | 3 +-- fs/exofs/super.c | 3 +-- fs/ext2/super.c | 3 +-- fs/ext3/super.c | 3 +-- fs/ext4/super.c | 3 +-- fs/freevxfs/vxfs_super.c | 3 +-- fs/fuse/inode.c | 9 ++------- fs/gfs2/ops_fstype.c | 3 +-- fs/hfs/super.c | 6 ++---- fs/hostfs/hostfs_kern.c | 4 ++-- fs/hpfs/super.c | 6 ++---- fs/hppfs/hppfs.c | 9 ++------- fs/hugetlbfs/inode.c | 13 ++----------- fs/isofs/inode.c | 3 +-- fs/jffs2/fs.c | 6 ++---- fs/jfs/super.c | 3 +-- fs/libfs.c | 6 ++---- fs/logfs/super.c | 6 ++---- fs/ncpfs/inode.c | 6 ++---- fs/nfs/getroot.c | 6 ++---- fs/nilfs2/super.c | 3 +-- fs/ocfs2/dlmfs/dlmfs.c | 14 ++------------ fs/ocfs2/super.c | 3 +-- fs/omfs/inode.c | 6 ++---- fs/openpromfs/inode.c | 3 +-- fs/proc/inode.c | 15 +++------------ fs/pstore/inode.c | 3 +-- fs/qnx4/inode.c | 6 ++---- fs/ramfs/inode.c | 12 ++---------- fs/reiserfs/super.c | 6 ++---- fs/romfs/super.c | 6 ++---- fs/squashfs/super.c | 3 +-- fs/sysfs/mount.c | 3 +-- fs/sysv/super.c | 3 +-- fs/ubifs/super.c | 6 ++---- fs/udf/super.c | 3 +-- fs/ufs/super.c | 6 ++---- fs/xfs/xfs_super.c | 6 ++---- ipc/mqueue.c | 24 +++++++----------------- kernel/cgroup.c | 8 ++------ mm/shmem.c | 6 ++---- net/sunrpc/rpc_pipe.c | 8 ++------ 64 files changed, 105 insertions(+), 264 deletions(-) (limited to 'net') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d4a094ca96f..17b3211e364 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -757,9 +757,9 @@ spufs_create_root(struct super_block *sb, void *data) goto out_iput; ret = -ENOMEM; - sb->s_root = d_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) - goto out_iput; + goto out; return 0; out_iput: diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 8a2a887478c..6a2cb560e96 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -293,11 +293,9 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; root_inode->i_op = &simple_dir_inode_operations; root_inode->i_fop = &simple_dir_operations; - sb->s_root = root_dentry = d_alloc_root(root_inode); - if (!root_dentry) { - iput(root_inode); + sb->s_root = root_dentry = d_make_root(root_inode); + if (!root_dentry) return -ENOMEM; - } if (MACHINE_IS_VM) rc = hypfs_vm_create_files(sb, root_dentry); else diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 35361753b48..15f24f36220 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -129,11 +129,9 @@ static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent) root->i_op = &simple_dir_inode_operations; root->i_fop = ibmasmfs_dir_ops; - root_dentry = d_alloc_root(root); - if (!root_dentry) { - iput(root); + root_dentry = d_make_root(root); + if (!root_dentry) return -ENOMEM; - } sb->s_root = root_dentry; ibmasmfs_create_files(sb, root_dentry); diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 2f0aa0f700e..277bb70b8d7 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -251,11 +251,9 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; root_inode->i_op = &simple_dir_inode_operations; root_inode->i_fop = &simple_dir_operations; - root_dentry = d_alloc_root(root_inode); - if (!root_dentry) { - iput(root_inode); + root_dentry = d_make_root(root_inode); + if (!root_dentry) return -ENOMEM; - } sb->s_root = root_dentry; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 9e186f3da83..bdaef8e3602 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -462,16 +462,9 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_op = &usbfs_ops; sb->s_time_gran = 1; inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); - - if (!inode) { - dbg("%s: could not get inode!",__func__); - return -ENOMEM; - } - - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { dbg("%s: could not get root dentry!",__func__); - iput(inode); return -ENOMEM; } sb->s_root = root; diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index f63dc6c150d..d825b248728 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1063,13 +1063,9 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) &simple_dir_operations, &simple_dir_inode_operations, &data->perms); - if (unlikely(!inode)) + sb->s_root = d_make_root(inode); + if (unlikely(!sb->s_root)) goto Enomem; - sb->s_root = d_alloc_root(inode); - if (unlikely(!sb->s_root)) { - iput(inode); - goto Enomem; - } /* EP0 file */ if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ae04266dba1..c95eea43b63 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -2059,10 +2059,8 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) if (!inode) goto Enomem; inode->i_op = &simple_dir_inode_operations; - if (!(sb->s_root = d_alloc_root (inode))) { - iput(inode); + if (!(sb->s_root = d_make_root (inode))) goto Enomem; - } /* the ep0 file is named after the controller we expect; * user mode code can use it for sanity checks, like we do. diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 7b0cd87b07c..10b7d3c9dba 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -155,9 +155,8 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, goto release_sb; } - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { - iput(inode); retval = -ENOMEM; goto release_sb; } diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 8e3b36ace30..06fdcc9382c 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -483,10 +483,9 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &adfs_dentry_operations; root = adfs_iget(sb, &root_obj); - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { int i; - iput(root); for (i = 0; i < asb->s_map_size; i++) brelse(asb->s_map[i].dm_bh); kfree(asb->s_map); diff --git a/fs/affs/super.c b/fs/affs/super.c index 8ba73fed796..0782653a05a 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -473,7 +473,7 @@ got_root: root_inode = affs_iget(sb, root_block); if (IS_ERR(root_inode)) { ret = PTR_ERR(root_inode); - goto out_error_noinode; + goto out_error; } if (AFFS_SB(sb)->s_flags & SF_INTL) @@ -481,7 +481,7 @@ got_root: else sb->s_d_op = &affs_dentry_operations; - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) { printk(KERN_ERR "AFFS: Get root inode failed\n"); goto out_error; @@ -494,9 +494,6 @@ got_root: * Begin the cascaded cleanup ... */ out_error: - if (root_inode) - iput(root_inode); -out_error_noinode: kfree(sbi->s_bitmap); affs_brelse(root_bh); kfree(sbi->s_prefix); diff --git a/fs/afs/super.c b/fs/afs/super.c index 983ec59fc80..f02b31e7e64 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -301,7 +301,6 @@ static int afs_fill_super(struct super_block *sb, { struct afs_super_info *as = sb->s_fs_info; struct afs_fid fid; - struct dentry *root = NULL; struct inode *inode = NULL; int ret; @@ -327,18 +326,16 @@ static int afs_fill_super(struct super_block *sb, set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); ret = -ENOMEM; - root = d_alloc_root(inode); - if (!root) + sb->s_root = d_make_root(inode); + if (!sb->s_root) goto error; sb->s_d_op = &afs_fs_dentry_operations; - sb->s_root = root; _leave(" = 0"); return 0; error: - iput(inode); _leave(" = %d", ret); return ret; } diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 06858d95512..d8dc002e9cc 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -247,12 +247,9 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) if (!ino) goto fail_free; root_inode = autofs4_get_inode(s, S_IFDIR | 0755); - if (!root_inode) - goto fail_ino; - - root = d_alloc_root(root_inode); + root = d_make_root(root_inode); if (!root) - goto fail_iput; + goto fail_ino; pipe = NULL; root->d_fsdata = ino; @@ -317,9 +314,6 @@ fail_fput: fail_dput: dput(root); goto fail_free; -fail_iput: - printk("autofs: get root dentry failed\n"); - iput(root_inode); fail_ino: kfree(ino); fail_free: diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 6e6d536767f..e18da23d42b 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -852,9 +852,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(root); goto unacquire_priv_sbp; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); befs_error(sb, "get root inode failed"); goto unacquire_priv_sbp; } diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index b0391bc402b..e23dc7c8b88 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -367,9 +367,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) ret = PTR_ERR(inode); goto out2; } - s->s_root = d_alloc_root(inode); + s->s_root = d_make_root(inode); if (!s->s_root) { - iput(inode); ret = -ENOMEM; goto out2; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3ce97b217cb..81df3fec6a6 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -629,7 +629,6 @@ static int btrfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; - struct dentry *root_dentry; struct btrfs_fs_info *fs_info = btrfs_sb(sb); struct btrfs_key key; int err; @@ -660,15 +659,12 @@ static int btrfs_fill_super(struct super_block *sb, goto fail_close; } - root_dentry = d_alloc_root(inode); - if (!root_dentry) { - iput(inode); + sb->s_root = d_make_root(inode); + if (!sb->s_root) { err = -ENOMEM; goto fail_close; } - sb->s_root = root_dentry; - save_mount_options(sb, data); cleancache_init_fs(sb); sb->s_flags |= MS_ACTIVE; diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 00de2c9568c..256f8522192 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -655,9 +655,8 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, dout("open_root_inode success\n"); if (ceph_ino(inode) == CEPH_INO_ROOT && fsc->sb->s_root == NULL) { - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { - iput(inode); root = ERR_PTR(-ENOMEM); goto out; } diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8b7d7ff8879..418fc42fb8b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -122,11 +122,9 @@ cifs_read_super(struct super_block *sb) goto out_no_root; } - sb->s_root = d_alloc_root(inode); - + sb->s_root = d_make_root(inode); if (!sb->s_root) { rc = -ENOMEM; - iput(inode); goto out_no_root; } diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 32dafc875c1..05156c17b55 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -213,9 +213,8 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent) printk("coda_read_super: rootinode is %ld dev %s\n", root->i_ino, root->i_sb->s_id); - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); error = -EINVAL; goto error; } diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 276e15cafd5..07f60455f1c 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -91,10 +91,9 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; } - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { pr_debug("%s: could not get root dentry!\n",__func__); - iput(inode); return -ENOMEM; } config_group_init(&configfs_root_group); diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index a2ee8f9f5a3..853480d2b3d 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -318,11 +318,9 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) root = get_cramfs_inode(sb, &super.root, 0); if (IS_ERR(root)) goto out; - sb->s_root = d_alloc_root(root); - if (!sb->s_root) { - iput(root); + sb->s_root = d_make_root(root); + if (!sb->s_root) goto out; - } return 0; out: kfree(sbi); diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index c4e2a58a2e8..57dae0baedf 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -309,12 +309,11 @@ devpts_fill_super(struct super_block *s, void *data, int silent) inode->i_fop = &simple_dir_operations; set_nlink(inode, 2); - s->s_root = d_alloc_root(inode); + s->s_root = d_make_root(inode); if (s->s_root) return 0; printk(KERN_ERR "devpts: get root dentry failed\n"); - iput(inode); fail: return -ENOMEM; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index b4a6befb121..6e0e017e693 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -550,9 +550,8 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags if (IS_ERR(inode)) goto out_free; - s->s_root = d_alloc_root(inode); + s->s_root = d_make_root(inode); if (!s->s_root) { - iput(inode); rc = -ENOMEM; goto out_free; } diff --git a/fs/efs/super.c b/fs/efs/super.c index 981106429a9..e755ec746c6 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -317,10 +317,9 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) goto out_no_fs; } - s->s_root = d_alloc_root(root); + s->s_root = d_make_root(root); if (!(s->s_root)) { printk(KERN_ERR "EFS: get root dentry failed\n"); - iput(root); ret = -ENOMEM; goto out_no_fs; } diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 6cafcadfc3c..7f2b590a36b 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -819,9 +819,8 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(root); goto free_sbi; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); EXOFS_ERR("ERROR: get root inode failed\n"); ret = -ENOMEM; goto free_sbi; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 9f6766a3ac1..e1025c7a437 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1088,9 +1088,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount3; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); ext2_msg(sb, KERN_ERR, "error: get root inode failed"); ret = -ENOMEM; goto failed_mount3; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 726c7ef6cdf..e0b45b93327 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2046,10 +2046,9 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) ext3_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck"); goto failed_mount3; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { ext3_msg(sb, KERN_ERR, "error: get root dentry failed"); - iput(root); ret = -ENOMEM; goto failed_mount3; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 502c61fd739..d2baea7bcf3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3735,9 +3735,8 @@ no_journal: iput(root); goto failed_mount4; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); ext4_msg(sb, KERN_ERR, "get root dentry failed"); ret = -ENOMEM; goto failed_mount4; diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 9d1c9955838..d4fabd26084 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -224,9 +224,8 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent) ret = PTR_ERR(root); goto out; } - sbp->s_root = d_alloc_root(root); + sbp->s_root = d_make_root(root); if (!sbp->s_root) { - iput(root); printk(KERN_WARNING "vxfs: unable to get root dentry.\n"); goto out_free_ilist; } diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 64cf8d07393..4aec5995867 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -988,14 +988,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) err = -ENOMEM; root = fuse_get_root_inode(sb, d.rootmode); - if (!root) + root_dentry = d_make_root(root); + if (!root_dentry) goto err_put_conn; - - root_dentry = d_alloc_root(root); - if (!root_dentry) { - iput(root); - goto err_put_conn; - } /* only now - we want root dentry with NULL ->d_op */ sb->s_d_op = &fuse_dentry_operations; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 24f609c9ef9..10e848c6d1b 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -431,10 +431,9 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode)); return PTR_ERR(inode); } - dentry = d_alloc_root(inode); + dentry = d_make_root(inode); if (!dentry) { fs_err(sdp, "can't alloc %s dentry\n", name); - iput(inode); return -ENOMEM; } *dptr = dentry; diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 8137fb3e678..7b4c537d6e1 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -430,15 +430,13 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &hfs_dentry_operations; res = -ENOMEM; - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) - goto bail_iput; + goto bail_no_root; /* everything's okay */ return 0; -bail_iput: - iput(root_inode); bail_no_root: printk(KERN_ERR "hfs: get root inode failed.\n"); bail: diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index e130bd46d67..588d45885a6 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -966,9 +966,9 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) } err = -ENOMEM; - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (sb->s_root == NULL) - goto out_put; + goto out; return 0; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 3690467c944..54f6eccb79d 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -625,11 +625,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) hpfs_init_inode(root); hpfs_read_inode(root); unlock_new_inode(root); - s->s_root = d_alloc_root(root); - if (!s->s_root) { - iput(root); + s->s_root = d_make_root(root); + if (!s->s_root) goto bail0; - } /* * find the root directory's . pointer & finish filling in the inode diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index d92f4ce8092..a80e45a690a 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -726,17 +726,12 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) err = -ENOMEM; root_inode = get_inode(sb, dget(proc_mnt->mnt_root)); - if (!root_inode) - goto out_mntput; - - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) - goto out_iput; + goto out_mntput; return 0; - out_iput: - iput(root_inode); out_mntput: mntput(proc_mnt); out: diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 1e85a7ac021..81932fa1861 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -831,8 +831,6 @@ bad_val: static int hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) { - struct inode * inode; - struct dentry * root; int ret; struct hugetlbfs_config config; struct hugetlbfs_sb_info *sbinfo; @@ -865,16 +863,9 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; sb->s_time_gran = 1; - inode = hugetlbfs_get_root(sb, &config); - if (!inode) - goto out_free; - - root = d_alloc_root(inode); - if (!root) { - iput(inode); + sb->s_root = d_make_root(hugetlbfs_get_root(sb, &config)); + if (!sb->s_root) goto out_free; - } - sb->s_root = root; return 0; out_free: kfree(sbinfo); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index bd62c76fb5d..29037c365ba 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -947,9 +947,8 @@ root_found: s->s_d_op = &isofs_dentry_ops[table]; /* get the root dentry */ - s->s_root = d_alloc_root(inode); + s->s_root = d_make_root(inode); if (!(s->s_root)) { - iput(inode); error = -ENOMEM; goto out_no_inode; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 2e0123867cb..c0d5c9d770d 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -561,9 +561,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) ret = -ENOMEM; D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n")); - sb->s_root = d_alloc_root(root_i); + sb->s_root = d_make_root(root_i); if (!sb->s_root) - goto out_root_i; + goto out_root; sb->s_maxbytes = 0xFFFFFFFF; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -573,8 +573,6 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) jffs2_start_garbage_collect_thread(c); return 0; - out_root_i: - iput(root_i); out_root: jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 4661ad70513..b3bb9550447 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -522,7 +522,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(inode); goto out_no_rw; } - sb->s_root = d_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) goto out_no_root; @@ -540,7 +540,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) out_no_root: jfs_err("jfs_read_super: get root dentry failed"); - iput(inode); out_no_rw: rc = jfs_umount(sb); diff --git a/fs/libfs.c b/fs/libfs.c index 5b2dbb3ba4f..7c895a763a1 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -491,11 +491,9 @@ int simple_fill_super(struct super_block *s, unsigned long magic, inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; set_nlink(inode, 2); - root = d_alloc_root(inode); - if (!root) { - iput(inode); + root = d_make_root(inode); + if (!root) return -ENOMEM; - } for (i = 0; !files->name || files->name[0]; i++, files++) { if (!files->name) continue; diff --git a/fs/logfs/super.c b/fs/logfs/super.c index b1a491a5fe7..7de18c3021f 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -315,11 +315,9 @@ static int logfs_get_sb_final(struct super_block *sb) if (IS_ERR(rootdir)) goto fail; - sb->s_root = d_alloc_root(rootdir); - if (!sb->s_root) { - iput(rootdir); + sb->s_root = d_make_root(rootdir); + if (!sb->s_root) goto fail; - } /* at that point we know that ->put_super() will be called */ super->s_erase_page = alloc_pages(GFP_KERNEL, 0); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 3d1e34f8a68..49df0e7f837 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -716,13 +716,11 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) if (!root_inode) goto out_disconnect; DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber); - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) - goto out_no_root; + goto out_disconnect; return 0; -out_no_root: - iput(root_inode); out_disconnect: ncp_lock_server(server); ncp_disconnect(server); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index dcb61548887..801d6d83078 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -49,11 +49,9 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i { /* The mntroot acts as the dummy root dentry for this superblock */ if (sb->s_root == NULL) { - sb->s_root = d_alloc_root(inode); - if (sb->s_root == NULL) { - iput(inode); + sb->s_root = d_make_root(inode); + if (sb->s_root == NULL) return -ENOMEM; - } ihold(inode); /* * Ensure that this dentry is invisible to d_find_alias(). diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1fc9ad3c1d1..1099a76cee5 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -917,9 +917,8 @@ static int nilfs_get_root_dentry(struct super_block *sb, if (root->cno == NILFS_CPTREE_CURRENT_CNO) { dentry = d_find_alias(inode); if (!dentry) { - dentry = d_alloc_root(inode); + dentry = d_make_root(inode); if (!dentry) { - iput(inode); ret = -ENOMEM; goto failed_dentry; } diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index abfac0d7ae9..3b5825ef319 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -582,24 +582,14 @@ static int dlmfs_fill_super(struct super_block * sb, void * data, int silent) { - struct inode * inode; - struct dentry * root; - sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = DLMFS_MAGIC; sb->s_op = &dlmfs_ops; - inode = dlmfs_get_root_inode(sb); - if (!inode) - return -ENOMEM; - - root = d_alloc_root(inode); - if (!root) { - iput(inode); + sb->s_root = d_make_root(dlmfs_get_root_inode(sb)); + if (!sb->s_root) return -ENOMEM; - } - sb->s_root = root; return 0; } diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 2b1184f7097..337687c3e23 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1166,9 +1166,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { - iput(inode); status = -ENOMEM; mlog_errno(status); goto read_super_error; diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 6065bb0ba20..dbc84222258 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -539,11 +539,9 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) goto out_brelse_bh2; } - sb->s_root = d_alloc_root(root); - if (!sb->s_root) { - iput(root); + sb->s_root = d_make_root(root); + if (!sb->s_root) goto out_brelse_bh2; - } printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name); ret = 0; diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index a88c03bc749..bc49c975d50 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -408,13 +408,12 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent) oi->type = op_inode_node; oi->u.node = of_find_node_by_path("/"); - s->s_root = d_alloc_root(root_inode); + s->s_root = d_make_root(root_inode); if (!s->s_root) goto out_no_root_dentry; return 0; out_no_root_dentry: - iput(root_inode); ret = -ENOMEM; out_no_root: printk("openprom_fill_super: get root inode failed\n"); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index a70af3a44f4..8461a7b82fd 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -486,8 +486,6 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) int proc_fill_super(struct super_block *s) { - struct inode * root_inode; - s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; @@ -496,17 +494,10 @@ int proc_fill_super(struct super_block *s) s->s_time_gran = 1; pde_get(&proc_root); - root_inode = proc_get_inode(s, &proc_root); - if (!root_inode) - goto out_no_root; - s->s_root = d_alloc_root(root_inode); - if (!s->s_root) { - iput(root_inode); - goto out_no_root; - } - return 0; + s->s_root = d_make_root(proc_get_inode(s, &proc_root)); + if (s->s_root) + return 0; -out_no_root: printk("proc_read_super: get root inode failed\n"); pde_put(&proc_root); return -ENOMEM; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index b3b426edb2f..ec7d1fb6f35 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -303,7 +303,7 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent) /* override ramfs "dir" options so we catch unlink(2) */ inode->i_op = &pstore_dir_inode_operations; - root = d_alloc_root(inode); + root = d_make_root(inode); sb->s_root = root; if (!root) { err = -ENOMEM; @@ -314,7 +314,6 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent) return 0; fail: - iput(inode); return err; } diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 6b009548d2e..db18d866d98 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -260,15 +260,13 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) } ret = -ENOMEM; - s->s_root = d_alloc_root(root); + s->s_root = d_make_root(root); if (s->s_root == NULL) - goto outi; + goto outb; brelse(bh); return 0; - outi: - iput(root); outb: kfree(qs->BitMap); out: diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index aec766abe3a..b6612d2ed71 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -210,7 +210,6 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent) { struct ramfs_fs_info *fsi; struct inode *inode = NULL; - struct dentry *root; int err; save_mount_options(sb, data); @@ -234,14 +233,8 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran = 1; inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0); - if (!inode) { - err = -ENOMEM; - goto fail; - } - - root = d_alloc_root(inode); - sb->s_root = root; - if (!root) { + sb->s_root = d_make_root(inode); + if (!sb->s_root) { err = -ENOMEM; goto fail; } @@ -250,7 +243,6 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent) fail: kfree(fsi); sb->s_fs_info = NULL; - iput(inode); return err; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index e12d8b97cd4..208dfd14440 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1874,11 +1874,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) unlock_new_inode(root_inode); } - s->s_root = d_alloc_root(root_inode); - if (!s->s_root) { - iput(root_inode); + s->s_root = d_make_root(root_inode); + if (!s->s_root) goto error; - } // define and initialize hash function sbi->s_hash_function = hash_function(s); if (sbi->s_hash_function == NULL) { diff --git a/fs/romfs/super.c b/fs/romfs/super.c index bb36ab74eb4..e64f6b5f7ae 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -538,14 +538,12 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent) if (IS_ERR(root)) goto error; - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) - goto error_i; + goto error; return 0; -error_i: - iput(root); error: return -EINVAL; error_rsb_inval: diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index ecaa2f7bdb8..970b1167e7c 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -316,11 +316,10 @@ check_directory_table: } insert_inode_hash(root); - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (sb->s_root == NULL) { ERROR("Root inode create failed\n"); err = -ENOMEM; - iput(root); goto failed_mount; } diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index e34f0d99ea4..2243f8ec64d 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -61,10 +61,9 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) } /* instantiate and link root dentry */ - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { pr_debug("%s: could not get root dentry!\n",__func__); - iput(inode); return -ENOMEM; } root->d_fsdata = &sysfs_root; diff --git a/fs/sysv/super.c b/fs/sysv/super.c index f467740e088..7491c33b646 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -341,9 +341,8 @@ static int complete_read_super(struct super_block *sb, int silent, int size) printk("SysV FS: get root inode failed\n"); return 0; } - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) { - iput(root_inode); printk("SysV FS: get root dentry failed\n"); return 0; } diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 63765d58445..76e4e0566ad 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2076,15 +2076,13 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) goto out_umount; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) - goto out_iput; + goto out_umount; mutex_unlock(&c->umount_mutex); return 0; -out_iput: - iput(root); out_umount: ubifs_umount(c); out_unlock: diff --git a/fs/udf/super.c b/fs/udf/super.c index 8d8b25336fb..85067b4c7e1 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2037,10 +2037,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) } /* Allocate a dentry for the root inode */ - sb->s_root = d_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) { udf_err(sb, "Couldn't allocate root dentry\n"); - iput(inode); goto error_out; } sb->s_maxbytes = MAX_LFS_FILESIZE; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index ec25d09fcaa..f636f6b460d 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1164,10 +1164,10 @@ magic_found: ret = PTR_ERR(inode); goto failed; } - sb->s_root = d_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) { ret = -ENOMEM; - goto dalloc_failed; + goto failed; } ufs_setup_cstotal(sb); @@ -1181,8 +1181,6 @@ magic_found: UFSD("EXIT\n"); return 0; -dalloc_failed: - iput(inode); failed: if (ubh) ubh_brelse_uspi (uspi); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 0e4c5c017fb..baf40e378d3 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1362,10 +1362,10 @@ xfs_fs_fill_super( error = EINVAL; goto out_syncd_stop; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { error = ENOMEM; - goto out_iput; + goto out_syncd_stop; } return 0; @@ -1384,8 +1384,6 @@ xfs_fs_fill_super( out: return -error; - out_iput: - iput(root); out_syncd_stop: xfs_syncd_stop(mp); out_unmount: diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 86ee272de21..28bd64ddeda 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -188,30 +188,20 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; struct ipc_namespace *ns = data; - int error; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = MQUEUE_MAGIC; sb->s_op = &mqueue_super_ops; - inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, - NULL); - if (IS_ERR(inode)) { - error = PTR_ERR(inode); - goto out; - } + inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL); + if (IS_ERR(inode)) + return PTR_ERR(inode); - sb->s_root = d_alloc_root(inode); - if (!sb->s_root) { - iput(inode); - error = -ENOMEM; - goto out; - } - error = 0; - -out: - return error; + sb->s_root = d_make_root(inode); + if (!sb->s_root) + return -ENOMEM; + return 0; } static struct dentry *mqueue_mount(struct file_system_type *fs_type, diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a5d3b5325f7..711c1a30cea 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1472,7 +1472,6 @@ static int cgroup_get_rootdir(struct super_block *sb) struct inode *inode = cgroup_new_inode(S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, sb); - struct dentry *dentry; if (!inode) return -ENOMEM; @@ -1481,12 +1480,9 @@ static int cgroup_get_rootdir(struct super_block *sb) inode->i_op = &cgroup_dir_inode_operations; /* directories start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); - dentry = d_alloc_root(inode); - if (!dentry) { - iput(inode); + sb->s_root = d_make_root(inode); + if (!sb->s_root) return -ENOMEM; - } - sb->s_root = dentry; /* for everything else we want ->d_op set */ sb->s_d_op = &cgroup_dops; return 0; diff --git a/mm/shmem.c b/mm/shmem.c index 269d049294a..154243f0a27 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2232,14 +2232,12 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) goto failed; inode->i_uid = sbinfo->uid; inode->i_gid = sbinfo->gid; - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) - goto failed_iput; + goto failed; sb->s_root = root; return 0; -failed_iput: - iput(inode); failed: shmem_put_super(sb); return err; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 63a7a7add21..7d6dd6efbdb 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1033,13 +1033,9 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran = 1; inode = rpc_get_inode(sb, S_IFDIR | 0755); - if (!inode) - return -ENOMEM; - sb->s_root = root = d_alloc_root(inode); - if (!root) { - iput(inode); + sb->s_root = root = d_make_root(inode); + if (!root) return -ENOMEM; - } if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; return 0; -- cgit v1.2.3-70-g09d2 From 40ffe67d2e89c7a475421d007becc11a2f88ea3d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 14 Mar 2012 21:54:32 -0400 Subject: switch unix_sock to struct path Signed-off-by: Al Viro --- include/net/af_unix.h | 3 +-- net/unix/af_unix.c | 35 +++++++++++++++-------------------- net/unix/diag.c | 2 +- security/lsm_audit.c | 8 ++------ 4 files changed, 19 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 5a4e29b168c..ca68e2cef23 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -49,8 +49,7 @@ struct unix_sock { /* WARNING: sk has to be the first member */ struct sock sk; struct unix_address *addr; - struct dentry *dentry; - struct vfsmount *mnt; + struct path path; struct mutex readlock; struct sock *peer; struct sock *other; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 85d3bb7490a..ef4b780ef63 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -293,7 +293,7 @@ static struct sock *unix_find_socket_byinode(struct inode *i) spin_lock(&unix_table_lock); sk_for_each(s, node, &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { - struct dentry *dentry = unix_sk(s)->dentry; + struct dentry *dentry = unix_sk(s)->path.dentry; if (dentry && dentry->d_inode == i) { sock_hold(s); @@ -377,8 +377,7 @@ static void unix_sock_destructor(struct sock *sk) static int unix_release_sock(struct sock *sk, int embrion) { struct unix_sock *u = unix_sk(sk); - struct dentry *dentry; - struct vfsmount *mnt; + struct path path; struct sock *skpair; struct sk_buff *skb; int state; @@ -389,10 +388,9 @@ static int unix_release_sock(struct sock *sk, int embrion) unix_state_lock(sk); sock_orphan(sk); sk->sk_shutdown = SHUTDOWN_MASK; - dentry = u->dentry; - u->dentry = NULL; - mnt = u->mnt; - u->mnt = NULL; + path = u->path; + u->path.dentry = NULL; + u->path.mnt = NULL; state = sk->sk_state; sk->sk_state = TCP_CLOSE; unix_state_unlock(sk); @@ -425,10 +423,8 @@ static int unix_release_sock(struct sock *sk, int embrion) kfree_skb(skb); } - if (dentry) { - dput(dentry); - mntput(mnt); - } + if (path.dentry) + path_put(&path); sock_put(sk); @@ -628,8 +624,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; sk->sk_destruct = unix_sock_destructor; u = unix_sk(sk); - u->dentry = NULL; - u->mnt = NULL; + u->path.dentry = NULL; + u->path.mnt = NULL; spin_lock_init(&u->lock); atomic_long_set(&u->inflight, 0); INIT_LIST_HEAD(&u->link); @@ -789,9 +785,9 @@ static struct sock *unix_find_other(struct net *net, u = unix_find_socket_byname(net, sunname, len, type, hash); if (u) { struct dentry *dentry; - dentry = unix_sk(u)->dentry; + dentry = unix_sk(u)->path.dentry; if (dentry) - touch_atime(unix_sk(u)->mnt, dentry); + touch_atime(unix_sk(u)->path.mnt, dentry); } else goto fail; } @@ -897,8 +893,7 @@ out_mknod_drop_write: list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; - u->dentry = path.dentry; - u->mnt = path.mnt; + u->path = path; } err = 0; @@ -1180,9 +1175,9 @@ restart: atomic_inc(&otheru->addr->refcnt); newu->addr = otheru->addr; } - if (otheru->dentry) { - newu->dentry = dget(otheru->dentry); - newu->mnt = mntget(otheru->mnt); + if (otheru->path.dentry) { + path_get(&otheru->path); + newu->path = otheru->path; } /* Set credentials */ diff --git a/net/unix/diag.c b/net/unix/diag.c index 6b7697fd911..ffd86518e64 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -29,7 +29,7 @@ rtattr_failure: static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb) { - struct dentry *dentry = unix_sk(sk)->dentry; + struct dentry *dentry = unix_sk(sk)->path.dentry; struct unix_diag_vfs *uv; if (dentry) { diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 293b8c45b1d..8b8f0902f6e 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -313,12 +313,8 @@ static void dump_common_audit_data(struct audit_buffer *ab, } case AF_UNIX: u = unix_sk(sk); - if (u->dentry) { - struct path path = { - .dentry = u->dentry, - .mnt = u->mnt - }; - audit_log_d_path(ab, " path=", &path); + if (u->path.dentry) { + audit_log_d_path(ab, " path=", &u->path); break; } if (!u->addr) -- cgit v1.2.3-70-g09d2 From 68ac1234fb949b66941d94dce4157742799fc581 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 15 Mar 2012 08:21:57 -0400 Subject: switch touch_atime to struct path Signed-off-by: Al Viro --- fs/cachefiles/namei.c | 3 ++- fs/ecryptfs/file.c | 9 ++++----- fs/inode.c | 5 +++-- fs/namei.c | 2 +- fs/nfsd/vfs.c | 11 ++++++----- fs/stat.c | 2 +- include/linux/fs.h | 4 ++-- net/unix/af_unix.c | 4 ++-- 8 files changed, 21 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index a0358c2189c..7f0771d3894 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -646,7 +646,8 @@ lookup_again: * (this is used to keep track of culling, and atimes are only * updated by read, write and readdir but not lookup or * open) */ - touch_atime(cache->mnt, next); + path.dentry = next; + touch_atime(&path); } /* open a file interface onto a data file */ diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index d3f95f941c4..2b17f2f9b12 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -48,8 +48,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, unsigned long nr_segs, loff_t pos) { ssize_t rc; - struct dentry *lower_dentry; - struct vfsmount *lower_vfsmount; + struct path lower; struct file *file = iocb->ki_filp; rc = generic_file_aio_read(iocb, iov, nr_segs, pos); @@ -60,9 +59,9 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, if (-EIOCBQUEUED == rc) rc = wait_on_sync_kiocb(iocb); if (rc >= 0) { - lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry); - lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry); - touch_atime(lower_vfsmount, lower_dentry); + lower.dentry = ecryptfs_dentry_to_lower(file->f_path.dentry); + lower.mnt = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry); + touch_atime(&lower); } return rc; } diff --git a/fs/inode.c b/fs/inode.c index 92de04b0baa..8b612813a6a 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1499,9 +1499,10 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, * This function automatically handles read only file systems and media, * as well as the "noatime" flag and inode specific "noatime" markers. */ -void touch_atime(struct vfsmount *mnt, struct dentry *dentry) +void touch_atime(struct path *path) { - struct inode *inode = dentry->d_inode; + struct vfsmount *mnt = path->mnt; + struct inode *inode = path->dentry->d_inode; struct timespec now; if (inode->i_flags & S_NOATIME) diff --git a/fs/namei.c b/fs/namei.c index a0b82762e8f..0ccc74ee92f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -642,7 +642,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p) cond_resched(); current->total_link_count++; - touch_atime(link->mnt, dentry); + touch_atime(link); nd_set_link(nd, NULL); error = security_inode_follow_link(link->dentry, nd); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index edf6d3ed877..e59f71d0cf7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1541,30 +1541,31 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, __be32 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) { - struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; __be32 err; int host_err; + struct path path; err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP); if (err) goto out; - dentry = fhp->fh_dentry; - inode = dentry->d_inode; + path.mnt = fhp->fh_export->ex_path.mnt; + path.dentry = fhp->fh_dentry; + inode = path.dentry->d_inode; err = nfserr_inval; if (!inode->i_op->readlink) goto out; - touch_atime(fhp->fh_export->ex_path.mnt, dentry); + touch_atime(&path); /* N.B. Why does this call need a get_fs()?? * Remove the set_fs and watch the fireworks:-) --okir */ oldfs = get_fs(); set_fs(KERNEL_DS); - host_err = inode->i_op->readlink(dentry, buf, *lenp); + host_err = inode->i_op->readlink(path.dentry, buf, *lenp); set_fs(oldfs); if (host_err < 0) diff --git a/fs/stat.c b/fs/stat.c index 8806b8997d2..86f13563a46 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -307,7 +307,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, if (inode->i_op->readlink) { error = security_inode_readlink(path.dentry); if (!error) { - touch_atime(path.mnt, path.dentry); + touch_atime(&path); error = inode->i_op->readlink(path.dentry, buf, bufsiz); } diff --git a/include/linux/fs.h b/include/linux/fs.h index b89dc4d60d9..9bbe1a9ac43 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1812,11 +1812,11 @@ static inline void inode_inc_iversion(struct inode *inode) spin_unlock(&inode->i_lock); } -extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry); +extern void touch_atime(struct path *); static inline void file_accessed(struct file *file) { if (!(file->f_flags & O_NOATIME)) - touch_atime(file->f_path.mnt, file->f_path.dentry); + touch_atime(&file->f_path); } int sync_inode(struct inode *inode, struct writeback_control *wbc); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ef4b780ef63..081679444a6 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -771,7 +771,7 @@ static struct sock *unix_find_other(struct net *net, goto put_fail; if (u->sk_type == type) - touch_atime(path.mnt, path.dentry); + touch_atime(&path); path_put(&path); @@ -787,7 +787,7 @@ static struct sock *unix_find_other(struct net *net, struct dentry *dentry; dentry = unix_sk(u)->path.dentry; if (dentry) - touch_atime(unix_sk(u)->path.mnt, dentry); + touch_atime(&unix_sk(u)->path); } else goto fail; } -- cgit v1.2.3-70-g09d2 From ffa94db6042e6fd014ae0bed8832ac707ef2afe9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Mar 2012 09:22:00 -0400 Subject: SUNRPC/LOCKD: Fix build warnings when CONFIG_SUNRPC_DEBUG is undefined Stephen Rothwell reports: net/sunrpc/rpcb_clnt.c: In function 'rpcb_enc_mapping': net/sunrpc/rpcb_clnt.c:820:19: warning: unused variable 'task' [-Wunused-variable] net/sunrpc/rpcb_clnt.c: In function 'rpcb_dec_getport': net/sunrpc/rpcb_clnt.c:837:19: warning: unused variable 'task' [-Wunused-variable] net/sunrpc/rpcb_clnt.c: In function 'rpcb_dec_set': net/sunrpc/rpcb_clnt.c:860:19: warning: unused variable 'task' [-Wunused-variable] net/sunrpc/rpcb_clnt.c: In function 'rpcb_enc_getaddr': net/sunrpc/rpcb_clnt.c:892:19: warning: unused variable 'task' [-Wunused-variable] net/sunrpc/rpcb_clnt.c: In function 'rpcb_dec_getaddr': net/sunrpc/rpcb_clnt.c:914:19: warning: unused variable 'task' [-Wunused-variable] fs/lockd/svclock.c:49:20: warning: 'nlmdbg_cookie2a' declared 'static' but never defined [-Wunused-function] Reported-by: Stephen Rothwell Signed-off-by: Trond Myklebust --- fs/lockd/svclock.c | 59 +++++++++++++++++++++++++------------------------- net/sunrpc/rpcb_clnt.c | 27 +++++++++++------------ 2 files changed, 42 insertions(+), 44 deletions(-) (limited to 'net') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index f0179c3745d..e46353f41a4 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -46,7 +46,6 @@ static void nlmsvc_remove_block(struct nlm_block *block); static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); static void nlmsvc_freegrantargs(struct nlm_rqst *call); static const struct rpc_call_ops nlmsvc_grant_ops; -static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie); /* * The list of blocked locks to retry @@ -54,6 +53,35 @@ static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie); static LIST_HEAD(nlm_blocked); static DEFINE_SPINLOCK(nlm_blocked_lock); +#ifdef LOCKD_DEBUG +static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) +{ + /* + * We can get away with a static buffer because we're only + * called with BKL held. + */ + static char buf[2*NLM_MAXCOOKIELEN+1]; + unsigned int i, len = sizeof(buf); + char *p = buf; + + len--; /* allow for trailing \0 */ + if (len < 3) + return "???"; + for (i = 0 ; i < cookie->len ; i++) { + if (len < 2) { + strcpy(p-3, "..."); + break; + } + sprintf(p, "%02x", cookie->data[i]); + p += 2; + len -= 2; + } + *p = '\0'; + + return buf; +} +#endif + /* * Insert a blocked lock into the global list */ @@ -935,32 +963,3 @@ nlmsvc_retry_blocked(void) return timeout; } - -#ifdef RPC_DEBUG -static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) -{ - /* - * We can get away with a static buffer because we're only - * called with BKL held. - */ - static char buf[2*NLM_MAXCOOKIELEN+1]; - unsigned int i, len = sizeof(buf); - char *p = buf; - - len--; /* allow for trailing \0 */ - if (len < 3) - return "???"; - for (i = 0 ; i < cookie->len ; i++) { - if (len < 2) { - strcpy(p-3, "..."); - break; - } - sprintf(p, "%02x", cookie->data[i]); - p += 2; - len -= 2; - } - *p = '\0'; - - return buf; -} -#endif diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index e699ff0ce90..207a74696c9 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -817,11 +817,11 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, const struct rpcbind_args *rpcb) { - struct rpc_task *task = req->rq_task; __be32 *p; dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name, + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2); @@ -834,7 +834,6 @@ static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, struct rpcbind_args *rpcb) { - struct rpc_task *task = req->rq_task; unsigned long port; __be32 *p; @@ -845,8 +844,8 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, return -EIO; port = be32_to_cpup(p); - dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid, - task->tk_msg.rpc_proc->p_name, port); + dprintk("RPC: %5u PMAP_%s result: %lu\n", req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, port); if (unlikely(port > USHRT_MAX)) return -EIO; @@ -857,7 +856,6 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, unsigned int *boolp) { - struct rpc_task *task = req->rq_task; __be32 *p; p = xdr_inline_decode(xdr, 4); @@ -869,7 +867,8 @@ static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, *boolp = 1; dprintk("RPC: %5u RPCB_%s call %s\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name, + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, (*boolp ? "succeeded" : "failed")); return 0; } @@ -889,11 +888,11 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string, static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, const struct rpcbind_args *rpcb) { - struct rpc_task *task = req->rq_task; __be32 *p; dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name, + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, rpcb->r_prog, rpcb->r_vers, rpcb->r_netid, rpcb->r_addr); @@ -911,7 +910,6 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, { struct sockaddr_storage address; struct sockaddr *sap = (struct sockaddr *)&address; - struct rpc_task *task = req->rq_task; __be32 *p; u32 len; @@ -928,7 +926,7 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, */ if (len == 0) { dprintk("RPC: %5u RPCB reply: program not registered\n", - task->tk_pid); + req->rq_task->tk_pid); return 0; } @@ -938,8 +936,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, p = xdr_inline_decode(xdr, len); if (unlikely(p == NULL)) goto out_fail; - dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid, - task->tk_msg.rpc_proc->p_name, (char *)p); + dprintk("RPC: %5u RPCB_%s reply: %s\n", req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, (char *)p); if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len, sap, sizeof(address)) == 0) @@ -950,7 +948,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, out_fail: dprintk("RPC: %5u malformed RPCB_%s reply\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name); + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name); return -EIO; } -- cgit v1.2.3-70-g09d2 From 4a6862b3649d705bf41a36e3c7943d0322a9ee27 Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Mon, 20 Feb 2012 13:07:42 -0600 Subject: xprtrdma: The transport should not bug-check when a dup reply is received The client side RDMA transport will bug check if it receives a duplicate reply, instead we should simply drop the duplicate reply. Signed-off-by: Tom Tucker Signed-off-by: Trond Myklebust --- net/sunrpc/xprtrdma/rpc_rdma.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 554d0814c87..12de982b7a5 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -771,13 +771,18 @@ repost: /* get request object */ req = rpcr_to_rdmar(rqst); + if (req->rl_reply) { + spin_unlock(&xprt->transport_lock); + dprintk("RPC: %s: duplicate reply 0x%p to RPC " + "request 0x%p: xid 0x%08x\n", __func__, rep, req, + headerp->rm_xid); + goto repost; + } dprintk("RPC: %s: reply 0x%p completes request 0x%p\n" " RPC request 0x%p xid 0x%08x\n", __func__, rep, req, rqst, headerp->rm_xid); - BUG_ON(!req || req->rl_reply); - /* from here on, the reply is no longer an orphan */ req->rl_reply = rep; -- cgit v1.2.3-70-g09d2 From 9b78145c0f280d4f01c460d6251eab2584181fa9 Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Mon, 20 Feb 2012 13:07:57 -0600 Subject: xprtrdma: Remove assumption that each segment is <= PAGE_SIZE The xprtrdma FRMR mapping logic assumes that a segment is <= PAGE_SIZE. This is not true for NFS4. Signed-off-by: Tom Tucker Signed-off-by: Trond Myklebust --- net/sunrpc/xprtrdma/verbs.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 28236bab57f..745973b729a 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1490,6 +1490,9 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, u8 key; int len, pageoff; int i, rc; + int seg_len; + u64 pa; + int page_no; pageoff = offset_in_page(seg1->mr_offset); seg1->mr_offset -= pageoff; /* start of page */ @@ -1497,11 +1500,15 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, len = -pageoff; if (*nsegs > RPCRDMA_MAX_DATA_SEGS) *nsegs = RPCRDMA_MAX_DATA_SEGS; - for (i = 0; i < *nsegs;) { + for (page_no = i = 0; i < *nsegs;) { rpcrdma_map_one(ia, seg, writing); - seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma; + pa = seg->mr_dma; + for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) { + seg1->mr_chunk.rl_mw->r.frmr.fr_pgl-> + page_list[page_no++] = pa; + pa += PAGE_SIZE; + } len += seg->mr_len; - BUG_ON(seg->mr_len > PAGE_SIZE); ++seg; ++i; /* Check for holes */ @@ -1540,9 +1547,9 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, frmr_wr.send_flags = IB_SEND_SIGNALED; frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; - frmr_wr.wr.fast_reg.page_list_len = i; + frmr_wr.wr.fast_reg.page_list_len = page_no; frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; - frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; + frmr_wr.wr.fast_reg.length = page_no << PAGE_SHIFT; BUG_ON(frmr_wr.wr.fast_reg.length < len); frmr_wr.wr.fast_reg.access_flags = (writing ? IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : -- cgit v1.2.3-70-g09d2 From 2a2a459eeeff48640dc557548ce576d666ab06ed Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Mar 2012 06:58:03 +0000 Subject: net: fix napi_reuse_skb() skb reserve napi->skb is allocated in napi_get_frags() using netdev_alloc_skb_ip_align(), with a reserve of NET_SKB_PAD + NET_IP_ALIGN bytes. However, when such skb is recycled in napi_reuse_skb(), it ends with a reserve of NET_IP_ALIGN which is suboptimal. Signed-off-by: Eric Dumazet Cc: Herbert Xu Signed-off-by: David S. Miller --- net/core/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 0f3eb7d79a2..452db7090d1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3560,7 +3560,8 @@ EXPORT_SYMBOL(napi_gro_receive); static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) { __skb_pull(skb, skb_headlen(skb)); - skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb)); + /* restore the reserve we had after netdev_alloc_skb_ip_align() */ + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN - skb_headroom(skb)); skb->vlan_tci = 0; skb->dev = napi->dev; skb->skb_iif = 0; -- cgit v1.2.3-70-g09d2 From 9395a09d05a23bb313cd20c99fb234f308d948b3 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 20 Mar 2012 14:01:21 +0000 Subject: l2tp: enable automatic module loading for l2tp_ppp When L2TP is configured as a module, requests for L2TP sockets do not result in the l2tp_ppp module being loaded. Fix this by adding the appropriate MODULE_ALIAS to be recognized by pppox's request_module() call. Signed-off-by: Benjamin LaHaise Signed-off-by: David S. Miller --- net/l2tp/l2tp_ppp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 9b071910b4b..1addd9f3f40 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -1845,3 +1845,4 @@ MODULE_AUTHOR("James Chapman "); MODULE_DESCRIPTION("PPP over L2TP over UDP"); MODULE_LICENSE("GPL"); MODULE_VERSION(PPPOL2TP_DRV_VERSION); +MODULE_ALIAS("pppox-proto-" __stringify(PX_PROTO_OL2TP)); -- cgit v1.2.3-70-g09d2 From a0f65a267dd62aef4e003f833ea6290fd1e07b34 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 10 Mar 2012 12:15:15 +0100 Subject: netfilter: xt_LOG: use CONFIG_IP6_NF_IPTABLES instead of CONFIG_IPV6 This fixes the following linking error: xt_LOG.c:(.text+0x789b1): undefined reference to `ip6t_ext_hdr' ifdefs have to use CONFIG_IP6_NF_IPTABLES instead of CONFIG_IPV6. Acked-by: Randy Dunlap Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_LOG.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index f99f8dee238..ff5f75fddb1 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -480,7 +480,7 @@ ipt_log_packet(u_int8_t pf, sb_close(m); } -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) /* One level of recursion won't kill us */ static void dump_ipv6_packet(struct sbuff *m, const struct nf_loginfo *info, @@ -824,7 +824,7 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par) if (par->family == NFPROTO_IPV4) ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li, loginfo->prefix); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) else if (par->family == NFPROTO_IPV6) ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out, &li, loginfo->prefix); @@ -864,7 +864,7 @@ static struct xt_target log_tg_regs[] __read_mostly = { .checkentry = log_tg_check, .me = THIS_MODULE, }, -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) { .name = "LOG", .family = NFPROTO_IPV6, @@ -882,7 +882,7 @@ static struct nf_logger ipt_log_logger __read_mostly = { .me = THIS_MODULE, }; -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) static struct nf_logger ip6t_log_logger __read_mostly = { .name = "ip6t_LOG", .logfn = &ip6t_log_packet, @@ -899,7 +899,7 @@ static int __init log_tg_init(void) return ret; nf_log_register(NFPROTO_IPV4, &ipt_log_logger); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); #endif return 0; @@ -908,7 +908,7 @@ static int __init log_tg_init(void) static void __exit log_tg_exit(void) { nf_log_unregister(&ipt_log_logger); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) nf_log_unregister(&ip6t_log_logger); #endif xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); -- cgit v1.2.3-70-g09d2 From 182fac2689b769a96e7fc9defcd560c5cca92b1e Mon Sep 17 00:00:00 2001 From: Jim Schutt Date: Wed, 29 Feb 2012 08:30:58 -0700 Subject: net/ceph: Only clear SOCK_NOSPACE when there is sufficient space in the socket buffer The Ceph messenger would sometimes queue multiple work items to write data to a socket when the socket buffer was full. Fix this problem by making ceph_write_space() use SOCK_NOSPACE in the same way that net/core/stream.c:sk_stream_write_space() does, i.e., clearing it only when sufficient space is available in the socket buffer. Signed-off-by: Jim Schutt Reviewed-by: Alex Elder --- net/ceph/messenger.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index ad5b70801f3..d11f91b0545 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -143,16 +143,22 @@ static void ceph_write_space(struct sock *sk) struct ceph_connection *con = (struct ceph_connection *)sk->sk_user_data; - /* only queue to workqueue if there is data we want to write. */ + /* only queue to workqueue if there is data we want to write, + * and there is sufficient space in the socket buffer to accept + * more data. clear SOCK_NOSPACE so that ceph_write_space() + * doesn't get called again until try_write() fills the socket + * buffer. See net/ipv4/tcp_input.c:tcp_check_space() + * and net/core/stream.c:sk_stream_write_space(). + */ if (test_bit(WRITE_PENDING, &con->state)) { - dout("ceph_write_space %p queueing write work\n", con); - queue_con(con); + if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { + dout("ceph_write_space %p queueing write work\n", con); + clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + queue_con(con); + } } else { dout("ceph_write_space %p nothing to write\n", con); } - - /* since we have our own write_space, clear the SOCK_NOSPACE flag */ - clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); } /* socket's state has changed */ -- cgit v1.2.3-70-g09d2 From 64486697771cbe219fffcb5c8e2ed9ca4fdf086c Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Thu, 16 Feb 2012 11:55:48 -0500 Subject: libceph: fix overflow check in crush_decode() The existing overflow check (n > ULONG_MAX / b) didn't work, because n = ULONG_MAX / b would both bypass the check and still overflow the allocation size a + n * b. The correct check should be (n > (ULONG_MAX - a) / b). Signed-off-by: Xi Wang Signed-off-by: Sage Weil --- net/ceph/osdmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index fd863fe7693..29ad46ec9dc 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -283,7 +283,8 @@ static struct crush_map *crush_decode(void *pbyval, void *end) ceph_decode_32_safe(p, end, yes, bad); #if BITS_PER_LONG == 32 err = -EINVAL; - if (yes > ULONG_MAX / sizeof(struct crush_rule_step)) + if (yes > (ULONG_MAX - sizeof(*r)) + / sizeof(struct crush_rule_step)) goto bad; #endif r = c->rules[i] = kmalloc(sizeof(*r) + -- cgit v1.2.3-70-g09d2 From 5766651971e81298732466c9aa462ff47898ba37 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 23 Jan 2012 15:49:27 -0600 Subject: ceph: use a shared zero page rather than one per messenger Each messenger allocates a page to be used when writing zeroes out in the event of error or other abnormal condition. Instead, use the kernel ZERO_PAGE() for that purpose. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- include/linux/ceph/messenger.h | 1 - net/ceph/messenger.c | 43 ++++++++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index ffbeb2c217b..6b5af5f976d 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -54,7 +54,6 @@ struct ceph_connection_operations { struct ceph_messenger { struct ceph_entity_inst inst; /* my name+address */ struct ceph_entity_addr my_enc_addr; - struct page *zero_page; /* used in certain error cases */ bool nocrc; diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index d11f91b0545..738356255e0 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -52,6 +52,9 @@ static char addr_str[MAX_ADDR_STR][MAX_ADDR_STR_LEN]; static DEFINE_SPINLOCK(addr_str_lock); static int last_addr_str; +static struct page *zero_page; /* used in certain error cases */ +static void *zero_page_address; /* kernel virtual addr of zero_page */ + const char *ceph_pr_addr(const struct sockaddr_storage *ss) { int i; @@ -99,18 +102,41 @@ struct workqueue_struct *ceph_msgr_wq; int ceph_msgr_init(void) { + BUG_ON(zero_page != NULL); + zero_page = ZERO_PAGE(0); + page_cache_get(zero_page); + + BUG_ON(zero_page_address != NULL); + zero_page_address = kmap(zero_page); + ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0); if (!ceph_msgr_wq) { pr_err("msgr_init failed to create workqueue\n"); + + zero_page_address = NULL; + kunmap(zero_page); + page_cache_release(zero_page); + zero_page = NULL; + return -ENOMEM; } + return 0; } EXPORT_SYMBOL(ceph_msgr_init); void ceph_msgr_exit(void) { + BUG_ON(ceph_msgr_wq == NULL); destroy_workqueue(ceph_msgr_wq); + + BUG_ON(zero_page_address == NULL); + zero_page_address = NULL; + + BUG_ON(zero_page == NULL); + kunmap(zero_page); + page_cache_release(zero_page); + zero_page = NULL; } EXPORT_SYMBOL(ceph_msgr_exit); @@ -841,9 +867,9 @@ static int write_partial_msg_pages(struct ceph_connection *con) max_write = bv->bv_len; #endif } else { - page = con->msgr->zero_page; + page = zero_page; if (crc) - kaddr = page_address(con->msgr->zero_page); + kaddr = zero_page_address; } len = min_t(int, max_write - con->out_msg_pos.page_pos, total_max_write); @@ -914,7 +940,7 @@ static int write_partial_skip(struct ceph_connection *con) while (con->out_skip > 0) { struct kvec iov = { - .iov_base = page_address(con->msgr->zero_page), + .iov_base = zero_page_address, .iov_len = min(con->out_skip, (int)PAGE_CACHE_SIZE) }; @@ -2222,15 +2248,6 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr, spin_lock_init(&msgr->global_seq_lock); - /* the zero page is needed if a request is "canceled" while the message - * is being written over the socket */ - msgr->zero_page = __page_cache_alloc(GFP_KERNEL | __GFP_ZERO); - if (!msgr->zero_page) { - kfree(msgr); - return ERR_PTR(-ENOMEM); - } - kmap(msgr->zero_page); - if (myaddr) msgr->inst.addr = *myaddr; @@ -2247,8 +2264,6 @@ EXPORT_SYMBOL(ceph_messenger_create); void ceph_messenger_destroy(struct ceph_messenger *msgr) { dout("destroy %p\n", msgr); - kunmap(msgr->zero_page); - __free_page(msgr->zero_page); kfree(msgr); dout("destroyed messenger %p\n", msgr); } -- cgit v1.2.3-70-g09d2 From a5bc3129a296fd4663c3ef0be5575e82453739dd Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 23 Jan 2012 15:49:27 -0600 Subject: ceph: make use of "else" where appropriate Rearrange ceph_tcp_connect() a bit, making use of "else" rather than re-testing a value with consecutive "if" statements. Don't record a connection's socket pointer unless the connect operation is successful. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 738356255e0..b5536e4e39a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -251,7 +251,6 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con) IPPROTO_TCP, &sock); if (ret) return ERR_PTR(ret); - con->sock = sock; sock->sk->sk_allocation = GFP_NOFS; #ifdef CONFIG_LOCKDEP @@ -268,18 +267,16 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con) dout("connect %s EINPROGRESS sk_state = %u\n", ceph_pr_addr(&con->peer_addr.in_addr), sock->sk->sk_state); - ret = 0; - } - if (ret < 0) { + } else if (ret < 0) { pr_err("connect %s error %d\n", ceph_pr_addr(&con->peer_addr.in_addr), ret); sock_release(sock); - con->sock = NULL; con->error_msg = "connect error"; - } - if (ret < 0) return ERR_PTR(ret); + } + con->sock = sock; + return sock; } -- cgit v1.2.3-70-g09d2 From f64a93172b97dcfcfa68f595652220653562f605 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 23 Jan 2012 15:49:27 -0600 Subject: ceph: kill addr_str_lock spinlock; use atomic instead A spinlock is used to protect a value used for selecting an array index for a string used for formatting a socket address for human consumption. The index is reset to 0 if it ever reaches the maximum index value. Instead, use an ever-increasing atomic variable as a sequence number, and compute the array index by masking off all but the sequence number's lowest bits. Make the number of entries in the array a power of two to allow the use of such a mask (to avoid jumps in the index value when the sequence number wraps). The length of these strings is somewhat arbitrarily set at 60 bytes. The worst-case length of a string produced is 54 bytes, for an IPv6 address that can't be shortened, e.g.: [1234:5678:9abc:def0:1111:2222:123.234.210.100]:32767 Change it so we arbitrarily use 64 bytes instead; if nothing else it will make the array of these line up better in hex dumps. Rename a few things to reinforce the distinction between the number of strings in the array and the length of individual strings. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index b5536e4e39a..e86bb3f1485 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -44,13 +44,16 @@ static void con_work(struct work_struct *); static void ceph_fault(struct ceph_connection *con); /* - * nicely render a sockaddr as a string. + * Nicely render a sockaddr as a string. An array of formatted + * strings is used, to approximate reentrancy. */ -#define MAX_ADDR_STR 20 -#define MAX_ADDR_STR_LEN 60 -static char addr_str[MAX_ADDR_STR][MAX_ADDR_STR_LEN]; -static DEFINE_SPINLOCK(addr_str_lock); -static int last_addr_str; +#define ADDR_STR_COUNT_LOG 5 /* log2(# address strings in array) */ +#define ADDR_STR_COUNT (1 << ADDR_STR_COUNT_LOG) +#define ADDR_STR_COUNT_MASK (ADDR_STR_COUNT - 1) +#define MAX_ADDR_STR_LEN 64 /* 54 is enough */ + +static char addr_str[ADDR_STR_COUNT][MAX_ADDR_STR_LEN]; +static atomic_t addr_str_seq = ATOMIC_INIT(0); static struct page *zero_page; /* used in certain error cases */ static void *zero_page_address; /* kernel virtual addr of zero_page */ @@ -62,11 +65,7 @@ const char *ceph_pr_addr(const struct sockaddr_storage *ss) struct sockaddr_in *in4 = (void *)ss; struct sockaddr_in6 *in6 = (void *)ss; - spin_lock(&addr_str_lock); - i = last_addr_str++; - if (last_addr_str == MAX_ADDR_STR) - last_addr_str = 0; - spin_unlock(&addr_str_lock); + i = atomic_inc_return(&addr_str_seq) & ADDR_STR_COUNT_MASK; s = addr_str[i]; switch (ss->ss_family) { -- cgit v1.2.3-70-g09d2 From bd406145129e8724cc71b65ff2a788dbd4d60c50 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 23 Jan 2012 15:49:27 -0600 Subject: ceph: eliminate some needless casts This eliminates type casts in some places where they are not required. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index e86bb3f1485..09a412ba4b7 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -70,13 +70,13 @@ const char *ceph_pr_addr(const struct sockaddr_storage *ss) switch (ss->ss_family) { case AF_INET: - snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%u", &in4->sin_addr, - (unsigned int)ntohs(in4->sin_port)); + snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%hu", &in4->sin_addr, + ntohs(in4->sin_port)); break; case AF_INET6: - snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%u", &in6->sin6_addr, - (unsigned int)ntohs(in6->sin6_port)); + snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%hu", &in6->sin6_addr, + ntohs(in6->sin6_port)); break; default: @@ -153,8 +153,8 @@ EXPORT_SYMBOL(ceph_msgr_flush); /* data available on socket, or listen socket received a connect */ static void ceph_data_ready(struct sock *sk, int count_unused) { - struct ceph_connection *con = - (struct ceph_connection *)sk->sk_user_data; + struct ceph_connection *con = sk->sk_user_data; + if (sk->sk_state != TCP_CLOSE_WAIT) { dout("ceph_data_ready on %p state = %lu, queueing work\n", con, con->state); @@ -189,8 +189,7 @@ static void ceph_write_space(struct sock *sk) /* socket's state has changed */ static void ceph_state_change(struct sock *sk) { - struct ceph_connection *con = - (struct ceph_connection *)sk->sk_user_data; + struct ceph_connection *con = sk->sk_user_data; dout("ceph_state_change %p state = %lu sk_state = %u\n", con, con->state, sk->sk_state); @@ -225,7 +224,7 @@ static void set_sock_callbacks(struct socket *sock, struct ceph_connection *con) { struct sock *sk = sock->sk; - sk->sk_user_data = (void *)con; + sk->sk_user_data = con; sk->sk_data_ready = ceph_data_ready; sk->sk_write_space = ceph_write_space; sk->sk_state_change = ceph_state_change; @@ -552,7 +551,7 @@ static void prepare_write_message(struct ceph_connection *con) /* fill in crc (except data pages), footer */ con->out_msg->hdr.crc = - cpu_to_le32(crc32c(0, (void *)&m->hdr, + cpu_to_le32(crc32c(0, &m->hdr, sizeof(m->hdr) - sizeof(m->hdr.crc))); con->out_msg->footer.flags = CEPH_MSG_FOOTER_COMPLETE; con->out_msg->footer.front_crc = @@ -1647,7 +1646,7 @@ static int read_partial_message(struct ceph_connection *con) return ret; con->in_base_pos += ret; if (con->in_base_pos == sizeof(con->in_hdr)) { - u32 crc = crc32c(0, (void *)&con->in_hdr, + u32 crc = crc32c(0, &con->in_hdr, sizeof(con->in_hdr) - sizeof(con->in_hdr.crc)); if (crc != le32_to_cpu(con->in_hdr.crc)) { pr_err("read_partial_message bad hdr " -- cgit v1.2.3-70-g09d2 From 99f0f3b2c4be15784bb4ede33b5f2c3f7861dba7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 23 Jan 2012 15:49:27 -0600 Subject: ceph: eliminate some abusive casts This fixes some spots where a type cast to (void *) was used as as a universal type hiding mechanism. Instead, properly cast the type to the intended target type. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 09a412ba4b7..3917847ad8e 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -62,8 +62,8 @@ const char *ceph_pr_addr(const struct sockaddr_storage *ss) { int i; char *s; - struct sockaddr_in *in4 = (void *)ss; - struct sockaddr_in6 *in6 = (void *)ss; + struct sockaddr_in *in4 = (struct sockaddr_in *) ss; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss; i = atomic_inc_return(&addr_str_seq) & ADDR_STR_COUNT_MASK; s = addr_str[i]; @@ -1112,8 +1112,8 @@ static void addr_set_port(struct sockaddr_storage *ss, int p) static int ceph_pton(const char *str, size_t len, struct sockaddr_storage *ss, char delim, const char **ipend) { - struct sockaddr_in *in4 = (void *)ss; - struct sockaddr_in6 *in6 = (void *)ss; + struct sockaddr_in *in4 = (struct sockaddr_in *) ss; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss; memset(ss, 0, sizeof(*ss)); -- cgit v1.2.3-70-g09d2 From ee57741c5209154b8ef124bcaa2496da1b69a988 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 24 Jan 2012 10:08:36 -0600 Subject: rbd: make ceph_parse_options() return a pointer ceph_parse_options() takes the address of a pointer as an argument and uses it to return the address of an allocated structure if successful. With this interface is not evident at call sites that the pointer is always initialized. Change the interface to return the address instead (or a pointer-coded error code) to make the validity of the returned pointer obvious. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- drivers/block/rbd.c | 6 ++++-- fs/ceph/super.c | 6 ++++-- include/linux/ceph/libceph.h | 2 +- net/ceph/ceph_common.c | 16 ++++++++-------- 4 files changed, 17 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index b9371f0b953..ed6711e3532 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -371,11 +371,13 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT; - ret = ceph_parse_options(&opt, options, mon_addr, + opt = ceph_parse_options(options, mon_addr, mon_addr + strlen(mon_addr), parse_rbd_opts_token, rbd_opts); - if (ret < 0) + if (IS_ERR(opt)) { + ret = PTR_ERR(opt); goto done_err; + } spin_lock(&node_lock); rbdc = __rbd_client_find(opt); diff --git a/fs/ceph/super.c b/fs/ceph/super.c index c3da3b32bdd..4fab1fdcfa6 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -334,10 +334,12 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt, *path += 2; dout("server path '%s'\n", *path); - err = ceph_parse_options(popt, options, dev_name, dev_name_end, + *popt = ceph_parse_options(options, dev_name, dev_name_end, parse_fsopt_token, (void *)fsopt); - if (err) + if (IS_ERR(*popt)) { + err = PTR_ERR(*popt); goto out; + } /* success */ *pfsopt = fsopt; diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 95bd8502e71..92eef7c3d3c 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -207,7 +207,7 @@ extern struct kmem_cache *ceph_cap_cachep; extern struct kmem_cache *ceph_dentry_cachep; extern struct kmem_cache *ceph_file_cachep; -extern int ceph_parse_options(struct ceph_options **popt, char *options, +extern struct ceph_options *ceph_parse_options(char *options, const char *dev_name, const char *dev_name_end, int (*parse_extra_token)(char *c, void *private), void *private); diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 761ad9d6cc3..621c3221b39 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -277,10 +277,11 @@ out: return err; } -int ceph_parse_options(struct ceph_options **popt, char *options, - const char *dev_name, const char *dev_name_end, - int (*parse_extra_token)(char *c, void *private), - void *private) +struct ceph_options * +ceph_parse_options(char *options, const char *dev_name, + const char *dev_name_end, + int (*parse_extra_token)(char *c, void *private), + void *private) { struct ceph_options *opt; const char *c; @@ -289,7 +290,7 @@ int ceph_parse_options(struct ceph_options **popt, char *options, opt = kzalloc(sizeof(*opt), GFP_KERNEL); if (!opt) - return err; + return ERR_PTR(-ENOMEM); opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr), GFP_KERNEL); if (!opt->mon_addr) @@ -412,12 +413,11 @@ int ceph_parse_options(struct ceph_options **popt, char *options, } /* success */ - *popt = opt; - return 0; + return opt; out: ceph_destroy_options(opt); - return err; + return ERR_PTR(err); } EXPORT_SYMBOL(ceph_parse_options); -- cgit v1.2.3-70-g09d2 From 963be4d7709f84d865f76d12d5b0ec7edad1c498 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 14 Feb 2012 14:05:33 -0600 Subject: libceph: move prepare_write_banner() One of the arguments to prepare_write_connect() indicates whether it is being called immediately after a call to prepare_write_banner(). Move the prepare_write_banner() call inside prepare_write_connect(), and reinterpret (and rename) the "after_banner" argument so it indicates that prepare_write_connect() should *make* the call rather than should know it has already been made. This was split out from the next patch to highlight this change in logic. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 3917847ad8e..0665945b646 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -676,7 +676,7 @@ static void prepare_write_banner(struct ceph_messenger *msgr, static int prepare_write_connect(struct ceph_messenger *msgr, struct ceph_connection *con, - int after_banner) + int include_banner) { unsigned global_seq = get_global_seq(con->msgr, 0); int proto; @@ -705,7 +705,9 @@ static int prepare_write_connect(struct ceph_messenger *msgr, con->out_connect.protocol_version = cpu_to_le32(proto); con->out_connect.flags = 0; - if (!after_banner) { + if (include_banner) + prepare_write_banner(msgr, con); + else { con->out_kvec_left = 0; con->out_kvec_bytes = 0; } @@ -1846,7 +1848,6 @@ more: /* open the socket first? */ if (con->sock == NULL) { - prepare_write_banner(msgr, con); prepare_write_connect(msgr, con, 1); prepare_read_banner(con); set_bit(CONNECTING, &con->state); -- cgit v1.2.3-70-g09d2 From 859eb7994876f26fd9f52d9589fbcab8e2fe8069 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 14 Feb 2012 14:05:33 -0600 Subject: libceph: encapsulate connection kvec operations Encapsulate the operation of adding a new chunk of data to the next open slot in a ceph_connection's out_kvec array. Also add a "reset" operation to make subsequent add operations start at the beginning of the array again. Use these routines throughout, avoiding duplicate code and ensuring all calls are handled consistently. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 117 ++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 61 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0665945b646..04d2b975ab0 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -469,14 +469,35 @@ static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt) return ret; } +static void ceph_con_out_kvec_reset(struct ceph_connection *con) +{ + con->out_kvec_left = 0; + con->out_kvec_bytes = 0; + con->out_kvec_cur = &con->out_kvec[0]; +} + +static void ceph_con_out_kvec_add(struct ceph_connection *con, + size_t size, void *data) +{ + int index; + + index = con->out_kvec_left; + BUG_ON(index >= ARRAY_SIZE(con->out_kvec)); + + con->out_kvec[index].iov_len = size; + con->out_kvec[index].iov_base = data; + con->out_kvec_left++; + con->out_kvec_bytes += size; +} /* * Prepare footer for currently outgoing message, and finish things * off. Assumes out_kvec* are already valid.. we just add on to the end. */ -static void prepare_write_message_footer(struct ceph_connection *con, int v) +static void prepare_write_message_footer(struct ceph_connection *con) { struct ceph_msg *m = con->out_msg; + int v = con->out_kvec_left; dout("prepare_write_message_footer %p\n", con); con->out_kvec_is_msg = true; @@ -494,9 +515,8 @@ static void prepare_write_message_footer(struct ceph_connection *con, int v) static void prepare_write_message(struct ceph_connection *con) { struct ceph_msg *m; - int v = 0; - con->out_kvec_bytes = 0; + ceph_con_out_kvec_reset(con); con->out_kvec_is_msg = true; con->out_msg_done = false; @@ -504,16 +524,13 @@ static void prepare_write_message(struct ceph_connection *con) * TCP packet that's a good thing. */ if (con->in_seq > con->in_seq_acked) { con->in_seq_acked = con->in_seq; - con->out_kvec[v].iov_base = &tag_ack; - con->out_kvec[v++].iov_len = 1; + ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); con->out_temp_ack = cpu_to_le64(con->in_seq_acked); - con->out_kvec[v].iov_base = &con->out_temp_ack; - con->out_kvec[v++].iov_len = sizeof(con->out_temp_ack); - con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack); + ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack), + &con->out_temp_ack); } - m = list_first_entry(&con->out_queue, - struct ceph_msg, list_head); + m = list_first_entry(&con->out_queue, struct ceph_msg, list_head); con->out_msg = m; /* put message on sent list */ @@ -537,17 +554,13 @@ static void prepare_write_message(struct ceph_connection *con) BUG_ON(le32_to_cpu(m->hdr.front_len) != m->front.iov_len); /* tag + hdr + front + middle */ - con->out_kvec[v].iov_base = &tag_msg; - con->out_kvec[v++].iov_len = 1; - con->out_kvec[v].iov_base = &m->hdr; - con->out_kvec[v++].iov_len = sizeof(m->hdr); - con->out_kvec[v++] = m->front; + ceph_con_out_kvec_add(con, sizeof (tag_msg), &tag_msg); + ceph_con_out_kvec_add(con, sizeof (m->hdr), &m->hdr); + ceph_con_out_kvec_add(con, m->front.iov_len, m->front.iov_base); + if (m->middle) - con->out_kvec[v++] = m->middle->vec; - con->out_kvec_left = v; - con->out_kvec_bytes += 1 + sizeof(m->hdr) + m->front.iov_len + - (m->middle ? m->middle->vec.iov_len : 0); - con->out_kvec_cur = con->out_kvec; + ceph_con_out_kvec_add(con, m->middle->vec.iov_len, + m->middle->vec.iov_base); /* fill in crc (except data pages), footer */ con->out_msg->hdr.crc = @@ -580,7 +593,7 @@ static void prepare_write_message(struct ceph_connection *con) con->out_more = 1; /* data + footer will follow */ } else { /* no, queue up footer too and be done */ - prepare_write_message_footer(con, v); + prepare_write_message_footer(con); } set_bit(WRITE_PENDING, &con->state); @@ -595,14 +608,14 @@ static void prepare_write_ack(struct ceph_connection *con) con->in_seq_acked, con->in_seq); con->in_seq_acked = con->in_seq; - con->out_kvec[0].iov_base = &tag_ack; - con->out_kvec[0].iov_len = 1; + ceph_con_out_kvec_reset(con); + + ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); + con->out_temp_ack = cpu_to_le64(con->in_seq_acked); - con->out_kvec[1].iov_base = &con->out_temp_ack; - con->out_kvec[1].iov_len = sizeof(con->out_temp_ack); - con->out_kvec_left = 2; - con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack); - con->out_kvec_cur = con->out_kvec; + ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack), + &con->out_temp_ack); + con->out_more = 1; /* more will follow.. eventually.. */ set_bit(WRITE_PENDING, &con->state); } @@ -613,11 +626,8 @@ static void prepare_write_ack(struct ceph_connection *con) static void prepare_write_keepalive(struct ceph_connection *con) { dout("prepare_write_keepalive %p\n", con); - con->out_kvec[0].iov_base = &tag_keepalive; - con->out_kvec[0].iov_len = 1; - con->out_kvec_left = 1; - con->out_kvec_bytes = 1; - con->out_kvec_cur = con->out_kvec; + ceph_con_out_kvec_reset(con); + ceph_con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive); set_bit(WRITE_PENDING, &con->state); } @@ -646,12 +656,9 @@ static int prepare_connect_authorizer(struct ceph_connection *con) con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol); con->out_connect.authorizer_len = cpu_to_le32(auth_len); - if (auth_len) { - con->out_kvec[con->out_kvec_left].iov_base = auth_buf; - con->out_kvec[con->out_kvec_left].iov_len = auth_len; - con->out_kvec_left++; - con->out_kvec_bytes += auth_len; - } + if (auth_len) + ceph_con_out_kvec_add(con, auth_len, auth_buf); + return 0; } @@ -661,15 +668,11 @@ static int prepare_connect_authorizer(struct ceph_connection *con) static void prepare_write_banner(struct ceph_messenger *msgr, struct ceph_connection *con) { - int len = strlen(CEPH_BANNER); + ceph_con_out_kvec_reset(con); + ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); + ceph_con_out_kvec_add(con, sizeof (msgr->my_enc_addr), + &msgr->my_enc_addr); - con->out_kvec[0].iov_base = CEPH_BANNER; - con->out_kvec[0].iov_len = len; - con->out_kvec[1].iov_base = &msgr->my_enc_addr; - con->out_kvec[1].iov_len = sizeof(msgr->my_enc_addr); - con->out_kvec_left = 2; - con->out_kvec_bytes = len + sizeof(msgr->my_enc_addr); - con->out_kvec_cur = con->out_kvec; con->out_more = 0; set_bit(WRITE_PENDING, &con->state); } @@ -707,22 +710,16 @@ static int prepare_write_connect(struct ceph_messenger *msgr, if (include_banner) prepare_write_banner(msgr, con); - else { - con->out_kvec_left = 0; - con->out_kvec_bytes = 0; - } - con->out_kvec[con->out_kvec_left].iov_base = &con->out_connect; - con->out_kvec[con->out_kvec_left].iov_len = sizeof(con->out_connect); - con->out_kvec_left++; - con->out_kvec_bytes += sizeof(con->out_connect); - con->out_kvec_cur = con->out_kvec; + else + ceph_con_out_kvec_reset(con); + ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); + con->out_more = 0; set_bit(WRITE_PENDING, &con->state); return prepare_connect_authorizer(con); } - /* * write as much of pending kvecs to the socket as we can. * 1 -> done @@ -919,10 +916,8 @@ static int write_partial_msg_pages(struct ceph_connection *con) /* prepare and queue up footer, too */ if (!crc) con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; - con->out_kvec_bytes = 0; - con->out_kvec_left = 0; - con->out_kvec_cur = con->out_kvec; - prepare_write_message_footer(con, 0); + ceph_con_out_kvec_reset(con); + prepare_write_message_footer(con); ret = 1; out: return ret; -- cgit v1.2.3-70-g09d2 From e0f43c9419c1900e5b50de4261e9686a45a0a2b8 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 14 Feb 2012 14:05:33 -0600 Subject: libceph: make ceph_msgr_wq private The messenger workqueue has no need to be public. So give it static scope. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- include/linux/ceph/messenger.h | 2 -- net/ceph/messenger.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 6b5af5f976d..5ca0f824420 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -14,8 +14,6 @@ struct ceph_msg; struct ceph_connection; -extern struct workqueue_struct *ceph_msgr_wq; /* receive work queue */ - /* * Ceph defines these callbacks for handling connection events. */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 04d2b975ab0..31f59ac03d8 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -97,7 +97,7 @@ static void encode_my_addr(struct ceph_messenger *msgr) /* * work queue for all reading and writing to/from the socket. */ -struct workqueue_struct *ceph_msgr_wq; +static struct workqueue_struct *ceph_msgr_wq; int ceph_msgr_init(void) { -- cgit v1.2.3-70-g09d2 From 6173d1f02fb19c0fba02857ae4e1109b5ec95034 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 14 Feb 2012 14:05:33 -0600 Subject: libceph: encapsulate some messenger cleanup code Define a helper function to perform various cleanup operations. Use it both in the exit routine and in the init routine in the event of an error. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 31f59ac03d8..c3023a600ad 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -99,6 +99,20 @@ static void encode_my_addr(struct ceph_messenger *msgr) */ static struct workqueue_struct *ceph_msgr_wq; +void _ceph_msgr_exit(void) +{ + if (ceph_msgr_wq) + destroy_workqueue(ceph_msgr_wq); + + BUG_ON(zero_page_address == NULL); + zero_page_address = NULL; + + BUG_ON(zero_page == NULL); + kunmap(zero_page); + page_cache_release(zero_page); + zero_page = NULL; +} + int ceph_msgr_init(void) { BUG_ON(zero_page != NULL); @@ -109,33 +123,21 @@ int ceph_msgr_init(void) zero_page_address = kmap(zero_page); ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0); - if (!ceph_msgr_wq) { - pr_err("msgr_init failed to create workqueue\n"); - - zero_page_address = NULL; - kunmap(zero_page); - page_cache_release(zero_page); - zero_page = NULL; + if (ceph_msgr_wq) + return 0; - return -ENOMEM; - } + pr_err("msgr_init failed to create workqueue\n"); + _ceph_msgr_exit(); - return 0; + return -ENOMEM; } EXPORT_SYMBOL(ceph_msgr_init); void ceph_msgr_exit(void) { BUG_ON(ceph_msgr_wq == NULL); - destroy_workqueue(ceph_msgr_wq); - BUG_ON(zero_page_address == NULL); - zero_page_address = NULL; - - BUG_ON(zero_page == NULL); - kunmap(zero_page); - page_cache_release(zero_page); - zero_page = NULL; + _ceph_msgr_exit(); } EXPORT_SYMBOL(ceph_msgr_exit); -- cgit v1.2.3-70-g09d2 From 41617d0c9c9832e030667277ddf6b4ffb4ecdc90 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 14 Feb 2012 14:05:33 -0600 Subject: libceph: make ceph_tcp_connect() return int There is no real need for ceph_tcp_connect() to return the socket pointer it creates, since it already assigns it to con->sock, which is visible to the caller. Instead, have it return an error code, which tidies things up a bit. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index c3023a600ad..e1e53bb2d0c 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -240,7 +240,7 @@ static void set_sock_callbacks(struct socket *sock, /* * initiate connection to a remote socket. */ -static struct socket *ceph_tcp_connect(struct ceph_connection *con) +static int ceph_tcp_connect(struct ceph_connection *con) { struct sockaddr_storage *paddr = &con->peer_addr.in_addr; struct socket *sock; @@ -250,7 +250,7 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con) ret = sock_create_kern(con->peer_addr.in_addr.ss_family, SOCK_STREAM, IPPROTO_TCP, &sock); if (ret) - return ERR_PTR(ret); + return ret; sock->sk->sk_allocation = GFP_NOFS; #ifdef CONFIG_LOCKDEP @@ -273,11 +273,11 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con) sock_release(sock); con->error_msg = "connect error"; - return ERR_PTR(ret); + return ret; } con->sock = sock; - return sock; + return 0; } static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len) @@ -1854,11 +1854,9 @@ more: con->in_tag = CEPH_MSGR_TAG_READY; dout("try_write initiating connect on %p new state %lu\n", con, con->state); - con->sock = ceph_tcp_connect(con); - if (IS_ERR(con->sock)) { - con->sock = NULL; + ret = ceph_tcp_connect(con); + if (ret < 0) { con->error_msg = "connect error"; - ret = -1; goto out; } } -- cgit v1.2.3-70-g09d2 From d3002b974cefbb7c1e325cc296966f768ff76b06 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 14 Feb 2012 14:05:33 -0600 Subject: libceph: a few small changes This gathers a number of very minor changes: - use %hu when formatting the a socket address's address family - null out the ceph_msgr_wq pointer after the queue has been destroyed - drop a needless cast in ceph_write_space() - add a WARN() call in ceph_state_change() in the event an unrecognized socket state is encountered - rearrange the logic in ceph_con_get() and ceph_con_put() so that: - the reference counts are only atomically read once - the values displayed via dout() calls are known to be meaningful at the time they are formatted Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index e1e53bb2d0c..44d8c77cabd 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -80,8 +80,8 @@ const char *ceph_pr_addr(const struct sockaddr_storage *ss) break; default: - snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %d)", - (int)ss->ss_family); + snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %hu)", + ss->ss_family); } return s; @@ -101,8 +101,10 @@ static struct workqueue_struct *ceph_msgr_wq; void _ceph_msgr_exit(void) { - if (ceph_msgr_wq) + if (ceph_msgr_wq) { destroy_workqueue(ceph_msgr_wq); + ceph_msgr_wq = NULL; + } BUG_ON(zero_page_address == NULL); zero_page_address = NULL; @@ -167,8 +169,7 @@ static void ceph_data_ready(struct sock *sk, int count_unused) /* socket has buffer space for writing */ static void ceph_write_space(struct sock *sk) { - struct ceph_connection *con = - (struct ceph_connection *)sk->sk_user_data; + struct ceph_connection *con = sk->sk_user_data; /* only queue to workqueue if there is data we want to write, * and there is sufficient space in the socket buffer to accept @@ -216,6 +217,8 @@ static void ceph_state_change(struct sock *sk) dout("ceph_state_change TCP_ESTABLISHED\n"); queue_con(con); break; + default: /* Everything else is uninteresting */ + break; } } @@ -420,22 +423,23 @@ bool ceph_con_opened(struct ceph_connection *con) */ struct ceph_connection *ceph_con_get(struct ceph_connection *con) { - dout("con_get %p nref = %d -> %d\n", con, - atomic_read(&con->nref), atomic_read(&con->nref) + 1); - if (atomic_inc_not_zero(&con->nref)) - return con; - return NULL; + int nref = __atomic_add_unless(&con->nref, 1, 0); + + dout("con_get %p nref = %d -> %d\n", con, nref, nref + 1); + + return nref ? con : NULL; } void ceph_con_put(struct ceph_connection *con) { - dout("con_put %p nref = %d -> %d\n", con, - atomic_read(&con->nref), atomic_read(&con->nref) - 1); - BUG_ON(atomic_read(&con->nref) == 0); - if (atomic_dec_and_test(&con->nref)) { + int nref = atomic_dec_return(&con->nref); + + BUG_ON(nref < 0); + if (nref == 0) { BUG_ON(con->sock); kfree(con); } + dout("con_put %p nref = %d -> %d\n", con, nref + 1, nref); } /* -- cgit v1.2.3-70-g09d2 From cffaba15cd95d4a16eb5a6aa5c22a79f67d555ab Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 15 Feb 2012 07:43:54 -0600 Subject: ceph: ensure Boolean options support both senses Many ceph-related Boolean options offer the ability to both enable and disable a feature. For all those that don't offer this, add a new option so that they do. Note that ceph_show_options()--which reports mount options currently in effect--only reports the option if it is different from the default value. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- fs/ceph/super.c | 10 ++++++++++ net/ceph/ceph_common.c | 10 ++++++++++ 2 files changed, 20 insertions(+) (limited to 'net') diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 4fab1fdcfa6..3663cf0cb07 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -130,10 +130,12 @@ enum { Opt_nodirstat, Opt_rbytes, Opt_norbytes, + Opt_asyncreaddir, Opt_noasyncreaddir, Opt_dcache, Opt_nodcache, Opt_ino32, + Opt_noino32, }; static match_table_t fsopt_tokens = { @@ -153,10 +155,12 @@ static match_table_t fsopt_tokens = { {Opt_nodirstat, "nodirstat"}, {Opt_rbytes, "rbytes"}, {Opt_norbytes, "norbytes"}, + {Opt_asyncreaddir, "asyncreaddir"}, {Opt_noasyncreaddir, "noasyncreaddir"}, {Opt_dcache, "dcache"}, {Opt_nodcache, "nodcache"}, {Opt_ino32, "ino32"}, + {Opt_noino32, "noino32"}, {-1, NULL} }; @@ -232,6 +236,9 @@ static int parse_fsopt_token(char *c, void *private) case Opt_norbytes: fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES; break; + case Opt_asyncreaddir: + fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR; + break; case Opt_noasyncreaddir: fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR; break; @@ -244,6 +251,9 @@ static int parse_fsopt_token(char *c, void *private) case Opt_ino32: fsopt->flags |= CEPH_MOUNT_OPT_INO32; break; + case Opt_noino32: + fsopt->flags &= ~CEPH_MOUNT_OPT_INO32; + break; default: BUG_ON(token); } diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 621c3221b39..cc913193d99 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -201,7 +201,9 @@ enum { Opt_ip, Opt_last_string, /* string args above */ + Opt_share, Opt_noshare, + Opt_crc, Opt_nocrc, }; @@ -217,7 +219,9 @@ static match_table_t opt_tokens = { {Opt_key, "key=%s"}, {Opt_ip, "ip=%s"}, /* string args above */ + {Opt_share, "share"}, {Opt_noshare, "noshare"}, + {Opt_crc, "crc"}, {Opt_nocrc, "nocrc"}, {-1, NULL} }; @@ -399,10 +403,16 @@ ceph_parse_options(char *options, const char *dev_name, opt->mount_timeout = intval; break; + case Opt_share: + opt->flags &= ~CEPH_OPT_NOSHARE; + break; case Opt_noshare: opt->flags |= CEPH_OPT_NOSHARE; break; + case Opt_crc: + opt->flags &= ~CEPH_OPT_NOCRC; + break; case Opt_nocrc: opt->flags |= CEPH_OPT_NOCRC; break; -- cgit v1.2.3-70-g09d2 From bca064d236a2e3162a07c758855221bcbe3c475b Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 15 Feb 2012 07:43:54 -0600 Subject: libceph: use "do" in CRC-related Boolean variables Change the name (and type) of a few CRC-related Boolean local variables so they contain the word "do", to distingish their purpose from variables used for holding an actual CRC value. Note that in the process of doing this I identified a fairly serious logic error in write_partial_msg_pages(): the value of "do_crc" assigned appears to be the opposite of what it should be. No attempt to fix this is made here; this change preserves the erroneous behavior. The problem I found is documented here: http://tracker.newdream.net/issues/2064 Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- include/linux/ceph/messenger.h | 2 +- net/ceph/messenger.c | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 5ca0f824420..3bff047f6b0 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -98,7 +98,7 @@ struct ceph_msg { struct ceph_msg_pos { int page, page_pos; /* which page; offset in page */ int data_pos; /* offset in data payload */ - int did_page_crc; /* true if we've calculated crc for current page */ + bool did_page_crc; /* true if we've calculated crc for current page */ }; /* ceph connection fault delay defaults, for exponential backoff */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 44d8c77cabd..204e229e662 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -595,7 +595,7 @@ static void prepare_write_message(struct ceph_connection *con) else con->out_msg_pos.page_pos = 0; con->out_msg_pos.data_pos = 0; - con->out_msg_pos.did_page_crc = 0; + con->out_msg_pos.did_page_crc = false; con->out_more = 1; /* data + footer will follow */ } else { /* no, queue up footer too and be done */ @@ -805,7 +805,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) struct ceph_msg *msg = con->out_msg; unsigned data_len = le32_to_cpu(msg->hdr.data_len); size_t len; - int crc = con->msgr->nocrc; + bool do_crc = con->msgr->nocrc; int ret; int total_max_write; int in_trail = 0; @@ -843,17 +843,17 @@ static int write_partial_msg_pages(struct ceph_connection *con) page = list_first_entry(&msg->trail->head, struct page, lru); - if (crc) + if (do_crc) kaddr = kmap(page); max_write = PAGE_SIZE; } else if (msg->pages) { page = msg->pages[con->out_msg_pos.page]; - if (crc) + if (do_crc) kaddr = kmap(page); } else if (msg->pagelist) { page = list_first_entry(&msg->pagelist->head, struct page, lru); - if (crc) + if (do_crc) kaddr = kmap(page); #ifdef CONFIG_BLOCK } else if (msg->bio) { @@ -862,26 +862,26 @@ static int write_partial_msg_pages(struct ceph_connection *con) bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg); page = bv->bv_page; page_shift = bv->bv_offset; - if (crc) + if (do_crc) kaddr = kmap(page) + page_shift; max_write = bv->bv_len; #endif } else { page = zero_page; - if (crc) + if (do_crc) kaddr = zero_page_address; } len = min_t(int, max_write - con->out_msg_pos.page_pos, total_max_write); - if (crc && !con->out_msg_pos.did_page_crc) { + if (do_crc && !con->out_msg_pos.did_page_crc) { void *base = kaddr + con->out_msg_pos.page_pos; u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc); BUG_ON(kaddr == NULL); con->out_msg->footer.data_crc = cpu_to_le32(crc32c(tmpcrc, base, len)); - con->out_msg_pos.did_page_crc = 1; + con->out_msg_pos.did_page_crc = true; } ret = kernel_sendpage(con->sock, page, con->out_msg_pos.page_pos + page_shift, @@ -889,7 +889,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) MSG_DONTWAIT | MSG_NOSIGNAL | MSG_MORE); - if (crc && + if (do_crc && (msg->pages || msg->pagelist || msg->bio || in_trail)) kunmap(page); @@ -903,7 +903,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) if (ret == len) { con->out_msg_pos.page_pos = 0; con->out_msg_pos.page++; - con->out_msg_pos.did_page_crc = 0; + con->out_msg_pos.did_page_crc = false; if (in_trail) list_move_tail(&page->lru, &msg->trail->head); @@ -920,7 +920,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) dout("write_partial_msg_pages %p msg %p done\n", con, msg); /* prepare and queue up footer, too */ - if (!crc) + if (!do_crc) con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; ceph_con_out_kvec_reset(con); prepare_write_message_footer(con); @@ -1557,7 +1557,7 @@ static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con, static int read_partial_message_pages(struct ceph_connection *con, struct page **pages, - unsigned data_len, int datacrc) + unsigned data_len, bool do_datacrc) { void *p; int ret; @@ -1570,7 +1570,7 @@ static int read_partial_message_pages(struct ceph_connection *con, p = kmap(pages[con->in_msg_pos.page]); ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos, left); - if (ret > 0 && datacrc) + if (ret > 0 && do_datacrc) con->in_data_crc = crc32c(con->in_data_crc, p + con->in_msg_pos.page_pos, ret); @@ -1590,7 +1590,7 @@ static int read_partial_message_pages(struct ceph_connection *con, #ifdef CONFIG_BLOCK static int read_partial_message_bio(struct ceph_connection *con, struct bio **bio_iter, int *bio_seg, - unsigned data_len, int datacrc) + unsigned data_len, bool do_datacrc) { struct bio_vec *bv = bio_iovec_idx(*bio_iter, *bio_seg); void *p; @@ -1606,7 +1606,7 @@ static int read_partial_message_bio(struct ceph_connection *con, ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos, left); - if (ret > 0 && datacrc) + if (ret > 0 && do_datacrc) con->in_data_crc = crc32c(con->in_data_crc, p + con->in_msg_pos.page_pos, ret); @@ -1633,7 +1633,7 @@ static int read_partial_message(struct ceph_connection *con) int ret; int to, left; unsigned front_len, middle_len, data_len; - int datacrc = con->msgr->nocrc; + bool do_datacrc = con->msgr->nocrc; int skip; u64 seq; @@ -1744,7 +1744,7 @@ static int read_partial_message(struct ceph_connection *con) while (con->in_msg_pos.data_pos < data_len) { if (m->pages) { ret = read_partial_message_pages(con, m->pages, - data_len, datacrc); + data_len, do_datacrc); if (ret <= 0) return ret; #ifdef CONFIG_BLOCK @@ -1752,7 +1752,7 @@ static int read_partial_message(struct ceph_connection *con) ret = read_partial_message_bio(con, &m->bio_iter, &m->bio_seg, - data_len, datacrc); + data_len, do_datacrc); if (ret <= 0) return ret; #endif @@ -1787,7 +1787,7 @@ static int read_partial_message(struct ceph_connection *con) m, con->in_middle_crc, m->footer.middle_crc); return -EBADMSG; } - if (datacrc && + if (do_datacrc && (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 && con->in_data_crc != le32_to_cpu(m->footer.data_crc)) { pr_err("read_partial_message %p data crc %u != exp. %u\n", m, -- cgit v1.2.3-70-g09d2 From a9a0c51af4e7c825c014b40694571456a75ebbc4 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 15 Feb 2012 07:43:54 -0600 Subject: libceph: separate CRC calculation from byte swapping Calculate CRC in a separate step from rearranging the byte order of the result, to improve clarity and readability. Use offsetof() to determine the number of bytes to include in the CRC calculation. In read_partial_message(), switch which value gets byte-swapped, since the just-computed CRC is already likely to be in a register. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 204e229e662..7ec6a228b66 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -521,6 +521,7 @@ static void prepare_write_message_footer(struct ceph_connection *con) static void prepare_write_message(struct ceph_connection *con) { struct ceph_msg *m; + u32 crc; ceph_con_out_kvec_reset(con); con->out_kvec_is_msg = true; @@ -569,17 +570,17 @@ static void prepare_write_message(struct ceph_connection *con) m->middle->vec.iov_base); /* fill in crc (except data pages), footer */ - con->out_msg->hdr.crc = - cpu_to_le32(crc32c(0, &m->hdr, - sizeof(m->hdr) - sizeof(m->hdr.crc))); + crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc)); + con->out_msg->hdr.crc = cpu_to_le32(crc); con->out_msg->footer.flags = CEPH_MSG_FOOTER_COMPLETE; - con->out_msg->footer.front_crc = - cpu_to_le32(crc32c(0, m->front.iov_base, m->front.iov_len)); - if (m->middle) - con->out_msg->footer.middle_crc = - cpu_to_le32(crc32c(0, m->middle->vec.iov_base, - m->middle->vec.iov_len)); - else + + crc = crc32c(0, m->front.iov_base, m->front.iov_len); + con->out_msg->footer.front_crc = cpu_to_le32(crc); + if (m->middle) { + crc = crc32c(0, m->middle->vec.iov_base, + m->middle->vec.iov_len); + con->out_msg->footer.middle_crc = cpu_to_le32(crc); + } else con->out_msg->footer.middle_crc = 0; con->out_msg->footer.data_crc = 0; dout("prepare_write_message front_crc %u data_crc %u\n", @@ -875,12 +876,13 @@ static int write_partial_msg_pages(struct ceph_connection *con) total_max_write); if (do_crc && !con->out_msg_pos.did_page_crc) { + u32 crc; void *base = kaddr + con->out_msg_pos.page_pos; u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc); BUG_ON(kaddr == NULL); - con->out_msg->footer.data_crc = - cpu_to_le32(crc32c(tmpcrc, base, len)); + crc = crc32c(tmpcrc, base, len); + con->out_msg->footer.data_crc = cpu_to_le32(crc); con->out_msg_pos.did_page_crc = true; } ret = kernel_sendpage(con->sock, page, @@ -1650,8 +1652,9 @@ static int read_partial_message(struct ceph_connection *con) con->in_base_pos += ret; if (con->in_base_pos == sizeof(con->in_hdr)) { u32 crc = crc32c(0, &con->in_hdr, - sizeof(con->in_hdr) - sizeof(con->in_hdr.crc)); - if (crc != le32_to_cpu(con->in_hdr.crc)) { + offsetof(struct ceph_msg_header, crc)); + + if (cpu_to_le32(crc) != con->in_hdr.crc) { pr_err("read_partial_message bad hdr " " crc %u != expected %u\n", crc, con->in_hdr.crc); -- cgit v1.2.3-70-g09d2 From fe3ad593e2c34457ffa6233014ab19f4d36f85f2 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 15 Feb 2012 07:43:54 -0600 Subject: libceph: do crc calculations outside loop Move blocks of code out of loops in read_partial_message_section() and read_partial_message(). They were only was getting called at the end of the last iteration of the loop anyway. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 7ec6a228b66..575511a29eb 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1544,10 +1544,9 @@ static int read_partial_message_section(struct ceph_connection *con, if (ret <= 0) return ret; section->iov_len += ret; - if (section->iov_len == sec_len) - *crc = crc32c(0, section->iov_base, - section->iov_len); } + if (section->iov_len == sec_len) + *crc = crc32c(0, section->iov_base, section->iov_len); return 1; } @@ -1638,6 +1637,7 @@ static int read_partial_message(struct ceph_connection *con) bool do_datacrc = con->msgr->nocrc; int skip; u64 seq; + u32 crc; dout("read_partial_message con %p msg %p\n", con, m); @@ -1650,18 +1650,16 @@ static int read_partial_message(struct ceph_connection *con) if (ret <= 0) return ret; con->in_base_pos += ret; - if (con->in_base_pos == sizeof(con->in_hdr)) { - u32 crc = crc32c(0, &con->in_hdr, - offsetof(struct ceph_msg_header, crc)); - - if (cpu_to_le32(crc) != con->in_hdr.crc) { - pr_err("read_partial_message bad hdr " - " crc %u != expected %u\n", - crc, con->in_hdr.crc); - return -EBADMSG; - } - } } + + crc = crc32c(0, &con->in_hdr, offsetof(struct ceph_msg_header, crc)); + if (cpu_to_le32(crc) != con->in_hdr.crc) { + pr_err("read_partial_message bad hdr " + " crc %u != expected %u\n", + crc, con->in_hdr.crc); + return -EBADMSG; + } + front_len = le32_to_cpu(con->in_hdr.front_len); if (front_len > CEPH_MSG_MAX_FRONT_LEN) return -EIO; -- cgit v1.2.3-70-g09d2 From f42299e6c3883c69c14079b8c88fe33815b2dcc3 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 15 Feb 2012 07:43:54 -0600 Subject: libceph: small refactor in write_partial_kvec() Make a small change in the code that counts down kvecs consumed by a ceph_tcp_sendmsg() call. Same functionality, just blocked out a little differently. Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 575511a29eb..e8f236e87f3 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -747,17 +747,18 @@ static int write_partial_kvec(struct ceph_connection *con) con->out_kvec_bytes -= ret; if (con->out_kvec_bytes == 0) break; /* done */ - while (ret > 0) { - if (ret >= con->out_kvec_cur->iov_len) { - ret -= con->out_kvec_cur->iov_len; - con->out_kvec_cur++; - con->out_kvec_left--; - } else { - con->out_kvec_cur->iov_len -= ret; - con->out_kvec_cur->iov_base += ret; - ret = 0; - break; - } + + /* account for full iov entries consumed */ + while (ret >= con->out_kvec_cur->iov_len) { + BUG_ON(!con->out_kvec_left); + ret -= con->out_kvec_cur->iov_len; + con->out_kvec_cur++; + con->out_kvec_left--; + } + /* and for a partially-consumed entry */ + if (ret) { + con->out_kvec_cur->iov_len -= ret; + con->out_kvec_cur->iov_base += ret; } } con->out_kvec_left = 0; -- cgit v1.2.3-70-g09d2 From 84495f496170a73ed79667b7fbf91947b7f47c87 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 15 Feb 2012 07:43:55 -0600 Subject: libceph: some simple changes Nothing too big here. - define the size of the buffer used for consuming ignored incoming data using a symbolic constant - simplify the condition determining whether to unmap the page in write_partial_msg_pages(): do it for crc but not if the page is the zero page Signed-off-by: Alex Elder Signed-off-by: Sage Weil --- net/ceph/messenger.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index e8f236e87f3..1a22975945d 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -38,6 +38,11 @@ static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE; static struct lock_class_key socket_class; #endif +/* + * When skipping (ignoring) a block of input we read it into a "skip + * buffer," which is this many bytes in size. + */ +#define SKIP_BUF_SIZE 1024 static void queue_con(struct ceph_connection *con); static void con_work(struct work_struct *); @@ -892,8 +897,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) MSG_DONTWAIT | MSG_NOSIGNAL | MSG_MORE); - if (do_crc && - (msg->pages || msg->pagelist || msg->bio || in_trail)) + if (do_crc && kaddr != zero_page_address) kunmap(page); if (ret == -EAGAIN) @@ -1982,8 +1986,9 @@ more: * * FIXME: there must be a better way to do this! */ - static char buf[1024]; - int skip = min(1024, -con->in_base_pos); + static char buf[SKIP_BUF_SIZE]; + int skip = min((int) sizeof (buf), -con->in_base_pos); + dout("skipping %d / %d bytes\n", skip, -con->in_base_pos); ret = ceph_tcp_recvmsg(con->sock, buf, skip); if (ret <= 0) -- cgit v1.2.3-70-g09d2 From 37675b0f42a8f7699c3602350d1c3b2a1698a3d3 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 7 Mar 2012 11:40:08 -0600 Subject: libceph: fix inverted crc option logic CRC's are computed for all messages between ceph entities. The CRC computation for the data portion of message can optionally be disabled using the "nocrc" (common) ceph option. The default is for CRC computation for the data portion to be enabled. Unfortunately, the code that implements this feature interprets the feature flag wrong, meaning that by default the CRC's have *not* been computed (or checked) for the data portion of messages unless the "nocrc" option was supplied. Fix this, in write_partial_msg_pages() and read_partial_message(). Also change the flag variable in write_partial_msg_pages() to be "no_datacrc" to match the usage elsewhere in the file. This fixes http://tracker.newdream.net/issues/2064 Signed-off-by: Alex Elder Reviewed-by: Sage Weil --- net/ceph/messenger.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 1a22975945d..589b7689d31 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -812,7 +812,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) struct ceph_msg *msg = con->out_msg; unsigned data_len = le32_to_cpu(msg->hdr.data_len); size_t len; - bool do_crc = con->msgr->nocrc; + bool do_datacrc = !con->msgr->nocrc; int ret; int total_max_write; int in_trail = 0; @@ -850,17 +850,17 @@ static int write_partial_msg_pages(struct ceph_connection *con) page = list_first_entry(&msg->trail->head, struct page, lru); - if (do_crc) + if (do_datacrc) kaddr = kmap(page); max_write = PAGE_SIZE; } else if (msg->pages) { page = msg->pages[con->out_msg_pos.page]; - if (do_crc) + if (do_datacrc) kaddr = kmap(page); } else if (msg->pagelist) { page = list_first_entry(&msg->pagelist->head, struct page, lru); - if (do_crc) + if (do_datacrc) kaddr = kmap(page); #ifdef CONFIG_BLOCK } else if (msg->bio) { @@ -869,19 +869,19 @@ static int write_partial_msg_pages(struct ceph_connection *con) bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg); page = bv->bv_page; page_shift = bv->bv_offset; - if (do_crc) + if (do_datacrc) kaddr = kmap(page) + page_shift; max_write = bv->bv_len; #endif } else { page = zero_page; - if (do_crc) + if (do_datacrc) kaddr = zero_page_address; } len = min_t(int, max_write - con->out_msg_pos.page_pos, total_max_write); - if (do_crc && !con->out_msg_pos.did_page_crc) { + if (do_datacrc && !con->out_msg_pos.did_page_crc) { u32 crc; void *base = kaddr + con->out_msg_pos.page_pos; u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc); @@ -897,7 +897,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) MSG_DONTWAIT | MSG_NOSIGNAL | MSG_MORE); - if (do_crc && kaddr != zero_page_address) + if (do_datacrc && kaddr != zero_page_address) kunmap(page); if (ret == -EAGAIN) @@ -927,7 +927,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) dout("write_partial_msg_pages %p msg %p done\n", con, msg); /* prepare and queue up footer, too */ - if (!do_crc) + if (!do_datacrc) con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; ceph_con_out_kvec_reset(con); prepare_write_message_footer(con); @@ -1639,7 +1639,7 @@ static int read_partial_message(struct ceph_connection *con) int ret; int to, left; unsigned front_len, middle_len, data_len; - bool do_datacrc = con->msgr->nocrc; + bool do_datacrc = !con->msgr->nocrc; int skip; u64 seq; u32 crc; -- cgit v1.2.3-70-g09d2 From 31739139f3ed7be802dd9019ec8d8cc910e3d241 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 7 Mar 2012 11:40:08 -0600 Subject: libceph: use kernel_sendpage() for sending zeroes If a message queued for send gets revoked, zeroes are sent over the wire instead of any unsent data. This is done by constructing a message and passing it to kernel_sendmsg() via ceph_tcp_sendmsg(). Since we are already working with a page in this case we can use the sendpage interface instead. Create a new ceph_tcp_sendpage() helper that sets up flags to match the way ceph_tcp_sendmsg() does now. Signed-off-by: Alex Elder Reviewed-by: Sage Weil --- net/ceph/messenger.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 589b7689d31..9207a8c0b21 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -321,6 +321,19 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov, return r; } +static int ceph_tcp_sendpage(struct socket *sock, struct page *page, + int offset, size_t size, int more) +{ + int flags = MSG_DONTWAIT | MSG_NOSIGNAL | (more ? MSG_MORE : MSG_EOR); + int ret; + + ret = kernel_sendpage(sock, page, offset, size, flags); + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + /* * Shutdown/close the socket for the given connection. @@ -944,12 +957,9 @@ static int write_partial_skip(struct ceph_connection *con) int ret; while (con->out_skip > 0) { - struct kvec iov = { - .iov_base = zero_page_address, - .iov_len = min(con->out_skip, (int)PAGE_CACHE_SIZE) - }; + size_t size = min(con->out_skip, (int) PAGE_CACHE_SIZE); - ret = ceph_tcp_sendmsg(con->sock, &iov, 1, iov.iov_len, 1); + ret = ceph_tcp_sendpage(con->sock, zero_page, 0, size, 1); if (ret <= 0) goto out; con->out_skip -= ret; -- cgit v1.2.3-70-g09d2 From e36b13cceb46136d849aeee06b4907ad3570ba78 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 7 Mar 2012 11:40:08 -0600 Subject: libceph: only call kernel_sendpage() via helper Make ceph_tcp_sendpage() be the only place kernel_sendpage() is used, by using this helper in write_partial_msg_pages(). Signed-off-by: Alex Elder Reviewed-by: Sage Weil --- net/ceph/messenger.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 9207a8c0b21..adca1e6537a 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -904,17 +904,13 @@ static int write_partial_msg_pages(struct ceph_connection *con) con->out_msg->footer.data_crc = cpu_to_le32(crc); con->out_msg_pos.did_page_crc = true; } - ret = kernel_sendpage(con->sock, page, + ret = ceph_tcp_sendpage(con->sock, page, con->out_msg_pos.page_pos + page_shift, - len, - MSG_DONTWAIT | MSG_NOSIGNAL | - MSG_MORE); + len, 1); if (do_datacrc && kaddr != zero_page_address) kunmap(page); - if (ret == -EAGAIN) - ret = 0; if (ret <= 0) goto out; -- cgit v1.2.3-70-g09d2 From 0cdf9e60189a87356a865a96dbafc2240af5c91d Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 7 Mar 2012 11:40:08 -0600 Subject: libceph: get rid of zero_page_address There's not a lot of benefit to zero_page_address, which basically holds a mapping of the zero page through the life of the messenger module. Even with our own mapping, the sendpage interface where it's used may need to kmap() it again. It's almost certain to be in low memory anyway. So stop treating the zero page specially in write_partial_msg_pages() and just get rid of zero_page_address entirely. Signed-off-by: Alex Elder Reviewed-by: Sage Weil --- net/ceph/messenger.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index adca1e6537a..4f1714c4c93 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -61,7 +61,6 @@ static char addr_str[ADDR_STR_COUNT][MAX_ADDR_STR_LEN]; static atomic_t addr_str_seq = ATOMIC_INIT(0); static struct page *zero_page; /* used in certain error cases */ -static void *zero_page_address; /* kernel virtual addr of zero_page */ const char *ceph_pr_addr(const struct sockaddr_storage *ss) { @@ -111,9 +110,6 @@ void _ceph_msgr_exit(void) ceph_msgr_wq = NULL; } - BUG_ON(zero_page_address == NULL); - zero_page_address = NULL; - BUG_ON(zero_page == NULL); kunmap(zero_page); page_cache_release(zero_page); @@ -126,9 +122,6 @@ int ceph_msgr_init(void) zero_page = ZERO_PAGE(0); page_cache_get(zero_page); - BUG_ON(zero_page_address != NULL); - zero_page_address = kmap(zero_page); - ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0); if (ceph_msgr_wq) return 0; @@ -889,7 +882,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) } else { page = zero_page; if (do_datacrc) - kaddr = zero_page_address; + kaddr = kmap(page); } len = min_t(int, max_write - con->out_msg_pos.page_pos, total_max_write); @@ -908,7 +901,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) con->out_msg_pos.page_pos + page_shift, len, 1); - if (do_datacrc && kaddr != zero_page_address) + if (do_datacrc) kunmap(page); if (ret <= 0) -- cgit v1.2.3-70-g09d2 From 9bd1966344bf975b5ce65e80fd6bacc41b4325a8 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 7 Mar 2012 11:40:08 -0600 Subject: libceph: rename "page_shift" variable to something sensible In write_partial_msg_pages() there is a local variable used to track the starting offset within a bio segment to use. Its name, "page_shift" defies the Linux convention of using that name for log-base-2(page size). Since it's only used in the bio case rename it "bio_offset". Use it along with the page_pos field to compute the memory offset when computing CRC's in that function. This makes the bio case match the others more closely. Signed-off-by: Alex Elder Reviewed-by: Sage Weil --- net/ceph/messenger.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 4f1714c4c93..2bf9ab4429e 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -837,7 +837,7 @@ static int write_partial_msg_pages(struct ceph_connection *con) struct page *page = NULL; void *kaddr = NULL; int max_write = PAGE_SIZE; - int page_shift = 0; + int bio_offset = 0; total_max_write = data_len - trail_len - con->out_msg_pos.data_pos; @@ -874,9 +874,9 @@ static int write_partial_msg_pages(struct ceph_connection *con) bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg); page = bv->bv_page; - page_shift = bv->bv_offset; + bio_offset = bv->bv_offset; if (do_datacrc) - kaddr = kmap(page) + page_shift; + kaddr = kmap(page); max_write = bv->bv_len; #endif } else { @@ -888,17 +888,18 @@ static int write_partial_msg_pages(struct ceph_connection *con) total_max_write); if (do_datacrc && !con->out_msg_pos.did_page_crc) { + void *base; u32 crc; - void *base = kaddr + con->out_msg_pos.page_pos; u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc); BUG_ON(kaddr == NULL); + base = kaddr + con->out_msg_pos.page_pos + bio_offset; crc = crc32c(tmpcrc, base, len); con->out_msg->footer.data_crc = cpu_to_le32(crc); con->out_msg_pos.did_page_crc = true; } ret = ceph_tcp_sendpage(con->sock, page, - con->out_msg_pos.page_pos + page_shift, + con->out_msg_pos.page_pos + bio_offset, len, 1); if (do_datacrc) -- cgit v1.2.3-70-g09d2 From 8d63e318c4eb1bea6f7e3cb4b77849eaa167bfec Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 7 Mar 2012 11:40:08 -0600 Subject: libceph: isolate kmap() call in write_partial_msg_pages() In write_partial_msg_pages(), every case now does an identical call to kmap(page). Instead, just call it once inside the CRC-computing block where it's needed. Move the definition of kaddr inside that block, and make it a (char *) to ensure portable pointer arithmetic. We still don't kunmap() it until after the sendpage() call, in case that also ends up needing to use the mapping. Signed-off-by: Alex Elder Reviewed-by: Sage Weil --- net/ceph/messenger.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 2bf9ab4429e..f0993af2ae4 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -835,7 +835,6 @@ static int write_partial_msg_pages(struct ceph_connection *con) while (data_len > con->out_msg_pos.data_pos) { struct page *page = NULL; - void *kaddr = NULL; int max_write = PAGE_SIZE; int bio_offset = 0; @@ -856,18 +855,12 @@ static int write_partial_msg_pages(struct ceph_connection *con) page = list_first_entry(&msg->trail->head, struct page, lru); - if (do_datacrc) - kaddr = kmap(page); max_write = PAGE_SIZE; } else if (msg->pages) { page = msg->pages[con->out_msg_pos.page]; - if (do_datacrc) - kaddr = kmap(page); } else if (msg->pagelist) { page = list_first_entry(&msg->pagelist->head, struct page, lru); - if (do_datacrc) - kaddr = kmap(page); #ifdef CONFIG_BLOCK } else if (msg->bio) { struct bio_vec *bv; @@ -875,14 +868,10 @@ static int write_partial_msg_pages(struct ceph_connection *con) bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg); page = bv->bv_page; bio_offset = bv->bv_offset; - if (do_datacrc) - kaddr = kmap(page); max_write = bv->bv_len; #endif } else { page = zero_page; - if (do_datacrc) - kaddr = kmap(page); } len = min_t(int, max_write - con->out_msg_pos.page_pos, total_max_write); @@ -891,7 +880,9 @@ static int write_partial_msg_pages(struct ceph_connection *con) void *base; u32 crc; u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc); + char *kaddr; + kaddr = kmap(page); BUG_ON(kaddr == NULL); base = kaddr + con->out_msg_pos.page_pos + bio_offset; crc = crc32c(tmpcrc, base, len); -- cgit v1.2.3-70-g09d2 From 64b5fad526f63e9b56752a7e8e153b99ec0ddecd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 21 Mar 2012 20:41:01 +0000 Subject: netlabel: use GFP flags from caller instead of GFP_ATOMIC This function takes a GFP flags as a parameter, but they are never used. We don't take a lock in this function so there is no reason to prefer GFP_ATOMIC over the caller's GFP flags. There is only one caller, cipso_v4_map_cat_rng_ntoh(), and it passes GFP_ATOMIC as the GFP flags so this doesn't change how the code works. It's just a cleanup. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/netlabel/netlabel_kapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 2560e7b441c..7c94aedd091 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -597,7 +597,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, iter = iter->next; iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; } - ret_val = netlbl_secattr_catmap_setbit(iter, spot, GFP_ATOMIC); + ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags); } return ret_val; -- cgit v1.2.3-70-g09d2 From f0229eaaf3f82522e2b16b41b0f45bb84a88d1b0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 21 Mar 2012 20:44:09 +0000 Subject: RDS: use gfp flags from caller in conn_alloc() We should be using the gfp flags the caller specified here, instead of GFP_KERNEL. I think this might be a bugfix, depending on the value of "sock->sk->sk_allocation" when we call rds_conn_create_outgoing() in rds_sendmsg(). Otherwise, it's just a cleanup. Signed-off-by: Dan Carpenter Acked-by: Venkat Venkatsubra Signed-off-by: David S. Miller --- net/rds/ib_cm.c | 2 +- net/rds/iw_cm.c | 2 +- net/rds/loop.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 51c868923f6..a1e11627747 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -749,7 +749,7 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp) int ret; /* XXX too lazy? */ - ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL); + ic = kzalloc(sizeof(struct rds_ib_connection), gfp); if (!ic) return -ENOMEM; diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c index 9556d2895f7..a91e1db62ee 100644 --- a/net/rds/iw_cm.c +++ b/net/rds/iw_cm.c @@ -694,7 +694,7 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp) unsigned long flags; /* XXX too lazy? */ - ic = kzalloc(sizeof(struct rds_iw_connection), GFP_KERNEL); + ic = kzalloc(sizeof(struct rds_iw_connection), gfp); if (!ic) return -ENOMEM; diff --git a/net/rds/loop.c b/net/rds/loop.c index 87ff2a8a454..6b12b68541a 100644 --- a/net/rds/loop.c +++ b/net/rds/loop.c @@ -121,7 +121,7 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp) struct rds_loop_connection *lc; unsigned long flags; - lc = kzalloc(sizeof(struct rds_loop_connection), GFP_KERNEL); + lc = kzalloc(sizeof(struct rds_loop_connection), gfp); if (!lc) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 26b2072e7536e57995b2867d057fbb32ecfe498d Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 21 Mar 2012 23:32:39 +0000 Subject: xfrm: Remove unused xfrm_state from xfrm_state_check_space The xfrm_state argument is unused in this function, so remove it. Also the name xfrm_state_check_space does not really match what this function does. It actually checks if we have enough head and tailroom on the skb. So we rename the function to xfrm_skb_check_space. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- net/xfrm/xfrm_output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 47bacd8c025..95a338c89f9 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -21,7 +21,7 @@ static int xfrm_output2(struct sk_buff *skb); -static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) +static int xfrm_skb_check_space(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev) @@ -48,7 +48,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err) goto resume; do { - err = xfrm_state_check_space(x, skb); + err = xfrm_skb_check_space(skb); if (err) { XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); goto error_nolock; -- cgit v1.2.3-70-g09d2 From 1265fd616782ef03b98fd19f65c2b47fcd4ea11f Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 21 Mar 2012 23:36:13 +0000 Subject: xfrm: Access the replay notify functions via the registered callbacks We call the wrong replay notify function when we use ESN replay handling. This leads to the fact that we don't send notifications if we use ESN. Fix this by calling the registered callbacks instead of xfrm_replay_notify(). Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- net/xfrm/xfrm_replay.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index 39e02c54ed2..2f6d11d04a2 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -167,7 +167,7 @@ static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) } if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb) @@ -279,7 +279,7 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq) replay_esn->bmp[nr] |= (1U << bitnr); if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event) @@ -473,7 +473,7 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) replay_esn->bmp[nr] |= (1U << bitnr); if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static struct xfrm_replay xfrm_replay_legacy = { -- cgit v1.2.3-70-g09d2 From c1ebd7dff700277e4d0a3da36833a406142e31d4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 22 Mar 2012 23:40:01 +0100 Subject: netfilter: cttimeout: fix dependency with l4protocol conntrack module This patch introduces nf_conntrack_l4proto_find_get() and nf_conntrack_l4proto_put() to fix module dependencies between timeout objects and l4-protocol conntrack modules. Thus, we make sure that the module cannot be removed if it is used by any of the cttimeout objects. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_l4proto.h | 4 +++ include/net/netfilter/nf_conntrack_timeout.h | 2 +- net/netfilter/nf_conntrack_proto.c | 21 +++++++++++++ net/netfilter/nfnetlink_cttimeout.c | 45 ++++++++++++++-------------- net/netfilter/xt_CT.c | 6 ++-- 5 files changed, 53 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 90c67c7db7e..3b572bb20aa 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -118,6 +118,10 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; extern struct nf_conntrack_l4proto * __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto); +extern struct nf_conntrack_l4proto * +nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto); +extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p); + /* Protocol registration. */ extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto); extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto); diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h index 0e04db4a086..34ec89f8dbf 100644 --- a/include/net/netfilter/nf_conntrack_timeout.h +++ b/include/net/netfilter/nf_conntrack_timeout.h @@ -15,7 +15,7 @@ struct ctnl_timeout { atomic_t refcnt; char name[CTNL_TIMEOUT_NAME_MAX]; __u16 l3num; - __u8 l4num; + struct nf_conntrack_l4proto *l4proto; char data[0]; }; diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 5701c8dd783..be3da2c8cdc 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -127,6 +127,27 @@ void nf_ct_l3proto_module_put(unsigned short l3proto) } EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); +struct nf_conntrack_l4proto * +nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) +{ + struct nf_conntrack_l4proto *p; + + rcu_read_lock(); + p = __nf_ct_l4proto_find(l3num, l4num); + if (!try_module_get(p->me)) + p = &nf_conntrack_l4proto_generic; + rcu_read_unlock(); + + return p; +} +EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); + +void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) +{ + module_put(p->me); +} +EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); + static int kill_l3proto(struct nf_conn *i, void *data) { return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index fec29a43de4..2b9e79f5ef0 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -98,11 +98,13 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, break; } - l4proto = __nf_ct_l4proto_find(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l3num, l4num); /* This protocol is not supportted, skip. */ - if (l4proto->l4proto != l4num) - return -EOPNOTSUPP; + if (l4proto->l4proto != l4num) { + ret = -EOPNOTSUPP; + goto err_proto_put; + } if (matching) { if (nlh->nlmsg_flags & NLM_F_REPLACE) { @@ -110,20 +112,25 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, * different kind, sorry. */ if (matching->l3num != l3num || - matching->l4num != l4num) - return -EINVAL; + matching->l4proto->l4proto != l4num) { + ret = -EINVAL; + goto err_proto_put; + } ret = ctnl_timeout_parse_policy(matching, l4proto, cda[CTA_TIMEOUT_DATA]); return ret; } - return -EBUSY; + ret = -EBUSY; + goto err_proto_put; } timeout = kzalloc(sizeof(struct ctnl_timeout) + l4proto->ctnl_timeout.obj_size, GFP_KERNEL); - if (timeout == NULL) - return -ENOMEM; + if (timeout == NULL) { + ret = -ENOMEM; + goto err_proto_put; + } ret = ctnl_timeout_parse_policy(timeout, l4proto, cda[CTA_TIMEOUT_DATA]); @@ -132,13 +139,15 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); timeout->l3num = l3num; - timeout->l4num = l4num; + timeout->l4proto = l4proto; atomic_set(&timeout->refcnt, 1); list_add_tail_rcu(&timeout->head, &cttimeout_list); return 0; err: kfree(timeout); +err_proto_put: + nf_ct_l4proto_put(l4proto); return ret; } @@ -149,7 +158,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; unsigned int flags = pid ? NLM_F_MULTI : 0; - struct nf_conntrack_l4proto *l4proto; + struct nf_conntrack_l4proto *l4proto = timeout->l4proto; event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); @@ -163,20 +172,10 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); - NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); + NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto); NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, htonl(atomic_read(&timeout->refcnt))); - l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); - - /* If the timeout object does not match the layer 4 protocol tracker, - * then skip dumping the data part since we don't know how to - * interpret it. This may happen for UPDlite, SCTP and DCCP since - * you can unload the module. - */ - if (timeout->l4num != l4proto->l4proto) - goto out; - if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { struct nlattr *nest_parms; int ret; @@ -192,7 +191,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, nla_nest_end(skb, nest_parms); } -out: + nlmsg_end(skb, nlh); return skb->len; @@ -293,6 +292,7 @@ static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) if (atomic_dec_and_test(&timeout->refcnt)) { /* We are protected by nfnl mutex. */ list_del_rcu(&timeout->head); + nf_ct_l4proto_put(timeout->l4proto); kfree_rcu(timeout, rcu_head); } else { /* still in use, restore reference counter. */ @@ -417,6 +417,7 @@ static void __exit cttimeout_exit(void) /* We are sure that our objects have no clients at this point, * it's safe to release them all without checking refcnt. */ + nf_ct_l4proto_put(cur->l4proto); kfree_rcu(cur, rcu_head); } #ifdef CONFIG_NF_CONNTRACK_TIMEOUT diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index b873445df44..80c39f0f6e9 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -243,11 +244,12 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) info->timeout, timeout->l3num); goto err3; } - if (timeout->l4num != e->ip.proto) { + if (timeout->l4proto->l4proto != e->ip.proto) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L4 protocol number %d\n", - info->timeout, timeout->l4num); + info->timeout, + timeout->l4proto->l4proto); goto err3; } timeout_ext = nf_ct_timeout_ext_add(ct, timeout, -- cgit v1.2.3-70-g09d2 From 1ac0bf99260761ad0a536ddbc15f6f9b82b9bab3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 22 Mar 2012 23:58:41 +0100 Subject: netfilter: xt_CT: missing rcu_read_lock section in timeout assignment Fix a dereference to pointer without rcu_read_lock held. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_CT.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 80c39f0f6e9..33a02b41abb 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -218,6 +218,7 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) struct ctnl_timeout *timeout; struct nf_conn_timeout *timeout_ext; + rcu_read_lock(); timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook); @@ -228,21 +229,21 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) ret = -EINVAL; pr_info("You cannot use inversion on " "L4 protocol\n"); - goto err3; + goto err4; } timeout = timeout_find_get(info->timeout); if (timeout == NULL) { ret = -ENOENT; pr_info("No such timeout policy \"%s\"\n", info->timeout); - goto err3; + goto err4; } if (timeout->l3num != par->family) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L3 protocol number %d\n", info->timeout, timeout->l3num); - goto err3; + goto err4; } if (timeout->l4proto->l4proto != e->ip.proto) { ret = -EINVAL; @@ -250,19 +251,20 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) "used by L4 protocol number %d\n", info->timeout, timeout->l4proto->l4proto); - goto err3; + goto err4; } timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_KERNEL); if (timeout_ext == NULL) { ret = -ENOMEM; - goto err3; + goto err4; } } else { ret = -ENOENT; pr_info("Timeout policy base is empty\n"); - goto err3; + goto err4; } + rcu_read_unlock(); } #endif @@ -272,6 +274,8 @@ out: info->ct = ct; return 0; +err4: + rcu_read_unlock(); err3: nf_conntrack_free(ct); err2: @@ -313,6 +317,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) nf_ct_l3proto_module_put(par->family); #ifdef CONFIG_NF_CONNTRACK_TIMEOUT + rcu_read_lock(); timeout_put = rcu_dereference(nf_ct_timeout_put_hook); if (timeout_put) { @@ -320,6 +325,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) if (timeout_ext) timeout_put(timeout_ext->timeout); } + rcu_read_unlock(); #endif } nf_ct_put(info->ct); -- cgit v1.2.3-70-g09d2 From eeb4cb952386aac764a5cf4cf2490e50a24a8880 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 23 Mar 2012 00:02:07 +0100 Subject: netfilter: xt_CT: fix assignation of the generic protocol tracker `iptables -p all' uses 0 to match all protocols, while the conntrack subsystem uses 255. We still need `-p all' to attach the custom timeout policies for the generic protocol tracker. Moreover, we may use `iptables -p sctp' while the SCTP tracker is not loaded. In that case, we have to default on the generic protocol tracker. Another possibility is `iptables -p ip' that should be supported as well. This patch makes sure we validate all possible scenarios. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_CT.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 33a02b41abb..0c8e43810ce 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,7 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) if (timeout_find_get) { const struct ipt_entry *e = par->entryinfo; + struct nf_conntrack_l4proto *l4proto; if (e->ip.invflags & IPT_INV_PROTO) { ret = -EINVAL; @@ -245,7 +247,12 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) info->timeout, timeout->l3num); goto err4; } - if (timeout->l4proto->l4proto != e->ip.proto) { + /* Make sure the timeout policy matches any existing + * protocol tracker, otherwise default to generic. + */ + l4proto = __nf_ct_l4proto_find(par->family, + e->ip.proto); + if (timeout->l4proto->l4proto != l4proto->l4proto) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L4 protocol number %d\n", -- cgit v1.2.3-70-g09d2 From 60b5f8f745739a4789395648595ed31ede582448 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 23 Mar 2012 00:04:53 +0100 Subject: netfilter: nf_conntrack: permanently attach timeout policy to conntrack We need to permanently attach the timeout policy to the conntrack, otherwise we may apply the custom timeout policy inconsistently. Without this patch, the following example: nfct timeout add test inet icmp timeout 100 iptables -I PREROUTING -t raw -p icmp -s 1.1.1.1 -j CT --timeout test Will only apply the custom timeout policy to outgoing packets from 1.1.1.1, but not to reply packets from 2.2.2.2 going to 1.1.1.1. To fix this issue, this patch modifies the current logic to attach the timeout policy when the first packet is seen (which is when the conntrack entry is created). Then, we keep using the attached timeout policy until the conntrack entry is destroyed. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_core.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7b48035826e..cbdb754dbb1 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -768,8 +768,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, struct sk_buff *skb, - unsigned int dataoff, u32 hash, - unsigned int *timeouts) + unsigned int dataoff, u32 hash) { struct nf_conn *ct; struct nf_conn_help *help; @@ -777,6 +776,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_ecache *ecache; struct nf_conntrack_expect *exp; u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; + struct nf_conn_timeout *timeout_ext; + unsigned int *timeouts; if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { pr_debug("Can't invert tuple.\n"); @@ -788,12 +789,21 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, if (IS_ERR(ct)) return (struct nf_conntrack_tuple_hash *)ct; + timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL; + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + if (!l4proto->new(ct, skb, dataoff, timeouts)) { nf_conntrack_free(ct); pr_debug("init conntrack: can't track with proto module\n"); return NULL; } + if (timeout_ext) + nf_ct_timeout_ext_add(ct, timeout_ext->timeout, GFP_ATOMIC); + nf_ct_acct_ext_add(ct, GFP_ATOMIC); nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); @@ -854,8 +864,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, int *set_reply, - enum ip_conntrack_info *ctinfo, - unsigned int *timeouts) + enum ip_conntrack_info *ctinfo) { struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple_hash *h; @@ -875,7 +884,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, h = __nf_conntrack_find_get(net, zone, &tuple, hash); if (!h) { h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, - skb, dataoff, hash, timeouts); + skb, dataoff, hash); if (!h) return NULL; if (IS_ERR(h)) @@ -964,19 +973,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, goto out; } - /* Decide what timeout policy we want to apply to this flow. */ - if (tmpl) { - timeout_ext = nf_ct_timeout_find(tmpl); - if (timeout_ext) - timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); - else - timeouts = l4proto->get_timeouts(net); - } else - timeouts = l4proto->get_timeouts(net); - ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, - l3proto, l4proto, &set_reply, &ctinfo, - timeouts); + l3proto, l4proto, &set_reply, &ctinfo); if (!ct) { /* Not valid part of a connection */ NF_CT_STAT_INC_ATOMIC(net, invalid); @@ -993,6 +991,13 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, NF_CT_ASSERT(skb->nfct); + /* Decide what timeout policy we want to apply to this flow. */ + timeout_ext = nf_ct_timeout_find(ct); + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts); if (ret <= 0) { /* Invalid: inverse of the return code tells -- cgit v1.2.3-70-g09d2 From 523f610e1be2a4afca605962e137064378883c5f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 22 Mar 2012 12:27:06 +0000 Subject: netfilter: remove forward module param confusion. It used to be an int, and it got changed to a bool parameter at least 7 years ago. It happens that NF_ACCEPT and NF_DROP are 0 and 1, so this works, but it's unclear, and the check that it's in range is not required. Reported-by: Dan Carpenter Signed-off-by: Rusty Russell Signed-off-by: David S. Miller --- net/ipv4/netfilter/iptable_filter.c | 9 ++------- net/ipv6/netfilter/ip6table_filter.c | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 0e58f09e59f..851acec852d 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -52,7 +52,7 @@ iptable_filter_hook(unsigned int hook, struct sk_buff *skb, static struct nf_hook_ops *filter_ops __read_mostly; /* Default to forward because I got too much mail already. */ -static bool forward = NF_ACCEPT; +static bool forward = true; module_param(forward, bool, 0000); static int __net_init iptable_filter_net_init(struct net *net) @@ -64,7 +64,7 @@ static int __net_init iptable_filter_net_init(struct net *net) return -ENOMEM; /* Entry 1 is the FORWARD hook */ ((struct ipt_standard *)repl->entries)[1].target.verdict = - -forward - 1; + forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; net->ipv4.iptable_filter = ipt_register_table(net, &packet_filter, repl); @@ -88,11 +88,6 @@ static int __init iptable_filter_init(void) { int ret; - if (forward < 0 || forward > NF_MAX_VERDICT) { - pr_err("iptables forward must be 0 or 1\n"); - return -EINVAL; - } - ret = register_pernet_subsys(&iptable_filter_net_ops); if (ret < 0) return ret; diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index a8f6da97e3b..325e59a0224 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -44,7 +44,7 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, static struct nf_hook_ops *filter_ops __read_mostly; /* Default to forward because I got too much mail already. */ -static bool forward = NF_ACCEPT; +static bool forward = true; module_param(forward, bool, 0000); static int __net_init ip6table_filter_net_init(struct net *net) @@ -56,7 +56,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) return -ENOMEM; /* Entry 1 is the FORWARD hook */ ((struct ip6t_standard *)repl->entries)[1].target.verdict = - -forward - 1; + forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; net->ipv6.ip6table_filter = ip6t_register_table(net, &packet_filter, repl); @@ -80,11 +80,6 @@ static int __init ip6table_filter_init(void) { int ret; - if (forward < 0 || forward > NF_MAX_VERDICT) { - pr_err("iptables forward must be 0 or 1\n"); - return -EINVAL; - } - ret = register_pernet_subsys(&ip6table_filter_net_ops); if (ret < 0) return ret; -- cgit v1.2.3-70-g09d2 From eaddcd76903c28e84bb452a35835babb0800a2c4 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 22 Mar 2012 16:14:29 +0000 Subject: bonding: remove entries for master_ip and vlan_ip and query devices instead The following patch aimed to resolve an issue where secondary, tertiary, etc. addresses added to bond interfaces could overwrite the bond->master_ip and vlan_ip values. commit 917fbdb32f37e9a93b00bb12ee83532982982df3 Author: Henrik Saavedra Persson Date: Wed Nov 23 23:37:15 2011 +0000 bonding: only use primary address for ARP That patch was good because it prevented bonds using ARP monitoring from sending frames with an invalid source IP address. Unfortunately, it didn't always work as expected. When using an ioctl (like ifconfig does) to set the IP address and netmask, 2 separate ioctls are actually called to set the IP and netmask if the mask chosen doesn't match the standard mask for that class of address. The first ioctl did not have a mask that matched the one in the primary address and would still cause the device address to be overwritten. The second ioctl that was called to set the mask would then detect as secondary and ignored, but the damage was already done. This was not an issue when using an application that used netlink sockets as the setting of IP and netmask came down at once. The inconsistent behavior between those two interfaces was something that needed to be resolved. While I was thinking about how I wanted to resolve this, Ralf Zeidler came with a patch that resolved this on a RHEL kernel by keeping a full shadow of the entries in dev->ifa_list for the bonding device and vlan devices in the bonding driver. I didn't like the duplication of the list as I want to see the 'bonding' struct and code shrink rather than grow, but liked the general idea. As the Subject indicates this patch drops the master_ip and vlan_ip elements from the 'bonding' and 'vlan_entry' structs, respectively. This can be done because a device's address-list is now traversed to determine the optimal source IP address for ARP requests and for checks to see if the bonding device has a particular IP address. This code could have all be contained inside the bonding driver, but it made more sense to me to EXPORT and call inet_confirm_addr since it did exactly what was needed. I tested this and a backported patch and everything works as expected. Ralf also helped with verification of the backported patch. Thanks to Ralf for all his help on this. v2: Whitespace and organizational changes based on suggestions from Jay Vosburgh and Dave Miller. v3: Fixup incorrect usage of rcu_read_unlock based on Dave Miller's suggestion. Signed-off-by: Andy Gospodarek CC: Ralf Zeidler Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 82 ++++++++--------------------------------- drivers/net/bonding/bonding.h | 18 ++++++++- net/ipv4/devinet.c | 1 + 3 files changed, 32 insertions(+), 69 deletions(-) (limited to 'net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0730203a19f..b920d829692 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2573,12 +2573,16 @@ re_arm: static int bond_has_this_ip(struct bonding *bond, __be32 ip) { struct vlan_entry *vlan; + struct net_device *vlan_dev; - if (ip == bond->master_ip) + if (ip == bond_confirm_addr(bond->dev, 0, ip)) return 1; list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - if (ip == vlan->vlan_ip) + rcu_read_lock(); + vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id); + rcu_read_unlock(); + if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip)) return 1; } @@ -2620,17 +2624,19 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) int i, vlan_id; __be32 *targets = bond->params.arp_targets; struct vlan_entry *vlan; - struct net_device *vlan_dev; + struct net_device *vlan_dev = NULL; struct rtable *rt; for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { + __be32 addr; if (!targets[i]) break; pr_debug("basa: target %x\n", targets[i]); if (!bond_vlan_used(bond)) { pr_debug("basa: empty vlan: arp_send\n"); + addr = bond_confirm_addr(bond->dev, targets[i], 0); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], - bond->master_ip, 0); + addr, 0); continue; } @@ -2655,8 +2661,9 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) if (rt->dst.dev == bond->dev) { ip_rt_put(rt); pr_debug("basa: rtdev == bond->dev: arp_send\n"); + addr = bond_confirm_addr(bond->dev, targets[i], 0); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], - bond->master_ip, 0); + addr, 0); continue; } @@ -2674,10 +2681,11 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } } - if (vlan_id) { + if (vlan_id && vlan_dev) { ip_rt_put(rt); + addr = bond_confirm_addr(vlan_dev, targets[i], 0); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], - vlan->vlan_ip, vlan_id); + addr, vlan_id); continue; } @@ -3299,68 +3307,10 @@ static int bond_netdev_event(struct notifier_block *this, return NOTIFY_DONE; } -/* - * bond_inetaddr_event: handle inetaddr notifier chain events. - * - * We keep track of device IPs primarily to use as source addresses in - * ARP monitor probes (rather than spewing out broadcasts all the time). - * - * We track one IP for the main device (if it has one), plus one per VLAN. - */ -static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct in_ifaddr *ifa = ptr; - struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev; - struct bond_net *bn = net_generic(dev_net(event_dev), bond_net_id); - struct bonding *bond; - struct vlan_entry *vlan; - - /* we only care about primary address */ - if(ifa->ifa_flags & IFA_F_SECONDARY) - return NOTIFY_DONE; - - list_for_each_entry(bond, &bn->dev_list, bond_list) { - if (bond->dev == event_dev) { - switch (event) { - case NETDEV_UP: - bond->master_ip = ifa->ifa_local; - return NOTIFY_OK; - case NETDEV_DOWN: - bond->master_ip = 0; - return NOTIFY_OK; - default: - return NOTIFY_DONE; - } - } - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - vlan_dev = __vlan_find_dev_deep(bond->dev, - vlan->vlan_id); - if (vlan_dev == event_dev) { - switch (event) { - case NETDEV_UP: - vlan->vlan_ip = ifa->ifa_local; - return NOTIFY_OK; - case NETDEV_DOWN: - vlan->vlan_ip = 0; - return NOTIFY_OK; - default: - return NOTIFY_DONE; - } - } - } - } - return NOTIFY_DONE; -} - static struct notifier_block bond_netdev_notifier = { .notifier_call = bond_netdev_event, }; -static struct notifier_block bond_inetaddr_notifier = { - .notifier_call = bond_inetaddr_event, -}; - /*---------------------------- Hashing Policies -----------------------------*/ /* @@ -4929,7 +4879,6 @@ static int __init bonding_init(void) } register_netdevice_notifier(&bond_netdev_notifier); - register_inetaddr_notifier(&bond_inetaddr_notifier); out: return res; err: @@ -4943,7 +4892,6 @@ err_link: static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); - unregister_inetaddr_notifier(&bond_inetaddr_notifier); bond_destroy_debugfs(); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 1aecc37e5b4..9f2bae6616d 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "bond_3ad.h" #include "bond_alb.h" @@ -166,7 +167,6 @@ struct bond_parm_tbl { struct vlan_entry { struct list_head vlan_list; - __be32 vlan_ip; unsigned short vlan_id; }; @@ -232,7 +232,6 @@ struct bonding { struct list_head bond_list; struct netdev_hw_addr_list mc_list; int (*xmit_hash_policy)(struct sk_buff *, int); - __be32 master_ip; u16 rr_tx_counter; struct ad_bond_info ad_info; struct alb_bond_info alb_info; @@ -378,6 +377,21 @@ static inline bool bond_is_slave_inactive(struct slave *slave) return slave->inactive; } +static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be32 local) +{ + struct in_device *in_dev; + __be32 addr = 0; + + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); + + if (in_dev) + addr = inet_confirm_addr(in_dev, dst, local, RT_SCOPE_HOST); + + rcu_read_unlock(); + return addr; +} + struct bond_net; struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e41c40f48cf..d4fad5c7744 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1079,6 +1079,7 @@ __be32 inet_confirm_addr(struct in_device *in_dev, return addr; } +EXPORT_SYMBOL(inet_confirm_addr); /* * Device notifier -- cgit v1.2.3-70-g09d2 From 626cf236608505d376e4799adb4f7eb00a8594af Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 23 Mar 2012 15:02:27 -0700 Subject: poll: add poll_requested_events() and poll_does_not_wait() functions In some cases the poll() implementation in a driver has to do different things depending on the events the caller wants to poll for. An example is when a driver needs to start a DMA engine if the caller polls for POLLIN, but doesn't want to do that if POLLIN is not requested but instead only POLLOUT or POLLPRI is requested. This is something that can happen in the video4linux subsystem among others. Unfortunately, the current epoll/poll/select implementation doesn't provide that information reliably. The poll_table_struct does have it: it has a key field with the event mask. But once a poll() call matches one or more bits of that mask any following poll() calls are passed a NULL poll_table pointer. Also, the eventpoll implementation always left the key field at ~0 instead of using the requested events mask. This was changed in eventpoll.c so the key field now contains the actual events that should be polled for as set by the caller. The solution to the NULL poll_table pointer is to set the qproc field to NULL in poll_table once poll() matches the events, not the poll_table pointer itself. That way drivers can obtain the mask through a new poll_requested_events inline. The poll_table_struct can still be NULL since some kernel code calls it internally (netfs_state_poll() in ./drivers/staging/pohmelfs/netfs.h). In that case poll_requested_events() returns ~0 (i.e. all events). Very rarely drivers might want to know whether poll_wait will actually wait. If another earlier file descriptor in the set already matched the events the caller wanted to wait for, then the kernel will return from the select() call without waiting. This might be useful information in order to avoid doing expensive work. A new helper function poll_does_not_wait() is added that drivers can use to detect this situation. This is now used in sock_poll_wait() in include/net/sock.h. This was the only place in the kernel that needed this information. Drivers should no longer access any of the poll_table internals, but use the poll_requested_events() and poll_does_not_wait() access functions instead. In order to enforce that the poll_table fields are now prepended with an underscore and a comment was added warning against using them directly. This required a change in unix_dgram_poll() in unix/af_unix.c which used the key field to get the requested events. It's been replaced by a call to poll_requested_events(). For qproc it was especially important to change its name since the behavior of that field changes with this patch since this function pointer can now be NULL when that wasn't possible in the past. Any driver accessing the qproc or key fields directly will now fail to compile. Some notes regarding the correctness of this patch: the driver's poll() function is called with a 'struct poll_table_struct *wait' argument. This pointer may or may not be NULL, drivers can never rely on it being one or the other as that depends on whether or not an earlier file descriptor in the select()'s fdset matched the requested events. There are only three things a driver can do with the wait argument: 1) obtain the key field: events = wait ? wait->key : ~0; This will still work although it should be replaced with the new poll_requested_events() function (which does exactly the same). This will now even work better, since wait is no longer set to NULL unnecessarily. 2) use the qproc callback. This could be deadly since qproc can now be NULL. Renaming qproc should prevent this from happening. There are no kernel drivers that actually access this callback directly, BTW. 3) test whether wait == NULL to determine whether poll would return without waiting. This is no longer sufficient as the correct test is now wait == NULL || wait->_qproc == NULL. However, the worst that can happen here is a slight performance hit in the case where wait != NULL and wait->_qproc == NULL. In that case the driver will assume that poll_wait() will actually add the fd to the set of waiting file descriptors. Of course, poll_wait() will not do that since it tests for wait->_qproc. This will not break anything, though. There is only one place in the whole kernel where this happens (sock_poll_wait() in include/net/sock.h) and that code will be replaced by a call to poll_does_not_wait() in the next patch. Note that even if wait->_qproc != NULL drivers cannot rely on poll_wait() actually waiting. The next file descriptor from the set might match the event mask and thus any possible waits will never happen. Signed-off-by: Hans Verkuil Reviewed-by: Jonathan Corbet Reviewed-by: Al Viro Cc: Davide Libenzi Signed-off-by: Hans de Goede Cc: Mauro Carvalho Chehab Cc: David Miller Cc: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/eventpoll.c | 18 +++++++++++++++--- fs/select.c | 40 ++++++++++++++++++---------------------- include/linux/poll.h | 37 +++++++++++++++++++++++++++++++------ include/net/sock.h | 2 +- net/unix/af_unix.c | 2 +- 5 files changed, 66 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 4d9d3a45e35..ca300071e79 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -699,9 +699,12 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, void *priv) { struct epitem *epi, *tmp; + poll_table pt; + init_poll_funcptr(&pt, NULL); list_for_each_entry_safe(epi, tmp, head, rdllink) { - if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & + pt._key = epi->event.events; + if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) & epi->event.events) return POLLIN | POLLRDNORM; else { @@ -1097,6 +1100,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, /* Initialize the poll table using the queue callback */ epq.epi = epi; init_poll_funcptr(&epq.pt, ep_ptable_queue_proc); + epq.pt._key = event->events; /* * Attach the item to the poll hooks and get current event bits. @@ -1191,6 +1195,9 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even { int pwake = 0; unsigned int revents; + poll_table pt; + + init_poll_funcptr(&pt, NULL); /* * Set the new event interest mask before calling f_op->poll(); @@ -1198,13 +1205,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even * f_op->poll() call and the new event set registering. */ epi->event.events = event->events; + pt._key = event->events; epi->event.data = event->data; /* protected by mtx */ /* * Get current event bits. We can safely use the file* here because * its usage count has been increased by the caller of this function. */ - revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL); + revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt); /* * If the item is "hot" and it is not registered inside the ready @@ -1239,6 +1247,9 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, unsigned int revents; struct epitem *epi; struct epoll_event __user *uevent; + poll_table pt; + + init_poll_funcptr(&pt, NULL); /* * We can loop without lock because we are passed a task private list. @@ -1251,7 +1262,8 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, list_del_init(&epi->rdllink); - revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & + pt._key = epi->event.events; + revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) & epi->event.events; /* diff --git a/fs/select.c b/fs/select.c index e782258d0de..ecfd0b125ba 100644 --- a/fs/select.c +++ b/fs/select.c @@ -223,7 +223,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, get_file(filp); entry->filp = filp; entry->wait_address = wait_address; - entry->key = p->key; + entry->key = p->_key; init_waitqueue_func_entry(&entry->wait, pollwake); entry->wait.private = pwq; add_wait_queue(wait_address, &entry->wait); @@ -386,13 +386,11 @@ get_max: static inline void wait_key_set(poll_table *wait, unsigned long in, unsigned long out, unsigned long bit) { - if (wait) { - wait->key = POLLEX_SET; - if (in & bit) - wait->key |= POLLIN_SET; - if (out & bit) - wait->key |= POLLOUT_SET; - } + wait->_key = POLLEX_SET; + if (in & bit) + wait->_key |= POLLIN_SET; + if (out & bit) + wait->_key |= POLLOUT_SET; } int do_select(int n, fd_set_bits *fds, struct timespec *end_time) @@ -414,7 +412,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) poll_initwait(&table); wait = &table.pt; if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { - wait = NULL; + wait->_qproc = NULL; timed_out = 1; } @@ -459,17 +457,17 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) if ((mask & POLLIN_SET) && (in & bit)) { res_in |= bit; retval++; - wait = NULL; + wait->_qproc = NULL; } if ((mask & POLLOUT_SET) && (out & bit)) { res_out |= bit; retval++; - wait = NULL; + wait->_qproc = NULL; } if ((mask & POLLEX_SET) && (ex & bit)) { res_ex |= bit; retval++; - wait = NULL; + wait->_qproc = NULL; } } } @@ -481,7 +479,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) *rexp = res_ex; cond_resched(); } - wait = NULL; + wait->_qproc = NULL; if (retval || timed_out || signal_pending(current)) break; if (table.error) { @@ -720,7 +718,7 @@ struct poll_list { * interested in events matching the pollfd->events mask, and the result * matching that mask is both recorded in pollfd->revents and returned. The * pwait poll_table will be used by the fd-provided poll handler for waiting, - * if non-NULL. + * if pwait->_qproc is non-NULL. */ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) { @@ -738,9 +736,7 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) if (file != NULL) { mask = DEFAULT_POLLMASK; if (file->f_op && file->f_op->poll) { - if (pwait) - pwait->key = pollfd->events | - POLLERR | POLLHUP; + pwait->_key = pollfd->events|POLLERR|POLLHUP; mask = file->f_op->poll(file, pwait); } /* Mask out unneeded events. */ @@ -763,7 +759,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list, /* Optimise the no-wait case */ if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { - pt = NULL; + pt->_qproc = NULL; timed_out = 1; } @@ -781,22 +777,22 @@ static int do_poll(unsigned int nfds, struct poll_list *list, for (; pfd != pfd_end; pfd++) { /* * Fish for events. If we found one, record it - * and kill the poll_table, so we don't + * and kill poll_table->_qproc, so we don't * needlessly register any other waiters after * this. They'll get immediately deregistered * when we break out and return. */ if (do_pollfd(pfd, pt)) { count++; - pt = NULL; + pt->_qproc = NULL; } } } /* * All waiters have already been registered, so don't provide - * a poll_table to them on the next loop iteration. + * a poll_table->_qproc to them on the next loop iteration. */ - pt = NULL; + pt->_qproc = NULL; if (!count) { count = wait->error; if (signal_pending(current)) diff --git a/include/linux/poll.h b/include/linux/poll.h index cf40010ce0c..48fe8bc398d 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -32,21 +32,46 @@ struct poll_table_struct; */ typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); +/* + * Do not touch the structure directly, use the access functions + * poll_does_not_wait() and poll_requested_events() instead. + */ typedef struct poll_table_struct { - poll_queue_proc qproc; - unsigned long key; + poll_queue_proc _qproc; + unsigned long _key; } poll_table; static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) { - if (p && wait_address) - p->qproc(filp, wait_address, p); + if (p && p->_qproc && wait_address) + p->_qproc(filp, wait_address, p); +} + +/* + * Return true if it is guaranteed that poll will not wait. This is the case + * if the poll() of another file descriptor in the set got an event, so there + * is no need for waiting. + */ +static inline bool poll_does_not_wait(const poll_table *p) +{ + return p == NULL || p->_qproc == NULL; +} + +/* + * Return the set of events that the application wants to poll for. + * This is useful for drivers that need to know whether a DMA transfer has + * to be started implicitly on poll(). You typically only want to do that + * if the application is actually polling for POLLIN and/or POLLOUT. + */ +static inline unsigned long poll_requested_events(const poll_table *p) +{ + return p ? p->_key : ~0UL; } static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc) { - pt->qproc = qproc; - pt->key = ~0UL; /* all events enabled */ + pt->_qproc = qproc; + pt->_key = ~0UL; /* all events enabled */ } struct poll_table_entry { diff --git a/include/net/sock.h b/include/net/sock.h index 04bc0b30e9e..a6ba1f8871f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1854,7 +1854,7 @@ static inline bool wq_has_sleeper(struct socket_wq *wq) static inline void sock_poll_wait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) { - if (p && wait_address) { + if (!poll_does_not_wait(p) && wait_address) { poll_wait(filp, wait_address, p); /* * We need to be sure we are in sync with the diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index eb4277c3318..d510353ef43 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2206,7 +2206,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, } /* No write status requested, avoid expensive OUT tests. */ - if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT))) + if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT))) return mask; writable = unix_writable(sk); -- cgit v1.2.3-70-g09d2 From 50269e19ad990e79eeda101fc6df80cffd5d4831 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Mar 2012 23:59:33 +0000 Subject: net: add a truesize parameter to skb_add_rx_frag() skb_add_rx_frag() API is misleading. Network skbs built with this helper can use uncharged kernel memory and eventually stress/crash machine in OOM. Add a 'truesize' parameter and then fix drivers in followup patches. Signed-off-by: Eric Dumazet Cc: Wey-Yi Guy Signed-off-by: David S. Miller --- drivers/net/usb/cdc-phonet.c | 6 ++++-- drivers/net/wireless/iwlegacy/3945.c | 3 ++- drivers/net/wireless/iwlegacy/4965-mac.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-agn-rx.c | 2 +- drivers/usb/gadget/f_phonet.c | 2 +- include/linux/skbuff.h | 2 +- net/core/skbuff.c | 4 ++-- 7 files changed, 13 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 790cbdea739..3886b30ed37 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -164,12 +164,14 @@ static void rx_complete(struct urb *req) /* Can't use pskb_pull() on page in IRQ */ memcpy(skb_put(skb, 1), page_address(page), 1); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - page, 1, req->actual_length); + page, 1, req->actual_length, + req->actual_length); page = NULL; } } else { skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - page, 0, req->actual_length); + page, 0, req->actual_length, + req->actual_length); page = NULL; } if (req->actual_length < PAGE_SIZE) diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index c5b1d199e0b..b25c01be0d9 100644 --- a/drivers/net/wireless/iwlegacy/3945.c +++ b/drivers/net/wireless/iwlegacy/3945.c @@ -499,7 +499,8 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, le32_to_cpu(rx_end->status), stats); skb_add_rx_frag(skb, 0, rxb->page, - (void *)rx_hdr->payload - (void *)pkt, len); + (void *)rx_hdr->payload - (void *)pkt, len, + len); il_update_stats(il, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 7b54dbb338b..17f1c685318 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -596,7 +596,8 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr, return; } - skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); + skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len, + len); il_update_stats(il, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 44c6f712b77..f4b84d1596e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -796,7 +796,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, offset = (void *)hdr - rxb_addr(rxb); p = rxb_steal_page(rxb); - skb_add_rx_frag(skb, 0, p, offset, len); + skb_add_rx_frag(skb, 0, p, offset, len, len); iwl_update_stats(priv, false, fc, len); diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 7cdcb63b21f..85a5cebe96b 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -345,7 +345,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) } skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - skb->len <= 1, req->actual); + skb->len <= 1, req->actual, req->actual); page = NULL; if (req->actual < req->length) { /* Last fragment */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a2b9953b582..681a1879914 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1244,7 +1244,7 @@ static inline void skb_fill_page_desc(struct sk_buff *skb, int i, } extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, - int off, int size); + int off, int size, unsigned int truesize); #define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) #define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frag_list(skb)) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6eb656acdfe..a690cae91cd 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -321,12 +321,12 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, EXPORT_SYMBOL(__netdev_alloc_skb); void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, - int size) + int size, unsigned int truesize) { skb_fill_page_desc(skb, i, page, off, size); skb->len += size; skb->data_len += size; - skb->truesize += size; + skb->truesize += truesize; } EXPORT_SYMBOL(skb_add_rx_frag); -- cgit v1.2.3-70-g09d2 From b3537c35c21f0e6750aa8bd786949b55509c6d0d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 21 Mar 2012 09:52:04 -0400 Subject: sunrpc: create nfsd dir in rpc_pipefs Add a new top-level dir in rpc_pipefs to hold the pipe for the clientid upcall. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- net/sunrpc/rpc_pipe.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 8584ec068e9..e651e1b6851 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1014,6 +1014,7 @@ enum { RPCAUTH_statd, RPCAUTH_nfsd4_cb, RPCAUTH_cache, + RPCAUTH_nfsd, RPCAUTH_RootEOF }; @@ -1046,6 +1047,10 @@ static const struct rpc_filelist files[] = { .name = "cache", .mode = S_IFDIR | S_IRUGO | S_IXUGO, }, + [RPCAUTH_nfsd] = { + .name = "nfsd", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, }; /* -- cgit v1.2.3-70-g09d2 From 92769108f5382a0bdb4c35eb80c183fb7797cfae Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 23 Mar 2012 15:25:03 -0400 Subject: sunrpc: skip portmap calls on sessions backchannel There's obviously no point to doing portmap calls over the sessions backchannel. Signed-off-by: J. Bruce Fields --- net/sunrpc/xprtsock.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 92bc5181dbe..890b03f8d87 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2475,6 +2475,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { static struct rpc_xprt_ops bc_tcp_ops = { .reserve_xprt = xprt_reserve_xprt, .release_xprt = xprt_release_xprt, + .rpcbind = xs_local_rpcbind, .buf_alloc = bc_malloc, .buf_free = bc_free, .send_request = bc_send_request, -- cgit v1.2.3-70-g09d2 From 66266b3ab4871958ed6a1e43f502cadaf3becfc8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 15 Mar 2012 13:25:41 -0400 Subject: cfg80211: allow CFG80211_SIGNAL_TYPE_UNSPEC in station_info The station_info struct had demanded dBm signal values, but the cfg80211 wireless extensions implementation was also accepting "unspecified" (i.e. RSSI) unit values while the nl80211 code was completely unaware of them. Resolve this by formally allowing the "unspecified" units while making nl80211 ignore them. Signed-off-by: John W. Linville Reviewed-by: Johannes Berg --- include/net/cfg80211.h | 6 ++++-- net/wireless/nl80211.c | 29 +++++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 69b7ad3a992..5ccac722739 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -619,8 +619,10 @@ struct sta_bss_parameters { * @llid: mesh local link id * @plid: mesh peer link id * @plink_state: mesh peer link state - * @signal: signal strength of last received packet in dBm - * @signal_avg: signal strength average in dBm + * @signal: the signal strength, type depends on the wiphy's signal_type + NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. + * @signal_avg: avg signal strength, type depends on the wiphy's signal_type + NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. * @txrate: current unicast bitrate from this station * @rxrate: current unicast bitrate to this station * @rx_packets: packets received from this station diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4c1eb9472dd..e49da279702 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2386,7 +2386,9 @@ nla_put_failure: } static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, - int flags, struct net_device *dev, + int flags, + struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo) { void *hdr; @@ -2425,12 +2427,18 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_PLINK_STATE) NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, sinfo->plink_state); - if (sinfo->filled & STATION_INFO_SIGNAL) - NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, - sinfo->signal); - if (sinfo->filled & STATION_INFO_SIGNAL_AVG) - NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG, - sinfo->signal_avg); + switch (rdev->wiphy.signal_type) { + case CFG80211_SIGNAL_TYPE_MBM: + if (sinfo->filled & STATION_INFO_SIGNAL) + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, + sinfo->signal); + if (sinfo->filled & STATION_INFO_SIGNAL_AVG) + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG, + sinfo->signal_avg); + break; + default: + break; + } if (sinfo->filled & STATION_INFO_TX_BITRATE) { if (!nl80211_put_sta_rate(msg, &sinfo->txrate, NL80211_STA_INFO_TX_BITRATE)) @@ -2523,7 +2531,7 @@ static int nl80211_dump_station(struct sk_buff *skb, if (nl80211_send_station(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - netdev, mac_addr, + dev, netdev, mac_addr, &sinfo) < 0) goto out; @@ -2568,7 +2576,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) return -ENOMEM; if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, - dev, mac_addr, &sinfo) < 0) { + rdev, dev, mac_addr, &sinfo) < 0) { nlmsg_free(msg); return -ENOBUFS; } @@ -7596,7 +7604,8 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) { + if (nl80211_send_station(msg, 0, 0, 0, + rdev, dev, mac_addr, sinfo) < 0) { nlmsg_free(msg); return; } -- cgit v1.2.3-70-g09d2 From b603c03e9534b9bec19ebf8c42bf217fd875ee65 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 18 Mar 2012 14:08:50 +0200 Subject: mac80211: remove outdated comment The on-oper-channel optimization was reverted, so remove the outdated comment as well. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- net/mac80211/main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b581a24fa15..16336480c63 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -102,9 +102,6 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) might_sleep(); - /* If this off-channel logic ever changes, ieee80211_on_oper_channel - * may need to change as well. - */ offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; if (local->scan_channel) { chan = local->scan_channel; -- cgit v1.2.3-70-g09d2 From d72308bff5c2fa207949a5925b020bce74495e33 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 19 Mar 2012 16:00:26 +0100 Subject: mac80211: fix possible tid_rx->reorder_timer use after free Is possible that we will arm the tid_rx->reorder_timer after del_timer_sync() in ___ieee80211_stop_rx_ba_session(). We need to stop timer after RCU grace period finish, so move it to ieee80211_free_tid_rx(). Timer will not be armed again, as rcu_dereference(sta->ampdu_mlme.tid_rx[tid]) will return NULL. Debug object detected problem with the following warning: ODEBUG: free active (active state 0) object type: timer_list hint: sta_rx_agg_reorder_timer_expired+0x0/0xf0 [mac80211] Bug report (with all warning messages): https://bugzilla.redhat.com/show_bug.cgi?id=804007 Reported-by: "jan p. springer" Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- net/mac80211/agg-rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 1068f668ac4..64d3ce5ea1a 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -49,6 +49,8 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) container_of(h, struct tid_ampdu_rx, rcu_head); int i; + del_timer_sync(&tid_rx->reorder_timer); + for (i = 0; i < tid_rx->buf_size; i++) dev_kfree_skb(tid_rx->reorder_buf[i]); kfree(tid_rx->reorder_buf); @@ -91,7 +93,6 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, tid, WLAN_BACK_RECIPIENT, reason); del_timer_sync(&tid_rx->session_timer); - del_timer_sync(&tid_rx->reorder_timer); call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx); } -- cgit v1.2.3-70-g09d2 From 864cf9bf99f62d2095c8e6cc3a87af80b263984e Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Tue, 27 Mar 2012 13:46:32 -0400 Subject: SUNRPC: Use the already looked-up xprt in rpcb_getport_async() rbcb_getport_async() was looking up the rpc_xprt (reference++) and then later looking it up again (reference++) to pass through the rpcbind_args. The xprt would only be dereferenced once, when we were done with the rpcbind_args (reference--). This leaves an extra reference to the transport that would never go away. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust --- net/sunrpc/rpcb_clnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 207a74696c9..78ac39fd9fe 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -734,7 +734,7 @@ void rpcb_getport_async(struct rpc_task *task) map->r_vers = clnt->cl_vers; map->r_prot = xprt->prot; map->r_port = 0; - map->r_xprt = xprt_get(xprt); + map->r_xprt = xprt; map->r_status = -EIO; switch (bind_version) { -- cgit v1.2.3-70-g09d2 From 94f826b8076e2cb92242061e92f21b5baa3eccc2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Mar 2012 09:53:52 +0000 Subject: net: fix a potential rcu_read_lock() imbalance in rt6_fill_node() Commit f2c31e32b378 (net: fix NULL dereferences in check_peer_redir() ) added a regression in rt6_fill_node(), leading to rcu_read_lock() imbalance. Thats because NLA_PUT() can make a jump to nla_put_failure label. Fix this by using nla_put() Many thanks to Ben Greear for his help Reported-by: Ben Greear Reported-by: Dave Jones Signed-off-by: Eric Dumazet Tested-by: Ben Greear Signed-off-by: David S. Miller --- net/ipv6/route.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 24c456e8aa1..496b62712fe 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2474,8 +2474,12 @@ static int rt6_fill_node(struct net *net, rcu_read_lock(); n = dst_get_neighbour_noref(&rt->dst); - if (n) - NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key); + if (n) { + if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) { + rcu_read_unlock(); + goto nla_put_failure; + } + } rcu_read_unlock(); if (rt->dst.dev) -- cgit v1.2.3-70-g09d2 From 4e7b2f1454382b220f792a7fbcbebd0985187161 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 27 Mar 2012 15:55:32 +0000 Subject: net/ipv4: fix IPv4 multicast over network namespaces When using multicast over a local bridge feeding a number of LXC guests using veth, the LXC guests are unable to get a response from other guests when pinging 224.0.0.1. Multicast packets did not appear to be getting delivered to the network namespaces of the guest hosts, and further inspection showed that the incoming route was pointing to the loopback device of the host, not the guest. This lead to the wrong network namespace being picked up by sockets (like ICMP). Fix this by using the correct network namespace when creating the inbound route entry. Signed-off-by: Benjamin LaHaise Signed-off-by: David S. Miller --- net/ipv4/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 12ccf880eb8..3b110a46362 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2042,7 +2042,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (err < 0) goto e_err; } - rth = rt_dst_alloc(init_net.loopback_dev, + rth = rt_dst_alloc(dev_net(dev)->loopback_dev, IN_DEV_CONF_GET(in_dev, NOPOLICY), false); if (!rth) goto e_nobufs; -- cgit v1.2.3-70-g09d2 From 3b9785c6b0ff37ac4ef5085b38756283da84dceb Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 27 Mar 2012 15:55:44 +0000 Subject: net/core: dev_forward_skb() should clear skb_iif While investigating another bug, I found that the code on the incoming path in __netif_receive_skb will only set skb->skb_iif if it is already 0. When dev_forward_skb() is used in the case of interfaces like veth, skb_iif may already have been set. Making dev_forward_skb() cause the packet to look like a newly received packet would seem to the the correct behaviour here, as otherwise the wrong incoming interface can be reported for such a packet. Signed-off-by: Benjamin LaHaise Signed-off-by: David S. Miller --- net/core/dev.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 452db7090d1..723a4065a00 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1597,6 +1597,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) kfree_skb(skb); return NET_RX_DROP; } + skb->skb_iif = 0; skb_set_dev(skb, dev); skb->tstamp.tv64 = 0; skb->pkt_type = PACKET_HOST; -- cgit v1.2.3-70-g09d2 From 6e4aff103774d6ee937a1dba9b1b4bf89100e7f6 Mon Sep 17 00:00:00 2001 From: Santosh Nayak Date: Thu, 1 Mar 2012 22:46:36 +0530 Subject: Bluetooth: Fix Endian Bug. Fix network to host endian conversion for L2CAP chan id. Signed-off-by: Santosh Nayak Acked-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c4fe583b0af..29122ed28ea 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -82,7 +82,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } if (la.l2_cid) - err = l2cap_add_scid(chan, la.l2_cid); + err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid)); else err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm); @@ -123,7 +123,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al if (la.l2_cid && la.l2_psm) return -EINVAL; - err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); + err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), + &la.l2_bdaddr); if (err) return err; -- cgit v1.2.3-70-g09d2 From 94324962066231a938564bebad0f941cd2d06bb2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 15 Mar 2012 14:48:41 +0100 Subject: Bluetooth: hci_core: fix NULL-pointer dereference at unregister Make sure hci_dev_open returns immediately if hci_dev_unregister has been called. This fixes a race between hci_dev_open and hci_dev_unregister which can lead to a NULL-pointer dereference. Bug is 100% reproducible using hciattach and a disconnected serial port: 0. # hciattach -n /dev/ttyO1 any noflow 1. hci_dev_open called from hci_power_on grabs req lock 2. hci_init_req executes but device fails to initialise (times out eventually) 3. hci_dev_open is called from hci_sock_ioctl and sleeps on req lock 4. hci_uart_tty_close calls hci_dev_unregister and sleeps on req lock in hci_dev_do_close 5. hci_dev_open (1) releases req lock 6. hci_dev_do_close grabs req lock and returns as device is not up 7. hci_dev_unregister sleeps in destroy_workqueue 8. hci_dev_open (3) grabs req lock, calls hci_init_req and eventually sleeps 9. hci_dev_unregister finishes, while hci_dev_open is still running... [ 79.627136] INFO: trying to register non-static key. [ 79.632354] the code is fine but needs lockdep annotation. [ 79.638122] turning off the locking correctness validator. [ 79.643920] [] (unwind_backtrace+0x0/0xf8) from [] (__lock_acquire+0x1590/0x1ab0) [ 79.653594] [] (__lock_acquire+0x1590/0x1ab0) from [] (lock_acquire+0x9c/0x128) [ 79.663085] [] (lock_acquire+0x9c/0x128) from [] (run_timer_softirq+0x150/0x3ac) [ 79.672668] [] (run_timer_softirq+0x150/0x3ac) from [] (__do_softirq+0xd4/0x22c) [ 79.682281] [] (__do_softirq+0xd4/0x22c) from [] (irq_exit+0x8c/0x94) [ 79.690856] [] (irq_exit+0x8c/0x94) from [] (handle_IRQ+0x34/0x84) [ 79.699157] [] (handle_IRQ+0x34/0x84) from [] (omap3_intc_handle_irq+0x48/0x4c) [ 79.708648] [] (omap3_intc_handle_irq+0x48/0x4c) from [] (__irq_usr+0x3c/0x60) [ 79.718048] Exception stack(0xcf281fb0 to 0xcf281ff8) [ 79.723358] 1fa0: 0001e6a0 be8dab00 0001e698 00036698 [ 79.731933] 1fc0: 0002df98 0002df38 0000001f 00000000 b6f234d0 00000000 00000004 00000000 [ 79.740509] 1fe0: 0001e6f8 be8d6aa0 be8dac50 0000aab8 80000010 ffffffff [ 79.747497] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 79.756011] pgd = cf3b4000 [ 79.758850] [00000000] *pgd=8f0c7831, *pte=00000000, *ppte=00000000 [ 79.765502] Internal error: Oops: 80000007 [#1] [ 79.770294] Modules linked in: [ 79.773529] CPU: 0 Tainted: G W (3.3.0-rc6-00002-gb5d5c87 #421) [ 79.781066] PC is at 0x0 [ 79.783721] LR is at run_timer_softirq+0x16c/0x3ac [ 79.788787] pc : [<00000000>] lr : [] psr: 60000113 [ 79.788787] sp : cf281ee0 ip : 00000000 fp : cf280000 [ 79.800903] r10: 00000004 r9 : 00000100 r8 : b6f234d0 [ 79.806427] r7 : c0519c28 r6 : cf093488 r5 : c0561a00 r4 : 00000000 [ 79.813323] r3 : 00000000 r2 : c054eee0 r1 : 00000001 r0 : 00000000 [ 79.820190] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 79.827728] Control: 10c5387d Table: 8f3b4019 DAC: 00000015 [ 79.833801] Process gpsd (pid: 1265, stack limit = 0xcf2802e8) [ 79.839965] Stack: (0xcf281ee0 to 0xcf282000) [ 79.844573] 1ee0: 00000002 00000000 c0040a24 00000000 00000002 cf281f08 00200200 00000000 [ 79.853210] 1f00: 00000000 cf281f18 cf281f08 00000000 00000000 00000000 cf281f18 cf281f18 [ 79.861816] 1f20: 00000000 00000001 c056184c 00000000 00000001 b6f234d0 c0561848 00000004 [ 79.870452] 1f40: cf280000 c003a3b8 c051e79c 00000001 00000000 00000100 3fa9e7b8 0000000a [ 79.879089] 1f60: 00000025 cf280000 00000025 00000000 00000000 b6f234d0 00000000 00000004 [ 79.887756] 1f80: 00000000 c003a924 c053ad38 c0013a50 fa200000 cf281fb0 ffffffff c0008530 [ 79.896362] 1fa0: 0001e6a0 0000aab8 80000010 c037499c 0001e6a0 be8dab00 0001e698 00036698 [ 79.904998] 1fc0: 0002df98 0002df38 0000001f 00000000 b6f234d0 00000000 00000004 00000000 [ 79.913665] 1fe0: 0001e6f8 be8d6aa0 be8dac50 0000aab8 80000010 ffffffff 00fbf700 04ffff00 [ 79.922302] [] (run_timer_softirq+0x16c/0x3ac) from [] (__do_softirq+0xd4/0x22c) [ 79.931945] [] (__do_softirq+0xd4/0x22c) from [] (irq_exit+0x8c/0x94) [ 79.940582] [] (irq_exit+0x8c/0x94) from [] (handle_IRQ+0x34/0x84) [ 79.948913] [] (handle_IRQ+0x34/0x84) from [] (omap3_intc_handle_irq+0x48/0x4c) [ 79.958404] [] (omap3_intc_handle_irq+0x48/0x4c) from [] (__irq_usr+0x3c/0x60) [ 79.967773] Exception stack(0xcf281fb0 to 0xcf281ff8) [ 79.973083] 1fa0: 0001e6a0 be8dab00 0001e698 00036698 [ 79.981658] 1fc0: 0002df98 0002df38 0000001f 00000000 b6f234d0 00000000 00000004 00000000 [ 79.990234] 1fe0: 0001e6f8 be8d6aa0 be8dac50 0000aab8 80000010 ffffffff [ 79.997161] Code: bad PC value [ 80.000396] ---[ end trace 6f6739840475f9ee ]--- [ 80.005279] Kernel panic - not syncing: Fatal exception in interrupt Cc: stable Signed-off-by: Johan Hovold Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 344b0f97282..8f928f75e85 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -92,6 +92,7 @@ enum { HCI_SERVICE_CACHE, HCI_LINK_KEYS, HCI_DEBUG_KEYS, + HCI_UNREGISTER, HCI_LE_SCAN, HCI_SSP_ENABLED, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 59ec99eb739..2054c1321c8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -666,6 +666,11 @@ int hci_dev_open(__u16 dev) hci_req_lock(hdev); + if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) { + ret = -ENODEV; + goto done; + } + if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) { ret = -ERFKILL; goto done; @@ -1850,6 +1855,8 @@ void hci_unregister_dev(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); + set_bit(HCI_UNREGISTER, &hdev->dev_flags); + write_lock(&hci_dev_list_lock); list_del(&hdev->list); write_unlock(&hci_dev_list_lock); -- cgit v1.2.3-70-g09d2 From 8d7e1c7f7e5f9fe8f6279752fc33fcb77afd5001 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 23 Mar 2012 09:42:15 +0200 Subject: Bluetooth: Fix memory leaks due to chan refcnt When we queue delayed work we hold(chan) and delayed work shall put(chan) after execution. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3e450f4a312..38d934a1124 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1309,6 +1309,7 @@ static void l2cap_monitor_timeout(struct work_struct *work) if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return; } @@ -1317,6 +1318,7 @@ static void l2cap_monitor_timeout(struct work_struct *work) l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_retrans_timeout(struct work_struct *work) @@ -1336,6 +1338,7 @@ static void l2cap_retrans_timeout(struct work_struct *work) l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_drop_acked_frames(struct l2cap_chan *chan) -- cgit v1.2.3-70-g09d2 From 9ffc93f203c18a70623f21950f1dd473c9ec48cd Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 28 Mar 2012 18:30:03 +0100 Subject: Remove all #inclusions of asm/system.h Remove all #inclusions of asm/system.h preparatory to splitting and killing it. Performed with the following command: perl -p -i -e 's!^#\s*include\s*.*\n!!' `grep -Irl '^#\s*include\s*' *` Signed-off-by: David Howells --- arch/um/include/asm/fixmap.h | 1 - drivers/acpi/processor_driver.c | 1 - drivers/atm/eni.c | 1 - drivers/atm/firestream.c | 1 - drivers/atm/horizon.c | 1 - drivers/atm/idt77105.c | 1 - drivers/atm/iphase.c | 1 - drivers/atm/suni.c | 1 - drivers/atm/zatm.c | 1 - drivers/block/floppy.c | 1 - drivers/block/hd.c | 1 - drivers/block/nbd.c | 1 - drivers/block/xd.c | 1 - drivers/bluetooth/bt3c_cs.c | 1 - drivers/bluetooth/btuart_cs.c | 1 - drivers/bluetooth/dtl1_cs.c | 1 - drivers/char/apm-emulation.c | 1 - drivers/char/ds1302.c | 1 - drivers/char/efirtc.c | 1 - drivers/char/genrtc.c | 1 - drivers/char/hpet.c | 1 - drivers/char/ipmi/ipmi_devintf.c | 1 - drivers/char/ipmi/ipmi_msghandler.c | 1 - drivers/char/ipmi/ipmi_si_intf.c | 1 - drivers/char/lp.c | 1 - drivers/char/mbcs.c | 1 - drivers/char/mspec.c | 1 - drivers/char/mwave/3780i.c | 1 - drivers/char/nvram.c | 1 - drivers/char/nwflash.c | 1 - drivers/char/pcmcia/synclink_cs.c | 1 - drivers/char/rtc.c | 1 - drivers/char/sonypi.c | 1 - drivers/char/xilinx_hwicap/xilinx_hwicap.c | 1 - drivers/cpufreq/omap-cpufreq.c | 1 - drivers/cpufreq/powernow-k7.c | 1 - drivers/firewire/core-cdev.c | 1 - drivers/firewire/core-device.c | 1 - drivers/firewire/core-topology.c | 1 - drivers/firewire/ohci.c | 1 - drivers/firewire/sbp2.c | 1 - drivers/i2c/busses/i2c-acorn.c | 1 - drivers/ide/ide-cs.c | 1 - drivers/ide/qd65xx.c | 1 - drivers/infiniband/hw/ehca/ehca_reqs.c | 1 - drivers/input/joydev.c | 1 - drivers/input/joystick/amijoy.c | 1 - drivers/input/mouse/amimouse.c | 1 - drivers/input/mouse/atarimouse.c | 1 - drivers/input/serio/hp_sdc.c | 1 - drivers/input/serio/maceps2.c | 1 - drivers/input/serio/rpckbd.c | 1 - drivers/input/serio/sa1111ps2.c | 1 - drivers/isdn/hardware/avm/avm_cs.c | 1 - drivers/isdn/hisax/avma1_cs.c | 1 - drivers/isdn/hisax/elsa_cs.c | 1 - drivers/isdn/hisax/sedlbauer_cs.c | 1 - drivers/isdn/hisax/teles_cs.c | 1 - drivers/isdn/i4l/isdn_bsdcomp.c | 1 - drivers/isdn/pcbit/layer2.c | 1 - drivers/macintosh/macio-adb.c | 1 - drivers/macintosh/therm_adt746x.c | 1 - drivers/macintosh/therm_pm72.c | 1 - drivers/macintosh/therm_windtunnel.c | 1 - drivers/macintosh/via-cuda.c | 1 - drivers/macintosh/via-macii.c | 1 - drivers/macintosh/via-pmu.c | 1 - drivers/macintosh/via-pmu68k.c | 1 - drivers/macintosh/windfarm_lm75_sensor.c | 1 - drivers/macintosh/windfarm_pm121.c | 1 - drivers/macintosh/windfarm_pm81.c | 1 - drivers/macintosh/windfarm_pm91.c | 1 - drivers/macintosh/windfarm_smu_controls.c | 1 - drivers/macintosh/windfarm_smu_sensors.c | 1 - drivers/media/dvb/dvb-core/dmxdev.c | 1 - drivers/media/dvb/firewire/firedtv-fw.c | 1 - drivers/media/dvb/ttpci/av7110.c | 1 - drivers/media/media-devnode.c | 1 - drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/v4l2-common.c | 1 - drivers/media/video/v4l2-dev.c | 1 - drivers/message/i2o/i2o_scsi.c | 1 - drivers/mfd/mcp-core.c | 1 - drivers/mfd/mcp-sa11x0.c | 1 - drivers/misc/sgi-xp/xp.h | 1 - drivers/mmc/card/block.c | 1 - drivers/mtd/devices/pmc551.c | 1 - drivers/mtd/devices/slram.c | 1 - drivers/mtd/maps/pcmciamtd.c | 1 - drivers/mtd/nand/bcm_umi_nand.c | 1 - drivers/net/appletalk/cops.c | 1 - drivers/net/appletalk/ltpc.c | 1 - drivers/net/arcnet/com20020_cs.c | 1 - drivers/net/bonding/bond_main.c | 1 - drivers/net/can/slcan.c | 1 - drivers/net/cris/eth_v10.c | 1 - drivers/net/ethernet/3com/3c574_cs.c | 1 - drivers/net/ethernet/3com/3c589_cs.c | 1 - drivers/net/ethernet/8390/3c503.c | 1 - drivers/net/ethernet/8390/ac3200.c | 1 - drivers/net/ethernet/8390/apne.c | 1 - drivers/net/ethernet/8390/ax88796.c | 1 - drivers/net/ethernet/8390/axnet_cs.c | 1 - drivers/net/ethernet/8390/e2100.c | 1 - drivers/net/ethernet/8390/es3210.c | 1 - drivers/net/ethernet/8390/etherh.c | 1 - drivers/net/ethernet/8390/hp-plus.c | 1 - drivers/net/ethernet/8390/hp.c | 1 - drivers/net/ethernet/8390/lib8390.c | 1 - drivers/net/ethernet/8390/lne390.c | 1 - drivers/net/ethernet/8390/mac8390.c | 1 - drivers/net/ethernet/8390/ne-h8300.c | 1 - drivers/net/ethernet/8390/ne.c | 1 - drivers/net/ethernet/8390/ne2.c | 1 - drivers/net/ethernet/8390/ne2k-pci.c | 1 - drivers/net/ethernet/8390/ne3210.c | 1 - drivers/net/ethernet/8390/pcnet_cs.c | 1 - drivers/net/ethernet/8390/smc-mca.c | 1 - drivers/net/ethernet/8390/smc-ultra.c | 1 - drivers/net/ethernet/8390/smc-ultra32.c | 1 - drivers/net/ethernet/8390/stnic.c | 1 - drivers/net/ethernet/8390/wd.c | 1 - drivers/net/ethernet/8390/zorro8390.c | 1 - drivers/net/ethernet/alteon/acenic.c | 1 - drivers/net/ethernet/amd/7990.c | 1 - drivers/net/ethernet/amd/am79c961a.c | 1 - drivers/net/ethernet/amd/amd8111e.c | 1 - drivers/net/ethernet/amd/declance.c | 1 - drivers/net/ethernet/amd/hplance.c | 1 - drivers/net/ethernet/amd/mvme147.c | 1 - drivers/net/ethernet/amd/nmclan_cs.c | 1 - drivers/net/ethernet/amd/sunlance.c | 1 - drivers/net/ethernet/broadcom/tg3.c | 1 - drivers/net/ethernet/cirrus/cs89x0.c | 1 - drivers/net/ethernet/cirrus/mac89x0.c | 1 - drivers/net/ethernet/dlink/de600.c | 1 - drivers/net/ethernet/dlink/de620.c | 1 - drivers/net/ethernet/fujitsu/at1700.c | 1 - drivers/net/ethernet/fujitsu/eth16i.c | 1 - drivers/net/ethernet/fujitsu/fmvj18x_cs.c | 1 - drivers/net/ethernet/i825xx/3c507.c | 1 - drivers/net/ethernet/i825xx/3c527.c | 1 - drivers/net/ethernet/i825xx/eepro.c | 1 - drivers/net/ethernet/i825xx/eexpress.c | 1 - drivers/net/ethernet/i825xx/ether1.c | 1 - drivers/net/ethernet/i825xx/znet.c | 1 - drivers/net/ethernet/korina.c | 1 - drivers/net/ethernet/marvell/mv643xx_eth.c | 1 - drivers/net/ethernet/marvell/pxa168_eth.c | 1 - drivers/net/ethernet/natsemi/jazzsonic.c | 1 - drivers/net/ethernet/natsemi/macsonic.c | 1 - drivers/net/ethernet/natsemi/ns83820.c | 1 - drivers/net/ethernet/neterion/s2io.c | 1 - drivers/net/ethernet/nvidia/forcedeth.c | 1 - drivers/net/ethernet/realtek/atp.c | 1 - drivers/net/ethernet/realtek/r8169.c | 1 - drivers/net/ethernet/seeq/ether3.c | 1 - drivers/net/ethernet/seeq/seeq8005.c | 1 - drivers/net/ethernet/smsc/smc91c92_cs.c | 1 - drivers/net/ethernet/sun/cassini.c | 1 - drivers/net/ethernet/sun/sunbmac.c | 1 - drivers/net/ethernet/sun/sungem.c | 1 - drivers/net/ethernet/sun/sunhme.c | 1 - drivers/net/ethernet/sun/sunqe.c | 1 - drivers/net/ethernet/tundra/tsi108_eth.c | 1 - drivers/net/ethernet/xircom/xirc2ps_cs.c | 1 - drivers/net/hamradio/6pack.c | 1 - drivers/net/hamradio/baycom_par.c | 1 - drivers/net/hamradio/bpqether.c | 1 - drivers/net/hamradio/mkiss.c | 1 - drivers/net/hamradio/scc.c | 1 - drivers/net/hamradio/yam.c | 1 - drivers/net/hippi/rrunner.c | 1 - drivers/net/irda/donauboe.c | 1 - drivers/net/loopback.c | 1 - drivers/net/plip/plip.c | 1 - drivers/net/slip/slhc.c | 1 - drivers/net/slip/slip.c | 1 - drivers/net/tokenring/3c359.c | 1 - drivers/net/tokenring/abyss.c | 1 - drivers/net/tokenring/ibmtr_cs.c | 1 - drivers/net/tokenring/lanstreamer.c | 1 - drivers/net/tokenring/madgemc.c | 1 - drivers/net/tokenring/olympic.c | 1 - drivers/net/tokenring/proteon.c | 1 - drivers/net/tokenring/skisa.c | 1 - drivers/net/tokenring/smctr.c | 1 - drivers/net/tokenring/tms380tr.c | 1 - drivers/net/tokenring/tmspci.c | 1 - drivers/net/tun.c | 1 - drivers/net/wan/dlci.c | 1 - drivers/net/wan/dscc4.c | 1 - drivers/net/wan/hd64570.c | 1 - drivers/net/wan/hd64572.c | 1 - drivers/net/wan/lapbether.c | 1 - drivers/net/wan/sdla.c | 1 - drivers/net/wan/x25_asy.c | 1 - drivers/net/wireless/airo.c | 1 - drivers/net/wireless/airo_cs.c | 1 - drivers/net/wireless/atmel.c | 1 - drivers/net/wireless/atmel_cs.c | 1 - drivers/net/wireless/prism54/islpci_mgt.c | 1 - drivers/net/wireless/ray_cs.c | 1 - drivers/net/wireless/wl3501_cs.c | 1 - drivers/nubus/nubus.c | 1 - drivers/parisc/dino.c | 1 - drivers/parisc/iosapic.c | 1 - drivers/parisc/lba_pci.c | 1 - drivers/pcmcia/cs.c | 1 - drivers/pcmcia/i82092.c | 1 - drivers/pcmcia/i82365.c | 1 - drivers/pcmcia/m32r_cfc.c | 1 - drivers/pcmcia/m32r_pcc.c | 1 - drivers/pcmcia/m8xx_pcmcia.c | 1 - drivers/pcmcia/pd6729.c | 1 - drivers/pcmcia/pxa2xx_base.c | 1 - drivers/pcmcia/sa11xx_base.c | 1 - drivers/pcmcia/soc_common.c | 1 - drivers/pcmcia/socket_sysfs.c | 1 - drivers/pcmcia/tcic.c | 1 - drivers/pcmcia/xxs1500_ss.c | 1 - drivers/pnp/pnpbios/bioscalls.c | 1 - drivers/pnp/pnpbios/core.c | 1 - drivers/s390/crypto/ap_bus.c | 1 - drivers/sbus/char/flash.c | 1 - drivers/sbus/char/openprom.c | 1 - drivers/sbus/char/uctrl.c | 1 - drivers/scsi/53c700.c | 1 - drivers/scsi/BusLogic.c | 1 - drivers/scsi/advansys.c | 1 - drivers/scsi/aha152x.c | 1 - drivers/scsi/aha1542.c | 1 - drivers/scsi/aha1740.c | 1 - drivers/scsi/arcmsr/arcmsr_hba.c | 1 - drivers/scsi/arm/acornscsi.c | 1 - drivers/scsi/arm/cumana_1.c | 1 - drivers/scsi/arm/oak.c | 1 - drivers/scsi/atp870u.c | 1 - drivers/scsi/dtc.c | 1 - drivers/scsi/fd_mcs.c | 1 - drivers/scsi/fdomain.c | 1 - drivers/scsi/g_NCR5380.c | 1 - drivers/scsi/gdth.c | 1 - drivers/scsi/ibmmca.c | 1 - drivers/scsi/in2000.c | 1 - drivers/scsi/mac53c94.c | 1 - drivers/scsi/mac_scsi.c | 1 - drivers/scsi/mesh.c | 1 - drivers/scsi/ncr53c8xx.c | 1 - drivers/scsi/nsp32.c | 1 - drivers/scsi/osst.c | 1 - drivers/scsi/pas16.c | 1 - drivers/scsi/qla1280.c | 1 - drivers/scsi/qlogicpti.c | 1 - drivers/scsi/st.c | 1 - drivers/scsi/sun3_scsi.c | 1 - drivers/scsi/sun3_scsi_vme.c | 1 - drivers/scsi/sym53c416.c | 1 - drivers/scsi/t128.c | 1 - drivers/scsi/u14-34f.c | 1 - drivers/scsi/ultrastor.c | 1 - drivers/scsi/wd7000.c | 1 - drivers/spi/spi-omap-uwire.c | 1 - drivers/staging/comedi/drivers.c | 1 - drivers/staging/comedi/drivers/cb_pcidas64.c | 1 - drivers/staging/comedi/drivers/mite.c | 1 - drivers/staging/crystalhd/crystalhd.h | 1 - drivers/staging/crystalhd/crystalhd_lnx.h | 1 - drivers/staging/crystalhd/crystalhd_misc.h | 1 + drivers/staging/et131x/et131x.c | 1 - drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c | 1 - drivers/staging/media/go7007/go7007-driver.c | 1 - drivers/staging/media/go7007/go7007-i2c.c | 1 - drivers/staging/media/go7007/go7007-v4l2.c | 1 - drivers/staging/media/go7007/snd-go7007.c | 1 - drivers/staging/media/lirc/lirc_serial.c | 1 - drivers/staging/media/lirc/lirc_sir.c | 1 - drivers/staging/panel/panel.c | 1 - drivers/staging/sbe-2t3e3/io.c | 1 - drivers/staging/telephony/phonedev.c | 1 - drivers/staging/tidspbridge/include/dspbridge/host_os.h | 1 - drivers/staging/wlags49_h2/wl_cs.c | 1 - drivers/staging/wlags49_h2/wl_main.c | 3 +-- drivers/staging/wlags49_h2/wl_netdev.c | 3 +-- drivers/staging/wlags49_h2/wl_pci.c | 1 - drivers/staging/wlags49_h2/wl_util.c | 3 +-- drivers/tty/amiserial.c | 1 - drivers/tty/isicom.c | 1 - drivers/tty/moxa.c | 1 - drivers/tty/mxser.c | 1 - drivers/tty/n_hdlc.c | 1 - drivers/tty/n_tty.c | 1 - drivers/tty/pty.c | 1 - drivers/tty/serial/68328serial.c | 1 - drivers/tty/serial/8250/serial_cs.c | 1 - drivers/tty/serial/crisv10.c | 1 - drivers/tty/serial/dz.c | 1 - drivers/tty/serial/icom.c | 1 - drivers/tty/serial/msm_serial_hs.c | 1 - drivers/tty/serial/zs.c | 1 - drivers/tty/synclink.c | 1 - drivers/tty/synclink_gt.c | 1 - drivers/tty/synclinkmp.c | 1 - drivers/tty/tty_io.c | 1 - drivers/tty/tty_ioctl.c | 1 - drivers/tty/vt/vt.c | 1 - drivers/usb/gadget/amd5536udc.c | 1 - drivers/usb/gadget/at91_udc.c | 1 - drivers/usb/gadget/dummy_hcd.c | 1 - drivers/usb/gadget/fsl_udc_core.c | 1 - drivers/usb/gadget/goku_udc.c | 1 - drivers/usb/gadget/langwell_udc.c | 1 - drivers/usb/gadget/mv_udc_core.c | 1 - drivers/usb/gadget/net2272.c | 1 - drivers/usb/gadget/net2280.c | 1 - drivers/usb/gadget/omap_udc.c | 1 - drivers/usb/gadget/printer.c | 1 - drivers/usb/gadget/pxa25x_udc.c | 1 - drivers/usb/gadget/rndis.c | 1 - drivers/usb/gadget/s3c2410_udc.c | 1 - drivers/usb/host/ehci-hcd.c | 1 - drivers/usb/host/isp116x-hcd.c | 1 - drivers/usb/host/isp1362-hcd.c | 1 - drivers/usb/host/ohci-hcd.c | 1 - drivers/usb/host/oxu210hp-hcd.c | 1 - drivers/usb/host/sl811-hcd.c | 1 - drivers/usb/host/u132-hcd.c | 1 - drivers/usb/host/uhci-hcd.c | 1 - drivers/video/amifb.c | 1 - drivers/video/bt431.h | 1 - drivers/video/bt455.h | 1 - drivers/video/console/fbcon.c | 1 - drivers/video/console/newport_con.c | 1 - drivers/video/cyber2000fb.c | 1 - drivers/video/dnfb.c | 1 - drivers/video/neofb.c | 1 - drivers/video/pmag-ba-fb.c | 1 - drivers/video/pmagb-b-fb.c | 1 - drivers/video/q40fb.c | 1 - drivers/video/savage/savagefb_driver.c | 1 - drivers/virtio/config.c | 1 - drivers/watchdog/advantechwdt.c | 1 - drivers/watchdog/alim7101_wdt.c | 1 - drivers/watchdog/booke_wdt.c | 1 - drivers/watchdog/eurotechwdt.c | 1 - drivers/watchdog/ib700wdt.c | 1 - drivers/watchdog/it87_wdt.c | 1 - drivers/watchdog/machzwd.c | 1 - drivers/watchdog/pc87413_wdt.c | 1 - drivers/watchdog/sbc60xxwdt.c | 1 - drivers/watchdog/sbc7240_wdt.c | 1 - drivers/watchdog/sbc8360.c | 1 - drivers/watchdog/sbc_fitpc2_wdt.c | 1 - drivers/watchdog/sc520_wdt.c | 1 - drivers/watchdog/smsc37b787_wdt.c | 1 - drivers/watchdog/w83627hf_wdt.c | 1 - drivers/watchdog/w83697hf_wdt.c | 1 - drivers/watchdog/w83697ug_wdt.c | 1 - drivers/watchdog/w83877f_wdt.c | 1 - drivers/watchdog/w83977f_wdt.c | 1 - drivers/watchdog/wdt.c | 1 - drivers/watchdog/wdt977.c | 1 - drivers/watchdog/wdt_pci.c | 1 - fs/binfmt_aout.c | 1 - fs/binfmt_flat.c | 1 - fs/coda/inode.c | 1 - fs/coda/psdev.c | 1 - fs/coda/upcall.c | 1 - fs/eventpoll.c | 1 - fs/jbd2/commit.c | 1 - fs/jbd2/journal.c | 1 - fs/ncpfs/file.c | 1 - fs/ncpfs/inode.c | 1 - fs/ncpfs/mmap.c | 1 - fs/nfs/client.c | 1 - fs/nfs/direct.c | 1 - fs/nfs/file.c | 1 - fs/nfs/getroot.c | 1 - fs/nfs/inode.c | 1 - fs/nfs/read.c | 1 - fs/nfs/super.c | 1 - fs/proc/inode.c | 1 - fs/reiserfs/journal.c | 1 - fs/ufs/inode.c | 1 - fs/ufs/super.c | 1 - fs/xfs/xfs_buf.h | 1 - include/acpi/platform/aclinux.h | 1 - include/asm-generic/atomic.h | 1 - include/linux/cnt32_to_63.h | 1 - include/linux/debug_locks.h | 1 - include/linux/efi.h | 1 - include/linux/ide.h | 1 - include/linux/interrupt.h | 1 - include/linux/lsm_audit.h | 1 - include/linux/mtd/map.h | 1 - include/linux/parport.h | 1 - include/linux/rwsem.h | 1 - include/linux/sched.h | 1 - include/linux/skbuff.h | 1 - include/linux/spinlock.h | 1 - include/linux/stop_machine.h | 1 - include/linux/tty.h | 1 - include/linux/wait.h | 1 - kernel/debug/debug_core.c | 1 - kernel/debug/kdb/kdb_bt.c | 1 - kernel/dma.c | 1 - kernel/kexec.c | 1 - kernel/rwsem.c | 1 - kernel/sysctl.c | 1 - lib/llist.c | 1 - lib/raid6/altivec.uc | 1 - net/802/fc.c | 1 - net/802/fddi.c | 1 - net/802/hippi.c | 1 - net/802/tr.c | 1 - net/atm/clip.c | 1 - net/ax25/af_ax25.c | 1 - net/ax25/ax25_addr.c | 1 - net/ax25/ax25_dev.c | 1 - net/ax25/ax25_ds_in.c | 1 - net/ax25/ax25_ds_subr.c | 1 - net/ax25/ax25_ds_timer.c | 1 - net/ax25/ax25_iface.c | 1 - net/ax25/ax25_in.c | 1 - net/ax25/ax25_ip.c | 1 - net/ax25/ax25_out.c | 1 - net/ax25/ax25_route.c | 1 - net/ax25/ax25_std_in.c | 1 - net/ax25/ax25_std_subr.c | 1 - net/ax25/ax25_std_timer.c | 1 - net/ax25/ax25_subr.c | 1 - net/ax25/ax25_timer.c | 1 - net/ax25/ax25_uid.c | 1 - net/bluetooth/bnep/sock.c | 1 - net/bluetooth/cmtp/sock.c | 1 - net/bluetooth/hci_conn.c | 1 - net/bluetooth/hci_core.c | 1 - net/bluetooth/hci_event.c | 1 - net/bluetooth/hci_sock.c | 1 - net/bluetooth/l2cap_core.c | 1 - net/bluetooth/rfcomm/sock.c | 1 - net/bluetooth/sco.c | 1 - net/core/datagram.c | 1 - net/core/dev.c | 1 - net/core/filter.c | 1 - net/core/gen_estimator.c | 1 - net/core/rtnetlink.c | 1 - net/core/scm.c | 1 - net/core/skbuff.c | 1 - net/core/sock.c | 1 - net/core/utils.c | 1 - net/decnet/af_decnet.c | 1 - net/decnet/dn_dev.c | 1 - net/decnet/dn_nsp_in.c | 1 - net/decnet/dn_nsp_out.c | 1 - net/econet/af_econet.c | 1 - net/ethernet/eth.c | 1 - net/ipv4/af_inet.c | 1 - net/ipv4/arp.c | 1 - net/ipv4/devinet.c | 1 - net/ipv4/fib_frontend.c | 1 - net/ipv4/fib_semantics.c | 1 - net/ipv4/fib_trie.c | 1 - net/ipv4/icmp.c | 1 - net/ipv4/igmp.c | 1 - net/ipv4/ip_input.c | 1 - net/ipv4/ip_output.c | 1 - net/ipv4/ipmr.c | 1 - net/ipv4/ping.c | 1 - net/ipv4/route.c | 1 - net/ipv4/udp.c | 1 - net/ipv6/af_inet6.c | 1 - net/ipv6/icmp.c | 1 - net/ipv6/ip6mr.c | 1 - net/irda/irlan/irlan_client.c | 1 - net/irda/irlan/irlan_common.c | 1 - net/irda/irlan/irlan_provider.c | 1 - net/irda/timer.c | 1 - net/lapb/lapb_iface.c | 1 - net/lapb/lapb_in.c | 1 - net/lapb/lapb_out.c | 1 - net/lapb/lapb_subr.c | 1 - net/lapb/lapb_timer.c | 1 - net/netfilter/ipvs/ip_vs_app.c | 1 - net/netfilter/ipvs/ip_vs_proto.c | 1 - net/netfilter/nfnetlink.c | 1 - net/netrom/af_netrom.c | 1 - net/netrom/nr_dev.c | 1 - net/netrom/nr_in.c | 1 - net/netrom/nr_out.c | 1 - net/netrom/nr_route.c | 1 - net/netrom/nr_subr.c | 1 - net/netrom/nr_timer.c | 1 - net/openvswitch/datapath.c | 1 - net/packet/af_packet.c | 1 - net/rose/af_rose.c | 1 - net/rose/rose_dev.c | 1 - net/rose/rose_in.c | 1 - net/rose/rose_link.c | 1 - net/rose/rose_out.c | 1 - net/rose/rose_route.c | 1 - net/rose/rose_subr.c | 1 - net/rose/rose_timer.c | 1 - net/sunrpc/clnt.c | 1 - security/selinux/include/avc.h | 1 - sound/oss/os.h | 1 - sound/oss/vidc.c | 1 - sound/oss/waveartist.c | 1 - sound/pci/asihpi/hpios.h | 1 - sound/pci/aw2/aw2-saa7146.c | 1 - 510 files changed, 4 insertions(+), 512 deletions(-) (limited to 'net') diff --git a/arch/um/include/asm/fixmap.h b/arch/um/include/asm/fixmap.h index 69c0252345f..21a423bae5e 100644 --- a/arch/um/include/asm/fixmap.h +++ b/arch/um/include/asm/fixmap.h @@ -2,7 +2,6 @@ #define __UM_FIXMAP_H #include -#include #include #include #include diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 2801b418d7b..d4d9cb7e016 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -46,7 +46,6 @@ #include #include -#include #include #include #include diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 6ff612d099c..2059ee460b0 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 5072f8ac16f..86fed1b9169 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index b81210330ac..75fd691cd43 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index 487a5473985..45d506363ab 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 9e373ba2030..d4386019af5 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -56,7 +56,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index 90f1ccca9e5..02159345566 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index d889f56e8d8..abe4e20b076 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 744f078f4dd..76a08236430 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -202,7 +202,6 @@ static int slow_floppy; #include #include -#include static int FLOPPY_IRQ = 6; static int FLOPPY_DMA = 2; diff --git a/drivers/block/hd.c b/drivers/block/hd.c index b52c9ca146f..bf397bf108b 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -44,7 +44,6 @@ #define HD_IRQ 14 #define REALLY_SLOW_IO -#include #include #include diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index c3f0ee16594..c7ba11f9b20 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -34,7 +34,6 @@ #include #include -#include #include #include diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 51a972704db..ff540520bad 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -52,7 +52,6 @@ #include #include -#include #include #include diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 9c09d6f05dc..308c8599ab5 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 194224d07f7..c4fc2f3fc32 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 049c0594a76..6e8d9618968 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index f4837a893df..57501ca9204 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -31,7 +31,6 @@ #include #include -#include /* * The apm_bios device is one of the misc char devices. diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c index ed8303f9890..7d34b203718 100644 --- a/drivers/char/ds1302.c +++ b/drivers/char/ds1302.c @@ -24,7 +24,6 @@ #include #include -#include #include #if defined(CONFIG_M32R) #include diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 53c524e7b82..a082d00b0f1 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -37,7 +37,6 @@ #include #include -#include #define EFI_RTC_VERSION "0.4" diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index f773a9dd14f..21cb980f115 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -56,7 +56,6 @@ #include #include -#include #include /* diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 0833896cf6f..3845ab44c33 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -36,7 +36,6 @@ #include #include -#include #include #include diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 2aa3977aae5..9eb360ff8ca 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 58c0e6387cf..c90e9390b78 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 50fcf9c0456..f9fdc114b31 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -41,7 +41,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/lp.c b/drivers/char/lp.c index f4348560706..0fbf1a776b5 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -135,7 +135,6 @@ #include #include -#include /* if you have more than 8 printers, remember to increase LP_NO */ #define LP_NO 8 diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 1aeaaba680d..47ff7e470d8 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 5c0d96a820f..8b78750f1ef 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index 492dbfb2efd..881c9e59593 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c @@ -56,7 +56,6 @@ #include #include -#include #include #include "smapi.h" #include "mwavedd.h" diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index eaade8a1ecd..9df78e2cc45 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -111,7 +111,6 @@ #include #include -#include static DEFINE_MUTEX(nvram_mutex); static DEFINE_SPINLOCK(nvram_state_lock); diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index bf586ae1ee8..d45c3345b4a 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -32,7 +32,6 @@ #include #include #include -#include #include /*****************************************************************************/ diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index f6453df4921..0a484b4a1b0 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -60,7 +60,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 872e09a02d2..af9437488b6 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -83,7 +83,6 @@ #include #include -#include #ifdef CONFIG_X86 #include diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 1ee8ce7d276..45713f0e7d6 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -54,7 +54,6 @@ #include #include -#include #include diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index e90e1c74fd4..31ba11ca75e 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -89,7 +89,6 @@ #include #include -#include #ifdef CONFIG_OF /* For open firmware. */ diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 5d04c57aae3..3093ca6152c 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index cf7e1ee005a..334cc2f1e9f 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -27,7 +27,6 @@ #include /* Needed for recalibrate_cpu_khz() */ #include -#include #include #ifdef CONFIG_X86_POWERNOW_K7_ACPI diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 22c6df5f136..2e6b24547e2 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -44,7 +44,6 @@ #include #include -#include #include "core.h" diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index afa7c83bd11..68109e9bb04 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -40,7 +40,6 @@ #include #include -#include #include "core.h" diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 255646ffc35..0de83508f32 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -31,7 +31,6 @@ #include #include -#include #include "core.h" diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 187b3f2e797..2b5460075a9 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -46,7 +46,6 @@ #include #include -#include #ifdef CONFIG_PPC_PMAC #include diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 000a29ffeda..b7e65d7eab6 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -52,7 +52,6 @@ #include #include -#include #include #include diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index 86796488ef4..ed9f48d566d 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -19,7 +19,6 @@ #include #include -#include #define FORCE_ONES 0xdc #define SCL 0x02 diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index d2f3db3cf3e..28e344ea514 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index 8bbfe5557c7..e03f4f19c1d 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #define DRV_NAME "qd65xx" diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 9a3fbfca9b4..fd05f48f6b0 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -42,7 +42,6 @@ */ -#include #include "ehca_classes.h" #include "ehca_tools.h" #include "ehca_qes.h" diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index c24ec2d5f92..26043cc6a01 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -13,7 +13,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index 0bc86204213..24044dacbf7 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -35,7 +35,6 @@ #include #include -#include #include #include diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index ff5f61a0fd3..5fa99341a39 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index 5c4a692bf73..d1c43236b12 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index be3316073ae..09a089996de 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -71,7 +71,6 @@ #include #include #include -#include /* Machine-specific abstraction */ diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 558200e96d0..61da763b120 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -21,7 +21,6 @@ #include #include -#include #include #include diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 8b44ddc8041..d8aac177307 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -39,7 +39,6 @@ #include #include #include -#include MODULE_AUTHOR("Vojtech Pavlik, Russell King"); MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 44fc8b4bcd8..e3c85fafe93 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -20,7 +20,6 @@ #include #include -#include #include diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index 44b50cc645e..c21353d8e91 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 33e3c94887d..c644557ae61 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index fe254e74a85..a8c4d3fc9a6 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 68f50495d16..f0dfc0c976e 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index bfe94284b0d..4deac451807 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index 7f3c54d4047..c59e8d2c067 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -69,7 +69,6 @@ #include /* used in new tty drivers */ #include -#include #include #include diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 682911f8113..a18e639b40d 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -36,7 +36,6 @@ #include -#include #include diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index b6ef8f59076..87de8d9bcfa 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index c60d025044e..fc71723cbc4 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #undef DEBUG diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 0ff92c20800..97cfc5ac9fd 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -127,7 +127,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 46c4e95f10d..3b4a157714b 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 971bc9582a5..86511c570dd 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -26,7 +26,6 @@ #include #endif #include -#include #include static volatile unsigned char __iomem *via; diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index c9570fcf1cc..3725f088f17 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -34,7 +34,6 @@ #include #include #include -#include static volatile unsigned char *via; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 6cccd60c594..22b8ce4191c 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index aeb30d07d5a..a00ee41f057 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -37,7 +37,6 @@ #include #include -#include #include #include diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 647c6add219..4d6a90a1372 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index 30e6195e19d..04067e073aa 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c @@ -215,7 +215,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 749d174b0dc..fc13d0f2663 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -107,7 +107,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 34427323512..a9430ed4f36 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index 43137b421f9..3c2be5193fd 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index 3c193504bb8..1cc4e4953d8 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index e4b5c03ae51..73970cd97af 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "dmxdev.h" static int debug; diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c index 864b6274c72..e24ec539a5f 100644 --- a/drivers/media/dvb/firewire/firedtv-fw.c +++ b/drivers/media/dvb/firewire/firedtv-fw.c @@ -20,7 +20,6 @@ #include #include -#include #include diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 6ecbcf61487..4bd8bd56bef 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -53,7 +53,6 @@ #include #include -#include #include diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 7b42ace419d..04d6d541d86 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -40,7 +40,6 @@ #include #include #include -#include #include diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 06f3d78389b..52d5dd71032 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -54,7 +54,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 5c6100fb407..1baec839330 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -55,7 +55,6 @@ #include #endif #include -#include #include #include #include diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 96e9615663e..8546f812944 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index c8ed7b63fdf..1d31d7284cb 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -57,7 +57,6 @@ #include #include -#include #include #include diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 86cc3f7841c..32c82de81ad 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -20,7 +20,6 @@ #include #include -#include #define to_mcp(d) container_of(d, struct mcp, attached_device) diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 02c53a0766c..4a27c2b9a89 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 851b2f25ce0..c862cd4583c 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -25,7 +25,6 @@ #endif #if defined CONFIG_IA64 -#include #include /* defines is_shub1() and is_shub2() */ #define is_shub() ia64_platform_is("sn2") #endif diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index e5a3c7b6ded..4c3b2847e47 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -41,7 +41,6 @@ #include #include -#include #include #include "queue.h" diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index ecff765579d..5d53c5760a6 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -93,7 +93,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index e585263161b..288594163c2 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -42,7 +42,6 @@ #include #include #include -#include #include diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index e8e9fec2355..0259cf58302 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 50387fd4009..64c9cbaf86a 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -31,7 +31,6 @@ #include #include -#include #include #include diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 9abd4eb86dc..dd5e04813b7 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -70,7 +70,6 @@ static const char *version = #include #include -#include #include #include diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 6057b30417a..0910dce3996 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -229,7 +229,6 @@ static int dma; #include #include -#include #include #include diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c index 980e65c1493..5bed4c4e250 100644 --- a/drivers/net/arcnet/com20020_cs.c +++ b/drivers/net/arcnet/com20020_cs.c @@ -47,7 +47,6 @@ #include #include -#include #define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0730203a19f..d6e85864bee 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 98a5a7d867f..034c16b60e9 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 7cb2785e209..ec03b401620 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -35,7 +35,6 @@ #include /* CRIS_LED_* I/O functions */ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c index e61b2f82ba3..66df9363808 100644 --- a/drivers/net/ethernet/3com/3c574_cs.c +++ b/drivers/net/ethernet/3com/3c574_cs.c @@ -95,7 +95,6 @@ earlier 3Com products. #include #include -#include /*====================================================================*/ diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index b23253b9f74..a556c01e011 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c @@ -50,7 +50,6 @@ #include #include -#include /* To minimize the size of the driver source I only define operating constants if they are used several times. You'll need the manual diff --git a/drivers/net/ethernet/8390/3c503.c b/drivers/net/ethernet/8390/3c503.c index fbab1367505..49d76bd0dc8 100644 --- a/drivers/net/ethernet/8390/3c503.c +++ b/drivers/net/ethernet/8390/3c503.c @@ -54,7 +54,6 @@ static const char version[] = #include #include -#include #include #include "8390.h" diff --git a/drivers/net/ethernet/8390/ac3200.c b/drivers/net/ethernet/8390/ac3200.c index 5337dd0a59b..ccf07942ff6 100644 --- a/drivers/net/ethernet/8390/ac3200.c +++ b/drivers/net/ethernet/8390/ac3200.c @@ -34,7 +34,6 @@ static const char version[] = #include #include -#include #include #include diff --git a/drivers/net/ethernet/8390/apne.c b/drivers/net/ethernet/8390/apne.c index 3ad5d2f9a49..923959275a8 100644 --- a/drivers/net/ethernet/8390/apne.c +++ b/drivers/net/ethernet/8390/apne.c @@ -39,7 +39,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index c30adcc9828..11476ca95e9 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -31,7 +31,6 @@ #include -#include /* Rename the lib8390.c functions to show that they are in this driver */ #define __ei_open ax_ei_open diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c index c5bd8eb7a9f..e1b3941bd14 100644 --- a/drivers/net/ethernet/8390/axnet_cs.c +++ b/drivers/net/ethernet/8390/axnet_cs.c @@ -46,7 +46,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/8390/e2100.c b/drivers/net/ethernet/8390/e2100.c index d16dc53c181..ed55ce85ebb 100644 --- a/drivers/net/ethernet/8390/e2100.c +++ b/drivers/net/ethernet/8390/e2100.c @@ -48,7 +48,6 @@ static const char version[] = #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/es3210.c b/drivers/net/ethernet/8390/es3210.c index 6428f9e7a55..ba1b5c95531 100644 --- a/drivers/net/ethernet/8390/es3210.c +++ b/drivers/net/ethernet/8390/es3210.c @@ -59,7 +59,6 @@ static const char version[] = #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c index a45b0d8a9f1..dbefd5658c1 100644 --- a/drivers/net/ethernet/8390/etherh.c +++ b/drivers/net/ethernet/8390/etherh.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/8390/hp-plus.c b/drivers/net/ethernet/8390/hp-plus.c index d42938b6b59..52f70f999c0 100644 --- a/drivers/net/ethernet/8390/hp-plus.c +++ b/drivers/net/ethernet/8390/hp-plus.c @@ -33,7 +33,6 @@ static const char version[] = #include #include -#include #include #include "8390.h" diff --git a/drivers/net/ethernet/8390/hp.c b/drivers/net/ethernet/8390/hp.c index 113f1e075a2..37fa89aa457 100644 --- a/drivers/net/ethernet/8390/hp.c +++ b/drivers/net/ethernet/8390/hp.c @@ -33,7 +33,6 @@ static const char version[] = #include #include -#include #include #include "8390.h" diff --git a/drivers/net/ethernet/8390/lib8390.c b/drivers/net/ethernet/8390/lib8390.c index e77f624e819..b329f5c0d62 100644 --- a/drivers/net/ethernet/8390/lib8390.c +++ b/drivers/net/ethernet/8390/lib8390.c @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/8390/lne390.c b/drivers/net/ethernet/8390/lne390.c index 69490ae018e..479409bf2e3 100644 --- a/drivers/net/ethernet/8390/lne390.c +++ b/drivers/net/ethernet/8390/lne390.c @@ -46,7 +46,6 @@ static const char *version = #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c index af5d9822cad..88ccc8b14f0 100644 --- a/drivers/net/ethernet/8390/mac8390.c +++ b/drivers/net/ethernet/8390/mac8390.c @@ -37,7 +37,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/8390/ne-h8300.c b/drivers/net/ethernet/8390/ne-h8300.c index 9b9c77d5a65..7fc28f2d28a 100644 --- a/drivers/net/ethernet/8390/ne-h8300.c +++ b/drivers/net/ethernet/8390/ne-h8300.c @@ -29,7 +29,6 @@ static const char version1[] = #include #include -#include #include #include diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index f92ea2a65a5..d04911d33b6 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -53,7 +53,6 @@ static const char version2[] = #include #include -#include #include #include "8390.h" diff --git a/drivers/net/ethernet/8390/ne2.c b/drivers/net/ethernet/8390/ne2.c index 922b32036c6..ef85839f43d 100644 --- a/drivers/net/ethernet/8390/ne2.c +++ b/drivers/net/ethernet/8390/ne2.c @@ -76,7 +76,6 @@ static const char *version = "ne2.c:v0.91 Nov 16 1998 Wim Dumon #include -#include #include #include diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c index 3fab04a0034..5e8845febfb 100644 --- a/drivers/net/ethernet/8390/ne2k-pci.c +++ b/drivers/net/ethernet/8390/ne2k-pci.c @@ -54,7 +54,6 @@ static int options[MAX_UNITS]; #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/8390/ne3210.c b/drivers/net/ethernet/8390/ne3210.c index 2a3e8057fea..a2f8b2b8e27 100644 --- a/drivers/net/ethernet/8390/ne3210.c +++ b/drivers/net/ethernet/8390/ne3210.c @@ -39,7 +39,6 @@ #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c index f2a4e5de18c..de1af0bfed4 100644 --- a/drivers/net/ethernet/8390/pcnet_cs.c +++ b/drivers/net/ethernet/8390/pcnet_cs.c @@ -49,7 +49,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/8390/smc-mca.c b/drivers/net/ethernet/8390/smc-mca.c index 77efec44fea..7a68590f280 100644 --- a/drivers/net/ethernet/8390/smc-mca.c +++ b/drivers/net/ethernet/8390/smc-mca.c @@ -47,7 +47,6 @@ #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c index 1cc306a83ff..b0fbce39661 100644 --- a/drivers/net/ethernet/8390/smc-ultra.c +++ b/drivers/net/ethernet/8390/smc-ultra.c @@ -69,7 +69,6 @@ static const char version[] = #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/smc-ultra32.c b/drivers/net/ethernet/8390/smc-ultra32.c index bb87053eb3d..923e42aedcf 100644 --- a/drivers/net/ethernet/8390/smc-ultra32.c +++ b/drivers/net/ethernet/8390/smc-ultra32.c @@ -57,7 +57,6 @@ static const char *version = "smc-ultra32.c: 06/97 v1.00\n"; #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c index 3b903759980..8df4c415723 100644 --- a/drivers/net/ethernet/8390/stnic.c +++ b/drivers/net/ethernet/8390/stnic.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c index c175fadb597..03eb3eed49f 100644 --- a/drivers/net/ethernet/8390/wd.c +++ b/drivers/net/ethernet/8390/wd.c @@ -39,7 +39,6 @@ static const char version[] = #include #include -#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/zorro8390.c b/drivers/net/ethernet/8390/zorro8390.c index bcd27323b20..7818e6397e9 100644 --- a/drivers/net/ethernet/8390/zorro8390.c +++ b/drivers/net/ethernet/8390/zorro8390.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c index 6c3b1c0adaa..7219123fa0a 100644 --- a/drivers/net/ethernet/alteon/acenic.c +++ b/drivers/net/ethernet/alteon/acenic.c @@ -78,7 +78,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/amd/7990.c b/drivers/net/ethernet/amd/7990.c index 1b046f58d58..6e722dc37db 100644 --- a/drivers/net/ethernet/amd/7990.c +++ b/drivers/net/ethernet/amd/7990.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c index cc7b9e46780..e10ffad525a 100644 --- a/drivers/net/ethernet/amd/am79c961a.c +++ b/drivers/net/ethernet/amd/am79c961a.c @@ -30,7 +30,6 @@ #include #include -#include #define TX_BUFFERS 15 #define RX_BUFFERS 25 diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 9f62504d008..64d0d9c1afa 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -88,7 +88,6 @@ Revision History: #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c index 7dc508e5c72..75299f500ee 100644 --- a/drivers/net/ethernet/amd/declance.c +++ b/drivers/net/ethernet/amd/declance.c @@ -64,7 +64,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/amd/hplance.c b/drivers/net/ethernet/amd/hplance.c index 4e2d68a4de8..8baff4e5d96 100644 --- a/drivers/net/ethernet/amd/hplance.c +++ b/drivers/net/ethernet/amd/hplance.c @@ -22,7 +22,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/mvme147.c index 56bc47a9418..9af3c307862 100644 --- a/drivers/net/ethernet/amd/mvme147.c +++ b/drivers/net/ethernet/amd/mvme147.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c index ebdb9e238a8..9f59bf63514 100644 --- a/drivers/net/ethernet/amd/nmclan_cs.c +++ b/drivers/net/ethernet/amd/nmclan_cs.c @@ -154,7 +154,6 @@ Include Files #include #include -#include /* ---------------------------------------------------------------------------- Defines diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c index e3fe3504e19..d7a3533d990 100644 --- a/drivers/net/ethernet/amd/sunlance.c +++ b/drivers/net/ethernet/amd/sunlance.c @@ -95,7 +95,6 @@ static char lancestr[] = "LANCE"; #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index b0657466041..a374f278834 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -48,7 +48,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c index d5ff93653e4..98c171b3a45 100644 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ b/drivers/net/ethernet/cirrus/cs89x0.c @@ -148,7 +148,6 @@ #include #include -#include #include #include #if ALLOW_DMA diff --git a/drivers/net/ethernet/cirrus/mac89x0.c b/drivers/net/ethernet/cirrus/mac89x0.c index 932fdccc339..e285f384b09 100644 --- a/drivers/net/ethernet/cirrus/mac89x0.c +++ b/drivers/net/ethernet/cirrus/mac89x0.c @@ -99,7 +99,6 @@ static char *version = #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/dlink/de600.c b/drivers/net/ethernet/dlink/de600.c index 682750c052c..414f0eea104 100644 --- a/drivers/net/ethernet/dlink/de600.c +++ b/drivers/net/ethernet/dlink/de600.c @@ -46,7 +46,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/dlink/de620.c b/drivers/net/ethernet/dlink/de620.c index afc5aaac6b6..2e2bc60ee81 100644 --- a/drivers/net/ethernet/dlink/de620.c +++ b/drivers/net/ethernet/dlink/de620.c @@ -122,7 +122,6 @@ static const char version[] = #include #include -#include /* Constant definitions for the DE-620 registers, commands and bits */ #include "de620.h" diff --git a/drivers/net/ethernet/fujitsu/at1700.c b/drivers/net/ethernet/fujitsu/at1700.c index 586b46fd4ee..3d94797c8f9 100644 --- a/drivers/net/ethernet/fujitsu/at1700.c +++ b/drivers/net/ethernet/fujitsu/at1700.c @@ -52,7 +52,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/fujitsu/eth16i.c b/drivers/net/ethernet/fujitsu/eth16i.c index c3f0178fb5c..a992d1f7e0d 100644 --- a/drivers/net/ethernet/fujitsu/eth16i.c +++ b/drivers/net/ethernet/fujitsu/eth16i.c @@ -163,7 +163,6 @@ static char *version = #include #include -#include #include diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c index 0230319ddb5..2418faf2251 100644 --- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c +++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c @@ -57,7 +57,6 @@ #include #include -#include /*====================================================================*/ diff --git a/drivers/net/ethernet/i825xx/3c507.c b/drivers/net/ethernet/i825xx/3c507.c index ed6925f1147..e8984b05990 100644 --- a/drivers/net/ethernet/i825xx/3c507.c +++ b/drivers/net/ethernet/i825xx/3c507.c @@ -63,7 +63,6 @@ static const char version[] = #include #include -#include #include /* use 0 for production, 1 for verification, 2..7 for debug */ diff --git a/drivers/net/ethernet/i825xx/3c527.c b/drivers/net/ethernet/i825xx/3c527.c index ef43f3e951c..278e791afe0 100644 --- a/drivers/net/ethernet/i825xx/3c527.c +++ b/drivers/net/ethernet/i825xx/3c527.c @@ -106,7 +106,6 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter #include -#include #include #include diff --git a/drivers/net/ethernet/i825xx/eepro.c b/drivers/net/ethernet/i825xx/eepro.c index 7a4ad4a0791..7f49fd54c52 100644 --- a/drivers/net/ethernet/i825xx/eepro.c +++ b/drivers/net/ethernet/i825xx/eepro.c @@ -148,7 +148,6 @@ static const char version[] = #include #include -#include #include #include diff --git a/drivers/net/ethernet/i825xx/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c index 3fc649e54a3..cc2e66ad443 100644 --- a/drivers/net/ethernet/i825xx/eexpress.c +++ b/drivers/net/ethernet/i825xx/eexpress.c @@ -116,7 +116,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/i825xx/ether1.c b/drivers/net/ethernet/i825xx/ether1.c index 406a12b4640..067db3f13e9 100644 --- a/drivers/net/ethernet/i825xx/ether1.c +++ b/drivers/net/ethernet/i825xx/ether1.c @@ -48,7 +48,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c index a43649735a0..bd1f1ef91e1 100644 --- a/drivers/net/ethernet/i825xx/znet.c +++ b/drivers/net/ethernet/i825xx/znet.c @@ -100,7 +100,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index f30db1c4660..bc58f1dc22f 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -55,7 +55,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 75af1afe46c..5e1ca0f0509 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -57,7 +57,6 @@ #include #include #include -#include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 45a6333588e..efec6b60b32 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c index 5b89fd377ae..95dd39ffb23 100644 --- a/drivers/net/ethernet/natsemi/jazzsonic.c +++ b/drivers/net/ethernet/natsemi/jazzsonic.c @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c index e640e23460d..b9680ba5a32 100644 --- a/drivers/net/ethernet/natsemi/macsonic.c +++ b/drivers/net/ethernet/natsemi/macsonic.c @@ -53,7 +53,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index c24b46cbfe2..d52728b3c43 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -121,7 +121,6 @@ #include #include -#include #define DRV_NAME "ns83820" diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index 22a8de00bf0..6338ef8606a 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -81,7 +81,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 8561dd25db6..aca13046e43 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -69,7 +69,6 @@ #include #include -#include #define TX_WORK_PER_LOOP 64 #define RX_WORK_PER_LOOP 64 diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c index 46c1932048c..e02f04d7f3a 100644 --- a/drivers/net/ethernet/realtek/atp.c +++ b/drivers/net/ethernet/realtek/atp.c @@ -140,7 +140,6 @@ static int xcvr[NUM_UNITS]; /* The data transfer mode. */ #include #include -#include #include #include diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 27c358c8f4d..7b23554f80b 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -29,7 +29,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c index 7b819bd8c41..df808ac8cb6 100644 --- a/drivers/net/ethernet/seeq/ether3.c +++ b/drivers/net/ethernet/seeq/ether3.c @@ -64,7 +64,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/seeq/seeq8005.c b/drivers/net/ethernet/seeq/seeq8005.c index 79899077444..698edbbfc14 100644 --- a/drivers/net/ethernet/seeq/seeq8005.c +++ b/drivers/net/ethernet/seeq/seeq8005.c @@ -47,7 +47,6 @@ static const char version[] = #include #include -#include #include #include diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c index d12e48a7861..04393b5fef7 100644 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ b/drivers/net/ethernet/smsc/smc91c92_cs.c @@ -53,7 +53,6 @@ #include #include -#include #include /*====================================================================*/ diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index 3c229556073..ce4df61b4b5 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -99,7 +99,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c index f359863b534..2a83fc57edb 100644 --- a/drivers/net/ethernet/sun/sunbmac.c +++ b/drivers/net/ethernet/sun/sunbmac.c @@ -35,7 +35,6 @@ #include #include #include -#include #include "sunbmac.h" diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index ba041596e04..558409ff405 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -41,7 +41,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 8b627e2f798..b95e7e681b3 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -36,7 +36,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c index 139d6b410d6..7d4a040d84a 100644 --- a/drivers/net/ethernet/sun/sunqe.c +++ b/drivers/net/ethernet/sun/sunqe.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index 840e0e9031f..277c93e9ff4 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -50,7 +50,6 @@ #include #include -#include #include #include diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c index 5c69c6f93fb..94a1f94f74b 100644 --- a/drivers/net/ethernet/xircom/xirc2ps_cs.c +++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c @@ -89,7 +89,6 @@ #include #include -#include #include #ifndef MANFID_COMPAQ diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 2a5a34d2d67..64783a0d545 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -13,7 +13,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index f1aea0c9833..acb636963e9 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -86,7 +86,6 @@ #include #include -#include #include /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 18d8affecd1..76d54774ba8 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -69,7 +69,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index bc02968cee1..aed1a6105b2 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -17,7 +17,6 @@ * Copyright (C) 2004, 05 Thomas Osterried DL9SAU */ #include -#include #include #include #include diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 33655814448..efc6c97163a 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -177,7 +177,6 @@ #include #include -#include #include #include diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 696327773fb..5a6412ecce7 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index 2a51363d9fe..168c8f41d09 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 617a446d126..4351296dde3 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -156,7 +156,6 @@ #include #include -#include #include #include diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b71998d0b5b..32eb94ece6c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -41,7 +41,6 @@ #include #include -#include #include #include diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c index 1a5a316cc96..bed62d9c53c 100644 --- a/drivers/net/plip/plip.c +++ b/drivers/net/plip/plip.c @@ -113,7 +113,6 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n" #include -#include #include #include diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 0a0a6643cf3..1252d9c726a 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -75,7 +75,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 69345dfae0f..d4c9db3da22 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -64,7 +64,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index d7c292aa76b..b15ac81d46f 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -68,7 +68,6 @@ #include #include -#include #include "3c359.h" diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 515f122777a..b715e6b444d 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -33,7 +33,6 @@ #include #include -#include #include #include diff --git a/drivers/net/tokenring/ibmtr_cs.c b/drivers/net/tokenring/ibmtr_cs.c index 91b684630fc..356e28e4881 100644 --- a/drivers/net/tokenring/ibmtr_cs.c +++ b/drivers/net/tokenring/ibmtr_cs.c @@ -63,7 +63,6 @@ #include #include -#include #define PCMCIA #include "ibmtr.c" diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 8d71e0d2906..3e4b4f09111 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -127,7 +127,6 @@ #include #include -#include #include "lanstreamer.h" diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 1cdc034f6ae..28adcdf3b14 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -28,7 +28,6 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; #include #include -#include #include #include diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index fd8dce90c95..0e234741cc7 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -106,7 +106,6 @@ #include #include -#include #include "olympic.h" diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 8d362e64a40..62d90e40f9e 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -31,7 +31,6 @@ static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n #include #include -#include #include #include #include diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index 46db5c5395b..ee11e93dc30 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -38,7 +38,6 @@ static const char version[] = "skisa.c: v1.03 09/12/2002 by Jochen Friedrich\n"; #include #include -#include #include #include #include diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 029846a9863..cb35fb79e01 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -49,7 +49,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 102f896bbc5..be4813e0366 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -98,7 +98,6 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A #include #include -#include #include #include #include diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index d3e788a9cd1..fb9918da579 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -34,7 +34,6 @@ #include #include -#include #include #include diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 74d7f76d14a..bb8c72c79c6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -69,7 +69,6 @@ #include #include -#include #include /* Uncomment to enable debugging */ diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 48ab38a34c5..147614ed86a 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -50,7 +50,6 @@ #include -#include #include #include #include diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index fe8d060d8ff..c676de7de02 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -93,7 +93,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c index 33b67d88fce..cf4903355a3 100644 --- a/drivers/net/wan/hd64570.c +++ b/drivers/net/wan/hd64570.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include "hd64570.h" diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c index efc0db10118..e2779faa6c4 100644 --- a/drivers/net/wan/hd64572.c +++ b/drivers/net/wan/hd64572.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include "hd64572.h" diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 7beeb9b88a3..a73b49eb87e 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index c8531612eea..de3bbf43fc5 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -54,7 +54,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index e862369b4a6..d7a65e141d1 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -18,7 +18,6 @@ #include -#include #include #include #include diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ddc061dd150..520a4b2eb9c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index c983c10e0f6..630577dd3a7 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -37,7 +37,6 @@ #include #include -#include #include "airo.h" diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 3010cee7b95..6c87a823f5a 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index ec295c4f677..ded03d226a7 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -48,7 +48,6 @@ #include #include -#include #include #include "atmel.h" diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index 851fa10241e..c5404cb59e0 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -24,7 +24,6 @@ #include #include -#include #include #include "prismcompat.h" diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 04fec1fa6e0..86a738bf591 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -53,7 +53,6 @@ #include #include -#include #include #include diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 98fbf54f600..00f6e69c1dc 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -53,7 +53,6 @@ #include #include -#include #include "wl3501.h" diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index b764ac22d52..44d01afafe9 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 7ff10c1e866..9c5aae52a3b 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -55,7 +55,6 @@ #include #include -#include #include #include diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 95930d01623..1f9e9fefb8e 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -140,7 +140,6 @@ #include #include #include -#include #include /* read/write functions */ #ifdef CONFIG_SUPERIO #include diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index d5f3d753a10..320e43a52e9 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include /* for register_parisc_driver() stuff */ diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index d9ea192c400..673c14ea11e 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index 3e447d0387b..0b66bfc0e14 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -17,7 +17,6 @@ #include -#include #include #include "i82092aa.h" diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 72a033a2acd..e6f3d17dd2b 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -48,7 +48,6 @@ #include #include #include -#include #include diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 2adb0106a03..a26f38c6402 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -24,7 +24,6 @@ #include #include #include -#include #include diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 1511ff71c87..296514155cd 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 271a590a5f3..a317defd616 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -52,7 +52,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 96c72e90b79..0f8b70b2776 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -19,7 +19,6 @@ #include -#include #include "pd6729.h" #include "i82365.h" diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 64d433ec4fc..85ac0957dcd 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 0c62fe31a40..79ecc23643e 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -41,7 +41,6 @@ #include #include -#include #include "soc_common.h" #include "sa11xx_base.h" diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index a0a9c2aa8d7..5d22c6acb8e 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -45,7 +45,6 @@ #include #include -#include #include "soc_common.h" diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 71aeed93037..d6881514d38 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 310160bffe3..cbe15fc3741 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -47,7 +47,6 @@ #include #include -#include #include #include "tcic.h" diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c index 379f4218857..8f6698074f8 100644 --- a/drivers/pcmcia/xxs1500_ss.c +++ b/drivers/pcmcia/xxs1500_ss.c @@ -21,7 +21,6 @@ #include #include -#include #include #define MEM_MAP_SIZE 0x400000 diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index b859d16cf78..769d265b221 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -17,7 +17,6 @@ #include #include -#include #include #include "pnpbios.h" diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index cfe86853feb..9d422264864 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -65,7 +65,6 @@ #include #include -#include #include #include "../base.h" diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index c5c121f14c9..7e9a72eb2fe 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 826157f3869..327657e2e26 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 8d6e508222b..2236aea3ca2 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #ifdef CONFIG_PCI diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 0b31658ccde..a9e468cc1ca 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index f672491774e..a3adfb4357f 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -129,7 +129,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index f66c33b9ab4..d4da3708763 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -47,7 +47,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index bfd618a6949..374c4edf4fc 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -41,7 +41,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index f17c92cf808..19a36945e6f 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -239,7 +239,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index ed119cedaae..ede91f37800 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -42,7 +42,6 @@ #include #include -#include #include #include "scsi.h" diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 1c10b796c1a..a3e6ed35391 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -53,7 +53,6 @@ #include #include -#include #include #include "scsi.h" diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 2fe9e90e53d..cbde1dca45a 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -61,7 +61,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index c454e44cf51..b330438ac66 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -138,7 +138,6 @@ #include #include -#include #include #include "../scsi.h" diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index a3398fe70a9..c3b99c93637 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -12,7 +12,6 @@ #include #include -#include #include "../scsi.h" #include diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c index 849cdf89f7b..d25f944b59c 100644 --- a/drivers/scsi/arm/oak.c +++ b/drivers/scsi/arm/oak.c @@ -13,7 +13,6 @@ #include #include -#include #include "../scsi.h" #include diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 7e6eca4a125..f29d5121d5e 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index c2677ba29c7..4b11bb04f5c 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -72,7 +72,6 @@ #endif -#include #include #include #include diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index a2c6135d337..53bfcaa86f0 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -93,7 +93,6 @@ #include #include -#include #include "scsi.h" #include diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 643f6d500fe..1a2a1e5824e 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -282,7 +282,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 81182badfeb..1a5954f0915 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -100,7 +100,6 @@ #undef NCR5380_STAT_LIMIT #endif -#include #include #include #include diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index d42ec921de4..5d72274c507 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -129,7 +129,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 67fc8ffd52e..cd09132d5d7 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -32,7 +32,6 @@ #include #include -#include #include #include "scsi.h" diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index 112f1bec775..deb5b6d8398 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -123,7 +123,6 @@ #include #include -#include #include "scsi.h" #include diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index e6173376605..e5cd8d8d4ce 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 2bccfbe5661..24828b54773 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -43,7 +43,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 49447477953..e8a04ae3276 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 4b3b4755945..5982a587bab 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -115,7 +115,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 002924963cd..62b616891a3 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -38,7 +38,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index de0b1a704fb..21883a2d632 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -54,7 +54,6 @@ static const char * osst_version = "0.99.4"; #include #include #include -#include /* The driver prints some debugging information on the console if DEBUG is defined and non-zero. */ diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c index f2018b46f49..2f72c9807b1 100644 --- a/drivers/scsi/pas16.c +++ b/drivers/scsi/pas16.c @@ -113,7 +113,6 @@ #include -#include #include #include #include diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index d838205ab16..6c6486f626e 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -359,7 +359,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index e40dc1cb09a..b191dd54920 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -35,7 +35,6 @@ #include "qlogicpti.h" #include -#include #include #include #include diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 9262cdfa4b2..a15f691f9d3 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -42,7 +42,6 @@ static const char *verstr = "20101219"; #include #include -#include #include #include diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index baf7328de95..6e25889db9d 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -63,7 +63,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index fbba78e5722..a3dd55d1d2f 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -25,7 +25,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 012c86edd59..ac4eca6a532 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index 041eaaace2c..d672d97fb84 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -106,7 +106,6 @@ * $Log: t128.c,v $ */ -#include #include #include #include diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 90e104d6b55..9c216e56356 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -410,7 +410,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 7e22b737dfd..14e0c40a68c 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -141,7 +141,6 @@ #include #include -#include #include #define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */ diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 9ee0afef2d1..d89a5dfd3ad 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -179,7 +179,6 @@ #include #include -#include #include #include diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 610f7391456..9b0d7169603 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index db1fd63aaab..bf185e2807d 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -42,7 +42,6 @@ #include #include #include -#include #include "comedidev.h" #include "internal.h" diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index c9e8c478576..915157d4780 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -86,7 +86,6 @@ TODO: #include "../comedidev.h" #include #include -#include #include "comedi_pci.h" #include "8253.h" diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index fd274e9c7b7..13e9c807169 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -55,7 +55,6 @@ #include "comedi_pci.h" #include "../comedidev.h" -#include #define PCI_MITE_SIZE 4096 #define PCI_DAQ_SIZE 4096 diff --git a/drivers/staging/crystalhd/crystalhd.h b/drivers/staging/crystalhd/crystalhd.h index 3f4d7951502..b3a550bd5b0 100644 --- a/drivers/staging/crystalhd/crystalhd.h +++ b/drivers/staging/crystalhd/crystalhd.h @@ -1,7 +1,6 @@ #ifndef _CRYSTALHD_H_ #define _CRYSTALHD_H_ -#include #include "bc_dts_defs.h" #include "crystalhd_misc.h" #include "bc_dts_glob_lnx.h" diff --git a/drivers/staging/crystalhd/crystalhd_lnx.h b/drivers/staging/crystalhd/crystalhd_lnx.h index a81f9298b0a..a9e36336d09 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.h +++ b/drivers/staging/crystalhd/crystalhd_lnx.h @@ -45,7 +45,6 @@ #include #include #include -#include #include #include "crystalhd.h" diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h index 84c87938a83..8cdaa7a3481 100644 --- a/drivers/staging/crystalhd/crystalhd_misc.h +++ b/drivers/staging/crystalhd/crystalhd_misc.h @@ -37,6 +37,7 @@ #include #include #include +#include "bc_dts_glob_lnx.h" /* Global log level variable defined in crystal_misc.c file */ extern uint32_t g_linklog_level; diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c index 3f919babe79..886f5650444 100644 --- a/drivers/staging/et131x/et131x.c +++ b/drivers/staging/et131x/et131x.c @@ -70,7 +70,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c index 7569aa0f24d..c4a8a0a26eb 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 6c9279a6d60..ece2dd14648 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c index b8cfa1a6eae..6bc82aaeef1 100644 --- a/drivers/staging/media/go7007/go7007-i2c.c +++ b/drivers/staging/media/go7007/go7007-i2c.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "go7007-priv.h" #include "wis-i2c.h" diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 2b27d8da70a..c8c96e26bc7 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "go7007.h" #include "go7007-priv.h" diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c index d071c838ac2..5af29ff68bf 100644 --- a/drivers/staging/media/go7007/snd-go7007.c +++ b/drivers/staging/media/go7007/snd-go7007.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index 8dd8897ad86..18a798c27a7 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -66,7 +66,6 @@ #include #include -#include #include #include #include diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c index c94382b917a..945d9623550 100644 --- a/drivers/staging/media/lirc/lirc_sir.c +++ b/drivers/staging/media/lirc/lirc_sir.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index 4683d5f355c..6183573f112 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -58,7 +58,6 @@ #include #include -#include #define LCD_MINOR 156 #define KEYPAD_MINOR 185 diff --git a/drivers/staging/sbe-2t3e3/io.c b/drivers/staging/sbe-2t3e3/io.c index b458ff03406..9a50bcc5959 100644 --- a/drivers/staging/sbe-2t3e3/io.c +++ b/drivers/staging/sbe-2t3e3/io.c @@ -11,7 +11,6 @@ */ #include -#include #include "2t3e3.h" #include "ctrl.h" diff --git a/drivers/staging/telephony/phonedev.c b/drivers/staging/telephony/phonedev.c index 1915af20117..1dd0b6717cc 100644 --- a/drivers/staging/telephony/phonedev.c +++ b/drivers/staging/telephony/phonedev.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/tidspbridge/include/dspbridge/host_os.h b/drivers/staging/tidspbridge/include/dspbridge/host_os.h index a2f31c69d12..ed00d3da320 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/host_os.h +++ b/drivers/staging/tidspbridge/include/dspbridge/host_os.h @@ -17,7 +17,6 @@ #ifndef _HOST_OS_H_ #define _HOST_OS_H_ -#include #include #include #include diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c index a2cbb29c3f5..7084f414846 100644 --- a/drivers/staging/wlags49_h2/wl_cs.c +++ b/drivers/staging/wlags49_h2/wl_cs.c @@ -74,7 +74,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c index dab603e0f45..d5bf0a7012f 100644 --- a/drivers/staging/wlags49_h2/wl_main.c +++ b/drivers/staging/wlags49_h2/wl_main.c @@ -86,8 +86,7 @@ // #include // #include // #include -// #include -// #include +// // #include #include #include diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c index 9c16f5478a7..90820ff1ace 100644 --- a/drivers/staging/wlags49_h2/wl_netdev.c +++ b/drivers/staging/wlags49_h2/wl_netdev.c @@ -79,8 +79,7 @@ // #include // #include // #include -// #include -// #include +// // #include #include #include diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c index 2bd9b84ace8..3df990c7306 100644 --- a/drivers/staging/wlags49_h2/wl_pci.c +++ b/drivers/staging/wlags49_h2/wl_pci.c @@ -77,7 +77,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c index b748a3ff795..f104e6f1e98 100644 --- a/drivers/staging/wlags49_h2/wl_util.c +++ b/drivers/staging/wlags49_h2/wl_util.c @@ -73,8 +73,7 @@ // #include // #include // #include -// #include -// #include +// // #include #include #include diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index afadcd43d14..24145c30c9b 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -85,7 +85,6 @@ static char *serial_version = "4.30"; #include -#include #include diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 03c14979acc..794ecb40017 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -133,7 +133,6 @@ #include #include -#include #include diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 8a8d0440bab..324467d28a5 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -46,7 +46,6 @@ #include #include -#include #include #include diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 17ff377e412..c6f372dd562 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -41,7 +41,6 @@ #include #include -#include #include #include #include diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index a09ce3ef5d7..1b2db9a3038 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -102,7 +102,6 @@ #include #include -#include #include #include diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index d2256d08ee7..94b6eda87af 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -50,7 +50,6 @@ #include #include -#include /* number of characters left in xmit buffer before select has we have room */ #define WAKEUP_CHARS 256 diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index f96ecaec24f..eeae7fafe9a 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -27,7 +27,6 @@ #include #include -#include #ifdef CONFIG_UNIX98_PTYS static struct tty_driver *ptm_driver; diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 7398390e7e6..5ce782529d6 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -39,7 +39,6 @@ #include #include -#include #include #include diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 86090605a84..29b695d041e 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 90280ae1823..5b07c0c3a10 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -34,7 +34,6 @@ static char *serial_version = "$Revision: 1.25 $"; #include #include -#include #include #include diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index e3699a84049..6491b8644a7 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index d55709a7a75..defc4e3393a 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -52,7 +52,6 @@ #include #include -#include #include #include #include diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 5e85e1e14c4..fca13dc73e2 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -50,7 +50,6 @@ #include #include -#include #include #include diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index b7455b52608..4001eee6c08 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -67,7 +67,6 @@ #include #include -#include #include #include diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 8e518da85fd..593d40ad0a6 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -86,7 +86,6 @@ #include #include -#include #include #include #include diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 34b1a3c4306..aa1debf97cc 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -73,7 +73,6 @@ #include #include -#include #include #include #include diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 4fb6c4b31b7..a3dddc12d2f 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -58,7 +58,6 @@ #include #include -#include #include #include #include diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index dd8a938510c..d939bd705c7 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -97,7 +97,6 @@ #include #include -#include #include #include diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 9314d93c1a2..a1b9a2f6856 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -23,7 +23,6 @@ #include #include -#include #undef TTY_DEBUG_WAIT_UNTIL_SENT diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 84c4a7d5603..3bdd4b19dd0 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -99,7 +99,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 2204a4c68d8..77779271f48 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -54,7 +54,6 @@ #include #include -#include #include /* gadget stack */ diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 15a8cdb2ded..d03ab95fcc8 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index e1cd56c5e2a..a6dfd216416 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #define DRIVER_DESC "USB Host+Gadget Emulator" diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index b30e21fdbb1..5f94e79cd6b 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -43,7 +43,6 @@ #include #include -#include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index e1dfd32dc80..e151d6b87de 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -43,7 +43,6 @@ #include #include #include -#include #include diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index edd52d963f1..f9cedd52cf2 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include "langwell_udc.h" diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 19bbe80c2f8..a73cf406e2a 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include "mv_udc.h" diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 01ae56f4717..43ac7482fa9 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -42,7 +42,6 @@ #include #include -#include #include #include "net2272.h" diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index a5ccabc37f3..ac335af154b 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -59,7 +59,6 @@ #include #include #include -#include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index b44830df593..3b4b6dd0f95 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index d83134b0f78..4e4dc1f5f38 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 1b33634f273..41ed69c96d8 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index d3cdffea9c8..73a934a170d 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -34,7 +34,6 @@ #include #include -#include #include diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index ab9c65e2c1d..195524cde6c 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index aede6374e4b..057cdda7a48 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #if defined(CONFIG_PPC_PS3) diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 924880087a7..9e65e3091c8 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -70,7 +70,6 @@ #include #include -#include #include #include "isp116x.h" diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 9e63cdf1ab7..2ed112d3e15 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -84,7 +84,6 @@ #include #include -#include #include #include diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index cd5e382db89..788ff07aa7c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -42,7 +42,6 @@ #include #include -#include #include #include diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 015c7c62ed4..3b38030b02a 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -40,7 +40,6 @@ #include #include -#include #include #include diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 2a2cce2d2fa..91ce1c02e61 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -51,7 +51,6 @@ #include #include -#include #include #include diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 16dd6a6abf0..dbbd1ba2522 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -55,7 +55,6 @@ #include #include #include -#include #include /* FIXME ohci.h is ONLY for internal use by the OHCI driver. diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e37dea87bb5..e4db350602b 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -45,7 +45,6 @@ #include #include #include -#include #include "uhci-hcd.h" diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index f23cae094f1..887df9d8142 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -53,7 +53,6 @@ #include #include -#include #include #include #include diff --git a/drivers/video/bt431.h b/drivers/video/bt431.h index c826f2787ba..04e0cfbba53 100644 --- a/drivers/video/bt431.h +++ b/drivers/video/bt431.h @@ -8,7 +8,6 @@ * archive for more details. */ #include -#include /* * Bt431 cursor generator registers, 32-bit aligned. diff --git a/drivers/video/bt455.h b/drivers/video/bt455.h index b7591fea7ad..80f61b03e9a 100644 --- a/drivers/video/bt455.h +++ b/drivers/video/bt455.h @@ -8,7 +8,6 @@ * archive for more details. */ #include -#include /* * Bt455 byte-wide registers, 32-bit aligned. diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 8745637e4b7..2e471c22abf 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -77,7 +77,6 @@ #include /* For counting font checksums */ #include #include -#include #include "fbcon.h" diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index a122d9287d1..6d159662904 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 850380795b0..c1527f5b47e 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -51,7 +51,6 @@ #include #include -#include #ifdef __arm__ #include diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index ec56d2544c7..49e3dda1a36 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index fb3f6739110..afc9521173e 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -71,7 +71,6 @@ #include #include #include -#include #ifdef CONFIG_MTRR #include diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 0c69fa20251..9b4a60b52a4 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -33,7 +33,6 @@ #include #include -#include #include