Skip to content

Commit 7acafda

Browse files
rluboscarlescufi
authored andcommitted
net: openthread: Fix possible deadlock in net_mgmt handlers
There is a risk of deadlock in case net_if APIs are used from within net_mgmt handlers as both module APIs are protected with their own mutexes. The scenario observed with OpenThread happend when NET_EVENT_IPV6_ADDR_ADD/NET_EVENT_IPV6_MADDR_ADD events were processed. The net_mgmt mutex is locked when both, an event handler is being processed (from a separate net_mgmt thread) and when an event is raised (for example when a new address is added on an interface). In case a net_mgmt handler tried to use some mutex-protected net_if API, we could end up in a deadlock situation - the net_mgmt would wait for the net_if mutex to release, while some other thread (in this case main during initialization) could wait within some net_if function, pending on net_mgmt mutex to be released to notify the event. Fix this, by preventing net_if APIs from being used from within OT net_mgmt handlers. Additionally, simplify the net_mgmt handlers logic, by making use of additional info provided with an event. Instead of blindy assuming that recently added address was the last on the list (which might not always be the case, if addresses are added/removed dynamically), read the actual address being added from the net_mgmt_event_callback structure. Signed-off-by: Robert Lubos <[email protected]>
1 parent 7acb318 commit 7acafda

File tree

3 files changed

+39
-37
lines changed

3 files changed

+39
-37
lines changed

subsys/net/l2/openthread/openthread.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,14 @@ static void ipv6_addr_event_handler(struct net_mgmt_event_callback *cb,
122122
return;
123123
}
124124

125+
if (cb->info == NULL || cb->info_length != sizeof(struct in6_addr)) {
126+
return;
127+
}
128+
125129
if (mgmt_event == NET_EVENT_IPV6_ADDR_ADD) {
126-
add_ipv6_addr_to_ot(ot_context);
130+
add_ipv6_addr_to_ot(ot_context, (const struct in6_addr *)cb->info);
127131
} else if (mgmt_event == NET_EVENT_IPV6_MADDR_ADD) {
128-
add_ipv6_maddr_to_ot(ot_context);
132+
add_ipv6_maddr_to_ot(ot_context, (const struct in6_addr *)cb->info);
129133
}
130134
}
131135
#endif

subsys/net/l2/openthread/openthread_utils.c

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -157,42 +157,52 @@ void add_ipv6_addr_to_zephyr(struct openthread_context *context)
157157
}
158158
}
159159

160-
void add_ipv6_addr_to_ot(struct openthread_context *context)
160+
void add_ipv6_addr_to_ot(struct openthread_context *context,
161+
const struct in6_addr *addr6)
161162
{
162-
struct net_if *iface = context->iface;
163-
struct otNetifAddress addr;
163+
struct otNetifAddress addr = { 0 };
164164
struct net_if_ipv6 *ipv6;
165+
struct net_if_addr *if_addr = NULL;
165166
int i;
166167

167-
(void)memset(&addr, 0, sizeof(addr));
168-
169-
if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
170-
NET_DBG("Cannot allocate IPv6 address");
168+
/* IPv6 struct should've already been allocated when we get an
169+
* address added event.
170+
*/
171+
ipv6 = context->iface->config.ip.ipv6;
172+
if (ipv6 == NULL) {
173+
NET_ERR("No IPv6 container allocated");
171174
return;
172175
}
173176

174-
/* save the last added IP address for this interface */
177+
/* Find the net_if_addr structure containing the newly added address. */
175178
for (i = NET_IF_MAX_IPV6_ADDR - 1; i >= 0; i--) {
176-
if (ipv6->unicast[i].is_used) {
177-
memcpy(&addr.mAddress,
178-
&ipv6->unicast[i].address.in6_addr,
179-
sizeof(addr.mAddress));
179+
if (ipv6->unicast[i].is_used &&
180+
net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr,
181+
addr6)) {
182+
if_addr = &ipv6->unicast[i];
180183
break;
181184
}
182185
}
183186

184-
ipv6->unicast[i].is_mesh_local = is_mesh_local(
187+
if (if_addr == NULL) {
188+
NET_ERR("No corresponding net_if_addr found");
189+
return;
190+
}
191+
192+
memcpy(&addr.mAddress, addr6, sizeof(addr.mAddress));
193+
194+
if_addr->is_mesh_local = is_mesh_local(
185195
context, ipv6->unicast[i].address.in6_addr.s6_addr);
186196

187197
addr.mValid = true;
188198
addr.mPreferred = true;
189199
addr.mPrefixLength = 64;
190200

191-
if (ipv6->unicast[i].addr_type == NET_ADDR_AUTOCONF) {
201+
if (if_addr->addr_type == NET_ADDR_AUTOCONF) {
192202
addr.mAddressOrigin = OT_ADDRESS_ORIGIN_SLAAC;
193-
} else if (ipv6->unicast[i].addr_type == NET_ADDR_DHCP) {
203+
} else if (if_addr->addr_type == NET_ADDR_DHCP) {
194204
addr.mAddressOrigin = OT_ADDRESS_ORIGIN_DHCPV6;
195-
} else if (ipv6->unicast[i].addr_type == NET_ADDR_MANUAL) {
205+
} else if (if_addr->addr_type == NET_ADDR_MANUAL) {
196206
addr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL;
197207
} else {
198208
NET_ERR("Unknown address type");
@@ -213,26 +223,12 @@ void add_ipv6_addr_to_ot(struct openthread_context *context)
213223
}
214224
}
215225

216-
void add_ipv6_maddr_to_ot(struct openthread_context *context)
226+
void add_ipv6_maddr_to_ot(struct openthread_context *context,
227+
const struct in6_addr *addr6)
217228
{
218229
struct otIp6Address addr;
219-
struct net_if_ipv6 *ipv6;
220-
int i;
221230

222-
if (net_if_config_ipv6_get(context->iface, &ipv6) < 0) {
223-
NET_DBG("Cannot allocate IPv6 address");
224-
return;
225-
}
226-
227-
/* save the last added IP address for this interface */
228-
for (i = NET_IF_MAX_IPV6_MADDR - 1; i >= 0; i--) {
229-
if (ipv6->mcast[i].is_used) {
230-
memcpy(&addr,
231-
&ipv6->mcast[i].address.in6_addr,
232-
sizeof(addr));
233-
break;
234-
}
235-
}
231+
memcpy(&addr, addr6, sizeof(addr));
236232

237233
openthread_api_mutex_lock(context);
238234
otIp6SubscribeMulticastAddress(context->instance, &addr);

subsys/net/l2/openthread/openthread_utils.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ void dump_pkt(const char *str, struct net_pkt *pkt);
2020
#endif
2121

2222
void add_ipv6_addr_to_zephyr(struct openthread_context *context);
23-
void add_ipv6_addr_to_ot(struct openthread_context *context);
24-
void add_ipv6_maddr_to_ot(struct openthread_context *context);
23+
void add_ipv6_addr_to_ot(struct openthread_context *context,
24+
const struct in6_addr *addr6);
25+
void add_ipv6_maddr_to_ot(struct openthread_context *context,
26+
const struct in6_addr *addr6);
2527
void add_ipv6_maddr_to_zephyr(struct openthread_context *context);
2628
void rm_ipv6_addr_from_zephyr(struct openthread_context *context);
2729
void rm_ipv6_maddr_from_zephyr(struct openthread_context *context);

0 commit comments

Comments
 (0)