|
@@ -62,6 +62,7 @@
|
|
|
struct rtnl_link {
|
|
|
rtnl_doit_func doit;
|
|
|
rtnl_dumpit_func dumpit;
|
|
|
+ unsigned int flags;
|
|
|
};
|
|
|
|
|
|
static DEFINE_MUTEX(rtnl_mutex);
|
|
@@ -184,6 +185,7 @@ int __rtnl_register(int protocol, int msgtype,
|
|
|
tab[msgindex].doit = doit;
|
|
|
if (dumpit)
|
|
|
tab[msgindex].dumpit = dumpit;
|
|
|
+ tab[msgindex].flags |= flags;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -233,6 +235,7 @@ int rtnl_unregister(int protocol, int msgtype)
|
|
|
|
|
|
handlers[msgindex].doit = NULL;
|
|
|
handlers[msgindex].dumpit = NULL;
|
|
|
+ handlers[msgindex].flags = 0;
|
|
|
rtnl_unlock();
|
|
|
|
|
|
return 0;
|
|
@@ -4143,6 +4146,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
struct rtnl_link *handlers;
|
|
|
int err = -EOPNOTSUPP;
|
|
|
rtnl_doit_func doit;
|
|
|
+ unsigned int flags;
|
|
|
int kind;
|
|
|
int family;
|
|
|
int type;
|
|
@@ -4209,6 +4213,17 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ flags = READ_ONCE(handlers[type].flags);
|
|
|
+ if (flags & RTNL_FLAG_DOIT_UNLOCKED) {
|
|
|
+ refcount_inc(&rtnl_msg_handlers_ref[family]);
|
|
|
+ doit = READ_ONCE(handlers[type].doit);
|
|
|
+ rcu_read_unlock();
|
|
|
+ if (doit)
|
|
|
+ err = doit(skb, nlh, extack);
|
|
|
+ refcount_dec(&rtnl_msg_handlers_ref[family]);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
rtnl_lock();
|