aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2005-11-05 15:14:13 -0500
committerThomas Graf <tgr@axs.localdomain>2005-11-05 16:02:26 -0500
commit6639607ed9deaed9ab3a1cc588f0288891ece2ac (patch)
tree370e98cbb4143cf397d5b3cf2a3a8ddf66a13cf1 /net/sched
parente06368221c204d7b5f1ba37d047170f9a0dd359d (diff)
[PKT_SCHED]: GRED: Use a central table definition change procedure
Introduces a function gred_change_table_def() acting as a central point to change the table definition. Adds missing validations for table definition: MAX_DPs > DPs > 0 and def_DP < DPs thus fixing possible invalid memory reference oopses. Only root could do it but having a typo crashing the machine is a bit hard. Adds missing locking while changing the table definition, the operation of changing the number of DPs and removing shadowed VQs may not be interrupted by a dequeue. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/sch_gred.c113
1 files changed, 61 insertions, 52 deletions
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index a1369550ce78..fdc20ced52ef 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -378,43 +378,72 @@ static void gred_reset(struct Qdisc* sch)
378 } 378 }
379} 379}
380 380
381static int gred_change(struct Qdisc *sch, struct rtattr *opt) 381static inline void gred_destroy_vq(struct gred_sched_data *q)
382{
383 kfree(q);
384}
385
386static inline int gred_change_table_def(struct Qdisc *sch, struct rtattr *dps)
382{ 387{
383 struct gred_sched *table = qdisc_priv(sch); 388 struct gred_sched *table = qdisc_priv(sch);
384 struct gred_sched_data *q;
385 struct tc_gred_qopt *ctl;
386 struct tc_gred_sopt *sopt; 389 struct tc_gred_sopt *sopt;
387 struct rtattr *tb[TCA_GRED_STAB]; 390 int i;
388 struct rtattr *tb2[TCA_GRED_DPS];
389 391
390 if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) 392 if (dps == NULL || RTA_PAYLOAD(dps) < sizeof(*sopt))
391 return -EINVAL; 393 return -EINVAL;
392 394
393 if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) { 395 sopt = RTA_DATA(dps);
394 rtattr_parse_nested(tb2, TCA_GRED_DPS, opt);
395 396
396 if (tb2[TCA_GRED_DPS-1] == 0) 397 if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || sopt->def_DP >= sopt->DPs)
397 return -EINVAL; 398 return -EINVAL;
398 399
399 sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); 400 sch_tree_lock(sch);
400 table->DPs=sopt->DPs; 401 table->DPs = sopt->DPs;
401 table->def=sopt->def_DP; 402 table->def = sopt->def_DP;
402 403
403 if (sopt->grio) { 404 /*
404 gred_enable_rio_mode(table); 405 * Every entry point to GRED is synchronized with the above code
405 gred_disable_wred_mode(table); 406 * and the DP is checked against DPs, i.e. shadowed VQs can no
406 if (gred_wred_mode_check(sch)) 407 * longer be found so we can unlock right here.
407 gred_enable_wred_mode(table); 408 */
408 } else { 409 sch_tree_unlock(sch);
409 gred_disable_rio_mode(table);
410 gred_disable_wred_mode(table);
411 }
412 410
413 table->initd=0; 411 if (sopt->grio) {
414 /* probably need to clear all the table DP entries as well */ 412 gred_enable_rio_mode(table);
415 return 0; 413 gred_disable_wred_mode(table);
416 } 414 if (gred_wred_mode_check(sch))
415 gred_enable_wred_mode(table);
416 } else {
417 gred_disable_rio_mode(table);
418 gred_disable_wred_mode(table);
419 }
420
421 for (i = table->DPs; i < MAX_DPs; i++) {
422 if (table->tab[i]) {
423 printk(KERN_WARNING "GRED: Warning: Destroying "
424 "shadowed VQ 0x%x\n", i);
425 gred_destroy_vq(table->tab[i]);
426 table->tab[i] = NULL;
427 }
428 }
417 429
430 table->initd = 0;
431
432 return 0;
433}
434
435static int gred_change(struct Qdisc *sch, struct rtattr *opt)
436{
437 struct gred_sched *table = qdisc_priv(sch);
438 struct gred_sched_data *q;
439 struct tc_gred_qopt *ctl;
440 struct rtattr *tb[TCA_GRED_STAB];
441
442 if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt))
443 return -EINVAL;
444
445 if (tb[TCA_GRED_PARMS-1] == NULL && tb[TCA_GRED_STAB-1] == NULL)
446 return gred_change_table_def(sch, tb[TCA_GRED_DPS-1]);
418 447
419 if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 || 448 if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 ||
420 RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) || 449 RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) ||
@@ -526,35 +555,15 @@ static int gred_change(struct Qdisc *sch, struct rtattr *opt)
526 555
527static int gred_init(struct Qdisc *sch, struct rtattr *opt) 556static int gred_init(struct Qdisc *sch, struct rtattr *opt)
528{ 557{
529 struct gred_sched *table = qdisc_priv(sch); 558 struct rtattr *tb[TCA_GRED_MAX];
530 struct tc_gred_sopt *sopt;
531 struct rtattr *tb[TCA_GRED_STAB];
532 struct rtattr *tb2[TCA_GRED_DPS];
533 559
534 if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) 560 if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_MAX, opt))
535 return -EINVAL; 561 return -EINVAL;
536 562
537 if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) { 563 if (tb[TCA_GRED_PARMS-1] || tb[TCA_GRED_STAB-1])
538 rtattr_parse_nested(tb2, TCA_GRED_DPS, opt); 564 return -EINVAL;
539
540 if (tb2[TCA_GRED_DPS-1] == 0)
541 return -EINVAL;
542
543 sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
544 table->DPs=sopt->DPs;
545 table->def=sopt->def_DP;
546
547 if (sopt->grio)
548 gred_enable_rio_mode(table);
549 else
550 gred_disable_rio_mode(table);
551
552 table->initd=0;
553 return 0;
554 }
555 565
556 DPRINTK("\n GRED_INIT error!\n"); 566 return gred_change_table_def(sch, tb[TCA_GRED_DPS-1]);
557 return -EINVAL;
558} 567}
559 568
560static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) 569static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
@@ -641,7 +650,7 @@ static void gred_destroy(struct Qdisc *sch)
641 650
642 for (i = 0;i < table->DPs; i++) { 651 for (i = 0;i < table->DPs; i++) {
643 if (table->tab[i]) 652 if (table->tab[i])
644 kfree(table->tab[i]); 653 gred_destroy_vq(table->tab[i]);
645 } 654 }
646} 655}
647 656