62
62
struct rtnl_link {
63
63
rtnl_doit_func doit ;
64
64
rtnl_dumpit_func dumpit ;
65
+ struct module * owner ;
65
66
unsigned int flags ;
66
67
struct rcu_head rcu ;
67
68
};
@@ -129,7 +130,6 @@ EXPORT_SYMBOL(lockdep_rtnl_is_held);
129
130
#endif /* #ifdef CONFIG_PROVE_LOCKING */
130
131
131
132
static struct rtnl_link __rcu * * rtnl_msg_handlers [RTNL_FAMILY_MAX + 1 ];
132
- static refcount_t rtnl_msg_handlers_ref [RTNL_FAMILY_MAX + 1 ];
133
133
134
134
static inline int rtm_msgindex (int msgtype )
135
135
{
@@ -159,27 +159,10 @@ static struct rtnl_link *rtnl_get_link(int protocol, int msgtype)
159
159
return tab [msgtype ];
160
160
}
161
161
162
- /**
163
- * __rtnl_register - Register a rtnetlink message type
164
- * @protocol: Protocol family or PF_UNSPEC
165
- * @msgtype: rtnetlink message type
166
- * @doit: Function pointer called for each request message
167
- * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
168
- * @flags: rtnl_link_flags to modifiy behaviour of doit/dumpit functions
169
- *
170
- * Registers the specified function pointers (at least one of them has
171
- * to be non-NULL) to be called whenever a request message for the
172
- * specified protocol family and message type is received.
173
- *
174
- * The special protocol family PF_UNSPEC may be used to define fallback
175
- * function pointers for the case when no entry for the specific protocol
176
- * family exists.
177
- *
178
- * Returns 0 on success or a negative error code.
179
- */
180
- int __rtnl_register (int protocol , int msgtype ,
181
- rtnl_doit_func doit , rtnl_dumpit_func dumpit ,
182
- unsigned int flags )
162
+ static int rtnl_register_internal (struct module * owner ,
163
+ int protocol , int msgtype ,
164
+ rtnl_doit_func doit , rtnl_dumpit_func dumpit ,
165
+ unsigned int flags )
183
166
{
184
167
struct rtnl_link * * tab , * link , * old ;
185
168
int msgindex ;
@@ -210,6 +193,9 @@ int __rtnl_register(int protocol, int msgtype,
210
193
goto unlock ;
211
194
}
212
195
196
+ WARN_ON (link -> owner && link -> owner != owner );
197
+ link -> owner = owner ;
198
+
213
199
WARN_ON (doit && link -> doit && link -> doit != doit );
214
200
if (doit )
215
201
link -> doit = doit ;
@@ -228,6 +214,54 @@ int __rtnl_register(int protocol, int msgtype,
228
214
rtnl_unlock ();
229
215
return ret ;
230
216
}
217
+
218
+ /**
219
+ * rtnl_register_module - Register a rtnetlink message type
220
+ *
221
+ * @owner: module registering the hook (THIS_MODULE)
222
+ * @protocol: Protocol family or PF_UNSPEC
223
+ * @msgtype: rtnetlink message type
224
+ * @doit: Function pointer called for each request message
225
+ * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
226
+ * @flags: rtnl_link_flags to modifiy behaviour of doit/dumpit functions
227
+ *
228
+ * Like rtnl_register, but for use by removable modules.
229
+ */
230
+ int rtnl_register_module (struct module * owner ,
231
+ int protocol , int msgtype ,
232
+ rtnl_doit_func doit , rtnl_dumpit_func dumpit ,
233
+ unsigned int flags )
234
+ {
235
+ return rtnl_register_internal (owner , protocol , msgtype ,
236
+ doit , dumpit , flags );
237
+ }
238
+ EXPORT_SYMBOL_GPL (rtnl_register_module );
239
+
240
+ /**
241
+ * __rtnl_register - Register a rtnetlink message type
242
+ * @protocol: Protocol family or PF_UNSPEC
243
+ * @msgtype: rtnetlink message type
244
+ * @doit: Function pointer called for each request message
245
+ * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
246
+ * @flags: rtnl_link_flags to modifiy behaviour of doit/dumpit functions
247
+ *
248
+ * Registers the specified function pointers (at least one of them has
249
+ * to be non-NULL) to be called whenever a request message for the
250
+ * specified protocol family and message type is received.
251
+ *
252
+ * The special protocol family PF_UNSPEC may be used to define fallback
253
+ * function pointers for the case when no entry for the specific protocol
254
+ * family exists.
255
+ *
256
+ * Returns 0 on success or a negative error code.
257
+ */
258
+ int __rtnl_register (int protocol , int msgtype ,
259
+ rtnl_doit_func doit , rtnl_dumpit_func dumpit ,
260
+ unsigned int flags )
261
+ {
262
+ return rtnl_register_internal (NULL , protocol , msgtype ,
263
+ doit , dumpit , flags );
264
+ }
231
265
EXPORT_SYMBOL_GPL (__rtnl_register );
232
266
233
267
/**
@@ -311,8 +345,6 @@ void rtnl_unregister_all(int protocol)
311
345
312
346
synchronize_net ();
313
347
314
- while (refcount_read (& rtnl_msg_handlers_ref [protocol ]) > 1 )
315
- schedule ();
316
348
kfree (tab );
317
349
}
318
350
EXPORT_SYMBOL_GPL (rtnl_unregister_all );
@@ -4372,6 +4404,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4372
4404
{
4373
4405
struct net * net = sock_net (skb -> sk );
4374
4406
struct rtnl_link * link ;
4407
+ struct module * owner ;
4375
4408
int err = - EOPNOTSUPP ;
4376
4409
rtnl_doit_func doit ;
4377
4410
unsigned int flags ;
@@ -4408,24 +4441,32 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4408
4441
if (!link || !link -> dumpit )
4409
4442
goto err_unlock ;
4410
4443
}
4444
+ owner = link -> owner ;
4411
4445
dumpit = link -> dumpit ;
4412
4446
4413
- refcount_inc (& rtnl_msg_handlers_ref [family ]);
4414
-
4415
4447
if (type == RTM_GETLINK - RTM_BASE )
4416
4448
min_dump_alloc = rtnl_calcit (skb , nlh );
4417
4449
4450
+ err = 0 ;
4451
+ /* need to do this before rcu_read_unlock() */
4452
+ if (!try_module_get (owner ))
4453
+ err = - EPROTONOSUPPORT ;
4454
+
4418
4455
rcu_read_unlock ();
4419
4456
4420
4457
rtnl = net -> rtnl ;
4421
- {
4458
+ if ( err == 0 ) {
4422
4459
struct netlink_dump_control c = {
4423
4460
.dump = dumpit ,
4424
4461
.min_dump_alloc = min_dump_alloc ,
4462
+ .module = owner ,
4425
4463
};
4426
4464
err = netlink_dump_start (rtnl , skb , nlh , & c );
4465
+ /* netlink_dump_start() will keep a reference on
4466
+ * module if dump is still in progress.
4467
+ */
4468
+ module_put (owner );
4427
4469
}
4428
- refcount_dec (& rtnl_msg_handlers_ref [family ]);
4429
4470
return err ;
4430
4471
}
4431
4472
@@ -4437,14 +4478,19 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4437
4478
goto out_unlock ;
4438
4479
}
4439
4480
4481
+ owner = link -> owner ;
4482
+ if (!try_module_get (owner )) {
4483
+ err = - EPROTONOSUPPORT ;
4484
+ goto out_unlock ;
4485
+ }
4486
+
4440
4487
flags = link -> flags ;
4441
4488
if (flags & RTNL_FLAG_DOIT_UNLOCKED ) {
4442
- refcount_inc (& rtnl_msg_handlers_ref [family ]);
4443
4489
doit = link -> doit ;
4444
4490
rcu_read_unlock ();
4445
4491
if (doit )
4446
4492
err = doit (skb , nlh , extack );
4447
- refcount_dec ( & rtnl_msg_handlers_ref [ family ] );
4493
+ module_put ( owner );
4448
4494
return err ;
4449
4495
}
4450
4496
rcu_read_unlock ();
@@ -4455,6 +4501,8 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4455
4501
err = link -> doit (skb , nlh , extack );
4456
4502
rtnl_unlock ();
4457
4503
4504
+ module_put (owner );
4505
+
4458
4506
return err ;
4459
4507
4460
4508
out_unlock :
@@ -4546,11 +4594,6 @@ static struct pernet_operations rtnetlink_net_ops = {
4546
4594
4547
4595
void __init rtnetlink_init (void )
4548
4596
{
4549
- int i ;
4550
-
4551
- for (i = 0 ; i < ARRAY_SIZE (rtnl_msg_handlers_ref ); i ++ )
4552
- refcount_set (& rtnl_msg_handlers_ref [i ], 1 );
4553
-
4554
4597
if (register_pernet_subsys (& rtnetlink_net_ops ))
4555
4598
panic ("rtnetlink_init: cannot initialize rtnetlink\n" );
4556
4599
0 commit comments