Skip to contentSkip to conversation

mac802154: remove pib/mib locks and locking fixes

PATCH In review Alexander Aring 3 participants 15 messages May 22, 2015 – May 26, 2015

Subsystems (2)
lore
Share & tools
lore

Alexander Aring

author maintainer
#0 lore raw

v2 cover mac802154: remove pib/mib locks and locking fixes

Hi,

this patch series contains patches for remove pib and mib lock. We have now a other locking strategie inside this stack which requires at the moment the rtnl lock only. The first patch will hold the rtnl lock which is required to access the mib attributes while calling socket ioctl. The last patch will use atomic operations for incremet the dsn value for dataframes, currently it could be that this value is the same in two contiguous frames which could be occur a wrong ack frame handling in ARET mode.

- Alex

changes since v2:
- switch patch 3 and 4.

Alexander Aring (4):
mac802154: fix hold rtnl while ioctl
mac802154: remove pib lock
mac802154: use atomic ops for sequence incrementation
mac802154: remove mib lock

 include/net/cfg802154.h         |  6 ++--
 include/net/ieee802154_netdev.h | 10 -------
 net/ieee802154/6lowpan/core.c   | 28 ------------------
 net/ieee802154/6lowpan/tx.c     |  2 +-
 net/ieee802154/core.c           |  2 --
 net/ieee802154/nl-mac.c         | 14 ++++++---
 net/ieee802154/nl-phy.c         |  6 ++--
 net/ieee802154/socket.c         | 12 ++++----
 net/mac802154/ieee802154_i.h    |  7 -----
 net/mac802154/iface.c           | 29 ++++++-------------
 net/mac802154/mac_cmd.c         |  7 ++---
 net/mac802154/mib.c             | 63 ++---------------------------------------
 net/mac802154/rx.c              |  5 ----
 13 files changed, 34 insertions(+), 157 deletions(-)
Signature · 1 line
2.4.1
author maintainer
#1 lore raw

PATCH v2 1/4 mac802154: fix hold rtnl while ioctl

This patch fixes an issue to set address configuration with ioctl. Accessing the mib requires rtnl lock and the ndo_do_ioctl doesn't hold the rtnl lock while this callback is called. This patch do that manually.

---
 net/mac802154/iface.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
net/mac802154/iface.c +3 -2
index 91b75ab..2a58788 100644
@@ -62,8 +62,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
-	ASSERT_RTNL();
-
+	rtnl_lock();
 	spin_lock_bh(&sdata->mib_lock);
 
 	switch (cmd) {
@@ -90,6 +89,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	case SIOCSIFADDR:
 		if (netif_running(dev)) {
 			spin_unlock_bh(&sdata->mib_lock);
+			rtnl_unlock();
 			return -EBUSY;
 		}
 
@@ -112,6 +112,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	}
 
 	spin_unlock_bh(&sdata->mib_lock);
+	rtnl_unlock();
 	return err;
 }
 
Signature · 1 line
2.4.1
#2 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Quoted 35 lines · Alexander Aring

This patch fixes an issue to set address configuration with ioctl. Accessing the mib requires rtnl lock and the ndo_do_ioctl doesn't hold the rtnl lock while this callback is called. This patch do that manually.

---
 net/mac802154/iface.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
net/mac802154/iface.c +2 -2
index 91b75ab..2a58788 100644
@@ -62,8 +62,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
-	ASSERT_RTNL();
-
+	rtnl_lock();
 	spin_lock_bh(&sdata->mib_lock);
 
 	switch (cmd) {
@@ -90,6 +89,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	case SIOCSIFADDR:
 		if (netif_running(dev)) {
 			spin_unlock_bh(&sdata->mib_lock);
+			rtnl_unlock();
 			return -EBUSY;
 		}
 

net/mac802154/iface.c mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) · line 117

Quoted 6 lines
net/mac802154/iface.c +1 -0
@@ -112,6 +112,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	}
 
 	spin_unlock_bh(&sdata->mib_lock);
+	rtnl_unlock();
 	return err;
 }

This patch is causing rtnl recursion and deadlocks on my system.

A daemon running on my system (NetworkManager) tries calling various wext ioctls on newly registered network interfaces, including 802.15.4 interfaces, which are dispatched from dev_ioctl() in net/core/dev_ioctl.c via wext_handle_ioctl() in net/wireless/wext-core.c to wireless_process_ioctl() to ioctl_standard_call() to ioctl_standard_iw_point() to mac802154_wpan_ioctl(), and wext_ioctl_dispatch() does:

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
        int ret = wext_permission_check(cmd);

        if (ret)
                return ret;

        dev_load(net, ifr->ifr_name);
        rtnl_lock();
        ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
        rtnl_unlock();

        return ret;
}

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

#3 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Hi Lennert,

Quoted 44 lines
Quoted 35 lines

This patch fixes an issue to set address configuration with ioctl. Accessing the mib requires rtnl lock and the ndo_do_ioctl doesn't hold the rtnl lock while this callback is called. This patch do that manually.

---
net/mac802154/iface.c | 5 +++--

1 file changed, 3 insertions(+), 2 deletions(-)
net/mac802154/iface.c +2 -2
index 91b75ab..2a58788 100644
@@ -62,8 +62,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
-	ASSERT_RTNL();
-
+	rtnl_lock();
 	spin_lock_bh(&sdata->mib_lock);
 
 	switch (cmd) {
@@ -90,6 +89,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	case SIOCSIFADDR:
 		if (netif_running(dev)) {
 			spin_unlock_bh(&sdata->mib_lock);
+			rtnl_unlock();
 			return -EBUSY;
 		}
 

net/mac802154/iface.c mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) · line 117

Quoted 6 lines
net/mac802154/iface.c +1 -0
@@ -112,6 +112,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	}
 
 	spin_unlock_bh(&sdata->mib_lock);
+	rtnl_unlock();
 	return err;
 }

This patch is causing rtnl recursion and deadlocks on my system.

Quoted 7 lines

A daemon running on my system (NetworkManager) tries calling various wext ioctls on newly registered network interfaces, including 802.15.4 interfaces, which are dispatched from dev_ioctl() in net/core/dev_ioctl.c via wext_handle_ioctl() in net/wireless/wext-core.c to wireless_process_ioctl() to ioctl_standard_call() to ioctl_standard_iw_point() to mac802154_wpan_ioctl(), and wext_ioctl_dispatch() does:

I would really wish that NM stops this insanity with poking at all network interfaces. No wonder that people just end up removing it. First it tries to poke nl80211 and then complaints why modules are auto-loaded even without WiFi cards present and now it tries to poke at WEXT for non-WiFi interfaces.

Quoted 18 lines

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
       int ret = wext_permission_check(cmd);

       if (ret)
               return ret;

       dev_load(net, ifr->ifr_name);
       rtnl_lock();
       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
       rtnl_unlock();

       return ret;
}
Quoted 7 lines

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

I think the ioctl handler should just first check which are its valid ioctl and also enforce permission in that run without the RTNL lock held. Return -EINVAL or -ENOIOCTLCMD when it gets a cmd that this function does not handle. And then have the function actually take the RTNL lock and process its two ioctl that it supports.

That way we should avoid the nasty with taking the RTNL lock for unsupported ioctl. And hopefully at some point we can actually remove WEXT from the kernel. That it creates this nasty mess for other protocols is just insane.

Regards

Marcel

#4 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Quoted 1 line · Marcel Holtmann

Hi Lennert,

Hi Marcel,

Quoted 52 lines
Quoted 44 lines
Quoted 35 lines

This patch fixes an issue to set address configuration with ioctl. Accessing the mib requires rtnl lock and the ndo_do_ioctl doesn't hold the rtnl lock while this callback is called. This patch do that manually.

---
net/mac802154/iface.c | 5 +++--

1 file changed, 3 insertions(+), 2 deletions(-)
net/mac802154/iface.c +2 -2
index 91b75ab..2a58788 100644
@@ -62,8 +62,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
-	ASSERT_RTNL();
-
+	rtnl_lock();
 	spin_lock_bh(&sdata->mib_lock);
 
 	switch (cmd) {
@@ -90,6 +89,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	case SIOCSIFADDR:
 		if (netif_running(dev)) {
 			spin_unlock_bh(&sdata->mib_lock);
+			rtnl_unlock();
 			return -EBUSY;
 		}
 

net/mac802154/iface.c mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) · line 117

Quoted 6 lines
net/mac802154/iface.c +1 -0
@@ -112,6 +112,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	}
 
 	spin_unlock_bh(&sdata->mib_lock);
+	rtnl_unlock();
 	return err;
 }

This patch is causing rtnl recursion and deadlocks on my system.

Quoted 7 lines

A daemon running on my system (NetworkManager) tries calling various wext ioctls on newly registered network interfaces, including 802.15.4 interfaces, which are dispatched from dev_ioctl() in net/core/dev_ioctl.c via wext_handle_ioctl() in net/wireless/wext-core.c to wireless_process_ioctl() to ioctl_standard_call() to ioctl_standard_iw_point() to mac802154_wpan_ioctl(), and wext_ioctl_dispatch() does:

Quoted 5 lines

I would really wish that NM stops this insanity with poking at all network interfaces. No wonder that people just end up removing it. First it tries to poke nl80211 and then complaints why modules are auto-loaded even without WiFi cards present and now it tries to poke at WEXT for non-WiFi interfaces.

I can't say that I'm a NetworkManager fan myself... well, at least it's helping to make the kernel more robust in this case, I suppose. :(

Quoted 26 lines
Quoted 18 lines

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
       int ret = wext_permission_check(cmd);

       if (ret)
               return ret;

       dev_load(net, ifr->ifr_name);
       rtnl_lock();
       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
       rtnl_unlock();

       return ret;
}
Quoted 7 lines

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

Quoted 8 lines

I think the ioctl handler should just first check which are its valid ioctl and also enforce permission in that run without the RTNL lock held. Return -EINVAL or -ENOIOCTLCMD when it gets a cmd that this function does not handle. And then have the function actually take the RTNL lock and process its two ioctl that it supports.

That way we should avoid the nasty with taking the RTNL lock for unsupported ioctl.

Something like the below? (Alexander?) (I verified that it fixes the problem for me.)

As to adding permission checks to the 802.15.4 subsystem, that's a whole 'nother undertaking -- for one, I can currently snoop on any 802.15.4 traffic going through the box (including 6LoWPAN traffic) as an unprivileged user, which is somewhat crazy -- but that's probably something for another email (thread).

Quoted 3 lines

And hopefully at some point we can actually remove WEXT from the kernel. That it creates this nasty mess for other protocols is just insane.

I totally agree that the rtnl lock being held or not being held upon entering an ndo ioctl depending on what the ioctl cmd is is very bad, as this is just conditional locking which is bad in itself because of multiple reasons, and WEXT should be taken out and shot for causing this situation to be able to arise in the first place.

commit f5f4876bee64af07f6733d6bdb87ecb7e6fac85d

Author: Lennert Buytenhek <[email protected]>
Date:   Tue May 26 08:53:33 2015 +0300

mac802154: Avoid rtnl deadlock in mac802154_wpan_ioctl().

->ndo_do_ioctl() can be entered with the rtnl lock already held, for example when sending a wext ioctl to a device (in which case the rtnl lock is taken by wext_ioctl_dispatch()), but mac802154_wpan_ioctl() currently unconditionally takes the rtnl lock on entry, which can cause deadlocks.

To fix this, bail out of mac802154_wpan_ioctl() before taking the rtnl lock if the ioctl cmd is not one of the cmds we implement.

net/mac802154/iface.c +3 -0
index f30788d..b544b5d 100644
@@ -62,6 +62,9 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
+	if (cmd != SIOCGIFADDR && cmd != SIOCSIFADDR)
+		return err;
+
 	rtnl_lock();
 
 	switch (cmd) {
author maintainer Acked-by
#5 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Hi,

Quoted 101 lines · Lennert Buytenhek
Quoted 1 line · Marcel Holtmann

Hi Lennert,

Hi Marcel,

Quoted 52 lines
Quoted 44 lines
Quoted 35 lines

This patch fixes an issue to set address configuration with ioctl. Accessing the mib requires rtnl lock and the ndo_do_ioctl doesn't hold the rtnl lock while this callback is called. This patch do that manually.

---
net/mac802154/iface.c | 5 +++--

1 file changed, 3 insertions(+), 2 deletions(-)
net/mac802154/iface.c +2 -2
index 91b75ab..2a58788 100644
@@ -62,8 +62,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
-	ASSERT_RTNL();
-
+	rtnl_lock();
 	spin_lock_bh(&sdata->mib_lock);
 
 	switch (cmd) {
@@ -90,6 +89,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	case SIOCSIFADDR:
 		if (netif_running(dev)) {
 			spin_unlock_bh(&sdata->mib_lock);
+			rtnl_unlock();
 			return -EBUSY;
 		}
 

net/mac802154/iface.c mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) · line 117

Quoted 6 lines
net/mac802154/iface.c +1 -0
@@ -112,6 +112,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	}
 
 	spin_unlock_bh(&sdata->mib_lock);
+	rtnl_unlock();
 	return err;
 }

This patch is causing rtnl recursion and deadlocks on my system.

Quoted 7 lines

A daemon running on my system (NetworkManager) tries calling various wext ioctls on newly registered network interfaces, including 802.15.4 interfaces, which are dispatched from dev_ioctl() in net/core/dev_ioctl.c via wext_handle_ioctl() in net/wireless/wext-core.c to wireless_process_ioctl() to ioctl_standard_call() to ioctl_standard_iw_point() to mac802154_wpan_ioctl(), and wext_ioctl_dispatch() does:

Quoted 5 lines

I would really wish that NM stops this insanity with poking at all network interfaces. No wonder that people just end up removing it. First it tries to poke nl80211 and then complaints why modules are auto-loaded even without WiFi cards present and now it tries to poke at WEXT for non-WiFi interfaces.

I can't say that I'm a NetworkManager fan myself... well, at least it's helping to make the kernel more robust in this case, I suppose. :(

Quoted 32 lines
Quoted 18 lines

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
       int ret = wext_permission_check(cmd);

       if (ret)
               return ret;

       dev_load(net, ifr->ifr_name);
       rtnl_lock();
       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
       rtnl_unlock();

       return ret;
}
Quoted 7 lines

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

I think the ioctl handler should just first check which are its valid ioctl and also enforce permission in that run without the RTNL lock held. Return -EINVAL or -ENOIOCTLCMD when it gets a cmd that this function does not handle. And then have the function actually take the RTNL lock and process its two ioctl that it supports.

Quoted 6 lines
Quoted 2 lines

That way we should avoid the nasty with taking the RTNL lock for unsupported ioctl.

Something like the below? (Alexander?) (I verified that it fixes the problem for me.)

I can suggest also other solutions which are:

- Remove the ndo_do_ioctl callback? If somebody wants to set address things, they should use netlink. There is also some warn notice in the callback "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n", which reports the user that he is not doing the right thing when setting addresses via ioctl. That's very trustful.

I know currently there is some function "mac802154_wpan_update_llsec" which makes the security layer to work, because it's not called when setting short/panid anywhere else. I would be happy if we can "deactivate" the security layer -> removing old netlink interface and then try to making an easy to use interface over nl802154 to access the mib security entries. (I have started somewhere, but this is also another thread to talk about access security attributes over nl802154.

- Hold the rtnl lock only when the socket code is called. I insert this code because somebody tried to ioctl a 802.15.4 socket and the lock wasn't held. Maybe we can hold the rtnl lock in the caller, see [0]. But this requires that all other callers hold the rtnl lock while calling this callback and I don't know if this is true.

Nevertheless your solutions will reduce to hold the rtnl_lock if not necessary and fixes the nm issue. So you get a:

If you see that to remove the ioctl it's a good idea (okay that's maybe not a good idea because there are at least one user outside which use this feature) you can send a patch for it.

Quoted 6 lines

As to adding permission checks to the 802.15.4 subsystem, that's a whole 'nother undertaking -- for one, I can currently snoop on any 802.15.4 traffic going through the box (including 6LoWPAN traffic) as an unprivileged user, which is somewhat crazy -- but that's probably something for another email (thread).

oh.

Quoted 35 lines
Quoted 4 lines

And hopefully at some point we can actually remove WEXT from the kernel. That it creates this nasty mess for other protocols is just insane.

I totally agree that the rtnl lock being held or not being held upon entering an ndo ioctl depending on what the ioctl cmd is is very bad, as this is just conditional locking which is bad in itself because of multiple reasons, and WEXT should be taken out and shot for causing this situation to be able to arise in the first place.

commit f5f4876bee64af07f6733d6bdb87ecb7e6fac85d

Author: Lennert Buytenhek <[email protected]>
Date:   Tue May 26 08:53:33 2015 +0300

mac802154: Avoid rtnl deadlock in mac802154_wpan_ioctl().

->ndo_do_ioctl() can be entered with the rtnl lock already held, for example when sending a wext ioctl to a device (in which case the rtnl lock is taken by wext_ioctl_dispatch()), but mac802154_wpan_ioctl() currently unconditionally takes the rtnl lock on entry, which can cause deadlocks.

To fix this, bail out of mac802154_wpan_ioctl() before taking the rtnl lock if the ioctl cmd is not one of the cmds we implement.

net/mac802154/iface.c +0 -0
index f30788d..b544b5d 100644

net/mac802154/iface.c mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) · line 70

Quoted 9 lines
net/mac802154/iface.c +3 -0
@@ -62,6 +62,9 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
+	if (cmd != SIOCGIFADDR && cmd != SIOCSIFADDR)
+		return err;
+
 	rtnl_lock();
 
 	switch (cmd) {

- Alex

[0] http://lxr.free-electrons.com/source/net/ieee802154/socket.c#L152

author maintainer
#6 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Quoted 128 lines · Alexander Aring

Hi,

Quoted 101 lines · Lennert Buytenhek
Quoted 1 line · Marcel Holtmann

Hi Lennert,

Hi Marcel,

Quoted 52 lines
Quoted 44 lines
Quoted 35 lines

This patch fixes an issue to set address configuration with ioctl. Accessing the mib requires rtnl lock and the ndo_do_ioctl doesn't hold the rtnl lock while this callback is called. This patch do that manually.

---
net/mac802154/iface.c | 5 +++--

1 file changed, 3 insertions(+), 2 deletions(-)
net/mac802154/iface.c +2 -2
index 91b75ab..2a58788 100644
@@ -62,8 +62,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
 	int err = -ENOIOCTLCMD;
 
-	ASSERT_RTNL();
-
+	rtnl_lock();
 	spin_lock_bh(&sdata->mib_lock);
 
 	switch (cmd) {
@@ -90,6 +89,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	case SIOCSIFADDR:
 		if (netif_running(dev)) {
 			spin_unlock_bh(&sdata->mib_lock);
+			rtnl_unlock();
 			return -EBUSY;
 		}
 

net/mac802154/iface.c mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) · line 117

Quoted 6 lines
net/mac802154/iface.c +1 -0
@@ -112,6 +112,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	}
 
 	spin_unlock_bh(&sdata->mib_lock);
+	rtnl_unlock();
 	return err;
 }

This patch is causing rtnl recursion and deadlocks on my system.

Quoted 7 lines

A daemon running on my system (NetworkManager) tries calling various wext ioctls on newly registered network interfaces, including 802.15.4 interfaces, which are dispatched from dev_ioctl() in net/core/dev_ioctl.c via wext_handle_ioctl() in net/wireless/wext-core.c to wireless_process_ioctl() to ioctl_standard_call() to ioctl_standard_iw_point() to mac802154_wpan_ioctl(), and wext_ioctl_dispatch() does:

Quoted 5 lines

I would really wish that NM stops this insanity with poking at all network interfaces. No wonder that people just end up removing it. First it tries to poke nl80211 and then complaints why modules are auto-loaded even without WiFi cards present and now it tries to poke at WEXT for non-WiFi interfaces.

I can't say that I'm a NetworkManager fan myself... well, at least it's helping to make the kernel more robust in this case, I suppose. :(

Quoted 32 lines
Quoted 18 lines

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
       int ret = wext_permission_check(cmd);

       if (ret)
               return ret;

       dev_load(net, ifr->ifr_name);
       rtnl_lock();
       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
       rtnl_unlock();

       return ret;
}
Quoted 7 lines

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

I think the ioctl handler should just first check which are its valid ioctl and also enforce permission in that run without the RTNL lock held. Return -EINVAL or -ENOIOCTLCMD when it gets a cmd that this function does not handle. And then have the function actually take the RTNL lock and process its two ioctl that it supports.

Quoted 6 lines
Quoted 2 lines

That way we should avoid the nasty with taking the RTNL lock for unsupported ioctl.

Something like the below? (Alexander?) (I verified that it fixes the problem for me.)

I can suggest also other solutions which are:

- Remove the ndo_do_ioctl callback? If somebody wants to set address things, they should use netlink. There is also some warn notice in the callback "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n", which reports the user that he is not doing the right thing when setting addresses via ioctl. That's very trustful.

I know currently there is some function "mac802154_wpan_update_llsec" which makes the security layer to work, because it's not called when setting short/panid anywhere else. I would be happy if we can "deactivate" the security layer -> removing old netlink interface and then try to making an easy to use interface over nl802154 to access the mib security entries. (I have started somewhere, but this is also another thread to talk about access security attributes over nl802154.

Quoted 3 lines

- Hold the rtnl lock only when the socket code is called. I insert this code because somebody tried to ioctl a 802.15.4 socket and the lock wasn't held. Maybe we can hold the rtnl lock in the caller, see [0].

besides I don't know why they use a check on ARPHRD there, a 802.15.4 socket can also be created on wpan intefaces only, which should be checked at creating the socket or somewhere.

A general question and sorry for this unknowledge is that: is it normal than a socket ioctl will call the netdev ioctl?

- Alex

#7 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Quoted 56 lines · Alexander Aring
Quoted 56 lines
Quoted 32 lines
Quoted 32 lines
Quoted 18 lines

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
       int ret = wext_permission_check(cmd);

       if (ret)
               return ret;

       dev_load(net, ifr->ifr_name);
       rtnl_lock();
       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
       rtnl_unlock();

       return ret;
}
Quoted 7 lines

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

I think the ioctl handler should just first check which are its valid ioctl and also enforce permission in that run without the RTNL lock held. Return -EINVAL or -ENOIOCTLCMD when it gets a cmd that this function does not handle. And then have the function actually take the RTNL lock and process its two ioctl that it supports.

Quoted 6 lines
Quoted 2 lines

That way we should avoid the nasty with taking the RTNL lock for unsupported ioctl.

Something like the below? (Alexander?) (I verified that it fixes the problem for me.)

I can suggest also other solutions which are:

- Remove the ndo_do_ioctl callback? If somebody wants to set address things, they should use netlink. There is also some warn notice in the callback "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n", which reports the user that he is not doing the right thing when setting addresses via ioctl. That's very trustful.

I know currently there is some function "mac802154_wpan_update_llsec" which makes the security layer to work, because it's not called when setting short/panid anywhere else. I would be happy if we can "deactivate" the security layer -> removing old netlink interface and then try to making an easy to use interface over nl802154 to access the mib security entries. (I have started somewhere, but this is also another thread to talk about access security attributes over nl802154.

Quoted 7 lines
Quoted 3 lines

- Hold the rtnl lock only when the socket code is called. I insert this code because somebody tried to ioctl a 802.15.4 socket and the lock wasn't held. Maybe we can hold the rtnl lock in the caller, see [0].

besides I don't know why they use a check on ARPHRD there, a 802.15.4 socket can also be created on wpan intefaces only, which should be checked at creating the socket or somewhere.

If you're talking about this code in net/ieee802154/socket.c:

===
static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
unsigned int cmd)

{
        struct ifreq ifr;
        int ret = -ENOIOCTLCMD;
        struct net_device *dev;

        if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
                return -EFAULT;

        ifr.ifr_name[IFNAMSIZ-1] = 0;

        dev_load(sock_net(sk), ifr.ifr_name);
        dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);

        if (!dev)
                return -ENODEV;

        if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
                ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);

        if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
                ret = -EFAULT;
        dev_put(dev);

        return ret;
}

static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)

{
        struct sock *sk = sock->sk;

        switch (cmd) {
        case SIOCGSTAMP:
                return sock_get_timestamp(sk, (struct timeval __user *)arg);
        case SIOCGSTAMPNS:
                return sock_get_timestampns(sk, (struct timespec __user *)arg);
        case SIOCGIFADDR:
        case SIOCSIFADDR:
                return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
                                cmd);
        default:
                if (!sk->sk_prot->ioctl)
                        return -ENOIOCTLCMD;
                return sk->sk_prot->ioctl(sk, cmd, arg);
        }
}

===

The network namespace is taken from the 802.15.4 socket, but the device name is taken from the struct ifreq that's passed in, which does not necessarily refer to a 802.15.4 device.

Quoted 2 lines

A general question and sorry for this unknowledge is that: is it normal than a socket ioctl will call the netdev ioctl?

netdevice(7) has a note about this. I think it's probably just because of historical reasons, because there is no 'dedicated' way of calling a netdev ioctl other than going through the socket (which, historically, means PF_INET) layer. Not very clean at all, but this is unlikely to ever change at this point. :-/

author maintainer
#8 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Quoted 117 lines · Lennert Buytenhek
Quoted 56 lines · Alexander Aring
Quoted 56 lines
Quoted 32 lines
Quoted 32 lines
Quoted 18 lines

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
       int ret = wext_permission_check(cmd);

       if (ret)
               return ret;

       dev_load(net, ifr->ifr_name);
       rtnl_lock();
       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
       rtnl_unlock();

       return ret;
}
Quoted 7 lines

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

I think the ioctl handler should just first check which are its valid ioctl and also enforce permission in that run without the RTNL lock held. Return -EINVAL or -ENOIOCTLCMD when it gets a cmd that this function does not handle. And then have the function actually take the RTNL lock and process its two ioctl that it supports.

Quoted 6 lines
Quoted 2 lines

That way we should avoid the nasty with taking the RTNL lock for unsupported ioctl.

Something like the below? (Alexander?) (I verified that it fixes the problem for me.)

I can suggest also other solutions which are:

- Remove the ndo_do_ioctl callback? If somebody wants to set address things, they should use netlink. There is also some warn notice in the callback "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n", which reports the user that he is not doing the right thing when setting addresses via ioctl. That's very trustful.

I know currently there is some function "mac802154_wpan_update_llsec" which makes the security layer to work, because it's not called when setting short/panid anywhere else. I would be happy if we can "deactivate" the security layer -> removing old netlink interface and then try to making an easy to use interface over nl802154 to access the mib security entries. (I have started somewhere, but this is also another thread to talk about access security attributes over nl802154.

Quoted 7 lines
Quoted 3 lines

- Hold the rtnl lock only when the socket code is called. I insert this code because somebody tried to ioctl a 802.15.4 socket and the lock wasn't held. Maybe we can hold the rtnl lock in the caller, see [0].

besides I don't know why they use a check on ARPHRD there, a 802.15.4 socket can also be created on wpan intefaces only, which should be checked at creating the socket or somewhere.

If you're talking about this code in net/ieee802154/socket.c:

===
static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
unsigned int cmd)

{
        struct ifreq ifr;
        int ret = -ENOIOCTLCMD;
        struct net_device *dev;

        if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
                return -EFAULT;

        ifr.ifr_name[IFNAMSIZ-1] = 0;

        dev_load(sock_net(sk), ifr.ifr_name);
        dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);

        if (!dev)
                return -ENODEV;

        if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
                ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);

        if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
                ret = -EFAULT;
        dev_put(dev);

        return ret;
}

static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)

{
        struct sock *sk = sock->sk;

        switch (cmd) {
        case SIOCGSTAMP:
                return sock_get_timestamp(sk, (struct timeval __user *)arg);
        case SIOCGSTAMPNS:
                return sock_get_timestampns(sk, (struct timespec __user *)arg);
        case SIOCGIFADDR:
        case SIOCSIFADDR:
                return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
                                cmd);
        default:
                if (!sk->sk_prot->ioctl)
                        return -ENOIOCTLCMD;
                return sk->sk_prot->ioctl(sk, cmd, arg);
        }
}
Quoted 6 lines

===

The network namespace is taken from the 802.15.4 socket, but the device name is taken from the struct ifreq that's passed in, which does not necessarily refer to a 802.15.4 device.

I see, okay.

Quoted 9 lines
Quoted 3 lines

A general question and sorry for this unknowledge is that: is it normal than a socket ioctl will call the netdev ioctl?

netdevice(7) has a note about this. I think it's probably just because of historical reasons, because there is no 'dedicated' way of calling a netdev ioctl other than going through the socket (which, historically, means PF_INET) layer. Not very clean at all, but this is unlikely to ever change at this point. :-/

ok.

- Alex

#9 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

In reply to Alexander Aring
Quoted 1 line · Alexander Aring

Hi,

Hello!

Quoted 45 lines
Quoted 32 lines
Quoted 32 lines
Quoted 18 lines

static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
unsigned int cmd, struct iw_request_info *info, wext_ioctl_func standard, wext_ioctl_func private)

{
       int ret = wext_permission_check(cmd);

       if (ret)
               return ret;

       dev_load(net, ifr->ifr_name);
       rtnl_lock();
       ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
       rtnl_unlock();

       return ret;
}
Quoted 7 lines

leading to a double rtnl lock in mac802154_wpan_ioctl().

The easy fix would be to have mac802154_wpan_ioctl() check the ioctl cmd before taking the rtnl -- I'm not too happy about the rtnl being held or not held upon entry to a device ioctl depending on the ioctl cmd and/or on who the caller is, but we might not be easily able to change this...

I think the ioctl handler should just first check which are its valid ioctl and also enforce permission in that run without the RTNL lock held. Return -EINVAL or -ENOIOCTLCMD when it gets a cmd that this function does not handle. And then have the function actually take the RTNL lock and process its two ioctl that it supports.

Quoted 5 lines
Quoted 2 lines

That way we should avoid the nasty with taking the RTNL lock for unsupported ioctl.

Something like the below? (Alexander?) (I verified that it fixes the problem for me.)

I can suggest also other solutions which are:

- Remove the ndo_do_ioctl callback? If somebody wants to set address things, they should use netlink. There is also some warn notice in the callback "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n", which reports the user that he is not doing the right thing when setting addresses via ioctl. That's very trustful.

[...]

Quoted 8 lines

I know currently there is some function "mac802154_wpan_update_llsec" which makes the security layer to work, because it's not called when setting short/panid anywhere else. I would be happy if we can "deactivate" the security layer -> removing old netlink interface and then try to making an easy to use interface over nl802154 to access the mib security entries. (I have started somewhere, but this is also another thread to talk about access security attributes over nl802154.

I haven't looked at this particular aspect too closely, so I'm not really able to comment on this right now.

Quoted 5 lines

- Hold the rtnl lock only when the socket code is called. I insert this code because somebody tried to ioctl a 802.15.4 socket and the lock wasn't held. Maybe we can hold the rtnl lock in the caller, see [0]. But this requires that all other callers hold the rtnl lock while calling this callback and I don't know if this is true.

I think that it makes sense to keep the invariant that upon entry of an ioctl, no locks are guaranteed to be held. WEXT violates this principle, but I would say that the WEXT behavior is undesirable, as it's not a good thing to take a bunch of locks just in case a callee might need them, and it will cause code to be written that will (silently) depend on these assumptions and it will be hard to untangle those dependencies later on, or even impossible to do in case it becomes part of an API/ABI (like it is now in the WEXT case).

Quoted 4 lines

Nevertheless your solutions will reduce to hold the rtnl_lock if not necessary and fixes the nm issue. So you get a:

Cool, I'll do this and submit it.

Quoted 3 lines

If you see that to remove the ioctl it's a good idea (okay that's maybe not a good idea because there are at least one user outside which use this feature) you can send a patch for it.

I agree that this ioctl is an ugly wart, and that it should probably be scheduled to be removed entirely. Do you have visibility into what userspace code might be using this -- I know that there's a zigbee stack, but I don't think we can see it?

author maintainer
#10 lore raw

Re: [PATCHv2 bluetooth-next 1/4] mac802154: fix hold rtnl while ioctl

Quoted 6 lines · Lennert Buytenhek
Quoted 5 lines

- Hold the rtnl lock only when the socket code is called. I insert this code because somebody tried to ioctl a 802.15.4 socket and the lock wasn't held. Maybe we can hold the rtnl lock in the caller, see [0]. But this requires that all other callers hold the rtnl lock while calling this callback and I don't know if this is true.

Quoted 9 lines

I think that it makes sense to keep the invariant that upon entry of an ioctl, no locks are guaranteed to be held. WEXT violates this principle, but I would say that the WEXT behavior is undesirable, as it's not a good thing to take a bunch of locks just in case a callee might need them, and it will cause code to be written that will (silently) depend on these assumptions and it will be hard to untangle those dependencies later on, or even impossible to do in case it becomes part of an API/ABI (like it is now in the WEXT case).

ok.

Quoted 8 lines
Quoted 5 lines

Nevertheless your solutions will reduce to hold the rtnl_lock if not necessary and fixes the nm issue. So you get a:

Cool, I'll do this and submit it.

ok.

Quoted 9 lines
Quoted 4 lines

If you see that to remove the ioctl it's a good idea (okay that's maybe not a good idea because there are at least one user outside which use this feature) you can send a patch for it.

I agree that this ioctl is an ugly wart, and that it should probably be scheduled to be removed entirely. Do you have visibility into what userspace code might be using this -- I know that there's a zigbee stack, but I don't think we can see it?

no, I don't know any _real_ software which using this ioctl. There was maybe a zigbee stack which wasn't released open source but I did not work on this stuff. I think, the previous maintainers just implement the way what they need for his userspace stuff, but I never saw any code about that.

Don't know if this is still active in development.

I know the following code which using this code:

- deprecated lowpan-tools has some unit tests to access this ioctl.

- the secuirty layer stuff. But this isn't supported by any official userspace software currently. There is some outside at [0]. But I would prefer to adding support for nl802154 and wpan-tools in some way which is very easy to setup.

- The person which reported the issue with rtnl lock. [1]

- Alex

[0] https://github.com/mysmartgrid/hexabus/tree/pb-crypto
[1] http://www.spinics.net/lists/linux-wpan/msg01893.html

author maintainer
#11 lore raw

PATCH v2 2/4 mac802154: remove pib lock

In reply to Alexander Aring

This patch removes the pib lock which is now replaced by rtnl lock. The new interface already use the rtnl lock only. Nevertheless this patch will fix issues while using new and old interface at the same time.

---
 include/net/cfg802154.h | 2 --
 net/ieee802154/core.c   | 2 --
 net/ieee802154/nl-phy.c | 6 +++---
 net/mac802154/iface.c   | 7 -------
 net/mac802154/mib.c     | 4 ++--
 5 files changed, 5 insertions(+), 16 deletions(-)
include/net/cfg802154.h +0 -2
index 11bbf17..c6aa1d2 100644
@@ -121,8 +121,6 @@ enum wpan_phy_flags {
 };
 
 struct wpan_phy {
-	struct mutex pib_lock;
-
 	/* If multiple wpan_phys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee802154_ptr, you won't
 	 * know whether it points to a wpan_phy your driver has registered
net/ieee802154/core.c +0 -2
index 2ee00e8..b0248e9 100644
@@ -121,8 +121,6 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size)
 	/* atomic_inc_return makes it start at 1, make it start at 0 */
 	rdev->wpan_phy_idx--;
 
-	mutex_init(&rdev->wpan_phy.pib_lock);
-
 	INIT_LIST_HEAD(&rdev->wpan_dev_list);
 	device_initialize(&rdev->wpan_phy.dev);
 	dev_set_name(&rdev->wpan_phy.dev, PHY_NAME "%d", rdev->wpan_phy_idx);
net/ieee802154/nl-phy.c +3 -3
index cbc0d09..77d7301 100644
@@ -50,7 +50,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
 	if (!hdr)
 		goto out;
 
-	mutex_lock(&phy->pib_lock);
+	rtnl_lock();
 	if (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))
@@ -63,13 +63,13 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
 	    nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
 		    pages * sizeof(uint32_t), buf))
 		goto nla_put_failure;
-	mutex_unlock(&phy->pib_lock);
+	rtnl_unlock();
 	kfree(buf);
 	genlmsg_end(msg, hdr);
 	return 0;
 
 nla_put_failure:
-	mutex_unlock(&phy->pib_lock);
+	rtnl_unlock();
 	genlmsg_cancel(msg, hdr);
 out:
 	kfree(buf);
net/mac802154/iface.c +0 -7
index 2a58788..22f478b 100644
@@ -242,7 +242,6 @@ static int mac802154_wpan_open(struct net_device *dev)
 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 	struct ieee802154_local *local = sdata->local;
 	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
-	struct wpan_phy *phy = sdata->local->phy;
 
 	rc = ieee802154_check_concurrent_iface(sdata, sdata->vif.type);
 	if (rc < 0)
@@ -252,8 +251,6 @@ static int mac802154_wpan_open(struct net_device *dev)
 	if (rc < 0)
 		return rc;
 
-	mutex_lock(&phy->pib_lock);
-
 	if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
 		rc = drv_set_promiscuous_mode(local,
 					      wpan_dev->promiscuous_mode);
@@ -295,11 +292,7 @@ static int mac802154_wpan_open(struct net_device *dev)
 			goto out;
 	}
 
-	mutex_unlock(&phy->pib_lock);
-	return 0;
-
 out:
-	mutex_unlock(&phy->pib_lock);
 	return rc;
 }
 
net/mac802154/mib.c +2 -2
index 5cf019a..033dfc7 100644
@@ -91,16 +91,16 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
 	struct ieee802154_local *local = sdata->local;
 	int res;
 
+	ASSERT_RTNL();
+
 	BUG_ON(dev->type != ARPHRD_IEEE802154);
 
 	res = drv_set_channel(local, page, chan);
 	if (res) {
 		pr_debug("set_channel failed\n");
 	} else {
-		mutex_lock(&local->phy->pib_lock);
 		local->phy->current_channel = chan;
 		local->phy->current_page = page;
-		mutex_unlock(&local->phy->pib_lock);
 	}
 }
 
Signature · 1 line
2.4.1
author maintainer
#12 lore raw

PATCH v2 3/4 mac802154: use atomic ops for sequence incrementation

In reply to Alexander Aring

This patch will use atomic operations for sequence number incrementation while MAC header generation. Upper layers like af_802154 or 6LoWPAN could call this function in a parallel context while generating 802.15.4 MAC header before queuing into wpan interfaces transmit queue.

---
 include/net/cfg802154.h         | 4 ++--
 include/net/ieee802154_netdev.h | 1 -
 net/ieee802154/6lowpan/core.c   | 8 --------
 net/mac802154/ieee802154_i.h    | 1 -
 net/mac802154/iface.c           | 9 ++++++---
 net/mac802154/mac_cmd.c         | 1 -
 net/mac802154/mib.c             | 9 ---------
 7 files changed, 8 insertions(+), 25 deletions(-)
include/net/cfg802154.h +2 -2
index c6aa1d2..4de59aa 100644
@@ -177,9 +177,9 @@ struct wpan_dev {
 	__le64 extended_addr;
 
 	/* MAC BSN field */
-	u8 bsn;
+	atomic_t bsn;
 	/* MAC DSN field */
-	u8 dsn;
+	atomic_t dsn;
 
 	u8 min_be;
 	u8 max_be;
include/net/ieee802154_netdev.h +0 -1
index 94a2970..144fefb 100644
@@ -431,7 +431,6 @@ struct ieee802154_mlme_ops {
 	 */
 	__le16 (*get_pan_id)(const struct net_device *dev);
 	__le16 (*get_short_addr)(const struct net_device *dev);
-	u8 (*get_dsn)(const struct net_device *dev);
 };
 
 static inline struct ieee802154_mlme_ops *
net/ieee802154/6lowpan/core.c +0 -8
index 0ae5822..2e77fad 100644
@@ -69,13 +69,6 @@ static __le16 lowpan_get_short_addr(const struct net_device *dev)
 	return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
 }
 
-static u8 lowpan_get_dsn(const struct net_device *dev)
-{
-	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
-
-	return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev);
-}
-
 static struct header_ops lowpan_header_ops = {
 	.create	= lowpan_header_create,
 };
@@ -106,7 +99,6 @@ static const struct net_device_ops lowpan_netdev_ops = {
 static struct ieee802154_mlme_ops lowpan_mlme = {
 	.get_pan_id = lowpan_get_pan_id,
 	.get_short_addr = lowpan_get_short_addr,
-	.get_dsn = lowpan_get_dsn,
 };
 
 static void lowpan_setup(struct net_device *dev)
net/mac802154/ieee802154_i.h +0 -1
index 127ba18..56b3847 100644
@@ -141,7 +141,6 @@ __le16 mac802154_dev_get_short_addr(const struct net_device *dev);
 __le16 mac802154_dev_get_pan_id(const struct net_device *dev);
 void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
-u8 mac802154_dev_get_dsn(const struct net_device *dev);
 
 int mac802154_get_params(struct net_device *dev,
 			 struct ieee802154_llsec_params *params);
net/mac802154/iface.c +6 -3
index 22f478b..0ec7bc4 100644
@@ -368,7 +368,7 @@ static int mac802154_header_create(struct sk_buff *skb,
 	hdr.fc.type = cb->type;
 	hdr.fc.security_enabled = cb->secen;
 	hdr.fc.ack_request = cb->ackreq;
-	hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+	hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
 
 	if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
 		return -EINVAL;
@@ -468,13 +468,16 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
 		       enum nl802154_iftype type)
 {
 	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+	u8 tmp;
 
 	/* set some type-dependent values */
 	sdata->vif.type = type;
 	sdata->wpan_dev.iftype = type;
 
-	get_random_bytes(&wpan_dev->bsn, 1);
-	get_random_bytes(&wpan_dev->dsn, 1);
+	get_random_bytes(&tmp, sizeof(tmp));
+	atomic_set(&wpan_dev->bsn, tmp);
+	get_random_bytes(&tmp, sizeof(tmp));
+	atomic_set(&wpan_dev->dsn, tmp);
 
 	/* defaults per 802.15.4-2011 */
 	wpan_dev->min_be = 3;
net/mac802154/mac_cmd.c +0 -1
index 6dcbb3b..3b347d4 100644
@@ -153,7 +153,6 @@ struct ieee802154_mlme_ops mac802154_mlme_wpan = {
 	.start_req = mac802154_mlme_start_req,
 	.get_pan_id = mac802154_dev_get_pan_id,
 	.get_short_addr = mac802154_dev_get_short_addr,
-	.get_dsn = mac802154_dev_get_dsn,
 
 	.llsec = &mac802154_llsec_ops,
 
net/mac802154/mib.c +0 -9
index 033dfc7..00a62de 100644
@@ -76,15 +76,6 @@ void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val)
 	spin_unlock_bh(&sdata->mib_lock);
 }
 
-u8 mac802154_dev_get_dsn(const struct net_device *dev)
-{
-	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
-
-	BUG_ON(dev->type != ARPHRD_IEEE802154);
-
-	return sdata->wpan_dev.dsn++;
-}
-
 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
 {
 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
Signature · 1 line
2.4.1
author maintainer
#13 lore raw

PATCH v2 4/4 mac802154: remove mib lock

In reply to Alexander Aring

This patch removes the mib lock. The new locking mechanism is to protect the mib values with the rtnl lock. Note that this isn't always necessary if we have an interface up the most mib values are readonly (e.g. address settings). With this behaviour we can remove locking in hotpath like frame parsing completely. It depends on context if we need to hold the rtnl lock or not, this makes the callbacks of ieee802154_mlme_ops unnecessary because these callbacks hols always the locks.

---
 include/net/ieee802154_netdev.h |  9 --------
 net/ieee802154/6lowpan/core.c   | 20 -----------------
 net/ieee802154/6lowpan/tx.c     |  2 +-
 net/ieee802154/nl-mac.c         | 14 ++++++++----
 net/ieee802154/socket.c         | 12 +++++-----
 net/mac802154/ieee802154_i.h    |  6 -----
 net/mac802154/iface.c           |  8 -------
 net/mac802154/mac_cmd.c         |  6 ++---
 net/mac802154/mib.c             | 50 -----------------------------------------
 net/mac802154/rx.c              |  5 -----
 10 files changed, 18 insertions(+), 114 deletions(-)
include/net/ieee802154_netdev.h +0 -9
index 144fefb..84a72a1 100644
@@ -422,15 +422,6 @@ struct ieee802154_mlme_ops {
 			       struct ieee802154_mac_params *params);
 
 	struct ieee802154_llsec_ops *llsec;
-
-	/* The fields below are required. */
-
-	/*
-	 * FIXME: these should become the part of PIB/MIB interface.
-	 * However we still don't have IB interface of any kind
-	 */
-	__le16 (*get_pan_id)(const struct net_device *dev);
-	__le16 (*get_short_addr)(const struct net_device *dev);
 };
 
 static inline struct ieee802154_mlme_ops *
net/ieee802154/6lowpan/core.c +0 -20
index 2e77fad..f20a387 100644
@@ -55,20 +55,6 @@
 LIST_HEAD(lowpan_devices);
 static int lowpan_open_count;
 
-static __le16 lowpan_get_pan_id(const struct net_device *dev)
-{
-	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
-
-	return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev);
-}
-
-static __le16 lowpan_get_short_addr(const struct net_device *dev)
-{
-	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
-
-	return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
-}
-
 static struct header_ops lowpan_header_ops = {
 	.create	= lowpan_header_create,
 };
@@ -96,11 +82,6 @@ static const struct net_device_ops lowpan_netdev_ops = {
 	.ndo_start_xmit		= lowpan_xmit,
 };
 
-static struct ieee802154_mlme_ops lowpan_mlme = {
-	.get_pan_id = lowpan_get_pan_id,
-	.get_short_addr = lowpan_get_short_addr,
-};
-
 static void lowpan_setup(struct net_device *dev)
 {
 	dev->addr_len		= IEEE802154_ADDR_LEN;
@@ -116,7 +97,6 @@ static void lowpan_setup(struct net_device *dev)
 
 	dev->netdev_ops		= &lowpan_netdev_ops;
 	dev->header_ops		= &lowpan_header_ops;
-	dev->ml_priv		= &lowpan_mlme;
 	dev->destructor		= free_netdev;
 	dev->features		|= NETIF_F_NETNS_LOCAL;
 }
net/ieee802154/6lowpan/tx.c +1 -1
index 2349070..98acf73 100644
@@ -207,7 +207,7 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *dev)
 
 	/* prepare wpan address data */
 	sa.mode = IEEE802154_ADDR_LONG;
-	sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+	sa.pan_id = lowpan_dev_info(dev)->real_dev->ieee802154_ptr->pan_id;
 	sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
 
 	/* intra-PAN communications */
net/ieee802154/nl-mac.c +10 -4
index cdc1cc3..ada58a8 100644
@@ -97,8 +97,10 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
 	BUG_ON(!phy);
 	get_device(&phy->dev);
 
-	short_addr = ops->get_short_addr(dev);
-	pan_id = ops->get_pan_id(dev);
+	rtnl_lock();
+	short_addr = dev->ieee802154_ptr->short_addr;
+	pan_id = dev->ieee802154_ptr->pan_id;
+	rtnl_unlock();
 
 	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
 	    nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
@@ -244,7 +246,9 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
 	addr.mode = IEEE802154_ADDR_LONG;
 	addr.extended_addr = nla_get_hwaddr(
 			info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
-	addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+	rtnl_lock();
+	addr.pan_id = dev->ieee802154_ptr->pan_id;
+	rtnl_unlock();
 
 	ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
 		nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
@@ -281,7 +285,9 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
 		addr.short_addr = nla_get_shortaddr(
 				info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
 	}
-	addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+	rtnl_lock();
+	addr.pan_id = dev->ieee802154_ptr->pan_id;
+	rtnl_unlock();
 
 	ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
 			nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
net/ieee802154/socket.c +5 -7
index 7aaaf96..e5cc253 100644
@@ -64,10 +64,8 @@ ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
 			if (tmp->type != ARPHRD_IEEE802154)
 				continue;
 
-			pan_id = ieee802154_mlme_ops(tmp)->get_pan_id(tmp);
-			short_addr =
-				ieee802154_mlme_ops(tmp)->get_short_addr(tmp);
-
+			pan_id = tmp->ieee802154_ptr->pan_id;
+			short_addr = tmp->ieee802154_ptr->short_addr;
 			if (pan_id == addr->pan_id &&
 			    short_addr == addr->short_addr) {
 				dev = tmp;
@@ -797,9 +795,9 @@ static int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
 	/* Data frame processing */
 	BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-	pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
-	short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
-	hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
+	pan_id = dev->ieee802154_ptr->pan_id;
+	short_addr = dev->ieee802154_ptr->short_addr;
+	hw_addr = dev->ieee802154_ptr->extended_addr;
 
 	read_lock(&dgram_lock);
 	sk_for_each(sk, &dgram_head) {
net/mac802154/ieee802154_i.h +0 -6
index 56b3847..eec668f 100644
@@ -86,8 +86,6 @@ struct ieee802154_sub_if_data {
 	unsigned long state;
 	char name[IFNAMSIZ];
 
-	spinlock_t mib_lock;
-
 	/* protects sec from concurrent access by netlink. access by
 	 * encrypt/decrypt/header_create safe without additional protection.
 	 */
@@ -136,10 +134,6 @@ ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 enum hrtimer_restart ieee802154_xmit_ifs_timer(struct hrtimer *timer);
 
 /* MIB callbacks */
-void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
-__le16 mac802154_dev_get_short_addr(const struct net_device *dev);
-__le16 mac802154_dev_get_pan_id(const struct net_device *dev);
-void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
 
 int mac802154_get_params(struct net_device *dev,
net/mac802154/iface.c +0 -8
index 0ec7bc4..f30788d 100644
@@ -63,7 +63,6 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	int err = -ENOIOCTLCMD;
 
 	rtnl_lock();
-	spin_lock_bh(&sdata->mib_lock);
 
 	switch (cmd) {
 	case SIOCGIFADDR:
@@ -88,7 +87,6 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	}
 	case SIOCSIFADDR:
 		if (netif_running(dev)) {
-			spin_unlock_bh(&sdata->mib_lock);
 			rtnl_unlock();
 			return -EBUSY;
 		}
@@ -111,7 +109,6 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		break;
 	}
 
-	spin_unlock_bh(&sdata->mib_lock);
 	rtnl_unlock();
 	return err;
 }
@@ -374,8 +371,6 @@ static int mac802154_header_create(struct sk_buff *skb,
 		return -EINVAL;
 
 	if (!saddr) {
-		spin_lock_bh(&sdata->mib_lock);
-
 		if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
 		    wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
 		    wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
@@ -387,8 +382,6 @@ static int mac802154_header_create(struct sk_buff *skb,
 		}
 
 		hdr.source.pan_id = wpan_dev->pan_id;
-
-		spin_unlock_bh(&sdata->mib_lock);
 	} else {
 		hdr.source = *(const struct ieee802154_addr *)saddr;
 	}
@@ -500,7 +493,6 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
 		sdata->dev->ml_priv = &mac802154_mlme_wpan;
 		wpan_dev->promiscuous_mode = false;
 
-		spin_lock_init(&sdata->mib_lock);
 		mutex_init(&sdata->sec_mtx);
 
 		mac802154_llsec_init(&sdata->sec);
net/mac802154/mac_cmd.c +2 -4
index 3b347d4..5220c2b2 100644
@@ -43,8 +43,8 @@ static int mac802154_mlme_start_req(struct net_device *dev,
 
 	BUG_ON(addr->mode != IEEE802154_ADDR_SHORT);
 
-	mac802154_dev_set_pan_id(dev, addr->pan_id);
-	mac802154_dev_set_short_addr(dev, addr->short_addr);
+	dev->ieee802154_ptr->pan_id = addr->pan_id;
+	dev->ieee802154_ptr->short_addr = addr->short_addr;
 	mac802154_dev_set_page_channel(dev, page, channel);
 
 	if (ops->llsec) {
@@ -151,8 +151,6 @@ static struct ieee802154_llsec_ops mac802154_llsec_ops = {
 
 struct ieee802154_mlme_ops mac802154_mlme_wpan = {
 	.start_req = mac802154_mlme_start_req,
-	.get_pan_id = mac802154_dev_get_pan_id,
-	.get_short_addr = mac802154_dev_get_short_addr,
 
 	.llsec = &mac802154_llsec_ops,
 
net/mac802154/mib.c +0 -50

56 lines not on this page · raw message

net/mac802154/rx.c +0 -5
index c0d67b2..e0f1006 100644
@@ -47,8 +47,6 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
 
 	pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
 
-	spin_lock_bh(&sdata->mib_lock);
-
 	span = wpan_dev->pan_id;
 	sshort = wpan_dev->short_addr;
 
@@ -83,13 +81,10 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
 			skb->pkt_type = PACKET_OTHERHOST;
 		break;
 	default:
-		spin_unlock_bh(&sdata->mib_lock);
 		pr_debug("invalid dest mode\n");
 		goto fail;
 	}
 
-	spin_unlock_bh(&sdata->mib_lock);
-
 	skb->dev = sdata->dev;
 
 	rc = mac802154_llsec_decrypt(&sdata->sec, skb);
Signature · 1 line
2.4.1
#14 lore raw
In reply to Alexander Aring

Hi Alex,

Quoted 19 lines

this patch series contains patches for remove pib and mib lock. We have now a other locking strategie inside this stack which requires at the moment the rtnl lock only. The first patch will hold the rtnl lock which is required to access the mib attributes while calling socket ioctl. The last patch will use atomic operations for incremet the dsn value for dataframes, currently it could be that this value is the same in two contiguous frames which could be occur a wrong ack frame handling in ARET mode.

- Alex

changes since v2:
- switch patch 3 and 4.

Alexander Aring (4):
mac802154: fix hold rtnl while ioctl
mac802154: remove pib lock
mac802154: use atomic ops for sequence incrementation
mac802154: remove mib lock

Quoted 14 lines
include/net/cfg802154.h         |  6 ++--
include/net/ieee802154_netdev.h | 10 -------
net/ieee802154/6lowpan/core.c   | 28 ------------------
net/ieee802154/6lowpan/tx.c     |  2 +-
net/ieee802154/core.c           |  2 --
net/ieee802154/nl-mac.c         | 14 ++++++---
net/ieee802154/nl-phy.c         |  6 ++--
net/ieee802154/socket.c         | 12 ++++----
net/mac802154/ieee802154_i.h    |  7 -----
net/mac802154/iface.c           | 29 ++++++-------------
net/mac802154/mac_cmd.c         |  7 ++---
net/mac802154/mib.c             | 63 ++---------------------------------------
net/mac802154/rx.c              |  5 ----
13 files changed, 34 insertions(+), 157 deletions(-)

all 4 patches have been applied to bluetooth-next tree.

Regards

Marcel