aboutsummaryrefslogtreecommitdiffstats
path: root/net/decnet/dn_fib.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/decnet/dn_fib.c')
-rw-r--r--net/decnet/dn_fib.c203
1 files changed, 104 insertions, 99 deletions
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index e36614eccc04..57dc159245ec 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,39 +489,21 @@ 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
489 492static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
490static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
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{ 493{
510 if (rta[RTA_TABLE - 1]) 494 if (attrs[RTA_TABLE])
511 table = nla_get_u32((struct nlattr *) rta[RTA_TABLE - 1]); 495 table = nla_get_u32(attrs[RTA_TABLE]);
512 496
513 return table; 497 return table;
514} 498}
515 499
516static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 500static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
517{ 501{
518 struct net *net = sock_net(skb->sk); 502 struct net *net = sock_net(skb->sk);
519 struct dn_fib_table *tb; 503 struct dn_fib_table *tb;
520 struct rtattr **rta = arg; 504 struct rtmsg *r = nlmsg_data(nlh);
521 struct rtmsg *r = NLMSG_DATA(nlh); 505 struct nlattr *attrs[RTA_MAX+1];
506 int err;
522 507
523 if (!capable(CAP_NET_ADMIN)) 508 if (!capable(CAP_NET_ADMIN))
524 return -EPERM; 509 return -EPERM;
@@ -526,22 +511,24 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
526 if (!net_eq(net, &init_net)) 511 if (!net_eq(net, &init_net))
527 return -EINVAL; 512 return -EINVAL;
528 513
529 if (dn_fib_check_attr(r, rta)) 514 err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
530 return -EINVAL; 515 if (err < 0)
516 return err;
531 517
532 tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0); 518 tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
533 if (tb) 519 if (!tb)
534 return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); 520 return -ESRCH;
535 521
536 return -ESRCH; 522 return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
537} 523}
538 524
539static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 525static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
540{ 526{
541 struct net *net = sock_net(skb->sk); 527 struct net *net = sock_net(skb->sk);
542 struct dn_fib_table *tb; 528 struct dn_fib_table *tb;
543 struct rtattr **rta = arg; 529 struct rtmsg *r = nlmsg_data(nlh);
544 struct rtmsg *r = NLMSG_DATA(nlh); 530 struct nlattr *attrs[RTA_MAX+1];
531 int err;
545 532
546 if (!capable(CAP_NET_ADMIN)) 533 if (!capable(CAP_NET_ADMIN))
547 return -EPERM; 534 return -EPERM;
@@ -549,14 +536,15 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
549 if (!net_eq(net, &init_net)) 536 if (!net_eq(net, &init_net))
550 return -EINVAL; 537 return -EINVAL;
551 538
552 if (dn_fib_check_attr(r, rta)) 539 err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
553 return -EINVAL; 540 if (err < 0)
541 return err;
554 542
555 tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1); 543 tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
556 if (tb) 544 if (!tb)
557 return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); 545 return -ENOBUFS;
558 546
559 return -ENOBUFS; 547 return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
560} 548}
561 549
562static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) 550static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
@@ -566,10 +554,31 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad
566 struct nlmsghdr nlh; 554 struct nlmsghdr nlh;
567 struct rtmsg rtm; 555 struct rtmsg rtm;
568 } req; 556 } req;
569 struct dn_kern_rta rta; 557 struct {
558 struct nlattr hdr;
559 __le16 dst;
560 } dst_attr = {
561 .dst = dst,
562 };
563 struct {
564 struct nlattr hdr;
565 __le16 prefsrc;
566 } prefsrc_attr = {
567 .prefsrc = ifa->ifa_local,
568 };
569 struct {
570 struct nlattr hdr;
571 u32 oif;
572 } oif_attr = {
573 .oif = ifa->ifa_dev->dev->ifindex,
574 };
575 struct nlattr *attrs[RTA_MAX+1] = {
576 [RTA_DST] = (struct nlattr *) &dst_attr,
577 [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
578 [RTA_OIF] = (struct nlattr *) &oif_attr,
579 };
570 580
571 memset(&req.rtm, 0, sizeof(req.rtm)); 581 memset(&req.rtm, 0, sizeof(req.rtm));
572 memset(&rta, 0, sizeof(rta));
573 582
574 if (type == RTN_UNICAST) 583 if (type == RTN_UNICAST)
575 tb = dn_fib_get_table(RT_MIN_TABLE, 1); 584 tb = dn_fib_get_table(RT_MIN_TABLE, 1);
@@ -591,14 +600,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); 600 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
592 req.rtm.rtm_type = type; 601 req.rtm.rtm_type = type;
593 602
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) 603 if (cmd == RTM_NEWROUTE)
599 tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL); 604 tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
600 else 605 else
601 tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL); 606 tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
602} 607}
603 608
604static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa) 609static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)