aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2013-03-21 03:45:28 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-22 10:31:16 -0400
commit58d7d8f9b20ee6f883532b952f246e4289fe06eb (patch)
tree9d57be6839dd056ab37a63043ae871d36e0cf548
parent9b924dbd5e903aa6394ff6feee8275b9bde313d1 (diff)
decnet: Parse netlink attributes on our own
decnet is the only subsystem left that is relying on the global netlink attribute buffer rta_buf. It's horrible design and we want to get rid of it. This converts all of decnet to do implicit attribute parsing. It also gets rid of the error prone struct dn_kern_rta. Yes, the fib_magic() stuff is not pretty. It's compiled tested but I need someone with appropriate hardware to test the patch since I don't have access to it. Cc: linux-decnet-user@lists.sourceforge.net Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/dn_fib.h28
-rw-r--r--net/decnet/dn_fib.c211
-rw-r--r--net/decnet/dn_route.c27
-rw-r--r--net/decnet/dn_table.c42
4 files changed, 160 insertions, 148 deletions
diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h
index 1ee9d4bda30d..74004af31c48 100644
--- a/include/net/dn_fib.h
+++ b/include/net/dn_fib.h
@@ -1,24 +1,9 @@
1#ifndef _NET_DN_FIB_H 1#ifndef _NET_DN_FIB_H
2#define _NET_DN_FIB_H 2#define _NET_DN_FIB_H
3 3
4/* WARNING: The ordering of these elements must match ordering 4#include <linux/netlink.h>
5 * of RTA_* rtnetlink attribute numbers. 5
6 */ 6extern const struct nla_policy rtm_dn_policy[];
7struct dn_kern_rta {
8 void *rta_dst;
9 void *rta_src;
10 int *rta_iif;
11 int *rta_oif;
12 void *rta_gw;
13 u32 *rta_priority;
14 void *rta_prefsrc;
15 struct rtattr *rta_mx;
16 struct rtattr *rta_mp;
17 unsigned char *rta_protoinfo;
18 u32 *rta_flow;
19 struct rta_cacheinfo *rta_ci;
20 struct rta_session *rta_sess;
21};
22 7
23struct dn_fib_res { 8struct dn_fib_res {
24 struct fib_rule *r; 9 struct fib_rule *r;
@@ -93,10 +78,10 @@ struct dn_fib_table {
93 u32 n; 78 u32 n;
94 79
95 int (*insert)(struct dn_fib_table *t, struct rtmsg *r, 80 int (*insert)(struct dn_fib_table *t, struct rtmsg *r,
96 struct dn_kern_rta *rta, struct nlmsghdr *n, 81 struct nlattr *attrs[], struct nlmsghdr *n,
97 struct netlink_skb_parms *req); 82 struct netlink_skb_parms *req);
98 int (*delete)(struct dn_fib_table *t, struct rtmsg *r, 83 int (*delete)(struct dn_fib_table *t, struct rtmsg *r,
99 struct dn_kern_rta *rta, struct nlmsghdr *n, 84 struct nlattr *attrs[], struct nlmsghdr *n,
100 struct netlink_skb_parms *req); 85 struct netlink_skb_parms *req);
101 int (*lookup)(struct dn_fib_table *t, const struct flowidn *fld, 86 int (*lookup)(struct dn_fib_table *t, const struct flowidn *fld,
102 struct dn_fib_res *res); 87 struct dn_fib_res *res);
@@ -116,13 +101,12 @@ extern void dn_fib_cleanup(void);
116extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd, 101extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd,
117 unsigned long arg); 102 unsigned long arg);
118extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, 103extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r,
119 struct dn_kern_rta *rta, 104 struct nlattr *attrs[],
120 const struct nlmsghdr *nlh, int *errp); 105 const struct nlmsghdr *nlh, int *errp);
121extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi, 106extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi,
122 const struct flowidn *fld, 107 const struct flowidn *fld,
123 struct dn_fib_res *res); 108 struct dn_fib_res *res);
124extern void dn_fib_release_info(struct dn_fib_info *fi); 109extern void dn_fib_release_info(struct dn_fib_info *fi);
125extern __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type);
126extern void dn_fib_flush(void); 110extern void dn_fib_flush(void);
127extern void dn_fib_select_multipath(const struct flowidn *fld, 111extern void dn_fib_select_multipath(const struct flowidn *fld,
128 struct dn_fib_res *res); 112 struct dn_fib_res *res);
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index e36614eccc04..42a8048fe725 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -145,22 +145,10 @@ static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi
145 return NULL; 145 return NULL;
146} 146}
147 147
148__le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type) 148static int dn_fib_count_nhs(const struct nlattr *attr)
149{ 149{
150 while(RTA_OK(attr,attrlen)) { 150 struct rtnexthop *nhp = nla_data(attr);
151 if (attr->rta_type == type) 151 int nhs = 0, nhlen = nla_len(attr);
152 return *(__le16*)RTA_DATA(attr);
153 attr = RTA_NEXT(attr, attrlen);
154 }
155
156 return 0;
157}
158
159static int dn_fib_count_nhs(struct rtattr *rta)
160{
161 int nhs = 0;
162 struct rtnexthop *nhp = RTA_DATA(rta);
163 int nhlen = RTA_PAYLOAD(rta);
164 152
165 while(nhlen >= (int)sizeof(struct rtnexthop)) { 153 while(nhlen >= (int)sizeof(struct rtnexthop)) {
166 if ((nhlen -= nhp->rtnh_len) < 0) 154 if ((nhlen -= nhp->rtnh_len) < 0)
@@ -172,10 +160,11 @@ static int dn_fib_count_nhs(struct rtattr *rta)
172 return nhs; 160 return nhs;
173} 161}
174 162
175static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r) 163static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
164 const struct rtmsg *r)
176{ 165{
177 struct rtnexthop *nhp = RTA_DATA(rta); 166 struct rtnexthop *nhp = nla_data(attr);
178 int nhlen = RTA_PAYLOAD(rta); 167 int nhlen = nla_len(attr);
179 168
180 change_nexthops(fi) { 169 change_nexthops(fi) {
181 int attrlen = nhlen - sizeof(struct rtnexthop); 170 int attrlen = nhlen - sizeof(struct rtnexthop);
@@ -187,7 +176,10 @@ static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, cons
187 nh->nh_weight = nhp->rtnh_hops + 1; 176 nh->nh_weight = nhp->rtnh_hops + 1;
188 177
189 if (attrlen) { 178 if (attrlen) {
190 nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); 179 struct nlattr *gw_attr;
180
181 gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
182 nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
191 } 183 }
192 nhp = RTNH_NEXT(nhp); 184 nhp = RTNH_NEXT(nhp);
193 } endfor_nexthops(fi); 185 } endfor_nexthops(fi);
@@ -268,7 +260,8 @@ out:
268} 260}
269 261
270 262
271struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp) 263struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
264 const struct nlmsghdr *nlh, int *errp)
272{ 265{
273 int err; 266 int err;
274 struct dn_fib_info *fi = NULL; 267 struct dn_fib_info *fi = NULL;
@@ -281,11 +274,9 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
281 if (dn_fib_props[r->rtm_type].scope > r->rtm_scope) 274 if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
282 goto err_inval; 275 goto err_inval;
283 276
284 if (rta->rta_mp) { 277 if (attrs[RTA_MULTIPATH] &&
285 nhs = dn_fib_count_nhs(rta->rta_mp); 278 (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
286 if (nhs == 0) 279 goto err_inval;
287 goto err_inval;
288 }
289 280
290 fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL); 281 fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
291 err = -ENOBUFS; 282 err = -ENOBUFS;
@@ -295,53 +286,65 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
295 fi->fib_protocol = r->rtm_protocol; 286 fi->fib_protocol = r->rtm_protocol;
296 fi->fib_nhs = nhs; 287 fi->fib_nhs = nhs;
297 fi->fib_flags = r->rtm_flags; 288 fi->fib_flags = r->rtm_flags;
298 if (rta->rta_priority)
299 fi->fib_priority = *rta->rta_priority;
300 if (rta->rta_mx) {
301 int attrlen = RTA_PAYLOAD(rta->rta_mx);
302 struct rtattr *attr = RTA_DATA(rta->rta_mx);
303 289
304 while(RTA_OK(attr, attrlen)) { 290 if (attrs[RTA_PRIORITY])
305 unsigned int flavour = attr->rta_type; 291 fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
292
293 if (attrs[RTA_METRICS]) {
294 struct nlattr *attr;
295 int rem;
306 296
307 if (flavour) { 297 nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
308 if (flavour > RTAX_MAX) 298 int type = nla_type(attr);
299
300 if (type) {
301 if (type > RTAX_MAX || nla_len(attr) < 4)
309 goto err_inval; 302 goto err_inval;
310 fi->fib_metrics[flavour-1] = *(unsigned int *)RTA_DATA(attr); 303
304 fi->fib_metrics[type-1] = nla_get_u32(attr);
311 } 305 }
312 attr = RTA_NEXT(attr, attrlen);
313 } 306 }
314 } 307 }
315 if (rta->rta_prefsrc)
316 memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
317 308
318 if (rta->rta_mp) { 309 if (attrs[RTA_PREFSRC])
319 if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0) 310 fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
311
312 if (attrs[RTA_MULTIPATH]) {
313 if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
320 goto failure; 314 goto failure;
321 if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) 315
316 if (attrs[RTA_OIF] &&
317 fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
322 goto err_inval; 318 goto err_inval;
323 if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2)) 319
320 if (attrs[RTA_GATEWAY] &&
321 fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
324 goto err_inval; 322 goto err_inval;
325 } else { 323 } else {
326 struct dn_fib_nh *nh = fi->fib_nh; 324 struct dn_fib_nh *nh = fi->fib_nh;
327 if (rta->rta_oif) 325
328 nh->nh_oif = *rta->rta_oif; 326 if (attrs[RTA_OIF])
329 if (rta->rta_gw) 327 nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
330 memcpy(&nh->nh_gw, rta->rta_gw, 2); 328
329 if (attrs[RTA_GATEWAY])
330 nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
331
331 nh->nh_flags = r->rtm_flags; 332 nh->nh_flags = r->rtm_flags;
332 nh->nh_weight = 1; 333 nh->nh_weight = 1;
333 } 334 }
334 335
335 if (r->rtm_type == RTN_NAT) { 336 if (r->rtm_type == RTN_NAT) {
336 if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif) 337 if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
337 goto err_inval; 338 goto err_inval;
338 memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2); 339
340 fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
339 goto link_it; 341 goto link_it;
340 } 342 }
341 343
342 if (dn_fib_props[r->rtm_type].error) { 344 if (dn_fib_props[r->rtm_type].error) {
343 if (rta->rta_gw || rta->rta_oif || rta->rta_mp) 345 if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
344 goto err_inval; 346 goto err_inval;
347
345 goto link_it; 348 goto link_it;
346 } 349 }
347 350
@@ -367,8 +370,8 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
367 } 370 }
368 371
369 if (fi->fib_prefsrc) { 372 if (fi->fib_prefsrc) {
370 if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || 373 if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
371 memcmp(&fi->fib_prefsrc, rta->rta_dst, 2)) 374 fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
372 if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) 375 if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
373 goto err_inval; 376 goto err_inval;
374 } 377 }
@@ -486,29 +489,24 @@ void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
486 spin_unlock_bh(&dn_fib_multipath_lock); 489 spin_unlock_bh(&dn_fib_multipath_lock);
487} 490}
488 491
492const struct nla_policy rtm_dn_policy[RTA_MAX + 1] = {
493 [RTA_DST] = { .type = NLA_U16 },
494 [RTA_SRC] = { .type = NLA_U16 },
495 [RTA_IIF] = { .type = NLA_U32 },
496 [RTA_OIF] = { .type = NLA_U32 },
497 [RTA_GATEWAY] = { .type = NLA_U16 },
498 [RTA_PRIORITY] = { .type = NLA_U32 },
499 [RTA_PREFSRC] = { .type = NLA_U16 },
500 [RTA_METRICS] = { .type = NLA_NESTED },
501 [RTA_MULTIPATH] = { .type = NLA_NESTED },
502 [RTA_TABLE] = { .type = NLA_U32 },
503 [RTA_MARK] = { .type = NLA_U32 },
504};
489 505
490static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) 506static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
491{
492 int i;
493
494 for(i = 1; i <= RTA_MAX; i++) {
495 struct rtattr *attr = rta[i-1];
496 if (attr) {
497 if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
498 return -EINVAL;
499 if (i != RTA_MULTIPATH && i != RTA_METRICS &&
500 i != RTA_TABLE)
501 rta[i-1] = (struct rtattr *)RTA_DATA(attr);
502 }
503 }
504
505 return 0;
506}
507
508static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
509{ 507{
510 if (rta[RTA_TABLE - 1]) 508 if (attrs[RTA_TABLE])
511 table = nla_get_u32((struct nlattr *) rta[RTA_TABLE - 1]); 509 table = nla_get_u32(attrs[RTA_TABLE]);
512 510
513 return table; 511 return table;
514} 512}
@@ -517,8 +515,9 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
517{ 515{
518 struct net *net = sock_net(skb->sk); 516 struct net *net = sock_net(skb->sk);
519 struct dn_fib_table *tb; 517 struct dn_fib_table *tb;
520 struct rtattr **rta = arg; 518 struct rtmsg *r = nlmsg_data(nlh);
521 struct rtmsg *r = NLMSG_DATA(nlh); 519 struct nlattr *attrs[RTA_MAX+1];
520 int err;
522 521
523 if (!capable(CAP_NET_ADMIN)) 522 if (!capable(CAP_NET_ADMIN))
524 return -EPERM; 523 return -EPERM;
@@ -526,22 +525,24 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
526 if (!net_eq(net, &init_net)) 525 if (!net_eq(net, &init_net))
527 return -EINVAL; 526 return -EINVAL;
528 527
529 if (dn_fib_check_attr(r, rta)) 528 err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
530 return -EINVAL; 529 if (err < 0)
530 return err;
531 531
532 tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0); 532 tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
533 if (tb) 533 if (!tb)
534 return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); 534 return -ESRCH;
535 535
536 return -ESRCH; 536 return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
537} 537}
538 538
539static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 539static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
540{ 540{
541 struct net *net = sock_net(skb->sk); 541 struct net *net = sock_net(skb->sk);
542 struct dn_fib_table *tb; 542 struct dn_fib_table *tb;
543 struct rtattr **rta = arg; 543 struct rtmsg *r = nlmsg_data(nlh);
544 struct rtmsg *r = NLMSG_DATA(nlh); 544 struct nlattr *attrs[RTA_MAX+1];
545 int err;
545 546
546 if (!capable(CAP_NET_ADMIN)) 547 if (!capable(CAP_NET_ADMIN))
547 return -EPERM; 548 return -EPERM;
@@ -549,14 +550,15 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
549 if (!net_eq(net, &init_net)) 550 if (!net_eq(net, &init_net))
550 return -EINVAL; 551 return -EINVAL;
551 552
552 if (dn_fib_check_attr(r, rta)) 553 err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
553 return -EINVAL; 554 if (err < 0)
555 return err;
554 556
555 tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1); 557 tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
556 if (tb) 558 if (!tb)
557 return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); 559 return -ENOBUFS;
558 560
559 return -ENOBUFS; 561 return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
560} 562}
561 563
562static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) 564static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
@@ -566,10 +568,31 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad
566 struct nlmsghdr nlh; 568 struct nlmsghdr nlh;
567 struct rtmsg rtm; 569 struct rtmsg rtm;
568 } req; 570 } req;
569 struct dn_kern_rta rta; 571 struct {
572 struct nlattr hdr;
573 __le16 dst;
574 } dst_attr = {
575 .dst = dst,
576 };
577 struct {
578 struct nlattr hdr;
579 __le16 prefsrc;
580 } prefsrc_attr = {
581 .prefsrc = ifa->ifa_local,
582 };
583 struct {
584 struct nlattr hdr;
585 u32 oif;
586 } oif_attr = {
587 .oif = ifa->ifa_dev->dev->ifindex,
588 };
589 struct nlattr *attrs[RTA_MAX+1] = {
590 [RTA_DST] = (struct nlattr *) &dst_attr,
591 [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
592 [RTA_OIF] = (struct nlattr *) &oif_attr,
593 };
570 594
571 memset(&req.rtm, 0, sizeof(req.rtm)); 595 memset(&req.rtm, 0, sizeof(req.rtm));
572 memset(&rta, 0, sizeof(rta));
573 596
574 if (type == RTN_UNICAST) 597 if (type == RTN_UNICAST)
575 tb = dn_fib_get_table(RT_MIN_TABLE, 1); 598 tb = dn_fib_get_table(RT_MIN_TABLE, 1);
@@ -591,14 +614,10 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad
591 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); 614 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
592 req.rtm.rtm_type = type; 615 req.rtm.rtm_type = type;
593 616
594 rta.rta_dst = &dst;
595 rta.rta_prefsrc = &ifa->ifa_local;
596 rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
597
598 if (cmd == RTM_NEWROUTE) 617 if (cmd == RTM_NEWROUTE)
599 tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL); 618 tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
600 else 619 else
601 tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL); 620 tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
602} 621}
603 622
604static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa) 623static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 5ac0e153ef83..b4b3508e77f0 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1619,17 +1619,21 @@ errout:
1619static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) 1619static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
1620{ 1620{
1621 struct net *net = sock_net(in_skb->sk); 1621 struct net *net = sock_net(in_skb->sk);
1622 struct rtattr **rta = arg;
1623 struct rtmsg *rtm = nlmsg_data(nlh); 1622 struct rtmsg *rtm = nlmsg_data(nlh);
1624 struct dn_route *rt = NULL; 1623 struct dn_route *rt = NULL;
1625 struct dn_skb_cb *cb; 1624 struct dn_skb_cb *cb;
1626 int err; 1625 int err;
1627 struct sk_buff *skb; 1626 struct sk_buff *skb;
1628 struct flowidn fld; 1627 struct flowidn fld;
1628 struct nlattr *tb[RTA_MAX+1];
1629 1629
1630 if (!net_eq(net, &init_net)) 1630 if (!net_eq(net, &init_net))
1631 return -EINVAL; 1631 return -EINVAL;
1632 1632
1633 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_dn_policy);
1634 if (err < 0)
1635 return err;
1636
1633 memset(&fld, 0, sizeof(fld)); 1637 memset(&fld, 0, sizeof(fld));
1634 fld.flowidn_proto = DNPROTO_NSP; 1638 fld.flowidn_proto = DNPROTO_NSP;
1635 1639
@@ -1639,12 +1643,14 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
1639 skb_reset_mac_header(skb); 1643 skb_reset_mac_header(skb);
1640 cb = DN_SKB_CB(skb); 1644 cb = DN_SKB_CB(skb);
1641 1645
1642 if (rta[RTA_SRC-1]) 1646 if (tb[RTA_SRC])
1643 memcpy(&fld.saddr, RTA_DATA(rta[RTA_SRC-1]), 2); 1647 fld.saddr = nla_get_le16(tb[RTA_SRC]);
1644 if (rta[RTA_DST-1]) 1648
1645 memcpy(&fld.daddr, RTA_DATA(rta[RTA_DST-1]), 2); 1649 if (tb[RTA_DST])
1646 if (rta[RTA_IIF-1]) 1650 fld.daddr = nla_get_le16(tb[RTA_DST]);
1647 memcpy(&fld.flowidn_iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); 1651
1652 if (tb[RTA_IIF])
1653 fld.flowidn_iif = nla_get_u32(tb[RTA_IIF]);
1648 1654
1649 if (fld.flowidn_iif) { 1655 if (fld.flowidn_iif) {
1650 struct net_device *dev; 1656 struct net_device *dev;
@@ -1669,10 +1675,9 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
1669 if (!err && -rt->dst.error) 1675 if (!err && -rt->dst.error)
1670 err = rt->dst.error; 1676 err = rt->dst.error;
1671 } else { 1677 } else {
1672 int oif = 0; 1678 if (tb[RTA_OIF])
1673 if (rta[RTA_OIF - 1]) 1679 fld.flowidn_oif = nla_get_u32(tb[RTA_OIF]);
1674 memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); 1680
1675 fld.flowidn_oif = oif;
1676 err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0); 1681 err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0);
1677 } 1682 }
1678 1683
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 6c2445bcaba1..fc42a0afd306 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -224,26 +224,27 @@ static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
224} 224}
225 225
226 226
227static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi) 227static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct nlattr *attrs[], struct dn_fib_info *fi)
228{ 228{
229 struct rtnexthop *nhp; 229 struct rtnexthop *nhp;
230 int nhlen; 230 int nhlen;
231 231
232 if (rta->rta_priority && *rta->rta_priority != fi->fib_priority) 232 if (attrs[RTA_PRIORITY] &&
233 nla_get_u32(attrs[RTA_PRIORITY]) != fi->fib_priority)
233 return 1; 234 return 1;
234 235
235 if (rta->rta_oif || rta->rta_gw) { 236 if (attrs[RTA_OIF] || attrs[RTA_GATEWAY]) {
236 if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && 237 if ((!attrs[RTA_OIF] || nla_get_u32(attrs[RTA_OIF]) == fi->fib_nh->nh_oif) &&
237 (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0)) 238 (!attrs[RTA_GATEWAY] || nla_get_le16(attrs[RTA_GATEWAY]) != fi->fib_nh->nh_gw))
238 return 0; 239 return 0;
239 return 1; 240 return 1;
240 } 241 }
241 242
242 if (rta->rta_mp == NULL) 243 if (!attrs[RTA_MULTIPATH])
243 return 0; 244 return 0;
244 245
245 nhp = RTA_DATA(rta->rta_mp); 246 nhp = nla_data(attrs[RTA_MULTIPATH]);
246 nhlen = RTA_PAYLOAD(rta->rta_mp); 247 nhlen = nla_len(attrs[RTA_MULTIPATH]);
247 248
248 for_nexthops(fi) { 249 for_nexthops(fi) {
249 int attrlen = nhlen - sizeof(struct rtnexthop); 250 int attrlen = nhlen - sizeof(struct rtnexthop);
@@ -254,7 +255,10 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern
254 if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) 255 if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
255 return 1; 256 return 1;
256 if (attrlen) { 257 if (attrlen) {
257 gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); 258 struct nlattr *gw_attr;
259
260 gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
261 gw = gw_attr ? nla_get_le16(gw_attr) : 0;
258 262
259 if (gw && gw != nh->nh_gw) 263 if (gw && gw != nh->nh_gw)
260 return 1; 264 return 1;
@@ -517,7 +521,8 @@ out:
517 return skb->len; 521 return skb->len;
518} 522}
519 523
520static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) 524static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
525 struct nlmsghdr *n, struct netlink_skb_parms *req)
521{ 526{
522 struct dn_hash *table = (struct dn_hash *)tb->data; 527 struct dn_hash *table = (struct dn_hash *)tb->data;
523 struct dn_fib_node *new_f, *f, **fp, **del_fp; 528 struct dn_fib_node *new_f, *f, **fp, **del_fp;
@@ -536,15 +541,14 @@ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct
536 return -ENOBUFS; 541 return -ENOBUFS;
537 542
538 dz_key_0(key); 543 dz_key_0(key);
539 if (rta->rta_dst) { 544 if (attrs[RTA_DST]) {
540 __le16 dst; 545 __le16 dst = nla_get_le16(attrs[RTA_DST]);
541 memcpy(&dst, rta->rta_dst, 2);
542 if (dst & ~DZ_MASK(dz)) 546 if (dst & ~DZ_MASK(dz))
543 return -EINVAL; 547 return -EINVAL;
544 key = dz_key(dst, dz); 548 key = dz_key(dst, dz);
545 } 549 }
546 550
547 if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL) 551 if ((fi = dn_fib_create_info(r, attrs, n, &err)) == NULL)
548 return err; 552 return err;
549 553
550 if (dz->dz_nent > (dz->dz_divisor << 2) && 554 if (dz->dz_nent > (dz->dz_divisor << 2) &&
@@ -654,7 +658,8 @@ out:
654} 658}
655 659
656 660
657static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) 661static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
662 struct nlmsghdr *n, struct netlink_skb_parms *req)
658{ 663{
659 struct dn_hash *table = (struct dn_hash*)tb->data; 664 struct dn_hash *table = (struct dn_hash*)tb->data;
660 struct dn_fib_node **fp, **del_fp, *f; 665 struct dn_fib_node **fp, **del_fp, *f;
@@ -671,9 +676,8 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
671 return -ESRCH; 676 return -ESRCH;
672 677
673 dz_key_0(key); 678 dz_key_0(key);
674 if (rta->rta_dst) { 679 if (attrs[RTA_DST]) {
675 __le16 dst; 680 __le16 dst = nla_get_le16(attrs[RTA_DST]);
676 memcpy(&dst, rta->rta_dst, 2);
677 if (dst & ~DZ_MASK(dz)) 681 if (dst & ~DZ_MASK(dz))
678 return -EINVAL; 682 return -EINVAL;
679 key = dz_key(dst, dz); 683 key = dz_key(dst, dz);
@@ -703,7 +707,7 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
703 (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) && 707 (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
704 (!r->rtm_protocol || 708 (!r->rtm_protocol ||
705 fi->fib_protocol == r->rtm_protocol) && 709 fi->fib_protocol == r->rtm_protocol) &&
706 dn_fib_nh_match(r, n, rta, fi) == 0) 710 dn_fib_nh_match(r, n, attrs, fi) == 0)
707 del_fp = fp; 711 del_fp = fp;
708 } 712 }
709 713