Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking fixes from David Miller: "The iwlwifi firmware compat fix is in here as well as some other stuff: 1) Fix request socket leak introduced by BPF deadlock fix, from Eric Dumazet. 2) Fix VLAN handling with TXQs in mac80211, from Johannes Berg. 3) Missing __qdisc_drop conversions in prio and qfq schedulers, from Gao Feng. 4) Use after free in netlink nlk groups handling, from Xin Long. 5) Handle MTU update properly in ipv6 gre tunnels, from Xin Long. 6) Fix leak of ipv6 fib tables on netns teardown, from Sabrina Dubroca with follow-on fix from Eric Dumazet. 7) Need RCU and preemption disabled during generic XDP data patch, from John Fastabend" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (54 commits) bpf: make error reporting in bpf_warn_invalid_xdp_action more clear Revert "mdio_bus: Remove unneeded gpiod NULL check" bpf: devmap, use cond_resched instead of cpu_relax bpf: add support for sockmap detach programs net: rcu lock and preempt disable missing around generic xdp bpf: don't select potentially stale ri->map from buggy xdp progs net: tulip: Constify tulip_tbl net: ethernet: ti: netcp_core: no need in netif_napi_del davicom: Display proper debug level up to 6 net: phy: sfp: rename dt properties to match the binding dt-binding: net: sfp binding documentation dt-bindings: add SFF vendor prefix dt-bindings: net: don't confuse with generic PHY property ip6_tunnel: fix setting hop_limit value for ipv6 tunnel ip_tunnel: fix setting ttl and tos value in collect_md mode ipv6: fix typo in fib6_net_exit() tcp: fix a request socket leak sctp: fix missing wake ups in some situations netfilter: xt_hashlimit: fix build error caused by 64bit division netfilter: xt_hashlimit: alloc hashtable with right size ...
This commit is contained in:
commit
fbd01410e8
|
@ -1,5 +1,9 @@
|
||||||
The following properties are common to the Ethernet controllers:
|
The following properties are common to the Ethernet controllers:
|
||||||
|
|
||||||
|
NOTE: All 'phy*' properties documented below are Ethernet specific. For the
|
||||||
|
generic PHY 'phys' property, see
|
||||||
|
Documentation/devicetree/bindings/phy/phy-bindings.txt.
|
||||||
|
|
||||||
- local-mac-address: array of 6 bytes, specifies the MAC address that was
|
- local-mac-address: array of 6 bytes, specifies the MAC address that was
|
||||||
assigned to the network device;
|
assigned to the network device;
|
||||||
- mac-address: array of 6 bytes, specifies the MAC address that was last used by
|
- mac-address: array of 6 bytes, specifies the MAC address that was last used by
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
Small Form Factor (SFF) Committee Small Form-factor Pluggable (SFP)
|
||||||
|
Transceiver
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible : must be "sff,sfp"
|
||||||
|
|
||||||
|
Optional Properties:
|
||||||
|
|
||||||
|
- i2c-bus : phandle of an I2C bus controller for the SFP two wire serial
|
||||||
|
interface
|
||||||
|
|
||||||
|
- mod-def0-gpios : GPIO phandle and a specifier of the MOD-DEF0 (AKA Mod_ABS)
|
||||||
|
module presence input gpio signal, active (module absent) high
|
||||||
|
|
||||||
|
- los-gpios : GPIO phandle and a specifier of the Receiver Loss of Signal
|
||||||
|
Indication input gpio signal, active (signal lost) high
|
||||||
|
|
||||||
|
- tx-fault-gpios : GPIO phandle and a specifier of the Module Transmitter
|
||||||
|
Fault input gpio signal, active (fault condition) high
|
||||||
|
|
||||||
|
- tx-disable-gpios : GPIO phandle and a specifier of the Transmitter Disable
|
||||||
|
output gpio signal, active (Tx disable) high
|
||||||
|
|
||||||
|
- rate-select0-gpios : GPIO phandle and a specifier of the Rx Signaling Rate
|
||||||
|
Select (AKA RS0) output gpio signal, low: low Rx rate, high: high Rx rate
|
||||||
|
|
||||||
|
- rate-select1-gpios : GPIO phandle and a specifier of the Tx Signaling Rate
|
||||||
|
Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high:
|
||||||
|
high Tx rate
|
||||||
|
|
||||||
|
Example #1: Direct serdes to SFP connection
|
||||||
|
|
||||||
|
sfp_eth3: sfp-eth3 {
|
||||||
|
compatible = "sff,sfp";
|
||||||
|
i2c-bus = <&sfp_1g_i2c>;
|
||||||
|
los-gpios = <&cpm_gpio2 22 GPIO_ACTIVE_HIGH>;
|
||||||
|
mod-def0-gpios = <&cpm_gpio2 21 GPIO_ACTIVE_LOW>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&cpm_sfp_1g_pins &cps_sfp_1g_pins>;
|
||||||
|
tx-disable-gpios = <&cps_gpio1 24 GPIO_ACTIVE_HIGH>;
|
||||||
|
tx-fault-gpios = <&cpm_gpio2 19 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
|
||||||
|
&cps_emac3 {
|
||||||
|
phy-names = "comphy";
|
||||||
|
phys = <&cps_comphy5 0>;
|
||||||
|
sfp = <&sfp_eth3>;
|
||||||
|
};
|
||||||
|
|
||||||
|
Example #2: Serdes to PHY to SFP connection
|
||||||
|
|
||||||
|
sfp_eth0: sfp-eth0 {
|
||||||
|
compatible = "sff,sfp";
|
||||||
|
i2c-bus = <&sfpp0_i2c>;
|
||||||
|
los-gpios = <&cps_gpio1 28 GPIO_ACTIVE_HIGH>;
|
||||||
|
mod-def0-gpios = <&cps_gpio1 27 GPIO_ACTIVE_LOW>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&cps_sfpp0_pins>;
|
||||||
|
tx-disable-gpios = <&cps_gpio1 29 GPIO_ACTIVE_HIGH>;
|
||||||
|
tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
|
||||||
|
p0_phy: ethernet-phy@0 {
|
||||||
|
compatible = "ethernet-phy-ieee802.3-c45";
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&cpm_phy0_pins &cps_phy0_pins>;
|
||||||
|
reg = <0>;
|
||||||
|
interrupt = <&cpm_gpio2 18 IRQ_TYPE_EDGE_FALLING>;
|
||||||
|
sfp = <&sfp_eth0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
&cpm_eth0 {
|
||||||
|
phy = <&p0_phy>;
|
||||||
|
phy-mode = "10gbase-kr";
|
||||||
|
};
|
|
@ -34,7 +34,9 @@ PHY user node
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Required Properties:
|
Required Properties:
|
||||||
phys : the phandle for the PHY device (used by the PHY subsystem)
|
phys : the phandle for the PHY device (used by the PHY subsystem; not to be
|
||||||
|
confused with the Ethernet specific 'phy' and 'phy-handle' properties,
|
||||||
|
see Documentation/devicetree/bindings/net/ethernet.txt for these)
|
||||||
phy-names : the names of the PHY corresponding to the PHYs present in the
|
phy-names : the names of the PHY corresponding to the PHYs present in the
|
||||||
*phys* phandle
|
*phys* phandle
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,7 @@ schindler Schindler
|
||||||
seagate Seagate Technology PLC
|
seagate Seagate Technology PLC
|
||||||
semtech Semtech Corporation
|
semtech Semtech Corporation
|
||||||
sensirion Sensirion AG
|
sensirion Sensirion AG
|
||||||
|
sff Small Form Factor Committee
|
||||||
sgx SGX Sensortech
|
sgx SGX Sensortech
|
||||||
sharp Sharp Corporation
|
sharp Sharp Corporation
|
||||||
si-en Si-En Technology Ltd.
|
si-en Si-En Technology Ltd.
|
||||||
|
|
|
@ -409,7 +409,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card *card)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (len) {
|
if (len) {
|
||||||
if (!(card->flags & (channel) ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))
|
if (!(card->flags & (channel ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE)))
|
||||||
return 0;
|
return 0;
|
||||||
if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
|
if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -65,7 +65,7 @@ MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
|
||||||
*/
|
*/
|
||||||
static int debug;
|
static int debug;
|
||||||
module_param(debug, int, 0644);
|
module_param(debug, int, 0644);
|
||||||
MODULE_PARM_DESC(debug, "dm9000 debug level (0-4)");
|
MODULE_PARM_DESC(debug, "dm9000 debug level (0-6)");
|
||||||
|
|
||||||
/* DM9000 register address locking.
|
/* DM9000 register address locking.
|
||||||
*
|
*
|
||||||
|
|
|
@ -515,7 +515,7 @@ void comet_timer(unsigned long data);
|
||||||
extern int tulip_debug;
|
extern int tulip_debug;
|
||||||
extern const char * const medianame[];
|
extern const char * const medianame[];
|
||||||
extern const char tulip_media_cap[];
|
extern const char tulip_media_cap[];
|
||||||
extern struct tulip_chip_table tulip_tbl[];
|
extern const struct tulip_chip_table tulip_tbl[];
|
||||||
void oom_timer(unsigned long data);
|
void oom_timer(unsigned long data);
|
||||||
extern u8 t21040_csr13[];
|
extern u8 t21040_csr13[];
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ static void tulip_timer(unsigned long data)
|
||||||
* It is indexed via the values in 'enum chips'
|
* It is indexed via the values in 'enum chips'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct tulip_chip_table tulip_tbl[] = {
|
const struct tulip_chip_table tulip_tbl[] = {
|
||||||
{ }, /* placeholder for array, slot unused currently */
|
{ }, /* placeholder for array, slot unused currently */
|
||||||
{ }, /* placeholder for array, slot unused currently */
|
{ }, /* placeholder for array, slot unused currently */
|
||||||
|
|
||||||
|
|
|
@ -2145,7 +2145,6 @@ static void netcp_delete_interface(struct netcp_device *netcp_device,
|
||||||
|
|
||||||
of_node_put(netcp->node_interface);
|
of_node_put(netcp->node_interface);
|
||||||
unregister_netdev(ndev);
|
unregister_netdev(ndev);
|
||||||
netif_napi_del(&netcp->rx_napi);
|
|
||||||
free_netdev(ndev);
|
free_netdev(ndev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -399,7 +399,8 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put PHYs in RESET to save power */
|
/* Put PHYs in RESET to save power */
|
||||||
gpiod_set_value_cansleep(bus->reset_gpiod, 1);
|
if (bus->reset_gpiod)
|
||||||
|
gpiod_set_value_cansleep(bus->reset_gpiod, 1);
|
||||||
|
|
||||||
device_del(&bus->dev);
|
device_del(&bus->dev);
|
||||||
return err;
|
return err;
|
||||||
|
@ -424,7 +425,8 @@ void mdiobus_unregister(struct mii_bus *bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put PHYs in RESET to save power */
|
/* Put PHYs in RESET to save power */
|
||||||
gpiod_set_value_cansleep(bus->reset_gpiod, 1);
|
if (bus->reset_gpiod)
|
||||||
|
gpiod_set_value_cansleep(bus->reset_gpiod, 1);
|
||||||
|
|
||||||
device_del(&bus->dev);
|
device_del(&bus->dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,11 +58,11 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *gpio_of_names[] = {
|
static const char *gpio_of_names[] = {
|
||||||
"moddef0",
|
"mod-def0",
|
||||||
"los",
|
"los",
|
||||||
"tx-fault",
|
"tx-fault",
|
||||||
"tx-disable",
|
"tx-disable",
|
||||||
"rate-select",
|
"rate-select0",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const enum gpiod_flags gpio_flags[] = {
|
static const enum gpiod_flags gpio_flags[] = {
|
||||||
|
|
|
@ -159,7 +159,8 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
|
||||||
|
|
||||||
brcmf_feat_firmware_capabilities(ifp);
|
brcmf_feat_firmware_capabilities(ifp);
|
||||||
memset(&gscan_cfg, 0, sizeof(gscan_cfg));
|
memset(&gscan_cfg, 0, sizeof(gscan_cfg));
|
||||||
if (drvr->bus_if->chip != BRCM_CC_43430_CHIP_ID)
|
if (drvr->bus_if->chip != BRCM_CC_43430_CHIP_ID &&
|
||||||
|
drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID)
|
||||||
brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN,
|
brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN,
|
||||||
"pfn_gscan_cfg",
|
"pfn_gscan_cfg",
|
||||||
&gscan_cfg, sizeof(gscan_cfg));
|
&gscan_cfg, sizeof(gscan_cfg));
|
||||||
|
|
|
@ -378,6 +378,7 @@ enum iwl_ucode_tlv_capa {
|
||||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80,
|
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80,
|
||||||
IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81,
|
IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81,
|
||||||
IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84,
|
IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84,
|
||||||
|
IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)86,
|
||||||
IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96,
|
IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96,
|
||||||
|
|
||||||
NUM_IWL_UCODE_TLV_CAPA
|
NUM_IWL_UCODE_TLV_CAPA
|
||||||
|
|
|
@ -92,7 +92,8 @@ static void iwl_mvm_send_led_fw_cmd(struct iwl_mvm *mvm, bool on)
|
||||||
|
|
||||||
static void iwl_mvm_led_set(struct iwl_mvm *mvm, bool on)
|
static void iwl_mvm_led_set(struct iwl_mvm *mvm, bool on)
|
||||||
{
|
{
|
||||||
if (mvm->cfg->device_family >= IWL_DEVICE_FAMILY_8000) {
|
if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||||
|
IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT)) {
|
||||||
iwl_mvm_send_led_fw_cmd(mvm, on);
|
iwl_mvm_send_led_fw_cmd(mvm, on);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1362,8 +1362,6 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||||
txi->control.rates,
|
txi->control.rates,
|
||||||
ARRAY_SIZE(txi->control.rates));
|
ARRAY_SIZE(txi->control.rates));
|
||||||
|
|
||||||
txi->rate_driver_data[0] = channel;
|
|
||||||
|
|
||||||
if (skb->len >= 24 + 8 &&
|
if (skb->len >= 24 + 8 &&
|
||||||
ieee80211_is_probe_resp(hdr->frame_control)) {
|
ieee80211_is_probe_resp(hdr->frame_control)) {
|
||||||
/* fake header transmission time */
|
/* fake header transmission time */
|
||||||
|
|
|
@ -1183,7 +1183,10 @@ static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fixed internal switch S1->WiFi, S0->BT */
|
/* fixed internal switch S1->WiFi, S0->BT */
|
||||||
btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0);
|
if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
|
||||||
|
btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
|
||||||
|
else
|
||||||
|
btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
|
||||||
|
|
||||||
switch (antpos_type) {
|
switch (antpos_type) {
|
||||||
case BTC_ANT_WIFI_AT_MAIN:
|
case BTC_ANT_WIFI_AT_MAIN:
|
||||||
|
|
|
@ -173,6 +173,16 @@ static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist)
|
||||||
|
|
||||||
u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv)
|
u8 rtl_get_hwpg_single_ant_path(struct rtl_priv *rtlpriv)
|
||||||
{
|
{
|
||||||
|
struct rtl_mod_params *mod_params = rtlpriv->cfg->mod_params;
|
||||||
|
|
||||||
|
/* override ant_num / ant_path */
|
||||||
|
if (mod_params->ant_sel) {
|
||||||
|
rtlpriv->btcoexist.btc_info.ant_num =
|
||||||
|
(mod_params->ant_sel == 1 ? ANT_X2 : ANT_X1);
|
||||||
|
|
||||||
|
rtlpriv->btcoexist.btc_info.single_ant_path =
|
||||||
|
(mod_params->ant_sel == 1 ? 0 : 1);
|
||||||
|
}
|
||||||
return rtlpriv->btcoexist.btc_info.single_ant_path;
|
return rtlpriv->btcoexist.btc_info.single_ant_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +193,7 @@ u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv)
|
||||||
|
|
||||||
u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
|
u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
|
||||||
{
|
{
|
||||||
|
struct rtl_mod_params *mod_params = rtlpriv->cfg->mod_params;
|
||||||
u8 num;
|
u8 num;
|
||||||
|
|
||||||
if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2)
|
if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2)
|
||||||
|
@ -190,6 +201,10 @@ u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
|
||||||
else
|
else
|
||||||
num = 1;
|
num = 1;
|
||||||
|
|
||||||
|
/* override ant_num / ant_path */
|
||||||
|
if (mod_params->ant_sel)
|
||||||
|
num = (mod_params->ant_sel == 1 ? ANT_X2 : ANT_X1) + 1;
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,7 +891,7 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter)
|
||||||
{
|
{
|
||||||
struct btc_coexist *btcoexist = &gl_bt_coexist;
|
struct btc_coexist *btcoexist = &gl_bt_coexist;
|
||||||
struct rtl_priv *rtlpriv = adapter;
|
struct rtl_priv *rtlpriv = adapter;
|
||||||
u8 ant_num = 2, chip_type, single_ant_path = 0;
|
u8 ant_num = 2, chip_type;
|
||||||
|
|
||||||
if (btcoexist->binded)
|
if (btcoexist->binded)
|
||||||
return false;
|
return false;
|
||||||
|
@ -911,12 +926,6 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter)
|
||||||
ant_num = rtl_get_hwpg_ant_num(rtlpriv);
|
ant_num = rtl_get_hwpg_ant_num(rtlpriv);
|
||||||
exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num);
|
exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num);
|
||||||
|
|
||||||
/* set default antenna position to main port */
|
|
||||||
btcoexist->board_info.btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT;
|
|
||||||
|
|
||||||
single_ant_path = rtl_get_hwpg_single_ant_path(rtlpriv);
|
|
||||||
exhalbtc_set_single_ant_path(single_ant_path);
|
|
||||||
|
|
||||||
if (rtl_get_hwpg_package_type(rtlpriv) == 0)
|
if (rtl_get_hwpg_package_type(rtlpriv) == 0)
|
||||||
btcoexist->board_info.tfbga_package = false;
|
btcoexist->board_info.tfbga_package = false;
|
||||||
else if (rtl_get_hwpg_package_type(rtlpriv) == 1)
|
else if (rtl_get_hwpg_package_type(rtlpriv) == 1)
|
||||||
|
|
|
@ -385,16 +385,16 @@ static inline void __dev_map_flush(struct bpf_map *map)
|
||||||
|
|
||||||
#if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL)
|
#if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL)
|
||||||
struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key);
|
struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key);
|
||||||
int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type);
|
int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type);
|
||||||
#else
|
#else
|
||||||
static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
|
static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int sock_map_attach_prog(struct bpf_map *map,
|
static inline int sock_map_prog(struct bpf_map *map,
|
||||||
struct bpf_prog *prog,
|
struct bpf_prog *prog,
|
||||||
u32 type)
|
u32 type)
|
||||||
{
|
{
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -958,7 +958,7 @@ void kfree_skb(struct sk_buff *skb);
|
||||||
void kfree_skb_list(struct sk_buff *segs);
|
void kfree_skb_list(struct sk_buff *segs);
|
||||||
void skb_tx_error(struct sk_buff *skb);
|
void skb_tx_error(struct sk_buff *skb);
|
||||||
void consume_skb(struct sk_buff *skb);
|
void consume_skb(struct sk_buff *skb);
|
||||||
void consume_stateless_skb(struct sk_buff *skb);
|
void __consume_stateless_skb(struct sk_buff *skb);
|
||||||
void __kfree_skb(struct sk_buff *skb);
|
void __kfree_skb(struct sk_buff *skb);
|
||||||
extern struct kmem_cache *skbuff_head_cache;
|
extern struct kmem_cache *skbuff_head_cache;
|
||||||
|
|
||||||
|
|
|
@ -919,21 +919,10 @@ struct ieee80211_tx_info {
|
||||||
unsigned long jiffies;
|
unsigned long jiffies;
|
||||||
};
|
};
|
||||||
/* NB: vif can be NULL for injected frames */
|
/* NB: vif can be NULL for injected frames */
|
||||||
union {
|
struct ieee80211_vif *vif;
|
||||||
/* NB: vif can be NULL for injected frames */
|
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
|
|
||||||
/* When packets are enqueued on txq it's easy
|
|
||||||
* to re-construct the vif pointer. There's no
|
|
||||||
* more space in tx_info so it can be used to
|
|
||||||
* store the necessary enqueue time for packet
|
|
||||||
* sojourn time computation.
|
|
||||||
*/
|
|
||||||
codel_time_t enqueue_time;
|
|
||||||
};
|
|
||||||
struct ieee80211_key_conf *hw_key;
|
struct ieee80211_key_conf *hw_key;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
/* 4 bytes free */
|
codel_time_t enqueue_time;
|
||||||
} control;
|
} control;
|
||||||
struct {
|
struct {
|
||||||
u64 cookie;
|
u64 cookie;
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/rhashtable.h>
|
|
||||||
|
|
||||||
#include <linux/netfilter/nf_conntrack_tcp.h>
|
#include <linux/netfilter/nf_conntrack_tcp.h>
|
||||||
#include <linux/netfilter/nf_conntrack_dccp.h>
|
#include <linux/netfilter/nf_conntrack_dccp.h>
|
||||||
|
@ -77,7 +76,7 @@ struct nf_conn {
|
||||||
possible_net_t ct_net;
|
possible_net_t ct_net;
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||||
struct rhlist_head nat_bysource;
|
struct hlist_node nat_bysource;
|
||||||
#endif
|
#endif
|
||||||
/* all members below initialized via memset */
|
/* all members below initialized via memset */
|
||||||
u8 __nfct_init_offset[0];
|
u8 __nfct_init_offset[0];
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#ifndef _NF_NAT_H
|
#ifndef _NF_NAT_H
|
||||||
#define _NF_NAT_H
|
#define _NF_NAT_H
|
||||||
#include <linux/rhashtable.h>
|
|
||||||
#include <linux/netfilter_ipv4.h>
|
#include <linux/netfilter_ipv4.h>
|
||||||
#include <linux/netfilter/nf_nat.h>
|
#include <linux/netfilter/nf_nat.h>
|
||||||
#include <net/netfilter/nf_conntrack_tuple.h>
|
#include <net/netfilter/nf_conntrack_tuple.h>
|
||||||
|
|
|
@ -766,8 +766,8 @@ struct bpf_sock {
|
||||||
|
|
||||||
/* User return codes for XDP prog type.
|
/* User return codes for XDP prog type.
|
||||||
* A valid XDP program must return one of these defined values. All other
|
* A valid XDP program must return one of these defined values. All other
|
||||||
* return codes are reserved for future use. Unknown return codes will result
|
* return codes are reserved for future use. Unknown return codes will
|
||||||
* in packet drop.
|
* result in packet drops and a warning via bpf_warn_invalid_xdp_action().
|
||||||
*/
|
*/
|
||||||
enum xdp_action {
|
enum xdp_action {
|
||||||
XDP_ABORTED = 0,
|
XDP_ABORTED = 0,
|
||||||
|
|
|
@ -159,7 +159,7 @@ static void dev_map_free(struct bpf_map *map)
|
||||||
unsigned long *bitmap = per_cpu_ptr(dtab->flush_needed, cpu);
|
unsigned long *bitmap = per_cpu_ptr(dtab->flush_needed, cpu);
|
||||||
|
|
||||||
while (!bitmap_empty(bitmap, dtab->map.max_entries))
|
while (!bitmap_empty(bitmap, dtab->map.max_entries))
|
||||||
cpu_relax();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < dtab->map.max_entries; i++) {
|
for (i = 0; i < dtab->map.max_entries; i++) {
|
||||||
|
|
|
@ -792,7 +792,7 @@ out_progs:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type)
|
int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type)
|
||||||
{
|
{
|
||||||
struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
|
struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
|
||||||
struct bpf_prog *orig;
|
struct bpf_prog *orig;
|
||||||
|
|
|
@ -1096,10 +1096,10 @@ static int bpf_obj_get(const union bpf_attr *attr)
|
||||||
|
|
||||||
#define BPF_PROG_ATTACH_LAST_FIELD attach_flags
|
#define BPF_PROG_ATTACH_LAST_FIELD attach_flags
|
||||||
|
|
||||||
static int sockmap_get_from_fd(const union bpf_attr *attr)
|
static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach)
|
||||||
{
|
{
|
||||||
|
struct bpf_prog *prog = NULL;
|
||||||
int ufd = attr->target_fd;
|
int ufd = attr->target_fd;
|
||||||
struct bpf_prog *prog;
|
|
||||||
struct bpf_map *map;
|
struct bpf_map *map;
|
||||||
struct fd f;
|
struct fd f;
|
||||||
int err;
|
int err;
|
||||||
|
@ -1109,16 +1109,20 @@ static int sockmap_get_from_fd(const union bpf_attr *attr)
|
||||||
if (IS_ERR(map))
|
if (IS_ERR(map))
|
||||||
return PTR_ERR(map);
|
return PTR_ERR(map);
|
||||||
|
|
||||||
prog = bpf_prog_get_type(attr->attach_bpf_fd, BPF_PROG_TYPE_SK_SKB);
|
if (attach) {
|
||||||
if (IS_ERR(prog)) {
|
prog = bpf_prog_get_type(attr->attach_bpf_fd,
|
||||||
fdput(f);
|
BPF_PROG_TYPE_SK_SKB);
|
||||||
return PTR_ERR(prog);
|
if (IS_ERR(prog)) {
|
||||||
|
fdput(f);
|
||||||
|
return PTR_ERR(prog);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sock_map_attach_prog(map, prog, attr->attach_type);
|
err = sock_map_prog(map, prog, attr->attach_type);
|
||||||
if (err) {
|
if (err) {
|
||||||
fdput(f);
|
fdput(f);
|
||||||
bpf_prog_put(prog);
|
if (prog)
|
||||||
|
bpf_prog_put(prog);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1155,7 +1159,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
|
||||||
break;
|
break;
|
||||||
case BPF_SK_SKB_STREAM_PARSER:
|
case BPF_SK_SKB_STREAM_PARSER:
|
||||||
case BPF_SK_SKB_STREAM_VERDICT:
|
case BPF_SK_SKB_STREAM_VERDICT:
|
||||||
return sockmap_get_from_fd(attr);
|
return sockmap_get_from_fd(attr, true);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1204,7 +1208,10 @@ static int bpf_prog_detach(const union bpf_attr *attr)
|
||||||
ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
|
ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
|
||||||
cgroup_put(cgrp);
|
cgroup_put(cgrp);
|
||||||
break;
|
break;
|
||||||
|
case BPF_SK_SKB_STREAM_PARSER:
|
||||||
|
case BPF_SK_SKB_STREAM_VERDICT:
|
||||||
|
ret = sockmap_get_from_fd(attr, false);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4203,6 +4203,22 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (insn->imm == BPF_FUNC_redirect_map) {
|
||||||
|
u64 addr = (unsigned long)prog;
|
||||||
|
struct bpf_insn r4_ld[] = {
|
||||||
|
BPF_LD_IMM64(BPF_REG_4, addr),
|
||||||
|
*insn,
|
||||||
|
};
|
||||||
|
cnt = ARRAY_SIZE(r4_ld);
|
||||||
|
|
||||||
|
new_prog = bpf_patch_insn_data(env, i + delta, r4_ld, cnt);
|
||||||
|
if (!new_prog)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
delta += cnt - 1;
|
||||||
|
env->prog = prog = new_prog;
|
||||||
|
insn = new_prog->insnsi + i + delta;
|
||||||
|
}
|
||||||
patch_call_imm:
|
patch_call_imm:
|
||||||
fn = prog->aux->ops->get_func_proto(insn->imm);
|
fn = prog->aux->ops->get_func_proto(insn->imm);
|
||||||
/* all functions that have prototype and verifier allowed
|
/* all functions that have prototype and verifier allowed
|
||||||
|
|
|
@ -3981,8 +3981,13 @@ static int netif_rx_internal(struct sk_buff *skb)
|
||||||
trace_netif_rx(skb);
|
trace_netif_rx(skb);
|
||||||
|
|
||||||
if (static_key_false(&generic_xdp_needed)) {
|
if (static_key_false(&generic_xdp_needed)) {
|
||||||
int ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog),
|
int ret;
|
||||||
skb);
|
|
||||||
|
preempt_disable();
|
||||||
|
rcu_read_lock();
|
||||||
|
ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog), skb);
|
||||||
|
rcu_read_unlock();
|
||||||
|
preempt_enable();
|
||||||
|
|
||||||
/* Consider XDP consuming the packet a success from
|
/* Consider XDP consuming the packet a success from
|
||||||
* the netdev point of view we do not want to count
|
* the netdev point of view we do not want to count
|
||||||
|
@ -4500,18 +4505,20 @@ static int netif_receive_skb_internal(struct sk_buff *skb)
|
||||||
if (skb_defer_rx_timestamp(skb))
|
if (skb_defer_rx_timestamp(skb))
|
||||||
return NET_RX_SUCCESS;
|
return NET_RX_SUCCESS;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
if (static_key_false(&generic_xdp_needed)) {
|
if (static_key_false(&generic_xdp_needed)) {
|
||||||
int ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog),
|
int ret;
|
||||||
skb);
|
|
||||||
|
|
||||||
if (ret != XDP_PASS) {
|
preempt_disable();
|
||||||
rcu_read_unlock();
|
rcu_read_lock();
|
||||||
|
ret = do_xdp_generic(rcu_dereference(skb->dev->xdp_prog), skb);
|
||||||
|
rcu_read_unlock();
|
||||||
|
preempt_enable();
|
||||||
|
|
||||||
|
if (ret != XDP_PASS)
|
||||||
return NET_RX_DROP;
|
return NET_RX_DROP;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_RPS
|
||||||
if (static_key_false(&rps_needed)) {
|
if (static_key_false(&rps_needed)) {
|
||||||
struct rps_dev_flow voidflow, *rflow = &voidflow;
|
struct rps_dev_flow voidflow, *rflow = &voidflow;
|
||||||
|
|
|
@ -1794,6 +1794,7 @@ struct redirect_info {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
struct bpf_map *map;
|
struct bpf_map *map;
|
||||||
struct bpf_map *map_to_flush;
|
struct bpf_map *map_to_flush;
|
||||||
|
const struct bpf_prog *map_owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct redirect_info, redirect_info);
|
static DEFINE_PER_CPU(struct redirect_info, redirect_info);
|
||||||
|
@ -1807,7 +1808,6 @@ BPF_CALL_2(bpf_redirect, u32, ifindex, u64, flags)
|
||||||
|
|
||||||
ri->ifindex = ifindex;
|
ri->ifindex = ifindex;
|
||||||
ri->flags = flags;
|
ri->flags = flags;
|
||||||
ri->map = NULL;
|
|
||||||
|
|
||||||
return TC_ACT_REDIRECT;
|
return TC_ACT_REDIRECT;
|
||||||
}
|
}
|
||||||
|
@ -2504,6 +2504,7 @@ static int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp,
|
||||||
struct bpf_prog *xdp_prog)
|
struct bpf_prog *xdp_prog)
|
||||||
{
|
{
|
||||||
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
|
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
|
||||||
|
const struct bpf_prog *map_owner = ri->map_owner;
|
||||||
struct bpf_map *map = ri->map;
|
struct bpf_map *map = ri->map;
|
||||||
u32 index = ri->ifindex;
|
u32 index = ri->ifindex;
|
||||||
struct net_device *fwd;
|
struct net_device *fwd;
|
||||||
|
@ -2511,6 +2512,15 @@ static int xdp_do_redirect_map(struct net_device *dev, struct xdp_buff *xdp,
|
||||||
|
|
||||||
ri->ifindex = 0;
|
ri->ifindex = 0;
|
||||||
ri->map = NULL;
|
ri->map = NULL;
|
||||||
|
ri->map_owner = NULL;
|
||||||
|
|
||||||
|
/* This is really only caused by a deliberately crappy
|
||||||
|
* BPF program, normally we would never hit that case,
|
||||||
|
* so no need to inform someone via tracepoints either,
|
||||||
|
* just bail out.
|
||||||
|
*/
|
||||||
|
if (unlikely(map_owner != xdp_prog))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
fwd = __dev_map_lookup_elem(map, index);
|
fwd = __dev_map_lookup_elem(map, index);
|
||||||
if (!fwd) {
|
if (!fwd) {
|
||||||
|
@ -2607,6 +2617,8 @@ BPF_CALL_2(bpf_xdp_redirect, u32, ifindex, u64, flags)
|
||||||
|
|
||||||
ri->ifindex = ifindex;
|
ri->ifindex = ifindex;
|
||||||
ri->flags = flags;
|
ri->flags = flags;
|
||||||
|
ri->map = NULL;
|
||||||
|
ri->map_owner = NULL;
|
||||||
|
|
||||||
return XDP_REDIRECT;
|
return XDP_REDIRECT;
|
||||||
}
|
}
|
||||||
|
@ -2619,7 +2631,8 @@ static const struct bpf_func_proto bpf_xdp_redirect_proto = {
|
||||||
.arg2_type = ARG_ANYTHING,
|
.arg2_type = ARG_ANYTHING,
|
||||||
};
|
};
|
||||||
|
|
||||||
BPF_CALL_3(bpf_xdp_redirect_map, struct bpf_map *, map, u32, ifindex, u64, flags)
|
BPF_CALL_4(bpf_xdp_redirect_map, struct bpf_map *, map, u32, ifindex, u64, flags,
|
||||||
|
const struct bpf_prog *, map_owner)
|
||||||
{
|
{
|
||||||
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
|
struct redirect_info *ri = this_cpu_ptr(&redirect_info);
|
||||||
|
|
||||||
|
@ -2629,10 +2642,14 @@ BPF_CALL_3(bpf_xdp_redirect_map, struct bpf_map *, map, u32, ifindex, u64, flags
|
||||||
ri->ifindex = ifindex;
|
ri->ifindex = ifindex;
|
||||||
ri->flags = flags;
|
ri->flags = flags;
|
||||||
ri->map = map;
|
ri->map = map;
|
||||||
|
ri->map_owner = map_owner;
|
||||||
|
|
||||||
return XDP_REDIRECT;
|
return XDP_REDIRECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note, arg4 is hidden from users and populated by the verifier
|
||||||
|
* with the right pointer.
|
||||||
|
*/
|
||||||
static const struct bpf_func_proto bpf_xdp_redirect_map_proto = {
|
static const struct bpf_func_proto bpf_xdp_redirect_map_proto = {
|
||||||
.func = bpf_xdp_redirect_map,
|
.func = bpf_xdp_redirect_map,
|
||||||
.gpl_only = false,
|
.gpl_only = false,
|
||||||
|
@ -3592,7 +3609,11 @@ static bool xdp_is_valid_access(int off, int size,
|
||||||
|
|
||||||
void bpf_warn_invalid_xdp_action(u32 act)
|
void bpf_warn_invalid_xdp_action(u32 act)
|
||||||
{
|
{
|
||||||
WARN_ONCE(1, "Illegal XDP return value %u, expect packet loss\n", act);
|
const u32 act_max = XDP_REDIRECT;
|
||||||
|
|
||||||
|
WARN_ONCE(1, "%s XDP return value %u, expect packet loss!\n",
|
||||||
|
act > act_max ? "Illegal" : "Driver unsupported",
|
||||||
|
act);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action);
|
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action);
|
||||||
|
|
||||||
|
|
|
@ -710,14 +710,11 @@ EXPORT_SYMBOL(consume_skb);
|
||||||
* consume_stateless_skb - free an skbuff, assuming it is stateless
|
* consume_stateless_skb - free an skbuff, assuming it is stateless
|
||||||
* @skb: buffer to free
|
* @skb: buffer to free
|
||||||
*
|
*
|
||||||
* Works like consume_skb(), but this variant assumes that all the head
|
* Alike consume_skb(), but this variant assumes that this is the last
|
||||||
* states have been already dropped.
|
* skb reference and all the head states have been already dropped
|
||||||
*/
|
*/
|
||||||
void consume_stateless_skb(struct sk_buff *skb)
|
void __consume_stateless_skb(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
if (!skb_unref(skb))
|
|
||||||
return;
|
|
||||||
|
|
||||||
trace_consume_skb(skb);
|
trace_consume_skb(skb);
|
||||||
skb_release_data(skb);
|
skb_release_data(skb);
|
||||||
kfree_skbmem(skb);
|
kfree_skbmem(skb);
|
||||||
|
|
|
@ -618,8 +618,8 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto)
|
||||||
ip_rt_put(rt);
|
ip_rt_put(rt);
|
||||||
goto tx_dropped;
|
goto tx_dropped;
|
||||||
}
|
}
|
||||||
iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, key->tos,
|
iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
|
||||||
key->ttl, df, !net_eq(tunnel->net, dev_net(dev)));
|
df, !net_eq(tunnel->net, dev_net(dev)));
|
||||||
return;
|
return;
|
||||||
tx_error:
|
tx_error:
|
||||||
dev->stats.tx_errors++;
|
dev->stats.tx_errors++;
|
||||||
|
|
|
@ -629,6 +629,7 @@ static void get_counters(const struct xt_table_info *t,
|
||||||
|
|
||||||
ADD_COUNTER(counters[i], bcnt, pcnt);
|
ADD_COUNTER(counters[i], bcnt, pcnt);
|
||||||
++i;
|
++i;
|
||||||
|
cond_resched();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -776,6 +776,7 @@ get_counters(const struct xt_table_info *t,
|
||||||
|
|
||||||
ADD_COUNTER(counters[i], bcnt, pcnt);
|
ADD_COUNTER(counters[i], bcnt, pcnt);
|
||||||
++i; /* macro does multi eval of i */
|
++i; /* macro does multi eval of i */
|
||||||
|
cond_resched();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1669,9 +1669,9 @@ process:
|
||||||
*/
|
*/
|
||||||
sock_hold(sk);
|
sock_hold(sk);
|
||||||
refcounted = true;
|
refcounted = true;
|
||||||
if (tcp_filter(sk, skb))
|
nsk = NULL;
|
||||||
goto discard_and_relse;
|
if (!tcp_filter(sk, skb))
|
||||||
nsk = tcp_check_req(sk, skb, req, false);
|
nsk = tcp_check_req(sk, skb, req, false);
|
||||||
if (!nsk) {
|
if (!nsk) {
|
||||||
reqsk_put(req);
|
reqsk_put(req);
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
|
|
|
@ -1397,12 +1397,15 @@ void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len)
|
||||||
unlock_sock_fast(sk, slow);
|
unlock_sock_fast(sk, slow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skb_unref(skb))
|
||||||
|
return;
|
||||||
|
|
||||||
/* In the more common cases we cleared the head states previously,
|
/* In the more common cases we cleared the head states previously,
|
||||||
* see __udp_queue_rcv_skb().
|
* see __udp_queue_rcv_skb().
|
||||||
*/
|
*/
|
||||||
if (unlikely(udp_skb_has_head_state(skb)))
|
if (unlikely(udp_skb_has_head_state(skb)))
|
||||||
skb_release_head_state(skb);
|
skb_release_head_state(skb);
|
||||||
consume_stateless_skb(skb);
|
__consume_stateless_skb(skb);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(skb_consume_udp);
|
EXPORT_SYMBOL_GPL(skb_consume_udp);
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,12 @@ void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt6_free_pcpu);
|
EXPORT_SYMBOL_GPL(rt6_free_pcpu);
|
||||||
|
|
||||||
|
static void fib6_free_table(struct fib6_table *table)
|
||||||
|
{
|
||||||
|
inetpeer_invalidate_tree(&table->tb6_peers);
|
||||||
|
kfree(table);
|
||||||
|
}
|
||||||
|
|
||||||
static void fib6_link_table(struct net *net, struct fib6_table *tb)
|
static void fib6_link_table(struct net *net, struct fib6_table *tb)
|
||||||
{
|
{
|
||||||
unsigned int h;
|
unsigned int h;
|
||||||
|
@ -2022,15 +2028,22 @@ out_timer:
|
||||||
|
|
||||||
static void fib6_net_exit(struct net *net)
|
static void fib6_net_exit(struct net *net)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
rt6_ifdown(net, NULL);
|
rt6_ifdown(net, NULL);
|
||||||
del_timer_sync(&net->ipv6.ip6_fib_timer);
|
del_timer_sync(&net->ipv6.ip6_fib_timer);
|
||||||
|
|
||||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
for (i = 0; i < FIB6_TABLE_HASHSZ; i++) {
|
||||||
inetpeer_invalidate_tree(&net->ipv6.fib6_local_tbl->tb6_peers);
|
struct hlist_head *head = &net->ipv6.fib_table_hash[i];
|
||||||
kfree(net->ipv6.fib6_local_tbl);
|
struct hlist_node *tmp;
|
||||||
#endif
|
struct fib6_table *tb;
|
||||||
inetpeer_invalidate_tree(&net->ipv6.fib6_main_tbl->tb6_peers);
|
|
||||||
kfree(net->ipv6.fib6_main_tbl);
|
hlist_for_each_entry_safe(tb, tmp, head, tb6_hlist) {
|
||||||
|
hlist_del(&tb->tb6_hlist);
|
||||||
|
fib6_free_table(tb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kfree(net->ipv6.fib_table_hash);
|
kfree(net->ipv6.fib_table_hash);
|
||||||
kfree(net->ipv6.rt6_stats);
|
kfree(net->ipv6.rt6_stats);
|
||||||
fib6_notifier_exit(net);
|
fib6_notifier_exit(net);
|
||||||
|
|
|
@ -432,7 +432,9 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ICMPV6_PKT_TOOBIG:
|
case ICMPV6_PKT_TOOBIG:
|
||||||
mtu = be32_to_cpu(info) - offset;
|
mtu = be32_to_cpu(info) - offset - t->tun_hlen;
|
||||||
|
if (t->dev->type == ARPHRD_ETHER)
|
||||||
|
mtu -= ETH_HLEN;
|
||||||
if (mtu < IPV6_MIN_MTU)
|
if (mtu < IPV6_MIN_MTU)
|
||||||
mtu = IPV6_MIN_MTU;
|
mtu = IPV6_MIN_MTU;
|
||||||
t->dev->mtu = mtu;
|
t->dev->mtu = mtu;
|
||||||
|
|
|
@ -1184,6 +1184,7 @@ route_lookup:
|
||||||
init_tel_txopt(&opt, encap_limit);
|
init_tel_txopt(&opt, encap_limit);
|
||||||
ipv6_push_frag_opts(skb, &opt.ops, &proto);
|
ipv6_push_frag_opts(skb, &opt.ops, &proto);
|
||||||
}
|
}
|
||||||
|
hop_limit = hop_limit ? : ip6_dst_hoplimit(dst);
|
||||||
|
|
||||||
/* Calculate max headroom for all the headers and adjust
|
/* Calculate max headroom for all the headers and adjust
|
||||||
* needed_headroom if necessary.
|
* needed_headroom if necessary.
|
||||||
|
|
|
@ -795,6 +795,7 @@ get_counters(const struct xt_table_info *t,
|
||||||
|
|
||||||
ADD_COUNTER(counters[i], bcnt, pcnt);
|
ADD_COUNTER(counters[i], bcnt, pcnt);
|
||||||
++i;
|
++i;
|
||||||
|
cond_resched();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1460,9 +1460,9 @@ process:
|
||||||
}
|
}
|
||||||
sock_hold(sk);
|
sock_hold(sk);
|
||||||
refcounted = true;
|
refcounted = true;
|
||||||
if (tcp_filter(sk, skb))
|
nsk = NULL;
|
||||||
goto discard_and_relse;
|
if (!tcp_filter(sk, skb))
|
||||||
nsk = tcp_check_req(sk, skb, req, false);
|
nsk = tcp_check_req(sk, skb, req, false);
|
||||||
if (!nsk) {
|
if (!nsk) {
|
||||||
reqsk_put(req);
|
reqsk_put(req);
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
|
|
|
@ -245,10 +245,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
||||||
ieee80211_tx_skb(sdata, skb);
|
ieee80211_tx_skb(sdata, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
u8 dialog_token, u16 timeout,
|
u8 dialog_token, u16 timeout,
|
||||||
u16 start_seq_num, u16 ba_policy, u16 tid,
|
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||||
u16 buf_size, bool tx, bool auto_seq)
|
u16 buf_size, bool tx, bool auto_seq)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sta->sdata->local;
|
struct ieee80211_local *local = sta->sdata->local;
|
||||||
struct tid_ampdu_rx *tid_agg_rx;
|
struct tid_ampdu_rx *tid_agg_rx;
|
||||||
|
@ -267,7 +267,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
ht_dbg(sta->sdata,
|
ht_dbg(sta->sdata,
|
||||||
"STA %pM requests BA session on unsupported tid %d\n",
|
"STA %pM requests BA session on unsupported tid %d\n",
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
goto end_no_lock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sta->sta.ht_cap.ht_supported) {
|
if (!sta->sta.ht_cap.ht_supported) {
|
||||||
|
@ -275,14 +275,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
"STA %pM erroneously requests BA session on tid %d w/o QoS\n",
|
"STA %pM erroneously requests BA session on tid %d w/o QoS\n",
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
/* send a response anyway, it's an error case if we get here */
|
/* send a response anyway, it's an error case if we get here */
|
||||||
goto end_no_lock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
||||||
ht_dbg(sta->sdata,
|
ht_dbg(sta->sdata,
|
||||||
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
|
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
goto end_no_lock;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sanity check for incoming parameters:
|
/* sanity check for incoming parameters:
|
||||||
|
@ -296,7 +296,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
ht_dbg_ratelimited(sta->sdata,
|
ht_dbg_ratelimited(sta->sdata,
|
||||||
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
|
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
|
||||||
sta->sta.addr, tid, ba_policy, buf_size);
|
sta->sta.addr, tid, ba_policy, buf_size);
|
||||||
goto end_no_lock;
|
goto end;
|
||||||
}
|
}
|
||||||
/* determine default buffer size */
|
/* determine default buffer size */
|
||||||
if (buf_size == 0)
|
if (buf_size == 0)
|
||||||
|
@ -311,7 +311,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
buf_size, sta->sta.addr);
|
buf_size, sta->sta.addr);
|
||||||
|
|
||||||
/* examine state machine */
|
/* examine state machine */
|
||||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
||||||
|
|
||||||
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
|
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
|
||||||
if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
|
if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
|
||||||
|
@ -415,15 +415,25 @@ end:
|
||||||
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
|
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
|
||||||
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
|
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
|
||||||
}
|
}
|
||||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
|
||||||
|
|
||||||
end_no_lock:
|
|
||||||
if (tx)
|
if (tx)
|
||||||
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
|
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
|
||||||
dialog_token, status, 1, buf_size,
|
dialog_token, status, 1, buf_size,
|
||||||
timeout);
|
timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
|
u8 dialog_token, u16 timeout,
|
||||||
|
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||||
|
u16 buf_size, bool tx, bool auto_seq)
|
||||||
|
{
|
||||||
|
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||||
|
___ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
|
||||||
|
start_seq_num, ba_policy, tid,
|
||||||
|
buf_size, tx, auto_seq);
|
||||||
|
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||||
|
}
|
||||||
|
|
||||||
void ieee80211_process_addba_request(struct ieee80211_local *local,
|
void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||||
struct sta_info *sta,
|
struct sta_info *sta,
|
||||||
struct ieee80211_mgmt *mgmt,
|
struct ieee80211_mgmt *mgmt,
|
||||||
|
|
|
@ -226,7 +226,11 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
|
||||||
clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
|
clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
|
||||||
|
|
||||||
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||||
|
local_bh_disable();
|
||||||
|
rcu_read_lock();
|
||||||
drv_wake_tx_queue(sta->sdata->local, txqi);
|
drv_wake_tx_queue(sta->sdata->local, txqi);
|
||||||
|
rcu_read_unlock();
|
||||||
|
local_bh_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -436,7 +440,7 @@ static void sta_addba_resp_timer_expired(unsigned long data)
|
||||||
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
|
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
ht_dbg(sta->sdata,
|
ht_dbg(sta->sdata,
|
||||||
"timer expired on %pM tid %d but we are not (or no longer) expecting addBA response there\n",
|
"timer expired on %pM tid %d not expecting addBA response\n",
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -639,7 +643,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||||
time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
|
time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
|
||||||
HT_AGG_RETRIES_PERIOD)) {
|
HT_AGG_RETRIES_PERIOD)) {
|
||||||
ht_dbg(sdata,
|
ht_dbg(sdata,
|
||||||
"BA request denied - waiting a grace period after %d failed requests on %pM tid %u\n",
|
"BA request denied - %d failed requests on %pM tid %u\n",
|
||||||
sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
|
sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto err_unlock_sta;
|
goto err_unlock_sta;
|
||||||
|
|
|
@ -300,6 +300,24 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
|
||||||
|
|
||||||
/* stopping might queue the work again - so cancel only afterwards */
|
/* stopping might queue the work again - so cancel only afterwards */
|
||||||
cancel_work_sync(&sta->ampdu_mlme.work);
|
cancel_work_sync(&sta->ampdu_mlme.work);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case the tear down is part of a reconfigure due to HW restart
|
||||||
|
* request, it is possible that the low level driver requested to stop
|
||||||
|
* the BA session, so handle it to properly clean tid_tx data.
|
||||||
|
*/
|
||||||
|
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||||
|
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||||
|
struct tid_ampdu_tx *tid_tx =
|
||||||
|
rcu_dereference_protected_tid_tx(sta, i);
|
||||||
|
|
||||||
|
if (!tid_tx)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (test_and_clear_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state))
|
||||||
|
ieee80211_stop_tx_ba_cb(sta, i, tid_tx);
|
||||||
|
}
|
||||||
|
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ieee80211_ba_session_work(struct work_struct *work)
|
void ieee80211_ba_session_work(struct work_struct *work)
|
||||||
|
@ -333,9 +351,9 @@ void ieee80211_ba_session_work(struct work_struct *work)
|
||||||
|
|
||||||
if (test_and_clear_bit(tid,
|
if (test_and_clear_bit(tid,
|
||||||
sta->ampdu_mlme.tid_rx_manage_offl))
|
sta->ampdu_mlme.tid_rx_manage_offl))
|
||||||
__ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
|
___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
|
||||||
IEEE80211_MAX_AMPDU_BUF,
|
IEEE80211_MAX_AMPDU_BUF,
|
||||||
false, true);
|
false, true);
|
||||||
|
|
||||||
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
|
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
|
||||||
sta->ampdu_mlme.tid_rx_manage_offl))
|
sta->ampdu_mlme.tid_rx_manage_offl))
|
||||||
|
|
|
@ -1760,6 +1760,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
u8 dialog_token, u16 timeout,
|
u8 dialog_token, u16 timeout,
|
||||||
u16 start_seq_num, u16 ba_policy, u16 tid,
|
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||||
u16 buf_size, bool tx, bool auto_seq);
|
u16 buf_size, bool tx, bool auto_seq);
|
||||||
|
void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
|
u8 dialog_token, u16 timeout,
|
||||||
|
u16 start_seq_num, u16 ba_policy, u16 tid,
|
||||||
|
u16 buf_size, bool tx, bool auto_seq);
|
||||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
|
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
|
||||||
enum ieee80211_agg_stop_reason reason);
|
enum ieee80211_agg_stop_reason reason);
|
||||||
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
|
@ -731,7 +731,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||||
local->ops->wake_tx_queue) {
|
local->ops->wake_tx_queue) {
|
||||||
/* XXX: for AP_VLAN, actually track AP queues */
|
/* XXX: for AP_VLAN, actually track AP queues */
|
||||||
netif_tx_start_all_queues(dev);
|
if (dev)
|
||||||
|
netif_tx_start_all_queues(dev);
|
||||||
} else if (dev) {
|
} else if (dev) {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int n_acs = IEEE80211_NUM_ACS;
|
int n_acs = IEEE80211_NUM_ACS;
|
||||||
|
@ -792,6 +793,7 @@ static int ieee80211_open(struct net_device *dev)
|
||||||
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||||
bool going_down)
|
bool going_down)
|
||||||
{
|
{
|
||||||
|
struct ieee80211_sub_if_data *txq_sdata = sdata;
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
struct fq *fq = &local->fq;
|
struct fq *fq = &local->fq;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -937,6 +939,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
switch (sdata->vif.type) {
|
switch (sdata->vif.type) {
|
||||||
case NL80211_IFTYPE_AP_VLAN:
|
case NL80211_IFTYPE_AP_VLAN:
|
||||||
|
txq_sdata = container_of(sdata->bss,
|
||||||
|
struct ieee80211_sub_if_data, u.ap);
|
||||||
|
|
||||||
mutex_lock(&local->mtx);
|
mutex_lock(&local->mtx);
|
||||||
list_del(&sdata->u.vlan.list);
|
list_del(&sdata->u.vlan.list);
|
||||||
mutex_unlock(&local->mtx);
|
mutex_unlock(&local->mtx);
|
||||||
|
@ -1007,8 +1012,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||||
|
|
||||||
if (sdata->vif.txq) {
|
if (txq_sdata->vif.txq) {
|
||||||
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
|
struct txq_info *txqi = to_txq_info(txq_sdata->vif.txq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME FIXME
|
||||||
|
*
|
||||||
|
* We really shouldn't purge the *entire* txqi since that
|
||||||
|
* contains frames for the other AP_VLANs (and possibly
|
||||||
|
* the AP itself) as well, but there's no API in FQ now
|
||||||
|
* to be able to filter.
|
||||||
|
*/
|
||||||
|
|
||||||
spin_lock_bh(&fq->lock);
|
spin_lock_bh(&fq->lock);
|
||||||
ieee80211_txq_purge(local, txqi);
|
ieee80211_txq_purge(local, txqi);
|
||||||
|
|
|
@ -3155,7 +3155,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||||
if (len < 24 + 6)
|
if (len < 24 + 6)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
reassoc = ieee80211_is_reassoc_req(mgmt->frame_control);
|
reassoc = ieee80211_is_reassoc_resp(mgmt->frame_control);
|
||||||
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
||||||
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||||
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
||||||
|
|
|
@ -707,6 +707,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
|
||||||
if (!cookie)
|
if (!cookie)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
|
flush_work(&local->hw_roc_start);
|
||||||
|
|
||||||
mutex_lock(&local->mtx);
|
mutex_lock(&local->mtx);
|
||||||
list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
|
list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
|
||||||
if (!mgmt_tx && roc->cookie != cookie)
|
if (!mgmt_tx && roc->cookie != cookie)
|
||||||
|
|
|
@ -1276,11 +1276,6 @@ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
|
||||||
IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
|
IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ieee80211_set_skb_vif(struct sk_buff *skb, struct txq_info *txqi)
|
|
||||||
{
|
|
||||||
IEEE80211_SKB_CB(skb)->control.vif = txqi->txq.vif;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 codel_skb_len_func(const struct sk_buff *skb)
|
static u32 codel_skb_len_func(const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
return skb->len;
|
return skb->len;
|
||||||
|
@ -3414,6 +3409,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_tx_info *info;
|
struct ieee80211_tx_info *info;
|
||||||
struct ieee80211_tx_data tx;
|
struct ieee80211_tx_data tx;
|
||||||
ieee80211_tx_result r;
|
ieee80211_tx_result r;
|
||||||
|
struct ieee80211_vif *vif;
|
||||||
|
|
||||||
spin_lock_bh(&fq->lock);
|
spin_lock_bh(&fq->lock);
|
||||||
|
|
||||||
|
@ -3430,8 +3426,6 @@ begin:
|
||||||
if (!skb)
|
if (!skb)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ieee80211_set_skb_vif(skb, txqi);
|
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *)skb->data;
|
hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
info = IEEE80211_SKB_CB(skb);
|
info = IEEE80211_SKB_CB(skb);
|
||||||
|
|
||||||
|
@ -3488,6 +3482,34 @@ begin:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (tx.sdata->vif.type) {
|
||||||
|
case NL80211_IFTYPE_MONITOR:
|
||||||
|
if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
|
||||||
|
vif = &tx.sdata->vif;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tx.sdata = rcu_dereference(local->monitor_sdata);
|
||||||
|
if (tx.sdata) {
|
||||||
|
vif = &tx.sdata->vif;
|
||||||
|
info->hw_queue =
|
||||||
|
vif->hw_queue[skb_get_queue_mapping(skb)];
|
||||||
|
} else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
|
||||||
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
|
goto begin;
|
||||||
|
} else {
|
||||||
|
vif = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_AP_VLAN:
|
||||||
|
tx.sdata = container_of(tx.sdata->bss,
|
||||||
|
struct ieee80211_sub_if_data, u.ap);
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
vif = &tx.sdata->vif;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEEE80211_SKB_CB(skb)->control.vif = vif;
|
||||||
out:
|
out:
|
||||||
spin_unlock_bh(&fq->lock);
|
spin_unlock_bh(&fq->lock);
|
||||||
|
|
||||||
|
|
|
@ -1436,7 +1436,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||||
WLAN_EID_SSID_LIST,
|
WLAN_EID_SSID_LIST,
|
||||||
WLAN_EID_CHANNEL_USAGE,
|
WLAN_EID_CHANNEL_USAGE,
|
||||||
WLAN_EID_INTERWORKING,
|
WLAN_EID_INTERWORKING,
|
||||||
/* mesh ID can't happen here */
|
WLAN_EID_MESH_ID,
|
||||||
/* 60 GHz can't happen here right now */
|
/* 60 GHz can't happen here right now */
|
||||||
};
|
};
|
||||||
noffset = ieee80211_ie_split(ie, ie_len,
|
noffset = ieee80211_ie_split(ie, ie_len,
|
||||||
|
|
|
@ -215,7 +215,7 @@ static void *__nf_hook_entries_try_shrink(struct nf_hook_entries __rcu **pp)
|
||||||
if (skip == hook_entries)
|
if (skip == hook_entries)
|
||||||
goto out_assign;
|
goto out_assign;
|
||||||
|
|
||||||
if (WARN_ON(skip == 0))
|
if (skip == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
hook_entries -= skip;
|
hook_entries -= skip;
|
||||||
|
|
|
@ -24,9 +24,13 @@ sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
|
||||||
if (sh) {
|
if (sh) {
|
||||||
sch = skb_header_pointer(skb, iph->len + sizeof(_sctph),
|
sch = skb_header_pointer(skb, iph->len + sizeof(_sctph),
|
||||||
sizeof(_schunkh), &_schunkh);
|
sizeof(_schunkh), &_schunkh);
|
||||||
if (sch && (sch->type == SCTP_CID_INIT ||
|
if (sch) {
|
||||||
sysctl_sloppy_sctp(ipvs)))
|
if (sch->type == SCTP_CID_ABORT ||
|
||||||
|
!(sysctl_sloppy_sctp(ipvs) ||
|
||||||
|
sch->type == SCTP_CID_INIT))
|
||||||
|
return 1;
|
||||||
ports = &sh->source;
|
ports = &sh->source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ports = skb_header_pointer(
|
ports = skb_header_pointer(
|
||||||
|
|
|
@ -30,19 +30,17 @@
|
||||||
#include <net/netfilter/nf_conntrack_zones.h>
|
#include <net/netfilter/nf_conntrack_zones.h>
|
||||||
#include <linux/netfilter/nf_nat.h>
|
#include <linux/netfilter/nf_nat.h>
|
||||||
|
|
||||||
|
static spinlock_t nf_nat_locks[CONNTRACK_LOCKS];
|
||||||
|
|
||||||
static DEFINE_MUTEX(nf_nat_proto_mutex);
|
static DEFINE_MUTEX(nf_nat_proto_mutex);
|
||||||
static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO]
|
static const struct nf_nat_l3proto __rcu *nf_nat_l3protos[NFPROTO_NUMPROTO]
|
||||||
__read_mostly;
|
__read_mostly;
|
||||||
static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO]
|
static const struct nf_nat_l4proto __rcu **nf_nat_l4protos[NFPROTO_NUMPROTO]
|
||||||
__read_mostly;
|
__read_mostly;
|
||||||
|
|
||||||
struct nf_nat_conn_key {
|
static struct hlist_head *nf_nat_bysource __read_mostly;
|
||||||
const struct net *net;
|
static unsigned int nf_nat_htable_size __read_mostly;
|
||||||
const struct nf_conntrack_tuple *tuple;
|
static unsigned int nf_nat_hash_rnd __read_mostly;
|
||||||
const struct nf_conntrack_zone *zone;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct rhltable nf_nat_bysource_table;
|
|
||||||
|
|
||||||
inline const struct nf_nat_l3proto *
|
inline const struct nf_nat_l3proto *
|
||||||
__nf_nat_l3proto_find(u8 family)
|
__nf_nat_l3proto_find(u8 family)
|
||||||
|
@ -118,17 +116,19 @@ int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
|
||||||
EXPORT_SYMBOL(nf_xfrm_me_harder);
|
EXPORT_SYMBOL(nf_xfrm_me_harder);
|
||||||
#endif /* CONFIG_XFRM */
|
#endif /* CONFIG_XFRM */
|
||||||
|
|
||||||
static u32 nf_nat_bysource_hash(const void *data, u32 len, u32 seed)
|
/* We keep an extra hash for each conntrack, for fast searching. */
|
||||||
|
static unsigned int
|
||||||
|
hash_by_src(const struct net *n, const struct nf_conntrack_tuple *tuple)
|
||||||
{
|
{
|
||||||
const struct nf_conntrack_tuple *t;
|
unsigned int hash;
|
||||||
const struct nf_conn *ct = data;
|
|
||||||
|
get_random_once(&nf_nat_hash_rnd, sizeof(nf_nat_hash_rnd));
|
||||||
|
|
||||||
t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
|
|
||||||
/* Original src, to ensure we map it consistently if poss. */
|
/* Original src, to ensure we map it consistently if poss. */
|
||||||
|
hash = jhash2((u32 *)&tuple->src, sizeof(tuple->src) / sizeof(u32),
|
||||||
|
tuple->dst.protonum ^ nf_nat_hash_rnd ^ net_hash_mix(n));
|
||||||
|
|
||||||
seed ^= net_hash_mix(nf_ct_net(ct));
|
return reciprocal_scale(hash, nf_nat_htable_size);
|
||||||
return jhash2((const u32 *)&t->src, sizeof(t->src) / sizeof(u32),
|
|
||||||
t->dst.protonum ^ seed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this tuple already taken? (not by us) */
|
/* Is this tuple already taken? (not by us) */
|
||||||
|
@ -184,28 +184,6 @@ same_src(const struct nf_conn *ct,
|
||||||
t->src.u.all == tuple->src.u.all);
|
t->src.u.all == tuple->src.u.all);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nf_nat_bysource_cmp(struct rhashtable_compare_arg *arg,
|
|
||||||
const void *obj)
|
|
||||||
{
|
|
||||||
const struct nf_nat_conn_key *key = arg->key;
|
|
||||||
const struct nf_conn *ct = obj;
|
|
||||||
|
|
||||||
if (!same_src(ct, key->tuple) ||
|
|
||||||
!net_eq(nf_ct_net(ct), key->net) ||
|
|
||||||
!nf_ct_zone_equal(ct, key->zone, IP_CT_DIR_ORIGINAL))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct rhashtable_params nf_nat_bysource_params = {
|
|
||||||
.head_offset = offsetof(struct nf_conn, nat_bysource),
|
|
||||||
.obj_hashfn = nf_nat_bysource_hash,
|
|
||||||
.obj_cmpfn = nf_nat_bysource_cmp,
|
|
||||||
.nelem_hint = 256,
|
|
||||||
.min_size = 1024,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Only called for SRC manip */
|
/* Only called for SRC manip */
|
||||||
static int
|
static int
|
||||||
find_appropriate_src(struct net *net,
|
find_appropriate_src(struct net *net,
|
||||||
|
@ -216,26 +194,22 @@ find_appropriate_src(struct net *net,
|
||||||
struct nf_conntrack_tuple *result,
|
struct nf_conntrack_tuple *result,
|
||||||
const struct nf_nat_range *range)
|
const struct nf_nat_range *range)
|
||||||
{
|
{
|
||||||
|
unsigned int h = hash_by_src(net, tuple);
|
||||||
const struct nf_conn *ct;
|
const struct nf_conn *ct;
|
||||||
struct nf_nat_conn_key key = {
|
|
||||||
.net = net,
|
|
||||||
.tuple = tuple,
|
|
||||||
.zone = zone
|
|
||||||
};
|
|
||||||
struct rhlist_head *hl, *h;
|
|
||||||
|
|
||||||
hl = rhltable_lookup(&nf_nat_bysource_table, &key,
|
hlist_for_each_entry_rcu(ct, &nf_nat_bysource[h], nat_bysource) {
|
||||||
nf_nat_bysource_params);
|
if (same_src(ct, tuple) &&
|
||||||
|
net_eq(net, nf_ct_net(ct)) &&
|
||||||
|
nf_ct_zone_equal(ct, zone, IP_CT_DIR_ORIGINAL)) {
|
||||||
|
/* Copy source part from reply tuple. */
|
||||||
|
nf_ct_invert_tuplepr(result,
|
||||||
|
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
||||||
|
result->dst = tuple->dst;
|
||||||
|
|
||||||
rhl_for_each_entry_rcu(ct, h, hl, nat_bysource) {
|
if (in_range(l3proto, l4proto, result, range))
|
||||||
nf_ct_invert_tuplepr(result,
|
return 1;
|
||||||
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
}
|
||||||
result->dst = tuple->dst;
|
|
||||||
|
|
||||||
if (in_range(l3proto, l4proto, result, range))
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +382,7 @@ nf_nat_setup_info(struct nf_conn *ct,
|
||||||
const struct nf_nat_range *range,
|
const struct nf_nat_range *range,
|
||||||
enum nf_nat_manip_type maniptype)
|
enum nf_nat_manip_type maniptype)
|
||||||
{
|
{
|
||||||
|
struct net *net = nf_ct_net(ct);
|
||||||
struct nf_conntrack_tuple curr_tuple, new_tuple;
|
struct nf_conntrack_tuple curr_tuple, new_tuple;
|
||||||
|
|
||||||
/* Can't setup nat info for confirmed ct. */
|
/* Can't setup nat info for confirmed ct. */
|
||||||
|
@ -416,7 +391,9 @@ nf_nat_setup_info(struct nf_conn *ct,
|
||||||
|
|
||||||
WARN_ON(maniptype != NF_NAT_MANIP_SRC &&
|
WARN_ON(maniptype != NF_NAT_MANIP_SRC &&
|
||||||
maniptype != NF_NAT_MANIP_DST);
|
maniptype != NF_NAT_MANIP_DST);
|
||||||
BUG_ON(nf_nat_initialized(ct, maniptype));
|
|
||||||
|
if (WARN_ON(nf_nat_initialized(ct, maniptype)))
|
||||||
|
return NF_DROP;
|
||||||
|
|
||||||
/* What we've got will look like inverse of reply. Normally
|
/* What we've got will look like inverse of reply. Normally
|
||||||
* this is what is in the conntrack, except for prior
|
* this is what is in the conntrack, except for prior
|
||||||
|
@ -447,19 +424,16 @@ nf_nat_setup_info(struct nf_conn *ct,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maniptype == NF_NAT_MANIP_SRC) {
|
if (maniptype == NF_NAT_MANIP_SRC) {
|
||||||
struct nf_nat_conn_key key = {
|
unsigned int srchash;
|
||||||
.net = nf_ct_net(ct),
|
spinlock_t *lock;
|
||||||
.tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
|
|
||||||
.zone = nf_ct_zone(ct),
|
|
||||||
};
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = rhltable_insert_key(&nf_nat_bysource_table,
|
srchash = hash_by_src(net,
|
||||||
&key,
|
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
|
||||||
&ct->nat_bysource,
|
lock = &nf_nat_locks[srchash % ARRAY_SIZE(nf_nat_locks)];
|
||||||
nf_nat_bysource_params);
|
spin_lock_bh(lock);
|
||||||
if (err)
|
hlist_add_head_rcu(&ct->nat_bysource,
|
||||||
return NF_DROP;
|
&nf_nat_bysource[srchash]);
|
||||||
|
spin_unlock_bh(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It's done. */
|
/* It's done. */
|
||||||
|
@ -553,6 +527,16 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data)
|
||||||
return i->status & IPS_NAT_MASK ? 1 : 0;
|
return i->status & IPS_NAT_MASK ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __nf_nat_cleanup_conntrack(struct nf_conn *ct)
|
||||||
|
{
|
||||||
|
unsigned int h;
|
||||||
|
|
||||||
|
h = hash_by_src(nf_ct_net(ct), &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
|
||||||
|
spin_lock_bh(&nf_nat_locks[h % ARRAY_SIZE(nf_nat_locks)]);
|
||||||
|
hlist_del_rcu(&ct->nat_bysource);
|
||||||
|
spin_unlock_bh(&nf_nat_locks[h % ARRAY_SIZE(nf_nat_locks)]);
|
||||||
|
}
|
||||||
|
|
||||||
static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
|
static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
|
||||||
{
|
{
|
||||||
if (nf_nat_proto_remove(ct, data))
|
if (nf_nat_proto_remove(ct, data))
|
||||||
|
@ -568,8 +552,7 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
|
||||||
* will delete entry from already-freed table.
|
* will delete entry from already-freed table.
|
||||||
*/
|
*/
|
||||||
clear_bit(IPS_SRC_NAT_DONE_BIT, &ct->status);
|
clear_bit(IPS_SRC_NAT_DONE_BIT, &ct->status);
|
||||||
rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource,
|
__nf_nat_cleanup_conntrack(ct);
|
||||||
nf_nat_bysource_params);
|
|
||||||
|
|
||||||
/* don't delete conntrack. Although that would make things a lot
|
/* don't delete conntrack. Although that would make things a lot
|
||||||
* simpler, we'd end up flushing all conntracks on nat rmmod.
|
* simpler, we'd end up flushing all conntracks on nat rmmod.
|
||||||
|
@ -698,8 +681,7 @@ EXPORT_SYMBOL_GPL(nf_nat_l3proto_unregister);
|
||||||
static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
|
static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
|
||||||
{
|
{
|
||||||
if (ct->status & IPS_SRC_NAT_DONE)
|
if (ct->status & IPS_SRC_NAT_DONE)
|
||||||
rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource,
|
__nf_nat_cleanup_conntrack(ct);
|
||||||
nf_nat_bysource_params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nf_ct_ext_type nat_extend __read_mostly = {
|
static struct nf_ct_ext_type nat_extend __read_mostly = {
|
||||||
|
@ -821,19 +803,27 @@ static struct nf_ct_helper_expectfn follow_master_nat = {
|
||||||
|
|
||||||
static int __init nf_nat_init(void)
|
static int __init nf_nat_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret, i;
|
||||||
|
|
||||||
ret = rhltable_init(&nf_nat_bysource_table, &nf_nat_bysource_params);
|
/* Leave them the same for the moment. */
|
||||||
if (ret)
|
nf_nat_htable_size = nf_conntrack_htable_size;
|
||||||
return ret;
|
if (nf_nat_htable_size < ARRAY_SIZE(nf_nat_locks))
|
||||||
|
nf_nat_htable_size = ARRAY_SIZE(nf_nat_locks);
|
||||||
|
|
||||||
|
nf_nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, 0);
|
||||||
|
if (!nf_nat_bysource)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = nf_ct_extend_register(&nat_extend);
|
ret = nf_ct_extend_register(&nat_extend);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
rhltable_destroy(&nf_nat_bysource_table);
|
nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size);
|
||||||
printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
|
printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(nf_nat_locks); i++)
|
||||||
|
spin_lock_init(&nf_nat_locks[i]);
|
||||||
|
|
||||||
nf_ct_helper_expectfn_register(&follow_master_nat);
|
nf_ct_helper_expectfn_register(&follow_master_nat);
|
||||||
|
|
||||||
BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
|
BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
|
||||||
|
@ -863,8 +853,8 @@ static void __exit nf_nat_cleanup(void)
|
||||||
|
|
||||||
for (i = 0; i < NFPROTO_NUMPROTO; i++)
|
for (i = 0; i < NFPROTO_NUMPROTO; i++)
|
||||||
kfree(nf_nat_l4protos[i]);
|
kfree(nf_nat_l4protos[i]);
|
||||||
|
synchronize_net();
|
||||||
rhltable_destroy(&nf_nat_bysource_table);
|
nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||||
#include <linux/netfilter/xt_hashlimit.h>
|
#include <linux/netfilter/xt_hashlimit.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||||
|
@ -279,7 +280,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,
|
||||||
size = cfg->size;
|
size = cfg->size;
|
||||||
} else {
|
} else {
|
||||||
size = (totalram_pages << PAGE_SHIFT) / 16384 /
|
size = (totalram_pages << PAGE_SHIFT) / 16384 /
|
||||||
sizeof(struct list_head);
|
sizeof(struct hlist_head);
|
||||||
if (totalram_pages > 1024 * 1024 * 1024 / PAGE_SIZE)
|
if (totalram_pages > 1024 * 1024 * 1024 / PAGE_SIZE)
|
||||||
size = 8192;
|
size = 8192;
|
||||||
if (size < 16)
|
if (size < 16)
|
||||||
|
@ -287,7 +288,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,
|
||||||
}
|
}
|
||||||
/* FIXME: don't use vmalloc() here or anywhere else -HW */
|
/* FIXME: don't use vmalloc() here or anywhere else -HW */
|
||||||
hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
|
hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
|
||||||
sizeof(struct list_head) * size);
|
sizeof(struct hlist_head) * size);
|
||||||
if (hinfo == NULL)
|
if (hinfo == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
*out_hinfo = hinfo;
|
*out_hinfo = hinfo;
|
||||||
|
@ -527,12 +528,12 @@ static u64 user2rate(u64 user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 user2rate_bytes(u64 user)
|
static u64 user2rate_bytes(u32 user)
|
||||||
{
|
{
|
||||||
u64 r;
|
u64 r;
|
||||||
|
|
||||||
r = user ? 0xFFFFFFFFULL / user : 0xFFFFFFFFULL;
|
r = user ? U32_MAX / user : U32_MAX;
|
||||||
r = (r - 1) << 4;
|
r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,7 +589,8 @@ static void rateinfo_init(struct dsthash_ent *dh,
|
||||||
dh->rateinfo.prev_window = 0;
|
dh->rateinfo.prev_window = 0;
|
||||||
dh->rateinfo.current_rate = 0;
|
dh->rateinfo.current_rate = 0;
|
||||||
if (hinfo->cfg.mode & XT_HASHLIMIT_BYTES) {
|
if (hinfo->cfg.mode & XT_HASHLIMIT_BYTES) {
|
||||||
dh->rateinfo.rate = user2rate_bytes(hinfo->cfg.avg);
|
dh->rateinfo.rate =
|
||||||
|
user2rate_bytes((u32)hinfo->cfg.avg);
|
||||||
if (hinfo->cfg.burst)
|
if (hinfo->cfg.burst)
|
||||||
dh->rateinfo.burst =
|
dh->rateinfo.burst =
|
||||||
hinfo->cfg.burst * dh->rateinfo.rate;
|
hinfo->cfg.burst * dh->rateinfo.rate;
|
||||||
|
@ -870,7 +872,7 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
|
||||||
|
|
||||||
/* Check for overflow. */
|
/* Check for overflow. */
|
||||||
if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
|
if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
|
||||||
if (cfg->avg == 0) {
|
if (cfg->avg == 0 || cfg->avg > U32_MAX) {
|
||||||
pr_info("hashlimit invalid rate\n");
|
pr_info("hashlimit invalid rate\n");
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -691,6 +691,9 @@ static void deferred_put_nlk_sk(struct rcu_head *head)
|
||||||
struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
|
struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
|
||||||
struct sock *sk = &nlk->sk;
|
struct sock *sk = &nlk->sk;
|
||||||
|
|
||||||
|
kfree(nlk->groups);
|
||||||
|
nlk->groups = NULL;
|
||||||
|
|
||||||
if (!refcount_dec_and_test(&sk->sk_refcnt))
|
if (!refcount_dec_and_test(&sk->sk_refcnt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -769,9 +772,6 @@ static int netlink_release(struct socket *sock)
|
||||||
netlink_table_ungrab();
|
netlink_table_ungrab();
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(nlk->groups);
|
|
||||||
nlk->groups = NULL;
|
|
||||||
|
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
|
sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
|
@ -955,7 +955,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
struct netlink_sock *nlk = nlk_sk(sk);
|
struct netlink_sock *nlk = nlk_sk(sk);
|
||||||
struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
|
struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
|
||||||
int err;
|
int err = 0;
|
||||||
long unsigned int groups = nladdr->nl_groups;
|
long unsigned int groups = nladdr->nl_groups;
|
||||||
bool bound;
|
bool bound;
|
||||||
|
|
||||||
|
@ -983,6 +983,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netlink_lock_table();
|
||||||
if (nlk->netlink_bind && groups) {
|
if (nlk->netlink_bind && groups) {
|
||||||
int group;
|
int group;
|
||||||
|
|
||||||
|
@ -993,7 +994,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
||||||
if (!err)
|
if (!err)
|
||||||
continue;
|
continue;
|
||||||
netlink_undo_bind(group, groups, sk);
|
netlink_undo_bind(group, groups, sk);
|
||||||
return err;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1006,12 +1007,13 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
||||||
netlink_autobind(sock);
|
netlink_autobind(sock);
|
||||||
if (err) {
|
if (err) {
|
||||||
netlink_undo_bind(nlk->ngroups, groups, sk);
|
netlink_undo_bind(nlk->ngroups, groups, sk);
|
||||||
return err;
|
goto unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
|
if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
|
||||||
return 0;
|
goto unlock;
|
||||||
|
netlink_unlock_table();
|
||||||
|
|
||||||
netlink_table_grab();
|
netlink_table_grab();
|
||||||
netlink_update_subscriptions(sk, nlk->subscriptions +
|
netlink_update_subscriptions(sk, nlk->subscriptions +
|
||||||
|
@ -1022,6 +1024,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
||||||
netlink_table_ungrab();
|
netlink_table_ungrab();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
netlink_unlock_table();
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int netlink_connect(struct socket *sock, struct sockaddr *addr,
|
static int netlink_connect(struct socket *sock, struct sockaddr *addr,
|
||||||
|
@ -1079,7 +1085,9 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr,
|
||||||
nladdr->nl_groups = netlink_group_mask(nlk->dst_group);
|
nladdr->nl_groups = netlink_group_mask(nlk->dst_group);
|
||||||
} else {
|
} else {
|
||||||
nladdr->nl_pid = nlk->portid;
|
nladdr->nl_pid = nlk->portid;
|
||||||
|
netlink_lock_table();
|
||||||
nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
|
nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
|
||||||
|
netlink_unlock_table();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -428,14 +428,18 @@ over_batch:
|
||||||
* some work and we will skip our goto
|
* some work and we will skip our goto
|
||||||
*/
|
*/
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
bool raced;
|
||||||
|
|
||||||
smp_mb();
|
smp_mb();
|
||||||
|
raced = send_gen != READ_ONCE(cp->cp_send_gen);
|
||||||
|
|
||||||
if ((test_bit(0, &conn->c_map_queued) ||
|
if ((test_bit(0, &conn->c_map_queued) ||
|
||||||
!list_empty(&cp->cp_send_queue)) &&
|
!list_empty(&cp->cp_send_queue)) && !raced) {
|
||||||
send_gen == READ_ONCE(cp->cp_send_gen)) {
|
|
||||||
rds_stats_inc(s_send_lock_queue_raced);
|
|
||||||
if (batch_count < send_batch_count)
|
if (batch_count < send_batch_count)
|
||||||
goto restart;
|
goto restart;
|
||||||
queue_delayed_work(rds_wq, &cp->cp_send_w, 1);
|
queue_delayed_work(rds_wq, &cp->cp_send_w, 1);
|
||||||
|
} else if (raced) {
|
||||||
|
rds_stats_inc(s_send_lock_queue_raced);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -182,7 +182,7 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
|
||||||
list_add_tail(&chain->list, &block->chain_list);
|
list_add_tail(&chain->list, &block->chain_list);
|
||||||
chain->block = block;
|
chain->block = block;
|
||||||
chain->index = chain_index;
|
chain->index = chain_index;
|
||||||
chain->refcnt = 1;
|
chain->refcnt = 0;
|
||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,15 +217,15 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
|
||||||
struct tcf_chain *chain;
|
struct tcf_chain *chain;
|
||||||
|
|
||||||
list_for_each_entry(chain, &block->chain_list, list) {
|
list_for_each_entry(chain, &block->chain_list, list) {
|
||||||
if (chain->index == chain_index) {
|
if (chain->index == chain_index)
|
||||||
chain->refcnt++;
|
goto incref;
|
||||||
return chain;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (create)
|
chain = create ? tcf_chain_create(block, chain_index) : NULL;
|
||||||
return tcf_chain_create(block, chain_index);
|
|
||||||
else
|
incref:
|
||||||
return NULL;
|
if (chain)
|
||||||
|
chain->refcnt++;
|
||||||
|
return chain;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tcf_chain_get);
|
EXPORT_SYMBOL(tcf_chain_get);
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
|
||||||
|
|
||||||
if (ret & __NET_XMIT_BYPASS)
|
if (ret & __NET_XMIT_BYPASS)
|
||||||
qdisc_qstats_drop(sch);
|
qdisc_qstats_drop(sch);
|
||||||
kfree_skb(skb);
|
__qdisc_drop(skb, to_free);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1215,7 +1215,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
||||||
if (cl == NULL) {
|
if (cl == NULL) {
|
||||||
if (err & __NET_XMIT_BYPASS)
|
if (err & __NET_XMIT_BYPASS)
|
||||||
qdisc_qstats_drop(sch);
|
qdisc_qstats_drop(sch);
|
||||||
kfree_skb(skb);
|
__qdisc_drop(skb, to_free);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid);
|
pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid);
|
||||||
|
|
|
@ -265,7 +265,8 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
|
||||||
sctp_ulpq_clear_pd(ulpq);
|
sctp_ulpq_clear_pd(ulpq);
|
||||||
|
|
||||||
if (queue == &sk->sk_receive_queue && !sp->data_ready_signalled) {
|
if (queue == &sk->sk_receive_queue && !sp->data_ready_signalled) {
|
||||||
sp->data_ready_signalled = 1;
|
if (!sock_owned_by_user(sk))
|
||||||
|
sp->data_ready_signalled = 1;
|
||||||
sk->sk_data_ready(sk);
|
sk->sk_data_ready(sk);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -637,7 +637,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
|
||||||
break;
|
break;
|
||||||
case NETDEV_UNREGISTER:
|
case NETDEV_UNREGISTER:
|
||||||
case NETDEV_CHANGENAME:
|
case NETDEV_CHANGENAME:
|
||||||
bearer_disable(dev_net(dev), b);
|
bearer_disable(net, b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
|
|
|
@ -3791,8 +3791,8 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
|
||||||
static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
|
static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
|
||||||
{
|
{
|
||||||
const struct cfg80211_beacon_data *bcn = ¶ms->beacon;
|
const struct cfg80211_beacon_data *bcn = ¶ms->beacon;
|
||||||
size_t ies_len = bcn->beacon_ies_len;
|
size_t ies_len = bcn->tail_len;
|
||||||
const u8 *ies = bcn->beacon_ies;
|
const u8 *ies = bcn->tail;
|
||||||
const u8 *rates;
|
const u8 *rates;
|
||||||
const u8 *cap;
|
const u8 *cap;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
|
* Copyright 2017 Intel Deutschland GmbH
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -1483,7 +1484,9 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
|
||||||
{
|
{
|
||||||
struct ieee80211_supported_band *sband = wiphy->bands[channel->band];
|
struct ieee80211_supported_band *sband = wiphy->bands[channel->band];
|
||||||
struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
|
struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
|
||||||
|
const struct ieee80211_regdomain *regd;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
u32 flags;
|
||||||
|
|
||||||
if (!is_ht40_allowed(channel)) {
|
if (!is_ht40_allowed(channel)) {
|
||||||
channel->flags |= IEEE80211_CHAN_NO_HT40;
|
channel->flags |= IEEE80211_CHAN_NO_HT40;
|
||||||
|
@ -1503,17 +1506,30 @@ static void reg_process_ht_flags_channel(struct wiphy *wiphy,
|
||||||
channel_after = c;
|
channel_after = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
regd = get_wiphy_regdom(wiphy);
|
||||||
|
if (regd) {
|
||||||
|
const struct ieee80211_reg_rule *reg_rule =
|
||||||
|
freq_reg_info_regd(MHZ_TO_KHZ(channel->center_freq),
|
||||||
|
regd, MHZ_TO_KHZ(20));
|
||||||
|
|
||||||
|
if (!IS_ERR(reg_rule))
|
||||||
|
flags = reg_rule->flags;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Please note that this assumes target bandwidth is 20 MHz,
|
* Please note that this assumes target bandwidth is 20 MHz,
|
||||||
* if that ever changes we also need to change the below logic
|
* if that ever changes we also need to change the below logic
|
||||||
* to include that as well.
|
* to include that as well.
|
||||||
*/
|
*/
|
||||||
if (!is_ht40_allowed(channel_before))
|
if (!is_ht40_allowed(channel_before) ||
|
||||||
|
flags & NL80211_RRF_NO_HT40MINUS)
|
||||||
channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
|
channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
|
||||||
else
|
else
|
||||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||||
|
|
||||||
if (!is_ht40_allowed(channel_after))
|
if (!is_ht40_allowed(channel_after) ||
|
||||||
|
flags & NL80211_RRF_NO_HT40PLUS)
|
||||||
channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
|
channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
|
||||||
else
|
else
|
||||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||||
|
|
|
@ -558,7 +558,7 @@ static void test_sockmap(int tasks, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test attaching bad fds */
|
/* Test attaching/detaching bad fds */
|
||||||
err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0);
|
err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
printf("Failed invalid parser prog attach\n");
|
printf("Failed invalid parser prog attach\n");
|
||||||
|
@ -571,6 +571,30 @@ static void test_sockmap(int tasks, void *data)
|
||||||
goto out_sockmap;
|
goto out_sockmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0);
|
||||||
|
if (!err) {
|
||||||
|
printf("Failed unknown prog attach\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed empty parser prog detach\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed empty verdict prog detach\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE);
|
||||||
|
if (!err) {
|
||||||
|
printf("Detach invalid prog successful\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
/* Load SK_SKB program and Attach */
|
/* Load SK_SKB program and Attach */
|
||||||
err = bpf_prog_load(SOCKMAP_PARSE_PROG,
|
err = bpf_prog_load(SOCKMAP_PARSE_PROG,
|
||||||
BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog);
|
BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog);
|
||||||
|
@ -643,6 +667,13 @@ static void test_sockmap(int tasks, void *data)
|
||||||
goto out_sockmap;
|
goto out_sockmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_attach(verdict_prog, map_fd_rx,
|
||||||
|
__MAX_BPF_ATTACH_TYPE, 0);
|
||||||
|
if (!err) {
|
||||||
|
printf("Attached unknown bpf prog\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
/* Test map update elem afterwards fd lives in fd and map_fd */
|
/* Test map update elem afterwards fd lives in fd and map_fd */
|
||||||
for (i = 0; i < 6; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY);
|
err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY);
|
||||||
|
@ -809,6 +840,24 @@ static void test_sockmap(int tasks, void *data)
|
||||||
assert(status == 0);
|
assert(status == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE);
|
||||||
|
if (!err) {
|
||||||
|
printf("Detached an invalid prog type.\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed parser prog detach\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed parser prog detach\n");
|
||||||
|
goto out_sockmap;
|
||||||
|
}
|
||||||
|
|
||||||
/* Test map close sockets */
|
/* Test map close sockets */
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
close(sfd[i]);
|
close(sfd[i]);
|
||||||
|
|
Loading…
Reference in New Issue