diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 21 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 56 |
2 files changed, 32 insertions, 45 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 5d1079b1838c..1823b7c63156 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1463,7 +1463,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1463 | } | 1463 | } |
1464 | 1464 | ||
1465 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | 1465 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, |
1466 | struct nlmsghdr *, int *)) | 1466 | struct nlmsghdr *)) |
1467 | { | 1467 | { |
1468 | struct nlmsghdr *nlh; | 1468 | struct nlmsghdr *nlh; |
1469 | int err; | 1469 | int err; |
@@ -1483,13 +1483,11 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
1483 | if (nlh->nlmsg_type < NLMSG_MIN_TYPE) | 1483 | if (nlh->nlmsg_type < NLMSG_MIN_TYPE) |
1484 | goto skip; | 1484 | goto skip; |
1485 | 1485 | ||
1486 | if (cb(skb, nlh, &err) < 0) { | 1486 | err = cb(skb, nlh); |
1487 | /* Not an error, but we have to interrupt processing | 1487 | if (err == -EINTR) { |
1488 | * here. Note: that in this case we do not pull | 1488 | /* Not an error, but we interrupt processing */ |
1489 | * message from skb, it will be processed later. | 1489 | netlink_queue_skip(nlh, skb); |
1490 | */ | 1490 | return err; |
1491 | if (err == 0) | ||
1492 | return -1; | ||
1493 | } | 1491 | } |
1494 | skip: | 1492 | skip: |
1495 | if (nlh->nlmsg_flags & NLM_F_ACK || err) | 1493 | if (nlh->nlmsg_flags & NLM_F_ACK || err) |
@@ -1515,9 +1513,14 @@ skip: | |||
1515 | * | 1513 | * |
1516 | * qlen must be initialized to 0 before the initial entry, afterwards | 1514 | * qlen must be initialized to 0 before the initial entry, afterwards |
1517 | * the function may be called repeatedly until qlen reaches 0. | 1515 | * the function may be called repeatedly until qlen reaches 0. |
1516 | * | ||
1517 | * The callback function may return -EINTR to signal that processing | ||
1518 | * of netlink messages shall be interrupted. In this case the message | ||
1519 | * currently being processed will NOT be requeued onto the receive | ||
1520 | * queue. | ||
1518 | */ | 1521 | */ |
1519 | void netlink_run_queue(struct sock *sk, unsigned int *qlen, | 1522 | void netlink_run_queue(struct sock *sk, unsigned int *qlen, |
1520 | int (*cb)(struct sk_buff *, struct nlmsghdr *, int *)) | 1523 | int (*cb)(struct sk_buff *, struct nlmsghdr *)) |
1521 | { | 1524 | { |
1522 | struct sk_buff *skb; | 1525 | struct sk_buff *skb; |
1523 | 1526 | ||
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 95391e609046..1b897bc92e61 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -295,60 +295,49 @@ int genl_unregister_family(struct genl_family *family) | |||
295 | return -ENOENT; | 295 | return -ENOENT; |
296 | } | 296 | } |
297 | 297 | ||
298 | static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | 298 | static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
299 | int *errp) | ||
300 | { | 299 | { |
301 | struct genl_ops *ops; | 300 | struct genl_ops *ops; |
302 | struct genl_family *family; | 301 | struct genl_family *family; |
303 | struct genl_info info; | 302 | struct genl_info info; |
304 | struct genlmsghdr *hdr = nlmsg_data(nlh); | 303 | struct genlmsghdr *hdr = nlmsg_data(nlh); |
305 | int hdrlen, err = -EINVAL; | 304 | int hdrlen, err; |
306 | 305 | ||
307 | family = genl_family_find_byid(nlh->nlmsg_type); | 306 | family = genl_family_find_byid(nlh->nlmsg_type); |
308 | if (family == NULL) { | 307 | if (family == NULL) |
309 | err = -ENOENT; | 308 | return -ENOENT; |
310 | goto errout; | ||
311 | } | ||
312 | 309 | ||
313 | hdrlen = GENL_HDRLEN + family->hdrsize; | 310 | hdrlen = GENL_HDRLEN + family->hdrsize; |
314 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) | 311 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) |
315 | goto errout; | 312 | return -EINVAL; |
316 | 313 | ||
317 | ops = genl_get_cmd(hdr->cmd, family); | 314 | ops = genl_get_cmd(hdr->cmd, family); |
318 | if (ops == NULL) { | 315 | if (ops == NULL) |
319 | err = -EOPNOTSUPP; | 316 | return -EOPNOTSUPP; |
320 | goto errout; | ||
321 | } | ||
322 | 317 | ||
323 | if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) { | 318 | if ((ops->flags & GENL_ADMIN_PERM) && |
324 | err = -EPERM; | 319 | security_netlink_recv(skb, CAP_NET_ADMIN)) |
325 | goto errout; | 320 | return -EPERM; |
326 | } | ||
327 | 321 | ||
328 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 322 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
329 | if (ops->dumpit == NULL) { | 323 | if (ops->dumpit == NULL) |
330 | err = -EOPNOTSUPP; | 324 | return -EOPNOTSUPP; |
331 | goto errout; | ||
332 | } | ||
333 | 325 | ||
334 | *errp = err = netlink_dump_start(genl_sock, skb, nlh, | 326 | err = netlink_dump_start(genl_sock, skb, nlh, |
335 | ops->dumpit, ops->done); | 327 | ops->dumpit, ops->done); |
336 | if (err == 0) | 328 | if (err == 0) |
337 | skb_pull(skb, min(NLMSG_ALIGN(nlh->nlmsg_len), | 329 | err = -EINTR; |
338 | skb->len)); | 330 | return err; |
339 | return -1; | ||
340 | } | 331 | } |
341 | 332 | ||
342 | if (ops->doit == NULL) { | 333 | if (ops->doit == NULL) |
343 | err = -EOPNOTSUPP; | 334 | return -EOPNOTSUPP; |
344 | goto errout; | ||
345 | } | ||
346 | 335 | ||
347 | if (family->attrbuf) { | 336 | if (family->attrbuf) { |
348 | err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr, | 337 | err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr, |
349 | ops->policy); | 338 | ops->policy); |
350 | if (err < 0) | 339 | if (err < 0) |
351 | goto errout; | 340 | return err; |
352 | } | 341 | } |
353 | 342 | ||
354 | info.snd_seq = nlh->nlmsg_seq; | 343 | info.snd_seq = nlh->nlmsg_seq; |
@@ -358,12 +347,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
358 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; | 347 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; |
359 | info.attrs = family->attrbuf; | 348 | info.attrs = family->attrbuf; |
360 | 349 | ||
361 | *errp = err = ops->doit(skb, &info); | 350 | return ops->doit(skb, &info); |
362 | return err; | ||
363 | |||
364 | errout: | ||
365 | *errp = err; | ||
366 | return -1; | ||
367 | } | 351 | } |
368 | 352 | ||
369 | static void genl_rcv(struct sock *sk, int len) | 353 | static void genl_rcv(struct sock *sk, int len) |