Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
4615fd15
Commit
4615fd15
authored
Nov 26, 2015
by
Emmanuel Grumbach
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'iwlwifi-fixes/master' into next
parents
6d808eba
9513c5e1
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
79 additions
and
55 deletions
+79
-55
drivers/net/wireless/intel/iwlwifi/iwl-7000.c
drivers/net/wireless/intel/iwlwifi/iwl-7000.c
+1
-1
drivers/net/wireless/intel/iwlwifi/iwl-8000.c
drivers/net/wireless/intel/iwlwifi/iwl-8000.c
+1
-1
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+2
-6
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+8
-3
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+47
-41
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+2
-2
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+18
-1
No files found.
drivers/net/wireless/intel/iwlwifi/iwl-7000.c
View file @
4615fd15
...
...
@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 1
7
#define IWL7260_UCODE_API_MAX 1
9
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 13
...
...
drivers/net/wireless/intel/iwlwifi/iwl-8000.c
View file @
4615fd15
...
...
@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 1
7
#define IWL8000_UCODE_API_MAX 1
9
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 13
...
...
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
View file @
4615fd15
...
...
@@ -309,9 +309,9 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
* to transmit packets to the AP, i.e. the PTK.
*/
if
(
key
->
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
)
{
key
->
hw_key_idx
=
0
;
mvm
->
ptk_ivlen
=
key
->
iv_len
;
mvm
->
ptk_icvlen
=
key
->
icv_len
;
ret
=
iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
key
,
0
);
}
else
{
/*
* firmware only supports TSC/RSC for a single key,
...
...
@@ -319,12 +319,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
* with new ones -- this relies on mac80211 doing
* list_add_tail().
*/
key
->
hw_key_idx
=
1
;
mvm
->
gtk_ivlen
=
key
->
iv_len
;
mvm
->
gtk_icvlen
=
key
->
icv_len
;
ret
=
iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
key
,
1
);
}
ret
=
iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
key
,
true
);
data
->
error
=
ret
!=
0
;
out_unlock:
mutex_unlock
(
&
mvm
->
mutex
);
...
...
@@ -772,9 +771,6 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
*/
set_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
);
/* We reprogram keys and shouldn't allocate new key indices */
memset
(
mvm
->
fw_key_table
,
0
,
sizeof
(
mvm
->
fw_key_table
));
mvm
->
ptk_ivlen
=
0
;
mvm
->
ptk_icvlen
=
0
;
mvm
->
ptk_ivlen
=
0
;
...
...
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
View file @
4615fd15
...
...
@@ -2941,6 +2941,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
{
struct
iwl_mvm
*
mvm
=
IWL_MAC80211_GET_MVM
(
hw
);
int
ret
;
u8
key_offset
;
if
(
iwlwifi_mod_params
.
sw_crypto
)
{
IWL_DEBUG_MAC80211
(
mvm
,
"leave - hwcrypto disabled
\n
"
);
...
...
@@ -3006,10 +3007,14 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break
;
}
/* in HW restart reuse the index, otherwise request a new one */
if
(
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
))
key_offset
=
key
->
hw_key_idx
;
else
key_offset
=
STA_KEY_IDX_INVALID
;
IWL_DEBUG_MAC80211
(
mvm
,
"set hwcrypto key
\n
"
);
ret
=
iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
key
,
test_bit
(
IWL_MVM_STATUS_IN_HW_RESTART
,
&
mvm
->
status
));
ret
=
iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
key
,
key_offset
);
if
(
ret
)
{
IWL_WARN
(
mvm
,
"set key failed
\n
"
);
/*
...
...
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
View file @
4615fd15
...
...
@@ -1201,7 +1201,8 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
return
max_offs
;
}
static
u8
iwl_mvm_get_key_sta_id
(
struct
ieee80211_vif
*
vif
,
static
u8
iwl_mvm_get_key_sta_id
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
)
{
struct
iwl_mvm_vif
*
mvmvif
=
iwl_mvm_vif_from_mac80211
(
vif
);
...
...
@@ -1218,8 +1219,21 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
* station ID, then use AP's station ID.
*/
if
(
vif
->
type
==
NL80211_IFTYPE_STATION
&&
mvmvif
->
ap_sta_id
!=
IWL_MVM_STATION_COUNT
)
return
mvmvif
->
ap_sta_id
;
mvmvif
->
ap_sta_id
!=
IWL_MVM_STATION_COUNT
)
{
u8
sta_id
=
mvmvif
->
ap_sta_id
;
sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
));
/*
* It is possible that the 'sta' parameter is NULL,
* for example when a GTK is removed - the sta_id will then
* be the AP ID, and no station was passed by mac80211.
*/
if
(
IS_ERR_OR_NULL
(
sta
))
return
IWL_MVM_STATION_COUNT
;
return
sta_id
;
}
return
IWL_MVM_STATION_COUNT
;
}
...
...
@@ -1227,7 +1241,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
static
int
iwl_mvm_send_sta_key
(
struct
iwl_mvm
*
mvm
,
struct
iwl_mvm_sta
*
mvm_sta
,
struct
ieee80211_key_conf
*
keyconf
,
bool
mcast
,
u32
tkip_iv32
,
u16
*
tkip_p1k
,
u32
cmd_flags
)
u32
tkip_iv32
,
u16
*
tkip_p1k
,
u32
cmd_flags
,
u8
key_offset
)
{
struct
iwl_mvm_add_sta_key_cmd
cmd
=
{};
__le16
key_flags
;
...
...
@@ -1269,7 +1284,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
if
(
mcast
)
key_flags
|=
cpu_to_le16
(
STA_KEY_MULTICAST
);
cmd
.
key_offset
=
key
conf
->
hw_key_idx
;
cmd
.
key_offset
=
key
_offset
;
cmd
.
key_flags
=
key_flags
;
cmd
.
sta_id
=
sta_id
;
...
...
@@ -1360,6 +1375,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
keyconf
,
u8
key_offset
,
bool
mcast
)
{
struct
iwl_mvm_sta
*
mvm_sta
=
iwl_mvm_sta_from_mac80211
(
sta
);
...
...
@@ -1375,17 +1391,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
ieee80211_get_key_rx_seq
(
keyconf
,
0
,
&
seq
);
ieee80211_get_tkip_rx_p1k
(
keyconf
,
addr
,
seq
.
tkip
.
iv32
,
p1k
);
ret
=
iwl_mvm_send_sta_key
(
mvm
,
mvm_sta
,
keyconf
,
mcast
,
seq
.
tkip
.
iv32
,
p1k
,
0
);
seq
.
tkip
.
iv32
,
p1k
,
0
,
key_offset
);
break
;
case
WLAN_CIPHER_SUITE_CCMP
:
case
WLAN_CIPHER_SUITE_WEP40
:
case
WLAN_CIPHER_SUITE_WEP104
:
ret
=
iwl_mvm_send_sta_key
(
mvm
,
mvm_sta
,
keyconf
,
mcast
,
0
,
NULL
,
0
);
0
,
NULL
,
0
,
key_offset
);
break
;
default:
ret
=
iwl_mvm_send_sta_key
(
mvm
,
mvm_sta
,
keyconf
,
mcast
,
0
,
NULL
,
0
);
0
,
NULL
,
0
,
key_offset
);
}
return
ret
;
...
...
@@ -1433,7 +1449,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
keyconf
,
bool
have_
key_offset
)
u8
key_offset
)
{
bool
mcast
=
!
(
keyconf
->
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
);
u8
sta_id
;
...
...
@@ -1443,7 +1459,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
lockdep_assert_held
(
&
mvm
->
mutex
);
/* Get the station id from the mvm local station table */
sta_id
=
iwl_mvm_get_key_sta_id
(
vif
,
sta
);
sta_id
=
iwl_mvm_get_key_sta_id
(
mvm
,
vif
,
sta
);
if
(
sta_id
==
IWL_MVM_STATION_COUNT
)
{
IWL_ERR
(
mvm
,
"Failed to find station id
\n
"
);
return
-
EINVAL
;
...
...
@@ -1470,18 +1486,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
if
(
WARN_ON_ONCE
(
iwl_mvm_sta_from_mac80211
(
sta
)
->
vif
!=
vif
))
return
-
EINVAL
;
if
(
!
have_key_offset
)
{
/*
* The D3 firmware hardcodes the PTK offset to 0, so we have to
* configure it there. As a result, this workaround exists to
* let the caller set the key offset (hw_key_idx), see d3.c.
*/
keyconf
->
hw_key_idx
=
iwl_mvm_set_fw_key_idx
(
mvm
);
if
(
keyconf
->
hw_key_idx
==
STA_KEY_IDX_INVALID
)
/* If the key_offset is not pre-assigned, we need to find a
* new offset to use. In normal cases, the offset is not
* pre-assigned, but during HW_RESTART we want to reuse the
* same indices, so we pass them when this function is called.
*
* In D3 entry, we need to hardcoded the indices (because the
* firmware hardcodes the PTK offset to 0). In this case, we
* need to make sure we don't overwrite the hw_key_idx in the
* keyconf structure, because otherwise we cannot configure
* the original ones back when resuming.
*/
if
(
key_offset
==
STA_KEY_IDX_INVALID
)
{
key_offset
=
iwl_mvm_set_fw_key_idx
(
mvm
);
if
(
key_offset
==
STA_KEY_IDX_INVALID
)
return
-
ENOSPC
;
keyconf
->
hw_key_idx
=
key_offset
;
}
ret
=
__iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
keyconf
,
mcast
);
ret
=
__iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
keyconf
,
key_offset
,
mcast
);
if
(
ret
)
{
__clear_bit
(
keyconf
->
hw_key_idx
,
mvm
->
fw_key_table
);
goto
end
;
...
...
@@ -1495,7 +1518,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
*/
if
(
keyconf
->
cipher
==
WLAN_CIPHER_SUITE_WEP40
||
keyconf
->
cipher
==
WLAN_CIPHER_SUITE_WEP104
)
{
ret
=
__iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
keyconf
,
!
mcast
);
ret
=
__iwl_mvm_set_sta_key
(
mvm
,
vif
,
sta
,
keyconf
,
key_offset
,
!
mcast
);
if
(
ret
)
{
__clear_bit
(
keyconf
->
hw_key_idx
,
mvm
->
fw_key_table
);
__iwl_mvm_remove_sta_key
(
mvm
,
sta_id
,
keyconf
,
mcast
);
...
...
@@ -1521,7 +1545,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
lockdep_assert_held
(
&
mvm
->
mutex
);
/* Get the station id from the mvm local station table */
sta_id
=
iwl_mvm_get_key_sta_id
(
vif
,
sta
);
sta_id
=
iwl_mvm_get_key_sta_id
(
mvm
,
vif
,
sta
);
IWL_DEBUG_WEP
(
mvm
,
"mvm remove dynamic key: idx=%d sta=%d
\n
"
,
keyconf
->
keyidx
,
sta_id
);
...
...
@@ -1547,24 +1571,6 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
return
0
;
}
/*
* It is possible that the 'sta' parameter is NULL, and thus
* there is a need to retrieve the sta from the local station table,
* for example when a GTK is removed (where the sta_id will then be
* the AP ID, and no station was passed by mac80211.)
*/
if
(
!
sta
)
{
sta
=
rcu_dereference_protected
(
mvm
->
fw_id_to_mac_id
[
sta_id
],
lockdep_is_held
(
&
mvm
->
mutex
));
if
(
!
sta
)
{
IWL_ERR
(
mvm
,
"Invalid station id
\n
"
);
return
-
EINVAL
;
}
}
if
(
WARN_ON_ONCE
(
iwl_mvm_sta_from_mac80211
(
sta
)
->
vif
!=
vif
))
return
-
EINVAL
;
ret
=
__iwl_mvm_remove_sta_key
(
mvm
,
sta_id
,
keyconf
,
mcast
);
if
(
ret
)
return
ret
;
...
...
@@ -1584,7 +1590,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
u16
*
phase1key
)
{
struct
iwl_mvm_sta
*
mvm_sta
;
u8
sta_id
=
iwl_mvm_get_key_sta_id
(
vif
,
sta
);
u8
sta_id
=
iwl_mvm_get_key_sta_id
(
mvm
,
vif
,
sta
);
bool
mcast
=
!
(
keyconf
->
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
);
if
(
WARN_ON_ONCE
(
sta_id
==
IWL_MVM_STATION_COUNT
))
...
...
@@ -1602,7 +1608,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
mvm_sta
=
iwl_mvm_sta_from_mac80211
(
sta
);
iwl_mvm_send_sta_key
(
mvm
,
mvm_sta
,
keyconf
,
mcast
,
iv32
,
phase1key
,
CMD_ASYNC
);
iv32
,
phase1key
,
CMD_ASYNC
,
keyconf
->
hw_key_idx
);
rcu_read_unlock
();
}
...
...
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
View file @
4615fd15
...
...
@@ -365,8 +365,8 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
int
iwl_mvm_set_sta_key
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
struct
ieee80211_key_conf
*
key
,
bool
have_
key_offset
);
struct
ieee80211_key_conf
*
key
conf
,
u8
key_offset
);
int
iwl_mvm_remove_sta_key
(
struct
iwl_mvm
*
mvm
,
struct
ieee80211_vif
*
vif
,
struct
ieee80211_sta
*
sta
,
...
...
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
View file @
4615fd15
...
...
@@ -423,14 +423,21 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* 8000 Series */
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0010
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x1010
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0130
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x1130
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0132
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x1132
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0110
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x01F0
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0012
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x1012
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x1110
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0050
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0250
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x1050
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0150
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x1150
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F4
,
0x0030
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F4
,
0x1130
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F4
,
0x1030
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0xC010
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0xC110
,
iwl8260_2ac_cfg
)},
...
...
@@ -438,18 +445,28 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{
IWL_PCI_DEVICE
(
0x24F3
,
0xC050
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0xD050
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x8010
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x8110
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x9010
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x9110
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F4
,
0x8030
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F4
,
0x9030
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x8130
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x9130
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x8132
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x9132
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x8050
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x8150
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x9050
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x9150
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0004
,
iwl8260_2n_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0044
,
iwl8260_2n_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F5
,
0x0010
,
iwl4165_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F6
,
0x0030
,
iwl4165_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0810
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0910
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0850
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0950
,
iwl8260_2ac_cfg
)},
{
IWL_PCI_DEVICE
(
0x24F3
,
0x0930
,
iwl8260_2ac_cfg
)},
#endif
/* CONFIG_IWLMVM */
{
0
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment