* Re: AP firmware for TI wl1251 wifi chip (wl1251-fw-ap.bin)
From: Pali Rohár @ 2016-03-21 11:01 UTC (permalink / raw)
To: Kalle Valo
Cc: kev-l0cyMroinI0, Andrew F. Davis, Guy Mishol, Yaniv Machani,
Arik Nemtsov, Felipe Balbi, Luciano Coelho, David Woodhouse,
Pavel Machek, Aaro Koskinen, Ben Hutchings, David Gnedt,
Ivaylo Dimitrov, Sebastian Reichel, Tony Lindgren, Nishanth Menon,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <878u1cglu3.fsf-HodKDYzPHsUD5k0oWYwrnHL1okKdlPRT@public.gmane.org>
On Monday 21 March 2016 12:35:32 Kalle Valo wrote:
> Pali Rohár <pali.rohar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>
> > In linux-firmware repository [1] is missing AP firmware for TI wl1251
> > chip. There is only STA firmware wl1251-fw.bin which supports managed
> > and ad-hoc modes.
> >
> > For other TI wilink chips there are <CHIP>-ap.bin firmware files
> > (wl1271-fw-ap.bin and wl128x-fw-ap.bin) which support AP mode. But for
> > wl1251 firmware file with guessed name "wl1251-fw-ap.bin" is missing.
> >
> > Do you have any idea what happened with AP firmware for ti wilink4
> > wl1251 wifi chip? Or where can be found? Guys from TI, can you help?
>
> It's a long time ago but IIRC wl1251 has not ever supported AP mode and
> wl1271 was the first one to support it. But I might be wrong of course.
Support for AP mode in current kernel driver wl1251.ko is missing, but I
could try to write it if there will be firmware for it.
According to some TI whitepaper about TI wilink4 devices (wl1251 and
wl1253) those devices have support for some Soft-AP mode.
--
Pali Rohár
pali.rohar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH net 10/10] net: hns: bug fix about the overflow of mss
From: Yisen Zhuang @ 2016-03-21 11:06 UTC (permalink / raw)
To: davem
Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
linux-kernel, linuxarm
In-Reply-To: <1458558401-190165-1-git-send-email-Yisen.Zhuang@huawei.com>
From: Daode Huang <huangdaode@hisilicon.com>
When set MTU to the minimum value 68, there are increasing number
of error packets occur, which is caused by the overflowed value of
mss. This patch fix the bug.
Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
drivers/net/ethernet/hisilicon/hns/hns_enet.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index 8aa325e..a192691 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -48,7 +48,6 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct sk_buff *skb;
- int skb_tmp_len;
__be16 protocol;
u8 bn_pid = 0;
u8 rrcfv = 0;
@@ -94,13 +93,13 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
/* check for tcp/udp header */
- if (iphdr->protocol == IPPROTO_TCP) {
+ if (iphdr->protocol == IPPROTO_TCP &&
+ skb_is_gso(skb)) {
hnae_set_bit(tvsvsn,
HNSV2_TXD_TSE_B, 1);
- skb_tmp_len = SKB_TMP_LEN(skb);
l4_len = tcp_hdrlen(skb);
- mss = mtu - skb_tmp_len - ETH_FCS_LEN;
- paylen = skb->len - skb_tmp_len;
+ mss = skb_shinfo(skb)->gso_size;
+ paylen = skb->len - SKB_TMP_LEN(skb);
}
} else if (skb->protocol == htons(ETH_P_IPV6)) {
hnae_set_bit(tvsvsn, HNSV2_TXD_IPV6_B, 1);
@@ -108,13 +107,13 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
/* check for tcp/udp header */
- if (ipv6hdr->nexthdr == IPPROTO_TCP) {
+ if (ipv6hdr->nexthdr == IPPROTO_TCP &&
+ skb_is_gso(skb) && skb_is_gso_v6(skb)) {
hnae_set_bit(tvsvsn,
HNSV2_TXD_TSE_B, 1);
- skb_tmp_len = SKB_TMP_LEN(skb);
l4_len = tcp_hdrlen(skb);
- mss = mtu - skb_tmp_len - ETH_FCS_LEN;
- paylen = skb->len - skb_tmp_len;
+ mss = skb_shinfo(skb)->gso_size;
+ paylen = skb->len - SKB_TMP_LEN(skb);
}
}
desc->tx.ip_offset = ip_offset;
--
1.9.1
^ permalink raw reply related
* [PATCH net 07/10] net: hns: fixes a bug of RSS
From: Yisen Zhuang @ 2016-03-21 11:06 UTC (permalink / raw)
To: davem
Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
linux-kernel, linuxarm
In-Reply-To: <1458558401-190165-1-git-send-email-Yisen.Zhuang@huawei.com>
From: Kejian Yan <yankejian@huawei.com>
If trying to get receive flow hash indirection table by ethtool, it needs
to call .get_rxnfc to get ring number first. So this patch implements the
.get_rxnfc of ethtool. And the data type of rss_indir_table is u32, it has
to be multiply by the width of data type when using memcpy.
Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 6 ++++--
drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 18 ++++++++++++++++++
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index 1d0da87..d2cca60 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -791,7 +791,8 @@ static int hns_ae_get_rss(struct hnae_handle *handle, u32 *indir, u8 *key,
memcpy(key, ppe_cb->rss_key, HNS_PPEV2_RSS_KEY_SIZE);
/* update the current hash->queue mappings from the shadow RSS table */
- memcpy(indir, ppe_cb->rss_indir_table, HNS_PPEV2_RSS_IND_TBL_SIZE);
+ memcpy(indir, ppe_cb->rss_indir_table,
+ HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir));
return 0;
}
@@ -806,7 +807,8 @@ static int hns_ae_set_rss(struct hnae_handle *handle, const u32 *indir,
hns_ppe_set_rss_key(ppe_cb, (u32 *)key);
/* update the shadow RSS table with user specified qids */
- memcpy(ppe_cb->rss_indir_table, indir, HNS_PPEV2_RSS_IND_TBL_SIZE);
+ memcpy(ppe_cb->rss_indir_table, indir,
+ HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir));
/* now update the hardware */
hns_ppe_set_indir_table(ppe_cb, ppe_cb->rss_indir_table);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index f3a5e05..02e9fa2 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -1245,6 +1245,23 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
return ops->set_rss(priv->ae_handle, indir, key, hfunc);
}
+static int hns_get_rxnfc(struct net_device *netdev,
+ struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct hns_nic_priv *priv = netdev_priv(netdev);
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXRINGS:
+ cmd->data = priv->ae_handle->q_num;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static struct ethtool_ops hns_ethtool_ops = {
.get_drvinfo = hns_nic_get_drvinfo,
.get_link = hns_nic_get_link,
@@ -1268,6 +1285,7 @@ static struct ethtool_ops hns_ethtool_ops = {
.get_rxfh_indir_size = hns_get_rss_indir_size,
.get_rxfh = hns_get_rss,
.set_rxfh = hns_set_rss,
+ .get_rxnfc = hns_get_rxnfc,
};
void hns_ethtool_set_ops(struct net_device *ndev)
--
1.9.1
^ permalink raw reply related
* [PATCH net 03/10] net: hns: add uc match for debug ports
From: Yisen Zhuang @ 2016-03-21 11:06 UTC (permalink / raw)
To: davem
Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
linux-kernel, linuxarm
In-Reply-To: <1458558401-190165-1-git-send-email-Yisen.Zhuang@huawei.com>
From: Kejian Yan <yankejian@huawei.com>
Debug ports receives lots of packets with dest mac addr does not match
local mac addr, because the filter is close, and it does not drop the
useless packets. This patch adds ON/OFF switch of filtering the packets
whose dest mac addr do not match the local addr in mac table. And the
switch is ON in initialization.
Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 3 +++
drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 30 +++++++++++++++++++++-
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 11 ++++++++
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h | 2 ++
drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h | 2 ++
5 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index 90352d6..5e0cedf 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -420,7 +420,10 @@ static int hns_ae_set_autoneg(struct hnae_handle *handle, u8 enable)
static void hns_ae_set_promisc_mode(struct hnae_handle *handle, u32 en)
{
+ struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle);
+
hns_dsaf_set_promisc_mode(hns_ae_get_dsaf_dev(handle->dev), en);
+ (void)hns_mac_set_promisc(mac_cb, (u8)!!en);
}
static int hns_ae_get_autoneg(struct hnae_handle *handle)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index b8517b0..5881405 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -290,6 +290,26 @@ static int hns_gmac_adjust_link(void *mac_drv, enum mac_speed speed,
return 0;
}
+static void hns_gmac_set_uc_match(void *mac_drv, u16 en)
+{
+ struct mac_driver *drv = (struct mac_driver *)mac_drv;
+
+ dsaf_set_dev_bit(drv, GMAC_REC_FILT_CONTROL_REG,
+ GMAC_UC_MATCH_EN_B, !en);
+ dsaf_set_dev_bit(drv, GMAC_STATION_ADDR_HIGH_2_REG,
+ GMAC_ADDR_EN_B, !en);
+}
+
+static int hns_gmac_set_promisc(void *mac_drv, u8 en)
+{
+ struct mac_driver *drv = (struct mac_driver *)mac_drv;
+
+ if (drv->mac_cb->mac_type == HNAE_PORT_DEBUG)
+ hns_gmac_set_uc_match(mac_drv, en);
+
+ return 0;
+}
+
static void hns_gmac_init(void *mac_drv)
{
u32 port;
@@ -305,6 +325,8 @@ static void hns_gmac_init(void *mac_drv)
mdelay(10);
hns_gmac_disable(mac_drv, MAC_COMM_MODE_RX_AND_TX);
hns_gmac_tx_loop_pkt_dis(mac_drv);
+ if (drv->mac_cb->mac_type == HNAE_PORT_DEBUG)
+ hns_gmac_set_uc_match(mac_drv, 0);
}
void hns_gmac_update_stats(void *mac_drv)
@@ -407,8 +429,13 @@ static void hns_gmac_set_mac_addr(void *mac_drv, char *mac_addr)
u32 low_val = mac_addr[5] | (mac_addr[4] << 8)
| (mac_addr[3] << 16) | (mac_addr[2] << 24);
+
+ u32 val = dsaf_read_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG);
+ u32 sta_addr_en = dsaf_get_bit(val, GMAC_ADDR_EN_B);
+
dsaf_write_dev(drv, GMAC_STATION_ADDR_LOW_2_REG, low_val);
- dsaf_write_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG, high_val);
+ dsaf_write_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG,
+ high_val | (sta_addr_en << GMAC_ADDR_EN_B));
}
}
@@ -699,6 +726,7 @@ void *hns_gmac_config(struct hns_mac_cb *mac_cb, struct mac_params *mac_param)
mac_drv->get_sset_count = hns_gmac_get_sset_count;
mac_drv->get_strings = hns_gmac_get_strings;
mac_drv->update_stats = hns_gmac_update_stats;
+ mac_drv->set_promiscuous = hns_gmac_set_promisc;
return (void *)mac_drv;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 5ef0e96..5f35418 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -861,6 +861,17 @@ int hns_mac_get_sset_count(struct hns_mac_cb *mac_cb, int stringset)
return mac_ctrl_drv->get_sset_count(stringset);
}
+int hns_mac_set_promisc(struct hns_mac_cb *mac_cb, u8 en)
+{
+ struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
+ int ret = 0;
+
+ if (mac_ctrl_drv->set_promiscuous)
+ ret = mac_ctrl_drv->set_promiscuous(mac_ctrl_drv, en);
+
+ return ret;
+}
+
int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb)
{
struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
index 0b05219..68b01fe 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
@@ -453,4 +453,6 @@ int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb);
void hns_set_led_opt(struct hns_mac_cb *mac_cb);
int hns_cpld_led_set_id(struct hns_mac_cb *mac_cb,
enum hnae_led_state status);
+int hns_mac_set_promisc(struct hns_mac_cb *mac_cb, u8 en);
+
#endif /* _HNS_DSAF_MAC_H */
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
index 60d695d..bf62687 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -922,6 +922,8 @@
#define GMAC_LP_REG_CF2MI_LP_EN_B 2
#define GMAC_MODE_CHANGE_EB_B 0
+#define GMAC_UC_MATCH_EN_B 0
+#define GMAC_ADDR_EN_B 16
#define GMAC_RECV_CTRL_STRIP_PAD_EN_B 3
#define GMAC_RECV_CTRL_RUNT_PKT_EN_B 4
--
1.9.1
^ permalink raw reply related
* [PATCH net 05/10] net: hns: set xge statistic reg as read only
From: Yisen Zhuang @ 2016-03-21 11:06 UTC (permalink / raw)
To: davem
Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
linux-kernel, linuxarm
In-Reply-To: <1458558401-190165-1-git-send-email-Yisen.Zhuang@huawei.com>
From: Qianqian Xie <xieqianqian@huawei.com>
As the user manual of HNS V2 describs, XGE_DFX_CTRL_CFG.xge_dfx_ctrl_cfg
should be configed as zero if we want xge statistic reg to be read only.
But HNS V1 gets the other meanings. It needs to be identified the process
and then config it rightly.
Signed-off-by: Qianqian Xie <xieqianqian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index 38fc5be..5c1ac9b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -748,8 +748,9 @@ static void hns_dsaf_tbl_stat_en(struct dsaf_device *dsaf_dev)
*/
static void hns_dsaf_rocee_bp_en(struct dsaf_device *dsaf_dev)
{
- dsaf_set_dev_bit(dsaf_dev, DSAF_XGE_CTRL_SIG_CFG_0_REG,
- DSAF_FC_XGE_TX_PAUSE_S, 1);
+ if (AE_IS_VER1(dsaf_dev->dsaf_ver))
+ dsaf_set_dev_bit(dsaf_dev, DSAF_XGE_CTRL_SIG_CFG_0_REG,
+ DSAF_FC_XGE_TX_PAUSE_S, 1);
}
/* set msk for dsaf exception irq*/
--
1.9.1
^ permalink raw reply related
* [PATCH net 09/10] net: hns: adds limitation for debug port mtu
From: Yisen Zhuang @ 2016-03-21 11:06 UTC (permalink / raw)
To: davem
Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
linux-kernel, linuxarm
In-Reply-To: <1458558401-190165-1-git-send-email-Yisen.Zhuang@huawei.com>
From: Kejian Yan <yankejian@huawei.com>
If mtu for debug port is set more than 1500, it may cause that packets
are dropped by ppe. So maximum value for debug port should be 1500.
Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 3 +++
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 3f96e3d..cfb8fc5 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -470,6 +470,9 @@ int hns_mac_set_mtu(struct hns_mac_cb *mac_cb, u32 new_mtu)
u32 max_frm = AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver) ?
MAC_MAX_MTU : MAC_MAX_MTU_V2;
+ if (mac_cb->mac_type == HNAE_PORT_DEBUG)
+ max_frm = MAC_MAX_MTU_DBG;
+
if ((new_mtu < MAC_MIN_MTU) || (new_frm > max_frm) ||
(new_frm > HNS_RCB_RING_MAX_BD_PER_PKT * buf_size))
return -EINVAL;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
index a69c8af..a68efd6 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
@@ -28,6 +28,7 @@ struct dsaf_device;
#define MAC_MAX_MTU 9600
#define MAC_MAX_MTU_V2 9728
#define MAC_MIN_MTU 68
+#define MAC_MAX_MTU_DBG MAC_DEFAULT_MTU
#define MAC_DEFAULT_PAUSE_TIME 0xff
--
1.9.1
^ permalink raw reply related
* [PATCH net 00/10] net: hns: bugs fixed for hns
From: Yisen Zhuang @ 2016-03-21 11:06 UTC (permalink / raw)
To: davem
Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
linux-kernel, linuxarm
This series includes some bug fixes and updates for hns driver.
>from Daode, one fix about mss.
>from Kejian, one fix about ping6 issue, one fix about mac address setting,
two fix for RSS setting, two fix about mtu setting.
>from qianqian, fixed HNS v2 xge statistic reg issue.
>from Sheng, one fix about manage packets sending, one fix about GMACs mac
setting.
For more details, please see individual patches.
Thanks a lot!
Daode Huang (1):
net: hns: bug fix about the overflow of mss
Kejian Yan (6):
net: hns: bug fix about ping6
net: hns: add uc match for debug ports
net: hns: fix return value of the function about rss
net: hns: fixes a bug of RSS
net: hns: fix the bug about mtu setting
net: hns: adds limitation for debug port mtu
Qianqian Xie (1):
net: hns: set xge statistic reg as read only
Sheng Li (2):
net: hns: fixed portid bug in sending manage pkt
net: hns: fixed the bug about GMACs mac setting
drivers/net/ethernet/hisilicon/hns/hnae.h | 3 ++
drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 12 +++++--
drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 40 +++++++++++++++++----
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 18 +++++++++-
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h | 4 +++
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c | 5 +--
drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c | 5 ++-
drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h | 2 ++
drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h | 2 ++
drivers/net/ethernet/hisilicon/hns/hns_enet.c | 32 +++++++++++------
drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 42 ++++++++++++----------
11 files changed, 123 insertions(+), 42 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH net 02/10] net: hns: fixed portid bug in sending manage pkt
From: Yisen Zhuang @ 2016-03-21 11:06 UTC (permalink / raw)
To: davem
Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
linux-kernel, linuxarm
In-Reply-To: <1458558401-190165-1-git-send-email-Yisen.Zhuang@huawei.com>
From: Sheng Li <lisheng011@huawei.com>
In chip V2, the default value of port id in tx BD is Zero. If it is not
configurated to the other value, all management packets will be sent out
from port0. So port_id in the tx BD needs to be updated when sending a
management packet.
In V2 chip, when sending mamagement packets, the driver should
config the port id to BD descs.
Signed-off-by: Sheng Li <lisheng011@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
drivers/net/ethernet/hisilicon/hns/hnae.h | 3 +++
drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 1 +
drivers/net/ethernet/hisilicon/hns/hns_enet.c | 6 +++++-
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 1cbcb9f..37d0cce 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -147,6 +147,8 @@ enum hnae_led_state {
#define HNSV2_TXD_BUFNUM_S 0
#define HNSV2_TXD_BUFNUM_M (0x7 << HNSV2_TXD_BUFNUM_S)
+#define HNSV2_TXD_PORTID_S 4
+#define HNSV2_TXD_PORTID_M (0X7 << HNSV2_TXD_PORTID_S)
#define HNSV2_TXD_RI_B 1
#define HNSV2_TXD_L4CS_B 2
#define HNSV2_TXD_L3CS_B 3
@@ -516,6 +518,7 @@ struct hnae_handle {
int q_num;
int vf_id;
u32 eport_id;
+ u32 dport_id; /* v2 tx bd should fill the dport_id */
enum hnae_port_type port_type;
struct list_head node; /* list to hnae_ae_dev->handle_list */
struct hnae_buf_ops *bops; /* operation for the buffer */
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index d4f92ed..90352d6 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -175,6 +175,7 @@ struct hnae_handle *hns_ae_get_handle(struct hnae_ae_dev *dev,
ae_handle->phy_node = vf_cb->mac_cb->phy_node;
ae_handle->if_support = vf_cb->mac_cb->if_support;
ae_handle->port_type = vf_cb->mac_cb->mac_type;
+ ae_handle->dport_id = port_idx;
return ae_handle;
vf_id_err:
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index 9ad5da4..8aa325e 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -66,10 +66,14 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
desc->addr = cpu_to_le64(dma);
desc->tx.send_size = cpu_to_le16((u16)size);
- /*config bd buffer end */
+ /* config bd buffer end */
hnae_set_bit(rrcfv, HNSV2_TXD_VLD_B, 1);
hnae_set_field(bn_pid, HNSV2_TXD_BUFNUM_M, 0, buf_num - 1);
+ /* fill port_id in the tx bd for sending management pkts */
+ hnae_set_field(bn_pid, HNSV2_TXD_PORTID_M,
+ HNSV2_TXD_PORTID_S, ring->q->handle->dport_id);
+
if (type == DESC_TYPE_SKB) {
skb = (struct sk_buff *)priv;
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v5 2/4] Documentation: Bindings: Add STM32 DWMAC glue
From: Alexandre Torgue @ 2016-03-21 10:45 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Maxime Coquelin, Giuseppe Cavallaro, netdev, devicetree,
Joachim Eastwood, linux-kernel, linux-arm-kernel
In-Reply-To: <CAGb2v65SvVi0cJbaaD9cYrqC3pJ9eumwhTVk11_N7r_nTZhS9g@mail.gmail.com>
Hi,
2016-03-18 17:00 GMT+01:00 Chen-Yu Tsai <wens@csie.org>:
> Hi,
>
> On Fri, Mar 18, 2016 at 11:37 PM, Alexandre TORGUE
> <alexandre.torgue@gmail.com> wrote:
>> Signed-off-by: Alexandre TORGUE <alexandre.torgue@gmail.com>
>>
>> diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
>> new file mode 100644
>> index 0000000..ada2aa4
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
>> @@ -0,0 +1,32 @@
>> +STMicroelectronics STM32 / MCU DWMAC glue layer controller
>> +
>> +This file documents platform glue layer for stmmac.
>> +Please see stmmac.txt for the other unchanged properties.
>> +
>> +The device node has following properties.
>> +
>> +Required properties:
>> +- compatible: Should be "st,stm32-dwmac" to select glue, and
>> + "snps,dwmac-3.50a" to select IP vesrion.
>
> If you need have sort of hardware glue, then it is not compatible.
>
We could have the case where the glue is set by a bootloader.
In this case, we will select IP version in compatible and we will use
generic dwmac glue to probe stmmac driver.
Regards
Alex.
> ChenYu
>
>> +- clocks: Must contain a phandle for each entry in clock-names.
>> +- clock-names: Should be "stmmaceth" for the host clock.
>> + Should be "tx-clk" for the MAC TX clock.
>> + Should be "rx-clk" for the MAC RX clock.
>> +- st,syscon : Should be phandle/offset pair. The phandle to the syscon node which
>> + encompases the glue register, and the offset of the control register.
>> +Example:
>> +
>> + ethernet0: dwmac@40028000 {
>> + compatible = "st,stm32-dwmac", "snps,dwmac-3.50a";
>> + status = "disabled";
>> + reg = <0x40028000 0x8000>;
>> + reg-names = "stmmaceth";
>> + interrupts = <0 61 0>, <0 62 0>;
>> + interrupt-names = "macirq", "eth_wake_irq";
>> + clock-names = "stmmaceth", "tx-clk", "rx-clk";
>> + clocks = <&rcc 0 25>, <&rcc 0 26>, <&rcc 0 27>;
>> + st,syscon = <&syscfg 0x4>;
>> + snps,pbl = <8>;
>> + snps,mixed-burst;
>> + dma-ranges;
>> + };
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: AP firmware for TI wl1251 wifi chip (wl1251-fw-ap.bin)
From: Kalle Valo @ 2016-03-21 10:35 UTC (permalink / raw)
To: Pali Rohár
Cc: Luciano Coelho, Felipe Balbi, kev-l0cyMroinI0, Shahar Levi,
Andrew F. Davis, Guy Mishol, Yaniv Machani, Arik Nemtsov,
Gery Kahn, Felipe Balbi, Luciano Coelho, David Woodhouse,
Pavel Machek, Aaro Koskinen, Ben Hutchings, David Gnedt,
Ivaylo Dimitrov, Sebastian Reichel, Tony Lindgren, Nishanth Menon,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <201603200040.26045@pali>
Pali Rohár <pali.rohar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> In linux-firmware repository [1] is missing AP firmware for TI wl1251
> chip. There is only STA firmware wl1251-fw.bin which supports managed
> and ad-hoc modes.
>
> For other TI wilink chips there are <CHIP>-ap.bin firmware files
> (wl1271-fw-ap.bin and wl128x-fw-ap.bin) which support AP mode. But for
> wl1251 firmware file with guessed name "wl1251-fw-ap.bin" is missing.
>
> Do you have any idea what happened with AP firmware for ti wilink4
> wl1251 wifi chip? Or where can be found? Guys from TI, can you help?
It's a long time ago but IIRC wl1251 has not ever supported AP mode and
wl1271 was the first one to support it. But I might be wrong of course.
--
Kalle Valo
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] mwifiex: advertise low priority scan feature
From: Kalle Valo @ 2016-03-21 10:28 UTC (permalink / raw)
To: Wei-Ning Huang
Cc: Linux Wireless, LKML, akarwar-eYqpPyKDWXRBDgjK7y7TUQ,
djkurtz-F7+t8E8rja9g9hUCZPvPmw, nishants-eYqpPyKDWXRBDgjK7y7TUQ,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1458547622-1632-1-git-send-email-wnhuang-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Wei-Ning Huang <wnhuang-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> writes:
> From: Amitkumar Karwar <akarwar-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
>
> Low priority scan handling code which delays or aborts scan
> operation based on Tx traffic is removed recently. The reason
> is firmware already takes care of it in our new feature scan
> channel gap. Hence we should advertise low priority scan
> support to cfg80211.
>
> This patch fixes a problem in which OBSS scan request from
> wpa_supplicant was being rejected by cfg80211.
>
> Signed-off-by: Wei-Ning Huang <wnhuang-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
The From line states that this is written by Amitkumar but there's no
Signed-off-By line from him. I can't take this without that, please
resend.
(Wei-Ning's s-o-b line is correct, I just need also Amitkumar's line.)
--
Kalle Valo
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [patch] mdio-sun4i: oops in error handling in probe
From: Chen-Yu Tsai @ 2016-03-21 10:11 UTC (permalink / raw)
To: Dan Carpenter
Cc: Florian Fainelli, Maxime Ripard, Chen-Yu Tsai, netdev,
kernel-janitors
In-Reply-To: <20160321090231.GA31670@mwanda>
On Mon, Mar 21, 2016 at 5:02 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> We could end up dereferencing an error pointer when we call
> regulator_disable().
>
> Fixes: 4bdcb1dd9feb ('net: Add MDIO bus driver for the Allwinner EMAC')
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
^ permalink raw reply
* [PATCH net-next 3/3] net: add the AF_HYPERV entries to family name tables
From: Dexuan Cui @ 2016-03-21 9:53 UTC (permalink / raw)
To: gregkh, davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
kys, haiyangz
This is for the hv_sock driver, which introduces AF_HYPERV(42).
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
---
net/core/sock.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/core/sock.c b/net/core/sock.c
index 7e73c26..51ffc54 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -222,7 +222,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
"sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
"sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" ,
"sk_lock-AF_NFC" , "sk_lock-AF_VSOCK" , "sk_lock-AF_KCM" ,
- "sk_lock-AF_MAX"
+ "sk_lock-AF_HYPERV", "sk_lock-AF_MAX"
};
static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" ,
@@ -239,7 +239,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
"slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" ,
"slock-AF_NFC" , "slock-AF_VSOCK" ,"slock-AF_KCM" ,
- "slock-AF_MAX"
+ "slock-AF_HYPERV", "slock-AF_MAX"
};
static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" ,
@@ -256,7 +256,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
"clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" ,
"clock-AF_NFC" , "clock-AF_VSOCK" , "clock-AF_KCM" ,
- "clock-AF_MAX"
+ "clock-AF_HYPERV", "clock-AF_MAX"
};
/*
--
2.1.0
^ permalink raw reply related
* [PATCH net-next 2/3] hv_sock: introduce Hyper-V Sockets
From: Dexuan Cui @ 2016-03-21 9:52 UTC (permalink / raw)
To: gregkh, davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
kys, haiyangz
Hyper-V Sockets (hv_sock) supplies a byte-stream based communication
mechanism between the host and the guest. It's somewhat like TCP over
VMBus, but the transportation layer (VMBus) is much simpler than IP.
With Hyper-V Sockets, applications between the host and the guest can talk
to each other directly by the traditional BSD-style socket APIs.
Hyper-V Sockets is only available on new Windows hosts, like Windows Server
2016. More info is in this article "Make your own integration services":
https://msdn.microsoft.com/en-us/virtualization/hyperv_on_windows/develop/make_mgmt_service
The patch implements the necessary support in the guest side by introducing
a new socket address family AF_HYPERV.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
---
I posted the V6 of the hv_sock patchset in Jan:
[PATCH V6 0/8] introduce Hyper-V VM Socket(hv_sock)
http://lkml.iu.edu/hypermail/linux/kernel/1601.3/01813.html
Now all the supporting patches in the VMBus side have been merged into
the mainline tree and the net-next tree, I think it's time to re-post the
net/ side's change -- I'm not sure if net-next is close now, since I don't
see a "net-next is CLOSED" mail recently?
The patch shouldn't cause any regression because it adds a new driver, not
touching the existing code.
Please comment on the patch.
MAINTAINERS | 2 +
include/linux/hyperv.h | 16 +
include/linux/socket.h | 5 +-
include/net/af_hvsock.h | 51 ++
include/uapi/linux/hyperv.h | 16 +
net/Kconfig | 1 +
net/Makefile | 1 +
net/hv_sock/Kconfig | 10 +
net/hv_sock/Makefile | 3 +
net/hv_sock/af_hvsock.c | 1480 +++++++++++++++++++++++++++++++++++++++++++
10 files changed, 1583 insertions(+), 2 deletions(-)
create mode 100644 include/net/af_hvsock.h
create mode 100644 net/hv_sock/Kconfig
create mode 100644 net/hv_sock/Makefile
create mode 100644 net/hv_sock/af_hvsock.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 0cbfc69..6fa438d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5222,7 +5222,9 @@ F: drivers/pci/host/pci-hyperv.c
F: drivers/net/hyperv/
F: drivers/scsi/storvsc_drv.c
F: drivers/video/fbdev/hyperv_fb.c
+F: net/hv_sock/
F: include/linux/hyperv.h
+F: include/net/af_hvsock.h
F: tools/hv/
F: Documentation/ABI/stable/sysfs-bus-vmbus
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index aa0fadc..b92439d 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1338,4 +1338,20 @@ extern __u32 vmbus_proto_version;
int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id,
const uuid_le *shv_host_servie_id);
+struct vmpipe_proto_header {
+ u32 pkt_type;
+ u32 data_size;
+} __packed;
+
+#define HVSOCK_HEADER_LEN (sizeof(struct vmpacket_descriptor) + \
+ sizeof(struct vmpipe_proto_header))
+
+/* See 'prev_indices' in hv_ringbuffer_read(), hv_ringbuffer_write() */
+#define PREV_INDICES_LEN (sizeof(u64))
+
+#define HVSOCK_PKT_LEN(payload_len) (HVSOCK_HEADER_LEN + \
+ ALIGN((payload_len), 8) + \
+ PREV_INDICES_LEN)
+#define HVSOCK_MIN_PKT_LEN HVSOCK_PKT_LEN(1)
+
#endif /* _HYPERV_H */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 73bf6c6..88b1ccd 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -201,8 +201,8 @@ struct ucred {
#define AF_NFC 39 /* NFC sockets */
#define AF_VSOCK 40 /* vSockets */
#define AF_KCM 41 /* Kernel Connection Multiplexor*/
-
-#define AF_MAX 42 /* For now.. */
+#define AF_HYPERV 42 /* Hyper-V Sockets */
+#define AF_MAX 43 /* For now.. */
/* Protocol families, same as address families. */
#define PF_UNSPEC AF_UNSPEC
@@ -249,6 +249,7 @@ struct ucred {
#define PF_NFC AF_NFC
#define PF_VSOCK AF_VSOCK
#define PF_KCM AF_KCM
+#define PF_HYPERV AF_HYPERV
#define PF_MAX AF_MAX
/* Maximum queue length specifiable by listen. */
diff --git a/include/net/af_hvsock.h b/include/net/af_hvsock.h
new file mode 100644
index 0000000..a5aa28d
--- /dev/null
+++ b/include/net/af_hvsock.h
@@ -0,0 +1,51 @@
+#ifndef __AF_HVSOCK_H__
+#define __AF_HVSOCK_H__
+
+#include <linux/kernel.h>
+#include <linux/hyperv.h>
+#include <net/sock.h>
+
+#define VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV (5 * PAGE_SIZE)
+#define VMBUS_RINGBUFFER_SIZE_HVSOCK_SEND (5 * PAGE_SIZE)
+
+#define HVSOCK_RCV_BUF_SZ VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV
+#define HVSOCK_SND_BUF_SZ PAGE_SIZE
+
+#define sk_to_hvsock(__sk) ((struct hvsock_sock *)(__sk))
+#define hvsock_to_sk(__hvsk) ((struct sock *)(__hvsk))
+
+struct hvsock_sock {
+ /* sk must be the first member. */
+ struct sock sk;
+
+ struct sockaddr_hv local_addr;
+ struct sockaddr_hv remote_addr;
+
+ /* protected by the global hvsock_mutex */
+ struct list_head bound_list;
+ struct list_head connected_list;
+
+ struct list_head accept_queue;
+ /* used by enqueue and dequeue */
+ struct mutex accept_queue_mutex;
+
+ struct delayed_work dwork;
+
+ u32 peer_shutdown;
+
+ struct vmbus_channel *channel;
+
+ struct {
+ struct vmpipe_proto_header hdr;
+ char buf[HVSOCK_SND_BUF_SZ];
+ } __packed send;
+
+ struct {
+ struct vmpipe_proto_header hdr;
+ char buf[HVSOCK_RCV_BUF_SZ];
+ unsigned int data_len;
+ unsigned int data_offset;
+ } __packed recv;
+};
+
+#endif /* __AF_HVSOCK_H__ */
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
index e347b24..21534db 100644
--- a/include/uapi/linux/hyperv.h
+++ b/include/uapi/linux/hyperv.h
@@ -26,6 +26,7 @@
#define _UAPI_HYPERV_H
#include <linux/uuid.h>
+#include <linux/socket.h>
/*
* Framework version for util services.
@@ -396,4 +397,19 @@ struct hv_kvp_ip_msg {
struct hv_kvp_ipaddr_value kvp_ip_val;
} __attribute__((packed));
+/* This is the Hyper-V socket's address format. */
+struct sockaddr_hv {
+ __kernel_sa_family_t shv_family; /* Address family */
+ __le16 reserved; /* Must be Zero */
+ uuid_le shv_vm_id; /* Not used. Must be Zero. */
+ uuid_le shv_service_id; /* Service ID */
+};
+
+#define SHV_VMID_GUEST NULL_UUID_LE
+#define SHV_VMID_HOST NULL_UUID_LE
+
+#define SHV_SERVICE_ID_ANY NULL_UUID_LE
+
+#define SHV_PROTO_RAW 1
+
#endif /* _UAPI_HYPERV_H */
diff --git a/net/Kconfig b/net/Kconfig
index e134498..9fbcb56 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -231,6 +231,7 @@ source "net/dns_resolver/Kconfig"
source "net/batman-adv/Kconfig"
source "net/openvswitch/Kconfig"
source "net/vmw_vsock/Kconfig"
+source "net/hv_sock/Kconfig"
source "net/netlink/Kconfig"
source "net/mpls/Kconfig"
source "net/hsr/Kconfig"
diff --git a/net/Makefile b/net/Makefile
index 81d1411..d115c31 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_NFC) += nfc/
obj-$(CONFIG_OPENVSWITCH) += openvswitch/
obj-$(CONFIG_VSOCKETS) += vmw_vsock/
+obj-$(CONFIG_HYPERV_SOCK) += hv_sock/
obj-$(CONFIG_MPLS) += mpls/
obj-$(CONFIG_HSR) += hsr/
ifneq ($(CONFIG_NET_SWITCHDEV),)
diff --git a/net/hv_sock/Kconfig b/net/hv_sock/Kconfig
new file mode 100644
index 0000000..1f41848
--- /dev/null
+++ b/net/hv_sock/Kconfig
@@ -0,0 +1,10 @@
+config HYPERV_SOCK
+ tristate "Hyper-V Sockets"
+ depends on HYPERV
+ default m if HYPERV
+ help
+ Hyper-V Sockets is somewhat like TCP over VMBus, allowing
+ communication between Linux guest and Hyper-V host without TCP/IP.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hv_sock.
diff --git a/net/hv_sock/Makefile b/net/hv_sock/Makefile
new file mode 100644
index 0000000..716c012
--- /dev/null
+++ b/net/hv_sock/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_HYPERV_SOCK) += hv_sock.o
+
+hv_sock-y += af_hvsock.o
diff --git a/net/hv_sock/af_hvsock.c b/net/hv_sock/af_hvsock.c
new file mode 100644
index 0000000..e5639eb
--- /dev/null
+++ b/net/hv_sock/af_hvsock.c
@@ -0,0 +1,1480 @@
+/*
+ * Hyper-V Socket driver
+ *
+ * Copyright(c) 2016, Microsoft Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <net/af_hvsock.h>
+
+static struct proto hvsock_proto = {
+ .name = "HV_SOCK",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct hvsock_sock),
+};
+
+#define SS_LISTEN 255
+
+static LIST_HEAD(hvsock_bound_list);
+static LIST_HEAD(hvsock_connected_list);
+static DEFINE_MUTEX(hvsock_mutex);
+
+static bool uuid_equals(uuid_le u1, uuid_le u2)
+{
+ return !uuid_le_cmp(u1, u2);
+}
+
+/* NOTE: hvsock_mutex must be held when the below helper functions, whose
+ * names begin with __ hvsock, are invoked.
+ */
+static void __hvsock_insert_bound(struct list_head *list,
+ struct hvsock_sock *hvsk)
+{
+ sock_hold(&hvsk->sk);
+ list_add(&hvsk->bound_list, list);
+}
+
+static void __hvsock_insert_connected(struct list_head *list,
+ struct hvsock_sock *hvsk)
+{
+ sock_hold(&hvsk->sk);
+ list_add(&hvsk->connected_list, list);
+}
+
+static void __hvsock_remove_bound(struct hvsock_sock *hvsk)
+{
+ list_del_init(&hvsk->bound_list);
+ sock_put(&hvsk->sk);
+}
+
+static void __hvsock_remove_connected(struct hvsock_sock *hvsk)
+{
+ list_del_init(&hvsk->connected_list);
+ sock_put(&hvsk->sk);
+}
+
+static struct sock *__hvsock_find_bound_socket(const struct sockaddr_hv *addr)
+{
+ struct hvsock_sock *hvsk;
+
+ list_for_each_entry(hvsk, &hvsock_bound_list, bound_list)
+ if (uuid_equals(addr->shv_service_id,
+ hvsk->local_addr.shv_service_id))
+ return hvsock_to_sk(hvsk);
+ return NULL;
+}
+
+static struct sock *__hvsock_find_connected_socket_by_channel(
+ const struct vmbus_channel *channel)
+{
+ struct hvsock_sock *hvsk;
+
+ list_for_each_entry(hvsk, &hvsock_connected_list, connected_list)
+ if (hvsk->channel == channel)
+ return hvsock_to_sk(hvsk);
+ return NULL;
+}
+
+static bool __hvsock_in_bound_list(struct hvsock_sock *hvsk)
+{
+ return !list_empty(&hvsk->bound_list);
+}
+
+static bool __hvsock_in_connected_list(struct hvsock_sock *hvsk)
+{
+ return !list_empty(&hvsk->connected_list);
+}
+
+static void hvsock_insert_connected(struct hvsock_sock *hvsk)
+{
+ __hvsock_insert_connected(&hvsock_connected_list, hvsk);
+}
+
+static
+void hvsock_enqueue_accept(struct sock *listener, struct sock *connected)
+{
+ struct hvsock_sock *hvlistener;
+ struct hvsock_sock *hvconnected;
+
+ hvlistener = sk_to_hvsock(listener);
+ hvconnected = sk_to_hvsock(connected);
+
+ sock_hold(connected);
+ sock_hold(listener);
+
+ mutex_lock(&hvlistener->accept_queue_mutex);
+ list_add_tail(&hvconnected->accept_queue, &hvlistener->accept_queue);
+ listener->sk_ack_backlog++;
+ mutex_unlock(&hvlistener->accept_queue_mutex);
+}
+
+static struct sock *hvsock_dequeue_accept(struct sock *listener)
+{
+ struct hvsock_sock *hvlistener;
+ struct hvsock_sock *hvconnected;
+
+ hvlistener = sk_to_hvsock(listener);
+
+ mutex_lock(&hvlistener->accept_queue_mutex);
+
+ if (list_empty(&hvlistener->accept_queue)) {
+ mutex_unlock(&hvlistener->accept_queue_mutex);
+ return NULL;
+ }
+
+ hvconnected = list_entry(hvlistener->accept_queue.next,
+ struct hvsock_sock, accept_queue);
+
+ list_del_init(&hvconnected->accept_queue);
+ listener->sk_ack_backlog--;
+
+ mutex_unlock(&hvlistener->accept_queue_mutex);
+
+ sock_put(listener);
+ /* The caller will need a reference on the connected socket so we let
+ * it call sock_put().
+ */
+
+ return hvsock_to_sk(hvconnected);
+}
+
+static bool hvsock_is_accept_queue_empty(struct sock *sk)
+{
+ struct hvsock_sock *hvsk = sk_to_hvsock(sk);
+ int ret;
+
+ mutex_lock(&hvsk->accept_queue_mutex);
+ ret = list_empty(&hvsk->accept_queue);
+ mutex_unlock(&hvsk->accept_queue_mutex);
+
+ return ret;
+}
+
+static void hvsock_addr_init(struct sockaddr_hv *addr, uuid_le service_id)
+{
+ memset(addr, 0, sizeof(*addr));
+ addr->shv_family = AF_HYPERV;
+ addr->shv_service_id = service_id;
+}
+
+static int hvsock_addr_validate(const struct sockaddr_hv *addr)
+{
+ if (!addr)
+ return -EFAULT;
+
+ if (addr->shv_family != AF_HYPERV)
+ return -EAFNOSUPPORT;
+
+ if (addr->reserved != 0)
+ return -EINVAL;
+
+ if (!uuid_equals(addr->shv_vm_id, NULL_UUID_LE))
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool hvsock_addr_bound(const struct sockaddr_hv *addr)
+{
+ return !uuid_equals(addr->shv_service_id, SHV_SERVICE_ID_ANY);
+}
+
+static int hvsock_addr_cast(const struct sockaddr *addr, size_t len,
+ struct sockaddr_hv **out_addr)
+{
+ if (len < sizeof(**out_addr))
+ return -EFAULT;
+
+ *out_addr = (struct sockaddr_hv *)addr;
+ return hvsock_addr_validate(*out_addr);
+}
+
+static int __hvsock_do_bind(struct hvsock_sock *hvsk,
+ struct sockaddr_hv *addr)
+{
+ struct sockaddr_hv hv_addr;
+ int ret = 0;
+
+ hvsock_addr_init(&hv_addr, addr->shv_service_id);
+
+ mutex_lock(&hvsock_mutex);
+
+ if (uuid_equals(addr->shv_service_id, SHV_SERVICE_ID_ANY)) {
+ do {
+ uuid_le_gen(&hv_addr.shv_service_id);
+ } while (__hvsock_find_bound_socket(&hv_addr));
+ } else {
+ if (__hvsock_find_bound_socket(&hv_addr)) {
+ ret = -EADDRINUSE;
+ goto out;
+ }
+ }
+
+ hvsock_addr_init(&hvsk->local_addr, hv_addr.shv_service_id);
+ __hvsock_insert_bound(&hvsock_bound_list, hvsk);
+
+out:
+ mutex_unlock(&hvsock_mutex);
+
+ return ret;
+}
+
+static int __hvsock_bind(struct sock *sk, struct sockaddr_hv *addr)
+{
+ struct hvsock_sock *hvsk = sk_to_hvsock(sk);
+ int ret;
+
+ if (hvsock_addr_bound(&hvsk->local_addr))
+ return -EINVAL;
+
+ switch (sk->sk_socket->type) {
+ case SOCK_STREAM:
+ ret = __hvsock_do_bind(hvsk, addr);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/* Autobind this socket to the local address if necessary. */
+static int hvsock_auto_bind(struct hvsock_sock *hvsk)
+{
+ struct sock *sk = hvsock_to_sk(hvsk);
+ struct sockaddr_hv local_addr;
+
+ if (hvsock_addr_bound(&hvsk->local_addr))
+ return 0;
+ hvsock_addr_init(&local_addr, SHV_SERVICE_ID_ANY);
+ return __hvsock_bind(sk, &local_addr);
+}
+
+static void hvsock_sk_destruct(struct sock *sk)
+{
+ struct hvsock_sock *hvsk = sk_to_hvsock(sk);
+ struct vmbus_channel *channel = hvsk->channel;
+
+ if (!channel)
+ return;
+
+ vmbus_hvsock_device_unregister(channel);
+}
+
+static void __hvsock_release(struct sock *sk)
+{
+ struct hvsock_sock *hvsk;
+ struct sock *pending;
+
+ hvsk = sk_to_hvsock(sk);
+
+ mutex_lock(&hvsock_mutex);
+ if (__hvsock_in_bound_list(hvsk))
+ __hvsock_remove_bound(hvsk);
+
+ if (__hvsock_in_connected_list(hvsk))
+ __hvsock_remove_connected(hvsk);
+ mutex_unlock(&hvsock_mutex);
+
+ lock_sock(sk);
+ sock_orphan(sk);
+ sk->sk_shutdown = SHUTDOWN_MASK;
+
+ /* Clean up any sockets that never were accepted. */
+ while ((pending = hvsock_dequeue_accept(sk)) != NULL) {
+ __hvsock_release(pending);
+ sock_put(pending);
+ }
+
+ release_sock(sk);
+ sock_put(sk);
+}
+
+static int hvsock_release(struct socket *sock)
+{
+ /* If accept() is interrupted by a signal, the temporary socket
+ * struct's sock->sk is NULL.
+ */
+ if (sock->sk) {
+ __hvsock_release(sock->sk);
+ sock->sk = NULL;
+ }
+
+ sock->state = SS_FREE;
+ return 0;
+}
+
+static struct sock *__hvsock_create(struct net *net, struct socket *sock,
+ gfp_t priority, unsigned short type)
+{
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+
+ sk = sk_alloc(net, AF_HYPERV, priority, &hvsock_proto, 0);
+ if (!sk)
+ return NULL;
+
+ sock_init_data(sock, sk);
+
+ /* sk->sk_type is normally set in sock_init_data, but only if sock is
+ * non-NULL. We make sure that our sockets always have a type by
+ * setting it here if needed.
+ */
+ if (!sock)
+ sk->sk_type = type;
+
+ hvsk = sk_to_hvsock(sk);
+ hvsock_addr_init(&hvsk->local_addr, SHV_SERVICE_ID_ANY);
+ hvsock_addr_init(&hvsk->remote_addr, SHV_SERVICE_ID_ANY);
+
+ sk->sk_destruct = hvsock_sk_destruct;
+
+ /* Looks stream-based socket doesn't need this. */
+ sk->sk_backlog_rcv = NULL;
+
+ sk->sk_state = 0;
+ sock_reset_flag(sk, SOCK_DONE);
+
+ INIT_LIST_HEAD(&hvsk->bound_list);
+ INIT_LIST_HEAD(&hvsk->connected_list);
+
+ INIT_LIST_HEAD(&hvsk->accept_queue);
+ mutex_init(&hvsk->accept_queue_mutex);
+
+ hvsk->peer_shutdown = 0;
+
+ hvsk->recv.data_len = 0;
+ hvsk->recv.data_offset = 0;
+
+ return sk;
+}
+
+static int hvsock_bind(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ struct sockaddr_hv *hv_addr;
+ struct sock *sk;
+ int ret;
+
+ sk = sock->sk;
+
+ if (hvsock_addr_cast(addr, addr_len, &hv_addr) != 0)
+ return -EINVAL;
+
+ lock_sock(sk);
+ ret = __hvsock_bind(sk, hv_addr);
+ release_sock(sk);
+
+ return ret;
+}
+
+static int hvsock_getname(struct socket *sock,
+ struct sockaddr *addr, int *addr_len, int peer)
+{
+ struct sockaddr_hv *hv_addr;
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+ int ret;
+
+ sk = sock->sk;
+ hvsk = sk_to_hvsock(sk);
+ ret = 0;
+
+ lock_sock(sk);
+
+ if (peer) {
+ if (sock->state != SS_CONNECTED) {
+ ret = -ENOTCONN;
+ goto out;
+ }
+ hv_addr = &hvsk->remote_addr;
+ } else {
+ hv_addr = &hvsk->local_addr;
+ }
+
+ __sockaddr_check_size(sizeof(*hv_addr));
+
+ memcpy(addr, hv_addr, sizeof(*hv_addr));
+ *addr_len = sizeof(*hv_addr);
+
+out:
+ release_sock(sk);
+ return ret;
+}
+
+static int hvsock_shutdown(struct socket *sock, int mode)
+{
+ struct sock *sk;
+
+ if (mode < SHUT_RD || mode > SHUT_RDWR)
+ return -EINVAL;
+ /* This maps:
+ * SHUT_RD (0) -> RCV_SHUTDOWN (1)
+ * SHUT_WR (1) -> SEND_SHUTDOWN (2)
+ * SHUT_RDWR (2) -> SHUTDOWN_MASK (3)
+ */
+ ++mode;
+
+ if (sock->state == SS_UNCONNECTED)
+ return -ENOTCONN;
+
+ sock->state = SS_DISCONNECTING;
+
+ sk = sock->sk;
+
+ lock_sock(sk);
+
+ sk->sk_shutdown |= mode;
+ sk->sk_state_change(sk);
+
+ /* TODO: how to send a FIN if we haven't done that? */
+ if (mode & SEND_SHUTDOWN)
+ ;
+
+ release_sock(sk);
+
+ return 0;
+}
+
+static void get_ringbuffer_rw_status(struct vmbus_channel *channel,
+ bool *can_read, bool *can_write)
+{
+ u32 avl_read_bytes, avl_write_bytes, dummy;
+
+ if (can_read) {
+ hv_get_ringbuffer_availbytes(&channel->inbound,
+ &avl_read_bytes,
+ &dummy);
+ *can_read = avl_read_bytes >= HVSOCK_MIN_PKT_LEN;
+ }
+
+ /* We write into the ringbuffer only when we're able to write a
+ * a payload of 4096 bytes (the actual written payload's length may be
+ * less than 4096).
+ */
+ if (can_write) {
+ hv_get_ringbuffer_availbytes(&channel->outbound,
+ &dummy,
+ &avl_write_bytes);
+ *can_write = avl_write_bytes > HVSOCK_PKT_LEN(PAGE_SIZE);
+ }
+}
+
+static unsigned int hvsock_poll(struct file *file, struct socket *sock,
+ poll_table *wait)
+{
+ struct vmbus_channel *channel;
+ bool can_read, can_write;
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+ unsigned int mask;
+
+ sk = sock->sk;
+ hvsk = sk_to_hvsock(sk);
+
+ poll_wait(file, sk_sleep(sk), wait);
+ mask = 0;
+
+ if (sk->sk_err)
+ /* Signify that there has been an error on this socket. */
+ mask |= POLLERR;
+
+ /* INET sockets treat local write shutdown and peer write shutdown as a
+ * case of POLLHUP set.
+ */
+ if ((sk->sk_shutdown == SHUTDOWN_MASK) ||
+ ((sk->sk_shutdown & SEND_SHUTDOWN) &&
+ (hvsk->peer_shutdown & SEND_SHUTDOWN))) {
+ mask |= POLLHUP;
+ }
+
+ if (sk->sk_shutdown & RCV_SHUTDOWN ||
+ hvsk->peer_shutdown & SEND_SHUTDOWN) {
+ mask |= POLLRDHUP;
+ }
+
+ lock_sock(sk);
+
+ /* Listening sockets that have connections in their accept
+ * queue can be read.
+ */
+ if (sk->sk_state == SS_LISTEN && !hvsock_is_accept_queue_empty(sk))
+ mask |= POLLIN | POLLRDNORM;
+
+ /* The mutex is to against hvsock_open_connection() */
+ mutex_lock(&hvsock_mutex);
+
+ channel = hvsk->channel;
+ if (channel) {
+ /* If there is something in the queue then we can read */
+ get_ringbuffer_rw_status(channel, &can_read, &can_write);
+
+ if (!can_read && hvsk->recv.data_len > 0)
+ can_read = true;
+
+ if (!(sk->sk_shutdown & RCV_SHUTDOWN) && can_read)
+ mask |= POLLIN | POLLRDNORM;
+ } else {
+ can_read = false;
+ can_write = false;
+ }
+
+ mutex_unlock(&hvsock_mutex);
+
+ /* Sockets whose connections have been closed terminated should
+ * also be considered read, and we check the shutdown flag for that.
+ */
+ if (sk->sk_shutdown & RCV_SHUTDOWN ||
+ hvsk->peer_shutdown & SEND_SHUTDOWN) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ /* Connected sockets that can produce data can be written. */
+ if (sk->sk_state == SS_CONNECTED && can_write &&
+ !(sk->sk_shutdown & SEND_SHUTDOWN)) {
+ /* Remove POLLWRBAND since INET sockets are not setting it.
+ */
+ mask |= POLLOUT | POLLWRNORM;
+ }
+
+ /* Simulate INET socket poll behaviors, which sets
+ * POLLOUT|POLLWRNORM when peer is closed and nothing to read,
+ * but local send is not shutdown.
+ */
+ if (sk->sk_state == SS_UNCONNECTED &&
+ !(sk->sk_shutdown & SEND_SHUTDOWN))
+ mask |= POLLOUT | POLLWRNORM;
+
+ release_sock(sk);
+
+ return mask;
+}
+
+/* This function runs in the tasklet context of process_chn_event() */
+static void hvsock_on_channel_cb(void *ctx)
+{
+ struct sock *sk = (struct sock *)ctx;
+ struct hvsock_sock *hvsk = sk_to_hvsock(sk);
+ struct vmbus_channel *channel = hvsk->channel;
+ bool can_read, can_write;
+
+ if (!channel) {
+ WARN_ONCE(1, "NULL channel! There is a programming bug.\n");
+ return;
+ }
+
+ get_ringbuffer_rw_status(channel, &can_read, &can_write);
+
+ if (can_read)
+ sk->sk_data_ready(sk);
+
+ if (can_write)
+ sk->sk_write_space(sk);
+}
+
+static void hvsock_close_connection(struct vmbus_channel *channel)
+{
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+
+ mutex_lock(&hvsock_mutex);
+
+ sk = __hvsock_find_connected_socket_by_channel(channel);
+
+ /* The guest has already closed the connection? */
+ if (!sk)
+ goto out;
+
+ sk->sk_socket->state = SS_UNCONNECTED;
+ sk->sk_state = SS_UNCONNECTED;
+ sock_set_flag(sk, SOCK_DONE);
+
+ hvsk = sk_to_hvsock(sk);
+ hvsk->peer_shutdown |= SEND_SHUTDOWN | RCV_SHUTDOWN;
+
+ sk->sk_state_change(sk);
+out:
+ mutex_unlock(&hvsock_mutex);
+}
+
+static int hvsock_open_connection(struct vmbus_channel *channel)
+{
+ struct hvsock_sock *hvsk, *new_hvsk;
+ struct sockaddr_hv hv_addr;
+ struct sock *sk, *new_sk;
+
+ uuid_le *instance, *service_id;
+ int ret;
+
+ instance = &channel->offermsg.offer.if_instance;
+ service_id = &channel->offermsg.offer.if_type;
+
+ hvsock_addr_init(&hv_addr, *instance);
+
+ mutex_lock(&hvsock_mutex);
+
+ sk = __hvsock_find_bound_socket(&hv_addr);
+
+ if (sk) {
+ /* It is from the guest client's connect() */
+ if (sk->sk_state != SS_CONNECTING) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ hvsk = sk_to_hvsock(sk);
+ hvsk->channel = channel;
+ set_channel_read_state(channel, false);
+ vmbus_set_chn_rescind_callback(channel,
+ hvsock_close_connection);
+ ret = vmbus_open(channel, VMBUS_RINGBUFFER_SIZE_HVSOCK_SEND,
+ VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV, NULL, 0,
+ hvsock_on_channel_cb, sk);
+ if (ret != 0) {
+ hvsk->channel = NULL;
+ goto out;
+ }
+
+ set_channel_pending_send_size(channel,
+ HVSOCK_PKT_LEN(PAGE_SIZE));
+ sk->sk_state = SS_CONNECTED;
+ sk->sk_socket->state = SS_CONNECTED;
+ hvsock_insert_connected(hvsk);
+ sk->sk_state_change(sk);
+ goto out;
+ }
+
+ /* Now we suppose it is from a host client's connect() */
+ hvsock_addr_init(&hv_addr, *service_id);
+ sk = __hvsock_find_bound_socket(&hv_addr);
+
+ /* No guest server listening? Well, let's ignore the offer */
+ if (!sk || sk->sk_state != SS_LISTEN) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) {
+ ret = -EMFILE;
+ goto out;
+ }
+
+ new_sk = __hvsock_create(sock_net(sk), NULL, GFP_KERNEL, sk->sk_type);
+ if (!new_sk) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ new_hvsk = sk_to_hvsock(new_sk);
+ new_sk->sk_state = SS_CONNECTING;
+ hvsock_addr_init(&new_hvsk->local_addr, *service_id);
+ hvsock_addr_init(&new_hvsk->remote_addr, *instance);
+
+ set_channel_read_state(channel, false);
+ new_hvsk->channel = channel;
+ vmbus_set_chn_rescind_callback(channel, hvsock_close_connection);
+ ret = vmbus_open(channel, VMBUS_RINGBUFFER_SIZE_HVSOCK_SEND,
+ VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV, NULL, 0,
+ hvsock_on_channel_cb, new_sk);
+ if (ret != 0) {
+ new_hvsk->channel = NULL;
+ sock_put(new_sk);
+ goto out;
+ }
+ set_channel_pending_send_size(channel, HVSOCK_PKT_LEN(PAGE_SIZE));
+
+ new_sk->sk_state = SS_CONNECTED;
+ hvsock_insert_connected(new_hvsk);
+ hvsock_enqueue_accept(sk, new_sk);
+ sk->sk_state_change(sk);
+out:
+ mutex_unlock(&hvsock_mutex);
+ return ret;
+}
+
+static void hvsock_connect_timeout(struct work_struct *work)
+{
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+
+ hvsk = container_of(work, struct hvsock_sock, dwork.work);
+ sk = hvsock_to_sk(hvsk);
+
+ lock_sock(sk);
+ if ((sk->sk_state == SS_CONNECTING) &&
+ (sk->sk_shutdown != SHUTDOWN_MASK)) {
+ sk->sk_state = SS_UNCONNECTED;
+ sk->sk_err = ETIMEDOUT;
+ sk->sk_error_report(sk);
+ }
+ release_sock(sk);
+
+ sock_put(sk);
+}
+
+static int hvsock_connect(struct socket *sock, struct sockaddr *addr,
+ int addr_len, int flags)
+{
+ struct sockaddr_hv *remote_addr;
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+
+ DEFINE_WAIT(wait);
+ long timeout;
+
+ int ret = 0;
+
+ sk = sock->sk;
+ hvsk = sk_to_hvsock(sk);
+
+ lock_sock(sk);
+
+ switch (sock->state) {
+ case SS_CONNECTED:
+ ret = -EISCONN;
+ goto out;
+ case SS_DISCONNECTING:
+ ret = -EINVAL;
+ goto out;
+ case SS_CONNECTING:
+ /* This continues on so we can move sock into the SS_CONNECTED
+ * state once the connection has completed (at which point err
+ * will be set to zero also). Otherwise, we will either wait
+ * for the connection or return -EALREADY should this be a
+ * non-blocking call.
+ */
+ ret = -EALREADY;
+ break;
+ default:
+ if ((sk->sk_state == SS_LISTEN) ||
+ hvsock_addr_cast(addr, addr_len, &remote_addr) != 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Set the remote address that we are connecting to. */
+ memcpy(&hvsk->remote_addr, remote_addr,
+ sizeof(hvsk->remote_addr));
+
+ ret = hvsock_auto_bind(hvsk);
+ if (ret)
+ goto out;
+
+ sk->sk_state = SS_CONNECTING;
+
+ ret = vmbus_send_tl_connect_request(
+ &hvsk->local_addr.shv_service_id,
+ &hvsk->remote_addr.shv_service_id);
+ if (ret < 0)
+ goto out;
+
+ /* Mark sock as connecting and set the error code to in
+ * progress in case this is a non-blocking connect.
+ */
+ sock->state = SS_CONNECTING;
+ ret = -EINPROGRESS;
+ }
+
+ /* The receive path will handle all communication until we are able to
+ * enter the connected state. Here we wait for the connection to be
+ * completed or a notification of an error.
+ */
+ timeout = 30 * HZ;
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+
+ while (sk->sk_state != SS_CONNECTED && sk->sk_err == 0) {
+ if (flags & O_NONBLOCK) {
+ /* If we're not going to block, we schedule a timeout
+ * function to generate a timeout on the connection
+ * attempt, in case the peer doesn't respond in a
+ * timely manner. We hold on to the socket until the
+ * timeout fires.
+ */
+ sock_hold(sk);
+ INIT_DELAYED_WORK(&hvsk->dwork,
+ hvsock_connect_timeout);
+ schedule_delayed_work(&hvsk->dwork, timeout);
+
+ /* Skip ahead to preserve error code set above. */
+ goto out_wait;
+ }
+
+ release_sock(sk);
+ timeout = schedule_timeout(timeout);
+ lock_sock(sk);
+
+ if (signal_pending(current)) {
+ ret = sock_intr_errno(timeout);
+ goto out_wait_error;
+ } else if (timeout == 0) {
+ ret = -ETIMEDOUT;
+ goto out_wait_error;
+ }
+
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+ }
+
+ ret = sk->sk_err ? -sk->sk_err : 0;
+
+out_wait_error:
+ if (ret < 0) {
+ sk->sk_state = SS_UNCONNECTED;
+ sock->state = SS_UNCONNECTED;
+ }
+out_wait:
+ finish_wait(sk_sleep(sk), &wait);
+out:
+ release_sock(sk);
+ return ret;
+}
+
+static
+int hvsock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ struct hvsock_sock *hvconnected;
+ struct sock *connected;
+ struct sock *listener;
+
+ DEFINE_WAIT(wait);
+ long timeout;
+
+ int ret = 0;
+
+ listener = sock->sk;
+
+ lock_sock(listener);
+
+ if (sock->type != SOCK_STREAM) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (listener->sk_state != SS_LISTEN) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Wait for children sockets to appear; these are the new sockets
+ * created upon connection establishment.
+ */
+ timeout = sock_sndtimeo(listener, flags & O_NONBLOCK);
+ prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE);
+
+ while ((connected = hvsock_dequeue_accept(listener)) == NULL &&
+ listener->sk_err == 0) {
+ release_sock(listener);
+ timeout = schedule_timeout(timeout);
+ lock_sock(listener);
+
+ if (signal_pending(current)) {
+ ret = sock_intr_errno(timeout);
+ goto out_wait;
+ } else if (timeout == 0) {
+ ret = -EAGAIN;
+ goto out_wait;
+ }
+
+ prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE);
+ }
+
+ if (listener->sk_err)
+ ret = -listener->sk_err;
+
+ if (connected) {
+ lock_sock(connected);
+ hvconnected = sk_to_hvsock(connected);
+
+ /* If the listener socket has received an error, then we should
+ * reject this socket and return. Note that we simply mark the
+ * socket rejected, drop our reference, and let the cleanup
+ * function handle the cleanup; the fact that we found it in
+ * the listener's accept queue guarantees that the cleanup
+ * function hasn't run yet.
+ */
+ if (ret) {
+ release_sock(connected);
+ sock_put(connected);
+ goto out_wait;
+ }
+
+ newsock->state = SS_CONNECTED;
+ sock_graft(connected, newsock);
+ release_sock(connected);
+ sock_put(connected);
+ }
+
+out_wait:
+ finish_wait(sk_sleep(listener), &wait);
+out:
+ release_sock(listener);
+ return ret;
+}
+
+static int hvsock_listen(struct socket *sock, int backlog)
+{
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+ int ret = 0;
+
+ sk = sock->sk;
+ lock_sock(sk);
+
+ if (sock->type != SOCK_STREAM) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (sock->state != SS_UNCONNECTED) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (backlog <= 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ /* This is an artificial limit */
+ if (backlog > 128)
+ backlog = 128;
+
+ hvsk = sk_to_hvsock(sk);
+ if (!hvsock_addr_bound(&hvsk->local_addr)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ sk->sk_ack_backlog = 0;
+ sk->sk_max_ack_backlog = backlog;
+ sk->sk_state = SS_LISTEN;
+out:
+ release_sock(sk);
+ return ret;
+}
+
+static int hvsock_setsockopt(struct socket *sock,
+ int level,
+ int optname,
+ char __user *optval, unsigned int optlen)
+{
+ return -ENOPROTOOPT;
+}
+
+static int hvsock_getsockopt(struct socket *sock,
+ int level,
+ int optname,
+ char __user *optval, int __user *optlen)
+{
+ return -ENOPROTOOPT;
+}
+
+static int hvsock_send_data(struct vmbus_channel *channel,
+ struct hvsock_sock *hvsk,
+ size_t to_write)
+{
+ hvsk->send.hdr.pkt_type = 1;
+ hvsk->send.hdr.data_size = to_write;
+ return vmbus_sendpacket(channel, &hvsk->send.hdr,
+ sizeof(hvsk->send.hdr) + to_write,
+ 0, VM_PKT_DATA_INBAND, 0);
+}
+
+static int hvsock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+{
+ struct vmbus_channel *channel;
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+
+ size_t total_to_write = len;
+ size_t total_written = 0;
+
+ bool can_write;
+ long timeout;
+ int ret = 0;
+
+ DEFINE_WAIT(wait);
+
+ if (len == 0)
+ return -EINVAL;
+
+ if (msg->msg_flags & ~MSG_DONTWAIT) {
+ pr_err("hvsock_sendmsg: unsupported flags=0x%x\n",
+ msg->msg_flags);
+ return -EOPNOTSUPP;
+ }
+
+ sk = sock->sk;
+ hvsk = sk_to_hvsock(sk);
+ channel = hvsk->channel;
+
+ lock_sock(sk);
+
+ /* Callers should not provide a destination with stream sockets. */
+ if (msg->msg_namelen) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Send data only if both sides are not shutdown in the direction. */
+ if (sk->sk_shutdown & SEND_SHUTDOWN ||
+ hvsk->peer_shutdown & RCV_SHUTDOWN) {
+ ret = -EPIPE;
+ goto out;
+ }
+
+ if (sk->sk_state != SS_CONNECTED ||
+ !hvsock_addr_bound(&hvsk->local_addr)) {
+ ret = -ENOTCONN;
+ goto out;
+ }
+
+ if (!hvsock_addr_bound(&hvsk->remote_addr)) {
+ ret = -EDESTADDRREQ;
+ goto out;
+ }
+
+ timeout = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
+
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+
+ while (total_to_write > 0) {
+ size_t to_write;
+
+ while (1) {
+ get_ringbuffer_rw_status(channel, NULL, &can_write);
+
+ if (can_write || sk->sk_err != 0 ||
+ (sk->sk_shutdown & SEND_SHUTDOWN) ||
+ (hvsk->peer_shutdown & RCV_SHUTDOWN))
+ break;
+
+ /* Don't wait for non-blocking sockets. */
+ if (timeout == 0) {
+ ret = -EAGAIN;
+ goto out_wait;
+ }
+
+ release_sock(sk);
+
+ timeout = schedule_timeout(timeout);
+
+ lock_sock(sk);
+ if (signal_pending(current)) {
+ ret = sock_intr_errno(timeout);
+ goto out_wait;
+ } else if (timeout == 0) {
+ ret = -EAGAIN;
+ goto out_wait;
+ }
+
+ prepare_to_wait(sk_sleep(sk), &wait,
+ TASK_INTERRUPTIBLE);
+ }
+
+ /* These checks occur both as part of and after the loop
+ * conditional since we need to check before and after
+ * sleeping.
+ */
+ if (sk->sk_err) {
+ ret = -sk->sk_err;
+ goto out_wait;
+ } else if ((sk->sk_shutdown & SEND_SHUTDOWN) ||
+ (hvsk->peer_shutdown & RCV_SHUTDOWN)) {
+ ret = -EPIPE;
+ goto out_wait;
+ }
+
+ /* Note: that write will only write as many bytes as possible
+ * in the ringbuffer. It is the caller's responsibility to
+ * check how many bytes we actually wrote.
+ */
+ do {
+ to_write = min_t(size_t, HVSOCK_SND_BUF_SZ,
+ total_to_write);
+ ret = memcpy_from_msg(hvsk->send.buf, msg, to_write);
+ if (ret != 0)
+ goto out_wait;
+
+ ret = hvsock_send_data(channel, hvsk, to_write);
+ if (ret != 0)
+ goto out_wait;
+
+ total_written += to_write;
+ total_to_write -= to_write;
+ } while (total_to_write > 0);
+ }
+out_wait:
+ if (total_written > 0)
+ ret = total_written;
+
+ finish_wait(sk_sleep(sk), &wait);
+out:
+ release_sock(sk);
+
+ /* ret is a bigger-than-0 total_written or a negative err code. */
+ if (ret == 0) {
+ WARN(1, "unexpected return value of 0\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int hvsock_recv_data(struct vmbus_channel *channel,
+ struct hvsock_sock *hvsk,
+ size_t *payload_len)
+{
+ u32 buffer_actual_len;
+ u64 dummy_req_id;
+ int ret;
+
+ ret = vmbus_recvpacket(channel, &hvsk->recv.hdr,
+ sizeof(hvsk->recv.hdr) + sizeof(hvsk->recv.buf),
+ &buffer_actual_len, &dummy_req_id);
+ if (ret != 0 || buffer_actual_len <= sizeof(hvsk->recv.hdr))
+ *payload_len = 0;
+ else
+ *payload_len = hvsk->recv.hdr.data_size;
+
+ return ret;
+}
+
+static int hvsock_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t len, int flags)
+{
+ struct vmbus_channel *channel;
+ struct hvsock_sock *hvsk;
+ struct sock *sk;
+
+ size_t total_to_read = len;
+ size_t copied;
+
+ bool can_read;
+ long timeout;
+
+ int ret = 0;
+
+ DEFINE_WAIT(wait);
+
+ sk = sock->sk;
+ hvsk = sk_to_hvsock(sk);
+ channel = hvsk->channel;
+
+ lock_sock(sk);
+
+ if (sk->sk_state != SS_CONNECTED) {
+ /* Recvmsg is supposed to return 0 if a peer performs an
+ * orderly shutdown. Differentiate between that case and when a
+ * peer has not connected or a local shutdown occurred with the
+ * SOCK_DONE flag.
+ */
+ if (sock_flag(sk, SOCK_DONE))
+ ret = 0;
+ else
+ ret = -ENOTCONN;
+
+ goto out;
+ }
+
+ /* We ignore msg->addr_name/len. */
+ if (flags & ~MSG_DONTWAIT) {
+ pr_err("hvsock_recvmsg: unsupported flags=0x%x\n", flags);
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* We don't check peer_shutdown flag here since peer may actually shut
+ * down, but there can be data in the queue that a local socket can
+ * receive.
+ */
+ if (sk->sk_shutdown & RCV_SHUTDOWN) {
+ ret = 0;
+ goto out;
+ }
+
+ /* It is valid on Linux to pass in a zero-length receive buffer. This
+ * is not an error. We may as well bail out now.
+ */
+ if (!len) {
+ ret = 0;
+ goto out;
+ }
+
+ timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+ copied = 0;
+
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+
+ while (1) {
+ bool need_refill = hvsk->recv.data_len == 0;
+
+ if (need_refill)
+ get_ringbuffer_rw_status(channel, &can_read, NULL);
+ else
+ can_read = true;
+
+ if (can_read) {
+ size_t payload_len;
+
+ if (need_refill) {
+ ret = hvsock_recv_data(channel, hvsk,
+ &payload_len);
+ if (ret != 0 || payload_len == 0 ||
+ payload_len > HVSOCK_RCV_BUF_SZ) {
+ ret = -EIO;
+ goto out_wait;
+ }
+
+ hvsk->recv.data_len = payload_len;
+ hvsk->recv.data_offset = 0;
+ }
+
+ if (hvsk->recv.data_len <= total_to_read) {
+ ret = memcpy_to_msg(msg, hvsk->recv.buf +
+ hvsk->recv.data_offset,
+ hvsk->recv.data_len);
+ if (ret != 0)
+ break;
+
+ copied += hvsk->recv.data_len;
+ total_to_read -= hvsk->recv.data_len;
+ hvsk->recv.data_len = 0;
+ hvsk->recv.data_offset = 0;
+
+ if (total_to_read == 0)
+ break;
+ } else {
+ ret = memcpy_to_msg(msg, hvsk->recv.buf +
+ hvsk->recv.data_offset,
+ total_to_read);
+ if (ret != 0)
+ break;
+
+ copied += total_to_read;
+ hvsk->recv.data_len -= total_to_read;
+ hvsk->recv.data_offset += total_to_read;
+ total_to_read = 0;
+ break;
+ }
+ } else {
+ if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) ||
+ (hvsk->peer_shutdown & SEND_SHUTDOWN))
+ break;
+
+ /* Don't wait for non-blocking sockets. */
+ if (timeout == 0) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ if (copied > 0)
+ break;
+
+ release_sock(sk);
+ timeout = schedule_timeout(timeout);
+ lock_sock(sk);
+
+ if (signal_pending(current)) {
+ ret = sock_intr_errno(timeout);
+ break;
+ } else if (timeout == 0) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ prepare_to_wait(sk_sleep(sk), &wait,
+ TASK_INTERRUPTIBLE);
+ }
+ }
+
+ if (sk->sk_err)
+ ret = -sk->sk_err;
+ else if (sk->sk_shutdown & RCV_SHUTDOWN)
+ ret = 0;
+
+ if (copied > 0) {
+ ret = copied;
+
+ /* If the other side has shutdown for sending and there
+ * is nothing more to read, then we modify the socket
+ * state.
+ */
+ if ((hvsk->peer_shutdown & SEND_SHUTDOWN) &&
+ hvsk->recv.data_len == 0) {
+ get_ringbuffer_rw_status(channel, &can_read, NULL);
+ if (!can_read) {
+ sk->sk_state = SS_UNCONNECTED;
+ sock_set_flag(sk, SOCK_DONE);
+ sk->sk_state_change(sk);
+ }
+ }
+ }
+out_wait:
+ finish_wait(sk_sleep(sk), &wait);
+out:
+ release_sock(sk);
+ return ret;
+}
+
+static const struct proto_ops hvsock_ops = {
+ .family = PF_HYPERV,
+ .owner = THIS_MODULE,
+ .release = hvsock_release,
+ .bind = hvsock_bind,
+ .connect = hvsock_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = hvsock_accept,
+ .getname = hvsock_getname,
+ .poll = hvsock_poll,
+ .ioctl = sock_no_ioctl,
+ .listen = hvsock_listen,
+ .shutdown = hvsock_shutdown,
+ .setsockopt = hvsock_setsockopt,
+ .getsockopt = hvsock_getsockopt,
+ .sendmsg = hvsock_sendmsg,
+ .recvmsg = hvsock_recvmsg,
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage,
+};
+
+static int hvsock_create(struct net *net, struct socket *sock,
+ int protocol, int kern)
+{
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (protocol != 0 && protocol != SHV_PROTO_RAW)
+ return -EPROTONOSUPPORT;
+
+ switch (sock->type) {
+ case SOCK_STREAM:
+ sock->ops = &hvsock_ops;
+ break;
+ default:
+ return -ESOCKTNOSUPPORT;
+ }
+
+ sock->state = SS_UNCONNECTED;
+
+ return __hvsock_create(net, sock, GFP_KERNEL, 0) ? 0 : -ENOMEM;
+}
+
+static const struct net_proto_family hvsock_family_ops = {
+ .family = AF_HYPERV,
+ .create = hvsock_create,
+ .owner = THIS_MODULE,
+};
+
+static int hvsock_probe(struct hv_device *hdev,
+ const struct hv_vmbus_device_id *dev_id)
+{
+ struct vmbus_channel *channel = hdev->channel;
+
+ /* We ignore the error return code to suppress the unnecessary
+ * error message in vmbus_probe(): on error the host will rescind
+ * the offer in 30 seconds and we can do cleanup at that time.
+ */
+ (void)hvsock_open_connection(channel);
+
+ return 0;
+}
+
+static int hvsock_remove(struct hv_device *hdev)
+{
+ struct vmbus_channel *channel = hdev->channel;
+
+ vmbus_close(channel);
+
+ return 0;
+}
+
+/* It's not really used. See vmbus_match() and vmbus_probe(). */
+static const struct hv_vmbus_device_id id_table[] = {
+ {},
+};
+
+static struct hv_driver hvsock_drv = {
+ .name = "hv_sock",
+ .hvsock = true,
+ .id_table = id_table,
+ .probe = hvsock_probe,
+ .remove = hvsock_remove,
+};
+
+static int __init hvsock_init(void)
+{
+ int ret;
+
+ /* Hyper-V socket requires at least VMBus 4.0 */
+ if ((vmbus_proto_version >> 16) < 4) {
+ pr_err("failed to load: VMBus 4 or later is required\n");
+ return -ENODEV;
+ }
+
+ ret = vmbus_driver_register(&hvsock_drv);
+ if (ret) {
+ pr_err("failed to register hv_sock driver\n");
+ return ret;
+ }
+
+ ret = proto_register(&hvsock_proto, 0);
+ if (ret) {
+ pr_err("failed to register protocol\n");
+ goto unreg_hvsock_drv;
+ }
+
+ ret = sock_register(&hvsock_family_ops);
+ if (ret) {
+ pr_err("failed to register address family\n");
+ goto unreg_proto;
+ }
+
+ return 0;
+
+unreg_proto:
+ proto_unregister(&hvsock_proto);
+unreg_hvsock_drv:
+ vmbus_driver_unregister(&hvsock_drv);
+ return ret;
+}
+
+static void __exit hvsock_exit(void)
+{
+ sock_unregister(AF_HYPERV);
+ proto_unregister(&hvsock_proto);
+ vmbus_driver_unregister(&hvsock_drv);
+}
+
+module_init(hvsock_init);
+module_exit(hvsock_exit);
+
+MODULE_DESCRIPTION("Hyper-V Sockets");
+MODULE_LICENSE("Dual BSD/GPL");
--
2.1.0
^ permalink raw reply related
* [PATCH net-next 1/3] net: add the AF_KCM entries to family name tables
From: Dexuan Cui @ 2016-03-21 9:51 UTC (permalink / raw)
To: gregkh, davem, netdev, linux-kernel, devel, olaf, apw, jasowang,
kys, haiyangz
This is for the recent kcm driver, which introduces AF_KCM(41) in
b7ac4eb(kcm: Kernel Connection Multiplexor module).
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Cc: Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/sock.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/core/sock.c b/net/core/sock.c
index b67b9ae..7e73c26 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -221,7 +221,8 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
"sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" ,
"sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
"sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" ,
- "sk_lock-AF_NFC" , "sk_lock-AF_VSOCK" , "sk_lock-AF_MAX"
+ "sk_lock-AF_NFC" , "sk_lock-AF_VSOCK" , "sk_lock-AF_KCM" ,
+ "sk_lock-AF_MAX"
};
static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" ,
@@ -237,7 +238,8 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
"slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
"slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" ,
- "slock-AF_NFC" , "slock-AF_VSOCK" ,"slock-AF_MAX"
+ "slock-AF_NFC" , "slock-AF_VSOCK" ,"slock-AF_KCM" ,
+ "slock-AF_MAX"
};
static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" ,
@@ -253,7 +255,8 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
"clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
"clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" ,
- "clock-AF_NFC" , "clock-AF_VSOCK" , "clock-AF_MAX"
+ "clock-AF_NFC" , "clock-AF_VSOCK" , "clock-AF_KCM" ,
+ "clock-AF_MAX"
};
/*
--
2.1.0
^ permalink raw reply related
* [patch] mdio-sun4i: oops in error handling in probe
From: Dan Carpenter @ 2016-03-21 9:02 UTC (permalink / raw)
To: Florian Fainelli, Maxime Ripard; +Cc: Chen-Yu Tsai, netdev, kernel-janitors
We could end up dereferencing an error pointer when we call
regulator_disable().
Fixes: 4bdcb1dd9feb ('net: Add MDIO bus driver for the Allwinner EMAC')
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c
index f70522c..1352965 100644
--- a/drivers/net/phy/mdio-sun4i.c
+++ b/drivers/net/phy/mdio-sun4i.c
@@ -122,6 +122,7 @@ static int sun4i_mdio_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
dev_info(&pdev->dev, "no regulator found\n");
+ data->regulator = NULL;
} else {
ret = regulator_enable(data->regulator);
if (ret)
@@ -137,7 +138,8 @@ static int sun4i_mdio_probe(struct platform_device *pdev)
return 0;
err_out_disable_regulator:
- regulator_disable(data->regulator);
+ if (data->regulator)
+ regulator_disable(data->regulator);
err_out_free_mdiobus:
mdiobus_free(bus);
return ret;
^ permalink raw reply related
* [PATCH] net: smc911x: avoid unused variable warnings
From: Arnd Bergmann @ 2016-03-21 8:30 UTC (permalink / raw)
To: netdev; +Cc: Arnd Bergmann, David S. Miller, Robert Jarzmik, linux-kernel
The change to use the generic DMA engine API in the smc911x
driver has led to a harmless warning about unused local variables:
smsc/smc911x.c: In function 'smc911x_probe':
smsc/smc911x.c:1796:20: error: unused variable 'param'
smsc/smc911x.c:1795:17: error: unused variable 'mask'
smsc/smc911x.c:1794:26: error: unused variable 'config'
This puts the variable declarations inside of the same #ifdef
that protects their use.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 79d3b59a93ba ("net: smc911x: convert pxa dma to dmaengine")
---
drivers/net/ethernet/smsc/smc911x.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index 3f5711061432..a733868a43aa 100644
--- a/drivers/net/ethernet/smsc/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -1791,9 +1791,11 @@ static int smc911x_probe(struct net_device *dev)
unsigned int val, chip_id, revision;
const char *version_string;
unsigned long irq_flags;
+#ifdef SMC_USE_DMA
struct dma_slave_config config;
dma_cap_mask_t mask;
struct pxad_param param;
+#endif
DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__);
--
2.7.0
^ permalink raw reply related
* Re: [PATCH] lan78xx: Protect runtime_auto check by #ifdef CONFIG_PM
From: Oliver Neukum @ 2016-03-21 8:36 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Woojung Huh, Microchip Linux Driver Support, David S. Miller,
Guenter Roeck, Rafael J. Wysocki, netdev, linux-usb, linux-pm,
linux-kernel
In-Reply-To: <1458470636-18986-1-git-send-email-geert@linux-m68k.org>
On Sun, 2016-03-20 at 11:43 +0100, Geert Uytterhoeven wrote:
> If CONFIG_PM=n:
>
> drivers/net/usb/lan78xx.c: In function ‘lan78xx_get_stats64’:
> drivers/net/usb/lan78xx.c:3274: error: ‘struct dev_pm_info’ has no
> member named ‘runtime_auto’
>
> If PM is disabled, the runtime_auto flag is not available, but auto
> suspend is not enabled anyway. Hence protect the check for
> runtime_auto
> by #ifdef CONFIG_PM to fix this.
>
> Fixes: a59f8c5b048dc938 ("lan78xx: add ndo_get_stats64")
> Reported-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
> ---
> Alternatively, we can add a dev_pm_runtime_auto_is_enabled() wrapper
> to
> include/linux/pm.h, which always return false if CONFIG_PM is
> disabled.
That is what we do for almost everything else in include/pm_runtime.h
So it is the best solution to add the stub.
Regards
Oliver
^ permalink raw reply
* RE: [PATCH] mwifiex: advertise low priority scan feature
From: Amitkumar Karwar @ 2016-03-21 8:26 UTC (permalink / raw)
To: Wei-Ning Huang, Linux Wireless
Cc: LKML, djkurtz@chromium.org, Nishant Sarmukadam,
kvalo@codeaurora.org, netdev@vger.kernel.org
In-Reply-To: <1458547622-1632-1-git-send-email-wnhuang@google.com>
> From: linux-wireless-owner@vger.kernel.org [mailto:linux-wireless-
> owner@vger.kernel.org] On Behalf Of Wei-Ning Huang
> Sent: Monday, March 21, 2016 1:37 PM
> To: Linux Wireless
> Cc: LKML; Amitkumar Karwar; djkurtz@chromium.org; Wei-Ning Huang;
> Nishant Sarmukadam; kvalo@codeaurora.org; netdev@vger.kernel.org
> Subject: [PATCH] mwifiex: advertise low priority scan feature
>
> From: Amitkumar Karwar <akarwar@marvell.com>
>
> Low priority scan handling code which delays or aborts scan operation
> based on Tx traffic is removed recently. The reason is firmware already
> takes care of it in our new feature scan channel gap. Hence we should
> advertise low priority scan support to cfg80211.
>
> This patch fixes a problem in which OBSS scan request from
> wpa_supplicant was being rejected by cfg80211.
>
> Signed-off-by: Wei-Ning Huang <wnhuang@chromium.org>
> ---
> drivers/net/wireless/marvell/mwifiex/cfg80211.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> index bb7235e..7dafc5b 100644
> --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> @@ -4086,6 +4086,7 @@ int mwifiex_register_cfg80211(struct
> mwifiex_adapter *adapter)
>
> wiphy->features |= NL80211_FEATURE_HT_IBSS |
> NL80211_FEATURE_INACTIVITY_TIMER |
> + NL80211_FEATURE_LOW_PRIORITY_SCAN |
> NL80211_FEATURE_NEED_OBSS_SCAN;
>
> if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
Acked-by: Amitkumar Karwar <akarwar@marvell.com>
Regards,
Amitkumar
^ permalink raw reply
* Re: [PATCH] mwifiex: advertise low priority scan feature
From: Wei-Ning Huang @ 2016-03-21 8:09 UTC (permalink / raw)
To: Linux Wireless
Cc: LKML, Amitkumar Karwar, Daniel Kurtz, Wei-Ning Huang,
Nishant Sarmukadam, kvalo-sgV2jX0FEOL9JmXXK+q4OQ,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1458547622-1632-1-git-send-email-wnhuang-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Tested-by: Wei-Ning Huang <wnhuang-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
On Mon, Mar 21, 2016 at 4:07 PM, Wei-Ning Huang <wnhuang-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> wrote:
> From: Amitkumar Karwar <akarwar-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
>
> Low priority scan handling code which delays or aborts scan
> operation based on Tx traffic is removed recently. The reason
> is firmware already takes care of it in our new feature scan
> channel gap. Hence we should advertise low priority scan
> support to cfg80211.
>
> This patch fixes a problem in which OBSS scan request from
> wpa_supplicant was being rejected by cfg80211.
>
> Signed-off-by: Wei-Ning Huang <wnhuang-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> ---
> drivers/net/wireless/marvell/mwifiex/cfg80211.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> index bb7235e..7dafc5b 100644
> --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> @@ -4086,6 +4086,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
>
> wiphy->features |= NL80211_FEATURE_HT_IBSS |
> NL80211_FEATURE_INACTIVITY_TIMER |
> + NL80211_FEATURE_LOW_PRIORITY_SCAN |
> NL80211_FEATURE_NEED_OBSS_SCAN;
>
> if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
> --
> 2.8.0.rc3.226.g39d4020
>
--
Wei-Ning Huang, 黃偉寧 | Software Engineer, Google Inc., Taiwan |
wnhuang-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org | Cell: +886 910-380678
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] mwifiex: advertise low priority scan feature
From: Wei-Ning Huang @ 2016-03-21 8:07 UTC (permalink / raw)
To: Linux Wireless
Cc: LKML, akarwar, djkurtz, Wei-Ning Huang, nishants, kvalo, netdev
From: Amitkumar Karwar <akarwar@marvell.com>
Low priority scan handling code which delays or aborts scan
operation based on Tx traffic is removed recently. The reason
is firmware already takes care of it in our new feature scan
channel gap. Hence we should advertise low priority scan
support to cfg80211.
This patch fixes a problem in which OBSS scan request from
wpa_supplicant was being rejected by cfg80211.
Signed-off-by: Wei-Ning Huang <wnhuang@chromium.org>
---
drivers/net/wireless/marvell/mwifiex/cfg80211.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index bb7235e..7dafc5b 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4086,6 +4086,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->features |= NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_INACTIVITY_TIMER |
+ NL80211_FEATURE_LOW_PRIORITY_SCAN |
NL80211_FEATURE_NEED_OBSS_SCAN;
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* Re: [PATCH net-next] net/mlx4_core: Fix backward compatibility on VFs
From: Alexey Kardashevskiy @ 2016-03-21 5:02 UTC (permalink / raw)
To: Eli Cohen, davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <56EBCE2F.40902-sLpHqDYs0B2HXe+LvDLADg@public.gmane.org>
On 03/18/2016 08:45 PM, Alexey Kardashevskiy wrote:
> On 03/18/2016 03:49 AM, Eli Cohen wrote:
>> Commit 85743f1eb345 ("net/mlx4_core: Set UAR page size to 4KB regardless
>> of system page size") introduced dependency where old VF drivers without
>> this fix fail to load if the PF driver runs with this commit.
>>
>> To resolve this add a module parameter which disables that functionality
>> by default. If both the PF and VFs are running with a driver with that
>> commit the administrator may set the module param to true.
>>
>> The module parameter is called enable_4k_uar.
>>
>> Fixes: 85743f1eb345 ('net/mlx4_core: Set UAR page size to 4KB ...')
>> Signed-off-by: Eli Cohen <eli-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
>
> Thanks!
After more tries, I found that if for whatever reason mlx4_core fails to
stop while shutting the guest down (last message is "mlx4_core
0000:00:00.0: mlx4_shutdown was called"), then next time VF in guest won't
start.
Example #1:
mlx4_core: Mellanox ConnectX core driver v2.2-1 (Feb, 2014)
mlx4_core: Initializing 0000:00:00.0
mlx4_core 0000:00:00.0: enabling device (0000 -> 0002)
mlx4_core 0000:00:00.0: Detected virtual function - running in slave mode
mlx4_core 0000:00:00.0: Sending reset
mlx4_core 0000:00:00.0: Sending vhcr0
mlx4_core 0000:00:00.0: HCA minimum page size:1
mlx4_core 0000:00:00.0: UAR size:4096 != kernel PAGE_SIZE of 65536
mlx4_core 0000:00:00.0: Failed to obtain slave caps
Example #2:
root@le-dbg:~# dhclient eth0
NETDEV WATCHDOG: eth0 (mlx4_core): transmit queue 11 timed out
------------[ cut here ]------------
WARNING: at /home/aik/p/guest-kernel/net/sched/sch_generic.c:303
and no IP assigned, timed out.
This is fixed by the guest restart, first restart might not help, then the
second restart will.
The host is running the latest upstream plus the patch I am replying to.
The guest is using initramdisk from debian bootstrap and vanilla v4.2
kernel, ppc64le arch, POWER8 chip, QEMU is running with 1 CPU and 2GB of RAM.
Does this look any familiar?
>
>
> Tested-by: Alexey Kardashevskiy <aik-sLpHqDYs0B2HXe+LvDLADg@public.gmane.org>
>
>
>
>
>> ---
>> drivers/net/ethernet/mellanox/mlx4/main.c | 24 ++++++++++++++++++------
>> 1 file changed, 18 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c
>> b/drivers/net/ethernet/mellanox/mlx4/main.c
>> index 503ec23e84cc..358f7230da58 100644
>> --- a/drivers/net/ethernet/mellanox/mlx4/main.c
>> +++ b/drivers/net/ethernet/mellanox/mlx4/main.c
>> @@ -105,6 +105,11 @@ module_param(enable_64b_cqe_eqe, bool, 0444);
>> MODULE_PARM_DESC(enable_64b_cqe_eqe,
>> "Enable 64 byte CQEs/EQEs when the FW supports this (default:
>> True)");
>>
>> +static bool enable_4k_uar;
>> +module_param(enable_4k_uar, bool, 0444);
>> +MODULE_PARM_DESC(enable_4k_uar,
>> + "Enable using 4K UAR. Should not be enabled if have VFs which
>> do not support 4K UARs (default: false)");
>> +
>> #define PF_CONTEXT_BEHAVIOUR_MASK (MLX4_FUNC_CAP_64B_EQE_CQE | \
>> MLX4_FUNC_CAP_EQE_CQE_STRIDE | \
>> MLX4_FUNC_CAP_DMFS_A0_STATIC)
>> @@ -423,7 +428,11 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct
>> mlx4_dev_cap *dev_cap)
>> /* Virtual PCI function needs to determine UAR page size from
>> * firmware. Only master PCI function can set the uar page size
>> */
>> - dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT;
>> + if (enable_4k_uar)
>> + dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT;
>> + else
>> + dev->uar_page_shift = PAGE_SHIFT;
>> +
>> mlx4_set_num_reserved_uars(dev, dev_cap);
>> }
>>
>> @@ -2233,11 +2242,14 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
>>
>> dev->caps.max_fmr_maps = (1 << (32 -
>> ilog2(dev->caps.num_mpts))) - 1;
>>
>> - /* Always set UAR page size 4KB, set log_uar_sz accordingly */
>> - init_hca.log_uar_sz = ilog2(dev->caps.num_uars) +
>> - PAGE_SHIFT -
>> - DEFAULT_UAR_PAGE_SHIFT;
>> - init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12;
>> + if (enable_4k_uar) {
>> + init_hca.log_uar_sz = ilog2(dev->caps.num_uars) +
>> + PAGE_SHIFT - DEFAULT_UAR_PAGE_SHIFT;
>> + init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12;
>> + } else {
>> + init_hca.log_uar_sz = ilog2(dev->caps.num_uars);
>> + init_hca.uar_page_sz = PAGE_SHIFT - 12;
>> + }
>>
>> init_hca.mw_enabled = 0;
>> if (dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW ||
>>
>
>
--
Alexey
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC PATCH 1/1] net namespace: dynamically configure new net namespace inherit net config
From: zhuyj @ 2016-03-21 2:35 UTC (permalink / raw)
To: Zhu Yanjun, davem, kuznet, jmorris, yoshfuji, kaber, netdev,
bruce.ashfield
In-Reply-To: <1457578473-14730-1-git-send-email-yanjun.zhu@windriver.com>
Hi, all
Would you like to give me some advice?
Any reply is appreciated.
Zhu Yanjun
On 03/10/2016 10:54 AM, Zhu Yanjun wrote:
> Sometimes the system engineer and application expect a new net namespace
> to inherit config from the base net config. Sometimes the current net config
> is expected by the system engineer and application. So it is necessary that
> the system engineer and application can choose a new net namespace to inherit
> from the base net config, or the current net config.
>
> For example, the value of /proc/sys/net/ipv4/ip_forward is taken as
> an example. The value of /proc/sys/net/ipv4/ip_forward in the base net
> config is 0 while the value of /proc/sys/net/ipv4/ip_forward is changed
> to 1 in the current net config. The system engineer and application can choose
> a new net namespace to inherit the value of /proc/sys/net/ipv4/ip_forward from
> the base or the current settings.
>
> Test case:
>
> 1. % cat /proc/sys/net/ipv4/net_ns_inherit
> 1
>
> 2. Set ip forwarding in the "base namespace"
>
> % echo 1 > /proc/sys/net/ipv4/ip_forward
>
> % cat /proc/sys/net/ipv4/ip_forward
> 1
>
> 3. Create a new namespace
>
> % ip netns add mynewns
>
> 4. Check ip forwarding in the new namespace
>
> % ip netns exec mynewns cat /proc/sys/net/ipv4/ip_forward
> 1
>
> 5. % echo 0 > /proc/sys/net/ipv4/net_ns_inherit
>
> % cat /proc/sys/net/ipv4/net_ns_inherit
> 0
>
> 6. Set ip forwarding in the "base namespace"
>
> % echo 1 > /proc/sys/net/ipv4/ip_forward
>
> % cat /proc/sys/net/ipv4/ip_forward
> 1
>
> 7. Create a new namespace
>
> % ip netns add mynewns_new
>
> 8. Check ip forwarding in the new namespace
>
> % ip netns exec mynewns_new cat /proc/sys/net/ipv4/ip_forward
> 0
>
> Suggested-by: Bruce Ashfield <bruce.ashfield@windriver.com>
> Signed-off-by: Zhu Yanjun <yanjun.zhu@windriver.com>
> CC: David S. Miller <davem@davemloft.net>
> CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
> CC: James Morris <jmorris@namei.org>
> CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
> CC: Patrick McHardy <kaber@trash.net>
>
> ---
> include/linux/inetdevice.h | 2 +-
> include/net/ip.h | 3 +++
> include/uapi/linux/sysctl.h | 1 +
> net/ipv4/devinet.c | 58 ++++++++++++++++++++++++++++++++++++-------
> net/ipv4/sysctl_net_ipv4.c | 7 ++++++
> 5 files changed, 61 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
> index ee971f3..1c0ae93 100644
> --- a/include/linux/inetdevice.h
> +++ b/include/linux/inetdevice.h
> @@ -164,7 +164,7 @@ static inline struct net_device *ip_dev_find(struct net *net, __be32 addr)
>
> int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
> int devinet_ioctl(struct net *net, unsigned int cmd, void __user *);
> -void devinet_init(void);
> +int devinet_init(void);
> struct in_device *inetdev_by_index(struct net *, int);
> __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope);
> __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst,
> diff --git a/include/net/ip.h b/include/net/ip.h
> index 1a98f1c..0ad4a7d 100644
> --- a/include/net/ip.h
> +++ b/include/net/ip.h
> @@ -245,6 +245,9 @@ extern int inet_peer_threshold;
> extern int inet_peer_minttl;
> extern int inet_peer_maxttl;
>
> +/* From devinet.c */
> +extern int net_ns_inherit;
> +
> /* From ip_input.c */
> extern int sysctl_ip_early_demux;
>
> diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
> index 0956373..350c3ce 100644
> --- a/include/uapi/linux/sysctl.h
> +++ b/include/uapi/linux/sysctl.h
> @@ -426,6 +426,7 @@ enum
> NET_TCP_ALLOWED_CONG_CONTROL=123,
> NET_TCP_MAX_SSTHRESH=124,
> NET_TCP_FRTO_RESPONSE=125,
> + NET_IPV4_NET_NS_INHERIT = 126,
> };
>
> enum {
> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
> index cebd9d3..b68d7fa 100644
> --- a/net/ipv4/devinet.c
> +++ b/net/ipv4/devinet.c
> @@ -2277,28 +2277,31 @@ static struct ctl_table ctl_forward_entry[] = {
> };
> #endif
>
> +#define NET_NS_INIT_DEFAULT 0
> +#define NET_NS_INIT_MODIFIED 1
> +
> +/* net ns initialized from current */
> +int net_ns_inherit __read_mostly = NET_NS_INIT_MODIFIED;
> +static struct ipv4_devconf *all_backup, *dflt_backup;
> +
> static __net_init int devinet_init_net(struct net *net)
> {
> int err;
> - struct ipv4_devconf *all, *dflt;
> + struct ipv4_devconf *all = NULL, *dflt = NULL;
> #ifdef CONFIG_SYSCTL
> struct ctl_table *tbl = ctl_forward_entry;
> struct ctl_table_header *forw_hdr;
> #endif
> -
> err = -ENOMEM;
> - all = &ipv4_devconf;
> - dflt = &ipv4_devconf_dflt;
>
> - if (!net_eq(net, &init_net)) {
> - all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
> + if (net_ns_inherit == NET_NS_INIT_DEFAULT) {
> + all = kmemdup(all_backup, sizeof(ipv4_devconf), GFP_KERNEL);
> if (!all)
> goto err_alloc_all;
>
> - dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
> + dflt = kmemdup(dflt_backup, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
> if (!dflt)
> goto err_alloc_dflt;
> -
> #ifdef CONFIG_SYSCTL
> tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
> if (!tbl)
> @@ -2309,6 +2312,29 @@ static __net_init int devinet_init_net(struct net *net)
> tbl[0].extra2 = net;
> #endif
> }
> + if (net_ns_inherit == NET_NS_INIT_MODIFIED) {
> + all = &ipv4_devconf;
> + dflt = &ipv4_devconf_dflt;
> +
> + if (!net_eq(net, &init_net)) {
> + all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
> + if (!all)
> + goto err_alloc_all;
> +
> + dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
> + if (!dflt)
> + goto err_alloc_dflt;
> +#ifdef CONFIG_SYSCTL
> + tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL);
> + if (!tbl)
> + goto err_alloc_ctl;
> +
> + tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
> + tbl[0].extra1 = all;
> + tbl[0].extra2 = net;
> +#endif
> + }
> + }
>
> #ifdef CONFIG_SYSCTL
> err = __devinet_sysctl_register(net, "all", all);
> @@ -2360,6 +2386,8 @@ static __net_exit void devinet_exit_net(struct net *net)
> __devinet_sysctl_unregister(net->ipv4.devconf_all);
> kfree(tbl);
> #endif
> + kfree(all_backup);
> + kfree(dflt_backup);
> kfree(net->ipv4.devconf_dflt);
> kfree(net->ipv4.devconf_all);
> }
> @@ -2377,10 +2405,20 @@ static struct rtnl_af_ops inet_af_ops __read_mostly = {
> .set_link_af = inet_set_link_af,
> };
>
> -void __init devinet_init(void)
> +int __init devinet_init(void)
> {
> int i;
>
> + all_backup = kmemdup(&ipv4_devconf, sizeof(ipv4_devconf), GFP_KERNEL);
> + if (!all_backup) {
> + return -ENOBUFS;
> + }
> +
> + dflt_backup = kmemdup(&ipv4_devconf_dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL);
> + if (!dflt_backup) {
> + return -ENOBUFS;
> + }
> +
> for (i = 0; i < IN4_ADDR_HSIZE; i++)
> INIT_HLIST_HEAD(&inet_addr_lst[i]);
>
> @@ -2398,4 +2436,6 @@ void __init devinet_init(void)
> rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
> rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
> inet_netconf_dump_devconf, NULL);
> +
> + return 0;
> }
> diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
> index a0bd7a5..d4a68e3 100644
> --- a/net/ipv4/sysctl_net_ipv4.c
> +++ b/net/ipv4/sysctl_net_ipv4.c
> @@ -799,6 +799,13 @@ static struct ctl_table ipv4_table[] = {
> .proc_handler = proc_dointvec_minmax,
> .extra1 = &one
> },
> + {
> + .procname = "net_ns_inherit",
> + .data = &net_ns_inherit,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec
> + },
> { }
> };
>
^ permalink raw reply
* Re: [PATCH] lan78xx: Protect runtime_auto check by #ifdef CONFIG_PM
From: Guenter Roeck @ 2016-03-20 22:59 UTC (permalink / raw)
To: Geert Uytterhoeven, Woojung Huh, Microchip Linux Driver Support,
David S. Miller
Cc: Rafael J. Wysocki, netdev, linux-usb, linux-pm, linux-kernel
In-Reply-To: <1458470636-18986-1-git-send-email-geert@linux-m68k.org>
On 03/20/2016 03:43 AM, Geert Uytterhoeven wrote:
> If CONFIG_PM=n:
>
> drivers/net/usb/lan78xx.c: In function ‘lan78xx_get_stats64’:
> drivers/net/usb/lan78xx.c:3274: error: ‘struct dev_pm_info’ has no member named ‘runtime_auto’
>
> If PM is disabled, the runtime_auto flag is not available, but auto
> suspend is not enabled anyway. Hence protect the check for runtime_auto
> by #ifdef CONFIG_PM to fix this.
>
> Fixes: a59f8c5b048dc938 ("lan78xx: add ndo_get_stats64")
> Reported-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
> ---
> Alternatively, we can add a dev_pm_runtime_auto_is_enabled() wrapper to
> include/linux/pm.h, which always return false if CONFIG_PM is disabled.
>
> The only other user in non-core code (drivers/usb/core/sysfs.c) has a
> big #ifdef CONFIG_PM check around all PM-related code.
>
> Thoughts?
Not that it matters anymore since David reverted the original patch,
but my reason for not sending a similar patch was that I wasn't sure
if .runtime_auto should be accessed from drivers in the first place,
or if there is some logical problem with the code.
Guenter
> ---
> drivers/net/usb/lan78xx.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
> index d36d5ebf37f355f2..7b9ac47b2ecf9905 100644
> --- a/drivers/net/usb/lan78xx.c
> +++ b/drivers/net/usb/lan78xx.c
> @@ -3271,7 +3271,9 @@ struct rtnl_link_stats64 *lan78xx_get_stats64(struct net_device *netdev,
> * periodic reading from HW will prevent from entering USB auto suspend.
> * if autosuspend is disabled, read from HW.
> */
> +#ifdef CONFIG_PM
> if (!dev->udev->dev.power.runtime_auto)
> +#endif
> lan78xx_update_stats(dev);
>
> mutex_lock(&dev->stats.access_lock);
>
^ permalink raw reply
* Re: [PATCH] appletalk: Pass IP-over-DDP packets through when 'ipddp0' interface is not present
From: Adam Seering @ 2016-03-20 21:19 UTC (permalink / raw)
To: David Miller; +Cc: acme, netdev
In-Reply-To: <1456447597.4577.49.camel@seering.org>
On Thu, 2016-02-25 at 19:46 -0500, Adam Seering wrote:
> On Thu, 2016-02-25 at 14:33 -0500, David Miller wrote:
> > From: Adam Seering <adam@seering.org>
> > Date: Tue, 23 Feb 2016 09:19:13 -0500
> >
> > > Let userspace programs transmit and receive raw IP-over-DDP
> > > packets
> > > with a kernel where "ipddp" was compiled as a module but is not
> > loaded
> > > (so no "ipddp0" network interface is exposed). This makes the
> > "module
> > > is not loaded" behavior match the "module was never compiled"
> > behavior.
> > >
> > > Signed-off-by: Adam Seering <adam@seering.org>
> >
> > I think a better approache is to somehow autoload the module.
>
> Could you elaborate? Specifically: the kernel currently suppresses
> packets on behalf of the module even after the module is unloaded.
> How
> would autoloading the module help with that?
>
I realize and appreciate that I'm not supposed to nag you folks for
feedback. But I don't know how to proceed. So, rather than nag you,
I've filed a bug:
https://bugzilla.kernel.org/show_bug.cgi?id=115031
I've tested my patch; I believe it to be the simplest change that
resolves this bug. I'm happy to write something else if it would be
cleaner and/or help others, but I would need a more-detailed
explanation of what you're looking for.
I've also filed a ticket downstream: Red Hat appears to not build the
ipddp module with their stock kernel release, so their users don't hit
this bug. But Ubuntu does build/ship ipddp; if they likewise didn't,
that would also solve my problem:
https://bugs.launchpad.net/ubuntu/+source/linux-lts-wily/+bug/1559772
Adam
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox