* [PATCH 10/17] ieee802154: add LIST_PHY command support
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
Add nl802154 command to get information about PHY's present in
the system.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
include/linux/nl802154.h | 4 +
net/ieee802154/Makefile | 2 +-
net/ieee802154/netlink.c | 4 +
net/ieee802154/nl-phy.c | 188 ++++++++++++++++++++++++++++++++++++++++++++
net/ieee802154/nl_policy.c | 2 +
5 files changed, 199 insertions(+), 1 deletions(-)
create mode 100644 net/ieee802154/nl-phy.c
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index b7d9435..275fd94 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -65,6 +65,9 @@ enum {
IEEE802154_ATTR_SEC,
IEEE802154_ATTR_PAGE,
+ IEEE802154_ATTR_CHANNEL_PAGE_LIST,
+
+ IEEE802154_ATTR_PHY_NAME,
__IEEE802154_ATTR_MAX,
};
@@ -114,6 +117,7 @@ enum {
IEEE802154_RX_ENABLE_CONF, /* Not supported yet */
IEEE802154_LIST_IFACE,
+ IEEE802154_LIST_PHY,
__IEEE802154_CMD_MAX,
};
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index 69af9f6..ce2d335 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
-ieee802154-y := netlink.o nl-mac.o nl_policy.o wpan-class.o
+ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
af_802154-y := af_ieee802154.o raw.o dgram.o
ccflags-y += -Wall -DDEBUG
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 5b738ec..8a22173 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -87,6 +87,10 @@ int __init ieee802154_nl_init(void)
if (rc)
goto fail;
+ rc = nl802154_phy_register();
+ if (rc)
+ goto fail;
+
return 0;
fail:
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
new file mode 100644
index 0000000..b7af722
--- /dev/null
+++ b/net/ieee802154/nl-phy.c
@@ -0,0 +1,188 @@
+/*
+ * Netlink inteface for IEEE 802.15.4 stack
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Maxim Osipov <maxim.osipov@siemens.com>
+ */
+
+#include <linux/kernel.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <net/wpan-phy.h>
+#include <linux/nl802154.h>
+
+#include "ieee802154.h"
+
+static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 pid,
+ u32 seq, int flags, struct wpan_phy *phy)
+{
+ void *hdr;
+ int i, pages = 0;
+ uint32_t *buf = kzalloc(32 * sizeof(uint32_t), GFP_KERNEL);
+
+ pr_debug("%s\n", __func__);
+
+ if (!buf)
+ goto out;
+
+ hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
+ IEEE802154_LIST_PHY);
+ if (!hdr)
+ goto out;
+
+ mutex_lock(&phy->pib_lock);
+ NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
+
+ NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, phy->current_page);
+ NLA_PUT_U8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel);
+ for (i = 0; i < 32; i++) {
+ if (phy->channels_supported[i])
+ buf[pages++] = phy->channels_supported[i] | (i << 27);
+ }
+ if (pages)
+ NLA_PUT(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
+ pages * sizeof(uint32_t), buf);
+
+ mutex_unlock(&phy->pib_lock);
+ return genlmsg_end(msg, hdr);
+
+nla_put_failure:
+ mutex_unlock(&phy->pib_lock);
+ genlmsg_cancel(msg, hdr);
+out:
+ kfree(buf);
+ return -EMSGSIZE;
+}
+
+static int ieee802154_list_phy(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ /* Request for interface name, index, type, IEEE address,
+ PAN Id, short address */
+ struct sk_buff *msg;
+ struct wpan_phy *phy;
+ const char *name;
+ int rc = -ENOBUFS;
+
+ pr_debug("%s\n", __func__);
+
+ if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
+ return -EINVAL;
+
+ name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
+ if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
+ return -EINVAL; /* phy name should be null-terminated */
+
+
+ phy = wpan_phy_find(name);
+ if (!phy)
+ return -ENODEV;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ goto out_dev;
+
+ rc = ieee802154_nl_fill_phy(msg, info->snd_pid, info->snd_seq,
+ 0, phy);
+ if (rc < 0)
+ goto out_free;
+
+ wpan_phy_put(phy);
+
+ return genlmsg_reply(msg, info);
+out_free:
+ nlmsg_free(msg);
+out_dev:
+ wpan_phy_put(phy);
+ return rc;
+
+}
+
+struct dump_phy_data {
+ struct sk_buff *skb;
+ struct netlink_callback *cb;
+ int idx, s_idx;
+};
+
+static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data)
+{
+ int rc;
+ struct dump_phy_data *data = _data;
+
+ pr_debug("%s\n", __func__);
+
+ if (data->idx++ < data->s_idx)
+ return 0;
+
+ rc = ieee802154_nl_fill_phy(data->skb,
+ NETLINK_CB(data->cb->skb).pid,
+ data->cb->nlh->nlmsg_seq,
+ NLM_F_MULTI,
+ phy);
+
+ if (rc < 0) {
+ data->idx--;
+ return rc;
+ }
+
+ return 0;
+}
+
+static int ieee802154_dump_phy(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct dump_phy_data data = {
+ .cb = cb,
+ .skb = skb,
+ .s_idx = cb->args[0],
+ .idx = 0,
+ };
+
+ pr_debug("%s\n", __func__);
+
+ wpan_phy_for_each(ieee802154_dump_phy_iter, &data);
+
+ cb->args[0] = data.idx;
+
+ return skb->len;
+}
+
+static struct genl_ops ieee802154_phy_ops[] = {
+ IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
+ ieee802154_dump_phy),
+};
+
+/*
+ * No need to unregister as family unregistration will do it.
+ */
+int nl802154_phy_register(void)
+{
+ int i;
+ int rc;
+
+ for (i = 0; i < ARRAY_SIZE(ieee802154_phy_ops); i++) {
+ rc = genl_register_ops(&nl802154_family,
+ &ieee802154_phy_ops[i]);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
index 2363ebe..6adda4d 100644
--- a/net/ieee802154/nl_policy.c
+++ b/net/ieee802154/nl_policy.c
@@ -27,6 +27,7 @@
const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
[IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, },
[IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, },
+ [IEEE802154_ATTR_PHY_NAME] = { .type = NLA_STRING, },
[IEEE802154_ATTR_STATUS] = { .type = NLA_U8, },
[IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
@@ -50,5 +51,6 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
[IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, },
[IEEE802154_ATTR_DURATION] = { .type = NLA_U8, },
[IEEE802154_ATTR_ED_LIST] = { .len = 27 },
+ [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, },
};
--
1.6.5
^ permalink raw reply related
* [PATCH 11/17] fakehard: no need to export net_to_phy, make it static
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
drivers/ieee802154/fakehard.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
index 77fbb51..ccf83eb 100644
--- a/drivers/ieee802154/fakehard.c
+++ b/drivers/ieee802154/fakehard.c
@@ -32,7 +32,7 @@
#include <net/nl802154.h>
#include <net/wpan-phy.h>
-struct wpan_phy *net_to_phy(struct net_device *dev)
+static struct wpan_phy *net_to_phy(struct net_device *dev)
{
return container_of(dev->dev.parent, struct wpan_phy, dev);
}
--
1.6.5
^ permalink raw reply related
* [PATCH 12/17] fakehard: claim all 2.4 Ghz channels as supported
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
Make fakehard device claim all 2.4 Ghz channels from 802.15.4-2006,
802.15.4a-2007 as supported by the hw.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
drivers/ieee802154/fakehard.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
index ccf83eb..70a9f9c 100644
--- a/drivers/ieee802154/fakehard.c
+++ b/drivers/ieee802154/fakehard.c
@@ -356,7 +356,15 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev)
dev->addr_len);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- phy->channels_supported[0] = (1 << 27) - 1;
+ /*
+ * For now we'd like to emulate 2.4 GHz-only device,
+ * both O-QPSK and CSS
+ */
+ /* 2.4 GHz O-QPSK 802.15.4-2003 */
+ phy->channels_supported[0] |= 0x7FFF800;
+ /* 2.4 GHz CSS 802.15.4a-2007 */
+ phy->channels_supported[3] |= 0x3fff;
+
phy->transmit_power = 0xbf;
dev->netdev_ops = &fake_ops;
--
1.6.5
^ permalink raw reply related
* [PATCH 13/17] ieee802154: add an mlme_ops call to retrieve PHY object
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
ops->get_phy should increment reference to wpan-phy. As we return
the external structure, we should do refcounting correctly.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
include/net/ieee802154_netdev.h | 6 ++++++
include/net/wpan-phy.h | 2 ++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index d23fb5a..5743055 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -74,8 +74,12 @@ static inline int mac_cb_type(struct sk_buff *skb)
#define IEEE802154_MAC_SCAN_PASSIVE 2
#define IEEE802154_MAC_SCAN_ORPHAN 3
+struct wpan_phy;
/*
* This should be located at net_device->ml_priv
+ *
+ * get_phy should increment the reference counting on returned phy.
+ * Use wpan_wpy_put to put that reference.
*/
struct ieee802154_mlme_ops {
int (*assoc_req)(struct net_device *dev,
@@ -94,6 +98,8 @@ struct ieee802154_mlme_ops {
int (*scan_req)(struct net_device *dev,
u8 type, u32 channels, u8 page, u8 duration);
+ struct wpan_phy *(*get_phy)(const struct net_device *dev);
+
/*
* FIXME: these should become the part of PIB/MIB interface.
* However we still don't have IB interface of any kind
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h
index f63537c..a65e985 100644
--- a/include/net/wpan-phy.h
+++ b/include/net/wpan-phy.h
@@ -44,6 +44,8 @@ struct wpan_phy {
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
+#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev)
+
struct wpan_phy *wpan_phy_alloc(size_t priv_size);
static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev)
{
--
1.6.5
^ permalink raw reply related
* [PATCH 14/17] fakehard: mlme_ops->get_phy implementation
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
drivers/ieee802154/fakehard.c | 38 ++++++++++++++++++++++++++++++++------
1 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
index 70a9f9c..f877f13 100644
--- a/drivers/ieee802154/fakehard.c
+++ b/drivers/ieee802154/fakehard.c
@@ -32,9 +32,29 @@
#include <net/nl802154.h>
#include <net/wpan-phy.h>
-static struct wpan_phy *net_to_phy(struct net_device *dev)
+struct fakehard_priv {
+ struct wpan_phy *phy;
+};
+
+static struct wpan_phy *fake_to_phy(const struct net_device *dev)
+{
+ struct fakehard_priv *priv = netdev_priv(dev);
+ return priv->phy;
+}
+
+/**
+ * fake_get_phy - Return a phy corresponding to this device.
+ * @dev: The network device for which to return the wan-phy object
+ *
+ * This function returns a wpan-phy object corresponding to the passed
+ * network device. Reference counter for wpan-phy object is incremented,
+ * so when the wpan-phy isn't necessary, you should drop the reference
+ * via @wpan_phy_put() call.
+ */
+static struct wpan_phy *fake_get_phy(const struct net_device *dev)
{
- return container_of(dev->dev.parent, struct wpan_phy, dev);
+ struct wpan_phy *phy = fake_to_phy(dev);
+ return to_phy(get_device(&phy->dev));
}
/**
@@ -121,7 +141,7 @@ static u8 fake_get_bsn(const struct net_device *dev)
static int fake_assoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
{
- struct wpan_phy *phy = net_to_phy(dev);
+ struct wpan_phy *phy = fake_to_phy(dev);
mutex_lock(&phy->pib_lock);
phy->current_channel = channel;
@@ -196,7 +216,7 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
u8 coord_realign)
{
- struct wpan_phy *phy = net_to_phy(dev);
+ struct wpan_phy *phy = fake_to_phy(dev);
mutex_lock(&phy->pib_lock);
phy->current_channel = channel;
@@ -239,6 +259,8 @@ static struct ieee802154_mlme_ops fake_mlme = {
.start_req = fake_start_req,
.scan_req = fake_scan_req,
+ .get_phy = fake_get_phy,
+
.get_pan_id = fake_get_pan_id,
.get_short_addr = fake_get_short_addr,
.get_dsn = fake_get_dsn,
@@ -313,7 +335,7 @@ static const struct net_device_ops fake_ops = {
static void ieee802154_fake_destruct(struct net_device *dev)
{
- struct wpan_phy *phy = net_to_phy(dev);
+ struct wpan_phy *phy = fake_to_phy(dev);
wpan_phy_unregister(phy);
free_netdev(dev);
@@ -338,13 +360,14 @@ static void ieee802154_fake_setup(struct net_device *dev)
static int __devinit ieee802154fake_probe(struct platform_device *pdev)
{
struct net_device *dev;
+ struct fakehard_priv *priv;
struct wpan_phy *phy = wpan_phy_alloc(0);
int err;
if (!phy)
return -ENOMEM;
- dev = alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup);
+ dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d", ieee802154_fake_setup);
if (!dev) {
wpan_phy_free(phy);
return -ENOMEM;
@@ -370,6 +393,9 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev)
dev->netdev_ops = &fake_ops;
dev->ml_priv = &fake_mlme;
+ priv = netdev_priv(dev);
+ priv->phy = phy;
+
/*
* If the name is a format string the caller wants us to do a
* name allocation.
--
1.6.5
^ permalink raw reply related
* [PATCH 15/17] ieee802154: add two nl802154 helpers
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
Add two nl802154 helpers: one for starting a reply message, one for sending.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
net/ieee802154/ieee802154.h | 5 +++++
net/ieee802154/netlink.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h
index 0790eb0..aadec42 100644
--- a/net/ieee802154/ieee802154.h
+++ b/net/ieee802154/ieee802154.h
@@ -38,8 +38,13 @@ void __exit ieee802154_nl_exit(void);
.dumpit = _dump, \
}
+struct genl_info;
+
struct sk_buff *ieee802154_nl_create(int flags, u8 req);
int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group);
+struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
+ int flags, u8 req);
+int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info);
extern struct genl_family nl802154_family;
int nl802154_mac_register(void);
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 8a22173..33137b9 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -75,6 +75,39 @@ out:
return -ENOBUFS;
}
+struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
+ int flags, u8 req)
+{
+ void *hdr;
+ struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+
+ if (!msg)
+ return NULL;
+
+ hdr = genlmsg_put_reply(msg, info,
+ &nl802154_family, flags, req);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info)
+{
+ /* XXX: nlh is right at the start of msg */
+ void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
+
+ if (genlmsg_end(msg, hdr) < 0)
+ goto out;
+
+ return genlmsg_reply(msg, info);
+out:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
int __init ieee802154_nl_init(void)
{
int rc;
--
1.6.5
^ permalink raw reply related
* [PATCH 16/17] ieee802154: add PHY_NAME to LIST_IFACE command results
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
net/ieee802154/nl-mac.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index e8816bf..135c167 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -33,6 +33,7 @@
#include <net/nl802154.h>
#include <net/ieee802154.h>
#include <net/ieee802154_netdev.h>
+#include <net/wpan-phy.h>
#include "ieee802154.h"
@@ -251,6 +252,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
u32 seq, int flags, struct net_device *dev)
{
void *hdr;
+ struct wpan_phy *phy;
pr_debug("%s\n", __func__);
@@ -259,7 +261,11 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
if (!hdr)
goto out;
+ phy = ieee802154_mlme_ops(dev)->get_phy(dev);
+ BUG_ON(!phy);
+
NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+ NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
@@ -268,9 +274,11 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
ieee802154_mlme_ops(dev)->get_short_addr(dev));
NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID,
ieee802154_mlme_ops(dev)->get_pan_id(dev));
+ wpan_phy_put(phy);
return genlmsg_end(msg, hdr);
nla_put_failure:
+ wpan_phy_put(phy);
genlmsg_cancel(msg, hdr);
out:
return -EMSGSIZE;
--
1.6.5
^ permalink raw reply related
* [PATCH 17/17] ieee802154: add support for creation/removal of logic interfaces
From: Dmitry Eremin-Solenikov @ 2009-11-06 12:39 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Sergey Lapin
In-Reply-To: <1257511181-19403-1-git-send-email-dbaryshkov@gmail.com>
Add support for two more NL802154 commands: ADD_IFACE and DEL_IFACE,
thus allowing creation and removal of logic WPAN interfaces on the top
of wpan-phy.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
include/linux/nl802154.h | 2 +
include/net/wpan-phy.h | 4 +
net/ieee802154/nl-phy.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 162 insertions(+), 0 deletions(-)
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index 275fd94..33d9f51 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -118,6 +118,8 @@ enum {
IEEE802154_LIST_IFACE,
IEEE802154_LIST_PHY,
+ IEEE802154_ADD_IFACE,
+ IEEE802154_DEL_IFACE,
__IEEE802154_CMD_MAX,
};
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h
index a65e985..8592623 100644
--- a/include/net/wpan-phy.h
+++ b/include/net/wpan-phy.h
@@ -41,6 +41,10 @@ struct wpan_phy {
struct device dev;
int idx;
+ struct net_device *(*add_iface)(struct wpan_phy *phy,
+ const char *name);
+ void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
+
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index b7af722..199a2d9 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -26,6 +26,9 @@
#include <net/netlink.h>
#include <net/genetlink.h>
#include <net/wpan-phy.h>
+#include <net/af_ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/rtnetlink.h> /* for rtnl_{un,}lock */
#include <linux/nl802154.h>
#include "ieee802154.h"
@@ -164,9 +167,162 @@ static int ieee802154_dump_phy(struct sk_buff *skb,
return skb->len;
}
+static int ieee802154_add_iface(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct sk_buff *msg;
+ struct wpan_phy *phy;
+ const char *name;
+ const char *devname;
+ int rc = -ENOBUFS;
+ struct net_device *dev;
+
+ pr_debug("%s\n", __func__);
+
+ if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
+ return -EINVAL;
+
+ name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
+ if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
+ return -EINVAL; /* phy name should be null-terminated */
+
+ if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
+ devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
+ if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1]
+ != '\0')
+ return -EINVAL; /* phy name should be null-terminated */
+ } else {
+ devname = "wpan%d";
+ }
+
+ if (strlen(devname) >= IFNAMSIZ)
+ return -ENAMETOOLONG;
+
+ phy = wpan_phy_find(name);
+ if (!phy)
+ return -ENODEV;
+
+ msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE);
+ if (!msg)
+ goto out_dev;
+
+ if (!phy->add_iface) {
+ rc = -EINVAL;
+ goto nla_put_failure;
+ }
+
+ dev = phy->add_iface(phy, devname);
+ if (IS_ERR(dev)) {
+ rc = PTR_ERR(dev);
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
+ NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+
+ dev_put(dev);
+
+ wpan_phy_put(phy);
+
+ return ieee802154_nl_reply(msg, info);
+
+nla_put_failure:
+ nlmsg_free(msg);
+out_dev:
+ wpan_phy_put(phy);
+ return rc;
+}
+
+static int ieee802154_del_iface(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct sk_buff *msg;
+ struct wpan_phy *phy;
+ const char *name;
+ int rc;
+ struct net_device *dev;
+
+ pr_debug("%s\n", __func__);
+
+ if (!info->attrs[IEEE802154_ATTR_DEV_NAME])
+ return -EINVAL;
+
+ name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
+ if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0')
+ return -EINVAL; /* name should be null-terminated */
+
+ dev = dev_get_by_name(genl_info_net(info), name);
+ if (!dev)
+ return -ENODEV;
+
+ phy = ieee802154_mlme_ops(dev)->get_phy(dev);
+ BUG_ON(!phy);
+
+ rc = -EINVAL;
+ /* phy name is optional, but should be checked if it's given */
+ if (info->attrs[IEEE802154_ATTR_PHY_NAME]) {
+ struct wpan_phy *phy2;
+
+ const char *pname =
+ nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
+ if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1]
+ != '\0')
+ /* name should be null-terminated */
+ goto out_dev;
+
+ phy2 = wpan_phy_find(pname);
+ if (!phy2)
+ goto out_dev;
+
+ if (phy != phy2) {
+ wpan_phy_put(phy2);
+ goto out_dev;
+ }
+ }
+
+ rc = -ENOBUFS;
+
+ msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE);
+ if (!msg)
+ goto out_dev;
+
+ if (!phy->del_iface) {
+ rc = -EINVAL;
+ goto nla_put_failure;
+ }
+
+ rtnl_lock();
+ phy->del_iface(phy, dev);
+
+ /* We don't have device anymore */
+ dev_put(dev);
+ dev = NULL;
+
+ rtnl_unlock();
+
+
+ NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
+ NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, name);
+
+ wpan_phy_put(phy);
+
+ return ieee802154_nl_reply(msg, info);
+
+nla_put_failure:
+ nlmsg_free(msg);
+out_dev:
+ wpan_phy_put(phy);
+ if (dev)
+ dev_put(dev);
+
+ return rc;
+}
+
static struct genl_ops ieee802154_phy_ops[] = {
IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
ieee802154_dump_phy),
+ IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
+ IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
};
/*
--
1.6.5
^ permalink raw reply related
* Re: [PATCH 2.6.33/1 00/12] WiMAX patches for 2.6.33 (batch #1)
From: David Miller @ 2009-11-06 13:23 UTC (permalink / raw)
To: inaky; +Cc: netdev, wimax
In-Reply-To: <1257445051.3263.12.camel@localhost.localdomain>
From: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Date: Thu, 05 Nov 2009 10:17:31 -0800
> So this pull should be against:
>
> REPO git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git
> BRANCH linux-2.6.33.y
This looks a lot better, pulled and pushed back out to net-next-2.6
Thanks.
^ permalink raw reply
* [PATCH net-next] Phonet: use rwlock for sockets list
From: Rémi Denis-Courmont @ 2009-11-06 13:41 UTC (permalink / raw)
To: netdev; +Cc: Rémi Denis-Courmont
From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
---
net/phonet/socket.c | 24 ++++++++++++------------
1 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 0412beb..ecb5f20 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -47,10 +47,10 @@ static int pn_socket_release(struct socket *sock)
static struct {
struct hlist_head hlist;
- spinlock_t lock;
+ rwlock_t lock;
} pnsocks = {
.hlist = HLIST_HEAD_INIT,
- .lock = __SPIN_LOCK_UNLOCKED(pnsocks.lock),
+ .lock = __RW_LOCK_UNLOCKED(pnsocks.lock),
};
/*
@@ -65,7 +65,7 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
u16 obj = pn_sockaddr_get_object(spn);
u8 res = spn->spn_resource;
- spin_lock_bh(&pnsocks.lock);
+ read_lock_bh(&pnsocks.lock);
sk_for_each(sknode, node, &pnsocks.hlist) {
struct pn_sock *pn = pn_sk(sknode);
@@ -91,7 +91,7 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
break;
}
- spin_unlock_bh(&pnsocks.lock);
+ read_unlock_bh(&pnsocks.lock);
return rval;
}
@@ -102,7 +102,7 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
struct hlist_node *node;
struct sock *sknode;
- spin_lock(&pnsocks.lock);
+ read_lock(&pnsocks.lock);
sk_for_each(sknode, node, &pnsocks.hlist) {
struct sk_buff *clone;
@@ -117,22 +117,22 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
sk_receive_skb(sknode, clone, 0);
}
}
- spin_unlock(&pnsocks.lock);
+ read_unlock(&pnsocks.lock);
}
void pn_sock_hash(struct sock *sk)
{
- spin_lock_bh(&pnsocks.lock);
+ write_lock_bh(&pnsocks.lock);
sk_add_node(sk, &pnsocks.hlist);
- spin_unlock_bh(&pnsocks.lock);
+ write_unlock_bh(&pnsocks.lock);
}
EXPORT_SYMBOL(pn_sock_hash);
void pn_sock_unhash(struct sock *sk)
{
- spin_lock_bh(&pnsocks.lock);
+ write_lock_bh(&pnsocks.lock);
sk_del_node_init(sk);
- spin_unlock_bh(&pnsocks.lock);
+ write_unlock_bh(&pnsocks.lock);
}
EXPORT_SYMBOL(pn_sock_unhash);
@@ -466,7 +466,7 @@ static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(pnsocks.lock)
{
- spin_lock_bh(&pnsocks.lock);
+ read_lock_bh(&pnsocks.lock);
return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
}
@@ -485,7 +485,7 @@ static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void pn_sock_seq_stop(struct seq_file *seq, void *v)
__releases(pnsocks.lock)
{
- spin_unlock_bh(&pnsocks.lock);
+ read_unlock_bh(&pnsocks.lock);
}
static int pn_sock_seq_show(struct seq_file *seq, void *v)
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH net-next] Phonet: use rwlock for sockets list
From: Eric Dumazet @ 2009-11-06 13:44 UTC (permalink / raw)
To: Rémi Denis-Courmont; +Cc: netdev, Rémi Denis-Courmont
In-Reply-To: <1257514891-18917-1-git-send-email-remi@remlab.net>
Rémi Denis-Courmont a écrit :
> From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
>
> Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
> ---
> net/phonet/socket.c | 24 ++++++++++++------------
> 1 files changed, 12 insertions(+), 12 deletions(-)
Hmm... rwlocks are bad...
Would you care to explain why you introduce a rwlock ?
Thanks
^ permalink raw reply
* Re: [PATCH net-next] Phonet: use rwlock for sockets list
From: Rémi Denis-Courmont @ 2009-11-06 13:54 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, Rémi Denis-Courmont
In-Reply-To: <4AF42834.7010707@gmail.com>
On Fri, 06 Nov 2009 14:44:20 +0100, Eric Dumazet <eric.dumazet@gmail.com>
wrote:
> Rémi Denis-Courmont a écrit :
>> From: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
>>
>> Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
>> ---
>> net/phonet/socket.c | 24 ++++++++++++------------
>> 1 files changed, 12 insertions(+), 12 deletions(-)
>
> Hmm... rwlocks are bad...
They're in many places throughout the non-IP families...
> Would you care to explain why you introduce a rwlock ?
It seems better than a spinlock, assuming that sockets are
created/destroyed more seldom than they receive packets. And then
sk_for_each_rcu does not exist. I am sure there is a good reason for that,
though I wouldn't know. I guess I should try to use RCU hlist_nulls then?
--
Rémi Denis-Courmont
^ permalink raw reply
* [PATCH, WTF] atm: move all compat_ioctl handling to atm/ioctl.c
From: Arnd Bergmann @ 2009-11-06 14:00 UTC (permalink / raw)
To: David Woodhouse; +Cc: David Miller, LKML, netdev, Eric Dumazet
For some interesting historic reasons that are not at all clear to me,
we seem to have two implementations of the ATM ioctl compatibility
layer in the kernel, and we use a combination of the two.
For ioctl numbers that have the same identifier on 32 and 64 bit systems,
we go directly through the compat_ioctl socket operation, for those that
differ, we do a conversion in fs/compat_ioctl.c.
This patch moves both variants into the vcc_compat_ioctl() function, while
preserving the current behaviour. It also kills off the COMPATIBLE_IOCTL
definitions that we never use here.
Doing it this way is clearly not a good solution, but I hope it is a
step into the right direction, so that someone is able to clean up this
mess for real.
Found while trying to untangle the compat socket ioctl mess
in fs/compat_ioctl.c.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
fs/compat_ioctl.c | 205 -----------------------------------------------------
net/atm/ioctl.c | 172 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 171 insertions(+), 206 deletions(-)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index f91fd51..8b78b5f 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1212,170 +1212,6 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long a
return err;
}
-struct atmif_sioc32 {
- compat_int_t number;
- compat_int_t length;
- compat_caddr_t arg;
-};
-
-struct atm_iobuf32 {
- compat_int_t length;
- compat_caddr_t buffer;
-};
-
-#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32)
-#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32)
-#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32)
-#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32)
-#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32)
-#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32)
-#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32)
-#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32)
-#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32)
-#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32)
-#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32)
-#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
-#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
-#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
-#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
-#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
-#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32)
-
-static struct {
- unsigned int cmd32;
- unsigned int cmd;
-} atm_ioctl_map[] = {
- { ATM_GETLINKRATE32, ATM_GETLINKRATE },
- { ATM_GETNAMES32, ATM_GETNAMES },
- { ATM_GETTYPE32, ATM_GETTYPE },
- { ATM_GETESI32, ATM_GETESI },
- { ATM_GETADDR32, ATM_GETADDR },
- { ATM_RSTADDR32, ATM_RSTADDR },
- { ATM_ADDADDR32, ATM_ADDADDR },
- { ATM_DELADDR32, ATM_DELADDR },
- { ATM_GETCIRANGE32, ATM_GETCIRANGE },
- { ATM_SETCIRANGE32, ATM_SETCIRANGE },
- { ATM_SETESI32, ATM_SETESI },
- { ATM_SETESIF32, ATM_SETESIF },
- { ATM_GETSTAT32, ATM_GETSTAT },
- { ATM_GETSTATZ32, ATM_GETSTATZ },
- { ATM_GETLOOP32, ATM_GETLOOP },
- { ATM_SETLOOP32, ATM_SETLOOP },
- { ATM_QUERYLOOP32, ATM_QUERYLOOP }
-};
-
-#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map)
-
-static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct atm_iobuf __user *iobuf;
- struct atm_iobuf32 __user *iobuf32;
- u32 data;
- void __user *datap;
- int len, err;
-
- iobuf = compat_alloc_user_space(sizeof(*iobuf));
- iobuf32 = compat_ptr(arg);
-
- if (get_user(len, &iobuf32->length) ||
- get_user(data, &iobuf32->buffer))
- return -EFAULT;
- datap = compat_ptr(data);
- if (put_user(len, &iobuf->length) ||
- put_user(datap, &iobuf->buffer))
- return -EFAULT;
-
- err = sys_ioctl(fd, cmd, (unsigned long)iobuf);
-
- if (!err) {
- if (copy_in_user(&iobuf32->length, &iobuf->length,
- sizeof(int)))
- err = -EFAULT;
- }
-
- return err;
-}
-
-static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct atmif_sioc __user *sioc;
- struct atmif_sioc32 __user *sioc32;
- u32 data;
- void __user *datap;
- int err;
-
- sioc = compat_alloc_user_space(sizeof(*sioc));
- sioc32 = compat_ptr(arg);
-
- if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
- get_user(data, &sioc32->arg))
- return -EFAULT;
- datap = compat_ptr(data);
- if (put_user(datap, &sioc->arg))
- return -EFAULT;
-
- err = sys_ioctl(fd, cmd, (unsigned long) sioc);
-
- if (!err) {
- if (copy_in_user(&sioc32->length, &sioc->length,
- sizeof(int)))
- err = -EFAULT;
- }
- return err;
-}
-
-static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
-{
- int i;
- unsigned int cmd = 0;
-
- switch (cmd32) {
- case SONET_GETSTAT:
- case SONET_GETSTATZ:
- case SONET_GETDIAG:
- case SONET_SETDIAG:
- case SONET_CLRDIAG:
- case SONET_SETFRAMING:
- case SONET_GETFRAMING:
- case SONET_GETFRSENSE:
- return do_atmif_sioc(fd, cmd32, arg);
- }
-
- for (i = 0; i < NR_ATM_IOCTL; i++) {
- if (cmd32 == atm_ioctl_map[i].cmd32) {
- cmd = atm_ioctl_map[i].cmd;
- break;
- }
- }
- if (i == NR_ATM_IOCTL)
- return -EINVAL;
-
- switch (cmd) {
- case ATM_GETNAMES:
- return do_atm_iobuf(fd, cmd, arg);
-
- case ATM_GETLINKRATE:
- case ATM_GETTYPE:
- case ATM_GETESI:
- case ATM_GETADDR:
- case ATM_RSTADDR:
- case ATM_ADDADDR:
- case ATM_DELADDR:
- case ATM_GETCIRANGE:
- case ATM_SETCIRANGE:
- case ATM_SETESI:
- case ATM_SETESIF:
- case ATM_GETSTAT:
- case ATM_GETSTATZ:
- case ATM_GETLOOP:
- case ATM_SETLOOP:
- case ATM_QUERYLOOP:
- return do_atmif_sioc(fd, cmd, arg);
- }
-
- return -EINVAL;
-}
-
static __used int
ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
{
@@ -2311,22 +2147,6 @@ COMPATIBLE_IOCTL(RAW_SETBIND)
COMPATIBLE_IOCTL(RAW_GETBIND)
/* SMB ioctls which do not need any translations */
COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
-/* Little a */
-COMPATIBLE_IOCTL(ATMSIGD_CTRL)
-COMPATIBLE_IOCTL(ATMARPD_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_MCAST)
-COMPATIBLE_IOCTL(ATMLEC_DATA)
-COMPATIBLE_IOCTL(ATM_SETSC)
-COMPATIBLE_IOCTL(SIOCSIFATMTCP)
-COMPATIBLE_IOCTL(SIOCMKCLIP)
-COMPATIBLE_IOCTL(ATMARP_MKIP)
-COMPATIBLE_IOCTL(ATMARP_SETENTRY)
-COMPATIBLE_IOCTL(ATMARP_ENCAP)
-COMPATIBLE_IOCTL(ATMTCP_CREATE)
-COMPATIBLE_IOCTL(ATMTCP_REMOVE)
-COMPATIBLE_IOCTL(ATMMPC_CTRL)
-COMPATIBLE_IOCTL(ATMMPC_DATA)
/* Watchdog */
COMPATIBLE_IOCTL(WDIOC_GETSUPPORT)
COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
@@ -2613,31 +2433,6 @@ HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
/* One SMB ioctl needs translations. */
#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
-HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
-HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl)
-HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl)
-HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
/* block stuff */
#ifdef CONFIG_BLOCK
/* loop */
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 4da8892..163547d 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -191,8 +191,178 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
}
#ifdef CONFIG_COMPAT
+struct atmif_sioc32 {
+ compat_int_t number;
+ compat_int_t length;
+ compat_caddr_t arg;
+};
+
+struct atm_iobuf32 {
+ compat_int_t length;
+ compat_caddr_t buffer;
+};
+
+#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32)
+#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32)
+#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32)
+#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32)
+#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32)
+#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32)
+#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32)
+#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32)
+#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32)
+#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32)
+#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32)
+#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
+#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
+#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
+#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
+#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
+#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32)
+
+static struct {
+ unsigned int cmd32;
+ unsigned int cmd;
+} atm_ioctl_map[] = {
+ { ATM_GETLINKRATE32, ATM_GETLINKRATE },
+ { ATM_GETNAMES32, ATM_GETNAMES },
+ { ATM_GETTYPE32, ATM_GETTYPE },
+ { ATM_GETESI32, ATM_GETESI },
+ { ATM_GETADDR32, ATM_GETADDR },
+ { ATM_RSTADDR32, ATM_RSTADDR },
+ { ATM_ADDADDR32, ATM_ADDADDR },
+ { ATM_DELADDR32, ATM_DELADDR },
+ { ATM_GETCIRANGE32, ATM_GETCIRANGE },
+ { ATM_SETCIRANGE32, ATM_SETCIRANGE },
+ { ATM_SETESI32, ATM_SETESI },
+ { ATM_SETESIF32, ATM_SETESIF },
+ { ATM_GETSTAT32, ATM_GETSTAT },
+ { ATM_GETSTATZ32, ATM_GETSTATZ },
+ { ATM_GETLOOP32, ATM_GETLOOP },
+ { ATM_SETLOOP32, ATM_SETLOOP },
+ { ATM_QUERYLOOP32, ATM_QUERYLOOP }
+};
+
+#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map)
+
+static int do_atm_iobuf(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct atm_iobuf __user *iobuf;
+ struct atm_iobuf32 __user *iobuf32;
+ u32 data;
+ void __user *datap;
+ int len, err;
+
+ iobuf = compat_alloc_user_space(sizeof(*iobuf));
+ iobuf32 = compat_ptr(arg);
+
+ if (get_user(len, &iobuf32->length) ||
+ get_user(data, &iobuf32->buffer))
+ return -EFAULT;
+ datap = compat_ptr(data);
+ if (put_user(len, &iobuf->length) ||
+ put_user(datap, &iobuf->buffer))
+ return -EFAULT;
+
+ err = do_vcc_ioctl(sock, cmd, (unsigned long)iobuf, 0);
+
+ if (!err) {
+ if (copy_in_user(&iobuf32->length, &iobuf->length,
+ sizeof(int)))
+ err = -EFAULT;
+ }
+
+ return err;
+}
+
+static int do_atmif_sioc(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct atmif_sioc __user *sioc;
+ struct atmif_sioc32 __user *sioc32;
+ u32 data;
+ void __user *datap;
+ int err;
+
+ sioc = compat_alloc_user_space(sizeof(*sioc));
+ sioc32 = compat_ptr(arg);
+
+ if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
+ get_user(data, &sioc32->arg))
+ return -EFAULT;
+ datap = compat_ptr(data);
+ if (put_user(datap, &sioc->arg))
+ return -EFAULT;
+
+ err = do_vcc_ioctl(sock, cmd, (unsigned long) sioc, 0);
+
+ if (!err) {
+ if (copy_in_user(&sioc32->length, &sioc->length,
+ sizeof(int)))
+ err = -EFAULT;
+ }
+ return err;
+}
+
+static int do_atm_ioctl(struct socket *sock, unsigned int cmd32, unsigned long arg)
+{
+ int i;
+ unsigned int cmd = 0;
+
+ switch (cmd32) {
+ case SONET_GETSTAT:
+ case SONET_GETSTATZ:
+ case SONET_GETDIAG:
+ case SONET_SETDIAG:
+ case SONET_CLRDIAG:
+ case SONET_SETFRAMING:
+ case SONET_GETFRAMING:
+ case SONET_GETFRSENSE:
+ return do_atmif_sioc(sock, cmd32, arg);
+ }
+
+ for (i = 0; i < NR_ATM_IOCTL; i++) {
+ if (cmd32 == atm_ioctl_map[i].cmd32) {
+ cmd = atm_ioctl_map[i].cmd;
+ break;
+ }
+ }
+ if (i == NR_ATM_IOCTL)
+ return -EINVAL;
+
+ switch (cmd) {
+ case ATM_GETNAMES:
+ return do_atm_iobuf(sock, cmd, arg);
+
+ case ATM_GETLINKRATE:
+ case ATM_GETTYPE:
+ case ATM_GETESI:
+ case ATM_GETADDR:
+ case ATM_RSTADDR:
+ case ATM_ADDADDR:
+ case ATM_DELADDR:
+ case ATM_GETCIRANGE:
+ case ATM_SETCIRANGE:
+ case ATM_SETESI:
+ case ATM_SETESIF:
+ case ATM_GETSTAT:
+ case ATM_GETSTATZ:
+ case ATM_GETLOOP:
+ case ATM_SETLOOP:
+ case ATM_QUERYLOOP:
+ return do_atmif_sioc(sock, cmd, arg);
+ }
+
+ return -EINVAL;
+}
+
int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
- return do_vcc_ioctl(sock, cmd, arg, 1);
+ int ret;
+
+ ret = do_vcc_ioctl(sock, cmd, arg, 1);
+ if (ret != -ENOIOCTLCMD)
+ return ret;
+
+ return do_atm_ioctl(sock, cmd, arg);
}
#endif
^ permalink raw reply related
* Re: [PATCH net-next] Phonet: use rwlock for sockets list
From: Eric Dumazet @ 2009-11-06 14:00 UTC (permalink / raw)
To: Rémi Denis-Courmont; +Cc: netdev, Rémi Denis-Courmont
In-Reply-To: <65081524fbfeb975c842ebc79a8fb038@chewa.net>
Rémi Denis-Courmont a écrit :
> It seems better than a spinlock, assuming that sockets are
> created/destroyed more seldom than they receive packets. And then
> sk_for_each_rcu does not exist. I am sure there is a good reason for that,
> though I wouldn't know. I guess I should try to use RCU hlist_nulls then?
>
spin_lock()/spin_unlock() is faster than read_lock()/read_unlock(), unless
there is contention. (two atomic ops instead of one)
So, unless you have a particular performance problem, it's actually
better to use a spinlock.
If you do have performance problem, a RCU conversion is better than rwlock.
I can do RCU conversion if you ask me...
^ permalink raw reply
* Re: [PATCH 1/2] udp: cleanup __udp4_lib_mcast_deliver
From: Lucian Adrian Grijincu @ 2009-11-06 14:04 UTC (permalink / raw)
To: David Miller; +Cc: netdev, opurdila
In-Reply-To: <20091106.004215.114490979.davem@davemloft.net>
În data de Vin 06 Noi 2009 10:42:15 David Miller a scris:
> Getting rid of the useless return value is fine, but the
> new do{}while() loop et al. is less readable to me.
It's not new.
I just moved it:
previously:
if(cond) {
do {}
while()
} else {return}
now:
if (!cond)
return;
do {}
while {}
Also this moves a consume_skb() from a path protected by spin locks.
As far as I understand it, the spin locks protect the hslot, and freeing the
skb does not walk/change or interact with the hslot in any way.
--
Lucian
^ permalink raw reply
* Re: [PATCH net-next] Phonet: use rwlock for sockets list
From: Rémi Denis-Courmont @ 2009-11-06 14:29 UTC (permalink / raw)
To: ext Eric Dumazet; +Cc: netdev@vger.kernel.org
In-Reply-To: <4AF42C07.4050008@gmail.com>
On Friday 06 November 2009 16:00:39 ext Eric Dumazet, you wrote:
> Rémi Denis-Courmont a écrit :
> > It seems better than a spinlock, assuming that sockets are
> > created/destroyed more seldom than they receive packets. And then
> > sk_for_each_rcu does not exist. I am sure there is a good reason for
> > that, though I wouldn't know. I guess I should try to use RCU hlist_nulls
> > then?
>
> spin_lock()/spin_unlock() is faster than read_lock()/read_unlock(), unless
> there is contention. (two atomic ops instead of one)
>
> So, unless you have a particular performance problem, it's actually
> better to use a spinlock.
>
> If you do have performance problem, a RCU conversion is better than rwlock.
> I can do RCU conversion if you ask me...
The most obvious current bottleneck is the sockets linked-list more so than
the locking scheme (RCU vs spinlock vs rwlock). I'll fix that soonish
regardless of the locking.
Then there is the devices lists. I did not want to clutter all net_device's
with a Phonet-specific pointer, since most devices aren't Phonet-capable. So
we have a linked-list for per-device data. There, I guess RCU would make
sense, but it did not seem trivial a change at all.
That said, there are no real "problems" yet - I was just trying to improve
things. N900 ships with the 2.6.30 Phonet stack, and it works fine :) The 3G
access network is typically the biggest bottleneck anyway...
So if you say R/W locks suck, screw this patch.
Thanks!
--
Rémi Denis-Courmont
Nokia Devices R&D, Maemo Software, Helsinki
^ permalink raw reply
* Re: netfilter 02/02: xt_connlimit: fix regression caused by zero family value
From: Patrick McHardy @ 2009-11-06 14:49 UTC (permalink / raw)
To: Jan Engelhardt
Cc: David S. Miller, Netfilter Development Mailinglist,
Linux Netdev List
In-Reply-To: <alpine.LSU.2.00.0911051943130.25147@obet.zrqbmnf.qr>
Jan Engelhardt wrote:
> On Thursday 2009-11-05 19:23, Patrick McHardy wrote:
>> netfilter: xt_connlimit: fix regression caused by zero family value
>>
>> Commit v2.6.28-rc1~7172~1092~2 was slightly incomplete; not all
>> instances of par->match->family were changed to par->family.
>>
>> Netfilter bugzilla #610.
>
> Hold it.
> git would never output ~7172~1092~2 because ~8266 would be much simpler.
>
> I originally wrote "Commit v2.6.28-rc1~717^2~109^2~2", but one of your
> programs seems to eat commit messages or more.
Indeed, my email client displays ^2 as ², which cut and paste transforms
to 2 :)
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] udp: cleanup __udp4_lib_mcast_deliver
From: Eric Dumazet @ 2009-11-06 15:10 UTC (permalink / raw)
To: Lucian Adrian Grijincu; +Cc: David Miller, netdev, opurdila
In-Reply-To: <200911061604.21465.lgrijincu@ixiacom.com>
Lucian Adrian Grijincu a écrit :
>
> As far as I understand it, the spin locks protect the hslot, and freeing the
> skb does not walk/change or interact with the hslot in any way.
>
Yes, but this single skb freeing is in multicast very slow path
(it happens if we receive a multicast packet with no listener, which should
not happen with multicast aware network...)
If you really want to optimize this part, we could use an array of
32 (or 64) socket pointers, to be able to perform the really expensive
work (skb_clone(), udp_queue_rcv_skb()) outside of the lock.
Something like this untested patch :
net/ipv4/udp.c | 68 ++++++++++++++++++++++++++++++-----------------
1 files changed, 44 insertions(+), 24 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d5e75e9..5d71aee 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1190,6 +1190,24 @@ drop:
return -1;
}
+
+static void flush_stack(struct sock **stack, unsigned int count,
+ struct sk_buff *skb, unsigned int final)
+{
+ unsigned int i;
+ struct sk_buff *skb1 = NULL;
+
+ for (i = 0; i < count; i++) {
+ if (likely(skb1 == NULL))
+ skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
+
+ if (likely(skb1 && udp_queue_rcv_skb(stack[i], skb1) <= 0))
+ skb1 = NULL;
+ }
+ if (unlikely(skb1))
+ consume_skb(skb1);
+}
+
/*
* Multicasts and broadcasts go to each listener.
*
@@ -1201,38 +1219,40 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
__be32 saddr, __be32 daddr,
struct udp_table *udptable)
{
- struct sock *sk;
+ struct sock *sk, *stack[256 / sizeof(void *)];
struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
int dif;
+ unsigned int i, count = 0;
spin_lock(&hslot->lock);
sk = sk_nulls_head(&hslot->head);
dif = skb->dev->ifindex;
sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
- if (sk) {
- struct sock *sknext = NULL;
-
- do {
- struct sk_buff *skb1 = skb;
-
- sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest,
- daddr, uh->source, saddr,
- dif);
- if (sknext)
- skb1 = skb_clone(skb, GFP_ATOMIC);
-
- if (skb1) {
- int ret = udp_queue_rcv_skb(sk, skb1);
- if (ret > 0)
- /* we should probably re-process instead
- * of dropping packets here. */
- kfree_skb(skb1);
- }
- sk = sknext;
- } while (sknext);
- } else
- consume_skb(skb);
+ while (sk) {
+ stack[count++] = sk;
+ if (unlikely(count == ARRAY_SIZE(stack))) {
+ flush_stack(stack, count, skb, ~0);
+ count = 0;
+ }
+
+ sk = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest,
+ daddr, uh->source, saddr, dif);
+ }
+ /*
+ * before releasing the lock, we must take reference on sockets
+ */
+ for (i = 0; i < count; i++)
+ sock_hold(stack[i]);
+
spin_unlock(&hslot->lock);
+
+ /*
+ * do the slow work with no lock held
+ */
+ flush_stack(stack, count, skb, count - 1);
+
+ for (i = 0; i < count; i++)
+ sock_put(stack[i]);
return 0;
}
^ permalink raw reply related
* Re: netfilter 02/02: xt_connlimit: fix regression caused by zero family value
From: Eric Dumazet @ 2009-11-06 15:14 UTC (permalink / raw)
To: Patrick McHardy
Cc: Jan Engelhardt, David S. Miller,
Netfilter Development Mailinglist, Linux Netdev List
In-Reply-To: <4AF43782.50604@trash.net>
Patrick McHardy a écrit :
> Indeed, my email client displays ^2 as ², which cut and paste transforms
> to 2 :)
>
One more Thunderbird addict^Wvictim :)
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC] netlink: add socket destruction notification
From: Patrick McHardy @ 2009-11-06 15:21 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, Jouni Malinen, Thomas Graf
In-Reply-To: <1254473048.3959.76.camel@johannes.local>
Johannes Berg wrote:
> When we want to keep track of resources associated with applications, we
> need to know when an app is going away. Add a notification function to
> netlink that tells us that, and also hook it up to generic netlink so
> generic netlink can notify the families. Due to the way generic netlink
> works though, we need to notify all families and they have to sort out
> whatever resources some commands associated with the socket themselves.
>
> @@ -166,6 +167,9 @@ static void netlink_sock_destruct(struct
> return;
> }
>
> + if (nlk->destruct)
> + nlk->destruct(sk);
> +
> WARN_ON(atomic_read(&sk->sk_rmem_alloc));
> WARN_ON(atomic_read(&sk->sk_wmem_alloc));
> WARN_ON(nlk_sk(sk)->groups);
This seems pretty similar to the NETLINK_URELEASE notifier invoked
in netlink_release(). Wouldn't that one work as well?
^ permalink raw reply
* Re: wanPMC-CxT1E1
From: Bob Beers @ 2009-11-06 15:25 UTC (permalink / raw)
To: Greg KH; +Cc: netdev, Krzysztof Halasa
In-Reply-To: <4f6ba3b0911021339v20d7692fm52bcd5208002d6e4@mail.gmail.com>
Hi Greg,
I don't mean to seem impatient, but is cxt1e1 in staging yet?
When it is, do I 'git pull' or re-baseline, or what? I don't mean
to cause you too much extra work, but once I get the hang of
this, I should be giving more than I'm taking.
I started over with a git clone of 2.6.31.y (vs 2.6.32.rcX) and
could submit a new patch that does not have the two Makefile
errors. It compiles and I can modprobe the driver, but on
modprobe -r, or attempting to use the pmcc4cfg util, my
system locks up, maybe due to the incomplete port of the
2 INIT_WORK() calls.
I want to first fix the unload problem, then remove all the
kernel version checking stuff. After that, I thought would be
a good time to start fixing coding style issues, so that it will
not be too painful for others to look at.
BTW, where should the pmcc4cfg source code go? It needs a
change in the Makefile before it compiles correctly.
thanks,
--
-Bob Beers
^ permalink raw reply
* Re: [RFC] netlink: add socket destruction notification
From: Johannes Berg @ 2009-11-06 15:26 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netdev, Jouni Malinen, Thomas Graf
In-Reply-To: <4AF43EF9.3020707@trash.net>
[-- Attachment #1: Type: text/plain, Size: 835 bytes --]
On Fri, 2009-11-06 at 16:21 +0100, Patrick McHardy wrote:
> Johannes Berg wrote:
> > When we want to keep track of resources associated with applications, we
> > need to know when an app is going away. Add a notification function to
> > netlink that tells us that, and also hook it up to generic netlink so
> > generic netlink can notify the families. Due to the way generic netlink
> > works though, we need to notify all families and they have to sort out
> > whatever resources some commands associated with the socket themselves.
> This seems pretty similar to the NETLINK_URELEASE notifier invoked
> in netlink_release(). Wouldn't that one work as well?
Hmm, it does seem similar, thanks for pointing it out. What exactly does
the condition
if (nlk->pid && !nlk->subscriptions) {
mean though?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [RFC] netlink: add socket destruction notification
From: Patrick McHardy @ 2009-11-06 15:37 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, Jouni Malinen, Thomas Graf
In-Reply-To: <1257521204.29454.31.camel@johannes.local>
Johannes Berg wrote:
> On Fri, 2009-11-06 at 16:21 +0100, Patrick McHardy wrote:
>> Johannes Berg wrote:
>>> When we want to keep track of resources associated with applications, we
>>> need to know when an app is going away. Add a notification function to
>>> netlink that tells us that, and also hook it up to generic netlink so
>>> generic netlink can notify the families. Due to the way generic netlink
>>> works though, we need to notify all families and they have to sort out
>>> whatever resources some commands associated with the socket themselves.
>
>
>> This seems pretty similar to the NETLINK_URELEASE notifier invoked
>> in netlink_release(). Wouldn't that one work as well?
>
> Hmm, it does seem similar, thanks for pointing it out. What exactly does
> the condition
> if (nlk->pid && !nlk->subscriptions) {
>
> mean though?
nlk->pid is non-zero for bound sockets, which is basically any
non-kernel socket which has either sent a message or explicitly
called bind(). nlk->subscriptions is zero for sockets not bound
to multicast groups.
So effectively it invokes the notifier for all bound unicast
userspace sockets. Not sure why it doesn't invoke the notifier
for sockets that are used for both unicast and multicast
reception. If that is a problem I think the second condition
could be removed.
^ permalink raw reply
* [PATCH net-next-2.6] udp: Optimise multicast reception
From: Eric Dumazet @ 2009-11-06 15:59 UTC (permalink / raw)
To: Lucian Adrian Grijincu, David Miller; +Cc: netdev, opurdila
In-Reply-To: <4AF43C5E.4060300@gmail.com>
Eric Dumazet a écrit :
> Yes, but this single skb freeing is in multicast very slow path
> (it happens if we receive a multicast packet with no listener, which should
> not happen with multicast aware network...)
>
>
> If you really want to optimize this part, we could use an array of
> 32 (or 64) socket pointers, to be able to perform the really expensive
> work (skb_clone(), udp_queue_rcv_skb()) outside of the lock.
>
> Something like this untested patch :
I did some tests and made one fix.
With this kind of stacking, we eventually could try a rcu lookup as well.
[PATCH net-next-2.6] udp: Optimise multicast reception
UDP multicast rx path is a bit complex and can hold a spinlock
for a long time.
Using a small (32 or 64 entries) stack of socket pointers can help
to perform expensive operations (skb_clone(), udp_queue_rcv_skb())
outside of the lock, in most cases.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/ipv4/udp.c | 70 ++++++++++++++++++++++++++++++-----------------
1 files changed, 46 insertions(+), 24 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d5e75e9..89637d0 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1190,6 +1190,24 @@ drop:
return -1;
}
+
+static void flush_stack(struct sock **stack, unsigned int count,
+ struct sk_buff *skb, unsigned int final)
+{
+ unsigned int i;
+ struct sk_buff *skb1 = NULL;
+
+ for (i = 0; i < count; i++) {
+ if (likely(skb1 == NULL))
+ skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
+
+ if (skb1 && udp_queue_rcv_skb(stack[i], skb1) <= 0)
+ skb1 = NULL;
+ }
+ if (skb1)
+ consume_skb(skb1);
+}
+
/*
* Multicasts and broadcasts go to each listener.
*
@@ -1201,38 +1219,42 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
__be32 saddr, __be32 daddr,
struct udp_table *udptable)
{
- struct sock *sk;
+ struct sock *sk, *stack[256 / sizeof(struct sock *)];
struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
int dif;
+ unsigned int i, count = 0;
spin_lock(&hslot->lock);
sk = sk_nulls_head(&hslot->head);
dif = skb->dev->ifindex;
sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
- if (sk) {
- struct sock *sknext = NULL;
-
- do {
- struct sk_buff *skb1 = skb;
-
- sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest,
- daddr, uh->source, saddr,
- dif);
- if (sknext)
- skb1 = skb_clone(skb, GFP_ATOMIC);
-
- if (skb1) {
- int ret = udp_queue_rcv_skb(sk, skb1);
- if (ret > 0)
- /* we should probably re-process instead
- * of dropping packets here. */
- kfree_skb(skb1);
- }
- sk = sknext;
- } while (sknext);
- } else
- consume_skb(skb);
+ while (sk) {
+ stack[count++] = sk;
+ sk = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest,
+ daddr, uh->source, saddr, dif);
+ if (unlikely(count == ARRAY_SIZE(stack))) {
+ if (!sk)
+ break;
+ flush_stack(stack, count, skb, ~0);
+ count = 0;
+ }
+
+ }
+ /*
+ * before releasing the lock, we must take reference on sockets
+ */
+ for (i = 0; i < count; i++)
+ sock_hold(stack[i]);
+
spin_unlock(&hslot->lock);
+
+ /*
+ * do the slow work with no lock held
+ */
+ flush_stack(stack, count, skb, count - 1);
+
+ for (i = 0; i < count; i++)
+ sock_put(stack[i]);
return 0;
}
^ permalink raw reply related
* Re: [RFC PATCH] net: add dataref destructor to sk_buff
From: Gregory Haskins @ 2009-11-06 16:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-kernel, alacrityvm-devel@lists.sourceforge.net
In-Reply-To: <20091105.210810.124818005.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 4583 bytes --]
David Miller wrote:
> From: Gregory Haskins <ghaskins@novell.com>
> Date: Fri, 02 Oct 2009 10:20:00 -0400
>
>> The following is an RFC for an attempt at addressing a zero-copy solution.
>>
>> To be perfectly honest, I have no idea if this is the best solution, or if
>> there is truly a problem with skb->destructor that requires an alternate
>> mechanism. What I do know is that this patch seems to work, and I would
>> like to see some kind of solution available upstream. So I thought I would
>> send my hack out as at least a point of discussion. FWIW: This has been
>> tested heavily in my rig and is technically suitable for inclusion after
>> review as is, if that is decided to be the optimal path forward here.
>>
>> Thanks for your review and consideration,
>
> I have no fundamental objections, but when you submit this for
> real can you show the code that uses it so we can get a better
> idea about things?
>
> Thanks.
Absolutely. I am not sure if this content would be appropriate for the
patch header, so I will just reply to your request here. If you would
like to see the patch resubmitted with the following in the header, let
me know.
The way we use this today is in the venet driver as part of the
AlacrityVM hypervisor. We therefore have a guest and host environment,
where the guest builds fully formed L2 frames, and the host generally
acts as a conduit for passing those frames to a real physical device
(such as through a soft-bridge, etc). We would like to do this without
requiring copies for certain classes of packets (i.e. packets larger
than a threshold). However we have to be smart about how we do this
since the guest technically "owns" the pages, and therefore needs
io-completion events to properly signify when pages are actually freed.
The way this all looks today is (I hope this doesn't get mangled):
----------------------------------------------------------------------
| guest | host |
----------------------------------------------------------------------
| stack | venet | venetdev | phydev |
----------------------------------------------------------------------
| alloc_skb() |
| dev_xmit() |
| -> queue_tx(sg) |
| -> dequeue_rx(sg) |
| alloc_pskb() |
| map_sg(sg)->pskb |
| loop(get_page()) |
| skb->release = cb |
| -> dev_xmit() |
| |
| txc_isr() <- |
| kfree_skb() |
| skb->release() |
| cb() <- |
| queue_event(sg) |
| txc_isr() <- |
| kfree_skb() |
| loop(put_page())|
----------------------------------------------------------------------
And here is the actual code in action
(kernel/vbus/devices/venet/device.c) from the alacrityvm.git tree
http://git.kernel.org/?p=linux/kernel/git/ghaskins/alacrityvm/linux-2.6.git;a=blob;f=kernel/vbus/devices/venet/device.c;h=d49ba7fa9f70cbb7e61c366d52d4c316d15f8b73;hb=HEAD
Line 587 is the "dequeue_rx()" operation from the diagram. Line 627 is
where we map in the guests pages to a scatterlist. Line 649 is where we
update the skb_shinfo->frags with the mapping. And finally, Line 677 is
where I register a callback for when the skb is released.
Line 853 is the callback that the stack invokes when the phydev finally
frees the packet. You can see that line 863 then sends an
transmit-complete event back up to the guest.
If this is not what you were looking for, please let me know. If this
looks acceptable to you, please consider the original patch for
inclusion at the next convenient merge window.
Thanks David!
-Greg
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 267 bytes --]
^ 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