diff options
author | Thomas Graf <tgraf@suug.ch> | 2007-03-23 02:30:12 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:27:30 -0400 |
commit | 1d00a4eb42bdade33a6ec0961cada93577a66ae6 (patch) | |
tree | a181b141818f594eb544601386bf09e45e6193bb /net | |
parent | 45e7ae7f716086994e4e747226881f901c67b031 (diff) |
[NETLINK]: Remove error pointer from netlink message handler
The error pointer argument in netlink message handlers is used
to signal the special case where processing has to be interrupted
because a dump was started but no error happened. Instead it is
simpler and more clear to return -EINTR and have netlink_run_queue()
deal with getting the queue right.
nfnetlink passed on this error pointer to its subsystem handlers
but only uses it to signal the start of a netlink dump. Therefore
it can be removed there as well.
This patch also cleans up the error handling in the affected
message handlers to be consistent since it had to be touched anyway.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/rtnetlink.c | 46 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 46 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 26 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 4 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 6 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 21 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 56 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 40 |
8 files changed, 91 insertions, 154 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b2136accd267..14241ada41a1 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -852,8 +852,7 @@ static int rtattr_max; | |||
852 | 852 | ||
853 | /* Process one rtnetlink message. */ | 853 | /* Process one rtnetlink message. */ |
854 | 854 | ||
855 | static __inline__ int | 855 | static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
856 | rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | ||
857 | { | 856 | { |
858 | rtnl_doit_func doit; | 857 | rtnl_doit_func doit; |
859 | int sz_idx, kind; | 858 | int sz_idx, kind; |
@@ -863,10 +862,8 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | |||
863 | int err; | 862 | int err; |
864 | 863 | ||
865 | type = nlh->nlmsg_type; | 864 | type = nlh->nlmsg_type; |
866 | |||
867 | /* Unknown message: reply with EINVAL */ | ||
868 | if (type > RTM_MAX) | 865 | if (type > RTM_MAX) |
869 | goto err_inval; | 866 | return -EINVAL; |
870 | 867 | ||
871 | type -= RTM_BASE; | 868 | type -= RTM_BASE; |
872 | 869 | ||
@@ -875,40 +872,33 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | |||
875 | return 0; | 872 | return 0; |
876 | 873 | ||
877 | family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; | 874 | family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; |
878 | if (family >= NPROTO) { | 875 | if (family >= NPROTO) |
879 | *errp = -EAFNOSUPPORT; | 876 | return -EAFNOSUPPORT; |
880 | return -1; | ||
881 | } | ||
882 | 877 | ||
883 | sz_idx = type>>2; | 878 | sz_idx = type>>2; |
884 | kind = type&3; | 879 | kind = type&3; |
885 | 880 | ||
886 | if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) { | 881 | if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) |
887 | *errp = -EPERM; | 882 | return -EPERM; |
888 | return -1; | ||
889 | } | ||
890 | 883 | ||
891 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { | 884 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
892 | rtnl_dumpit_func dumpit; | 885 | rtnl_dumpit_func dumpit; |
893 | 886 | ||
894 | dumpit = rtnl_get_dumpit(family, type); | 887 | dumpit = rtnl_get_dumpit(family, type); |
895 | if (dumpit == NULL) | 888 | if (dumpit == NULL) |
896 | goto err_inval; | 889 | return -EINVAL; |
897 | |||
898 | if ((*errp = netlink_dump_start(rtnl, skb, nlh, | ||
899 | dumpit, NULL)) != 0) { | ||
900 | return -1; | ||
901 | } | ||
902 | 890 | ||
903 | netlink_queue_skip(nlh, skb); | 891 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); |
904 | return -1; | 892 | if (err == 0) |
893 | err = -EINTR; | ||
894 | return err; | ||
905 | } | 895 | } |
906 | 896 | ||
907 | memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); | 897 | memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); |
908 | 898 | ||
909 | min_len = rtm_min[sz_idx]; | 899 | min_len = rtm_min[sz_idx]; |
910 | if (nlh->nlmsg_len < min_len) | 900 | if (nlh->nlmsg_len < min_len) |
911 | goto err_inval; | 901 | return -EINVAL; |
912 | 902 | ||
913 | if (nlh->nlmsg_len > min_len) { | 903 | if (nlh->nlmsg_len > min_len) { |
914 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); | 904 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); |
@@ -918,7 +908,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | |||
918 | unsigned flavor = attr->rta_type; | 908 | unsigned flavor = attr->rta_type; |
919 | if (flavor) { | 909 | if (flavor) { |
920 | if (flavor > rta_max[sz_idx]) | 910 | if (flavor > rta_max[sz_idx]) |
921 | goto err_inval; | 911 | return -EINVAL; |
922 | rta_buf[flavor-1] = attr; | 912 | rta_buf[flavor-1] = attr; |
923 | } | 913 | } |
924 | attr = RTA_NEXT(attr, attrlen); | 914 | attr = RTA_NEXT(attr, attrlen); |
@@ -927,15 +917,9 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | |||
927 | 917 | ||
928 | doit = rtnl_get_doit(family, type); | 918 | doit = rtnl_get_doit(family, type); |
929 | if (doit == NULL) | 919 | if (doit == NULL) |
930 | goto err_inval; | 920 | return -EINVAL; |
931 | err = doit(skb, nlh, (void *)&rta_buf[0]); | ||
932 | |||
933 | *errp = err; | ||
934 | return err; | ||
935 | 921 | ||
936 | err_inval: | 922 | return doit(skb, nlh, (void *)&rta_buf[0]); |
937 | *errp = -EINVAL; | ||
938 | return -1; | ||
939 | } | 923 | } |
940 | 924 | ||
941 | static void rtnetlink_rcv(struct sock *sk, int len) | 925 | static void rtnetlink_rcv(struct sock *sk, int len) |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 76f11f325919..443ba7753a33 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -661,7 +661,7 @@ static const size_t cta_min[CTA_MAX] = { | |||
661 | 661 | ||
662 | static int | 662 | static int |
663 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, | 663 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, |
664 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 664 | struct nlmsghdr *nlh, struct nfattr *cda[]) |
665 | { | 665 | { |
666 | struct nf_conntrack_tuple_hash *h; | 666 | struct nf_conntrack_tuple_hash *h; |
667 | struct nf_conntrack_tuple tuple; | 667 | struct nf_conntrack_tuple tuple; |
@@ -709,7 +709,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
709 | 709 | ||
710 | static int | 710 | static int |
711 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | 711 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, |
712 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 712 | struct nlmsghdr *nlh, struct nfattr *cda[]) |
713 | { | 713 | { |
714 | struct nf_conntrack_tuple_hash *h; | 714 | struct nf_conntrack_tuple_hash *h; |
715 | struct nf_conntrack_tuple tuple; | 715 | struct nf_conntrack_tuple tuple; |
@@ -720,22 +720,15 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
720 | int err = 0; | 720 | int err = 0; |
721 | 721 | ||
722 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 722 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
723 | u32 rlen; | ||
724 | |||
725 | #ifndef CONFIG_NF_CT_ACCT | 723 | #ifndef CONFIG_NF_CT_ACCT |
726 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) | 724 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) |
727 | return -ENOTSUPP; | 725 | return -ENOTSUPP; |
728 | #endif | 726 | #endif |
729 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 727 | err = netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table, |
730 | ctnetlink_dump_table, | 728 | ctnetlink_done); |
731 | ctnetlink_done)) != 0) | 729 | if (err == 0) |
732 | return -EINVAL; | 730 | err = -EINTR; |
733 | 731 | return err; | |
734 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
735 | if (rlen > skb->len) | ||
736 | rlen = skb->len; | ||
737 | skb_pull(skb, rlen); | ||
738 | return 0; | ||
739 | } | 732 | } |
740 | 733 | ||
741 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | 734 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) |
@@ -1009,7 +1002,7 @@ err: | |||
1009 | 1002 | ||
1010 | static int | 1003 | static int |
1011 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | 1004 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, |
1012 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1005 | struct nlmsghdr *nlh, struct nfattr *cda[]) |
1013 | { | 1006 | { |
1014 | struct nf_conntrack_tuple otuple, rtuple; | 1007 | struct nf_conntrack_tuple otuple, rtuple; |
1015 | struct nf_conntrack_tuple_hash *h = NULL; | 1008 | struct nf_conntrack_tuple_hash *h = NULL; |
@@ -1260,7 +1253,7 @@ static const size_t cta_min_exp[CTA_EXPECT_MAX] = { | |||
1260 | 1253 | ||
1261 | static int | 1254 | static int |
1262 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | 1255 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, |
1263 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1256 | struct nlmsghdr *nlh, struct nfattr *cda[]) |
1264 | { | 1257 | { |
1265 | struct nf_conntrack_tuple tuple; | 1258 | struct nf_conntrack_tuple tuple; |
1266 | struct nf_conntrack_expect *exp; | 1259 | struct nf_conntrack_expect *exp; |
@@ -1273,17 +1266,12 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1273 | return -EINVAL; | 1266 | return -EINVAL; |
1274 | 1267 | ||
1275 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 1268 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
1276 | u32 rlen; | 1269 | err = netlink_dump_start(ctnl, skb, nlh, |
1277 | 1270 | ctnetlink_exp_dump_table, | |
1278 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 1271 | ctnetlink_done); |
1279 | ctnetlink_exp_dump_table, | 1272 | if (err == 0) |
1280 | ctnetlink_done)) != 0) | 1273 | err = -EINTR; |
1281 | return -EINVAL; | 1274 | return err; |
1282 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
1283 | if (rlen > skb->len) | ||
1284 | rlen = skb->len; | ||
1285 | skb_pull(skb, rlen); | ||
1286 | return 0; | ||
1287 | } | 1275 | } |
1288 | 1276 | ||
1289 | if (cda[CTA_EXPECT_MASTER-1]) | 1277 | if (cda[CTA_EXPECT_MASTER-1]) |
@@ -1330,7 +1318,7 @@ out: | |||
1330 | 1318 | ||
1331 | static int | 1319 | static int |
1332 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | 1320 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, |
1333 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1321 | struct nlmsghdr *nlh, struct nfattr *cda[]) |
1334 | { | 1322 | { |
1335 | struct nf_conntrack_expect *exp, *tmp; | 1323 | struct nf_conntrack_expect *exp, *tmp; |
1336 | struct nf_conntrack_tuple tuple; | 1324 | struct nf_conntrack_tuple tuple; |
@@ -1464,7 +1452,7 @@ out: | |||
1464 | 1452 | ||
1465 | static int | 1453 | static int |
1466 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, | 1454 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, |
1467 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | 1455 | struct nlmsghdr *nlh, struct nfattr *cda[]) |
1468 | { | 1456 | { |
1469 | struct nf_conntrack_tuple tuple; | 1457 | struct nf_conntrack_tuple tuple; |
1470 | struct nf_conntrack_expect *exp; | 1458 | struct nf_conntrack_expect *exp; |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index dec36abdf949..c37ed0156b07 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -195,17 +195,14 @@ int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) | |||
195 | EXPORT_SYMBOL_GPL(nfnetlink_unicast); | 195 | EXPORT_SYMBOL_GPL(nfnetlink_unicast); |
196 | 196 | ||
197 | /* Process one complete nfnetlink message. */ | 197 | /* Process one complete nfnetlink message. */ |
198 | static int nfnetlink_rcv_msg(struct sk_buff *skb, | 198 | static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
199 | struct nlmsghdr *nlh, int *errp) | ||
200 | { | 199 | { |
201 | struct nfnl_callback *nc; | 200 | struct nfnl_callback *nc; |
202 | struct nfnetlink_subsystem *ss; | 201 | struct nfnetlink_subsystem *ss; |
203 | int type, err = 0; | 202 | int type, err; |
204 | 203 | ||
205 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) { | 204 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) |
206 | *errp = -EPERM; | 205 | return -EPERM; |
207 | return -1; | ||
208 | } | ||
209 | 206 | ||
210 | /* Only requests are handled by kernel now. */ | 207 | /* Only requests are handled by kernel now. */ |
211 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) | 208 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) |
@@ -227,12 +224,12 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, | |||
227 | ss = nfnetlink_get_subsys(type); | 224 | ss = nfnetlink_get_subsys(type); |
228 | if (!ss) | 225 | if (!ss) |
229 | #endif | 226 | #endif |
230 | goto err_inval; | 227 | return -EINVAL; |
231 | } | 228 | } |
232 | 229 | ||
233 | nc = nfnetlink_find_client(type, ss); | 230 | nc = nfnetlink_find_client(type, ss); |
234 | if (!nc) | 231 | if (!nc) |
235 | goto err_inval; | 232 | return -EINVAL; |
236 | 233 | ||
237 | { | 234 | { |
238 | u_int16_t attr_count = | 235 | u_int16_t attr_count = |
@@ -243,16 +240,9 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, | |||
243 | 240 | ||
244 | err = nfnetlink_check_attributes(ss, nlh, cda); | 241 | err = nfnetlink_check_attributes(ss, nlh, cda); |
245 | if (err < 0) | 242 | if (err < 0) |
246 | goto err_inval; | 243 | return err; |
247 | 244 | return nc->call(nfnl, skb, nlh, cda); | |
248 | err = nc->call(nfnl, skb, nlh, cda, errp); | ||
249 | *errp = err; | ||
250 | return err; | ||
251 | } | 245 | } |
252 | |||
253 | err_inval: | ||
254 | *errp = -EINVAL; | ||
255 | return -1; | ||
256 | } | 246 | } |
257 | 247 | ||
258 | static void nfnetlink_rcv(struct sock *sk, int len) | 248 | static void nfnetlink_rcv(struct sock *sk, int len) |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 9709f94787f8..b174aadd73e6 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -759,7 +759,7 @@ static struct notifier_block nfulnl_rtnl_notifier = { | |||
759 | 759 | ||
760 | static int | 760 | static int |
761 | nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, | 761 | nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, |
762 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) | 762 | struct nlmsghdr *nlh, struct nfattr *nfqa[]) |
763 | { | 763 | { |
764 | return -ENOTSUPP; | 764 | return -ENOTSUPP; |
765 | } | 765 | } |
@@ -797,7 +797,7 @@ static const int nfula_cfg_min[NFULA_CFG_MAX] = { | |||
797 | 797 | ||
798 | static int | 798 | static int |
799 | nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | 799 | nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, |
800 | struct nlmsghdr *nlh, struct nfattr *nfula[], int *errp) | 800 | struct nlmsghdr *nlh, struct nfattr *nfula[]) |
801 | { | 801 | { |
802 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 802 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
803 | u_int16_t group_num = ntohs(nfmsg->res_id); | 803 | u_int16_t group_num = ntohs(nfmsg->res_id); |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index b6585caa431e..9aefb1c9bfa3 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -783,7 +783,7 @@ static const int nfqa_verdict_min[NFQA_MAX] = { | |||
783 | 783 | ||
784 | static int | 784 | static int |
785 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | 785 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, |
786 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) | 786 | struct nlmsghdr *nlh, struct nfattr *nfqa[]) |
787 | { | 787 | { |
788 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 788 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
789 | u_int16_t queue_num = ntohs(nfmsg->res_id); | 789 | u_int16_t queue_num = ntohs(nfmsg->res_id); |
@@ -848,7 +848,7 @@ err_out_put: | |||
848 | 848 | ||
849 | static int | 849 | static int |
850 | nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, | 850 | nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, |
851 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) | 851 | struct nlmsghdr *nlh, struct nfattr *nfqa[]) |
852 | { | 852 | { |
853 | return -ENOTSUPP; | 853 | return -ENOTSUPP; |
854 | } | 854 | } |
@@ -865,7 +865,7 @@ static struct nf_queue_handler nfqh = { | |||
865 | 865 | ||
866 | static int | 866 | static int |
867 | nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | 867 | nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, |
868 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) | 868 | struct nlmsghdr *nlh, struct nfattr *nfqa[]) |
869 | { | 869 | { |
870 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 870 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
871 | u_int16_t queue_num = ntohs(nfmsg->res_id); | 871 | u_int16_t queue_num = ntohs(nfmsg->res_id); |
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) |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 4d2f2094e6df..5e52d6275bad 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1852,46 +1852,39 @@ static struct xfrm_link { | |||
1852 | [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, | 1852 | [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, |
1853 | }; | 1853 | }; |
1854 | 1854 | ||
1855 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | 1855 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
1856 | { | 1856 | { |
1857 | struct rtattr *xfrma[XFRMA_MAX]; | 1857 | struct rtattr *xfrma[XFRMA_MAX]; |
1858 | struct xfrm_link *link; | 1858 | struct xfrm_link *link; |
1859 | int type, min_len; | 1859 | int type, min_len, err; |
1860 | 1860 | ||
1861 | type = nlh->nlmsg_type; | 1861 | type = nlh->nlmsg_type; |
1862 | |||
1863 | /* Unknown message: reply with EINVAL */ | ||
1864 | if (type > XFRM_MSG_MAX) | 1862 | if (type > XFRM_MSG_MAX) |
1865 | goto err_einval; | 1863 | return -EINVAL; |
1866 | 1864 | ||
1867 | type -= XFRM_MSG_BASE; | 1865 | type -= XFRM_MSG_BASE; |
1868 | link = &xfrm_dispatch[type]; | 1866 | link = &xfrm_dispatch[type]; |
1869 | 1867 | ||
1870 | /* All operations require privileges, even GET */ | 1868 | /* All operations require privileges, even GET */ |
1871 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) { | 1869 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) |
1872 | *errp = -EPERM; | 1870 | return -EPERM; |
1873 | return -1; | ||
1874 | } | ||
1875 | 1871 | ||
1876 | if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || | 1872 | if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || |
1877 | type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && | 1873 | type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && |
1878 | (nlh->nlmsg_flags & NLM_F_DUMP)) { | 1874 | (nlh->nlmsg_flags & NLM_F_DUMP)) { |
1879 | if (link->dump == NULL) | 1875 | if (link->dump == NULL) |
1880 | goto err_einval; | 1876 | return -EINVAL; |
1881 | |||
1882 | if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, | ||
1883 | link->dump, NULL)) != 0) { | ||
1884 | return -1; | ||
1885 | } | ||
1886 | 1877 | ||
1887 | netlink_queue_skip(nlh, skb); | 1878 | err = netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); |
1888 | return -1; | 1879 | if (err == 0) |
1880 | err = -EINTR; | ||
1881 | return err; | ||
1889 | } | 1882 | } |
1890 | 1883 | ||
1891 | memset(xfrma, 0, sizeof(xfrma)); | 1884 | memset(xfrma, 0, sizeof(xfrma)); |
1892 | 1885 | ||
1893 | if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type])) | 1886 | if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type])) |
1894 | goto err_einval; | 1887 | return -EINVAL; |
1895 | 1888 | ||
1896 | if (nlh->nlmsg_len > min_len) { | 1889 | if (nlh->nlmsg_len > min_len) { |
1897 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); | 1890 | int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); |
@@ -1901,7 +1894,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err | |||
1901 | unsigned short flavor = attr->rta_type; | 1894 | unsigned short flavor = attr->rta_type; |
1902 | if (flavor) { | 1895 | if (flavor) { |
1903 | if (flavor > XFRMA_MAX) | 1896 | if (flavor > XFRMA_MAX) |
1904 | goto err_einval; | 1897 | return -EINVAL; |
1905 | xfrma[flavor - 1] = attr; | 1898 | xfrma[flavor - 1] = attr; |
1906 | } | 1899 | } |
1907 | attr = RTA_NEXT(attr, attrlen); | 1900 | attr = RTA_NEXT(attr, attrlen); |
@@ -1909,14 +1902,9 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err | |||
1909 | } | 1902 | } |
1910 | 1903 | ||
1911 | if (link->doit == NULL) | 1904 | if (link->doit == NULL) |
1912 | goto err_einval; | 1905 | return -EINVAL; |
1913 | *errp = link->doit(skb, nlh, xfrma); | ||
1914 | |||
1915 | return *errp; | ||
1916 | 1906 | ||
1917 | err_einval: | 1907 | return link->doit(skb, nlh, xfrma); |
1918 | *errp = -EINVAL; | ||
1919 | return -1; | ||
1920 | } | 1908 | } |
1921 | 1909 | ||
1922 | static void xfrm_netlink_rcv(struct sock *sk, int len) | 1910 | static void xfrm_netlink_rcv(struct sock *sk, int len) |