Project

General

Profile

Download (117 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	shaper.inc
4
*/
5
/* ====================================================================
6
 *  Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
7
 *
8
 *  Some or all of this file is based on the m0n0wall project which is
9
 *  Copyright (c)  2004 Manuel Kasper (BSD 2 clause)
10
 *
11
 *  Redistribution and use in source and binary forms, with or without modification,
12
 *  are permitted provided that the following conditions are met:
13
 *
14
 *  1. Redistributions of source code must retain the above copyright notice,
15
 *      this list of conditions and the following disclaimer.
16
 *
17
 *  2. Redistributions in binary form must reproduce the above copyright
18
 *      notice, this list of conditions and the following disclaimer in
19
 *      the documentation and/or other materials provided with the
20
 *      distribution.
21
 *
22
 *  3. All advertising materials mentioning features or use of this software
23
 *      must display the following acknowledgment:
24
 *      "This product includes software developed by the pfSense Project
25
 *       for use in the pfSense software distribution. (http://www.pfsense.org/).
26
 *
27
 *  4. The names "pfSense" and "pfSense Project" must not be used to
28
 *       endorse or promote products derived from this software without
29
 *       prior written permission. For written permission, please contact
30
 *       coreteam@pfsense.org.
31
 *
32
 *  5. Products derived from this software may not be called "pfSense"
33
 *      nor may "pfSense" appear in their names without prior written
34
 *      permission of the Electric Sheep Fencing, LLC.
35
 *
36
 *  6. Redistributions of any form whatsoever must retain the following
37
 *      acknowledgment:
38
 *
39
 *  "This product includes software developed by the pfSense Project
40
 *  for use in the pfSense software distribution (http://www.pfsense.org/).
41
 *
42
 *  THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
43
 *  EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
45
 *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
46
 *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
49
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
51
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
53
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
54
 *
55
 *  ====================================================================
56
 *
57
 */
58

    
59
/* XXX: needs some reducing on include. */
60
/* include all configuration functions. */
61
require_once("globals.inc");
62
require_once("functions.inc");
63
require_once("util.inc");
64
require_once("notices.inc");
65

    
66
/*
67
 * I admit :) this is derived from xmlparse.inc StartElement()
68
 */
69
function &get_reference_to_me_in_config(&$mypath) {
70
	global $config;
71

    
72
	$ptr =& $config['shaper'];
73
	foreach ($mypath as $indeks) {
74
		$ptr =& $ptr['queue'][$indeks];
75
	}
76

    
77
	return $ptr;
78
}
79

    
80
function unset_object_by_reference(&$mypath) {
81
	global $config;
82

    
83
	$ptr =& $config['shaper'];
84
	for ($i = 0; $i < count($mypath) - 1; $i++) {
85
		$ptr =& $ptr['queue'][$mypath[$i]];
86
	}
87
	unset($ptr['queue'][$mypath[$i]]);
88
}
89

    
90
function &get_dn_reference_to_me_in_config(&$mypath) {
91
	global $config;
92

    
93
	$ptr =& $config['dnshaper'];
94
	foreach ($mypath as $indeks) {
95
		$ptr =& $ptr['queue'][$indeks];
96
	}
97

    
98
	return $ptr;
99
}
100

    
101
function unset_dn_object_by_reference(&$mypath) {
102
	global $config;
103

    
104
	$ptr =& $config['dnshaper'];
105
	for ($i = 0; $i < count($mypath) - 1; $i++) {
106
		$ptr =& $ptr['queue'][$mypath[$i]];
107
	}
108
	unset($ptr['queue'][$mypath[$i]]);
109
}
110

    
111
function clean_child_queues($type, $mypath) {
112
	$ref = &get_reference_to_me_in_config($mypath);
113

    
114
	switch ($type) {
115
		case 'HFSC':
116
			if (isset($ref['borrow'])) {
117
				unset($ref['borrow']);
118
			}
119
			if (isset($ref['hogs'])) {
120
				unset($ref['hogs']);
121
			}
122
			if (isset($ref['buckets'])) {
123
				unset($ref['buckets']);
124
			}
125
			break;
126
		case 'PRIQ':
127
			if (isset($ref['borrow'])) {
128
				unset($ref['borrow']);
129
			}
130
			if (isset($ref['bandwidth'])) {
131
				unset($ref['bandwidth']);
132
			}
133
			if (isset($ref['bandwidthtype'])) {
134
				unset($ref['bandwidthtype']);
135
			}
136
			/* fall through */
137
		case 'FAIRQ':
138
			if (isset($ref['borrow'])) {
139
				unset($ref['borrow']);
140
			}
141
			/* fall through */
142
		case 'CBQ':
143
			if (isset($ref['realtime'])) {
144
				unset($ref['realtime']);
145
			}
146
			if (isset($ref['realtime1'])) {
147
				unset($ref['realtime1']);
148
			}
149
			if (isset($ref['realtime2'])) {
150
				unset($ref['realtime2']);
151
			}
152
			if (isset($ref['realtime3'])) {
153
				unset($ref['realtime3']);
154
			}
155
			if (isset($ref['upperlimit'])) {
156
				unset($ref['upperlimit']);
157
			}
158
			if (isset($ref['upperlimit1'])) {
159
				unset($ref['upperlimit1']);
160
			}
161
			if (isset($ref['upperlimit2'])) {
162
				unset($ref['upperlimit2']);
163
			}
164
			if (isset($ref['upperlimit3'])) {
165
				unset($ref['upperlimit3']);
166
			}
167
			if (isset($ref['linkshare'])) {
168
				unset($ref['linkshare']);
169
			}
170
			if (isset($ref['linkshare1'])) {
171
				unset($ref['linkshare1']);
172
			}
173
			if (isset($ref['linkshare2'])) {
174
				unset($ref['linkshare2']);
175
			}
176
			if (isset($ref['linkshare3'])) {
177
				unset($ref['linkshare3']);
178
			}
179
			if (isset($ref['hogs'])) {
180
				unset($ref['hogs']);
181
			}
182
			if (isset($ref['buckets'])) {
183
				unset($ref['buckets']);
184
			}
185
			break;
186
	}
187
}
188

    
189
function get_bandwidthtype_scale($type) {
190
	switch ($type) {
191
		case "Gb":
192
			$factor = 1024 * 1024 * 1024;
193
			break;
194
		case "Mb":
195
			$factor = 1024 * 1024;
196
			break;
197
		case "Kb":
198
			$factor = 1024;
199
			break;
200
		case "b":
201
		default:
202
			$factor = 1;
203
			break;
204
	}
205
	return intval($factor);
206
}
207

    
208
function get_bandwidth($bw, $scale, $obj) {
209

    
210
	$pattern= "/(b|Kb|Mb|Gb|%)/";
211
	if (!preg_match($pattern, $scale, $match))
212
		return 0;
213

    
214
	switch ($match[1]) {
215
		case '%':
216
			$objbw = ($bw / 100) * get_queue_bandwidth($obj);
217
			break;
218
		default:
219
			$objbw = $bw * get_bandwidthtype_scale($scale);
220
			break;
221
	}
222

    
223
	return floatval($objbw);
224
}
225

    
226
/*
227
 * XXX - unused
228
 *
229
function get_hfsc_bandwidth($object, $bw) {
230
	$pattern= "/[0-9]+/";
231
	if (preg_match($pattern, $bw, $match)) {
232
		$bw_1 = $match[1];
233
	} else {
234
		return 0;
235
	}
236
	$pattern= "/(b|Kb|Mb|Gb|%)/";
237
	if (preg_match($pattern, $bw, $match)) {
238
		switch ($match[1]) {
239
			case '%':
240
				$bw_1 = ($bw_1 / 100) * get_interface_bandwidth($object);
241
				break;
242
			default:
243
				$bw_1 = $bw_1 * get_bandwidthtype_scale($match[0]);
244
				break;
245
		}
246
		return floatval($bw_1);
247
	} else {
248
		return 0;
249
	}
250
}
251
*/
252

    
253
function get_queue_bandwidth($obj) {
254
	$bw = $obj->GetBandwidth();
255
	$scale = $obj->GetBwscale();
256

    
257
	$pattern= "/(b|Kb|Mb|Gb|%)/";
258
	if (!preg_match($pattern, $scale, $match))
259
		return 0;
260

    
261
	switch ($match[1]) {
262
		case '%':
263
			$objbw = ($bw / 100) * get_queue_bandwidth($obj->GetParent());
264
			break;
265
		default:
266
			$objbw = $bw * get_bandwidthtype_scale($scale);
267
			break;
268
	}
269

    
270
	return floatval($objbw);
271
}
272

    
273
function get_interface_bandwidth($object) {
274
	global $altq_list_queues;
275

    
276
	$int = $object->GetInterface();
277
	$altq =& $altq_list_queues[$int];
278
	if ($altq) {
279
		$bw_3 = $altq->GetBandwidth();
280
		$bw_3 = $bw_3 * get_bandwidthtype_scale($altq->GetBwscale());
281
		return floatval($bw_3);
282
	} else {
283
		return 0;
284
	}
285
}
286

    
287
/*
288
 * This is duplicated here since we cannot include guiconfig.inc.
289
 * Including it makes all stuff break.
290
 */
291
function shaper_do_input_validation($postdata, $reqdfields, $reqdfieldsn, $input_errors) {
292

    
293
	/* check for bad control characters */
294
	foreach ($postdata as $pn => $pd) {
295
		if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
296
			$input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $pn);
297
		}
298
	}
299

    
300
	for ($i = 0; $i < count($reqdfields); $i++) {
301
		if ($postdata[$reqdfields[$i]] == "") {
302
			$input_errors[] = sprintf(gettext("The field '%s' is required."), $reqdfieldsn[$i]);
303
		}
304
	}
305
}
306

    
307
function cleanup_queue_from_rules($queue) {
308
	global $config;
309

    
310
	foreach ($config['filter']['rule'] as $rule) {
311
		if ($rule['defaultqueue'] == $queue) {
312
			unset($rule['defaultqueue']);
313
		}
314
		if ($rule['ackqueue'] == $queue) {
315
			unset($rule['ackqueue']);
316
		}
317
	}
318
}
319

    
320
function cleanup_dnqueue_from_rules($queue) {
321
	global $config;
322

    
323
	foreach ($config['filter']['rule'] as $rule) {
324
		if ($rule['dnpipe'] == $queue) {
325
			unset($rule['dnpipe']);
326
		}
327
		if ($rule['pdnpipe'] == $queue) {
328
			unset($rule['pdnpipe']);
329
		}
330
	}
331
}
332

    
333
class altq_root_queue {
334
	var $interface;
335
	var $tbrconfig ;
336
	var $bandwidth;
337
	var $bandwidthtype; /* b, Kb, Mb, Gb, % */
338
	var $scheduler;
339
	var $qlimit;
340
	var $queues = array();
341
	var $qenabled = false;
342
	var $link;
343

    
344
	/* Accessor functions */
345
	function GetDefaultQueuePresent() {
346
		if (!empty($this->queues)) {
347
			foreach ($this->queues as $q) {
348
				if ($q->GetDefault()) {
349
					return true;
350
				}
351
			}
352
		}
353

    
354
		return false;
355
	}
356
	function SetLink($link) {
357
		$this->link = $link;
358
	}
359
	function GetLink() {
360
		return $this->link;
361
	}
362
	function GetEnabled() {
363
		return $this->qenabled;
364
	}
365
	function SetEnabled($value) {
366
		$this->qenabled = $value;
367
	}
368
	function CanHaveChildren() {
369
		if ($this->GetScheduler() == "CODELQ") {
370
			return false;
371
		} else {
372
			return true;
373
		}
374
	}
375
	function CanBeDeleted() {
376
		return false;
377
	}
378
	function GetQname() {
379
		return $this->interface;
380
	}
381
	function SetQname($name) {
382
		$this->interface = trim($name);
383
	}
384
	function GetInterface() {
385
		return $this->interface;
386
	}
387
	function SetInterface($name) {
388
		$this->interface = trim($name);
389
	}
390
	function GetTbrConfig() {
391
		return $this->tbrconfig;
392
	}
393
	function SetTbrConfig($tbrconfig) {
394
		$this->tbrconfig = $tbrconfig;
395
	}
396
	function GetBandwidth() {
397
		return $this->bandwidth;
398
	}
399
	function SetBandwidth($bw) {
400
		$this->bandwidth = $bw;
401
	}
402
	function GetBwscale() {
403
		return $this->bandwidthtype;
404
	}
405
	function SetBwscale($bwscale) {
406
		$this->bandwidthtype = $bwscale;
407
	}
408
	function GetScheduler() {
409
		return $this->scheduler;
410
	}
411
	function SetScheduler($scheduler) {
412
		$this->scheduler = trim($scheduler);
413
	}
414
	function GetQlimit() {
415
		return $this->qlimit;
416
	}
417
	function SetQlimit($limit) {
418
		$this->qlimit = $limit;
419
	}
420

    
421
	function GetBwscaleText() {
422
		switch ($this->bandwidthtype) {
423
			case "b":
424
				$bwscaletext = "Bit/s";
425
				break;
426
			case "Kb":
427
				$bwscaletext = "Kbit/s";
428
				break;
429
			case "Mb":
430
				$bwscaletext = "Mbit/s";
431
				break;
432
			case "Gb":
433
				$bwscaletext = "Gbit/s";
434
				break;
435
			default:
436
				/* For others that do not need translating like % */
437
				$bwscaletext = $this->bandwidthtype;
438
				break;
439
		}
440
		return $bwscaletext;
441
	}
442

    
443
	function CheckBandwidth($bw, $bwtype) {
444
		$sum = $this->GetTotalBw();
445
		if ($sum > $bw * get_bandwidthtype_scale($bwtype))
446
			return 1;
447
		foreach ($this->queues as $q) {
448
			if ($q->CheckBandwidth(0, ''))
449
				return 1;
450
		}
451

    
452
		return 0;
453
	}
454

    
455
	function GetTotalBw($qignore = NULL) {
456
		$sum = 0;
457
		foreach ($this->queues as $q) {
458
			if ($qignore != NULL && $qignore == $q)
459
				continue;
460
			$sum += get_bandwidth($q->GetBandwidth(), $q->GetBwscale(), $this);
461
		}
462

    
463
		return $sum;
464
	}
465

    
466
	function validate_input($data, &$input_errors) {
467

    
468
		$reqdfields[] = "bandwidth";
469
		$reqdfieldsn[] = gettext("Bandwidth");
470
		$reqdfields[] = "bandwidthtype";
471
		$reqdfieldsn[] = gettext("Bandwidthtype");
472

    
473
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
474

    
475
		if (!isset($data['bandwidth']) || strlen($data['bandwidth']) == 0) {
476
			$input_errors[] = gettext("Bandwidth must be set.  This is usually the interface speed.");
477
		}
478
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
479
			$input_errors[] = gettext("Bandwidth must be an integer.");
480
		}
481
		if ($data['bandwidth'] < 0) {
482
			$input_errors[] = gettext("Bandwidth cannot be negative.");
483
		}
484
		if ($data['bandwidthtype'] == "%") {
485
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
486
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100.");
487
			}
488
		}
489
		if ($this->CheckBandwidth($data['bandwidth'], $data['bandwidthtype']))
490
			$input_errors[] = "The sum of child bandwidth is higher than parent.";
491

    
492
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
493
			$input_errors[] = gettext("Qlimit must be an integer.");
494
		}
495
		if ($data['qlimit'] < 0) {
496
			$input_errors[] = gettext("Qlimit must be positive.");
497
		}
498
		if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig']))) {
499
			$input_errors[] = gettext("Tbrsize must be an integer.");
500
		}
501
		if ($data['tbrconfig'] < 0) {
502
			$input_errors[] = gettext("Tbrsize must be positive.");
503
		}
504
	}
505

    
506
	/* Implement this to shorten some code on the frontend page */
507
	function ReadConfig(&$conf) {
508
		if (isset($conf['tbrconfig'])) {
509
			$this->SetTbrConfig($conf['tbrconfig']);
510
		} else {
511
			$this->SetTbrConfig($conf['tbrconfig']);
512
		}
513
		$this->SetBandwidth($conf['bandwidth']);
514
		if ($conf['bandwidthtype'] <> "") {
515
			$this->SetBwscale($conf['bandwidthtype']);
516
		}
517
		if (isset($conf['scheduler'])) {
518
			if ($this->GetScheduler() != $conf['scheduler']) {
519
				foreach ($this->queues as $q) {
520
					clean_child_queues($conf['scheduler'], $this->GetLink());
521
					$q->clean_queue($conf['scheduler']);
522
				}
523
			}
524
			$this->SetScheduler($conf['scheduler']);
525
		}
526
		if (isset($conf['qlimit']) && $conf['qlimit'] <> "") {
527
			$this->SetQlimit($conf['qlimit']);
528
		} else {
529
			$this->SetQlimit("");
530
		}
531
		if (isset($conf['name'])) {
532
			$this->SetQname($conf['name']);
533
		}
534
		if (!empty($conf['enabled'])) {
535
			$this->SetEnabled($conf['enabled']);
536
		} else {
537
			$this->SetEnabled("");
538
		}
539
	}
540

    
541
	function copy_queue($interface, &$cflink) {
542
		$cflink['interface'] = $interface;
543
		$cflink['name'] = $interface;
544
		$cflink['scheduler'] = $this->GetScheduler();
545
		$cflink['bandwidth'] = $this->GetBandwidth();
546
		$cflink['bandwidthtype'] = $this->GetBwscale();
547
		$cflink['qlimit'] = $this->GetQlimit();
548
		$cflink['tbrconfig'] = $this->GetTbrConfig();
549
		$cflink['enabled'] = $this->GetEnabled();
550
		if (is_array($this->queues)) {
551
			$cflink['queue'] = array();
552
			foreach ($this->queues as $q) {
553
				$cflink['queue'][$q->GetQname()] = array();
554
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
555
			}
556
		}
557
	}
558

    
559
	function &get_queue_list(&$q = null) {
560
		$qlist = array();
561

    
562
		//$qlist[$this->GetQname()] = & $this;
563
		if (is_array($this->queues)) {
564
			foreach ($this->queues as $queue) {
565
				$queue->get_queue_list($qlist);
566
			}
567
		}
568
		return $qlist;
569
	}
570

    
571
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
572

    
573
		if (!is_array($this->queues)) {
574
			$this->queues = array();
575
		}
576

    
577
		switch ($this->GetScheduler()) {
578
			case "PRIQ":
579
				$q =& new priq_queue();
580
				break;
581
			case "HFSC":
582
				$q =& new hfsc_queue();
583
				break;
584
			case "CBQ":
585
				$q =& new cbq_queue();
586
				break;
587
			case "FAIRQ":
588
				$q =& new fairq_queue();
589
				break;
590
			default:
591
				/* XXX: but should not happen anyway */
592
				return;
593
				break;
594
		}
595
		$q->SetLink($path);
596
		$q->SetInterface($this->GetInterface());
597
		$q->SetEnabled("on");
598
		$q->SetParent($this);
599
		$q->ReadConfig($queue);
600
		$q->validate_input($queue, $input_errors);
601

    
602
		$this->queues[$q->GetQname()] = &$q;
603
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
604
		if (is_array($queue['queue'])) {
605
			foreach ($queue['queue'] as $key1 => $que) {
606
				array_push($path, $key1);
607
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
608
				array_pop($path);
609
			}
610
		}
611

    
612
		return $q;
613
	}
614

    
615
	/* interface here might be optional */
616
	function &find_queue($interface, $qname) {
617
		if ($qname == $this->GetQname()) {
618
			return $this;
619
		}
620
		foreach ($this->queues as $q) {
621
			$result =& $q->find_queue("", $qname);
622
			if ($result) {
623
				return $result;
624
			}
625
		}
626
	}
627

    
628
	function &find_parentqueue($interface, $qname) {
629
		if ($qname == $interface) {
630
			$result = NULL;
631
		} else if ($this->queues[$qname]) {
632
			$result = $this;
633
		} else if ($this->GetScheduler() <> "PRIQ") {
634
			foreach ($this->queues as $q) {
635
				$result = $q->find_parentqueue("", $qname);
636
				if ($result) {
637
					return $result;
638
				}
639
			}
640
		}
641
	}
642

    
643
	function build_tree() {
644
		global $shaperIFlist;
645

    
646
		$tree = " <li><a href=\"firewall_shaper.php?interface=".$this->GetInterface()."&amp;queue=". $this->GetInterface()."&amp;action=show";
647
		$tree .= "\">" . $shaperIFlist[$this->GetInterface()] . "</a>";
648
		if (is_array($this->queues)) {
649
			$tree .= "<ul>";
650
			foreach ($this->queues as $q) {
651
				$tree .= $q->build_tree();
652
			}
653
			$tree .= "</ul>";
654
		}
655
		$tree .= "</li>";
656
		return $tree;
657
	}
658

    
659
	function delete_queue() {
660
		foreach ($this->queues as $q)
661
			$q->delete_queue();
662
		unset_object_by_reference($this->GetLink());
663
	}
664

    
665
	function delete_all() {
666
		if (count($this->queues)) {
667
			foreach ($this->queues as $q) {
668
				$q->delete_all();
669
				unset_object_by_reference($q->GetLink());
670
				unset($q);
671
			}
672
			unset($this->queues);
673
		}
674
	}
675

    
676
	/*
677
	 * First it spits:
678
	 * altq on $interface ..............
679
	 *	then it goes like
680
	 *	foreach ($queues as $qkey => $queue) {
681
	 *		this->queues[$qkey]->build_rule();
682
	 *	}
683
	 */
684
	function build_rules(&$default = false) {
685
		if (count($this->queues) > 0 && $this->GetEnabled() == "on") {
686
			$default = false;
687
			$rules = " altq on " . get_real_interface($this->GetInterface());
688
			if ($this->GetScheduler()) {
689
				$rules .= " ".strtolower($this->GetScheduler());
690
			}
691
			if ($this->GetQlimit() > 0) {
692
				$rules .= " qlimit " . $this->GetQlimit() . " ";
693
			}
694
			if ($this->GetBandwidth()) {
695
				$rules .= " bandwidth ".trim($this->GetBandwidth());
696
				if ($this->GetBwscale()) {
697
					$rules .= $this->GetBwscale();
698
				}
699
			}
700
			if ($this->GetTbrConfig()) {
701
				$rules .= " tbrsize ".$this->GetTbrConfig();
702
			}
703
			if (count($this->queues)) {
704
				$i = count($this->queues);
705
				$rules .= " queue { ";
706
				foreach ($this->queues as $qkey => $qnone) {
707
					if ($i > 1) {
708
						$i--;
709
						$rules .= " {$qkey}, ";
710
					} else {
711
						$rules .= " {$qkey} ";
712
					}
713
				}
714
				$rules .= " } \n";
715
				foreach ($this->queues as $q) {
716
					$rules .= $q->build_rules($default);
717
				}
718
			}
719

    
720
			if ($default == false) {
721
				$error = sprintf(gettext("SHAPER: no default queue specified for interface %s."), $this->GetInterface()) . " " . gettext("The interface queue will be enforced as default.");
722
				file_notice("Shaper", $error, "Error occurred", "");
723
				unset($error);
724
				return "\n";
725
			}
726
			$frule .= $rules;
727
		} else if ($this->GetEnabled() == "on" && $this->GetScheduler() == "CODELQ") {
728
			$rules = " altq on " . get_real_interface($this->GetInterface());
729
			if ($this->GetScheduler()) {
730
				$rules .= " ".strtolower($this->GetScheduler());
731
			}
732
			if ($this->GetQlimit() > 0) {
733
				$rules .= " ( qlimit " . $this->GetQlimit() . " ) ";
734
			}
735
			if ($this->GetBandwidth()) {
736
				$rules .= " bandwidth ".trim($this->GetBandwidth());
737
				if ($this->GetBwscale()) {
738
					$rules .= $this->GetBwscale();
739
				}
740
			}
741
			if ($this->GetTbrConfig()) {
742
				$rules .= " tbrsize ".$this->GetTbrConfig();
743
			}
744

    
745
			$rules .= " queue";
746
		}
747

    
748
		$rules .= " \n";
749
		return $rules;
750
	}
751

    
752
	function build_javascript() {
753
		$javascript = "<script type=\"text/javascript\">";
754
		$javascript .= "//<![CDATA[\n";
755
		$javascript .= "function mySuspend() {";
756
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
757
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden'; ";
758
		$javascript .= "else if (document.all)";
759
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
760
		$javascript .= "}";
761

    
762
		$javascript .= "function myResume() {";
763
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
764
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';";
765
		$javascript .= "else if (document.all) ";
766
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';";
767
		$javascript .= "}";
768
		$javascript .= "//]]>";
769
		$javascript .= "</script>";
770

    
771
		return $javascript;
772
	}
773

    
774
	function build_shortform() {
775
		global $g;
776

    
777
		$altq =& $this;
778

    
779
		if ($altq) {
780
			$scheduler = ": " . $altq->GetScheduler();
781
		}
782

    
783
		$form = '<dl class="dl-horizontal">';
784
		$form .= '	<dt>';
785
		$form .= '		<a href="firewall_shaper.php?interface=' . $this->GetInterface() . '&amp;queue=' . $this->GetQname() . '&amp;action=show">' . $shaperIFlist[$this->GetInterface()] . '</a>';
786
		$form .= '	</dt>';
787
		$form .= '	<dd>';
788
		$form .=		$scheduler;
789
		$form .= '	</dd>';
790

    
791
		$form .= '	<dt>';
792
		$form .=		'Bandwidth';
793
		$form .= '	</dt>';
794
		$form .= '	<dd>';
795
		$form .=		$this->GetBandwidth() . '&nbsp;' . $this->GetBwscaleText();
796
		$form .= '	</dd>';
797

    
798
		$form .= '	<dt>';
799
		$form .= 'Disable';
800
		$form .= '	<dt>';
801
		$form .= '	<dd>';
802

    
803
		$form .= '<a class="btn btn-danger btn-xs" href="firewall_shaper_queues.php?interface=';
804
		$form .= $this->GetInterface() . '&amp;queue=';
805
		$form .= $this->GetQname() . '&amp;action=delete">';
806
		$form .= '<i class="fa fa-trash icon-embed-btn"></i>';
807
		$form .= gettext("Remove shaper from this interface") . '</a>';
808

    
809
		$form .= '	</dd>';
810

    
811
		$form .= '</dl>';
812

    
813
		return $form;
814

    
815
	}
816

    
817
	/*
818
	 * For requesting the parameters of the root queues
819
	 * to the user like the traffic wizard does.
820
	 */
821
	function build_form() {
822

    
823
		$sform = new Form();
824

    
825
		$sform->setAction("firewall_shaper.php");
826

    
827
		$section = new Form_Section(null);
828

    
829
		$section->addInput(new Form_Checkbox(
830
			'enabled',
831
			'Enable/Disable',
832
			'Enable/disable discipline and its children',
833
			($this->GetEnabled() == "on"),
834
			'on'
835
		));
836

    
837
		$section->addInput(new Form_StaticText(
838
			'Name',
839
			$this->GetQname()
840
		));
841

    
842
		$section->addInput(new Form_Select(
843
			'scheduler',
844
			'Scheduler Type',
845
			$this->GetScheduler(),
846
			array('HFSC' => 'HFSC',
847
				  'CBQ' => 'CBQ',
848
				  'FAIRQ' => 'FAIRQ',
849
				  'CODELQ' => 'CODELQ',
850
				  'PRIQ' => 'PRIQ')
851
		))->setHelp('Changing this changes all child queues! Beware information can be lost.');
852

    
853
		$group = new Form_group('Bandwidth');
854

    
855
		$group->add(new Form_Input(
856
			'bandwidth',
857
			null,
858
			'number',
859
			$this->GetBandwidth()
860
		));
861

    
862
		$group->add(new Form_Select(
863
			'bandwidthtype',
864
			null,
865
			$this->GetBwscale(),
866
			array('Kb' => 'Kbit/s',
867
				  'Mb' => 'Mbit/s',
868
				  'Gb' => 'Gbit/s',
869
				  'b' => 'Bit/s',
870
				  '%' => '%')
871
		));
872

    
873
		$section->add($group);
874

    
875
		$section->addInput(new Form_Input(
876
			'qlimit',
877
			'Queue Limit',
878
			'number',
879
			$this->GetQlimit()
880
		));
881

    
882
		$section->addInput(new Form_Input(
883
			'tbrconfig',
884
			'TBR Size',
885
			'number',
886
			$this->GetTbrConfig()
887
		))->setHelp('Adjusts the size, in bytes, of the token bucket regulator. If not specified, heuristics based on the interface ' .
888
					'bandwidth are used to determine the size.');
889

    
890
		$section->addInput(new Form_Input(
891
			'interface',
892
			null,
893
			'hidden',
894
			$this->GetInterface()
895
		));
896

    
897
		$section->addInput(new Form_Input(
898
			'name',
899
			null,
900
			'hidden',
901
			$this->GetQname()
902
		));
903

    
904
		$sform->add($section);
905

    
906
		return($sform);
907
	}
908

    
909
	function update_altq_queue_data(&$data) {
910
		$this->ReadConfig($data);
911
	}
912

    
913
	/*
914
	 * Should call on each of it queues and subqueues
915
	 * the same function much like build_rules();
916
	 */
917
	function wconfig() {
918
		$cflink = &get_reference_to_me_in_config($this->GetLink());
919
		if (!is_array($cflink)) {
920
			$cflink = array();
921
		}
922
		$cflink['interface'] = $this->GetInterface();
923
		$cflink['name'] = $this->GetQname();
924
		$cflink['scheduler'] = $this->GetScheduler();
925
		$cflink['bandwidth'] = $this->GetBandwidth();
926
		$cflink['bandwidthtype'] = $this->GetBwscale();
927
		$cflink['qlimit'] = trim($this->GetQlimit());
928
		if (empty($cflink['qlimit'])) {
929
			unset($cflink['qlimit']);
930
		}
931
		$cflink['tbrconfig'] = trim($this->GetTbrConfig());
932
		if (empty($cflink['tbrconfig'])) {
933
			unset($cflink['tbrconfig']);
934
		}
935
		$cflink['enabled'] = $this->GetEnabled();
936
		if (empty($cflink['enabled'])) {
937
			unset($cflink['enabled']);
938
		}
939
	}
940

    
941
}
942

    
943
class priq_queue {
944
	var $qname;
945
	var $qinterface;
946
	var $qlimit;
947
	var $qpriority;
948
	var $description;
949
	var $isparent;
950
	var $qbandwidth;
951
	var $qbandwidthtype;
952
	var $qdefault = "";
953
	var $qrio = "";
954
	var $qred = "";
955
	var $qcodel = "";
956
	var $qecn = "";
957
	var $qack;
958
	var $qenabled = "";
959
	var $qparent;
960
	var $link;
961

    
962
	/* This is here to help with form building and building rules/lists */
963
	var $subqueues = array();
964

    
965
	/* Accessor functions */
966
	function SetLink($link) {
967
		$this->link = $link;
968
	}
969
	function GetLink() {
970
		return $this->link;
971
	}
972
	function &GetParent() {
973
		return $this->qparent;
974
	}
975
	function SetParent(&$parent) {
976
		$this->qparent = &$parent;
977
	}
978
	function GetEnabled() {
979
		return $this->qenabled;
980
	}
981
	function SetEnabled($value) {
982
		$this->qenabled = $value;
983
	}
984
	function CanHaveChildren() {
985
		return false;
986
	}
987
	function CanBeDeleted() {
988
		return true;
989
	}
990
	function GetQname() {
991
		return $this->qname;
992
	}
993
	function SetQname($name) {
994
		$this->qname = trim($name);
995
	}
996
	function GetBandwidth() {
997
		return $this->qbandwidth;
998
	}
999
	function SetBandwidth($bandwidth) {
1000
		$this->qbandwidth = $bandwidth;
1001
	}
1002
	function GetInterface() {
1003
		return $this->qinterface;
1004
	}
1005
	function SetInterface($name) {
1006
		$this->qinterface = trim($name);
1007
	}
1008
	function GetQlimit() {
1009
		return $this->qlimit;
1010
	}
1011
	function SetQlimit($limit) {
1012
		$this->qlimit = $limit;
1013
	}
1014
	function GetQpriority() {
1015
		return $this->qpriority;
1016
	}
1017
	function SetQpriority($priority) {
1018
		$this->qpriority = $priority;
1019
	}
1020
	function GetDescription() {
1021
		return $this->description;
1022
	}
1023
	function SetDescription($str) {
1024
		$this->description = trim($str);
1025
	}
1026
	function GetFirstime() {
1027
		return $this->firsttime;
1028
	}
1029
	function SetFirsttime($number) {
1030
		$this->firsttime = $number;
1031
	}
1032
	function CheckBandwidth($bw, $bwtype) {
1033
		$parent = $this->GetParent();
1034
		$sum = $parent->GetTotalBw(($bw > 0) ? $this : NULL);
1035
		if ($bw > 0)
1036
			$sum += get_bandwidth($bw, $bwtype, $parent);
1037
		if ($sum > get_queue_bandwidth($parent))
1038
			return 1;
1039

    
1040
		foreach ($this->subqueues as $q) {
1041
			if ($q->CheckBandwidth(0, ''))
1042
				return 1;
1043
		}
1044

    
1045
		return 0;
1046
	}
1047
	function GetTotalBw($qignore = NULL) {
1048
		$sum = 0;
1049
		foreach ($this->subqueues as $q) {
1050
			if ($qignore != NULL && $qignore == $q)
1051
				continue;
1052
			$sum += get_bandwidth($q->GetBandwidth(), $q->GetBwscale(), $q->GetParent());
1053
		}
1054

    
1055
		return $sum;
1056
	}
1057
	function GetBwscale() {
1058
		return $this->qbandwidthtype;
1059
	}
1060
	function SetBwscale($scale) {
1061
		$this->qbandwidthtype = $scale;
1062
	}
1063
	function GetDefaultQueuePresent() {
1064
		if ($this->GetDefault()) {
1065
			return true;
1066
		}
1067
		if (!empty($this->subqueues)) {
1068
			foreach ($this->subqueues as $q) {
1069
				if ($q->GetDefault()) {
1070
					return true;
1071
				}
1072
			}
1073
		}
1074

    
1075
		return false;
1076
	}
1077
	function GetDefault() {
1078
		return $this->qdefault;
1079
	}
1080
	function SetDefault($value = false) {
1081
		$this->qdefault = $value;
1082
	}
1083
	function GetCodel() {
1084
		return $this->codel;
1085
	}
1086
	function SetCodel($codel = false) {
1087
		$this->codel = $codel;
1088
	}
1089
	function GetRed() {
1090
		return $this->qred;
1091
	}
1092
	function SetRed($red = false) {
1093
		$this->qred = $red;
1094
	}
1095
	function GetRio() {
1096
		return $this->qrio;
1097
	}
1098
	function SetRio($rio = false) {
1099
		$this->qrio = $rio;
1100
	}
1101
	function GetEcn() {
1102
		return $this->qecn;
1103
	}
1104
	function SetEcn($ecn = false) {
1105
		$this->qecn = $ecn;
1106
	}
1107
	function GetAck() {
1108
		return $this->qack;
1109
	}
1110
	function SetAck($ack = false) {
1111
		$this->qack = $ack;
1112
	}
1113

    
1114
	function GetBwscaleText() {
1115
		switch ($this->qbandwidthtype) {
1116
			case "b":
1117
				$bwscaletext = "Bit/s";
1118
				break;
1119
			case "Kb":
1120
				$bwscaletext = "Kbit/s";
1121
				break;
1122
			case "Mb":
1123
				$bwscaletext = "Mbit/s";
1124
				break;
1125
			case "Gb":
1126
				$bwscaletext = "Gbit/s";
1127
				break;
1128
			default:
1129
				/* For others that do not need translating like % */
1130
				$bwscaletext = $this->qbandwidthtype;
1131
				break;
1132
		}
1133
		return $bwscaletext;
1134
	}
1135

    
1136
	function build_javascript() {
1137
		$javascript = "<script type=\"text/javascript\">";
1138
		$javascript .= "//<![CDATA[\n";
1139
		$javascript .= "function mySuspend() { \n";
1140
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
1141
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
1142
		$javascript .= "else if (document.all)\n";
1143
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
1144
		$javascript .= "}\n";
1145

    
1146
		$javascript .= "function myResume() {\n";
1147
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
1148
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
1149
		$javascript .= "else if (document.all)\n";
1150
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
1151
		$javascript .= "}\n";
1152
		$javascript .= "//]]>";
1153
		$javascript .= "</script>";
1154

    
1155
		return $javascript;
1156
	}
1157

    
1158
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
1159

    
1160
	/*
1161
	 * Currently this will not be called unless we decide to clone a whole
1162
	 * queue tree on the 'By Queues' view or support drag&drop on the tree/list
1163
	 */
1164
	function copy_queue($interface, &$cflink) {
1165

    
1166
		$cflink['name'] = $this->GetQname();
1167
		$cflink['interface'] = $interface;
1168
		$cflink['qlimit'] = $this->GetQlimit();
1169
		$cflink['priority'] = $this->GetQpriority();
1170
		$cflink['description'] = $this->GetDescription();
1171
		$cflink['enabled'] = $this->GetEnabled();
1172
		$cflink['default'] = $this->GetDefault();
1173
		$cflink['red'] = $this->GetRed();
1174
		$cflink['codel'] = $this->GetCodel();
1175
		$cflink['rio'] = $this->GetRio();
1176
		$cflink['ecn'] = $this->GetEcn();
1177

    
1178
		if (is_array($this->subqueues)) {
1179
			$cflinkp['queue'] = array();
1180
			foreach ($this->subqueues as $q) {
1181
				$cflink['queue'][$q->GetQname()] = array();
1182
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1183
			}
1184
		}
1185
	}
1186

    
1187
	function clean_queue($sched) {
1188
		clean_child_queues($sched, $this->GetLink());
1189
		if (is_array($this->subqueues)) {
1190
			foreach ($this->subqueues as $q) {
1191
				$q->clean_queue($sched);
1192
			}
1193
		}
1194
	}
1195

    
1196
	function &get_queue_list(&$qlist) {
1197

    
1198
		$qlist[$this->GetQname()] = & $this;
1199
		if (is_array($this->subqueues)) {
1200
			foreach ($this->subqueues as $queue) {
1201
				$queue->get_queue_list($qlist);
1202
			}
1203
		}
1204
	}
1205

    
1206
	function delete_queue() {
1207
		unref_on_altq_queue_list($this->GetQname());
1208
		cleanup_queue_from_rules($this->GetQname());
1209
		unset_object_by_reference($this->GetLink());
1210
	}
1211

    
1212
	function delete_all() {
1213
		if (count($this->subqueues)) {
1214
			foreach ($this->subqueues as $q) {
1215
				$q->delete_all();
1216
				unset_object_by_reference($q->GetLink());
1217
				unset($q);
1218
			}
1219
			unset($this->subqueues);
1220
		}
1221
	}
1222

    
1223
	function &find_queue($interface, $qname) {
1224
		if ($qname == $this->GetQname()) {
1225
			return $this;
1226
		}
1227
	}
1228

    
1229
	function find_parentqueue($interface, $qname) { return; }
1230

    
1231
	function validate_input($data, &$input_errors) {
1232

    
1233
		$reqdfields[] = "name";
1234
		$reqdfieldsn[] = gettext("Name");
1235
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1236

    
1237
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
1238
			$input_errors[] = gettext("Bandwidth must be an integer.");
1239
		}
1240
		if ($data['bandwidth'] < 0) {
1241
			$input_errors[] = gettext("Bandwidth cannot be negative.");
1242
		}
1243
		if ($data['bandwidthtype'] == "%") {
1244
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
1245
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100.");
1246
			}
1247
		}
1248
		if ($this->CheckBandwidth($data['bandwidth'], $data['bandwidthtype']))
1249
			$input_errors[] = "The sum of child bandwidth is higher than parent.";
1250
		if ($data['priority'] && (!is_numeric($data['priority']) ||
1251
		    ($data['priority'] < 1) || ($data['priority'] > 15))) {
1252
			$input_errors[] = gettext("The priority must be an integer between 1 and 15.");
1253
		}
1254
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
1255
				$input_errors[] = gettext("Queue limit must be an integer");
1256
		}
1257
		if ($data['qlimit'] < 0) {
1258
				$input_errors[] = gettext("Queue limit must be positive");
1259
		}
1260
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['newname'])) {
1261
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1262
		}
1263
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['name'])) {
1264
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1265
		}
1266
		$default = $this->GetDefault();
1267
		if (!empty($data['default']) && altq_get_default_queue($data['interface']) && empty($default)) {
1268
			$input_errors[] = gettext("Only one default queue per interface is allowed.");
1269
		}
1270
	}
1271

    
1272
	function ReadConfig(&$q) {
1273
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
1274
			$this->SetQname($q['newname']);
1275
		} else if (!empty($q['newname'])) {
1276
			$this->SetQname($q['newname']);
1277
		} else if (isset($q['name'])) {
1278
			$this->SetQname($q['name']);
1279
		}
1280
		if (isset($q['interface'])) {
1281
			$this->SetInterface($q['interface']);
1282
		}
1283
		$this->SetBandwidth($q['bandwidth']);
1284
		if ($q['bandwidthtype'] <> "") {
1285
			$this->SetBwscale($q['bandwidthtype']);
1286
		}
1287
		if (!empty($q['qlimit'])) {
1288
			$this->SetQlimit($q['qlimit']);
1289
		} else {
1290
			$this->SetQlimit(""); // Default
1291
		}
1292
		if (!empty($q['priority'])) {
1293
			$this->SetQPriority($q['priority']);
1294
		} else {
1295
			$this->SetQpriority("");
1296
		}
1297
		if (!empty($q['description'])) {
1298
			$this->SetDescription($q['description']);
1299
		} else {
1300
			$this->SetDescription("");
1301
		}
1302
		if (!empty($q['red'])) {
1303
			$this->SetRed($q['red']);
1304
		} else {
1305
			$this->SetRed();
1306
		}
1307
		if (!empty($q['codel'])) {
1308
			$this->SetCodel($q['codel']);
1309
		} else {
1310
			$this->SetCodel();
1311
		}
1312
		if (!empty($q['rio'])) {
1313
			$this->SetRio($q['rio']);
1314
		} else {
1315
			$this->SetRio();
1316
		}
1317
		if (!empty($q['ecn'])) {
1318
			$this->SetEcn($q['ecn']);
1319
		} else {
1320
			$this->SetEcn();
1321
		}
1322
		if (!empty($q['default'])) {
1323
			$this->SetDefault($q['default']);
1324
		} else {
1325
			$this->SetDefault();
1326
		}
1327
		if (!empty($q['enabled'])) {
1328
			$this->SetEnabled($q['enabled']);
1329
		} else {
1330
			$this->SetEnabled("");
1331
		}
1332
	}
1333

    
1334
	function build_tree() {
1335
		$tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&amp;queue=". $this->GetQname()."&amp;action=show";
1336
		$tree .= "\" ";
1337
		$tmpvalue = $this->GetDefault();
1338
		if (!empty($tmpvalue)) {
1339
			$tree .= " class=\"navlnk\"";
1340
		}
1341
		$tree .= " >" . $this->GetQname() . "</a>";
1342
		/*
1343
		 * Not needed here!
1344
		 * if (is_array($queues) {
1345
		 *	  $tree .= "<ul>";
1346
		 *	  foreach ($q as $queues)
1347
		 *		  $tree .= $queues['$q->GetName()']->build_tree();
1348
		 *	  endforeach
1349
		 *	  $tree .= "</ul>";
1350
		 * }
1351
		 */
1352

    
1353
		$tree .= "</li>";
1354

    
1355
		return $tree;
1356
	}
1357

    
1358
	/* Should return something like:
1359
	 * queue $qname on $qinterface bandwidth ....
1360
	 */
1361
	function build_rules(&$default = false) {
1362
		$pfq_rule = " queue ". $this->qname;
1363
		if ($this->GetInterface()) {
1364
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1365
		}
1366
		$tmpvalue = $this->GetQpriority();
1367
		if (!empty($tmpvalue)) {
1368
			$pfq_rule .= " priority ".$this->GetQpriority();
1369
		}
1370
		$tmpvalue = $this->GetQlimit();
1371
		if (!empty($tmpvalue)) {
1372
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1373
		}
1374
		if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault() || $this->GetCodel()) {
1375
			$pfq_rule .= " priq ( ";
1376
			$tmpvalue = $this->GetRed();
1377
			if (!empty($tmpvalue)) {
1378
				$comma = 1;
1379
				$pfq_rule .= " red ";
1380
			}
1381
			$tmpvalue = $this->GetRio();
1382
			if (!empty($tmpvalue)) {
1383
				if ($comma) {
1384
					$pfq_rule .= " ,";
1385
				}
1386
				$comma = 1;
1387
				$pfq_rule .= " rio ";
1388
			}
1389
			$tmpvalue = $this->GetEcn();
1390
			if (!empty($tmpvalue)) {
1391
				if ($comma) {
1392
					$pfq_rule .= " ,";
1393
				}
1394
				$comma = 1;
1395
				$pfq_rule .= " ecn ";
1396
			}
1397
			$tmpvalue = $this->GetCodel();
1398
			if (!empty($tmpvalue)) {
1399
				if ($comma) {
1400
					$pfq_rule .= " ,";
1401
				}
1402
				$comma = 1;
1403
				$pfq_rule .= " codel ";
1404
			}
1405
			$tmpvalue = $this->GetDefault();
1406
			if (!empty($tmpvalue)) {
1407
				if ($comma) {
1408
					$pfq_rule .= " ,";
1409
				}
1410
				$pfq_rule .= " default ";
1411
				$default = true;
1412
			}
1413
			$pfq_rule .= " ) ";
1414
		}
1415

    
1416
		$pfq_rule .= " \n";
1417

    
1418
		return $pfq_rule;
1419
	}
1420

    
1421
	/*
1422
	 * To return the html form to show to user
1423
	 * for getting the parameters.
1424
	 * Should do even for first time when the
1425
	 * object is created and later when we may
1426
	 * need to update it. (2)
1427
	 */
1428

    
1429
	function build_form() {
1430

    
1431
		$sform = new Form();
1432

    
1433
		$sform->setAction("firewall_shaper.php");
1434

    
1435
		$section = new Form_Section("");
1436

    
1437
		$section->addInput(new Form_Checkbox(
1438
			'enabled',
1439
			'Enable/Disable',
1440
			'Enable/disable discipline and its children',
1441
			($this->GetEnabled() == "on"),
1442
			'on'
1443
		));
1444

    
1445
		$section->addInput(new Form_Input(
1446
			'newname',
1447
			'Name',
1448
			'text',
1449
			$this->GetQname()
1450
		))->setHelp('Enter the name of the queue here. Do not use spaces and limit the size to 15 characters.');
1451

    
1452
		$section->addInput(new Form_Input(
1453
			'name',
1454
			null,
1455
			'hidden',
1456
			$this->GetQname()
1457
		));
1458

    
1459
		$section->addInput(new Form_Input(
1460
			'priority',
1461
			'Priority',
1462
			'number',
1463
			$this->GetQpriority(),
1464
			['min' => '0', 'max'=> '7']
1465
		))->setHelp('For hfsc, the range is 0 to 7. The default is 1. Hfsc queues with a higher priority are preferred in the case of overload.');
1466

    
1467
		$section->addInput(new Form_Input(
1468
			'qlimit',
1469
			'Queue Limit',
1470
			'number',
1471
			$this->GetQlimit()
1472
		))->setHelp('Queue limit in packets.');
1473

    
1474
		$group = new Form_Group('Scheduler options');
1475

    
1476
		if (empty($this->subqueues)) {
1477
			$group->add(new Form_Checkbox(
1478
				'default',
1479
				null,
1480
				null,
1481
				$this->GetDefault(),
1482
				'default'
1483
			))->setHelp('Default Queue');
1484
		}
1485

    
1486
		$group->add(new Form_Checkbox(
1487
			'red',
1488
			null,
1489
			null,
1490
			!empty($this->GetRed())
1491
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#red">' . gettext('Random Early Detection') . '</a>');
1492

    
1493
		$group->add(new Form_Checkbox(
1494
			'rio',
1495
			null,
1496
			null,
1497
			!empty($this->GetRio())
1498
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#rio">' . gettext('Random Early Detection In and Out') . '</a>');
1499

    
1500
		$group->add(new Form_Checkbox(
1501
			'ecn',
1502
			null,
1503
			null,
1504
			!empty($this->GetEcn())
1505
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#ecn">' . gettext('Explicit Congestion Notification') . '</a>');
1506

    
1507
		$group->add(new Form_Checkbox(
1508
			'codel',
1509
			null,
1510
			null,
1511
			!empty($this->GetCodel())
1512
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#ecn">' . gettext('Codel Active Queue') . '</a>');
1513

    
1514
		$group->setHelp('Select options for this queue');
1515

    
1516
		$section->add($group);
1517

    
1518
		$section->addInput(new Form_Input(
1519
			'description',
1520
			'Description',
1521
			'text',
1522
			$this->GetDescription()
1523
		));
1524

    
1525
		$sform->add($section);
1526

    
1527
		$sform->addGlobal(new Form_Input(
1528
			'interface',
1529
			null,
1530
			'hidden',
1531
			$this->GetInterface()
1532
		));
1533

    
1534
		$sform->addGlobal(new Form_Input(
1535
			'name',
1536
			null,
1537
			'hidden',
1538
			$this->GetQname()
1539
		));
1540

    
1541
		return($sform);
1542
	}
1543

    
1544
	function build_shortform() {
1545
		/* XXX: Hacks in sight. Mostly layer violations!  */
1546
		global $g, $altq_list_queues;
1547
		global $shaperIFlist;
1548

    
1549
		$altq =& $altq_list_queues[$this->GetInterface()];
1550

    
1551
		if ($altq) {
1552
			$scheduler = $altq->GetScheduler();
1553
		}
1554

    
1555
		$form = '<dl class="dl-horizontal">';
1556
		$form .= '	<dt>';
1557
		$form .= '		<a href="firewall_shaper.php?interface=' . $this->GetInterface() . '&amp;queue=' . $this->GetQname() . '&amp;action=show">' . $shaperIFlist[$this->GetInterface()] . '</a>';
1558
		$form .= '	</dt>';
1559
		$form .= '	<dd>';
1560
		$form .=		$scheduler;
1561
		$form .= '	</dd>';
1562

    
1563
		$form .= '	<dt>';
1564
		$form .=		'Bandwidth';
1565
		$form .= '	</dt>';
1566
		$form .= '	<dd>';
1567
		$form .=		$this->GetBandwidth() . '&nbsp;' . $this->GetBwscaleText();
1568
		$form .= '	</dd>';
1569

    
1570
		$tmpvalue = $this->GetQpriority();
1571
		if (!empty($tmpvalue)) {
1572
			$form .= '	<dt>';
1573
			$form .=		'Priority';
1574
			$form .= '	<dt>';
1575
			$form .= '	<dd>';
1576
			$form .=		'On';
1577
			$form .= '	</dd>';
1578
		}
1579

    
1580
		$tmpvalue = $this->GetDefault();
1581
		if (!empty($tmpvalue)) {
1582
			$form .= '	<dt>';
1583
			$form .=		'Default';
1584
			$form .= '	<dt>';
1585
			$form .= '	<dd>';
1586
			$form .=		'On';
1587
			$form .= '	</dd>';
1588
		}
1589

    
1590
			$form .= '	<dt>';
1591
			$form .= 'Delete';
1592
			$form .= '	<dt>';
1593
			$form .= '	<dd>';
1594

    
1595
			$form .= '<a class="btn btn-danger btn-xs" href="firewall_shaper_queues.php?interface=';
1596
			$form .= $this->GetInterface() . '&amp;queue=';
1597
			$form .= $this->GetQname() . '&amp;action=delete">';
1598
			$form .= '<i class="fa fa-trash icon-embed-btn"></i>';
1599
			$form .= gettext("Delete Queue from this Interface") . '</a>';
1600

    
1601
			$form .= '	</dd>';
1602

    
1603
			$form .= '</dl>';
1604

    
1605
		return $form;
1606

    
1607
	}
1608

    
1609
	function update_altq_queue_data(&$q) {
1610
		$this->ReadConfig($q);
1611
	}
1612

    
1613
	function wconfig() {
1614
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1615
		if (!is_array($cflink)) {
1616
			$cflink = array();
1617
		}
1618
		$cflink['name'] = $this->GetQname();
1619
		$cflink['interface'] = $this->GetInterface();
1620
		$cflink['qlimit'] = trim($this->GetQlimit());
1621
		if (empty($cflink['qlimit'])) {
1622
			unset($cflink['qlimit']);
1623
		}
1624
		$cflink['priority'] = trim($this->GetQpriority());
1625
		if (empty($cflink['priority'])) {
1626
			unset($cflink['priority']);
1627
		}
1628
		$cflink['description'] = trim($this->GetDescription());
1629
		if (empty($cflink['description'])) {
1630
			unset($cflink['description']);
1631
		}
1632
		$cflink['enabled'] = trim($this->GetEnabled());
1633
		if (empty($cflink['enabled'])) {
1634
			unset($cflink['enabled']);
1635
		}
1636
		$cflink['default'] = trim($this->GetDefault());
1637
		if (empty($cflink['default'])) {
1638
			unset($cflink['default']);
1639
		}
1640
		$cflink['red'] = trim($this->GetRed());
1641
		if (empty($cflink['red'])) {
1642
			unset($cflink['red']);
1643
		}
1644
		$cflink['codel'] = trim($this->GetCodel());
1645
		if (empty($cflink['codel'])) {
1646
			unset($cflink['codel']);
1647
		}
1648
		$cflink['rio'] = trim($this->GetRio());
1649
		if (empty($cflink['rio'])) {
1650
			unset($cflink['rio']);
1651
		}
1652
		$cflink['ecn'] = trim($this->GetEcn());
1653
		if (empty($cflink['ecn'])) {
1654
			unset($cflink['ecn']);
1655
		}
1656
	}
1657
}
1658

    
1659
class hfsc_queue extends priq_queue {
1660
	/* realtime */
1661
	var $realtime;
1662
	var $r_m1;
1663
	var $r_d;
1664
	var $r_m2;
1665
	/* linkshare */
1666
	var $linkshare;
1667
	var $l_m1;
1668
	var $l_d;
1669
	var $l_m2;
1670
	/* upperlimit */
1671
	var $upperlimit;
1672
	var $u_m1;
1673
	var $u_d;
1674
	var $u_m2;
1675

    
1676
	/*
1677
	 * HFSC can have nested queues.
1678
	 */
1679
	function CanHaveChildren() {
1680
		return true;
1681
	}
1682
	function GetRealtime() {
1683
		return $this->realtime;
1684
	}
1685
	function GetR_m1() {
1686
		return $this->r_m1;
1687
	}
1688
	function GetR_d() {
1689
		return $this->r_d;
1690
	}
1691
	function GetR_m2() {
1692
		return $this->r_m2;
1693
	}
1694
	function SetRealtime() {
1695
		$this->realtime = "on";
1696
	}
1697
	function DisableRealtime() {
1698
		$this->realtime = "";
1699
	}
1700
	function SetR_m1($value) {
1701
		$this->r_m1 = $value;
1702
	}
1703
	function SetR_d($value) {
1704
		$this->r_d = $value;
1705
	}
1706
	function SetR_m2($value) {
1707
		$this->r_m2 = $value;
1708
	}
1709
	function GetLinkshare() {
1710
		return $this->linkshare;
1711
	}
1712
	function DisableLinkshare() {
1713
		$this->linkshare = "";
1714
	}
1715
	function GetL_m1() {
1716
		return $this->l_m1;
1717
	}
1718
	function GetL_d() {
1719
		return $this->l_d;
1720
	}
1721
	function GetL_m2() {
1722
		return $this->l_m2;
1723
	}
1724
	function SetLinkshare() {
1725
		$this->linkshare = "on";
1726
	}
1727
	function SetL_m1($value) {
1728
		$this->l_m1 = $value;
1729
	}
1730
	function SetL_d($value) {
1731
		$this->l_d = $value;
1732
	}
1733
	function SetL_m2($value) {
1734
		$this->l_m2 = $value;
1735
	}
1736
	function GetUpperlimit() {
1737
		return $this->upperlimit;
1738
	}
1739
	function GetU_m1() {
1740
		return $this->u_m1;
1741
	}
1742
	function GetU_d() {
1743
		return $this->u_d;
1744
	}
1745
	function GetU_m2() {
1746
		return $this->u_m2;
1747
	}
1748
	function SetUpperlimit() {
1749
		$this->upperlimit = "on";
1750
	}
1751
	function DisableUpperlimit() {
1752
		$this->upperlimit = "";
1753
	}
1754
	function SetU_m1($value) {
1755
		$this->u_m1 = $value;
1756
	}
1757
	function SetU_d($value) {
1758
		$this->u_d = $value;
1759
	}
1760
	function SetU_m2($value) {
1761
		$this->u_m2 = $value;
1762
	}
1763

    
1764
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1765

    
1766
		if (!is_array($this->subqueues)) {
1767
			$this->subqueues = array();
1768
		}
1769
		$q =& new hfsc_queue();
1770
		$q->SetInterface($this->GetInterface());
1771
		$q->SetParent($this);
1772
		$q->ReadConfig($qname);
1773
		$q->validate_input($qname, $input_errors);
1774

    
1775
		$q->SetEnabled("on");
1776
		$q->SetLink($path);
1777

    
1778
		$this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue()
1779
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
1780
		if (is_array($qname['queue'])) {
1781
			foreach ($qname['queue'] as $key1 => $que) {
1782
				array_push($path, $key1);
1783
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
1784
				array_pop($path);
1785
			}
1786
		}
1787

    
1788
		return $q;
1789
	}
1790

    
1791
	function copy_queue($interface, &$cflink) {
1792

    
1793
		$cflink['name'] = $this->GetQname();
1794
		$cflink['interface'] = $interface;
1795
		$cflink['qlimit'] = trim($this->GetQlimit());
1796
		if (empty($cflink['qlimit'])) {
1797
			unset($cflink['qlimit']);
1798
		}
1799
		$cflink['priority'] = trim($this->GetQpriority());
1800
		if (empty($cflink['priority'])) {
1801
			unset($cflink['priority']);
1802
		}
1803
		$cflink['description'] = trim($this->GetDescription());
1804
		if (empty($cflink['description'])) {
1805
			unset($cflink['description']);
1806
		}
1807
		$cflink['bandwidth'] = $this->GetBandwidth();
1808
		$cflink['bandwidthtype'] = $this->GetBwscale();
1809
		$cflink['enabled'] = trim($this->GetEnabled());
1810
		if (empty($cflink['enabled'])) {
1811
			unset($cflink['enabled']);
1812
		}
1813
		$cflink['default'] = trim($this->GetDefault());
1814
		if (empty($cflink['default'])) {
1815
			unset($cflink['default']);
1816
		}
1817
		$cflink['red'] = trim($this->GetRed());
1818
		if (empty($cflink['red'])) {
1819
			unset($cflink['red']);
1820
		}
1821
		$cflink['rio'] = trim($this->GetRio());
1822
		if (empty($cflink['rio'])) {
1823
			unset($cflink['rio']);
1824
		}
1825
		$cflink['ecn'] = trim($this->GetEcn());
1826
		if (empty($cflink['ecn'])) {
1827
			unset($cflink['ecn']);
1828
		}
1829
		if ($this->GetLinkshare() <> "") {
1830
			if ($this->GetL_m1() <> "") {
1831
				$cflink['linkshare1'] = $this->GetL_m1();
1832
				$cflink['linkshare2'] = $this->GetL_d();
1833
				$cflink['linkshare'] = "on";
1834
			} else {
1835
				unset($cflink['linkshare1']);
1836
				unset($cflink['linkshare2']);
1837
				unset($cflink['linkshare']);
1838
			}
1839
			if ($this->GetL_m2() <> "") {
1840
				$cflink['linkshare3'] = $this->GetL_m2();
1841
				$cflink['linkshare'] = "on";
1842
			} else {
1843
				unset($cflink['linkshare3']);
1844
				unset($cflink['linkshare']);
1845
			}
1846
		}
1847
		if ($this->GetRealtime() <> "") {
1848
			if ($this->GetR_m1() <> "") {
1849
				$cflink['realtime1'] = $this->GetR_m1();
1850
				$cflink['realtime2'] = $this->GetR_d();
1851
				$cflink['realtime'] = "on";
1852
			} else {
1853
				unset($cflink['realtime1']);
1854
				unset($cflink['realtime2']);
1855
				unset($cflink['realtime']);
1856
			}
1857
			if ($this->GetR_m2() <> "") {
1858
				$cflink['realtime3'] = $this->GetR_m2();
1859
				$cflink['realtime'] = "on";
1860
			} else {
1861
				unset($cflink['realtime3']);
1862
				unset($cflink['realtime']);
1863
			}
1864
		}
1865
		if ($this->GetUpperlimit() <> "") {
1866
			if ($this->GetU_m1() <> "") {
1867
				$cflink['upperlimit1'] = $this->GetU_m1();
1868
				$cflink['upperlimit2'] = $this->GetU_d();
1869
				$cflink['upperlimit'] = "on";
1870
			} else {
1871
				unset($cflink['upperlimit']);
1872
				unset($cflink['upperlimit1']);
1873
				unset($cflink['upperlimit2']);
1874
			}
1875
			if ($this->GetU_m2() <> "") {
1876
				$cflink['upperlimit3'] = $this->GetU_m2();
1877
				$cflink['upperlimit'] = "on";
1878
			} else {
1879
				unset($cflink['upperlimit3']);
1880
				unset($cflink['upperlimit']);
1881
			}
1882
		}
1883

    
1884
		if (is_array($this->subqueues)) {
1885
			$cflinkp['queue'] = array();
1886
			foreach ($this->subqueues as $q) {
1887
				$cflink['queue'][$q->GetQname()] = array();
1888
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1889
			}
1890
		}
1891
	}
1892

    
1893
	function delete_queue() {
1894
		unref_on_altq_queue_list($this->GetQname());
1895
		cleanup_queue_from_rules($this->GetQname());
1896
		$parent =& $this->GetParent();
1897
		foreach ($this->subqueues as $q)
1898
			$q->delete_queue();
1899
		unset_object_by_reference($this->GetLink());
1900
	}
1901

    
1902
	/*
1903
	 * Should search even its children
1904
	 */
1905
	function &find_queue($interface, $qname) {
1906
		if ($qname == $this->GetQname()) {
1907
			return $this;
1908
		}
1909

    
1910
		foreach ($this->subqueues as $q) {
1911
			$result =& $q->find_queue("", $qname);
1912
			if ($result) {
1913
				return $result;
1914
			}
1915
		}
1916
	}
1917

    
1918
	function &find_parentqueue($interface, $qname) {
1919
		if ($this->subqueues[$qname]) {
1920
			return $this;
1921
		}
1922
		foreach ($this->subqueues as $q) {
1923
			$result = $q->find_parentqueue("", $qname);
1924
			if ($result) {
1925
				return $result;
1926
			}
1927
		}
1928
	}
1929

    
1930
	function validate_input($data, &$input_errors) {
1931
		parent::validate_input($data, $input_errors);
1932

    
1933
		$reqdfields[] = "bandwidth";
1934
		$reqdfieldsn[] = gettext("Bandwidth");
1935
		$reqdfields[] = "bandwidthtype";
1936
		$reqdfieldsn[] = gettext("Bandwidthtype");
1937

    
1938
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1939

    
1940
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1941
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
1942
				$input_errors[] = gettext("Bandwidth must be an integer.");
1943
			}
1944

    
1945
			if ($data['bandwidth'] < 0) {
1946
				$input_errors[] = gettext("Bandwidth cannot be negative.");
1947
			}
1948

    
1949
			if ($data['bandwidthtype'] == "%") {
1950
				if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
1951
					$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100.");
1952
				}
1953
			}
1954
		}
1955

    
1956
		if ($data['upperlimit1'] <> "" && $data['upperlimit2'] == "") {
1957
			$input_errors[] = gettext("upperlimit service curve defined but missing (d) value");
1958
		}
1959
		if ($data['upperlimit2'] <> "" && $data['upperlimit1'] == "") {
1960
			$input_errors[] = gettext("upperlimit service curve defined but missing initial bandwidth (m1) value");
1961
		}
1962
		if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1'])) {
1963
			$input_errors[] = gettext("upperlimit m1 value needs to be Kb, Mb, Gb, or %");
1964
		}
1965
		if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2'])) {
1966
			$input_errors[] = gettext("upperlimit d value needs to be numeric");
1967
		}
1968
		if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3'])) {
1969
			$input_errors[] = gettext("upperlimit m2 value needs to be Kb, Mb, Gb, or %");
1970
		}
1971

    
1972
		/*
1973
		if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") {
1974
			$bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']);
1975
			$bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']);
1976
			if (floatval($bw_1) < floatval($bw_2)) {
1977
				$input_errors[] = ("upperlimit m1 cannot be smaller than m2");
1978
			}
1979

    
1980
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
1981
				$input_errors[] = ("upperlimit specification exceeds 80% of allowable allocation.");
1982
			}
1983
		}
1984
		*/
1985
		if ($data['linkshare1'] <> "" && $data['linkshare2'] == "") {
1986
			$input_errors[] = gettext("linkshare service curve defined but missing (d) value");
1987
		}
1988
		if ($data['linkshare2'] <> "" && $data['linkshare1'] == "") {
1989
			$input_errors[] = gettext("linkshare service curve defined but missing initial bandwidth (m1) value");
1990
		}
1991
		if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1'])) {
1992
			$input_errors[] = gettext("linkshare m1 value needs to be Kb, Mb, Gb, or %");
1993
		}
1994
		if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2'])) {
1995
			$input_errors[] = gettext("linkshare d value needs to be numeric");
1996
		}
1997
		if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3'])) {
1998
			$input_errors[] = gettext("linkshare m2 value needs to be Kb, Mb, Gb, or %");
1999
		}
2000
		if ($data['realtime1'] <> "" && $data['realtime2'] == "") {
2001
			$input_errors[] = gettext("realtime service curve defined but missing (d) value");
2002
		}
2003
		if ($data['realtime2'] <> "" && $data['realtime1'] == "") {
2004
			$input_errors[] = gettext("realtime service curve defined but missing initial bandwidth (m1) value");
2005
		}
2006

    
2007
		/*
2008
		if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) {
2009
			$bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']);
2010
			$bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']);
2011
			if (floatval($bw_1) < floatval($bw_2)) {
2012
				$input_errors[] = ("linkshare m1 cannot be smaller than m2");
2013
			}
2014

    
2015
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
2016
				$input_errors[] = ("linkshare specification exceeds 80% of allowable allocation.");
2017
			}
2018
		}
2019
		*/
2020

    
2021
		if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1'])) {
2022
			$input_errors[] = gettext("realtime m1 value needs to be Kb, Mb, Gb, or %");
2023
		}
2024
		if ($data['realtime2'] <> "" && !is_numeric($data['realtime2'])) {
2025
			$input_errors[] = gettext("realtime d value needs to be numeric");
2026
		}
2027
		if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3'])) {
2028
			$input_errors[] = gettext("realtime m2 value needs to be Kb, Mb, Gb, or %");
2029
		}
2030

    
2031
		/*
2032
		if (isset($data['realtime']) && $data['realtime3'] <> "" && $data['realtime1'] <> "" && 0) {
2033
			$bw_1 = get_hfsc_bandwidth($this, $data['realtime1']);
2034
			$bw_2 = get_hfsc_bandwidth($this, $data['realtime3']);
2035
			if (floatval($bw_1) < floatval($bw_2)) {
2036
				$input_errors[] = ("realtime m1 cannot be smaller than m2");
2037
			}
2038

    
2039
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
2040
				$input_errors[] = ("realtime specification exceeds 80% of allowable allocation.");
2041
			}
2042
		}
2043
		*/
2044
	}
2045

    
2046
	function ReadConfig(&$cflink) {
2047
		if (!empty($cflink['linkshare'])) {
2048
			if (!empty($cflink['linkshare1'])) {
2049
				$this->SetL_m1($cflink['linkshare1']);
2050
				$this->SetL_d($cflink['linkshare2']);
2051
				$this->SetLinkshare();
2052
			} else {
2053
				$this->SetL_m1("");
2054
				$this->SetL_d("");
2055
				$this->DisableLinkshare();
2056
			}
2057
			if (!empty($cflink['linkshare3'])) {
2058
				$this->SetL_m2($cflink['linkshare3']);
2059
				$this->SetLinkshare();
2060
			}
2061
		} else {
2062
			$this->DisableLinkshare();
2063
		}
2064
		if (!empty($cflink['realtime'])) {
2065
			if (!empty($cflink['realtime1'])) {
2066
				$this->SetR_m1($cflink['realtime1']);
2067
				$this->SetR_d($cflink['realtime2']);
2068
				$this->SetRealtime();
2069
			} else {
2070
				$this->SetR_m1("");
2071
				$this->SetR_d("");
2072
				$this->DisableRealtime();
2073
			}
2074
			if (!empty($cflink['realtime3'])) {
2075
				$this->SetR_m2($cflink['realtime3']);
2076
				$this->SetRealtime();
2077
			}
2078
		} else {
2079
			$this->DisableRealtime();
2080
		}
2081
		if (!empty($cflink['upperlimit'])) {
2082
			if (!empty($cflink['upperlimit1'])) {
2083
				$this->SetU_m1($cflink['upperlimit1']);
2084
				$this->SetU_d($cflink['upperlimit2']);
2085
				$this->SetUpperlimit();
2086
			} else {
2087
				$this->SetU_m1("");
2088
				$this->SetU_d("");
2089
				$this->DisableUpperlimit();
2090
			}
2091
			if (!empty($cflink['upperlimit3'])) {
2092
				$this->SetU_m2($cflink['upperlimit3']);
2093
				$this->SetUpperlimit();
2094
			}
2095
		} else {
2096
			$this->DisableUpperlimit();
2097
		}
2098
		parent::ReadConfig($cflink);
2099
	}
2100

    
2101
	function build_tree() {
2102
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface() ."&amp;queue=" . $this->GetQname()."&amp;action=show";
2103
		$tree .= "\" ";
2104
		$tmpvalue = $this->GetDefault();
2105
		if (!empty($tmpvalue)) {
2106
			$tree .= " class=\"navlnk\"";
2107
		}
2108
		$tree .= " >" . $this->GetQname() . "</a>";
2109
		if (is_array($this->subqueues)) {
2110
			$tree .= "<ul>";
2111
			foreach ($this->subqueues as $q) {
2112
				$tree .= $q->build_tree();
2113
			}
2114
			$tree .= "</ul>";
2115
		}
2116
		$tree .= "</li>";
2117
		return $tree;
2118
	}
2119

    
2120
	/* Even this should take children into consideration */
2121
	function build_rules(&$default = false) {
2122

    
2123
		$pfq_rule = " queue ". $this->qname;
2124
		if ($this->GetInterface()) {
2125
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2126
		}
2127
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2128
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2129
		}
2130

    
2131
		$tmpvalue = $this->GetQlimit();
2132
		if (!empty($tmpvalue)) {
2133
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2134
		}
2135
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetCodel() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
2136
			$pfq_rule .= " hfsc ( ";
2137
			$tmpvalue = $this->GetRed();
2138
			if (!empty($tmpvalue)) {
2139
				$comma = 1;
2140
				$pfq_rule .= " red ";
2141
			}
2142

    
2143
			$tmpvalue = $this->GetRio();
2144
			if (!empty($tmpvalue)) {
2145
				if ($comma) {
2146
					$pfq_rule .= " ,";
2147
				}
2148
				$comma = 1;
2149
				$pfq_rule .= " rio ";
2150
			}
2151
			$tmpvalue = $this->GetEcn();
2152
			if (!empty($tmpvalue)) {
2153
				if ($comma) {
2154
					$pfq_rule .= " ,";
2155
				}
2156
				$comma = 1;
2157
				$pfq_rule .= " ecn ";
2158
			}
2159
			$tmpvalue = $this->GetCodel();
2160
			if (!empty($tmpvalue)) {
2161
				if ($comma) {
2162
					$pfq_rule .= " ,";
2163
				}
2164
				$comma = 1;
2165
				$pfq_rule .= " codel ";
2166
			}
2167
			$tmpvalue = $this->GetDefault();
2168
			if (!empty($tmpvalue)) {
2169
				if ($comma) {
2170
					$pfq_rule .= " ,";
2171
				}
2172
				$comma = 1;
2173
				$pfq_rule .= " default ";
2174
				$default = true;
2175
			}
2176

    
2177
			if ($this->GetRealtime() <> "") {
2178
				if ($comma) {
2179
					$pfq_rule .= " , ";
2180
				}
2181
				if ($this->GetR_m1() <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "") {
2182
					$pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") ";
2183
				} else if ($this->GetR_m2() <> "") {
2184
					$pfq_rule .= " realtime " . $this->GetR_m2();
2185
				}
2186
				$comma = 1;
2187
			}
2188
			if ($this->GetLinkshare() <> "") {
2189
				if ($comma) {
2190
					$pfq_rule .= " ,";
2191
				}
2192
				if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "") {
2193
					$pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") ";
2194
				} else if ($this->GetL_m2() <> "") {
2195
					$pfq_rule .= " linkshare " . $this->GetL_m2() . " ";
2196
				}
2197
				$comma = 1;
2198
			}
2199
			if ($this->GetUpperlimit() <> "") {
2200
				if ($comma) {
2201
					$pfq_rule .= " ,";
2202
				}
2203
				if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "") {
2204
							$pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") ";
2205
				} else if ($this->GetU_m2() <> "") {
2206
					$pfq_rule .= " upperlimit " . $this->GetU_m2() . " ";
2207
				}
2208
			}
2209
			$pfq_rule .= " ) ";
2210
		}
2211
		if (count($this->subqueues)) {
2212
			$i = count($this->subqueues);
2213
			$pfq_rule .= " { ";
2214
			foreach ($this->subqueues as $qkey => $qnone) {
2215
				if ($i > 1) {
2216
					$i--;
2217
					$pfq_rule .= " {$qkey}, ";
2218
				} else {
2219
					$pfq_rule .= " {$qkey} ";
2220
				}
2221
			}
2222
			$pfq_rule .= " } \n";
2223
			foreach ($this->subqueues as $q) {
2224
				$pfq_rule .= $q->build_rules($default);
2225
			}
2226
		}
2227

    
2228
		$pfq_rule .= " \n";
2229

    
2230
		return $pfq_rule;
2231
	}
2232

    
2233
	function build_javascript() {
2234

    
2235
		$javascript = <<<EOJS
2236
<script type="text/javascript">
2237
//<![CDATA[
2238
	events.push(function(){
2239

    
2240
		// Disables the specified input element
2241
		function disableInput(id, disable) {
2242
			$('#' + id).prop("disabled", disable);
2243
		}
2244

    
2245
		// Upperlimit
2246
		function enable_upperlimit() {
2247
			disableInput('upperlimit1', !$('#upperlimit').prop('checked'));
2248
			disableInput('upperlimit2', !$('#upperlimit').prop('checked'));
2249
			disableInput('upperlimit3', !$('#upperlimit').prop('checked'));
2250
		}
2251

    
2252
		$('#upperlimit').click(function () {
2253
			enable_upperlimit();
2254
		});
2255

    
2256
		enable_upperlimit();
2257

    
2258
		// realtime
2259
		function enable_realtime() {
2260
			disableInput('realtime1', !$('#realtime').prop('checked'));
2261
			disableInput('realtime2', !$('#realtime').prop('checked'));
2262
			disableInput('realtime3', !$('#realtime').prop('checked'));
2263
		}
2264

    
2265
		$('#realtime').click(function () {
2266
			enable_realtime();
2267
		});
2268

    
2269
		enable_realtime();
2270

    
2271
		// linkshare
2272
		function enable_linkshare() {
2273
			disableInput('linkshare1', !$('#linkshare').prop('checked'));
2274
			disableInput('linkshare2', !$('#linkshare').prop('checked'));
2275
			disableInput('linkshare3', !$('#linkshare').prop('checked'));
2276
		}
2277

    
2278
		$('#linkshare').click(function () {
2279
			enable_linkshare();
2280
		});
2281

    
2282
		enable_linkshare();
2283
	});
2284
//]]>
2285
</script>
2286
EOJS;
2287

    
2288
		return $javascript;
2289
	}
2290

    
2291
	function build_form() {
2292

    
2293
		$sform = parent::build_form();
2294

    
2295
		$section = new Form_Section('Service Curve (sc)');
2296

    
2297
		$group = new Form_Group('Bandwidth');
2298

    
2299
		$group->add(new Form_Input(
2300
			'bandwidth',
2301
			null,
2302
			'number',
2303
			$this->GetBandwidth()
2304
		));
2305

    
2306
		$group->add(new Form_Select(
2307
			'bandwidthtype',
2308
			null,
2309
			$this->GetBwscale(),
2310
			array('Kb' => 'Kbit/s',
2311
				  'Mb' => 'Mbit/s',
2312
				  'Gb' => 'Gbit/s',
2313
				  'b' => 'Bit/s',
2314
				  '%' => '%')
2315
		));
2316

    
2317
		$group->setHelp('Choose the amount of bandwidth for this queue');
2318

    
2319
		$section->add($group);
2320

    
2321
		$group = new Form_Group('Max bandwidth for queue.');
2322

    
2323
		$group->add(new Form_Checkbox(
2324
			'upperlimit',
2325
			null,
2326
			'Upper Limit',
2327
			($this->GetUpperlimit()<> "")
2328
		));
2329

    
2330
		$group->add(new Form_Input(
2331
			'upperlimit1',
2332
			null,
2333
			'text',
2334
			$this->GetU_m1()
2335
		))->setHelp('m1');
2336

    
2337
		$group->add(new Form_Input(
2338
			'upperlimit2',
2339
			null,
2340
			'text',
2341
			$this->GetU_d()
2342
		))->setHelp('d');
2343

    
2344
		$group->add(new Form_Input(
2345
			'upperlimit3',
2346
			null,
2347
			'text',
2348
			$this->GetU_m2()
2349
		))->setHelp('m2');
2350

    
2351

    
2352
		$section->add($group);
2353

    
2354
		$group = new Form_Group('Min bandwidth for queue.');
2355

    
2356
		$group->add(new Form_Checkbox(
2357
			'realtime',
2358
			null,
2359
			'Real Time',
2360
			($this->GetRealtime()<> "")
2361
		));
2362

    
2363
		$group->add(new Form_Input(
2364
			'realtime1',
2365
			null,
2366
			'text',
2367
			$this->GetR_m1()
2368
		))->setHelp('m1');
2369

    
2370
		$group->add(new Form_Input(
2371
			'realtime2',
2372
			null,
2373
			'text',
2374
			$this->GetR_d()
2375
		))->setHelp('d');
2376

    
2377
		$group->add(new Form_Input(
2378
			'realtime3',
2379
			null,
2380
			'text',
2381
			$this->GetR_m2()
2382
		))->setHelp('m2');
2383

    
2384
		$section->add($group);
2385

    
2386
		$group = new Form_Group('B/W share of a backlogged queue.');
2387

    
2388
		$group->add(new Form_Checkbox(
2389
			'linkshare',
2390
			null,
2391
			'Link Share',
2392
			($this->GetLinkshare()<> "")
2393
		));
2394

    
2395
		$group->add(new Form_Input(
2396
			'linkshare1',
2397
			null,
2398
			'text',
2399
			$this->GetL_m1()
2400
		))->setHelp('m1');
2401

    
2402
		$group->add(new Form_Input(
2403
			'linkshare2',
2404
			null,
2405
			'text',
2406
			$this->GetL_d()
2407
		))->setHelp('d');
2408

    
2409
		$group->add(new Form_Input(
2410
			'linkshare3',
2411
			null,
2412
			'text',
2413
			$this->GetL_m2()
2414
		))->setHelp('m2');
2415

    
2416
		$group->sethelp('Bandwidth share overrides priority.' . '<br />' .
2417
						'The format for service curve specifications is (m1, d, m2). m2 controls the bandwidth assigned to the queue. ' .
2418
						'm1 and d are optional and can be used to control the initial bandwidth assignment. ' .
2419
						'For the first d milliseconds the queue gets the bandwidth given as m1, afterwards the value given in m2.');
2420

    
2421
		$section->add($group);
2422

    
2423
		$sform->add($section);
2424

    
2425
		return($sform);
2426
	}
2427

    
2428
	function update_altq_queue_data(&$data) {
2429
		$this->ReadConfig($data);
2430
	}
2431

    
2432
	function wconfig() {
2433
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2434
		if (!is_array($cflink)) {
2435
			$cflink = array();
2436
		}
2437
		$cflink['name'] = $this->GetQname();
2438
		$cflink['interface'] = $this->GetInterface();
2439
		$cflink['qlimit'] = trim($this->GetQlimit());
2440
		if (empty($cflink['qlimit'])) {
2441
			unset($cflink['qlimit']);
2442
		}
2443
		$cflink['priority'] = $this->GetQpriority();
2444
		if (empty($cflink['priority'])) {
2445
			unset($cflink['priority']);
2446
		}
2447
		$cflink['description'] = $this->GetDescription();
2448
		if (empty($cflink['description'])) {
2449
			unset($cflink['description']);
2450
		}
2451
		$cflink['bandwidth'] = $this->GetBandwidth();
2452
		$cflink['bandwidthtype'] = $this->GetBwscale();
2453
		$cflink['enabled'] = $this->GetEnabled();
2454
		if (empty($cflink['enabled'])) {
2455
			unset($cflink['enabled']);
2456
		}
2457
		$cflink['default'] = $this->GetDefault();
2458
		if (empty($cflink['default'])) {
2459
			unset($cflink['default']);
2460
		}
2461
		$cflink['red'] = trim($this->GetRed());
2462
		if (empty($cflink['red'])) {
2463
			unset($cflink['red']);
2464
		}
2465
		$cflink['rio'] = $this->GetRio();
2466
		if (empty($cflink['rio'])) {
2467
			unset($cflink['rio']);
2468
		}
2469
		$cflink['ecn'] = trim($this->GetEcn());
2470
		if (empty($cflink['ecn'])) {
2471
			unset($cflink['ecn']);
2472
		}
2473
		$cflink['codel'] = trim($this->GetCodel());
2474
		if (empty($cflink['codel'])) {
2475
			unset($cflink['codel']);
2476
		}
2477
		if ($this->GetLinkshare() <> "") {
2478
			if ($this->GetL_m1() <> "") {
2479
				$cflink['linkshare1'] = $this->GetL_m1();
2480
				$cflink['linkshare2'] = $this->GetL_d();
2481
				$cflink['linkshare'] = "on";
2482
			} else {
2483
				unset($cflink['linkshare']);
2484
				unset($cflink['linkshare1']);
2485
				unset($cflink['linkshare2']);
2486
			}
2487
			if ($this->GetL_m2() <> "") {
2488
				$cflink['linkshare3'] = $this->GetL_m2();
2489
				$cflink['linkshare'] = "on";
2490
			} else {
2491
				unset($cflink['linkshare']);
2492
				unset($cflink['linkshare3']);
2493
			}
2494
		} else {
2495
			unset($cflink['linkshare']);
2496
			unset($cflink['linkshare1']);
2497
			unset($cflink['linkshare2']);
2498
			unset($cflink['linkshare3']);
2499
		}
2500
		if ($this->GetRealtime() <> "") {
2501
			if ($this->GetR_m1() <> "") {
2502
				$cflink['realtime1'] = $this->GetR_m1();
2503
				$cflink['realtime2'] = $this->GetR_d();
2504
				$cflink['realtime'] = "on";
2505
			} else {
2506
				unset($cflink['realtime']);
2507
				unset($cflink['realtime1']);
2508
				unset($cflink['realtime2']);
2509
			}
2510
			if ($this->GetR_m2() <> "") {
2511
				$cflink['realtime3'] = $this->GetR_m2();
2512
				$cflink['realtime'] = "on";
2513
			} else {
2514
				unset($cflink['realtime']);
2515
				unset($cflink['realtime3']);
2516
			}
2517
		} else {
2518
			unset($cflink['realtime']);
2519
			unset($cflink['realtime1']);
2520
			unset($cflink['realtime2']);
2521
			unset($cflink['realtime3']);
2522
		}
2523
		if ($this->GetUpperlimit() <> "") {
2524
			if ($this->GetU_m1() <> "") {
2525
				$cflink['upperlimit1'] = $this->GetU_m1();
2526
				$cflink['upperlimit2'] = $this->GetU_d();
2527
				$cflink['upperlimit'] = "on";
2528
			} else {
2529
				unset($cflink['upperlimit']);
2530
				unset($cflink['upperlimit1']);
2531
				unset($cflink['upperlimit2']);
2532
			}
2533
			if ($this->GetU_m2() <> "") {
2534
				$cflink['upperlimit3'] = $this->GetU_m2();
2535
				$cflink['upperlimit'] = "on";
2536
			} else {
2537
				unset($cflink['upperlimit']);
2538
				unset($cflink['upperlimit3']);
2539
			}
2540
		} else {
2541
			unset($cflink['upperlimit']);
2542
			unset($cflink['upperlimit1']);
2543
			unset($cflink['upperlimit2']);
2544
			unset($cflink['upperlimit3']);
2545
		}
2546
	}
2547
}
2548

    
2549
class cbq_queue extends priq_queue {
2550
	var $qborrow = "";
2551

    
2552
	function GetBorrow() {
2553
		return $this->qborrow;
2554
	}
2555
	function SetBorrow($borrow) {
2556
		$this->qborrow = $borrow;
2557
	}
2558
	function CanHaveChildren() {
2559
		return true;
2560
	}
2561

    
2562
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2563

    
2564
		if (!is_array($this->subqueues)) {
2565
			$this->subqueues = array();
2566
		}
2567
		$q =& new cbq_queue();
2568
		$q->SetInterface($this->GetInterface());
2569
		$q->SetParent($this);
2570
		$q->ReadConfig($qname);
2571
		$q->validate_input($qname, $input_errors);
2572

    
2573
		$q->SetEnabled("on");
2574
		$q->SetLink($path);
2575
		$this->subqueues[$q->GetQName()] = &$q;
2576
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2577
		if (is_array($qname['queue'])) {
2578
			foreach ($qname['queue'] as $key1 => $que) {
2579
				array_push($path, $key1);
2580
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
2581
				array_pop($path);
2582
			}
2583
		}
2584

    
2585
		return $q;
2586
	}
2587

    
2588
	function copy_queue($interface, &$cflink) {
2589

    
2590
		$cflink['interface'] = $interface;
2591
		$cflink['qlimit'] = trim($this->GetQlimit());
2592
		if (empty($clink['qlimit'])) {
2593
			unset($cflink['qlimit']);
2594
		}
2595
		$cflink['priority'] = trim($this->GetQpriority());
2596
		if (empty($cflink['priority'])) {
2597
			unset($cflink['priority']);
2598
		}
2599
		$cflink['name'] = $this->GetQname();
2600
		$cflink['description'] = trim($this->GetDescription());
2601
		if (empty($cflink['description'])) {
2602
			unset($cflink['description']);
2603
		}
2604
		$cflink['bandwidth'] = $this->GetBandwidth();
2605
		$cflink['bandwidthtype'] = $this->GetBwscale();
2606
		$cflink['enabled'] = trim($this->GetEnabled());
2607
		if (empty($cflink['enabled'])) {
2608
			unset($cflink['enabled']);
2609
		}
2610
		$cflink['default'] = trim($this->GetDefault());
2611
		if (empty($cflink['default'])) {
2612
			unset($cflink['default']);
2613
		}
2614
		$cflink['red'] = trim($this->GetRed());
2615
		if (empty($cflink['red'])) {
2616
			unset($cflink['red']);
2617
		}
2618
		$cflink['rio'] = trim($this->GetRio());
2619
		if (empty($cflink['rio'])) {
2620
			unset($cflink['rio']);
2621
		}
2622
		$cflink['ecn'] = trim($this->GetEcn());
2623
		if (empty($cflink['ecn'])) {
2624
			unset($cflink['ecn']);
2625
		}
2626
		$cflink['borrow'] = trim($this->GetBorrow());
2627
		if (empty($cflink['borrow'])) {
2628
			unset($cflink['borrow']);
2629
		}
2630
		if (is_array($this->queues)) {
2631
			$cflinkp['queue'] = array();
2632
			foreach ($this->subqueues as $q) {
2633
				$cflink['queue'][$q->GetQname()] = array();
2634
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
2635
			}
2636
		}
2637
	}
2638

    
2639
	/*
2640
	 * Should search even its children
2641
	 */
2642
	function &find_queue($interface, $qname) {
2643
		if ($qname == $this->GetQname()) {
2644
			return $this;
2645
		}
2646
		foreach ($this->subqueues as $q) {
2647
			$result =& $q->find_queue("", $qname);
2648
			if ($result) {
2649
				return $result;
2650
			}
2651
		}
2652
	}
2653

    
2654
	function &find_parentqueue($interface, $qname) {
2655
		if ($this->subqueues[$qname]) {
2656
			return $this;
2657
		}
2658
		foreach ($this->subqueues as $q) {
2659
			$result = $q->find_parentqueue("", $qname);
2660
			if ($result) {
2661
				return $result;
2662
			}
2663
		}
2664
	}
2665

    
2666
	function delete_queue() {
2667
		unref_on_altq_queue_list($this->GetQname());
2668
		cleanup_queue_from_rules($this->GetQname());
2669
		foreach ($this->subqueues as $q)
2670
			$q->delete_queue();
2671
		unset_object_by_reference($this->GetLink());
2672
	}
2673

    
2674
	function validate_input($data, &$input_errors) {
2675
		parent::validate_input($data, $input_errors);
2676

    
2677
		if ($data['priority'] > 7) {
2678
				$input_errors[] = gettext("Priority must be an integer between 1 and 7.");
2679
		}
2680
		$reqdfields[] = "bandwidth";
2681
		$reqdfieldsn[] = gettext("Bandwidth");
2682
		$reqdfields[] = "bandwidthtype";
2683
		$reqdfieldsn[] = gettext("Bandwidthtype");
2684

    
2685
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2686
	}
2687

    
2688
	function ReadConfig(&$q) {
2689
		parent::ReadConfig($q);
2690
		if (!empty($q['borrow'])) {
2691
			$this->SetBorrow("on");
2692
		} else {
2693
			$this->SetBorrow("");
2694
		}
2695
	}
2696

    
2697
	function build_javascript() {
2698
		return parent::build_javascript();
2699
	}
2700

    
2701
	function build_tree() {
2702
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2703
		$tree .= "\" ";
2704
		$tmpvalue = trim($this->GetDefault());
2705
		if (!empty($tmpvalue)) {
2706
			$tree .= " class=\"navlnk\"";
2707
		}
2708
		$tree .= " >" . $this->GetQname() . "</a>";
2709
		if (is_array($this->subqueues)) {
2710
			$tree .= "<ul>";
2711
			foreach ($this->subqueues as $q) {
2712
				$tree .= $q->build_tree();
2713
			}
2714
			$tree .= "</ul>";
2715
		}
2716
		$tree .= "</li>";
2717
		return $tree;
2718
	}
2719

    
2720
	/* Even this should take children into consideration */
2721
	function build_rules(&$default = false) {
2722
		$pfq_rule = "queue ". $this->qname;
2723
		if ($this->GetInterface()) {
2724
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2725
		}
2726
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2727
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2728
		}
2729
		$tmpvalue = $this->GetQpriority();
2730
		if (!empty($tmpvalue)) {
2731
			$pfq_rule .= " priority " . $this->GetQpriority();
2732
		}
2733
		$tmpvalue = trim($this->GetQlimit());
2734
		if (!empty($tmpvalue)) {
2735
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2736
		}
2737
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow() || $this->GetCodel()) {
2738
			$pfq_rule .= " cbq ( ";
2739
			$tmpvalue = trim($this->GetRed());
2740
			if (!empty($tmpvalue)) {
2741
				$comma = 1;
2742
				$pfq_rule .= " red ";
2743
			}
2744
			$tmpvalue = trim($this->GetCodel());
2745
			if (!empty($tmpvalue)) {
2746
				$comma = 1;
2747
				$pfq_rule .= " codel ";
2748
			}
2749
			$tmpvalue = trim($this->GetRio());
2750
			if (!empty($tmpvalue)) {
2751
				if ($comma) {
2752
					$pfq_rule .= " ,";
2753
				}
2754
				$comma = 1;
2755
				$pfq_rule .= " rio ";
2756
			}
2757
			$tmpvalue = trim($this->GetEcn());
2758
			if (!empty($tmpvalue)) {
2759
				if ($comma) {
2760
					$pfq_rule .= " ,";
2761
				}
2762
				$comma = 1;
2763
				$pfq_rule .= " ecn ";
2764
			}
2765
			$tmpvalue = trim($this->GetDefault());
2766
			if (!empty($tmpvalue)) {
2767
				if ($comma) {
2768
					$pfq_rule .= " ,";
2769
				}
2770
				$comma = 1;
2771
				$pfq_rule .= " default ";
2772
				$default = true;
2773
			}
2774
			$tmpvalue = trim($this->GetBorrow());
2775
			if (!empty($tmpvalue)) {
2776
				if ($comma) {
2777
					$pfq_rule .= ", ";
2778
				}
2779
				$pfq_rule .= " borrow ";
2780
			}
2781
			$pfq_rule .= " ) ";
2782
		}
2783
		if (count($this->subqueues)) {
2784
			$i = count($this->subqueues);
2785
			$pfq_rule .= " { ";
2786
			foreach ($this->subqueues as $qkey => $qnone) {
2787
				if ($i > 1) {
2788
					$i--;
2789
					$pfq_rule .= " {$qkey}, ";
2790
				} else {
2791
					$pfq_rule .= " {$qkey} ";
2792
				}
2793
			}
2794
			$pfq_rule .= " } \n";
2795
			foreach ($this->subqueues as $q) {
2796
				$pfq_rule .= $q->build_rules($default);
2797
			}
2798
		}
2799

    
2800
		$pfq_rule .= " \n";
2801
		return $pfq_rule;
2802
	}
2803

    
2804
	function build_form() {
2805
		$sform = parent::build_form();
2806

    
2807
		$section = new Form_Section('');
2808

    
2809
		$group = new Form_Group('Bandwidth');
2810

    
2811
		$group->add(new Form_Input(
2812
			'bandwidth',
2813
			null,
2814
			'number',
2815
			$this->GetBandwidth()
2816
		));
2817

    
2818
		$group->add(new Form_Select(
2819
			'bandwidthtype',
2820
			null,
2821
			$this->GetBwscale(),
2822
			array('Kb' => 'Kbit/s',
2823
				  'Mb' => 'Mbit/s',
2824
				  'Gb' => 'Gbit/s',
2825
				  'b' => 'Bit/s',
2826
				  '%' => '%')
2827
		));
2828

    
2829
		$group->setHelp('Choose the amount of bandwidth for this queue');
2830

    
2831
		$section->add($group);
2832

    
2833
		$section->addInput(new Form_Checkbox(
2834
			'borrow',
2835
			'Scheduler option',
2836
			'Borrow from other queues when available',
2837
			($this->GetBorrow() == "on")
2838
		));
2839

    
2840
		return $sform;
2841
	}
2842

    
2843
	function update_altq_queue_data(&$data) {
2844
		$this->ReadConfig($data);
2845
	}
2846

    
2847
	function wconfig() {
2848
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2849
		if (!is_array($cflink)) {
2850
			$cflink = array();
2851
		}
2852
		$cflink['interface'] = $this->GetInterface();
2853
		$cflink['qlimit'] = trim($this->GetQlimit());
2854
		if (empty($cflink['qlimit'])) {
2855
			unset($cflink['qlimit']);
2856
		}
2857
		$cflink['priority'] = $this->GetQpriority();
2858
		if (empty($cflink['priority'])) {
2859
			unset($cflink['priority']);
2860
		}
2861
		$cflink['name'] = $this->GetQname();
2862
		$cflink['description'] = $this->GetDescription();
2863
		if (empty($cflink['description'])) {
2864
			unset($cflink['description']);
2865
		}
2866
		$cflink['bandwidth'] = $this->GetBandwidth();
2867
		$cflink['bandwidthtype'] = $this->GetBwscale();
2868
		$cflink['enabled'] = trim($this->GetEnabled());
2869
		if (empty($cflink['enabled'])) {
2870
			unset($cflink['enabled']);
2871
		}
2872
		$cflink['default'] = trim($this->GetDefault());
2873
		if (empty($cflink['default'])) {
2874
			unset($cflink['default']);
2875
		}
2876
		$cflink['red'] = trim($this->GetRed());
2877
		if (empty($cflink['red'])) {
2878
			unset($cflink['red']);
2879
		}
2880
		$cflink['rio'] = trim($this->GetRio());
2881
		if (empty($cflink['rio'])) {
2882
			unset($cflink['rio']);
2883
		}
2884
		$cflink['ecn'] = trim($this->GetEcn());
2885
		if (empty($cflink['ecn'])) {
2886
			unset($cflink['ecn']);
2887
		}
2888
		$cflink['codel'] = trim($this->GetCodel());
2889
		if (empty($cflink['codel'])) {
2890
			unset($cflink['codel']);
2891
		}
2892
		$cflink['borrow'] = trim($this->GetBorrow());
2893
		if (empty($cflink['borrow'])) {
2894
			unset($cflink['borrow']);
2895
		}
2896
	}
2897
}
2898

    
2899
class fairq_queue extends priq_queue {
2900
	var $hogs;
2901
	var $buckets;
2902

    
2903
	function GetBuckets() {
2904
		return $this->buckets;
2905
	}
2906
	function SetBuckets($buckets) {
2907
		$this->buckets = $buckets;
2908
	}
2909
	function GetHogs() {
2910
		return $this->hogs;
2911
	}
2912
	function SetHogs($hogs) {
2913
		$this->hogs = $hogs;
2914
	}
2915
	function CanHaveChildren() {
2916
		return false;
2917
	}
2918

    
2919

    
2920
	function copy_queue($interface, &$cflink) {
2921
		$cflink['interface'] = $interface;
2922
		$cflink['qlimit'] = $this->GetQlimit();
2923
		$cflink['priority'] = $this->GetQpriority();
2924
		$cflink['name'] = $this->GetQname();
2925
		$cflink['description'] = $this->GetDescription();
2926
		$cflink['bandwidth'] = $this->GetBandwidth();
2927
		$cflink['bandwidthtype'] = $this->GetBwscale();
2928
		$cflink['enabled'] = $this->GetEnabled();
2929
		$cflink['default'] = $this->GetDefault();
2930
		$cflink['red'] = $this->GetRed();
2931
		$cflink['rio'] = $this->GetRio();
2932
		$cflink['ecn'] = $this->GetEcn();
2933
		$cflink['buckets'] = $this->GetBuckets();
2934
		$cflink['hogs'] = $this->GetHogs();
2935
	}
2936

    
2937
	/*
2938
	 * Should search even its children
2939
	 */
2940
	function &find_queue($interface, $qname) {
2941
		if ($qname == $this->GetQname()) {
2942
			return $this;
2943
		}
2944
	}
2945

    
2946
	function find_parentqueue($interface, $qname) { return; }
2947

    
2948
	function delete_queue() {
2949
		unref_on_altq_queue_list($this->GetQname());
2950
		cleanup_queue_from_rules($this->GetQname());
2951
		unset_object_by_reference($this->GetLink());
2952
	}
2953

    
2954
	function validate_input($data, &$input_errors) {
2955
		parent::validate_input($data, $input_errors);
2956

    
2957
		if ($data['priority'] > 255) {
2958
				$input_errors[] = gettext("Priority must be an integer between 1 and 255.");
2959
		}
2960
		$reqdfields[] = "bandwidth";
2961
		$reqdfieldsn[] = gettext("Bandwidth");
2962
		$reqdfields[] = "bandwidthtype";
2963
		$reqdfieldsn[] = gettext("Bandwidthtype");
2964

    
2965
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2966
	}
2967

    
2968
	function ReadConfig(&$q) {
2969
		parent::ReadConfig($q);
2970
		if (!empty($q['buckets'])) {
2971
			$this->SetBuckets($q['buckets']);
2972
		} else {
2973
			$this->SetBuckets("");
2974
		}
2975
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs'])) {
2976
			$this->SetHogs($q['hogs']);
2977
		} else {
2978
			$this->SetHogs("");
2979
		}
2980
	}
2981

    
2982
	function build_javascript() {
2983
		return parent::build_javascript();
2984
	}
2985

    
2986
	function build_tree() {
2987
		$tree = " <li><a href=\"firewall_shaper.php?interface=" .
2988
		$this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2989
		$tree .= "\" ";
2990
		$tmpvalue = trim($this->GetDefault());
2991
		if (!empty($tmpvalue)) {
2992
			$tree .= " class=\"navlnk\"";
2993
		}
2994
		$tree .= " >" . $this->GetQname() . "</a>";
2995
		$tree .= "</li>";
2996
		return $tree;
2997
	}
2998

    
2999
	/* Even this should take children into consideration */
3000
	function build_rules(&$default = false) {
3001
		$pfq_rule = "queue ". $this->qname;
3002
		if ($this->GetInterface()) {
3003
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
3004
		}
3005
		if ($this->GetBandwidth() && $this->GetBwscale()) {
3006
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
3007
		}
3008
		$tmpvalue = trim($this->GetQpriority());
3009
		if (!empty($tmpvalue)) {
3010
			$pfq_rule .= " priority " . $this->GetQpriority();
3011
		}
3012
		$tmpvalue = trim($this->GetQlimit());
3013
		if (!empty($tmpvalue)) {
3014
			$pfq_rule .= " qlimit " . $this->GetQlimit();
3015
		}
3016
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() ||
3017
		    $this->GetEcn() || $this->GetBuckets() || $this->GetHogs() || $this->GetCodel()) {
3018
			$pfq_rule .= " fairq ( ";
3019
			$tmpvalue = trim($this->GetRed());
3020
			if (!empty($tmpvalue)) {
3021
				$comma = 1;
3022
				$pfq_rule .= " red ";
3023
			}
3024
			$tmpvalue = trim($this->GetCodel());
3025
			if (!empty($tmpvalue)) {
3026
				$comma = 1;
3027
				$pfq_rule .= " codel ";
3028
			}
3029
			$tmpvalue = trim($this->GetRio());
3030
			if (!empty($tmpvalue)) {
3031
				if ($comma) {
3032
					$pfq_rule .= " ,";
3033
				}
3034
				$comma = 1;
3035
				$pfq_rule .= " rio ";
3036
			}
3037
			$tmpvalue = trim($this->GetEcn());
3038
			if (!empty($tmpvalue)) {
3039
				if ($comma) {
3040
					$pfq_rule .= " ,";
3041
				}
3042
				$comma = 1;
3043
				$pfq_rule .= " ecn ";
3044
			}
3045
			$tmpvalue = trim($this->GetDefault());
3046
			if (!empty($tmpvalue)) {
3047
				if ($comma) {
3048
					$pfq_rule .= " ,";
3049
				}
3050
				$comma = 1;
3051
				$pfq_rule .= " default ";
3052
				$default = true;
3053
			}
3054
			$tmpvalue = trim($this->GetBuckets());
3055
			if (!empty($tmpvalue)) {
3056
				if ($comma) {
3057
					$pfq_rule .= ", ";
3058
				}
3059
				$pfq_rule .= " buckets " . $this->GetBuckets() . " ";
3060
			}
3061
			$tmpvalue = trim($this->GetHogs());
3062
			if (!empty($tmpvalue)) {
3063
				if ($comma) {
3064
					$pfq_rule .= ", ";
3065
				}
3066
				$pfq_rule .= " hogs " . $this->GetHogs() . " ";
3067
			}
3068
			$pfq_rule .= " ) ";
3069
		}
3070

    
3071
		$pfq_rule .= " \n";
3072
		return $pfq_rule;
3073
	}
3074

    
3075
	function build_form() {
3076
		$form = parent::build_form();
3077

    
3078
		$section = new Form_Section('');
3079

    
3080
		$group = new Form_Group('Bandwidth');
3081

    
3082
		$group->add(new Form_Input(
3083
			'bandwidth',
3084
			null,
3085
			'number',
3086
			$this->GetBandwidth()
3087
		));
3088

    
3089
		$group->add(new Form_Select(
3090
			'bandwidthtype',
3091
			null,
3092
			$this->GetBwscale(),
3093
			array('Kb' => 'Kbit/s',
3094
				  'Mb' => 'Mbit/s',
3095
				  'Gb' => 'Gbit/s',
3096
				  'b' => 'Bit/s',
3097
				  '%' => '%')
3098
		));
3099

    
3100
		$group->setHelp('Choose the amount of bandwidth for this queue');
3101

    
3102
		$section->add($group);
3103

    
3104
		$section->addInput(new Form_Input(
3105
			'buckets',
3106
			'Scheduler specific options',
3107
			'text',
3108
			$this->GetBuckets()
3109
		))->setHelp('Number of buckets available');
3110

    
3111
		$section->addInput(new Form_Input(
3112
			'hogs',
3113
			'',
3114
			'text',
3115
			$this->GetHogs()
3116
			))->setHelp('Bandwidth limit for hosts to not saturate link');
3117

    
3118
		$form->add($section);
3119
		return $form;
3120
	}
3121

    
3122
	function update_altq_queue_data(&$data) {
3123
		$this->ReadConfig($data);
3124
	}
3125

    
3126
	function wconfig() {
3127
		$cflink =& get_reference_to_me_in_config($this->GetLink());
3128
		if (!is_array($cflink)) {
3129
			$cflink = array();
3130
		}
3131
		$cflink['interface'] = $this->GetInterface();
3132
		$cflink['qlimit'] = trim($this->GetQlimit());
3133
		if (empty($cflink['qlimit'])) {
3134
			unset($cflink['qlimit']);
3135
		}
3136
		$cflink['priority'] = trim($this->GetQpriority());
3137
		if (empty($cflink['priority'])) {
3138
			unset($cflink['priority']);
3139
		}
3140
		$cflink['name'] = $this->GetQname();
3141
		$cflink['description'] = trim($this->GetDescription());
3142
		if (empty($cflink['description'])) {
3143
			unset($cflink['description']);
3144
		}
3145
		$cflink['bandwidth'] = $this->GetBandwidth();
3146
		$cflink['bandwidthtype'] = $this->GetBwscale();
3147
		$cflink['enabled'] = $this->GetEnabled();
3148
		if (empty($cflink['enabled'])) {
3149
			unset($cflink['enabled']);
3150
		}
3151
		$cflink['default'] = trim($this->GetDefault());
3152
		if (empty($cflink['default'])) {
3153
			unset($cflink['default']);
3154
		}
3155
		$cflink['red'] = trim($this->GetRed());
3156
		if (empty($cflink['red'])) {
3157
			unset($cflink['red']);
3158
		}
3159
		$cflink['rio'] = trim($this->GetRio());
3160
		if (empty($cflink['rio'])) {
3161
			unset($cflink['rio']);
3162
		}
3163
		$cflink['ecn'] = trim($this->GetEcn());
3164
		if (empty($cflink['ecn'])) {
3165
			unset($cflink['ecn']);
3166
		}
3167
		$cflink['codel'] = trim($this->GetCodel());
3168
		if (empty($cflink['codel'])) {
3169
			unset($cflink['codel']);
3170
		}
3171
		$cflink['buckets'] = trim($this->GetBuckets());
3172
		if (empty($cflink['buckets'])) {
3173
			unset($cflink['buckets']);
3174
		}
3175
		$cflink['hogs'] = trim($this->GetHogs());
3176
		if (empty($cflink['hogs'])) {
3177
			unset($cflink['hogs']);
3178
		}
3179
	}
3180
}
3181

    
3182

    
3183
/*
3184
 * dummynet(4) wrappers.
3185
 */
3186

    
3187

    
3188
/*
3189
 * List of respective objects!
3190
 */
3191
$dummynet_pipe_list = array();
3192

    
3193
class dummynet_class {
3194
	var $qname;
3195
	var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
3196
	var $qlimit;
3197
	var $description;
3198
	var $qenabled;
3199
	var $link;
3200
	var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
3201
	var $plr;
3202

    
3203
	var $buckets;
3204
	/* mask parameters */
3205
	var $mask;
3206
	var $noerror;
3207

    
3208
	/* Accessor functions */
3209
	function SetLink($link) {
3210
		$this->link = $link;
3211
	}
3212
	function GetLink() {
3213
		return $this->link;
3214
	}
3215
	function GetMask() {
3216
		if (!isset($this->mask["type"])) {
3217
			$this->mask["type"] = "none";
3218
		}
3219
		return $this->mask;
3220
	}
3221
	function SetMask($mask) {
3222
		$this->mask = $mask;
3223
	}
3224
	function &GetParent() {
3225
		return $this->qparent;
3226
	}
3227
	function SetParent(&$parent) {
3228
		$this->qparent = &$parent;
3229
	}
3230
	function GetEnabled() {
3231
		return $this->qenabled;
3232
	}
3233
	function SetEnabled($value) {
3234
		$this->qenabled = $value;
3235
	}
3236
	function CanHaveChildren() {
3237
		return false;
3238
	}
3239
	function CanBeDeleted() {
3240
		return true;
3241
	}
3242
	function GetQname() {
3243
		return $this->qname;
3244
	}
3245
	function SetQname($name) {
3246
		$this->qname = trim($name);
3247
	}
3248
	function GetQlimit() {
3249
		return $this->qlimit;
3250
	}
3251
	function SetQlimit($limit) {
3252
		$this->qlimit = $limit;
3253
	}
3254
	function GetDescription() {
3255
		return $this->description;
3256
	}
3257
	function SetDescription($str) {
3258
		$this->description = trim($str);
3259
	}
3260
	function GetFirstime() {
3261
		return $this->firsttime;
3262
	}
3263
	function SetFirsttime($number) {
3264
		$this->firsttime = $number;
3265
	}
3266
	function GetBuckets() {
3267
		return $this->buckets;
3268
	}
3269
	function SetBuckets($buckets) {
3270
		$this->buckets = $buckets;
3271
	}
3272
	function SetNumber($number) {
3273
		$this->qnumber = $number;
3274
	}
3275
	function GetNumber() {
3276
		return $this->qnumber;
3277
	}
3278
	function GetPlr() {
3279
		return $this->plr;
3280
	}
3281
	function SetPlr($plr) {
3282
		$this->plr = $plr;
3283
	}
3284

    
3285
	function build_javascript() {
3286
		$javascript .= "<script type=\"text/javascript\">\n";
3287
		$javascript .= "//<![CDATA[\n";
3288
		$javascript .= "function enable_maskbits(enable_over) {\n";
3289
		$javascript .= "var e = document.getElementById(\"mask\");\n";
3290
		$javascript .= "if ((e.options[e.selectedIndex].text == \"none\") || enable_over) {\n";
3291
		$javascript .= "document.iform.maskbits.disabled = 1;\n";
3292
		$javascript .= "document.iform.maskbits.value = \"\";\n";
3293
		$javascript .= "document.iform.maskbitsv6.disabled = 1;\n";
3294
		$javascript .= "document.iform.maskbitsv6.value = \"\";\n";
3295
		$javascript .= "} else {\n";
3296
		$javascript .= "document.iform.maskbits.disabled = 0;\n";
3297
		$javascript .= "document.iform.maskbitsv6.disabled = 0;\n";
3298
		$javascript .= "}}\n";
3299
		$javascript .= "//]]>\n";
3300
		$javascript .= "</script>\n";
3301
		return $javascript;
3302
	}
3303

    
3304
	function validate_input($data, &$input_errors) {
3305
		$reqdfields[] = "bandwidth";
3306
		$reqdfieldsn[] = gettext("Bandwidth");
3307
		/*$reqdfields[] = "burst";
3308
		$reqdfieldsn[] = gettext("Burst"); */
3309
		$reqdfields[] = "bandwidthtype";
3310
		$reqdfieldsn[] = gettext("Bandwidthtype");
3311
		$reqdfields[] = "newname";
3312
		$reqdfieldsn[] = gettext("Name");
3313

    
3314
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3315

    
3316
		if ($data['plr'] && (!is_numeric($data['plr']) ||
3317
		    ($data['plr'] < 0) || ($data['plr'] > 1))) {
3318
			$input_errors[] = gettext("Plr must be a value between 0 and 1.");
3319
		}
3320
		if ($data['buckets'] && (!is_numeric($data['buckets']) ||
3321
		    ($data['buckets'] < 16) || ($data['buckets'] > 65535))) {
3322
			$input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
3323
		}
3324
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
3325
			$input_errors[] = gettext("Queue limit must be an integer");
3326
		}
3327
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname'])) {
3328
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3329
		}
3330
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name'])) {
3331
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3332
		}
3333
		if (isset($data['maskbits']) && ($data['maskbits'] <> "")) {
3334
			if ((!is_numeric($data['maskbits'])) || ($data['maskbits'] <= 0) || ($data['maskbits'] > 32)) {
3335
				$input_errors[] = gettext("IPV4 bit mask must be blank or numeric value between 1 and 32.");
3336
			}
3337
		}
3338
		if (isset($data['maskbitsv6']) && ($data['maskbitsv6'] <> "")) {
3339
			if ((!is_numeric($data['maskbitsv6'])) || ($data['maskbitsv6'] <= 0) || ($data['maskbitsv6'] > 128)) {
3340
				$input_errors[] = gettext("IPV6 bit mask must be blank or numeric value between 1 and 128.");
3341
			}
3342
		}
3343
	}
3344

    
3345
	function build_mask_rules(&$pfq_rule) {
3346
		$mask = $this->GetMask();
3347
		if (!empty($mask['type'])) {
3348
			if ($mask['type'] <> 'none') {
3349
				$pfq_rule .= " mask";
3350
			}
3351
			switch ($mask['type']) {
3352
				case 'srcaddress':
3353
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3354
						$pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
3355
					} else {
3356
						$pfq_rule .= " src-ip6 /128";
3357
					}
3358
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3359
						$pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3360
					} else {
3361
						$pfq_rule .= " src-ip 0xffffffff";
3362
					}
3363
					break;
3364
				case 'dstaddress':
3365
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3366
						$pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
3367
					} else {
3368
						$pfq_rule .= " dst-ip6 /128";
3369
					}
3370
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3371
						$pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3372
					} else {
3373
						$pfq_rule .= " dst-ip 0xffffffff";
3374
					}
3375
					break;
3376
				default:
3377
					break;
3378
			}
3379
		}
3380
	}
3381

    
3382
}
3383

    
3384
class dnpipe_class extends dummynet_class {
3385
	var $delay;
3386
	var $qbandwidth = array();
3387
	var $qbandwidthtype;
3388

    
3389
		/* This is here to help on form building and building rules/lists */
3390
	var $subqueues = array();
3391

    
3392
	function CanHaveChildren() {
3393
		return true;
3394
	}
3395
	function SetDelay($delay) {
3396
		$this->delay = $delay;
3397
	}
3398
	function GetDelay() {
3399
		return $this->delay;
3400
	}
3401
	function delete_queue() {
3402
		cleanup_dnqueue_from_rules($this->GetQname());
3403
		foreach ($this->subqueues as $q) {
3404
			$q->delete_queue();
3405
		}
3406
		unset_dn_object_by_reference($this->GetLink());
3407
		@pfSense_pipe_action("pipe delete " . $this->GetNumber());
3408
	}
3409
	function GetBandwidth() {
3410
		return $this->qbandwidth;
3411
	}
3412
	function SetBandwidth($bandwidth) {
3413
		$this->qbandwidth = $bandwidth;
3414
	}
3415
	function GetBurst() {
3416
		return $this->qburst;
3417
	}
3418
	function SetBurst($burst) {
3419
		$this->qburst = $burst;
3420
	}
3421

    
3422
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
3423

    
3424
		if (!is_array($this->subqueues)) {
3425
			$this->subqueues = array();
3426
		}
3427

    
3428
		$q =& new dnqueue_class();
3429
		$q->SetLink($path);
3430
		$q->SetEnabled("on");
3431
		$q->SetPipe($this->GetQname());
3432
		$q->SetParent($this);
3433
		$q->ReadConfig($queue);
3434
		$q->validate_input($queue, $input_errors);
3435
		if (count($input_errors)) {
3436
			log_error(sprintf(gettext('SHAPER: Could not create queue %1$s on interface %2$s because: %3$s'), $q->GetQname(), $interface, print_r($input_errors, true)));
3437
			return $q;
3438
		}
3439
		$number = dnqueue_find_nextnumber();
3440
		$q->SetNumber($number);
3441
		$this->subqueues[$q->GetQname()] = &$q;
3442

    
3443
		return $q;
3444
	}
3445

    
3446
	function &get_queue_list(&$q = null) {
3447
		$qlist = array();
3448

    
3449
		$qlist[$this->GetQname()] = $this->GetNumber();
3450
		if (is_array($this->subqueues)) {
3451
			foreach ($this->subqueues as $queue) {
3452
				$queue->get_queue_list($qlist);
3453
			}
3454
		}
3455
		return $qlist;
3456
	}
3457

    
3458
	/*
3459
	 * Should search even its children
3460
	 */
3461
	function &find_queue($pipe, $qname) {
3462
		if ($qname == $this->GetQname()) {
3463
			return $this;
3464
		}
3465
		foreach ($this->subqueues as $q) {
3466
			$result =& $q->find_queue("", $qname);
3467
			if ($result) {
3468
				return $result;
3469
			}
3470
		}
3471
	}
3472

    
3473
	function &find_parentqueue($pipe, $qname) {
3474
		return NULL;
3475
	}
3476

    
3477
	function validate_input($data, &$input_errors) {
3478
		parent::validate_input($data, $input_errors);
3479

    
3480
		$schedule = 0;
3481
		$schedulenone = 0;
3482
		$entries = 0;
3483
		/* XXX: Really no better way? */
3484
		for ($i = 0; $i < 2900; $i++) {
3485
			if (!empty($data["bwsched{$i}"])) {
3486
				if ($data["bwsched{$i}"] != "none") {
3487
					$schedule++;
3488
				} else {
3489
					$schedulenone++;
3490
				}
3491
			}
3492
			if (!empty($data["bandwidth{$i}"])) {
3493
				if (!is_numeric($data["bandwidth{$i}"])) {
3494
					$input_errors[] = sprintf(gettext("Bandwidth for schedule %s must be an integer."), $data["bwsched{$i}"]);
3495
				} else if (($data["burst{$i}"] != "") && (!is_numeric($data["burst{$i}"]))) {
3496
					$input_errors[] = sprintf(gettext("Burst for schedule %s must be an integer."), $data["bwsched{$i}"]);
3497
				} else {
3498
					$entries++;
3499
				}
3500
			}
3501
		}
3502
		if ($schedule == 0 && $entries > 1) {
3503
			$input_errors[] = gettext("A schedule needs to be specified for every additional entry.");
3504
		}
3505
		if ($schedulenone > 0 && $entries > 1) {
3506
			$input_errors[] = gettext("If more than one bandwidth configured all schedules need to be selected.");
3507
		}
3508
		if ($entries == 0) {
3509
			$input_errors[] = gettext("At least one bw specification is necessary.");
3510
		}
3511
		if ($data['delay'] && (!is_numeric($data['delay']))) {
3512
			$input_errors[] = gettext("Delay must be an integer.");
3513
		}
3514
	}
3515

    
3516
	function ReadConfig(&$q) {
3517
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3518
			$this->SetQname($q['newname']);
3519
		} else if (!empty($q['newname'])) {
3520
			$this->SetQname($q['newname']);
3521
		} else {
3522
			$this->SetQname($q['name']);
3523
		}
3524
		$this->SetNumber($q['number']);
3525

    
3526
		if (!empty($_POST)) {
3527
			$bandwidth = array();
3528
			/* XXX: Really no better way? */
3529
			for ($i = 0; $i < 2900; $i++) {
3530
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") {
3531
					$bw = array();
3532
					$bw['bw'] = $q["bandwidth{$i}"];
3533
					$bw['burst'] = $q["burst{$i}"];
3534
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"]) {
3535
						$bw['bwscale'] = $q["bwtype{$i}"];
3536
					}
3537
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"]) {
3538
						$bw['bwsched'] = $q["bwsched{$i}"];
3539
					}
3540
					$bandwidth[] = $bw;
3541
				}
3542
			}
3543
			$this->SetBandwidth($bandwidth);
3544
		}
3545

    
3546
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
3547
			$this->SetBandwidth($q['bandwidth']['item']);
3548
			$this->SetBurst($q['burst']['item']);
3549
		}
3550

    
3551
		if (isset($q['qlimit']) && $q['qlimit'] <> "") {
3552
			$this->SetQlimit($q['qlimit']);
3553
		} else {
3554
			$this->SetQlimit("");
3555
		}
3556
		if (isset($q['mask']) && $q['mask'] <> "") {
3557
			$masktype = $q['mask'];
3558
		} else {
3559
			$masktype = "";
3560
		}
3561
		if (isset($q['maskbits']) && $q['maskbits'] <> "") {
3562
			$maskbits = $q['maskbits'];
3563
		} else {
3564
			$maskbits = "";
3565
		}
3566
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
3567
			$maskbitsv6 = $q['maskbitsv6'];
3568
		} else {
3569
			$maskbitsv6 = "";
3570
		}
3571
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3572
		if (isset($q['buckets']) && $q['buckets'] <> "") {
3573
			$this->SetBuckets($q['buckets']);
3574
		} else {
3575
			$this->SetBuckets("");
3576
		}
3577
		if (isset($q['plr']) && $q['plr'] <> "") {
3578
			$this->SetPlr($q['plr']);
3579
		} else {
3580
			$this->SetPlr("");
3581
		}
3582
		if (isset($q['delay']) && $q['delay'] <> "") {
3583
			$this->SetDelay($q['delay']);
3584
		} else {
3585
			$this->SetDelay(0);
3586
		}
3587
		if (isset($q['description']) && $q['description'] <> "") {
3588
			$this->SetDescription($q['description']);
3589
		} else {
3590
			$this->SetDescription("");
3591
		}
3592
		$this->SetEnabled($q['enabled']);
3593

    
3594
	}
3595

    
3596
	function build_tree() {
3597
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&amp;queue=".$this->GetQname() ."&amp;action=show\">";
3598
		$tree .= $this->GetQname() . "</a>";
3599
		if (is_array($this->subqueues)) {
3600
			$tree .= "<ul>";
3601
			foreach ($this->subqueues as $q) {
3602
				$tree .= $q->build_tree();
3603
			}
3604
			$tree .= "</ul>";
3605
		}
3606
		$tree .= "</li>";
3607

    
3608
		return $tree;
3609
	}
3610

    
3611
	function build_rules() {
3612
		global $config, $time_based_rules;
3613

    
3614
		if ($this->GetEnabled() == "") {
3615
			return;
3616
		}
3617

    
3618
		$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
3619
		$found = false;
3620
		$bandwidth = $this->GetBandwidth();
3621
		if (is_array($bandwidth)) {
3622
			foreach ($bandwidth as $bw) {
3623
				if ($bw['bwsched'] != "none") {
3624
					$time_based_rules = true;
3625
					if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3626
						foreach ($config['schedules']['schedule'] as $schedule) {
3627
							if ($bw['bwsched'] == $schedule['name']) {
3628
								if (filter_get_time_based_rule_status($schedule)) {
3629
									$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3630
									if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3631
										$pfq_rule .= " burst ".trim($bw['burst']);
3632
									}
3633
									$found = true;
3634
									break;
3635
								}
3636
							}
3637
						}
3638
					} else {
3639
						$pfq_rule .= " bw 0";
3640
						$found = true;
3641
						break;
3642
					}
3643
				} else {
3644
					$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3645
					if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3646
						$pfq_rule .= " burst ".trim($bw['burst']);
3647
					}
3648
					$found = true;
3649
					break;
3650
				}
3651
			}
3652
			if ($found == false) {
3653
				$pfq_rule .= " bw 0";
3654
			}
3655
		} else {
3656
			$pfq_rule .= " bw 0";
3657
		}
3658

    
3659
		if ($this->GetQlimit()) {
3660
			$pfq_rule .= " queue " . $this->GetQlimit();
3661
		}
3662
		if ($this->GetPlr()) {
3663
			$pfq_rule .= " plr " . $this->GetPlr();
3664
		}
3665
		if ($this->GetBuckets()) {
3666
			$pfq_rule .= " buckets " . $this->GetBuckets();
3667
		}
3668
		if ($this->GetDelay()) {
3669
			$pfq_rule .= " delay " . $this->GetDelay();
3670
		}
3671
		$this->build_mask_rules($pfq_rule);
3672

    
3673
		$pfq_rule .= "\n";
3674

    
3675
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3676
			foreach ($this->subqueues as $q) {
3677
				$pfq_rule .= $q->build_rules();
3678
			}
3679
		}
3680
		$pfq_rule .= " \n";
3681

    
3682
		return $pfq_rule;
3683
	}
3684

    
3685
	function update_dn_data(&$data) {
3686
		$this->ReadConfig($data);
3687
	}
3688

    
3689
	function build_javascript() {
3690
		global $g, $config;
3691

    
3692
		$javasr = parent::build_javascript();
3693

    
3694
		//build list of schedules
3695
		$schedules = "<option value='none'>none</option>";
3696
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3697
			foreach ($config['schedules']['schedule'] as $schedule) {
3698
				if ($schedule['name'] <> "") {
3699
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3700
				}
3701
			}
3702
		}
3703
		$bwopt = "";
3704
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw) {
3705
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3706
		}
3707

    
3708
		$javasr .= <<<EOD
3709
<script type='text/javascript'>
3710
//<![CDATA[
3711
var addBwRowTo = (function() {
3712

    
3713
	return (function (tableId) {
3714

    
3715
	var table = document.getElementById(tableId);
3716
	var totalrows = table.rows.length -1;
3717

    
3718
	var row = table.insertRow(totalrows + 1);
3719
	var cell1 = row.insertCell(0);
3720
	var cell2 = row.insertCell(1);
3721
	var cell3 = row.insertCell(2);
3722
	var cell4 = row.insertCell(3);
3723

    
3724
	cell1.innerHTML = "<input type='hidden' value='" + totalrows +"' name='bandwidth_row-" + totalrows + "' /><input type='text' class='form-control' name='bandwidth" + totalrows + "' id='bandwidth" + totalrows + "' />";
3725
	cell2.innerHTML = "<input type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "' /><select class='form-control' name='bwtype" + totalrows + "'>{$bwopt}</select>";
3726
	cell3.innerHTML = "<input type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "' /><select class='form-control' name='bwsched" + totalrows + "'>{$schedules}</select>";
3727
	cell4.innerHTML = '<a class="btn btn-warning" onclick="removeBwRow(this); return false;" href="#"><i class="fa fa-trash icon-embed-btn"></i>Delete</a>';
3728

    
3729
	});
3730
})();
3731

    
3732
function removeBwRow(el) {
3733
	var d = el.parentNode.parentNode.rowIndex;
3734
	document.getElementById('maintable').deleteRow(d);
3735
}
3736
//]]>
3737
</script>
3738

    
3739
EOD;
3740

    
3741
		return $javasr;
3742
	}
3743

    
3744
	// Compose a table of bandwidths that can then be inserted into the form using a Form_StaticText
3745
	// The table has been "Bootstrapped" to match the web design while maintaining compatibility with
3746
	// with the javascript in this class
3747
	function build_bwtable() {
3748
		global $config;
3749

    
3750
		$bandwidth = $this->GetBandwidth();
3751
				//build list of schedules
3752
		$schedules = array();
3753
		$schedules[] = "none";//leave none to leave rule enabled all the time
3754
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3755
			foreach ($config['schedules']['schedule'] as $schedule) {
3756
				if ($schedule['name'] != "") {
3757
					$schedules[] = $schedule['name'];
3758
				}
3759
			}
3760
		}
3761

    
3762
		$form = '<div class="table-responsive">';
3763
		$form .= '<table id="maintable" class="table table-hover table-striped">';
3764
		$form .= "<thead><tr>";
3765
		$form .= "<th>Bandwidth</th>";
3766
		//$form .= "<td width='35%'><div id='fifthcolumn'>Burst</div></td>";
3767
		$form .= "<th>Bw type</th>";
3768
		$form .= "<th>Schedule</th>";
3769
		$form .= "<th></th>";
3770
		$form .= "</tr></thead>";
3771
		$form .= "<tbody>";
3772

    
3773
		// If there are no bandwidths defined, make a blank one for convenience
3774
		if (empty($bandwidth)) {
3775
			$bandwidth = array(0 => array('bw' => '', 'bwscale' => 'Kb', 'bwsched' => 'none'));
3776
		}
3777

    
3778
		if (is_array($bandwidth)) {
3779
			foreach ($bandwidth as $bwidx => $bw) {
3780
				$form .= '<tr>';
3781
				$form .= '<td class="col-xs-4">';
3782
				$form .= "<input class='form-control' type=\"number\" id=\"bandwidth{$bwidx}\" name=\"bandwidth{$bwidx}\" value=\"{$bw['bw']}\" />";
3783
				//$form .= "</td><td width='20%'>";
3784
				//$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"burst{$bwidx}\" name=\"burst{$bwidx}\" value=\"{$bw['burst']}\" />";
3785
				$form .= "</td>";
3786
				$form .= '<td class="col-xs-4">';
3787
				$form .= "<select id=\"bwtype{$bwidx}\" name=\"bwtype{$bwidx}\" class=\"form-control\">";
3788

    
3789
				foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "b" => "Bit/s") as $bwsidx => $bwscale) {
3790
					$form .= "<option value=\"{$bwsidx}\"";
3791

    
3792
					if ($bw['bwscale'] == $bwsidx) {
3793
						$form .= " selected";
3794
					}
3795

    
3796
					$form .= ">{$bwscale}</option>";
3797
				}
3798

    
3799
				$form .= "</select>";
3800
				$form .= "</td>";
3801
				$form .= '<td class="col-xs-4">';
3802
				$form .= "<select id=\"bwsched{$bwidx}\" name=\"bwsched{$bwidx}\" class=\"form-control\">";
3803

    
3804
				foreach ($schedules as $schd) {
3805
					$selected = "";
3806
					if ($bw['bwsched'] == $schd) {
3807
						$selected = "selected";
3808
					}
3809

    
3810
					$form .= "<option value='{$schd}' {$selected}>{$schd}</option>";
3811
				}
3812

    
3813
				$form .= "</select>";
3814
				$form .= "</td>";
3815
				$form .= '<td>';
3816
				$form .= '<a class="btn btn-warning" onclick="removeBwRow(this); return false;"><i class="fa fa-trash icon-embed-btn"></i>' . gettext('Delete') . '</a>';
3817
				$form .= "</td></tr>";
3818
			}
3819
		}
3820
		$form .= "</tbody></table></div><br />";
3821

    
3822
		$form .= '<a class="btn btn-sm btn-success" onclick="javascript:addBwRowTo(\'maintable\'); return false;" >';
3823
		$form .= '<i class="fa fa-plus icon-embed-btn"></i>';
3824
		$form .= gettext("Add Schedule") . "</a>";
3825

    
3826
		return($form);
3827
	}
3828

    
3829
	function build_form() {
3830
		global $g, $config, $pipe, $action, $qname;
3831

    
3832
		//build list of schedules
3833
		$schedules = array();
3834
		$schedules[] = "none";//leave none to leave rule enabled all the time
3835
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3836
			foreach ($config['schedules']['schedule'] as $schedule) {
3837
				if ($schedule['name'] <> "") {
3838
					$schedules[] = $schedule['name'];
3839
				}
3840
			}
3841
		}
3842

    
3843

    
3844
		$sform = new Form();
3845
		$sform->setAction("firewall_shaper.php");
3846

    
3847
		$section = new Form_Section('Limiters');
3848

    
3849
		$section->addInput(new Form_Checkbox(
3850
			'enabled',
3851
			'Enable',
3852
			'Enable limiter and its children',
3853
			($this->GetEnabled() == "on"),
3854
			'on'
3855
		));
3856

    
3857
		$section->addInput(new Form_Input(
3858
			'newname',
3859
			'Name',
3860
			'text',
3861
			$this->GetQname()
3862
		));
3863

    
3864
		$section->addInput(new Form_Input(
3865
			'name',
3866
			null,
3867
			'hidden',
3868
			$this->GetQname()
3869
		));
3870

    
3871
		if ($this->GetNumber() > 0) {
3872
			$section->addInput(new Form_Input(
3873
				'number',
3874
				null,
3875
				'hidden',
3876
				$this->GetNumber()
3877
			));
3878
		}
3879

    
3880
		$bandwidth = $this->GetBandwidth();
3881

    
3882
		// Delete a row
3883
//		if(isset($_GET['delbwrow']) && (count($bandwidth) > 0))
3884
//			unset($bandwidth[$_GET['delbwrow']]);
3885

    
3886
		// Add a row
3887
//		if($_GET['newbwrow']) {
3888
//			array_push($bandwidth, array(count($bandwidth) => array('bw' => '', 'burst' => '', 'bwscale' => 'Kb', 'bwsched' => 'none') ));
3889
//		}
3890

    
3891
		if (is_array($bandwidth)) {
3892
				$section->addInput(new Form_StaticText(
3893
				'Bandwidth',
3894
				$this->build_bwtable()
3895
			));
3896
		}
3897

    
3898
		$mask = $this->GetMask();
3899

    
3900
		$section->addInput(new Form_Select(
3901
			'mask',
3902
			'Mask',
3903
			$mask['type'],
3904
			array('none' => gettext('None'), 'srcaddress' => gettext('Source addresses'), 'dstaddress' => gettext('Destination addresses'))
3905
		))->setHelp('If "source" or "destination" slots is chosen a dynamic pipe with the bandwidth, delay, packet loss ' .
3906
					'and queue size given above will be created for each source/destination IP address encountered, respectively. ' .
3907
					'This makes it possible to easily specify bandwidth limits per host.');
3908

    
3909
		$group = new Form_Group(null);
3910

    
3911
		$group->add(new Form_Select(
3912
			'maskbits',
3913
			null,
3914
			$mask['bits'],
3915
			array_combine(range(32, 1, -1), range(32, 1, -1))
3916
		))->setHelp('IPV4 mask bits' . '<br />' . '255.255.255.255/?');
3917

    
3918
		$group->add(new Form_Select(
3919
			'maskbitsv6',
3920
			null,
3921
			$mask['bitsv6'],
3922
			array_combine(range(128, 1, -1), range(128, 1, -1))
3923
		))->setHelp('IPV6 mask bits' . '<br />' . '<span style="font-family:consolas">ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/?</span>');
3924

    
3925
		$section->add($group);
3926

    
3927
		$section->addInput(new Form_Input(
3928
			'description',
3929
			'Description',
3930
			'text',
3931
			$this->GetDescription()
3932
		))->setHelp('A description may be entered here for administrative reference (not parsed).');
3933

    
3934
		$sform->add($section);
3935

    
3936
		$section = new Form_Section('Advanced Options');
3937

    
3938
		$section->addInput(new Form_Input(
3939
			'delay',
3940
			'Delay (ms)',
3941
			'text',
3942
			$this->GetDelay() > 0 ? $this->GetDelay():null
3943
		))->setHelp('In most cases, zero (0) should specified here (or leave the field empty).');
3944

    
3945
		$section->addInput(new Form_Input(
3946
			'plr',
3947
			'Packet Loss Rate',
3948
			'number',
3949
			$this->GetPlr(),
3950
			['step' => '0.001', 'min' => '0.000']
3951
		))->setHelp('In most cases, zero (0) should be specified here (or leave the field empty). ' .
3952
					'A value of 0.001 means one packet in 1000 gets dropped.');
3953

    
3954
		$section->addInput(new Form_Input(
3955
			'qlimit',
3956
			'Queue size (slots)',
3957
			'number',
3958
			$this->GetQlimit()
3959
		))->setHelp('In most cases, the field should be left empty. All packets in this pipe are placed into a fixed-size queue first, ' .
3960
					'then they are delayed by value specified in the Delay field, and then they are delivered to their destination.');
3961

    
3962
		$section->addInput(new Form_Input(
3963
			'buckets',
3964
			'Bucket size (slots)',
3965
			'number',
3966
			$this->GetBuckets()
3967
		))->setHelp('In most cases, this field should be left empty. It increases the hash size set.');
3968

    
3969
		$sform->add($section);
3970

    
3971
		return($sform);
3972
		}
3973

    
3974
	function wconfig() {
3975
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3976
		if (!is_array($cflink)) {
3977
			$cflink = array();
3978
		}
3979
		$cflink['name'] = $this->GetQname();
3980
		$cflink['number'] = $this->GetNumber();
3981
		$cflink['qlimit'] = $this->GetQlimit();
3982
		$cflink['plr'] = $this->GetPlr();
3983
		$cflink['description'] = $this->GetDescription();
3984

    
3985
		$bandwidth = $this->GetBandwidth();
3986
		if (is_array($bandwidth)) {
3987
			$cflink['bandwidth'] = array();
3988
			$cflink['bandwidth']['item'] = array();
3989
			foreach ($bandwidth as $bwidx => $bw) {
3990
				$cflink['bandwidth']['item'][] = $bw;
3991
			}
3992
		}
3993

    
3994
		$cflink['enabled'] = $this->GetEnabled();
3995
		$cflink['buckets'] = $this->GetBuckets();
3996
		$mask = $this->GetMask();
3997
		$cflink['mask'] = $mask['type'];
3998
		$cflink['maskbits'] = $mask['bits'];
3999
		$cflink['maskbitsv6'] = $mask['bitsv6'];
4000
		$cflink['delay'] = $this->GetDelay();
4001
	}
4002

    
4003
}
4004

    
4005
class dnqueue_class extends dummynet_class {
4006
	var $pipeparent;
4007
	var $weight;
4008

    
4009
	function GetWeight() {
4010
		return $this->weight;
4011
	}
4012
	function SetWeight($weight) {
4013
		$this->weight = $weight;
4014
	}
4015
	function GetPipe() {
4016
		return $this->pipeparent;
4017
	}
4018
	function SetPipe($pipe) {
4019
		$this->pipeparent = $pipe;
4020
	}
4021

    
4022
	/* Just a stub in case we ever try to call this from the frontend. */
4023
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
4024
		return;
4025
	}
4026

    
4027
	function delete_queue() {
4028
		cleanup_dnqueue_from_rules($this->GetQname());
4029
		unset_dn_object_by_reference($this->GetLink());
4030
		@pfSense_pipe_action("queue delete " . $this->GetNumber());
4031
	}
4032

    
4033
	function validate_input($data, &$input_errors) {
4034
		parent::validate_input($data, $input_errors);
4035

    
4036
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
4037
		    ($data['weight'] < 1 && $data['weight'] > 100))) {
4038
			$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
4039
		}
4040
	}
4041

    
4042
	/*
4043
	 * Should search even its children
4044
	 */
4045
	function &find_queue($pipe, $qname) {
4046
		if ($qname == $this->GetQname()) {
4047
			return $this;
4048
		} else {
4049
			return NULL;
4050
		}
4051
	}
4052

    
4053
	function &find_parentqueue($pipe, $qname) {
4054
		return $this->qparent;
4055
	}
4056

    
4057
	function &get_queue_list(&$qlist) {
4058
		if ($this->GetEnabled() == "") {
4059
			return;
4060
		}
4061
		$qlist[$this->GetQname()] = "?" .$this->GetNumber();
4062
	}
4063

    
4064
	function ReadConfig(&$q) {
4065
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
4066
			$this->SetQname($q['newname']);
4067
		} else if (!empty($q['newname'])) {
4068
			$this->SetQname($q['newname']);
4069
		} else {
4070
			$this->SetQname($q['name']);
4071
		}
4072
		$this->SetNumber($q['number']);
4073
		if (isset($q['qlimit']) && $q['qlimit'] <> "") {
4074
			$this->SetQlimit($q['qlimit']);
4075
		} else {
4076
			$this->SetQlimit("");
4077
		}
4078
		if (isset($q['mask']) && $q['mask'] <> "") {
4079
			$masktype = $q['mask'];
4080
		} else {
4081
			$masktype = "";
4082
		}
4083
		if (isset($q['maskbits']) && $q['maskbits'] <> "") {
4084
			$maskbits = $q['maskbits'];
4085
		} else {
4086
			$maskbits = "";
4087
		}
4088
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
4089
			$maskbitsv6 = $q['maskbitsv6'];
4090
		} else {
4091
			$maskbitsv6 = "";
4092
		}
4093
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
4094
		if (isset($q['buckets']) && $q['buckets'] <> "") {
4095
			$this->SetBuckets($q['buckets']);
4096
		} else {
4097
			$this->SetBuckets("");
4098
		}
4099
		if (isset($q['plr']) && $q['plr'] <> "") {
4100
			$this->SetPlr($q['plr']);
4101
		} else {
4102
			$this->SetPlr("");
4103
		}
4104
		if (isset($q['weight']) && $q['weight'] <> "") {
4105
			$this->SetWeight($q['weight']);
4106
		} else {
4107
			$this->SetWeight("");
4108
		}
4109
		if (isset($q['description']) && $q['description'] <> "") {
4110
			$this->SetDescription($q['description']);
4111
		} else {
4112
			$this->SetDescription("");
4113
		}
4114
		$this->SetEnabled($q['enabled']);
4115
	}
4116

    
4117
	function build_tree() {
4118
		$parent =& $this->GetParent();
4119
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">";
4120
		$tree .= $this->GetQname() . "</a>";
4121
		$tree .= "</li>";
4122

    
4123
		return $tree;
4124
	}
4125

    
4126
	function build_rules() {
4127
		if ($this->GetEnabled() == "") {
4128
			return;
4129
		}
4130

    
4131
		$parent =& $this->GetParent();
4132
		$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
4133
		if ($this->GetQlimit()) {
4134
			$pfq_rule .= " queue " . $this->GetQlimit();
4135
		}
4136
		if ($this->GetWeight()) {
4137
			$pfq_rule .= " weight " . $this->GetWeight();
4138
		}
4139
		if ($this->GetBuckets()) {
4140
			$pfq_rule .= " buckets " . $this->GetBuckets();
4141
		}
4142
		$this->build_mask_rules($pfq_rule);
4143
		$pfq_rule .= "\n";
4144

    
4145
		return $pfq_rule;
4146
	}
4147

    
4148
	function build_javascript() {
4149
		return parent::build_javascript();
4150
	}
4151

    
4152
	function build_form() {
4153
		global $g, $config, $pipe, $action, $qname;
4154

    
4155
		//build list of schedules
4156
		$schedules = array();
4157
		$schedules[] = "none";//leave none to leave rule enabled all the time
4158
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
4159
			foreach ($config['schedules']['schedule'] as $schedule) {
4160
				if ($schedule['name'] <> "") {
4161
					$schedules[] = $schedule['name'];
4162
				}
4163
			}
4164
		}
4165

    
4166

    
4167
		$sform = new Form();
4168
		$sform->setAction("firewall_shaper.php");
4169
		$section = new Form_Section('Limiters');
4170

    
4171
		$section->addInput(new Form_Checkbox(
4172
			'enabled',
4173
			'Enable',
4174
			'Enable this queue',
4175
			($this->GetEnabled() == "on"),
4176
			'on'
4177
		));
4178

    
4179
		$section->addInput(new Form_Input(
4180
			'newname',
4181
			'Name',
4182
			'text',
4183
			$this->GetQname()
4184
		));
4185

    
4186
		$section->addInput(new Form_Input(
4187
			'name',
4188
			null,
4189
			'hidden',
4190
			$this->GetQname()
4191
		));
4192

    
4193
		if ($this->GetNumber() > 0) {
4194
			$section->addInput(new Form_Input(
4195
				'number',
4196
				null,
4197
				'hidden',
4198
				$this->GetNumber()
4199
			));
4200
		}
4201

    
4202
		$mask = $this->GetMask();
4203

    
4204
		$section->addInput(new Form_Select(
4205
			'mask',
4206
			'Mask',
4207
			$mask['type'],
4208
			array('none' => gettext('None'), 'srcaddress' => gettext('Source addresses'), 'dstaddress' => gettext('Destination addresses'))
4209
		))->setHelp('If "source" or "destination" slots is chosen a dynamic pipe with the bandwidth, delay, packet loss ' .
4210
					'and queue size given above will be created for each source/destination IP address encountered, respectively. ' .
4211
					'This makes it possible to easily specify bandwidth limits per host.');
4212

    
4213
		$group = new Form_Group(null);
4214

    
4215
		$group->add(new Form_Select(
4216
			'maskbits',
4217
			null,
4218
			$mask['bits'],
4219
			array_combine(range(32, 1, -1), range(32, 1, -1))
4220
		))->setHelp('IPV4 mask bits' . '<br />' . '255.255.255.255/?');
4221

    
4222
		$group->add(new Form_Select(
4223
			'maskbitsv6',
4224
			null,
4225
			$mask['bitsv6'],
4226
			array_combine(range(128, 1, -1), range(128, 1, -1))
4227
		))->setHelp('IPV6 mask bits' . '<br />' . '<span style="font-family:consolas">ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/?</span>');
4228

    
4229
		$section->add($group);
4230

    
4231
		$section->addInput(new Form_Input(
4232
			'description',
4233
			'Description',
4234
			'text',
4235
			$this->GetDescription()
4236
		))->setHelp('A description may be entered here for administrative reference (not parsed).');
4237

    
4238
		$sform->add($section);
4239

    
4240
		$section = new Form_Section('Advanced Options');
4241

    
4242
		$section->addInput(new Form_Input(
4243
			'weight',
4244
			'Weight',
4245
			'number',
4246
			$this->GetWeight(),
4247
			['min' => '1', 'max' => '100']
4248
		))->setHelp('For queues under the same parent this specifies the share that a queue gets(values range from 1 to 100),' .
4249
					' it can be left blank otherwise.');
4250

    
4251
		$section->addInput(new Form_Input(
4252
			'plr',
4253
			'Packet Loss Rate',
4254
			'number',
4255
			$this->GetPlr(),
4256
			['step' => '0.001', 'min' => '0.000']
4257
		))->setHelp('In most cases, zero (0) should be specified here (or leave the field empty). ' .
4258
					'A value of 0.001 means one packet in 1000 gets dropped');
4259

    
4260
		$section->addInput(new Form_Input(
4261
			'qlimit',
4262
			'Queue size (slots)',
4263
			'number',
4264
			$this->GetQlimit()
4265
		))->setHelp('In most cases, the field should be left empty. All packets in this pipe are placed into a fixed-size queue first, ' .
4266
					'then they are delayed by value specified in the Delay field, and then they are delivered to their destination.');
4267

    
4268
		$section->addInput(new Form_Input(
4269
			'buckets',
4270
			'Bucket size (slots)',
4271
			'number',
4272
			$this->GetBuckets()
4273
		))->setHelp('In most cases, this field should be left empty. It increases the hash size set');
4274

    
4275
		$section->addInput(new Form_Input(
4276
			'pipe',
4277
			null,
4278
			'hidden',
4279
			$this->GetPipe()
4280
		));
4281

    
4282
		$sform->add($section);
4283

    
4284
		return($sform);
4285
	}
4286

    
4287
	function update_dn_data(&$data) {
4288
		$this->ReadConfig($data);
4289
	}
4290

    
4291
	function wconfig() {
4292
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
4293
		if (!is_array($cflink)) {
4294
			$cflink = array();
4295
		}
4296
		$cflink['name'] = $this->GetQname();
4297
		$cflink['number'] = $this->GetNumber();
4298
		$cflink['qlimit'] = $this->GetQlimit();
4299
		$cflink['description'] = $this->GetDescription();
4300
		$cflink['weight'] = $this->GetWeight();
4301
		$cflink['enabled'] = $this->GetEnabled();
4302
		$cflink['buckets'] = $this->GetBuckets();
4303
		$mask = $this->GetMask();
4304
		$cflink['mask'] = $mask['type'];
4305
		$cflink['maskbits'] = $mask['bits'];
4306
		$cflink['maskbitsv6'] = $mask['bitsv6'];
4307
	}
4308
}
4309

    
4310
function get_dummynet_name_list() {
4311

    
4312
	$dn_name_list =& get_unique_dnqueue_list();
4313
	$dn_name = array();
4314
	if (is_array($dn_name_list)) {
4315
		foreach ($dn_name_list as $key => $value) {
4316
			$dn_name[] = $key;
4317
		}
4318
	}
4319

    
4320
	return $dn_name;
4321

    
4322
}
4323

    
4324
function get_altq_name_list() {
4325
	$altq_name_list =& get_unique_queue_list();
4326
	$altq_name = array();
4327
	if (is_array($altq_name_list)) {
4328
		foreach ($altq_name_list as $key => $aqobj) {
4329
			$altq_name[] = $key;
4330
		}
4331
	}
4332

    
4333
	return $altq_name;
4334
}
4335

    
4336
/*
4337
 * XXX: TODO Make a class shaper to hide all these functions
4338
 * from the global namespace.
4339
 */
4340

    
4341
/*
4342
 * This is a layer violation but for now there is no way
4343
 * I can find to properly do this with PHP.
4344
 */
4345
function altq_get_default_queue($interface) {
4346
	global $altq_list_queues;
4347

    
4348
	$altq_tmp = $altq_list_queues[$interface];
4349
	if ($altq_tmp) {
4350
		return $altq_tmp->GetDefaultQueuePresent();
4351
	} else {
4352
		return false;
4353
	}
4354
}
4355

    
4356
function altq_check_default_queues() {
4357
	global $altq_list_queues;
4358

    
4359
	$count = 0;
4360
	if (is_array($altq_list_queues)) {
4361
		foreach ($altq_list_queues as $altq) {
4362
			if ($altq->GetDefaultQueuePresent()) {
4363
				$count++;
4364
			}
4365
		}
4366
	}
4367
	else {
4368
		$count++;
4369
	}
4370

    
4371
	return 0;
4372
}
4373

    
4374
function &get_unique_queue_list() {
4375
	global $altq_list_queues;
4376

    
4377
	$qlist = array();
4378
	if (is_array($altq_list_queues)) {
4379
		foreach ($altq_list_queues as $altq) {
4380
			if ($altq->GetEnabled() == "") {
4381
				continue;
4382
			}
4383
			$tmplist =& $altq->get_queue_list();
4384
			foreach ($tmplist as $qname => $link) {
4385
				if ($link->GetEnabled() <> "") {
4386
					$qlist[$qname] = $link;
4387
				}
4388
			}
4389
		}
4390
	}
4391
	return $qlist;
4392
}
4393

    
4394
function &get_unique_dnqueue_list() {
4395
	global $dummynet_pipe_list;
4396

    
4397
	$qlist = array();
4398
	if (is_array($dummynet_pipe_list)) {
4399
		foreach ($dummynet_pipe_list as $dn) {
4400
			if ($dn->GetEnabled() == "") {
4401
				continue;
4402
			}
4403
			$tmplist =& $dn->get_queue_list();
4404
			foreach ($tmplist as $qname => $link) {
4405
				$qlist[$qname] = $link;
4406
			}
4407
		}
4408
	}
4409
	return $qlist;
4410
}
4411

    
4412
function ref_on_altq_queue_list($parent, $qname) {
4413
	if (isset($GLOBALS['queue_list'][$qname])) {
4414
		$GLOBALS['queue_list'][$qname]++;
4415
	} else {
4416
		$GLOBALS['queue_list'][$qname] = 1;
4417
	}
4418

    
4419
	unref_on_altq_queue_list($parent);
4420
}
4421

    
4422
function unref_on_altq_queue_list($qname) {
4423
	$GLOBALS['queue_list'][$qname]--;
4424
	if ($GLOBALS['queue_list'][$qname] <= 1) {
4425
		unset($GLOBALS['queue_list'][$qname]);
4426
	}
4427
}
4428

    
4429
function read_altq_config() {
4430
	global $altq_list_queues, $config;
4431
	$path = array();
4432

    
4433
	if (!is_array($config['shaper'])) {
4434
		$config['shaper'] = array();
4435
	}
4436
	if (!is_array($config['shaper']['queue'])) {
4437
		$config['shaper']['queue'] = array();
4438
	}
4439
	$a_int = &$config['shaper']['queue'];
4440

    
4441
	$altq_list_queues = array();
4442

    
4443
	if (!is_array($config['shaper']['queue'])) {
4444
		return;
4445
	}
4446

    
4447
	foreach ($a_int as $key => $conf) {
4448
		$int = $conf['interface'];
4449
		$root =& new altq_root_queue();
4450
		$root->SetInterface($int);
4451
		$altq_list_queues[$root->GetInterface()] = &$root;
4452
		$root->ReadConfig($conf);
4453
		array_push($path, $key);
4454
		$root->SetLink($path);
4455
		if (is_array($conf['queue'])) {
4456
			foreach ($conf['queue'] as $key1 => $q) {
4457
				array_push($path, $key1);
4458
				/*
4459
				 * XXX: we completely ignore errors here but anyway we must have
4460
				 *	checked them before so no harm should be come from this.
4461
				 */
4462
				$root->add_queue($root->GetInterface(), $q, $path, $input_errors);
4463
				array_pop($path);
4464
			}
4465
		}
4466
		array_pop($path);
4467
	}
4468
}
4469

    
4470
function read_dummynet_config() {
4471
	global $dummynet_pipe_list, $config;
4472
	$path = array();
4473

    
4474
	if (!is_array($config['dnshaper'])) {
4475
		$config['dnshaper'] = array();
4476
	}
4477
	if (!is_array($config['dnshaper']['queue'])) {
4478
		$config['dnshaper']['queue'] = array();
4479
	}
4480
	$a_int = &$config['dnshaper']['queue'];
4481

    
4482
	$dummynet_pipe_list = array();
4483

    
4484
	if (!is_array($config['dnshaper']['queue']) ||
4485
	    !count($config['dnshaper']['queue'])) {
4486
		return;
4487
	}
4488

    
4489
	foreach ($a_int as $key => $conf) {
4490
		if (empty($conf['name'])) {
4491
			continue; /* XXX: grrrrrr at php */
4492
		}
4493
		$root =& new dnpipe_class();
4494
		$root->ReadConfig($conf);
4495
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4496
		array_push($path, $key);
4497
		$root->SetLink($path);
4498
		if (is_array($conf['queue'])) {
4499
			foreach ($conf['queue'] as $key1 => $q) {
4500
				array_push($path, $key1);
4501
				/*
4502
				 * XXX: we completely ignore errors here but anyway we must have
4503
				 *	checked them before so no harm should be come from this.
4504
				 */
4505
				$root->add_queue($root->GetQname(), $q, $path, $input_errors);
4506
				array_pop($path);
4507
			}
4508
		}
4509
		array_pop($path);
4510
	}
4511
}
4512

    
4513
function get_interface_list_to_show() {
4514
	global $altq_list_queues, $config;
4515
	global $shaperIFlist;
4516

    
4517
	$tree = "";
4518
	foreach ($shaperIFlist as $shif => $shDescr) {
4519
		if ($altq_list_queues[$shif]) {
4520
			continue;
4521
		} else {
4522
			if (!is_altq_capable(get_real_interface($shif))) {
4523
				continue;
4524
			}
4525
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4526
		}
4527
	}
4528

    
4529
	return $tree;
4530
}
4531

    
4532
function filter_generate_altq_queues() {
4533
	global $altq_list_queues;
4534

    
4535
	read_altq_config();
4536

    
4537
	$altq_rules = "";
4538
	foreach ($altq_list_queues as $altq) {
4539
		$altq_rules .= $altq->build_rules();
4540
	}
4541

    
4542
	return $altq_rules;
4543
}
4544

    
4545
function dnqueue_find_nextnumber() {
4546
	global $dummynet_pipe_list;
4547

    
4548
	$dnused = array();
4549
	if (is_array($dummynet_pipe_list)) {
4550
		foreach ($dummynet_pipe_list as $dn) {
4551
			$tmplist =& $dn->get_queue_list();
4552
			foreach ($tmplist as $qname => $link) {
4553
				if ($link[0] == "?") {
4554
					$dnused[$qname] = substr($link, 1);
4555
				}
4556
			}
4557
		}
4558
	}
4559

    
4560
	sort($dnused, SORT_NUMERIC);
4561
	$dnnumber = 0;
4562
	$found = false;
4563
	foreach ($dnused as $dnnum) {
4564
		if (($dnnum - $dnnumber) > 1) {
4565
			$dnnumber = $dnnum - 1;
4566
			$found = true;
4567
			break;
4568
		} else {
4569
			$dnnumber = $dnnum;
4570
		}
4571
	}
4572

    
4573
	if ($found == false) {
4574
		$dnnumber++;
4575
	}
4576

    
4577
	unset($dnused, $dnnum, $found);
4578
	return $dnnumber;
4579
}
4580

    
4581
function dnpipe_find_nextnumber() {
4582
	global $dummynet_pipe_list;
4583

    
4584
	$dnused = array();
4585
	foreach ($dummynet_pipe_list as $dn) {
4586
		$dnused[] = $dn->GetNumber();
4587
	}
4588

    
4589
	sort($dnused, SORT_NUMERIC);
4590
	$dnnumber = 0;
4591
	$found = false;
4592
	foreach ($dnused as $dnnum) {
4593
		if (($dnnum - $dnnumber) > 1) {
4594
			$dnnumber = $dnnum - 1;
4595
			$found = true;
4596
			break;
4597
		} else {
4598
			$dnnumber = $dnnum;
4599
		}
4600
	}
4601

    
4602
	if ($found == false) {
4603
		$dnnumber++;
4604
	}
4605

    
4606
	unset($dnused, $dnnum, $found);
4607
	return $dnnumber;
4608
}
4609

    
4610
function filter_generate_dummynet_rules() {
4611
	global $g, $dummynet_pipe_list;
4612

    
4613
	read_dummynet_config();
4614

    
4615
	$dn_rules = "";
4616
	foreach ($dummynet_pipe_list as $dn) {
4617
		$dn_rules .= $dn->build_rules();
4618
	}
4619

    
4620
	if (!empty($dn_rules)) {
4621
		if (!is_module_loaded("dummynet.ko")) {
4622
			mwexec("/sbin/kldload dummynet");
4623
			set_sysctl(array(
4624
				"net.inet.ip.dummynet.io_fast" => "1",
4625
				"net.inet.ip.dummynet.hash_size" => "256"
4626
			));
4627
		}
4628
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4629
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4630
	}
4631
}
4632

    
4633
function build_iface_without_this_queue($iface, $qname) {
4634
	global $g, $altq_list_queues;
4635
	global $shaperIFlist;
4636

    
4637
	$altq =& $altq_list_queues[$iface];
4638

    
4639
	if ($altq) {
4640
		$scheduler = $altq->GetScheduler();
4641
	}
4642

    
4643
	$form = '<dl class="dl-horizontal">';
4644

    
4645
	$form .= '	<dt>';
4646
	$form .= '		<a href="firewall_shaper.php?interface=' . $iface . '&amp;queue=' . $iface . '&amp;action=show">' . $shaperIFlist[$iface] . '</a>';
4647
	$form .= '	</dt>';
4648
	$form .= '	<dd>';
4649
	$form .=		$scheduler;
4650
	$form .= '	</dd>';
4651

    
4652
	$form .= '	<dt>';
4653
	$form .= 'Clone';
4654
	$form .= '	</dt>';
4655
	$form .= '	<dd>';
4656
	$form .= '<a class="btn btn-info btn-xs" href="firewall_shaper_queues.php?interface=';
4657
	$form .= $iface . '&amp;queue=';
4658
	$form .= $qname . '&amp;action=add">';
4659
	$form .= '<i class="fa fa-clone icon-embed-btn"></i>';
4660
	$form .= gettext("Clone Shaper to this Interface") . '</a>';
4661
	$form .= '	</dd>';
4662

    
4663
	$form .= '</dl>';
4664

    
4665
	return $form;
4666

    
4667
}
4668

    
4669
$default_shaper_msg = sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "<br />";
4670
$dn_default_shaper_msg = $default_shaper_msg;
4671

    
4672
$shaper_msg = gettext("The tree on the left navigates through the %s.");
4673
$default_shaper_msg .= sprintf($shaper_msg, gettext("queues")) . "<br />";
4674
$dn_default_shaper_msg .= sprintf($shaper_msg, gettext("limiters")) . "<br />";
4675

    
4676
$shaper_msg = gettext("Buttons at the bottom represent %s actions and are activated accordingly.");
4677
$default_shaper_msg .= sprintf($shaper_msg, gettext("queue"));
4678
$dn_default_shaper_msg .= sprintf($shaper_msg, gettext("limiter"));
4679

    
4680
?>
(50-50/65)