Project

General

Profile

Download (118 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_hfsc_bandwidth($object, $bw) {
209
	$pattern= "/[0-9]+/";
210
	if (preg_match($pattern, $bw, $match)) {
211
		$bw_1 = $match[1];
212
	} else {
213
		return 0;
214
	}
215
	$pattern= "/(b|Kb|Mb|Gb|%)/";
216
	if (preg_match($pattern, $bw, $match)) {
217
		switch ($match[1]) {
218
			case '%':
219
				$bw_1 = $bw_1 / 100 * get_interface_bandwidth($object);
220
				break;
221
			default:
222
				$bw_1 = $bw_1 * get_bandwidthtype_scale($match[0]);
223
				break;
224
		}
225
		return floatval($bw_1);
226
	} else {
227
		return 0;
228
	}
229
}
230

    
231
function get_interface_bandwidth($object) {
232
	global $altq_list_queues;
233

    
234
	$int = $object->GetInterface();
235
	$altq =& $altq_list_queues[$int];
236
	if ($altq) {
237
		$bw_3 = $altq->GetBandwidth();
238
		$bw_3 = $bw_3 * get_bandwidthtype_scale($altq->GetBwscale());
239
		return floatval($bw_3);
240
	} else {
241
		return 0;
242
	}
243
}
244

    
245
/*
246
 * This is duplicated here since we cannot include guiconfig.inc.
247
 * Including it makes all stuff break.
248
 */
249
function shaper_do_input_validation($postdata, $reqdfields, $reqdfieldsn, $input_errors) {
250

    
251
	/* check for bad control characters */
252
	foreach ($postdata as $pn => $pd) {
253
		if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
254
			$input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $pn);
255
		}
256
	}
257

    
258
	for ($i = 0; $i < count($reqdfields); $i++) {
259
		if ($postdata[$reqdfields[$i]] == "") {
260
			$input_errors[] = sprintf(gettext("The field '%s' is required."), $reqdfieldsn[$i]);
261
		}
262
	}
263
}
264

    
265
function cleanup_queue_from_rules($queue) {
266
	global $config;
267

    
268
	foreach ($config['filter']['rule'] as $rule) {
269
		if ($rule['defaultqueue'] == $queue) {
270
			unset($rule['defaultqueue']);
271
		}
272
		if ($rule['ackqueue'] == $queue) {
273
			unset($rule['ackqueue']);
274
		}
275
	}
276
}
277

    
278
function cleanup_dnqueue_from_rules($queue) {
279
	global $config;
280

    
281
	foreach ($config['filter']['rule'] as $rule) {
282
		if ($rule['dnpipe'] == $queue) {
283
			unset($rule['dnpipe']);
284
		}
285
		if ($rule['pdnpipe'] == $queue) {
286
			unset($rule['pdnpipe']);
287
		}
288
	}
289
}
290

    
291
class altq_root_queue {
292
	var $interface;
293
	var $tbrconfig ;
294
	var $bandwidth;
295
	var $bandwidthtype; /* b, Kb, Mb */
296
	var $scheduler;
297
	var $qlimit;
298
	var $queues = array();
299
	var $qenabled = false;
300
	var $link;
301
	var $available_bw; /* in b/s */
302

    
303
	/* Accessor functions */
304
	function GetAvailableBandwidth() {
305
		return $this->available_bw;
306
	}
307
	function SetAvailableBandwidth($bw) {
308
		$this->available_bw = $bw;
309
	}
310
	function GetDefaultQueuePresent() {
311
		if (!empty($this->queues)) {
312
			foreach ($this->queues as $q) {
313
				if ($q->GetDefault()) {
314
					return true;
315
				}
316
			}
317
		}
318

    
319
		return false;
320
	}
321
	function SetLink($link) {
322
		$this->link = $link;
323
	}
324
	function GetLink() {
325
		return $this->link;
326
	}
327
	function GetEnabled() {
328
		return $this->qenabled;
329
	}
330
	function SetEnabled($value) {
331
		$this->qenabled = $value;
332
	}
333
	function CanHaveChildren() {
334
		if ($this->GetScheduler() == "CODELQ") {
335
			return false;
336
		} else {
337
			return true;
338
		}
339
	}
340
	function CanBeDeleted() {
341
		return false;
342
	}
343
	function GetQname() {
344
		return $this->interface;
345
	}
346
	function SetQname($name) {
347
		$this->interface = trim($name);
348
	}
349
	function GetInterface() {
350
		return $this->interface;
351
	}
352
	function SetInterface($name) {
353
		$this->interface = trim($name);
354
	}
355
	function GetTbrConfig() {
356
		return $this->tbrconfig;
357
	}
358
	function SetTbrConfig($tbrconfig) {
359
		$this->tbrconfig = $tbrconfig;
360
	}
361
	function GetBandwidth() {
362
		return $this->bandwidth;
363
	}
364
	function SetBandwidth($bw) {
365
		$this->bandwidth = $bw;
366
	}
367
	function GetBwscale() {
368
		return $this->bandwidthtype;
369
	}
370
	function SetBwscale($bwscale) {
371
		$this->bandwidthtype = $bwscale;
372
	}
373
	function GetScheduler() {
374
		return $this->scheduler;
375
	}
376
	function SetScheduler($scheduler) {
377
		$this->scheduler = trim($scheduler);
378
	}
379
	function GetQlimit() {
380
		return $this->qlimit;
381
	}
382
	function SetQlimit($limit) {
383
		$this->qlimit = $limit;
384
	}
385

    
386
	function validate_input($data, &$input_errors) {
387

    
388
		$reqdfields[] = "bandwidth";
389
		$reqdfieldsn[] = gettext("Bandwidth");
390
		$reqdfields[] = "bandwidthtype";
391
		$reqdfieldsn[] = gettext("Bandwidthtype");
392

    
393
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
394

    
395
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
396
			$input_errors[] = gettext("Bandwidth must be an integer.");
397
		}
398
		if ($data['bandwidth'] < 0) {
399
			$input_errors[] = gettext("Bandwidth cannot be negative.");
400
		}
401
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
402
			$input_errors[] = gettext("Qlimit must be an integer.");
403
		}
404
		if ($data['qlimit'] < 0) {
405
			$input_errors[] = gettext("Qlimit must be positive.");
406
		}
407
		if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig']))) {
408
			$input_errors[] = gettext("Tbrsize must be an integer.");
409
		}
410
		if ($data['tbrconfig'] < 0) {
411
			$input_errors[] = gettext("Tbrsize must be positive.");
412
		}
413
	}
414

    
415
	/* Implement this to shorten some code on the frontend page */
416
	function ReadConfig(&$conf) {
417
		if (isset($conf['tbrconfig'])) {
418
			$this->SetTbrConfig($conf['tbrconfig']);
419
		} else {
420
			$this->SetTbrConfig($conf['tbrconfig']);
421
		}
422
		$this->SetBandwidth($conf['bandwidth']);
423
		if ($conf['bandwidthtype'] <> "") {
424
			$this->SetBwscale($conf['bandwidthtype']);
425
		}
426
		if (isset($conf['scheduler'])) {
427
			if ($this->GetScheduler() != $conf['scheduler']) {
428
				foreach ($this->queues as $q) {
429
					clean_child_queues($conf['scheduler'], $this->GetLink());
430
					$q->clean_queue($conf['scheduler']);
431
				}
432
			}
433
			$this->SetScheduler($conf['scheduler']);
434
		}
435
		if (isset($conf['qlimit']) && $conf['qlimit'] <> "") {
436
			$this->SetQlimit($conf['qlimit']);
437
		} else {
438
			$this->SetQlimit("");
439
		}
440
		if (isset($conf['name'])) {
441
			$this->SetQname($conf['name']);
442
		}
443
		if (!empty($conf['enabled'])) {
444
			$this->SetEnabled($conf['enabled']);
445
		} else {
446
			$this->SetEnabled("");
447
		}
448
	}
449

    
450
	function copy_queue($interface, &$cflink) {
451
		$cflink['interface'] = $interface;
452
		$cflink['name'] = $interface;
453
		$cflink['scheduler'] = $this->GetScheduler();
454
		$cflink['bandwidth'] = $this->GetBandwidth();
455
		$cflink['bandwidthtype'] = $this->GetBwscale();
456
		$cflink['qlimit'] = $this->GetQlimit();
457
		$cflink['tbrconfig'] = $this->GetTbrConfig();
458
		$cflink['enabled'] = $this->GetEnabled();
459
		if (is_array($this->queues)) {
460
			$cflink['queue'] = array();
461
			foreach ($this->queues as $q) {
462
				$cflink['queue'][$q->GetQname()] = array();
463
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
464
			}
465
		}
466
	}
467

    
468
	function &get_queue_list(&$q = null) {
469
		$qlist = array();
470

    
471
		//$qlist[$this->GetQname()] = & $this;
472
		if (is_array($this->queues)) {
473
			foreach ($this->queues as $queue) {
474
				$queue->get_queue_list($qlist);
475
			}
476
		}
477
		return $qlist;
478
	}
479

    
480
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
481

    
482
		if (!is_array($this->queues)) {
483
			$this->queues = array();
484
		}
485

    
486
		switch ($this->GetScheduler()) {
487
			case "PRIQ":
488
				$q =& new priq_queue();
489
				break;
490
			case "HFSC":
491
				$q =& new hfsc_queue();
492
				break;
493
			case "CBQ":
494
				$q =& new cbq_queue();
495
				break;
496
			case "FAIRQ":
497
				$q =& new fairq_queue();
498
				break;
499
			default:
500
				/* XXX: but should not happen anyway */
501
				return;
502
				break;
503
		}
504
		$q->SetLink($path);
505
		$q->SetInterface($this->GetInterface());
506
		$q->SetEnabled("on");
507
		$q->SetParent($this);
508
		$q->ReadConfig($queue);
509
		$q->validate_input($queue, $input_errors);
510
		if (count($input_errors)) {
511
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
512
			return $q;
513
		}
514

    
515
		if (isset($queue['bandwidth'])) {
516
			switch ($queue['bandwidthtype']) {
517
				case "%":
518
					$myBw = $this->GetAvailableBandwidth() * $queue['bandwidth'] / 100;
519
					break;
520
				default:
521
					$myBw = $queue['bandwidth'] * get_bandwidthtype_scale($queue['bandwidthtype']);
522
					break;
523
			}
524
		}
525
		$q->SetAvailableBandwidth($myBw);
526
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
527
		$this->queues[$q->GetQname()] = &$q;
528
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
529
		if (is_array($queue['queue'])) {
530
			foreach ($queue['queue'] as $key1 => $que) {
531
				array_push($path, $key1);
532
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
533
				array_pop($path);
534
			}
535
		}
536

    
537
		return $q;
538
	}
539

    
540
	/* interface here might be optional */
541
	function &find_queue($interface, $qname) {
542
		if ($qname == $this->GetQname()) {
543
			return $this;
544
		}
545
		foreach ($this->queues as $q) {
546
			$result =& $q->find_queue("", $qname);
547
			if ($result) {
548
				return $result;
549
			}
550
		}
551
	}
552

    
553
	function &find_parentqueue($interface, $qname) {
554
		if ($qname == $interface) {
555
			$result = NULL;
556
		} else if ($this->queues[$qname]) {
557
			$result = $this;
558
		} else if ($this->GetScheduler() <> "PRIQ") {
559
			foreach ($this->queues as $q) {
560
				$result = $q->find_parentqueue("", $qname);
561
				if ($result) {
562
					return $result;
563
				}
564
			}
565
		}
566
	}
567

    
568
	function build_tree() {
569
		global $shaperIFlist;
570

    
571
		$tree = " <li><a href=\"firewall_shaper.php?interface=".$this->GetInterface()."&amp;queue=". $this->GetInterface()."&amp;action=show";
572
		$tree .= "\">" . $shaperIFlist[$this->GetInterface()] . "</a>";
573
		if (is_array($this->queues)) {
574
			$tree .= "<ul>";
575
			foreach ($this->queues as $q) {
576
				$tree .= $q->build_tree();
577
			}
578
			$tree .= "</ul>";
579
		}
580
		$tree .= "</li>";
581
		return $tree;
582
	}
583

    
584
	function delete_queue() {
585
		foreach ($this->queues as $q) {
586
			$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
587
			$q->delete_queue();
588
		}
589
		unset_object_by_reference($this->GetLink());
590
	}
591

    
592
	function delete_all() {
593
		if (count($this->queues)) {
594
			foreach ($this->queues as $q) {
595
				$q->delete_all();
596
				unset_object_by_reference($q->GetLink());
597
				unset($q);
598
			}
599
			unset($this->queues);
600
		}
601
	}
602

    
603
	/*
604
	 * First it spits:
605
	 * altq on $interface ..............
606
	 *	then it goes like
607
	 *	foreach ($queues as $qkey => $queue) {
608
	 *		this->queues[$qkey]->build_rule();
609
	 *	}
610
	 */
611
	function build_rules(&$default = false) {
612
		if (count($this->queues) > 0 && $this->GetEnabled() == "on") {
613
			$default = false;
614
			$rules = " altq on " . get_real_interface($this->GetInterface());
615
			if ($this->GetScheduler()) {
616
				$rules .= " ".strtolower($this->GetScheduler());
617
			}
618
			if ($this->GetQlimit() > 0) {
619
				$rules .= " qlimit " . $this->GetQlimit() . " ";
620
			}
621
			if ($this->GetBandwidth()) {
622
				$rules .= " bandwidth ".trim($this->GetBandwidth());
623
				if ($this->GetBwscale()) {
624
					$rules .= $this->GetBwscale();
625
				}
626
			}
627
			if ($this->GetTbrConfig()) {
628
				$rules .= " tbrsize ".$this->GetTbrConfig();
629
			}
630
			if (count($this->queues)) {
631
				$i = count($this->queues);
632
				$rules .= " queue { ";
633
				foreach ($this->queues as $qkey => $qnone) {
634
					if ($i > 1) {
635
						$i--;
636
						$rules .= " {$qkey}, ";
637
					} else {
638
						$rules .= " {$qkey} ";
639
					}
640
				}
641
				$rules .= " } \n";
642
				foreach ($this->queues as $q) {
643
					$rules .= $q->build_rules($default);
644
				}
645
			}
646

    
647
			if ($default == false) {
648
				$error = "SHAPER: no default queue specified for interface ". $this->GetInterface() . ". The interface queue will be enforced as default.";
649
				file_notice("Shaper", $error, "Error occurred", "");
650
				unset($error);
651
				return "\n";
652
			}
653
			$frule .= $rules;
654
		} else if ($this->GetEnabled() == "on" && $this->GetScheduler() == "CODELQ") {
655
			$rules = " altq on " . get_real_interface($this->GetInterface());
656
			if ($this->GetScheduler()) {
657
				$rules .= " ".strtolower($this->GetScheduler());
658
			}
659
			if ($this->GetQlimit() > 0) {
660
				$rules .= " ( qlimit " . $this->GetQlimit() . " ) ";
661
			}
662
			if ($this->GetBandwidth()) {
663
				$rules .= " bandwidth ".trim($this->GetBandwidth());
664
				if ($this->GetBwscale()) {
665
					$rules .= $this->GetBwscale();
666
				}
667
			}
668
			if ($this->GetTbrConfig()) {
669
				$rules .= " tbrsize ".$this->GetTbrConfig();
670
			}
671

    
672
			$rules .= " queue";
673
		}
674

    
675
		$rules .= " \n";
676
		return $rules;
677
	}
678

    
679
	function build_javascript() {
680
		$javascript = "<script type=\"text/javascript\">";
681
		$javascript .= "//<![CDATA[\n";
682
		$javascript .= "function mySuspend() {";
683
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
684
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden'; ";
685
		$javascript .= "else if (document.all)";
686
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
687
		$javascript .= "}";
688

    
689
		$javascript .= "function myResume() {";
690
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
691
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';";
692
		$javascript .= "else if (document.all) ";
693
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';";
694
		$javascript .= "}";
695
		$javascript .= "//]]>";
696
		$javascript .= "</script>";
697

    
698
		return $javascript;
699
	}
700

    
701
	function build_shortform() {
702
		global $g;
703

    
704
		$altq =& $this;
705

    
706
		if ($altq) {
707
			$scheduler = ": " . $altq->GetScheduler();
708
		}
709

    
710
		$form = '<dl class="dl-horizontal">';
711
		$form .= '	<dt>';
712
		$form .= '		<a href="firewall_shaper.php?interface=' . $this->GetInterface() . '&amp;queue=' . $this->GetQname() . '&amp;action=show">' . $shaperIFlist[$this->GetInterface()] . '</a>';
713
		$form .= '	</dt>';
714
		$form .= '	<dd>';
715
		$form .=		$scheduler;
716
		$form .= '	</dd>';
717

    
718
		$form .= '	<dt>';
719
		$form .=		'Bandwidth';
720
		$form .= '	</dt>';
721
		$form .= '	<dd>';
722
		$form .=		$this->GetBandwidth() . '&nbsp;' . $this->GetBwscale();
723
		$form .= '	</dd>';
724

    
725
		$form .= '	<dt>';
726
		$form .= 'Disable';
727
		$form .= '	<dt>';
728
		$form .= '	<dd>';
729

    
730
		$form .= '<a class="btn btn-default btn-xs" href="firewall_shaper_queues.php?interface=';
731
		$form .= $this->GetInterface() . '&amp;queue=';
732
		$form .= $this->GetQname() . '&amp;action=delete">';
733
		$form .= gettext("Disable shaper on interface") . '</a>';
734

    
735
		$form .= '	</dd>';
736

    
737
		$form .= '</dl>';
738

    
739
		return $form;
740

    
741
	}
742

    
743
	/*
744
	 * For requesting the parameters of the root queues
745
	 * to the user like the traffic wizard does.
746
	 */
747
	function build_form() {
748

    
749
		$sform = new Form(new Form_Button(
750
			'Submit',
751
			'Save'
752
		));
753

    
754
		$sform->setAction("firewall_shaper.php");
755

    
756
		$section = new Form_Section(null);
757

    
758
		$section->addInput(new Form_Checkbox(
759
			'enabled',
760
			'Enable/Disable',
761
			'Enable/disable discipline and its children',
762
			($this->GetEnabled() == "on"),
763
			'on'
764
		));
765

    
766
		$section->addInput(new Form_StaticText(
767
			'Name',
768
			$this->GetQname()
769
		));
770

    
771
		$section->addInput(new Form_Select(
772
			'scheduler',
773
			'Scheduler Type',
774
			$this->GetScheduler(),
775
			array('HFSC' => 'HFSC',
776
				  'CBQ' => 'CBQ',
777
				  'FAIRQ' => 'FAIRQ',
778
				  'CODELQ' => 'CODELQ',
779
				  'PRIQ' => 'PRIQ')
780
		))->setHelp('Changing this changes all child queues! Beware you can lose information.');
781

    
782
		$group = new Form_group('Bandwidth');
783

    
784
		$group->add(new Form_Input(
785
			'bandwidth',
786
			null,
787
			'number',
788
			$this->GetBandwidth()
789
		));
790

    
791
		$group->add(new Form_Select(
792
			'bandwidthtype',
793
			null,
794
			$this->GetBwscale(),
795
			array('Kb' => 'Kb',
796
				  'Mb' => 'Mb',
797
				  'Gb' => 'Gb',
798
				  'b' => 'b',
799
				  '%' => '%')
800
		));
801

    
802
		$section->add($group);
803

    
804
		$section->addInput(new Form_Input(
805
			'qlimit',
806
			'Queue Limit',
807
			'number',
808
			$this->GetQlimit()
809
		));
810

    
811
		$section->addInput(new Form_Input(
812
			'tbrconfig',
813
			'TRB Size',
814
			'number',
815
			$this->GetTbrConfig()
816
		))->setHelp('Adjusts the size, in bytes, of the token bucket regulator. If not specified, heuristics based on the interface ' .
817
					'bandwidth are used to determine the size.');
818

    
819
		$section->addInput(new Form_Input(
820
			'interface',
821
			null,
822
			'hidden',
823
			$this->GetInterface()
824
		));
825

    
826
		$section->addInput(new Form_Input(
827
			'name',
828
			null,
829
			'hidden',
830
			$this->GetQname()
831
		));
832

    
833
		$sform->add($section);
834

    
835
		return($sform);
836
	}
837

    
838
	function update_altq_queue_data(&$data) {
839
		$this->ReadConfig($data);
840
	}
841

    
842
	/*
843
	 * Should call on each of it queues and subqueues
844
	 * the same function much like build_rules();
845
	 */
846
	function wconfig() {
847
		$cflink = &get_reference_to_me_in_config($this->GetLink());
848
		if (!is_array($cflink)) {
849
			$cflink = array();
850
		}
851
		$cflink['interface'] = $this->GetInterface();
852
		$cflink['name'] = $this->GetQname();
853
		$cflink['scheduler'] = $this->GetScheduler();
854
		$cflink['bandwidth'] = $this->GetBandwidth();
855
		$cflink['bandwidthtype'] = $this->GetBwscale();
856
		$cflink['qlimit'] = trim($this->GetQlimit());
857
		if (empty($cflink['qlimit'])) {
858
			unset($cflink['qlimit']);
859
		}
860
		$cflink['tbrconfig'] = trim($this->GetTbrConfig());
861
		if (empty($cflink['tbrconfig'])) {
862
			unset($cflink['tbrconfig']);
863
		}
864
		$cflink['enabled'] = $this->GetEnabled();
865
		if (empty($cflink['enabled'])) {
866
			unset($cflink['enabled']);
867
		}
868
	}
869

    
870
}
871

    
872
class priq_queue {
873
	var $qname;
874
	var $qinterface;
875
	var $qlimit;
876
	var $qpriority;
877
	var $description;
878
	var $isparent;
879
	var $qbandwidth;
880
	var $qbandwidthtype;
881
	var $qdefault = "";
882
	var $qrio = "";
883
	var $qred = "";
884
	var $qcodel = "";
885
	var $qecn = "";
886
	var $qack;
887
	var $qenabled = "";
888
	var $qparent;
889
	var $link;
890
	var $available_bw; /* in b/s */
891

    
892
	/* This is here to help with form building and building rules/lists */
893
	var $subqueues = array();
894

    
895
	/* Accessor functions */
896
	function GetAvailableBandwidth() {
897
		return $this->available_bw;
898
	}
899
	function SetAvailableBandwidth($bw) {
900
		$this->available_bw = $bw;
901
	}
902
	function SetLink($link) {
903
		$this->link = $link;
904
	}
905
	function GetLink() {
906
		return $this->link;
907
	}
908
	function &GetParent() {
909
		return $this->qparent;
910
	}
911
	function SetParent(&$parent) {
912
		$this->qparent = &$parent;
913
	}
914
	function GetEnabled() {
915
		return $this->qenabled;
916
	}
917
	function SetEnabled($value) {
918
		$this->qenabled = $value;
919
	}
920
	function CanHaveChildren() {
921
		return false;
922
	}
923
	function CanBeDeleted() {
924
		return true;
925
	}
926
	function GetQname() {
927
		return $this->qname;
928
	}
929
	function SetQname($name) {
930
		$this->qname = trim($name);
931
	}
932
	function GetBandwidth() {
933
		return $this->qbandwidth;
934
	}
935
	function SetBandwidth($bandwidth) {
936
		$this->qbandwidth = $bandwidth;
937
	}
938
	function GetInterface() {
939
		return $this->qinterface;
940
	}
941
	function SetInterface($name) {
942
		$this->qinterface = trim($name);
943
	}
944
	function GetQlimit() {
945
		return $this->qlimit;
946
	}
947
	function SetQlimit($limit) {
948
		$this->qlimit = $limit;
949
	}
950
	function GetQpriority() {
951
		return $this->qpriority;
952
	}
953
	function SetQpriority($priority) {
954
		$this->qpriority = $priority;
955
	}
956
	function GetDescription() {
957
		return $this->description;
958
	}
959
	function SetDescription($str) {
960
		$this->description = trim($str);
961
	}
962
	function GetFirstime() {
963
		return $this->firsttime;
964
	}
965
	function SetFirsttime($number) {
966
		$this->firsttime = $number;
967
	}
968
	function GetBwscale() {
969
		return $this->qbandwidthtype;
970
	}
971
	function SetBwscale($scale) {
972
		$this->qbandwidthtype = $scale;
973
	}
974
	function GetDefaultQueuePresent() {
975
		if ($this->GetDefault()) {
976
			return true;
977
		}
978
		if (!empty($this->subqueues)) {
979
			foreach ($this->subqueues as $q) {
980
				if ($q->GetDefault()) {
981
					return true;
982
				}
983
			}
984
		}
985

    
986
		return false;
987
	}
988
	function GetDefault() {
989
		return $this->qdefault;
990
	}
991
	function SetDefault($value = false) {
992
		$this->qdefault = $value;
993
	}
994
	function GetCodel() {
995
		return $this->codel;
996
	}
997
	function SetCodel($codel = false) {
998
		$this->codel = $codel;
999
	}
1000
	function GetRed() {
1001
		return $this->qred;
1002
	}
1003
	function SetRed($red = false) {
1004
		$this->qred = $red;
1005
	}
1006
	function GetRio() {
1007
		return $this->qrio;
1008
	}
1009
	function SetRio($rio = false) {
1010
		$this->qrio = $rio;
1011
	}
1012
	function GetEcn() {
1013
		return $this->qecn;
1014
	}
1015
	function SetEcn($ecn = false) {
1016
		$this->qecn = $ecn;
1017
	}
1018
	function GetAck() {
1019
		return $this->qack;
1020
	}
1021
	function SetAck($ack = false) {
1022
		$this->qack = $ack;
1023
	}
1024

    
1025
	function build_javascript() {
1026
		$javascript = "<script type=\"text/javascript\">";
1027
		$javascript .= "//<![CDATA[\n";
1028
		$javascript .= "function mySuspend() { \n";
1029
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
1030
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
1031
		$javascript .= "else if (document.all)\n";
1032
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
1033
		$javascript .= "}\n";
1034

    
1035
		$javascript .= "function myResume() {\n";
1036
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
1037
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
1038
		$javascript .= "else if (document.all)\n";
1039
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
1040
		$javascript .= "}\n";
1041
		$javascript .= "//]]>";
1042
		$javascript .= "</script>";
1043

    
1044
		return $javascript;
1045
	}
1046

    
1047
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
1048

    
1049
	/*
1050
	 * Currently this will not be called unless we decide to clone a whole
1051
	 * queue tree on the 'By Queues' view or support drag&drop on the tree/list
1052
	 */
1053
	function copy_queue($interface, &$cflink) {
1054

    
1055
		$cflink['name'] = $this->GetQname();
1056
		$cflink['interface'] = $interface;
1057
		$cflink['qlimit'] = $this->GetQlimit();
1058
		$cflink['priority'] = $this->GetQpriority();
1059
		$cflink['description'] = $this->GetDescription();
1060
		$cflink['enabled'] = $this->GetEnabled();
1061
		$cflink['default'] = $this->GetDefault();
1062
		$cflink['red'] = $this->GetRed();
1063
		$cflink['codel'] = $this->GetCodel();
1064
		$cflink['rio'] = $this->GetRio();
1065
		$cflink['ecn'] = $this->GetEcn();
1066

    
1067
		if (is_array($this->subqueues)) {
1068
			$cflinkp['queue'] = array();
1069
			foreach ($this->subqueues as $q) {
1070
				$cflink['queue'][$q->GetQname()] = array();
1071
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1072
			}
1073
		}
1074
	}
1075

    
1076
	function clean_queue($sched) {
1077
		clean_child_queues($sched, $this->GetLink());
1078
		if (is_array($this->subqueues)) {
1079
			foreach ($this->subqueues as $q) {
1080
				$q->clean_queue($sched);
1081
			}
1082
		}
1083
	}
1084

    
1085
	function &get_queue_list(&$qlist) {
1086

    
1087
		$qlist[$this->GetQname()] = & $this;
1088
		if (is_array($this->subqueues)) {
1089
			foreach ($this->subqueues as $queue) {
1090
				$queue->get_queue_list($qlist);
1091
			}
1092
		}
1093
	}
1094

    
1095
	function delete_queue() {
1096
		unref_on_altq_queue_list($this->GetQname());
1097
		cleanup_queue_from_rules($this->GetQname());
1098
		unset_object_by_reference($this->GetLink());
1099
	}
1100

    
1101
	function delete_all() {
1102
		if (count($this->subqueues)) {
1103
			foreach ($this->subqueues as $q) {
1104
				$q->delete_all();
1105
				unset_object_by_reference($q->GetLink());
1106
				unset($q);
1107
			}
1108
			unset($this->subqueues);
1109
		}
1110
	}
1111

    
1112
	function &find_queue($interface, $qname) {
1113
		if ($qname == $this->GetQname()) {
1114
			return $this;
1115
		}
1116
	}
1117

    
1118
	function find_parentqueue($interface, $qname) { return; }
1119

    
1120
	function validate_input($data, &$input_errors) {
1121

    
1122
		$reqdfields[] = "name";
1123
		$reqdfieldsn[] = gettext("Name");
1124
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1125

    
1126
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
1127
			$input_errors[] = "Bandwidth must be an integer.";
1128
		}
1129
		if ($data['bandwidth'] < 0) {
1130
			$input_errors[] = "Bandwidth cannot be negative.";
1131
		}
1132
		if ($data['priority'] && (!is_numeric($data['priority']) ||
1133
		    ($data['priority'] < 1) || ($data['priority'] > 15))) {
1134
			$input_errors[] = gettext("The priority must be an integer between 1 and 15.");
1135
		}
1136
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
1137
				$input_errors[] = gettext("Queue limit must be an integer");
1138
		}
1139
		if ($data['qlimit'] < 0) {
1140
				$input_errors[] = gettext("Queue limit must be positive");
1141
		}
1142
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['newname'])) {
1143
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1144
		}
1145
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['name'])) {
1146
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1147
		}
1148
		$default = $this->GetDefault();
1149
		if (!empty($data['default']) && altq_get_default_queue($data['interface']) && empty($default)) {
1150
			$input_errors[] = gettext("Only one default queue per interface is allowed.");
1151
		}
1152
	}
1153

    
1154
	function ReadConfig(&$q) {
1155
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
1156
			$this->SetQname($q['newname']);
1157
		} else if (!empty($q['newname'])) {
1158
			$this->SetQname($q['newname']);
1159
		} else if (isset($q['name'])) {
1160
			$this->SetQname($q['name']);
1161
		}
1162
		if (isset($q['interface'])) {
1163
			$this->SetInterface($q['interface']);
1164
		}
1165
		$this->SetBandwidth($q['bandwidth']);
1166
		if ($q['bandwidthtype'] <> "") {
1167
			$this->SetBwscale($q['bandwidthtype']);
1168
		}
1169
		if (!empty($q['qlimit'])) {
1170
			$this->SetQlimit($q['qlimit']);
1171
		} else {
1172
			$this->SetQlimit(""); // Default
1173
		}
1174
		if (!empty($q['priority'])) {
1175
			$this->SetQPriority($q['priority']);
1176
		} else {
1177
			$this->SetQpriority("");
1178
		}
1179
		if (!empty($q['description'])) {
1180
			$this->SetDescription($q['description']);
1181
		} else {
1182
			$this->SetDescription("");
1183
		}
1184
		if (!empty($q['red'])) {
1185
			$this->SetRed($q['red']);
1186
		} else {
1187
			$this->SetRed();
1188
		}
1189
		if (!empty($q['codel'])) {
1190
			$this->SetCodel($q['codel']);
1191
		} else {
1192
			$this->SetCodel();
1193
		}
1194
		if (!empty($q['rio'])) {
1195
			$this->SetRio($q['rio']);
1196
		} else {
1197
			$this->SetRio();
1198
		}
1199
		if (!empty($q['ecn'])) {
1200
			$this->SetEcn($q['ecn']);
1201
		} else {
1202
			$this->SetEcn();
1203
		}
1204
		if (!empty($q['default'])) {
1205
			$this->SetDefault($q['default']);
1206
		} else {
1207
			$this->SetDefault();
1208
		}
1209
		if (!empty($q['enabled'])) {
1210
			$this->SetEnabled($q['enabled']);
1211
		} else {
1212
			$this->SetEnabled("");
1213
		}
1214
	}
1215

    
1216
	function build_tree() {
1217
		$tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&amp;queue=". $this->GetQname()."&amp;action=show";
1218
		$tree .= "\" ";
1219
		$tmpvalue = $this->GetDefault();
1220
		if (!empty($tmpvalue)) {
1221
			$tree .= " class=\"navlnk\"";
1222
		}
1223
		$tree .= " >" . $this->GetQname() . "</a>";
1224
		/*
1225
		 * Not needed here!
1226
		 * if (is_array($queues) {
1227
		 *	  $tree .= "<ul>";
1228
		 *	  foreach ($q as $queues)
1229
		 *		  $tree .= $queues['$q->GetName()']->build_tree();
1230
		 *	  endforeach
1231
		 *	  $tree .= "</ul>";
1232
		 * }
1233
		 */
1234

    
1235
		$tree .= "</li>";
1236

    
1237
		return $tree;
1238
	}
1239

    
1240
	/* Should return something like:
1241
	 * queue $qname on $qinterface bandwidth ....
1242
	 */
1243
	function build_rules(&$default = false) {
1244
		$pfq_rule = " queue ". $this->qname;
1245
		if ($this->GetInterface()) {
1246
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1247
		}
1248
		$tmpvalue = $this->GetQpriority();
1249
		if (!empty($tmpvalue)) {
1250
			$pfq_rule .= " priority ".$this->GetQpriority();
1251
		}
1252
		$tmpvalue = $this->GetQlimit();
1253
		if (!empty($tmpvalue)) {
1254
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1255
		}
1256
		if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault() || $this->GetCodel()) {
1257
			$pfq_rule .= " priq ( ";
1258
			$tmpvalue = $this->GetRed();
1259
			if (!empty($tmpvalue)) {
1260
				$comma = 1;
1261
				$pfq_rule .= " red ";
1262
			}
1263
			$tmpvalue = $this->GetRio();
1264
			if (!empty($tmpvalue)) {
1265
				if ($comma) {
1266
					$pfq_rule .= " ,";
1267
				}
1268
				$comma = 1;
1269
				$pfq_rule .= " rio ";
1270
			}
1271
			$tmpvalue = $this->GetEcn();
1272
			if (!empty($tmpvalue)) {
1273
				if ($comma) {
1274
					$pfq_rule .= " ,";
1275
				}
1276
				$comma = 1;
1277
				$pfq_rule .= " ecn ";
1278
			}
1279
			$tmpvalue = $this->GetCodel();
1280
			if (!empty($tmpvalue)) {
1281
				if ($comma) {
1282
					$pfq_rule .= " ,";
1283
				}
1284
				$comma = 1;
1285
				$pfq_rule .= " codel ";
1286
			}
1287
			$tmpvalue = $this->GetDefault();
1288
			if (!empty($tmpvalue)) {
1289
				if ($comma) {
1290
					$pfq_rule .= " ,";
1291
				}
1292
				$pfq_rule .= " default ";
1293
				$default = true;
1294
			}
1295
			$pfq_rule .= " ) ";
1296
		}
1297

    
1298
		$pfq_rule .= " \n";
1299

    
1300
		return $pfq_rule;
1301
	}
1302

    
1303
	/*
1304
	 * To return the html form to show to user
1305
	 * for getting the parameters.
1306
	 * Should do even for first time when the
1307
	 * object is created and later when we may
1308
	 * need to update it. (2)
1309
	 */
1310

    
1311
	function build_form() {
1312

    
1313
		$sform = new Form(new Form_Button(
1314
			'Submit',
1315
			'Save'
1316
		));
1317

    
1318
		$sform->setAction("firewall_shaper.php");
1319

    
1320
		$section = new Form_Section("");
1321

    
1322
		$section->addInput(new Form_Checkbox(
1323
			'enabled',
1324
			'Enable/Disable',
1325
			'Enable/disable discipline and its children',
1326
			($this->GetEnabled() == "on"),
1327
			'on'
1328
		));
1329

    
1330
		$section->addInput(new Form_Input(
1331
			'newname',
1332
			'Name',
1333
			'text',
1334
			$this->GetQname()
1335
		))->setHelp('Enter the name of the queue here. Do not use spaces and limit the size to 15 characters.');
1336

    
1337
		$section->addInput(new Form_Input(
1338
			'name',
1339
			null,
1340
			'hidden',
1341
			$this->GetQname()
1342
		));
1343

    
1344
		$section->addInput(new Form_Input(
1345
			'priority',
1346
			'Priority',
1347
			'number',
1348
			$this->GetQpriority(),
1349
			['min' => '0', 'max'=> '7']
1350
		))->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.');
1351

    
1352
		$section->addInput(new Form_Input(
1353
			'qlimit',
1354
			'Queue Limit',
1355
			'number',
1356
			$this->GetQlimit()
1357
		))->setHelp('Queue limit in packets.');
1358

    
1359
		$group = new Form_Group('Scheduler options');
1360

    
1361
		if (empty($this->subqueues)) {
1362
			$group->add(new Form_Checkbox(
1363
				'default',
1364
				null,
1365
				null,
1366
				$this->GetDefault(),
1367
				'default'
1368
			))->setHelp('Default Queue');
1369
		}
1370

    
1371
		$group->add(new Form_Checkbox(
1372
			'red',
1373
			null,
1374
			null,
1375
			!empty($this->GetRed())
1376
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#red">' . gettext('Random Early Detection') . '</a>');
1377

    
1378
		$group->add(new Form_Checkbox(
1379
			'rio',
1380
			null,
1381
			null,
1382
			!empty($this->GetRio())
1383
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#rio">' . gettext('Random Early Detection In and Out') . '</a>');
1384

    
1385
		$group->add(new Form_Checkbox(
1386
			'ecn',
1387
			null,
1388
			null,
1389
			!empty($this->GetEcn())
1390
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#ecn">' . gettext('Explicit Congestion Notification') . '</a>');
1391

    
1392
		$group->add(new Form_Checkbox(
1393
			'codel',
1394
			null,
1395
			null,
1396
			!empty($this->GetCodel())
1397
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#ecn">' . gettext('Codel Active Queue') . '</a>');
1398

    
1399
		$group->setHelp('Select options for this queue');
1400

    
1401
		$section->add($group);
1402

    
1403
		$section->addInput(new Form_Input(
1404
			'description',
1405
			'Description',
1406
			'text',
1407
			$this->GetDescription()
1408
		));
1409

    
1410
		$sform->add($section);
1411

    
1412
		$sform->addGlobal(new Form_Input(
1413
			'interface',
1414
			null,
1415
			'hidden',
1416
			$this->GetInterface()
1417
		));
1418

    
1419
		$sform->addGlobal(new Form_Input(
1420
			'name',
1421
			null,
1422
			'hidden',
1423
			$this->GetQname()
1424
		));
1425

    
1426
		return($sform);
1427
	}
1428

    
1429
	function build_shortform() {
1430
		/* XXX: Hacks in sight. Mostly layer violations!  */
1431
		global $g, $altq_list_queues;
1432
		global $shaperIFlist;
1433

    
1434
		$altq =& $altq_list_queues[$this->GetInterface()];
1435

    
1436
		if ($altq) {
1437
			$scheduler = $altq->GetScheduler();
1438
		}
1439

    
1440
		$form = '<dl class="dl-horizontal">';
1441
		$form .= '	<dt>';
1442
		$form .= '		<a href="firewall_shaper.php?interface=' . $this->GetInterface() . '&amp;queue=' . $this->GetQname() . '&amp;action=show">' . $shaperIFlist[$this->GetInterface()] . '</a>';
1443
		$form .= '	</dt>';
1444
		$form .= '	<dd>';
1445
		$form .=		$scheduler;
1446
		$form .= '	</dd>';
1447

    
1448
		$form .= '	<dt>';
1449
		$form .=		'Bandwidth';
1450
		$form .= '	</dt>';
1451
		$form .= '	<dd>';
1452
		$form .=		$this->GetBandwidth() . '&nbsp;' . $this->GetBwscale();
1453
		$form .= '	</dd>';
1454

    
1455
		$tmpvalue = $this->GetQpriority();
1456
		if (!empty($tmpvalue)) {
1457
			$form .= '	<dt>';
1458
			$form .=		'Priority';
1459
			$form .= '	<dt>';
1460
			$form .= '	<dd>';
1461
			$form .=		'On';
1462
			$form .= '	</dd>';
1463
		}
1464

    
1465
		$tmpvalue = $this->GetDefault();
1466
		if (!empty($tmpvalue)) {
1467
			$form .= '	<dt>';
1468
			$form .=		'Default';
1469
			$form .= '	<dt>';
1470
			$form .= '	<dd>';
1471
			$form .=		'On';
1472
			$form .= '	</dd>';
1473
		}
1474

    
1475
			$form .= '	<dt>';
1476
			$form .= 'Delete';
1477
			$form .= '	<dt>';
1478
			$form .= '	<dd>';
1479

    
1480
			$form .= '<a class="btn btn-danger btn-xs" href="firewall_shaper_queues.php?interface=';
1481
			$form .= $this->GetInterface() . '&amp;queue=';
1482
			$form .= $this->GetQname() . '&amp;action=delete">';
1483
			$form .= gettext("Delete queue from interface") . '</a>';
1484

    
1485
			$form .= '	</dd>';
1486

    
1487
			$form .= '</dl>';
1488

    
1489
		return $form;
1490

    
1491
	}
1492

    
1493
	function update_altq_queue_data(&$q) {
1494
		$this->ReadConfig($q);
1495
	}
1496

    
1497
	function wconfig() {
1498
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1499
		if (!is_array($cflink)) {
1500
			$cflink = array();
1501
		}
1502
		$cflink['name'] = $this->GetQname();
1503
		$cflink['interface'] = $this->GetInterface();
1504
		$cflink['qlimit'] = trim($this->GetQlimit());
1505
		if (empty($cflink['qlimit'])) {
1506
			unset($cflink['qlimit']);
1507
		}
1508
		$cflink['priority'] = trim($this->GetQpriority());
1509
		if (empty($cflink['priority'])) {
1510
			unset($cflink['priority']);
1511
		}
1512
		$cflink['description'] = trim($this->GetDescription());
1513
		if (empty($cflink['description'])) {
1514
			unset($cflink['description']);
1515
		}
1516
		$cflink['enabled'] = trim($this->GetEnabled());
1517
		if (empty($cflink['enabled'])) {
1518
			unset($cflink['enabled']);
1519
		}
1520
		$cflink['default'] = trim($this->GetDefault());
1521
		if (empty($cflink['default'])) {
1522
			unset($cflink['default']);
1523
		}
1524
		$cflink['red'] = trim($this->GetRed());
1525
		if (empty($cflink['red'])) {
1526
			unset($cflink['red']);
1527
		}
1528
		$cflink['codel'] = trim($this->GetCodel());
1529
		if (empty($cflink['codel'])) {
1530
			unset($cflink['codel']);
1531
		}
1532
		$cflink['rio'] = trim($this->GetRio());
1533
		if (empty($cflink['rio'])) {
1534
			unset($cflink['rio']);
1535
		}
1536
		$cflink['ecn'] = trim($this->GetEcn());
1537
		if (empty($cflink['ecn'])) {
1538
			unset($cflink['ecn']);
1539
		}
1540
	}
1541
}
1542

    
1543
class hfsc_queue extends priq_queue {
1544
	/* realtime */
1545
	var $realtime;
1546
	var $r_m1;
1547
	var $r_d;
1548
	var $r_m2;
1549
	/* linkshare */
1550
	var $linkshare;
1551
	var $l_m1;
1552
	var $l_d;
1553
	var $l_m2;
1554
	/* upperlimit */
1555
	var $upperlimit;
1556
	var $u_m1;
1557
	var $u_d;
1558
	var $u_m2;
1559

    
1560
	/*
1561
	 * HFSC can have nested queues.
1562
	 */
1563
	function CanHaveChildren() {
1564
		return true;
1565
	}
1566
	function GetRealtime() {
1567
		return $this->realtime;
1568
	}
1569
	function GetR_m1() {
1570
		return $this->r_m1;
1571
	}
1572
	function GetR_d() {
1573
		return $this->r_d;
1574
	}
1575
	function GetR_m2() {
1576
		return $this->r_m2;
1577
	}
1578
	function SetRealtime() {
1579
		$this->realtime = "on";
1580
	}
1581
	function DisableRealtime() {
1582
		$this->realtime = "";
1583
	}
1584
	function SetR_m1($value) {
1585
		$this->r_m1 = $value;
1586
	}
1587
	function SetR_d($value) {
1588
		$this->r_d = $value;
1589
	}
1590
	function SetR_m2($value) {
1591
		$this->r_m2 = $value;
1592
	}
1593
	function GetLinkshare() {
1594
		return $this->linkshare;
1595
	}
1596
	function DisableLinkshare() {
1597
		$this->linkshare = "";
1598
	}
1599
	function GetL_m1() {
1600
		return $this->l_m1;
1601
	}
1602
	function GetL_d() {
1603
		return $this->l_d;
1604
	}
1605
	function GetL_m2() {
1606
		return $this->l_m2;
1607
	}
1608
	function SetLinkshare() {
1609
		$this->linkshare = "on";
1610
	}
1611
	function SetL_m1($value) {
1612
		$this->l_m1 = $value;
1613
	}
1614
	function SetL_d($value) {
1615
		$this->l_d = $value;
1616
	}
1617
	function SetL_m2($value) {
1618
		$this->l_m2 = $value;
1619
	}
1620
	function GetUpperlimit() {
1621
		return $this->upperlimit;
1622
	}
1623
	function GetU_m1() {
1624
		return $this->u_m1;
1625
	}
1626
	function GetU_d() {
1627
		return $this->u_d;
1628
	}
1629
	function GetU_m2() {
1630
		return $this->u_m2;
1631
	}
1632
	function SetUpperlimit() {
1633
		$this->upperlimit = "on";
1634
	}
1635
	function DisableUpperlimit() {
1636
		$this->upperlimit = "";
1637
	}
1638
	function SetU_m1($value) {
1639
		$this->u_m1 = $value;
1640
	}
1641
	function SetU_d($value) {
1642
		$this->u_d = $value;
1643
	}
1644
	function SetU_m2($value) {
1645
		$this->u_m2 = $value;
1646
	}
1647

    
1648
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1649

    
1650
		if (!is_array($this->subqueues)) {
1651
			$this->subqueues = array();
1652
		}
1653
		$q =& new hfsc_queue();
1654
		$q->SetInterface($this->GetInterface());
1655
		$q->SetParent($this);
1656
		$q->ReadConfig($qname);
1657
		$q->validate_input($qname, $input_errors);
1658
		if (count($input_errors)) {
1659
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
1660
			return $q;
1661
		}
1662

    
1663
		$q->SetEnabled("on");
1664
		$q->SetLink($path);
1665
		switch ($q->GetBwscale()) {
1666
			case "%":
1667
				$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
1668
				break;
1669
			default:
1670
				$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
1671
				break;
1672
		}
1673
		$q->SetAvailableBandwidth($myBw);
1674
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
1675

    
1676
		$this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue()
1677
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
1678
		if (is_array($qname['queue'])) {
1679
			foreach ($qname['queue'] as $key1 => $que) {
1680
				array_push($path, $key1);
1681
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
1682
				array_pop($path);
1683
			}
1684
		}
1685

    
1686
		return $q;
1687
	}
1688

    
1689
	function copy_queue($interface, &$cflink) {
1690

    
1691
		$cflink['name'] = $this->GetQname();
1692
		$cflink['interface'] = $interface;
1693
		$cflink['qlimit'] = trim($this->GetQlimit());
1694
		if (empty($cflink['qlimit'])) {
1695
			unset($cflink['qlimit']);
1696
		}
1697
		$cflink['priority'] = trim($this->GetQpriority());
1698
		if (empty($cflink['priority'])) {
1699
			unset($cflink['priority']);
1700
		}
1701
		$cflink['description'] = trim($this->GetDescription());
1702
		if (empty($cflink['description'])) {
1703
			unset($cflink['description']);
1704
		}
1705
		$cflink['bandwidth'] = $this->GetBandwidth();
1706
		$cflink['bandwidthtype'] = $this->GetBwscale();
1707
		$cflink['enabled'] = trim($this->GetEnabled());
1708
		if (empty($cflink['enabled'])) {
1709
			unset($cflink['enabled']);
1710
		}
1711
		$cflink['default'] = trim($this->GetDefault());
1712
		if (empty($cflink['default'])) {
1713
			unset($cflink['default']);
1714
		}
1715
		$cflink['red'] = trim($this->GetRed());
1716
		if (empty($cflink['red'])) {
1717
			unset($cflink['red']);
1718
		}
1719
		$cflink['rio'] = trim($this->GetRio());
1720
		if (empty($cflink['rio'])) {
1721
			unset($cflink['rio']);
1722
		}
1723
		$cflink['ecn'] = trim($this->GetEcn());
1724
		if (empty($cflink['ecn'])) {
1725
			unset($cflink['ecn']);
1726
		}
1727
		if ($this->GetLinkshare() <> "") {
1728
			if ($this->GetL_m1() <> "") {
1729
				$cflink['linkshare1'] = $this->GetL_m1();
1730
				$cflink['linkshare2'] = $this->GetL_d();
1731
				$cflink['linkshare'] = "on";
1732
			} else {
1733
				unset($cflink['linkshare1']);
1734
				unset($cflink['linkshare2']);
1735
				unset($cflink['linkshare']);
1736
			}
1737
			if ($this->GetL_m2() <> "") {
1738
				$cflink['linkshare3'] = $this->GetL_m2();
1739
				$cflink['linkshare'] = "on";
1740
			} else {
1741
				unset($cflink['linkshare3']);
1742
				unset($cflink['linkshare']);
1743
			}
1744
		}
1745
		if ($this->GetRealtime() <> "") {
1746
			if ($this->GetR_m1() <> "") {
1747
				$cflink['realtime1'] = $this->GetR_m1();
1748
				$cflink['realtime2'] = $this->GetR_d();
1749
				$cflink['realtime'] = "on";
1750
			} else {
1751
				unset($cflink['realtime1']);
1752
				unset($cflink['realtime2']);
1753
				unset($cflink['realtime']);
1754
			}
1755
			if ($this->GetR_m2() <> "") {
1756
				$cflink['realtime3'] = $this->GetR_m2();
1757
				$cflink['realtime'] = "on";
1758
			} else {
1759
				unset($cflink['realtime3']);
1760
				unset($cflink['realtime']);
1761
			}
1762
		}
1763
		if ($this->GetUpperlimit() <> "") {
1764
			if ($this->GetU_m1() <> "") {
1765
				$cflink['upperlimit1'] = $this->GetU_m1();
1766
				$cflink['upperlimit2'] = $this->GetU_d();
1767
				$cflink['upperlimit'] = "on";
1768
			} else {
1769
				unset($cflink['upperlimit']);
1770
				unset($cflink['upperlimit1']);
1771
				unset($cflink['upperlimit2']);
1772
			}
1773
			if ($this->GetU_m2() <> "") {
1774
				$cflink['upperlimit3'] = $this->GetU_m2();
1775
				$cflink['upperlimit'] = "on";
1776
			} else {
1777
				unset($cflink['upperlimit3']);
1778
				unset($cflink['upperlimit']);
1779
			}
1780
		}
1781

    
1782
		if (is_array($this->subqueues)) {
1783
			$cflinkp['queue'] = array();
1784
			foreach ($this->subqueues as $q) {
1785
				$cflink['queue'][$q->GetQname()] = array();
1786
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1787
			}
1788
		}
1789
	}
1790

    
1791
	function delete_queue() {
1792
		unref_on_altq_queue_list($this->GetQname());
1793
		cleanup_queue_from_rules($this->GetQname());
1794
		$parent =& $this->GetParent();
1795
		foreach ($this->subqueues as $q) {
1796
			$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
1797
				$q->delete_queue();
1798
		}
1799
		unset_object_by_reference($this->GetLink());
1800
	}
1801

    
1802
	/*
1803
	 * Should search even its children
1804
	 */
1805
	function &find_queue($interface, $qname) {
1806
		if ($qname == $this->GetQname()) {
1807
			return $this;
1808
		}
1809

    
1810
		foreach ($this->subqueues as $q) {
1811
			$result =& $q->find_queue("", $qname);
1812
			if ($result) {
1813
				return $result;
1814
			}
1815
		}
1816
	}
1817

    
1818
	function &find_parentqueue($interface, $qname) {
1819
		if ($this->subqueues[$qname]) {
1820
			return $this;
1821
		}
1822
		foreach ($this->subqueues as $q) {
1823
			$result = $q->find_parentqueue("", $qname);
1824
			if ($result) {
1825
				return $result;
1826
			}
1827
		}
1828
	}
1829

    
1830
	function validate_input($data, &$input_errors) {
1831
		parent::validate_input($data, $input_errors);
1832

    
1833
		$reqdfields[] = "bandwidth";
1834
		$reqdfieldsn[] = gettext("Bandwidth");
1835
		$reqdfields[] = "bandwidthtype";
1836
		$reqdfieldsn[] = gettext("Bandwidthtype");
1837

    
1838
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1839

    
1840
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1841
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
1842
				$input_errors[] = gettext("Bandwidth must be an integer.");
1843
			}
1844

    
1845
			if ($data['bandwidth'] < 0) {
1846
				$input_errors[] = gettext("Bandwidth cannot be negative.");
1847
			}
1848

    
1849
			if ($data['bandwidthtype'] == "%") {
1850
				if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
1851
					$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
1852
				}
1853
			}
1854
		/*
1855
			$parent =& $this->GetParent();
1856
			switch ($data['bandwidthtype']) {
1857
			case "%":
1858
				$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
1859
			default:
1860
				$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
1861
				break;
1862
			}
1863
			if ($parent->GetAvailableBandwidth() < $myBw) {
1864
				$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
1865
			}
1866
		*/
1867
		}
1868

    
1869
		if ($data['upperlimit1'] <> "" && $data['upperlimit2'] == "") {
1870
			$input_errors[] = gettext("upperlimit service curve defined but missing (d) value");
1871
		}
1872
		if ($data['upperlimit2'] <> "" && $data['upperlimit1'] == "") {
1873
			$input_errors[] = gettext("upperlimit service curve defined but missing initial bandwidth (m1) value");
1874
		}
1875
		if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1'])) {
1876
			$input_errors[] = gettext("upperlimit m1 value needs to be Kb, Mb, Gb, or %");
1877
		}
1878
		if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2'])) {
1879
			$input_errors[] = gettext("upperlimit d value needs to be numeric");
1880
		}
1881
		if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3'])) {
1882
			$input_errors[] = gettext("upperlimit m2 value needs to be Kb, Mb, Gb, or %");
1883
		}
1884

    
1885
		/*
1886
		if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") {
1887
			$bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']);
1888
			$bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']);
1889
			if (floatval($bw_1) < floatval($bw_2)) {
1890
				$input_errors[] = ("upperlimit m1 cannot be smaller than m2");
1891
			}
1892

    
1893
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
1894
				$input_errors[] = ("upperlimit specification exceeds 80% of allowable allocation.");
1895
			}
1896
		}
1897
		*/
1898
		if ($data['linkshare1'] <> "" && $data['linkshare2'] == "") {
1899
			$input_errors[] = gettext("linkshare service curve defined but missing (d) value");
1900
		}
1901
		if ($data['linkshare2'] <> "" && $data['linkshare1'] == "") {
1902
			$input_errors[] = gettext("linkshare service curve defined but missing initial bandwidth (m1) value");
1903
		}
1904
		if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1'])) {
1905
			$input_errors[] = gettext("linkshare m1 value needs to be Kb, Mb, Gb, or %");
1906
		}
1907
		if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2'])) {
1908
			$input_errors[] = gettext("linkshare d value needs to be numeric");
1909
		}
1910
		if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3'])) {
1911
			$input_errors[] = gettext("linkshare m2 value needs to be Kb, Mb, Gb, or %");
1912
		}
1913
		if ($data['realtime1'] <> "" && $data['realtime2'] == "") {
1914
			$input_errors[] = gettext("realtime service curve defined but missing (d) value");
1915
		}
1916
		if ($data['realtime2'] <> "" && $data['realtime1'] == "") {
1917
			$input_errors[] = gettext("realtime service curve defined but missing initial bandwidth (m1) value");
1918
		}
1919

    
1920
		/*
1921
		if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) {
1922
			$bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']);
1923
			$bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']);
1924
			if (floatval($bw_1) < floatval($bw_2)) {
1925
				$input_errors[] = ("linkshare m1 cannot be smaller than m2");
1926
			}
1927

    
1928
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
1929
				$input_errors[] = ("linkshare specification exceeds 80% of allowable allocation.");
1930
			}
1931
		}
1932
		*/
1933

    
1934
		if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1'])) {
1935
			$input_errors[] = gettext("realtime m1 value needs to be Kb, Mb, Gb, or %");
1936
		}
1937
		if ($data['realtime2'] <> "" && !is_numeric($data['realtime2'])) {
1938
			$input_errors[] = gettext("realtime d value needs to be numeric");
1939
		}
1940
		if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3'])) {
1941
			$input_errors[] = gettext("realtime m2 value needs to be Kb, Mb, Gb, or %");
1942
		}
1943

    
1944
		/*
1945
		if (isset($data['realtime']) && $data['realtime3'] <> "" && $data['realtime1'] <> "" && 0) {
1946
			$bw_1 = get_hfsc_bandwidth($this, $data['realtime1']);
1947
			$bw_2 = get_hfsc_bandwidth($this, $data['realtime3']);
1948
			if (floatval($bw_1) < floatval($bw_2)) {
1949
				$input_errors[] = ("realtime m1 cannot be smaller than m2");
1950
			}
1951

    
1952
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
1953
				$input_errors[] = ("realtime specification exceeds 80% of allowable allocation.");
1954
			}
1955
		}
1956
		*/
1957
	}
1958

    
1959
	function ReadConfig(&$cflink) {
1960
		if (!empty($cflink['linkshare'])) {
1961
			if (!empty($cflink['linkshare1'])) {
1962
				$this->SetL_m1($cflink['linkshare1']);
1963
				$this->SetL_d($cflink['linkshare2']);
1964
				$this->SetLinkshare();
1965
			} else {
1966
				$this->SetL_m1("");
1967
				$this->SetL_d("");
1968
				$this->DisableLinkshare();
1969
			}
1970
			if (!empty($cflink['linkshare3'])) {
1971
				$this->SetL_m2($cflink['linkshare3']);
1972
				$this->SetLinkshare();
1973
			}
1974
		} else {
1975
			$this->DisableLinkshare();
1976
		}
1977
		if (!empty($cflink['realtime'])) {
1978
			if (!empty($cflink['realtime1'])) {
1979
				$this->SetR_m1($cflink['realtime1']);
1980
				$this->SetR_d($cflink['realtime2']);
1981
				$this->SetRealtime();
1982
			} else {
1983
				$this->SetR_m1("");
1984
				$this->SetR_d("");
1985
				$this->DisableRealtime();
1986
			}
1987
			if (!empty($cflink['realtime3'])) {
1988
				$this->SetR_m2($cflink['realtime3']);
1989
				$this->SetRealtime();
1990
			}
1991
		} else {
1992
			$this->DisableRealtime();
1993
		}
1994
		if (!empty($cflink['upperlimit'])) {
1995
			if (!empty($cflink['upperlimit1'])) {
1996
				$this->SetU_m1($cflink['upperlimit1']);
1997
				$this->SetU_d($cflink['upperlimit2']);
1998
				$this->SetUpperlimit();
1999
			} else {
2000
				$this->SetU_m1("");
2001
				$this->SetU_d("");
2002
				$this->DisableUpperlimit();
2003
			}
2004
			if (!empty($cflink['upperlimit3'])) {
2005
				$this->SetU_m2($cflink['upperlimit3']);
2006
				$this->SetUpperlimit();
2007
			}
2008
		} else {
2009
			$this->DisableUpperlimit();
2010
		}
2011
		parent::ReadConfig($cflink);
2012
	}
2013

    
2014
	function build_tree() {
2015
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface() ."&amp;queue=" . $this->GetQname()."&amp;action=show";
2016
		$tree .= "\" ";
2017
		$tmpvalue = $this->GetDefault();
2018
		if (!empty($tmpvalue)) {
2019
			$tree .= " class=\"navlnk\"";
2020
		}
2021
		$tree .= " >" . $this->GetQname() . "</a>";
2022
		if (is_array($this->subqueues)) {
2023
			$tree .= "<ul>";
2024
			foreach ($this->subqueues as $q) {
2025
				$tree .= $q->build_tree();
2026
			}
2027
			$tree .= "</ul>";
2028
		}
2029
		$tree .= "</li>";
2030
		return $tree;
2031
	}
2032

    
2033
	/* Even this should take children into consideration */
2034
	function build_rules(&$default = false) {
2035

    
2036
		$pfq_rule = " queue ". $this->qname;
2037
		if ($this->GetInterface()) {
2038
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2039
		}
2040
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2041
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2042
		}
2043

    
2044
		$tmpvalue = $this->GetQlimit();
2045
		if (!empty($tmpvalue)) {
2046
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2047
		}
2048
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetCodel() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
2049
			$pfq_rule .= " hfsc ( ";
2050
			$tmpvalue = $this->GetRed();
2051
			if (!empty($tmpvalue)) {
2052
				$comma = 1;
2053
				$pfq_rule .= " red ";
2054
			}
2055

    
2056
			$tmpvalue = $this->GetRio();
2057
			if (!empty($tmpvalue)) {
2058
				if ($comma) {
2059
					$pfq_rule .= " ,";
2060
				}
2061
				$comma = 1;
2062
				$pfq_rule .= " rio ";
2063
			}
2064
			$tmpvalue = $this->GetEcn();
2065
			if (!empty($tmpvalue)) {
2066
				if ($comma) {
2067
					$pfq_rule .= " ,";
2068
				}
2069
				$comma = 1;
2070
				$pfq_rule .= " ecn ";
2071
			}
2072
			$tmpvalue = $this->GetCodel();
2073
			if (!empty($tmpvalue)) {
2074
				if ($comma) {
2075
					$pfq_rule .= " ,";
2076
				}
2077
				$comma = 1;
2078
				$pfq_rule .= " codel ";
2079
			}
2080
			$tmpvalue = $this->GetDefault();
2081
			if (!empty($tmpvalue)) {
2082
				if ($comma) {
2083
					$pfq_rule .= " ,";
2084
				}
2085
				$comma = 1;
2086
				$pfq_rule .= " default ";
2087
				$default = true;
2088
			}
2089

    
2090
			if ($this->GetRealtime() <> "") {
2091
				if ($comma) {
2092
					$pfq_rule .= " , ";
2093
				}
2094
				if ($this->GetR_m1() <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "") {
2095
					$pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") ";
2096
				} else if ($this->GetR_m2() <> "") {
2097
					$pfq_rule .= " realtime " . $this->GetR_m2();
2098
				}
2099
				$comma = 1;
2100
			}
2101
			if ($this->GetLinkshare() <> "") {
2102
				if ($comma) {
2103
					$pfq_rule .= " ,";
2104
				}
2105
				if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "") {
2106
					$pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") ";
2107
				} else if ($this->GetL_m2() <> "") {
2108
					$pfq_rule .= " linkshare " . $this->GetL_m2() . " ";
2109
				}
2110
				$comma = 1;
2111
			}
2112
			if ($this->GetUpperlimit() <> "") {
2113
				if ($comma) {
2114
					$pfq_rule .= " ,";
2115
				}
2116
				if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "") {
2117
							$pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") ";
2118
				} else if ($this->GetU_m2() <> "") {
2119
					$pfq_rule .= " upperlimit " . $this->GetU_m2() . " ";
2120
				}
2121
			}
2122
			$pfq_rule .= " ) ";
2123
		}
2124
		if (count($this->subqueues)) {
2125
			$i = count($this->subqueues);
2126
			$pfq_rule .= " { ";
2127
			foreach ($this->subqueues as $qkey => $qnone) {
2128
				if ($i > 1) {
2129
					$i--;
2130
					$pfq_rule .= " {$qkey}, ";
2131
				} else {
2132
					$pfq_rule .= " {$qkey} ";
2133
				}
2134
			}
2135
			$pfq_rule .= " } \n";
2136
			foreach ($this->subqueues as $q) {
2137
				$pfq_rule .= $q->build_rules($default);
2138
			}
2139
		}
2140

    
2141
		$pfq_rule .= " \n";
2142

    
2143
		return $pfq_rule;
2144
	}
2145

    
2146
	function build_javascript() {
2147

    
2148
		$javascript = <<<EOJS
2149
<script type="text/javascript">
2150
//<![CDATA[
2151
	events.push(function(){
2152

    
2153
		// Disables the specified input element
2154
		function disableInput(id, disable) {
2155
			$('#' + id).prop("disabled", disable);
2156
		}
2157

    
2158
		// Upperlimit
2159
		function enable_upperlimit() {
2160
			disableInput('upperlimit1', !$('#upperlimit').prop('checked'));
2161
			disableInput('upperlimit2', !$('#upperlimit').prop('checked'));
2162
			disableInput('upperlimit3', !$('#upperlimit').prop('checked'));
2163
		}
2164

    
2165
		$('#upperlimit').click(function () {
2166
			enable_upperlimit();
2167
		});
2168

    
2169
		enable_upperlimit();
2170

    
2171
		// realtime
2172
		function enable_realtime() {
2173
			disableInput('realtime1', !$('#realtime').prop('checked'));
2174
			disableInput('realtime2', !$('#realtime').prop('checked'));
2175
			disableInput('realtime3', !$('#realtime').prop('checked'));
2176
		}
2177

    
2178
		$('#realtime').click(function () {
2179
			enable_realtime();
2180
		});
2181

    
2182
		enable_realtime();
2183

    
2184
		// linkshare
2185
		function enable_linkshare() {
2186
			disableInput('linkshare1', !$('#linkshare').prop('checked'));
2187
			disableInput('linkshare2', !$('#linkshare').prop('checked'));
2188
			disableInput('linkshare3', !$('#linkshare').prop('checked'));
2189
		}
2190

    
2191
		$('#linkshare').click(function () {
2192
			enable_linkshare();
2193
		});
2194

    
2195
		enable_linkshare();
2196
	});
2197
//]]>
2198
</script>
2199
EOJS;
2200

    
2201
		return $javascript;
2202
	}
2203

    
2204
	function build_form() {
2205

    
2206
		$sform = parent::build_form();
2207

    
2208
		$section = new Form_Section('Service Curve (sc)');
2209

    
2210
		$group = new Form_Group('Bandwidth');
2211

    
2212
		$group->add(new Form_Input(
2213
			'bandwidth',
2214
			null,
2215
			'number',
2216
			$this->GetBandwidth()
2217
		));
2218

    
2219
		$group->add(new Form_Select(
2220
			'bandwidthtype',
2221
			null,
2222
			$this->GetBwscale(),
2223
			array('Kb' => 'Kb',
2224
				  'Mb' => 'Mb',
2225
				  'Gb' => 'Gb',
2226
				  'b' => 'b',
2227
				  '%' => '%')
2228
		));
2229

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

    
2232
		$section->add($group);
2233

    
2234
		$group = new Form_Group('Max bandwidth for queue.');
2235

    
2236
		$group->add(new Form_Checkbox(
2237
			'upperlimit',
2238
			null,
2239
			'Upper Limit',
2240
			($this->GetUpperlimit()<> "")
2241
		));
2242

    
2243
		$group->add(new Form_Input(
2244
			'upperlimit1',
2245
			null,
2246
			'text',
2247
			$this->GetU_m1()
2248
		))->setHelp('m1');
2249

    
2250
		$group->add(new Form_Input(
2251
			'upperlimit2',
2252
			null,
2253
			'text',
2254
			$this->GetU_d()
2255
		))->setHelp('d');
2256

    
2257
		$group->add(new Form_Input(
2258
			'upperlimit3',
2259
			null,
2260
			'text',
2261
			$this->GetU_m2()
2262
		))->setHelp('m2');
2263

    
2264

    
2265
		$section->add($group);
2266

    
2267
		$group = new Form_Group('Min bandwidth for queue.');
2268

    
2269
		$group->add(new Form_Checkbox(
2270
			'realtime',
2271
			null,
2272
			'Real Time',
2273
			($this->GetRealtime()<> "")
2274
		));
2275

    
2276
		$group->add(new Form_Input(
2277
			'realtime1',
2278
			null,
2279
			'text',
2280
			$this->GetR_m1()
2281
		))->setHelp('m1');
2282

    
2283
		$group->add(new Form_Input(
2284
			'realtime2',
2285
			null,
2286
			'text',
2287
			$this->GetR_d()
2288
		))->setHelp('d');
2289

    
2290
		$group->add(new Form_Input(
2291
			'realtime3',
2292
			null,
2293
			'text',
2294
			$this->GetR_m2()
2295
		))->setHelp('m2');
2296

    
2297
		$section->add($group);
2298

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

    
2301
		$group->add(new Form_Checkbox(
2302
			'linkshare',
2303
			null,
2304
			'Link Share',
2305
			($this->GetLinkshare()<> "")
2306
		));
2307

    
2308
		$group->add(new Form_Input(
2309
			'linkshare1',
2310
			null,
2311
			'text',
2312
			$this->GetL_m1()
2313
		))->setHelp('m1');
2314

    
2315
		$group->add(new Form_Input(
2316
			'linkshare2',
2317
			null,
2318
			'text',
2319
			$this->GetL_d()
2320
		))->setHelp('d');
2321

    
2322
		$group->add(new Form_Input(
2323
			'linkshare3',
2324
			null,
2325
			'text',
2326
			$this->GetL_m2()
2327
		))->setHelp('m2');
2328

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

    
2334
		$section->add($group);
2335

    
2336
		$sform->add($section);
2337

    
2338
		return($sform);
2339
	}
2340

    
2341
	function update_altq_queue_data(&$data) {
2342
		$this->ReadConfig($data);
2343
	}
2344

    
2345
	function wconfig() {
2346
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2347
		if (!is_array($cflink)) {
2348
			$cflink = array();
2349
		}
2350
		$cflink['name'] = $this->GetQname();
2351
		$cflink['interface'] = $this->GetInterface();
2352
		$cflink['qlimit'] = trim($this->GetQlimit());
2353
		if (empty($cflink['qlimit'])) {
2354
			unset($cflink['qlimit']);
2355
		}
2356
		$cflink['priority'] = $this->GetQpriority();
2357
		if (empty($cflink['priority'])) {
2358
			unset($cflink['priority']);
2359
		}
2360
		$cflink['description'] = $this->GetDescription();
2361
		if (empty($cflink['description'])) {
2362
			unset($cflink['description']);
2363
		}
2364
		$cflink['bandwidth'] = $this->GetBandwidth();
2365
		$cflink['bandwidthtype'] = $this->GetBwscale();
2366
		$cflink['enabled'] = $this->GetEnabled();
2367
		if (empty($cflink['enabled'])) {
2368
			unset($cflink['enabled']);
2369
		}
2370
		$cflink['default'] = $this->GetDefault();
2371
		if (empty($cflink['default'])) {
2372
			unset($cflink['default']);
2373
		}
2374
		$cflink['red'] = trim($this->GetRed());
2375
		if (empty($cflink['red'])) {
2376
			unset($cflink['red']);
2377
		}
2378
		$cflink['rio'] = $this->GetRio();
2379
		if (empty($cflink['rio'])) {
2380
			unset($cflink['rio']);
2381
		}
2382
		$cflink['ecn'] = trim($this->GetEcn());
2383
		if (empty($cflink['ecn'])) {
2384
			unset($cflink['ecn']);
2385
		}
2386
		$cflink['codel'] = trim($this->GetCodel());
2387
		if (empty($cflink['codel'])) {
2388
			unset($cflink['codel']);
2389
		}
2390
		if ($this->GetLinkshare() <> "") {
2391
			if ($this->GetL_m1() <> "") {
2392
				$cflink['linkshare1'] = $this->GetL_m1();
2393
				$cflink['linkshare2'] = $this->GetL_d();
2394
				$cflink['linkshare'] = "on";
2395
			} else {
2396
				unset($cflink['linkshare']);
2397
				unset($cflink['linkshare1']);
2398
				unset($cflink['linkshare2']);
2399
			}
2400
			if ($this->GetL_m2() <> "") {
2401
				$cflink['linkshare3'] = $this->GetL_m2();
2402
				$cflink['linkshare'] = "on";
2403
			} else {
2404
				unset($cflink['linkshare']);
2405
				unset($cflink['linkshare3']);
2406
			}
2407
		} else {
2408
			unset($cflink['linkshare']);
2409
			unset($cflink['linkshare1']);
2410
			unset($cflink['linkshare2']);
2411
			unset($cflink['linkshare3']);
2412
		}
2413
		if ($this->GetRealtime() <> "") {
2414
			if ($this->GetR_m1() <> "") {
2415
				$cflink['realtime1'] = $this->GetR_m1();
2416
				$cflink['realtime2'] = $this->GetR_d();
2417
				$cflink['realtime'] = "on";
2418
			} else {
2419
				unset($cflink['realtime']);
2420
				unset($cflink['realtime1']);
2421
				unset($cflink['realtime2']);
2422
			}
2423
			if ($this->GetR_m2() <> "") {
2424
				$cflink['realtime3'] = $this->GetR_m2();
2425
				$cflink['realtime'] = "on";
2426
			} else {
2427
				unset($cflink['realtime']);
2428
				unset($cflink['realtime3']);
2429
			}
2430
		} else {
2431
			unset($cflink['realtime']);
2432
			unset($cflink['realtime1']);
2433
			unset($cflink['realtime2']);
2434
			unset($cflink['realtime3']);
2435
		}
2436
		if ($this->GetUpperlimit() <> "") {
2437
			if ($this->GetU_m1() <> "") {
2438
				$cflink['upperlimit1'] = $this->GetU_m1();
2439
				$cflink['upperlimit2'] = $this->GetU_d();
2440
				$cflink['upperlimit'] = "on";
2441
			} else {
2442
				unset($cflink['upperlimit']);
2443
				unset($cflink['upperlimit1']);
2444
				unset($cflink['upperlimit2']);
2445
			}
2446
			if ($this->GetU_m2() <> "") {
2447
				$cflink['upperlimit3'] = $this->GetU_m2();
2448
				$cflink['upperlimit'] = "on";
2449
			} else {
2450
				unset($cflink['upperlimit']);
2451
				unset($cflink['upperlimit3']);
2452
			}
2453
		} else {
2454
			unset($cflink['upperlimit']);
2455
			unset($cflink['upperlimit1']);
2456
			unset($cflink['upperlimit2']);
2457
			unset($cflink['upperlimit3']);
2458
		}
2459
	}
2460
}
2461

    
2462
class cbq_queue extends priq_queue {
2463
	var $qborrow = "";
2464

    
2465
	function GetBorrow() {
2466
		return $this->qborrow;
2467
	}
2468
	function SetBorrow($borrow) {
2469
		$this->qborrow = $borrow;
2470
	}
2471
	function CanHaveChildren() {
2472
		return true;
2473
	}
2474

    
2475
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2476

    
2477
		if (!is_array($this->subqueues)) {
2478
			$this->subqueues = array();
2479
		}
2480
		$q =& new cbq_queue();
2481
		$q->SetInterface($this->GetInterface());
2482
		$q->SetParent($this);
2483
		$q->ReadConfig($qname);
2484
		$q->validate_input($qname, $input_errors);
2485
		if (count($input_errors)) {
2486
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
2487
			return $q;
2488
		}
2489
		switch ($q->GetBwscale()) {
2490
			case "%":
2491
				$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
2492
				break;
2493
			default:
2494
				$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
2495
				break;
2496
		}
2497
		$q->SetAvailableBandwidth($myBw);
2498
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
2499

    
2500
		$q->SetEnabled("on");
2501
		$q->SetLink($path);
2502
		$this->subqueues[$q->GetQName()] = &$q;
2503
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2504
		if (is_array($qname['queue'])) {
2505
			foreach ($qname['queue'] as $key1 => $que) {
2506
				array_push($path, $key1);
2507
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
2508
				array_pop($path);
2509
			}
2510
		}
2511

    
2512
		return $q;
2513
	}
2514

    
2515
	function copy_queue($interface, &$cflink) {
2516

    
2517
		$cflink['interface'] = $interface;
2518
		$cflink['qlimit'] = trim($this->GetQlimit());
2519
		if (empty($clink['qlimit'])) {
2520
			unset($cflink['qlimit']);
2521
		}
2522
		$cflink['priority'] = trim($this->GetQpriority());
2523
		if (empty($cflink['priority'])) {
2524
			unset($cflink['priority']);
2525
		}
2526
		$cflink['name'] = $this->GetQname();
2527
		$cflink['description'] = trim($this->GetDescription());
2528
		if (empty($cflink['description'])) {
2529
			unset($cflink['description']);
2530
		}
2531
		$cflink['bandwidth'] = $this->GetBandwidth();
2532
		$cflink['bandwidthtype'] = $this->GetBwscale();
2533
		$cflink['enabled'] = trim($this->GetEnabled());
2534
		if (empty($cflink['enabled'])) {
2535
			unset($cflink['enabled']);
2536
		}
2537
		$cflink['default'] = trim($this->GetDefault());
2538
		if (empty($cflink['default'])) {
2539
			unset($cflink['default']);
2540
		}
2541
		$cflink['red'] = trim($this->GetRed());
2542
		if (empty($cflink['red'])) {
2543
			unset($cflink['red']);
2544
		}
2545
		$cflink['rio'] = trim($this->GetRio());
2546
		if (empty($cflink['rio'])) {
2547
			unset($cflink['rio']);
2548
		}
2549
		$cflink['ecn'] = trim($this->GetEcn());
2550
		if (empty($cflink['ecn'])) {
2551
			unset($cflink['ecn']);
2552
		}
2553
		$cflink['borrow'] = trim($this->GetBorrow());
2554
		if (empty($cflink['borrow'])) {
2555
			unset($cflink['borrow']);
2556
		}
2557
		if (is_array($this->queues)) {
2558
			$cflinkp['queue'] = array();
2559
			foreach ($this->subqueues as $q) {
2560
				$cflink['queue'][$q->GetQname()] = array();
2561
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
2562
			}
2563
		}
2564
	}
2565

    
2566
	/*
2567
	 * Should search even its children
2568
	 */
2569
	function &find_queue($interface, $qname) {
2570
		if ($qname == $this->GetQname()) {
2571
			return $this;
2572
		}
2573
		foreach ($this->subqueues as $q) {
2574
			$result =& $q->find_queue("", $qname);
2575
			if ($result) {
2576
				return $result;
2577
			}
2578
		}
2579
	}
2580

    
2581
	function &find_parentqueue($interface, $qname) {
2582
		if ($this->subqueues[$qname]) {
2583
			return $this;
2584
		}
2585
		foreach ($this->subqueues as $q) {
2586
			$result = $q->find_parentqueue("", $qname);
2587
			if ($result) {
2588
				return $result;
2589
			}
2590
		}
2591
	}
2592

    
2593
	function delete_queue() {
2594
		unref_on_altq_queue_list($this->GetQname());
2595
		cleanup_queue_from_rules($this->GetQname());
2596
		foreach ($this->subqueues as $q) {
2597
			$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
2598
				$q->delete_queue();
2599
		}
2600
		unset_object_by_reference($this->GetLink());
2601
	}
2602

    
2603
	function validate_input($data, &$input_errors) {
2604
		parent::validate_input($data, $input_errors);
2605

    
2606
		if ($data['priority'] > 7) {
2607
				$input_errors[] = gettext("Priority must be an integer between 1 and 7.");
2608
		}
2609
		$reqdfields[] = "bandwidth";
2610
		$reqdfieldsn[] = gettext("Bandwidth");
2611
		$reqdfields[] = "bandwidthtype";
2612
		$reqdfieldsn[] = gettext("Bandwidthtype");
2613

    
2614
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2615

    
2616
		if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
2617
			$input_errors[] = gettext("Bandwidth must be an integer.");
2618
		}
2619

    
2620

    
2621
		if ($data['bandwidth'] < 0) {
2622
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2623
		}
2624

    
2625
		if ($data['bandwidthtype'] == "%") {
2626
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
2627
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2628
			}
2629
		}
2630

    
2631
/*
2632
		$parent =& $this->GetParent();
2633
		switch ($data['bandwidthtype']) {
2634
		case "%":
2635
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2636
			break;
2637
		default:
2638
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2639
			break;
2640
		}
2641
		if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
2642
			$input_errors[] = "The sum of the children bandwidth exceeds that of the parent.";
2643
		}
2644
 */
2645
	}
2646

    
2647
	function ReadConfig(&$q) {
2648
		parent::ReadConfig($q);
2649
		if (!empty($q['borrow'])) {
2650
			$this->SetBorrow("on");
2651
		} else {
2652
			$this->SetBorrow("");
2653
		}
2654
	}
2655

    
2656
	function build_javascript() {
2657
		return parent::build_javascript();
2658
	}
2659

    
2660
	function build_tree() {
2661
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2662
		$tree .= "\" ";
2663
		$tmpvalue = trim($this->GetDefault());
2664
		if (!empty($tmpvalue)) {
2665
			$tree .= " class=\"navlnk\"";
2666
		}
2667
		$tree .= " >" . $this->GetQname() . "</a>";
2668
		if (is_array($this->subqueues)) {
2669
			$tree .= "<ul>";
2670
			foreach ($this->subqueues as $q) {
2671
				$tree .= $q->build_tree();
2672
			}
2673
			$tree .= "</ul>";
2674
		}
2675
		$tree .= "</li>";
2676
		return $tree;
2677
	}
2678

    
2679
	/* Even this should take children into consideration */
2680
	function build_rules(&$default = false) {
2681
		$pfq_rule = "queue ". $this->qname;
2682
		if ($this->GetInterface()) {
2683
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2684
		}
2685
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2686
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2687
		}
2688
		$tmpvalue = $this->GetQpriority();
2689
		if (!empty($tmpvalue)) {
2690
			$pfq_rule .= " priority " . $this->GetQpriority();
2691
		}
2692
		$tmpvalue = trim($this->GetQlimit());
2693
		if (!empty($tmpvalue)) {
2694
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2695
		}
2696
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow() || $this->GetCodel()) {
2697
			$pfq_rule .= " cbq ( ";
2698
			$tmpvalue = trim($this->GetRed());
2699
			if (!empty($tmpvalue)) {
2700
				$comma = 1;
2701
				$pfq_rule .= " red ";
2702
			}
2703
			$tmpvalue = trim($this->GetCodel());
2704
			if (!empty($tmpvalue)) {
2705
				$comma = 1;
2706
				$pfq_rule .= " codel ";
2707
			}
2708
			$tmpvalue = trim($this->GetRio());
2709
			if (!empty($tmpvalue)) {
2710
				if ($comma) {
2711
					$pfq_rule .= " ,";
2712
				}
2713
				$comma = 1;
2714
				$pfq_rule .= " rio ";
2715
			}
2716
			$tmpvalue = trim($this->GetEcn());
2717
			if (!empty($tmpvalue)) {
2718
				if ($comma) {
2719
					$pfq_rule .= " ,";
2720
				}
2721
				$comma = 1;
2722
				$pfq_rule .= " ecn ";
2723
			}
2724
			$tmpvalue = trim($this->GetDefault());
2725
			if (!empty($tmpvalue)) {
2726
				if ($comma) {
2727
					$pfq_rule .= " ,";
2728
				}
2729
				$comma = 1;
2730
				$pfq_rule .= " default ";
2731
				$default = true;
2732
			}
2733
			$tmpvalue = trim($this->GetBorrow());
2734
			if (!empty($tmpvalue)) {
2735
				if ($comma) {
2736
					$pfq_rule .= ", ";
2737
				}
2738
				$pfq_rule .= " borrow ";
2739
			}
2740
			$pfq_rule .= " ) ";
2741
		}
2742
		if (count($this->subqueues)) {
2743
			$i = count($this->subqueues);
2744
			$pfq_rule .= " { ";
2745
			foreach ($this->subqueues as $qkey => $qnone) {
2746
				if ($i > 1) {
2747
					$i--;
2748
					$pfq_rule .= " {$qkey}, ";
2749
				} else {
2750
					$pfq_rule .= " {$qkey} ";
2751
				}
2752
			}
2753
			$pfq_rule .= " } \n";
2754
			foreach ($this->subqueues as $q) {
2755
				$pfq_rule .= $q->build_rules($default);
2756
			}
2757
		}
2758

    
2759
		$pfq_rule .= " \n";
2760
		return $pfq_rule;
2761
	}
2762

    
2763
	function build_form() {
2764
		$sform = parent::build_form();
2765

    
2766
		$section = new Form_Section('');
2767

    
2768
		$group = new Form_Group('Bandwidth');
2769

    
2770
		$group->add(new Form_Input(
2771
			'bandwidth',
2772
			null,
2773
			'number',
2774
			$this->GetBandwidth()
2775
		));
2776

    
2777
		$group->add(new Form_Select(
2778
			'bandwidthtype',
2779
			null,
2780
			$this->GetBwscale(),
2781
			array('Kb' => 'Kb',
2782
				  'Mb' => 'Mb',
2783
				  'Gb' => 'Gb',
2784
				  'b' => 'b',
2785
				  '%' => '%')
2786
		));
2787

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

    
2790
		$section->add($group);
2791

    
2792
		$section->addInput(new Form_Checkbox(
2793
			'borrow',
2794
			'Scheduler option',
2795
			'Borrow from other queues when available',
2796
			($this->GetBorrow() == "on")
2797
		));
2798

    
2799
		return $sform;
2800
	}
2801

    
2802
	function update_altq_queue_data(&$data) {
2803
		$this->ReadConfig($data);
2804
	}
2805

    
2806
	function wconfig() {
2807
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2808
		if (!is_array($cflink)) {
2809
			$cflink = array();
2810
		}
2811
		$cflink['interface'] = $this->GetInterface();
2812
		$cflink['qlimit'] = trim($this->GetQlimit());
2813
		if (empty($cflink['qlimit'])) {
2814
			unset($cflink['qlimit']);
2815
		}
2816
		$cflink['priority'] = $this->GetQpriority();
2817
		if (empty($cflink['priority'])) {
2818
			unset($cflink['priority']);
2819
		}
2820
		$cflink['name'] = $this->GetQname();
2821
		$cflink['description'] = $this->GetDescription();
2822
		if (empty($cflink['description'])) {
2823
			unset($cflink['description']);
2824
		}
2825
		$cflink['bandwidth'] = $this->GetBandwidth();
2826
		$cflink['bandwidthtype'] = $this->GetBwscale();
2827
		$cflink['enabled'] = trim($this->GetEnabled());
2828
		if (empty($cflink['enabled'])) {
2829
			unset($cflink['enabled']);
2830
		}
2831
		$cflink['default'] = trim($this->GetDefault());
2832
		if (empty($cflink['default'])) {
2833
			unset($cflink['default']);
2834
		}
2835
		$cflink['red'] = trim($this->GetRed());
2836
		if (empty($cflink['red'])) {
2837
			unset($cflink['red']);
2838
		}
2839
		$cflink['rio'] = trim($this->GetRio());
2840
		if (empty($cflink['rio'])) {
2841
			unset($cflink['rio']);
2842
		}
2843
		$cflink['ecn'] = trim($this->GetEcn());
2844
		if (empty($cflink['ecn'])) {
2845
			unset($cflink['ecn']);
2846
		}
2847
		$cflink['codel'] = trim($this->GetCodel());
2848
		if (empty($cflink['codel'])) {
2849
			unset($cflink['codel']);
2850
		}
2851
		$cflink['borrow'] = trim($this->GetBorrow());
2852
		if (empty($cflink['borrow'])) {
2853
			unset($cflink['borrow']);
2854
		}
2855
	}
2856
}
2857

    
2858
class fairq_queue extends priq_queue {
2859
	var $hogs;
2860
	var $buckets;
2861

    
2862
	function GetBuckets() {
2863
		return $this->buckets;
2864
	}
2865
	function SetBuckets($buckets) {
2866
		$this->buckets = $buckets;
2867
	}
2868
	function GetHogs() {
2869
		return $this->hogs;
2870
	}
2871
	function SetHogs($hogs) {
2872
		$this->hogs = $hogs;
2873
	}
2874
	function CanHaveChildren() {
2875
		return false;
2876
	}
2877

    
2878

    
2879
	function copy_queue($interface, &$cflink) {
2880
		$cflink['interface'] = $interface;
2881
		$cflink['qlimit'] = $this->GetQlimit();
2882
		$cflink['priority'] = $this->GetQpriority();
2883
		$cflink['name'] = $this->GetQname();
2884
		$cflink['description'] = $this->GetDescription();
2885
		$cflink['bandwidth'] = $this->GetBandwidth();
2886
		$cflink['bandwidthtype'] = $this->GetBwscale();
2887
		$cflink['enabled'] = $this->GetEnabled();
2888
		$cflink['default'] = $this->GetDefault();
2889
		$cflink['red'] = $this->GetRed();
2890
		$cflink['rio'] = $this->GetRio();
2891
		$cflink['ecn'] = $this->GetEcn();
2892
		$cflink['buckets'] = $this->GetBuckets();
2893
		$cflink['hogs'] = $this->GetHogs();
2894
	}
2895

    
2896
	/*
2897
	 * Should search even its children
2898
	 */
2899
	function &find_queue($interface, $qname) {
2900
		if ($qname == $this->GetQname()) {
2901
			return $this;
2902
		}
2903
	}
2904

    
2905
	function find_parentqueue($interface, $qname) { return; }
2906

    
2907
	function delete_queue() {
2908
		unref_on_altq_queue_list($this->GetQname());
2909
		cleanup_queue_from_rules($this->GetQname());
2910
		unset_object_by_reference($this->GetLink());
2911
	}
2912

    
2913
	function validate_input($data, &$input_errors) {
2914
		parent::validate_input($data, $input_errors);
2915

    
2916
		if ($data['priority'] > 255) {
2917
				$input_errors[] = gettext("Priority must be an integer between 1 and 255.");
2918
		}
2919
		$reqdfields[] = "bandwidth";
2920
		$reqdfieldsn[] = gettext("Bandwidth");
2921
		$reqdfields[] = "bandwidthtype";
2922
		$reqdfieldsn[] = gettext("Bandwidthtype");
2923

    
2924
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2925

    
2926
		if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
2927
			$input_errors[] = gettext("Bandwidth must be an integer.");
2928
		}
2929

    
2930

    
2931
		if ($data['bandwidth'] < 0) {
2932
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2933
		}
2934

    
2935

    
2936
		if ($data['bandwidthtype'] == "%") {
2937
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
2938
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2939
			}
2940
		}
2941

    
2942
/*
2943
		$parent =& $this->GetParent();
2944
		switch ($data['bandwidthtype']) {
2945
		case "%":
2946
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2947
		default:
2948
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2949
			break;
2950
		}
2951
		if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
2952
			$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
2953
		}
2954
*/
2955
	}
2956

    
2957
	function ReadConfig(&$q) {
2958
		parent::ReadConfig($q);
2959
		if (!empty($q['buckets'])) {
2960
			$this->SetBuckets($q['buckets']);
2961
		} else {
2962
			$this->SetBuckets("");
2963
		}
2964
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs'])) {
2965
			$this->SetHogs($q['hogs']);
2966
		} else {
2967
			$this->SetHogs("");
2968
		}
2969
	}
2970

    
2971
	function build_javascript() {
2972
		return parent::build_javascript();
2973
	}
2974

    
2975
	function build_tree() {
2976
		$tree = " <li><a href=\"firewall_shaper.php?interface=" .
2977
		$this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2978
		$tree .= "\" ";
2979
		$tmpvalue = trim($this->GetDefault());
2980
		if (!empty($tmpvalue)) {
2981
			$tree .= " class=\"navlnk\"";
2982
		}
2983
		$tree .= " >" . $this->GetQname() . "</a>";
2984
		$tree .= "</li>";
2985
		return $tree;
2986
	}
2987

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

    
3060
		$pfq_rule .= " \n";
3061
		return $pfq_rule;
3062
	}
3063

    
3064
	function build_form() {
3065
		$form = parent::build_form();
3066

    
3067
		$section = new Form_Section('');
3068

    
3069
		$group = new Form_Group('Bandwidth');
3070

    
3071
		$group->add(new Form_Input(
3072
			'bandwidth',
3073
			null,
3074
			'number',
3075
			$this->GetBandwidth()
3076
		));
3077

    
3078
		$group->add(new Form_Select(
3079
			'bandwidthtype',
3080
			null,
3081
			$this->GetBwscale(),
3082
			array('Kb' => 'Kb',
3083
				  'Mb' => 'Mb',
3084
				  'Gb' => 'Gb',
3085
				  'b' => 'b',
3086
				  '%' => '%')
3087
		));
3088

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

    
3091
		$section->add($group);
3092

    
3093

    
3094
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
3095
		$form .= "<td class=\"vtable\"><table><tr><td>";
3096
		$form .= "<input id=\"buckets\" name=\"buckets\" value=\"";
3097
		$tmpvalue = trim($this->GetBuckets());
3098
		if (!empty($tmpvalue)) {
3099
			$form .= $this->GetBuckets();
3100
		}
3101
		$form .= "\" /> " . gettext("Number of buckets available.") . "<br /></td></tr>";
3102
		$form .= "<tr><td class=\"vtable\"><input id=\"hogs\" name=\"hogs\" value=\"";
3103
		$tmpvalue = trim($this->GetHogs());
3104
		if (!empty($tmpvalue)) {
3105
			$form .= $this->GetHogs();
3106
		}
3107
		$form .= "\" /> " . gettext("Bandwidth limit for hosts to not saturate link.") . "<br /></td></tr>";
3108
		$form .= "</table></td></tr>";
3109
		return $form;
3110
	}
3111

    
3112
	function update_altq_queue_data(&$data) {
3113
		$this->ReadConfig($data);
3114
	}
3115

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

    
3172

    
3173
/*
3174
 * dummynet(4) wrappers.
3175
 */
3176

    
3177

    
3178
/*
3179
 * List of respective objects!
3180
 */
3181
$dummynet_pipe_list = array();
3182

    
3183
class dummynet_class {
3184
	var $qname;
3185
	var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
3186
	var $qlimit;
3187
	var $description;
3188
	var $qenabled;
3189
	var $link;
3190
	var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
3191
	var $plr;
3192

    
3193
	var $buckets;
3194
	/* mask parameters */
3195
	var $mask;
3196
	var $noerror;
3197

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

    
3275
	function build_javascript() {
3276
		$javascript .= "<script type=\"text/javascript\">\n";
3277
		$javascript .= "//<![CDATA[\n";
3278
		$javascript .= "function enable_maskbits(enable_over) {\n";
3279
		$javascript .= "var e = document.getElementById(\"mask\");\n";
3280
		$javascript .= "if ((e.options[e.selectedIndex].text == \"none\") || enable_over) {\n";
3281
		$javascript .= "document.iform.maskbits.disabled = 1;\n";
3282
		$javascript .= "document.iform.maskbits.value = \"\";\n";
3283
		$javascript .= "document.iform.maskbitsv6.disabled = 1;\n";
3284
		$javascript .= "document.iform.maskbitsv6.value = \"\";\n";
3285
		$javascript .= "} else {\n";
3286
		$javascript .= "document.iform.maskbits.disabled = 0;\n";
3287
		$javascript .= "document.iform.maskbitsv6.disabled = 0;\n";
3288
		$javascript .= "}}\n";
3289
		$javascript .= "//]]>\n";
3290
		$javascript .= "</script>\n";
3291
		return $javascript;
3292
	}
3293

    
3294
	function validate_input($data, &$input_errors) {
3295
		$reqdfields[] = "bandwidth";
3296
		$reqdfieldsn[] = gettext("Bandwidth");
3297
		/*$reqdfields[] = "burst";
3298
		$reqdfieldsn[] = gettext("Burst"); */
3299
		$reqdfields[] = "bandwidthtype";
3300
		$reqdfieldsn[] = gettext("Bandwidthtype");
3301
		$reqdfields[] = "newname";
3302
		$reqdfieldsn[] = gettext("Name");
3303

    
3304
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3305

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

    
3335
	function build_mask_rules(&$pfq_rule) {
3336
		$mask = $this->GetMask();
3337
		if (!empty($mask['type'])) {
3338
			if ($mask['type'] <> 'none') {
3339
				$pfq_rule .= " mask";
3340
			}
3341
			switch ($mask['type']) {
3342
				case 'srcaddress':
3343
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3344
						$pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
3345
					} else {
3346
						$pfq_rule .= " src-ip6 /128";
3347
					}
3348
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3349
						$pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3350
					} else {
3351
						$pfq_rule .= " src-ip 0xffffffff";
3352
					}
3353
					break;
3354
				case 'dstaddress':
3355
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3356
						$pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
3357
					} else {
3358
						$pfq_rule .= " dst-ip6 /128";
3359
					}
3360
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3361
						$pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3362
					} else {
3363
						$pfq_rule .= " dst-ip 0xffffffff";
3364
					}
3365
					break;
3366
				default:
3367
					break;
3368
			}
3369
		}
3370
	}
3371

    
3372
}
3373

    
3374
class dnpipe_class extends dummynet_class {
3375
	var $delay;
3376
	var $qbandwidth = array();
3377
	var $qbandwidthtype;
3378

    
3379
		/* This is here to help on form building and building rules/lists */
3380
	var $subqueues = array();
3381

    
3382
	function CanHaveChildren() {
3383
		return true;
3384
	}
3385
	function SetDelay($delay) {
3386
		$this->delay = $delay;
3387
	}
3388
	function GetDelay() {
3389
		return $this->delay;
3390
	}
3391
	function delete_queue() {
3392
		cleanup_dnqueue_from_rules($this->GetQname());
3393
		foreach ($this->subqueues as $q) {
3394
			$q->delete_queue();
3395
		}
3396
		unset_dn_object_by_reference($this->GetLink());
3397
		@pfSense_pipe_action("pipe delete " . $this->GetNumber());
3398
	}
3399
	function GetBandwidth() {
3400
		return $this->qbandwidth;
3401
	}
3402
	function SetBandwidth($bandwidth) {
3403
		$this->qbandwidth = $bandwidth;
3404
	}
3405
	function GetBurst() {
3406
		return $this->qburst;
3407
	}
3408
	function SetBurst($burst) {
3409
		$this->qburst = $burst;
3410
	}
3411

    
3412
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
3413

    
3414
		if (!is_array($this->subqueues)) {
3415
			$this->subqueues = array();
3416
		}
3417

    
3418
		$q =& new dnqueue_class();
3419
		$q->SetLink($path);
3420
		$q->SetEnabled("on");
3421
		$q->SetPipe($this->GetQname());
3422
		$q->SetParent($this);
3423
		$q->ReadConfig($queue);
3424
		$q->validate_input($queue, $input_errors);
3425
		if (count($input_errors)) {
3426
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
3427
			return $q;
3428
		}
3429
		$number = dnqueue_find_nextnumber();
3430
		$q->SetNumber($number);
3431
		$this->subqueues[$q->GetQname()] = &$q;
3432

    
3433
		return $q;
3434
	}
3435

    
3436
	function &get_queue_list(&$q = null) {
3437
		$qlist = array();
3438

    
3439
		$qlist[$this->GetQname()] = $this->GetNumber();
3440
		if (is_array($this->subqueues)) {
3441
			foreach ($this->subqueues as $queue) {
3442
				$queue->get_queue_list($qlist);
3443
			}
3444
		}
3445
		return $qlist;
3446
	}
3447

    
3448
	/*
3449
	 * Should search even its children
3450
	 */
3451
	function &find_queue($pipe, $qname) {
3452
		if ($qname == $this->GetQname()) {
3453
			return $this;
3454
		}
3455
		foreach ($this->subqueues as $q) {
3456
			$result =& $q->find_queue("", $qname);
3457
			if ($result) {
3458
				return $result;
3459
			}
3460
		}
3461
	}
3462

    
3463
	function &find_parentqueue($pipe, $qname) {
3464
		return NULL;
3465
	}
3466

    
3467
	function validate_input($data, &$input_errors) {
3468
		parent::validate_input($data, $input_errors);
3469

    
3470
		$schedule = 0;
3471
		$schedulenone = 0;
3472
		$entries = 0;
3473
		/* XXX: Really no better way? */
3474
		for ($i = 0; $i < 2900; $i++) {
3475
			if (!empty($data["bwsched{$i}"])) {
3476
				if ($data["bwsched{$i}"] != "none") {
3477
					$schedule++;
3478
				} else {
3479
					$schedulenone++;
3480
				}
3481
			}
3482
			if (!empty($data["bandwidth{$i}"])) {
3483
				if (!is_numeric($data["bandwidth{$i}"])) {
3484
					$input_errors[] = sprintf(gettext("Bandwidth for schedule %s must be an integer."), $data["bwsched{$i}"]);
3485
				} else if (($data["burst{$i}"] != "") && (!is_numeric($data["burst{$i}"]))) {
3486
					$input_errors[] = sprintf(gettext("Burst for schedule %s must be an integer."), $data["bwsched{$i}"]);
3487
				} else {
3488
					$entries++;
3489
				}
3490
			}
3491
		}
3492
		if ($schedule == 0 && $entries > 1) {
3493
			$input_errors[] = gettext("You need to specify a schedule for every additional entry");
3494
		}
3495
		if ($schedulenone > 0 && $entries > 1) {
3496
			$input_errors[] = gettext("If more than one bandwidth configured all schedules need to be selected");
3497
		}
3498
		if ($entries == 0) {
3499
			$input_errors[] = gettext("At least one bw specification is necessary");
3500
		}
3501
		if ($data['delay'] && (!is_numeric($data['delay']))) {
3502
			$input_errors[] = gettext("Delay must be an integer.");
3503
		}
3504
	}
3505

    
3506
	function ReadConfig(&$q) {
3507
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3508
			$this->SetQname($q['newname']);
3509
		} else if (!empty($q['newname'])) {
3510
			$this->SetQname($q['newname']);
3511
		} else {
3512
			$this->SetQname($q['name']);
3513
		}
3514
		$this->SetNumber($q['number']);
3515

    
3516
		if (!empty($_POST)) {
3517
			$bandwidth = array();
3518
			/* XXX: Really no better way? */
3519
			for ($i = 0; $i < 2900; $i++) {
3520
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") {
3521
					$bw = array();
3522
					$bw['bw'] = $q["bandwidth{$i}"];
3523
					$bw['burst'] = $q["burst{$i}"];
3524
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"]) {
3525
						$bw['bwscale'] = $q["bwtype{$i}"];
3526
					}
3527
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"]) {
3528
						$bw['bwsched'] = $q["bwsched{$i}"];
3529
					}
3530
					$bandwidth[] = $bw;
3531
				}
3532
			}
3533
			$this->SetBandwidth($bandwidth);
3534
		}
3535

    
3536
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
3537
			$this->SetBandwidth($q['bandwidth']['item']);
3538
			$this->SetBurst($q['burst']['item']);
3539
		}
3540

    
3541
		if (isset($q['qlimit']) && $q['qlimit'] <> "") {
3542
			$this->SetQlimit($q['qlimit']);
3543
		} else {
3544
			$this->SetQlimit("");
3545
		}
3546
		if (isset($q['mask']) && $q['mask'] <> "") {
3547
			$masktype = $q['mask'];
3548
		} else {
3549
			$masktype = "";
3550
		}
3551
		if (isset($q['maskbits']) && $q['maskbits'] <> "") {
3552
			$maskbits = $q['maskbits'];
3553
		} else {
3554
			$maskbits = "";
3555
		}
3556
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
3557
			$maskbitsv6 = $q['maskbitsv6'];
3558
		} else {
3559
			$maskbitsv6 = "";
3560
		}
3561
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3562
		if (isset($q['buckets']) && $q['buckets'] <> "") {
3563
			$this->SetBuckets($q['buckets']);
3564
		} else {
3565
			$this->SetBuckets("");
3566
		}
3567
		if (isset($q['plr']) && $q['plr'] <> "") {
3568
			$this->SetPlr($q['plr']);
3569
		} else {
3570
			$this->SetPlr("");
3571
		}
3572
		if (isset($q['delay']) && $q['delay'] <> "") {
3573
			$this->SetDelay($q['delay']);
3574
		} else {
3575
			$this->SetDelay(0);
3576
		}
3577
		if (isset($q['description']) && $q['description'] <> "") {
3578
			$this->SetDescription($q['description']);
3579
		} else {
3580
			$this->SetDescription("");
3581
		}
3582
		$this->SetEnabled($q['enabled']);
3583

    
3584
	}
3585

    
3586
	function build_tree() {
3587
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&amp;queue=".$this->GetQname() ."&amp;action=show\">";
3588
		$tree .= $this->GetQname() . "</a>";
3589
		if (is_array($this->subqueues)) {
3590
			$tree .= "<ul>";
3591
			foreach ($this->subqueues as $q) {
3592
				$tree .= $q->build_tree();
3593
			}
3594
			$tree .= "</ul>";
3595
		}
3596
		$tree .= "</li>";
3597

    
3598
		return $tree;
3599
	}
3600

    
3601
	function build_rules() {
3602
		global $config, $time_based_rules;
3603

    
3604
		if ($this->GetEnabled() == "") {
3605
			return;
3606
		}
3607

    
3608
		$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
3609
		$found = false;
3610
		$bandwidth = $this->GetBandwidth();
3611
		if (is_array($bandwidth)) {
3612
			foreach ($bandwidth as $bw) {
3613
				if ($bw['bwsched'] != "none") {
3614
					$time_based_rules = true;
3615
					if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3616
						foreach ($config['schedules']['schedule'] as $schedule) {
3617
							if ($bw['bwsched'] == $schedule['name']) {
3618
								if (filter_get_time_based_rule_status($schedule)) {
3619
									$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3620
									if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3621
										$pfq_rule .= " burst ".trim($bw['burst']);
3622
									}
3623
									$found = true;
3624
									break;
3625
								}
3626
							}
3627
						}
3628
					} else {
3629
						$pfq_rule .= " bw 0";
3630
						$found = true;
3631
						break;
3632
					}
3633
				} else {
3634
					$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3635
					if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3636
						$pfq_rule .= " burst ".trim($bw['burst']);
3637
					}
3638
					$found = true;
3639
					break;
3640
				}
3641
			}
3642
			if ($found == false) {
3643
				$pfq_rule .= " bw 0";
3644
			}
3645
		} else {
3646
			$pfq_rule .= " bw 0";
3647
		}
3648

    
3649
		if ($this->GetQlimit()) {
3650
			$pfq_rule .= " queue " . $this->GetQlimit();
3651
		}
3652
		if ($this->GetPlr()) {
3653
			$pfq_rule .= " plr " . $this->GetPlr();
3654
		}
3655
		if ($this->GetBuckets()) {
3656
			$pfq_rule .= " buckets " . $this->GetBuckets();
3657
		}
3658
		if ($this->GetDelay()) {
3659
			$pfq_rule .= " delay " . $this->GetDelay();
3660
		}
3661
		$this->build_mask_rules($pfq_rule);
3662

    
3663
		$pfq_rule .= "\n";
3664

    
3665
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3666
			foreach ($this->subqueues as $q) {
3667
				$pfq_rule .= $q->build_rules();
3668
			}
3669
		}
3670
		$pfq_rule .= " \n";
3671

    
3672
		return $pfq_rule;
3673
	}
3674

    
3675
	function update_dn_data(&$data) {
3676
		$this->ReadConfig($data);
3677
	}
3678

    
3679
	function build_javascript() {
3680
		global $g, $config;
3681

    
3682
		$javasr = parent::build_javascript();
3683

    
3684
		//build list of schedules
3685
		$schedules = "<option value='none'>none</option>";
3686
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3687
			foreach ($config['schedules']['schedule'] as $schedule) {
3688
				if ($schedule['name'] <> "") {
3689
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3690
				}
3691
			}
3692
		}
3693
		$bwopt = "";
3694
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw) {
3695
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3696
		}
3697

    
3698
		$javasr .= <<<EOD
3699
<script type='text/javascript'>
3700
//<![CDATA[
3701
var addBwRowTo = (function() {
3702

    
3703
	return (function (tableId) {
3704

    
3705
	var table = document.getElementById(tableId);
3706
	var totalrows = table.rows.length -1;
3707

    
3708
	var row = table.insertRow(totalrows + 1);
3709
	var cell1 = row.insertCell(0);
3710
	var cell2 = row.insertCell(1);
3711
	var cell3 = row.insertCell(2);
3712
	var cell4 = row.insertCell(3);
3713

    
3714
	cell1.innerHTML = "<input type='hidden' value='" + totalrows +"' name='bandwidth_row-" + totalrows + "' /><input type='text' class='form-control' name='bandwidth" + totalrows + "' id='bandwidth" + totalrows + "' />";
3715
	cell2.innerHTML = "<input type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "' /><select class='form-control' name='bwtype" + totalrows + "'>{$bwopt}</select>";
3716
	cell3.innerHTML = "<input type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "' /><select class='form-control' name='bwsched" + totalrows + "'>{$schedules}</select>";
3717
	cell4.innerHTML = '<a class="btn btn-default" onclick="removeBwRow(this); return false;" href="#">Remove</a>';
3718

    
3719
	});
3720
})();
3721

    
3722
function removeBwRow(el) {
3723
	var d = el.parentNode.parentNode.rowIndex;
3724
	document.getElementById('maintable').deleteRow(d);
3725
}
3726
//]]>
3727
</script>
3728

    
3729
EOD;
3730

    
3731
		return $javasr;
3732
	}
3733

    
3734
	// Compose a table of bandwidths that can then be inserted into the form using a Form_StaticText
3735
	// The table has been "Bootstrapped" to match the web design while maintaining compatibility with
3736
	// with the javascript in this class
3737
	function build_bwtable() {
3738
		global $config;
3739

    
3740
		$bandwidth = $this->GetBandwidth();
3741
				//build list of schedules
3742
		$schedules = array();
3743
		$schedules[] = "none";//leave none to leave rule enabled all the time
3744
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3745
			foreach ($config['schedules']['schedule'] as $schedule) {
3746
				if ($schedule['name'] != "") {
3747
					$schedules[] = $schedule['name'];
3748
				}
3749
			}
3750
		}
3751

    
3752
		$form = '<div class="table-responsive">';
3753
		$form .= '<table id="maintable" class="table table-hover table-striped">';
3754
		$form .= "<thead><tr>";
3755
		$form .= "<th>Bandwidth</th>";
3756
		//$form .= "<td width='35%'><div id='fifthcolumn'>Burst</div></td>";
3757
		$form .= "<th>Bw type</th>";
3758
		$form .= "<th>Schedule</th>";
3759
		$form .= "<th></th>";
3760
		$form .= "</tr></thead>";
3761
		$form .= "<tbody>";
3762

    
3763
		// If there are no bandwidths defined, make a blank one for convenience
3764
		if (empty($bandwidth)) {
3765
			$bandwidth = array(0 => array('bw' => '', 'bwscale' => 'Kb', 'bwsched' => 'none'));
3766
		}
3767

    
3768
		if (is_array($bandwidth)) {
3769
			foreach ($bandwidth as $bwidx => $bw) {
3770
				$form .= '<tr>';
3771
				$form .= '<td class="col-xs-4">';
3772
				$form .= "<input class='form-control' type=\"number\" id=\"bandwidth{$bwidx}\" name=\"bandwidth{$bwidx}\" value=\"{$bw['bw']}\" />";
3773
				//$form .= "</td><td width='20%'>";
3774
				//$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"burst{$bwidx}\" name=\"burst{$bwidx}\" value=\"{$bw['burst']}\" />";
3775
				$form .= "</td>";
3776
				$form .= '<td class="col-xs-4">';
3777
				$form .= "<select id=\"bwtype{$bwidx}\" name=\"bwtype{$bwidx}\" class=\"form-control\">";
3778

    
3779
				foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwsidx => $bwscale) {
3780
					$form .= "<option value=\"{$bwsidx}\"";
3781

    
3782
					if ($bw['bwscale'] == $bwsidx) {
3783
						$form .= " selected";
3784
					}
3785

    
3786
					$form .= ">{$bwscale}</option>";
3787
				}
3788

    
3789
				$form .= "</select>";
3790
				$form .= "</td>";
3791
				$form .= '<td class="col-xs-4">';
3792
				$form .= "<select id=\"bwsched{$bwidx}\" name=\"bwsched{$bwidx}\" class=\"form-control\">";
3793

    
3794
				foreach ($schedules as $schd) {
3795
					$selected = "";
3796
					if ($bw['bwsched'] == $schd) {
3797
						$selected = "selected";
3798
					}
3799

    
3800
					$form .= "<option value='{$schd}' {$selected}>{$schd}</option>";
3801
				}
3802

    
3803
				$form .= "</select>";
3804
				$form .= "</td>";
3805
				$form .= '<td>';
3806
				$form .= '<a type="button" class="btn btn-default" onclick="removeBwRow(this); return false;">' . gettext('Remove') . '</a>';
3807
				$form .= "</td></tr>";
3808
			}
3809
		}
3810
		$form .= "</tbody></table></div><br />";
3811

    
3812
		$form .= '<a type="button" class="btn btn-sm btn-success" onclick="javascript:addBwRowTo(\'maintable\'); return false;" >';
3813
		$form .= gettext("Add another schedule") . "</a>";
3814

    
3815
		return($form);
3816
	}
3817

    
3818
	function build_form() {
3819
		global $g, $config, $pipe, $action, $qname;
3820

    
3821
		//build list of schedules
3822
		$schedules = array();
3823
		$schedules[] = "none";//leave none to leave rule enabled all the time
3824
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3825
			foreach ($config['schedules']['schedule'] as $schedule) {
3826
				if ($schedule['name'] <> "") {
3827
					$schedules[] = $schedule['name'];
3828
				}
3829
			}
3830
		}
3831

    
3832

    
3833
		$sform = new Form();
3834
		$sform->setAction("firewall_shaper.php");
3835

    
3836
		$section = new Form_Section('Limiters');
3837

    
3838
		$section->addInput(new Form_Checkbox(
3839
			'enabled',
3840
			'Enable',
3841
			'Enable limiter and its children',
3842
			($this->GetEnabled() == "on"),
3843
			'on'
3844
		));
3845

    
3846
		$section->addInput(new Form_Input(
3847
			'newname',
3848
			'Name',
3849
			'text',
3850
			$this->GetQname()
3851
		));
3852

    
3853
		$section->addInput(new Form_Input(
3854
			'name',
3855
			null,
3856
			'hidden',
3857
			$this->GetQname()
3858
		));
3859

    
3860
		if ($this->GetNumber() > 0) {
3861
			$section->addInput(new Form_Input(
3862
				'number',
3863
				null,
3864
				'hidden',
3865
				$this->GetNumber()
3866
			));
3867
		}
3868

    
3869
		$bandwidth = $this->GetBandwidth();
3870

    
3871
		// Delete a row
3872
//		if(isset($_GET['delbwrow']) && (count($bandwidth) > 0))
3873
//			unset($bandwidth[$_GET['delbwrow']]);
3874

    
3875
		// Add a row
3876
//		if($_GET['newbwrow']) {
3877
//			array_push($bandwidth, array(count($bandwidth) => array('bw' => '', 'burst' => '', 'bwscale' => 'Kb', 'bwsched' => 'none') ));
3878
//		}
3879

    
3880
		if (is_array($bandwidth)) {
3881
				$section->addInput(new Form_StaticText(
3882
				'Bandwidth',
3883
				$this->build_bwtable()
3884
			));
3885
		}
3886

    
3887
		$mask = $this->GetMask();
3888

    
3889
		$section->addInput(new Form_Select(
3890
			'mask',
3891
			'Mask',
3892
			$mask['type'],
3893
			array('none' => 'None', 'srcaddress' => 'Source addresses', 'dstaddress' => 'Destination addresses')
3894
		))->setHelp('If "source" or "destination" slots is chosen a dynamic pipe with the bandwidth, delay, packet loss ' .
3895
					'and queue size given above will be created for each source/destination IP address encountered, respectively. ' .
3896
					'This makes it possible to easily specify bandwidth limits per host.');
3897

    
3898
		$group = new Form_Group(null);
3899

    
3900
		$group->add(new Form_Select(
3901
			'maskbits',
3902
			null,
3903
			$mask['bits'],
3904
			array_combine(range(32, 1, -1), range(32, 1, -1))
3905
		))->setHelp('IPV4 mask bits' . '<br />' . '255.255.255.255/?');
3906

    
3907
		$group->add(new Form_Select(
3908
			'maskbitsv6',
3909
			null,
3910
			$mask['bitsv6'],
3911
			array_combine(range(128, 1, -1), range(128, 1, -1))
3912
		))->setHelp('IPV6 mask bits' . '<br />' . '<font face="consolas">ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/?</font>');
3913

    
3914
		$section->add($group);
3915

    
3916
		$section->addInput(new Form_Input(
3917
			'description',
3918
			'Description',
3919
			'text',
3920
			$this->GetDescription()
3921
		))->setHelp('You may enter a description here for your reference (not parsed).');
3922

    
3923
		$sform->add($section);
3924

    
3925
		$section = new Form_Section('Advanced options');
3926

    
3927
		$section->addInput(new Form_Input(
3928
			'delay',
3929
			'Delay (ms)',
3930
			'text',
3931
			$this->GetDelay() > 0 ? $this->GetDelay():null
3932
		))->setHelp('In most cases, you should specify 0 here (or leave the field empty)');
3933

    
3934
		$section->addInput(new Form_Input(
3935
			'plr',
3936
			'Packet Loss Rate',
3937
			'number',
3938
			$this->GetPlr(),
3939
			['step' => '0.001', 'min' => '0.000']
3940
		))->setHelp('In most cases, you should specify 0 here (or leave the field empty). ' .
3941
					'A value of 0.001 means one packet in 1000 gets dropped');
3942

    
3943
		$section->addInput(new Form_Input(
3944
			'qlimit',
3945
			'Queue size (slots)',
3946
			'number',
3947
			$this->GetQlimit()
3948
		))->setHelp('In most cases, you should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, ' .
3949
					'then they are delayed by value specified in the Delay field, and then they are delivered to their destination.');
3950

    
3951
		$section->addInput(new Form_Input(
3952
			'buckets',
3953
			'Bucket size (slots)',
3954
			'number',
3955
			$this->GetBuckets()
3956
		))->setHelp('In most cases, you should leave this field empty. It increases the hash size set');
3957

    
3958
		$sform->add($section);
3959

    
3960
		return($sform);
3961
		}
3962

    
3963
	function wconfig() {
3964
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3965
		if (!is_array($cflink)) {
3966
			$cflink = array();
3967
		}
3968
		$cflink['name'] = $this->GetQname();
3969
		$cflink['number'] = $this->GetNumber();
3970
		$cflink['qlimit'] = $this->GetQlimit();
3971
		$cflink['plr'] = $this->GetPlr();
3972
		$cflink['description'] = $this->GetDescription();
3973

    
3974
		$bandwidth = $this->GetBandwidth();
3975
		if (is_array($bandwidth)) {
3976
			$cflink['bandwidth'] = array();
3977
			$cflink['bandwidth']['item'] = array();
3978
			foreach ($bandwidth as $bwidx => $bw) {
3979
				$cflink['bandwidth']['item'][] = $bw;
3980
			}
3981
		}
3982

    
3983
		$cflink['enabled'] = $this->GetEnabled();
3984
		$cflink['buckets'] = $this->GetBuckets();
3985
		$mask = $this->GetMask();
3986
		$cflink['mask'] = $mask['type'];
3987
		$cflink['maskbits'] = $mask['bits'];
3988
		$cflink['maskbitsv6'] = $mask['bitsv6'];
3989
		$cflink['delay'] = $this->GetDelay();
3990
	}
3991

    
3992
}
3993

    
3994
class dnqueue_class extends dummynet_class {
3995
	var $pipeparent;
3996
	var $weight;
3997

    
3998
	function GetWeight() {
3999
		return $this->weight;
4000
	}
4001
	function SetWeight($weight) {
4002
		$this->weight = $weight;
4003
	}
4004
	function GetPipe() {
4005
		return $this->pipeparent;
4006
	}
4007
	function SetPipe($pipe) {
4008
		$this->pipeparent = $pipe;
4009
	}
4010

    
4011
	/* Just a stub in case we ever try to call this from the frontend. */
4012
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
4013
		return;
4014
	}
4015

    
4016
	function delete_queue() {
4017
		cleanup_dnqueue_from_rules($this->GetQname());
4018
		unset_dn_object_by_reference($this->GetLink());
4019
		@pfSense_pipe_action("queue delete " . $this->GetNumber());
4020
	}
4021

    
4022
	function validate_input($data, &$input_errors) {
4023
		parent::validate_input($data, $input_errors);
4024

    
4025
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
4026
		    ($data['weight'] < 1 && $data['weight'] > 100))) {
4027
			$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
4028
		}
4029
	}
4030

    
4031
	/*
4032
	 * Should search even its children
4033
	 */
4034
	function &find_queue($pipe, $qname) {
4035
		if ($qname == $this->GetQname()) {
4036
			return $this;
4037
		} else {
4038
			return NULL;
4039
		}
4040
	}
4041

    
4042
	function &find_parentqueue($pipe, $qname) {
4043
		return $this->qparent;
4044
	}
4045

    
4046
	function &get_queue_list(&$qlist) {
4047
		if ($this->GetEnabled() == "") {
4048
			return;
4049
		}
4050
		$qlist[$this->GetQname()] = "?" .$this->GetNumber();
4051
	}
4052

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

    
4106
	function build_tree() {
4107
		$parent =& $this->GetParent();
4108
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">";
4109
		$tree .= $this->GetQname() . "</a>";
4110
		$tree .= "</li>";
4111

    
4112
		return $tree;
4113
	}
4114

    
4115
	function build_rules() {
4116
		if ($this->GetEnabled() == "") {
4117
			return;
4118
		}
4119

    
4120
		$parent =& $this->GetParent();
4121
		$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
4122
		if ($this->GetQlimit()) {
4123
			$pfq_rule .= " queue " . $this->GetQlimit();
4124
		}
4125
		if ($this->GetWeight()) {
4126
			$pfq_rule .= " weight " . $this->GetWeight();
4127
		}
4128
		if ($this->GetBuckets()) {
4129
			$pfq_rule .= " buckets " . $this->GetBuckets();
4130
		}
4131
		$this->build_mask_rules($pfq_rule);
4132
		$pfq_rule .= "\n";
4133

    
4134
		return $pfq_rule;
4135
	}
4136

    
4137
	function build_javascript() {
4138
		return parent::build_javascript();
4139
	}
4140

    
4141
	function build_form() {
4142
		global $g, $config, $pipe, $action, $qname;
4143

    
4144
		//build list of schedules
4145
		$schedules = array();
4146
		$schedules[] = "none";//leave none to leave rule enabled all the time
4147
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
4148
			foreach ($config['schedules']['schedule'] as $schedule) {
4149
				if ($schedule['name'] <> "") {
4150
					$schedules[] = $schedule['name'];
4151
				}
4152
			}
4153
		}
4154

    
4155

    
4156
		$sform = new Form();
4157
		$sform->setAction("firewall_shaper.php");
4158
		$section = new Form_Section('Limiters');
4159

    
4160
		$section->addInput(new Form_Checkbox(
4161
			'enabled',
4162
			'Enable',
4163
			'Enable this queue',
4164
			($this->GetEnabled() == "on"),
4165
			'on'
4166
		));
4167

    
4168
		$section->addInput(new Form_Input(
4169
			'newname',
4170
			'Name',
4171
			'text',
4172
			$this->GetQname()
4173
		));
4174

    
4175
		$section->addInput(new Form_Input(
4176
			'name',
4177
			null,
4178
			'hidden',
4179
			$this->GetQname()
4180
		));
4181

    
4182
		if ($this->GetNumber() > 0) {
4183
			$section->addInput(new Form_Input(
4184
				'number',
4185
				null,
4186
				'hidden',
4187
				$this->GetNumber()
4188
			));
4189
		}
4190

    
4191
		$mask = $this->GetMask();
4192

    
4193
		$section->addInput(new Form_Select(
4194
			'mask',
4195
			'Mask',
4196
			$mask['type'],
4197
			array('none' => 'None', 'srcaddress' => 'Source addresses', 'dstaddress' => 'Destination addresses')
4198
		))->setHelp('If "source" or "destination" slots is chosen a dynamic pipe with the bandwidth, delay, packet loss ' .
4199
					'and queue size given above will be created for each source/destination IP address encountered, respectively. ' .
4200
					'This makes it possible to easily specify bandwidth limits per host.');
4201

    
4202
		$group = new Form_Group(null);
4203

    
4204
		$group->add(new Form_Select(
4205
			'maskbits',
4206
			null,
4207
			$mask['bits'],
4208
			array_combine(range(32, 1, -1), range(32, 1, -1))
4209
		))->setHelp('IPV4 mask bits' . '<br />' . '255.255.255.255/?');
4210

    
4211
		$group->add(new Form_Select(
4212
			'maskbitsv6',
4213
			null,
4214
			$mask['bitsv6'],
4215
			array_combine(range(128, 1, -1), range(128, 1, -1))
4216
		))->setHelp('IPV6 mask bits' . '<br />' . '<font face="consolas">ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/?</font>');
4217

    
4218
		$section->add($group);
4219

    
4220
		$section->addInput(new Form_Input(
4221
			'description',
4222
			'Description',
4223
			'text',
4224
			$this->GetDescription()
4225
		))->setHelp('You may enter a description here for your reference (not parsed).');
4226

    
4227
		$sform->add($section);
4228

    
4229
		$section = new Form_Section('Advanced options');
4230

    
4231
		$section->addInput(new Form_Input(
4232
			'weight',
4233
			'Weight',
4234
			'number',
4235
			$this->GetWeight(),
4236
			['min' => '1', 'max' => '100']
4237
		))->setHelp('For queues under the same parent this specifies the share that a queue gets(values range from 1 to 100),' .
4238
					' you can leave it blank otherwise');
4239

    
4240
		$section->addInput(new Form_Input(
4241
			'plr',
4242
			'Packet Loss Rate',
4243
			'number',
4244
			$this->GetPlr(),
4245
			['step' => '0.001', 'min' => '0.000']
4246
		))->setHelp('In most cases, you should specify 0 here (or leave the field empty). ' .
4247
					'A value of 0.001 means one packet in 1000 gets dropped');
4248

    
4249
		$section->addInput(new Form_Input(
4250
			'qlimit',
4251
			'Queue size (slots)',
4252
			'number',
4253
			$this->GetQlimit()
4254
		))->setHelp('In most cases, you should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, ' .
4255
					'then they are delayed by value specified in the Delay field, and then they are delivered to their destination.');
4256

    
4257
		$section->addInput(new Form_Input(
4258
			'buckets',
4259
			'Bucket size (slots)',
4260
			'number',
4261
			$this->GetBuckets()
4262
		))->setHelp('In most cases, you should leave this field empty. It increases the hash size set');
4263

    
4264
		$section->addInput(new Form_Input(
4265
			'pipe',
4266
			null,
4267
			'hidden',
4268
			$this->GetPipe()
4269
		));
4270

    
4271
		$sform->add($section);
4272

    
4273
		return($sform);
4274
	}
4275

    
4276
	function update_dn_data(&$data) {
4277
		$this->ReadConfig($data);
4278
	}
4279

    
4280
	function wconfig() {
4281
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
4282
		if (!is_array($cflink)) {
4283
			$cflink = array();
4284
		}
4285
		$cflink['name'] = $this->GetQname();
4286
		$cflink['number'] = $this->GetNumber();
4287
		$cflink['qlimit'] = $this->GetQlimit();
4288
		$cflink['description'] = $this->GetDescription();
4289
		$cflink['weight'] = $this->GetWeight();
4290
		$cflink['enabled'] = $this->GetEnabled();
4291
		$cflink['buckets'] = $this->GetBuckets();
4292
		$mask = $this->GetMask();
4293
		$cflink['mask'] = $mask['type'];
4294
		$cflink['maskbits'] = $mask['bits'];
4295
		$cflink['maskbitsv6'] = $mask['bitsv6'];
4296
	}
4297
}
4298

    
4299
function get_dummynet_name_list() {
4300

    
4301
	$dn_name_list =& get_unique_dnqueue_list();
4302
	$dn_name = array();
4303
	if (is_array($dn_name_list)) {
4304
		foreach ($dn_name_list as $key => $value) {
4305
			$dn_name[] = $key;
4306
		}
4307
	}
4308

    
4309
	return $dn_name;
4310

    
4311
}
4312

    
4313
function get_altq_name_list() {
4314
	$altq_name_list =& get_unique_queue_list();
4315
	$altq_name = array();
4316
	if (is_array($altq_name_list)) {
4317
		foreach ($altq_name_list as $key => $aqobj) {
4318
			$altq_name[] = $key;
4319
		}
4320
	}
4321

    
4322
	return $altq_name;
4323
}
4324

    
4325
/*
4326
 * XXX: TODO Make a class shaper to hide all these functions
4327
 * from the global namespace.
4328
 */
4329

    
4330
/*
4331
 * This is a layer violation but for now there is no way
4332
 * I can find to properly do this with PHP.
4333
 */
4334
function altq_get_default_queue($interface) {
4335
	global $altq_list_queues;
4336

    
4337
	$altq_tmp = $altq_list_queues[$interface];
4338
	if ($altq_tmp) {
4339
		return $altq_tmp->GetDefaultQueuePresent();
4340
	} else {
4341
		return false;
4342
	}
4343
}
4344

    
4345
function altq_check_default_queues() {
4346
	global $altq_list_queues;
4347

    
4348
	$count = 0;
4349
	if (is_array($altq_list_queues)) {
4350
		foreach ($altq_list_queues as $altq) {
4351
			if ($altq->GetDefaultQueuePresent()) {
4352
				$count++;
4353
			}
4354
		}
4355
	}
4356
	else {
4357
		$count++;
4358
	}
4359

    
4360
	return 0;
4361
}
4362

    
4363
function &get_unique_queue_list() {
4364
	global $altq_list_queues;
4365

    
4366
	$qlist = array();
4367
	if (is_array($altq_list_queues)) {
4368
		foreach ($altq_list_queues as $altq) {
4369
			if ($altq->GetEnabled() == "") {
4370
				continue;
4371
			}
4372
			$tmplist =& $altq->get_queue_list();
4373
			foreach ($tmplist as $qname => $link) {
4374
				if ($link->GetEnabled() <> "") {
4375
					$qlist[$qname] = $link;
4376
				}
4377
			}
4378
		}
4379
	}
4380
	return $qlist;
4381
}
4382

    
4383
function &get_unique_dnqueue_list() {
4384
	global $dummynet_pipe_list;
4385

    
4386
	$qlist = array();
4387
	if (is_array($dummynet_pipe_list)) {
4388
		foreach ($dummynet_pipe_list as $dn) {
4389
			if ($dn->GetEnabled() == "") {
4390
				continue;
4391
			}
4392
			$tmplist =& $dn->get_queue_list();
4393
			foreach ($tmplist as $qname => $link) {
4394
				$qlist[$qname] = $link;
4395
			}
4396
		}
4397
	}
4398
	return $qlist;
4399
}
4400

    
4401
function ref_on_altq_queue_list($parent, $qname) {
4402
	if (isset($GLOBALS['queue_list'][$qname])) {
4403
		$GLOBALS['queue_list'][$qname]++;
4404
	} else {
4405
		$GLOBALS['queue_list'][$qname] = 1;
4406
	}
4407

    
4408
	unref_on_altq_queue_list($parent);
4409
}
4410

    
4411
function unref_on_altq_queue_list($qname) {
4412
	$GLOBALS['queue_list'][$qname]--;
4413
	if ($GLOBALS['queue_list'][$qname] <= 1) {
4414
		unset($GLOBALS['queue_list'][$qname]);
4415
	}
4416
}
4417

    
4418
function read_altq_config() {
4419
	global $altq_list_queues, $config;
4420
	$path = array();
4421

    
4422
	if (!is_array($config['shaper'])) {
4423
		$config['shaper'] = array();
4424
	}
4425
	if (!is_array($config['shaper']['queue'])) {
4426
		$config['shaper']['queue'] = array();
4427
	}
4428
	$a_int = &$config['shaper']['queue'];
4429

    
4430
	$altq_list_queues = array();
4431

    
4432
	if (!is_array($config['shaper']['queue'])) {
4433
		return;
4434
	}
4435

    
4436
	foreach ($a_int as $key => $conf) {
4437
		$int = $conf['interface'];
4438
		$root =& new altq_root_queue();
4439
		$root->SetInterface($int);
4440
		$altq_list_queues[$root->GetInterface()] = &$root;
4441
		$root->ReadConfig($conf);
4442
		array_push($path, $key);
4443
		$root->SetLink($path);
4444
		if (is_array($conf['queue'])) {
4445
			foreach ($conf['queue'] as $key1 => $q) {
4446
				array_push($path, $key1);
4447
				/*
4448
				 * XXX: we completely ignore errors here but anyway we must have
4449
				 *	checked them before so no harm should be come from this.
4450
				 */
4451
				$root->add_queue($root->GetInterface(), $q, $path, $input_errors);
4452
				array_pop($path);
4453
			}
4454
		}
4455
		array_pop($path);
4456
	}
4457
}
4458

    
4459
function read_dummynet_config() {
4460
	global $dummynet_pipe_list, $config;
4461
	$path = array();
4462

    
4463
	if (!is_array($config['dnshaper'])) {
4464
		$config['dnshaper'] = array();
4465
	}
4466
	if (!is_array($config['dnshaper']['queue'])) {
4467
		$config['dnshaper']['queue'] = array();
4468
	}
4469
	$a_int = &$config['dnshaper']['queue'];
4470

    
4471
	$dummynet_pipe_list = array();
4472

    
4473
	if (!is_array($config['dnshaper']['queue']) ||
4474
	    !count($config['dnshaper']['queue'])) {
4475
		return;
4476
	}
4477

    
4478
	foreach ($a_int as $key => $conf) {
4479
		if (empty($conf['name'])) {
4480
			continue; /* XXX: grrrrrr at php */
4481
		}
4482
		$root =& new dnpipe_class();
4483
		$root->ReadConfig($conf);
4484
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4485
		array_push($path, $key);
4486
		$root->SetLink($path);
4487
		if (is_array($conf['queue'])) {
4488
			foreach ($conf['queue'] as $key1 => $q) {
4489
				array_push($path, $key1);
4490
				/*
4491
				 * XXX: we completely ignore errors here but anyway we must have
4492
				 *	checked them before so no harm should be come from this.
4493
				 */
4494
				$root->add_queue($root->GetQname(), $q, $path, $input_errors);
4495
				array_pop($path);
4496
			}
4497
		}
4498
		array_pop($path);
4499
	}
4500
}
4501

    
4502
function get_interface_list_to_show() {
4503
	global $altq_list_queues, $config;
4504
	global $shaperIFlist;
4505

    
4506
	$tree = "";
4507
	foreach ($shaperIFlist as $shif => $shDescr) {
4508
		if ($altq_list_queues[$shif]) {
4509
			continue;
4510
		} else {
4511
			if (!is_altq_capable(get_real_interface($shif))) {
4512
				continue;
4513
			}
4514
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4515
		}
4516
	}
4517

    
4518
	return $tree;
4519
}
4520

    
4521
function filter_generate_altq_queues() {
4522
	global $altq_list_queues;
4523

    
4524
	read_altq_config();
4525

    
4526
	$altq_rules = "";
4527
	foreach ($altq_list_queues as $altq) {
4528
		$altq_rules .= $altq->build_rules();
4529
	}
4530

    
4531
	return $altq_rules;
4532
}
4533

    
4534
function dnqueue_find_nextnumber() {
4535
	global $dummynet_pipe_list;
4536

    
4537
	$dnused = array();
4538
	if (is_array($dummynet_pipe_list)) {
4539
		foreach ($dummynet_pipe_list as $dn) {
4540
			$tmplist =& $dn->get_queue_list();
4541
			foreach ($tmplist as $qname => $link) {
4542
				if ($link[0] == "?") {
4543
					$dnused[$qname] = substr($link, 1);
4544
				}
4545
			}
4546
		}
4547
	}
4548

    
4549
	sort($dnused, SORT_NUMERIC);
4550
	$dnnumber = 0;
4551
	$found = false;
4552
	foreach ($dnused as $dnnum) {
4553
		if (($dnnum - $dnnumber) > 1) {
4554
			$dnnumber = $dnnum - 1;
4555
			$found = true;
4556
			break;
4557
		} else {
4558
			$dnnumber = $dnnum;
4559
		}
4560
	}
4561

    
4562
	if ($found == false) {
4563
		$dnnumber++;
4564
	}
4565

    
4566
	unset($dnused, $dnnum, $found);
4567
	return $dnnumber;
4568
}
4569

    
4570
function dnpipe_find_nextnumber() {
4571
	global $dummynet_pipe_list;
4572

    
4573
	$dnused = array();
4574
	foreach ($dummynet_pipe_list as $dn) {
4575
		$dnused[] = $dn->GetNumber();
4576
	}
4577

    
4578
	sort($dnused, SORT_NUMERIC);
4579
	$dnnumber = 0;
4580
	$found = false;
4581
	foreach ($dnused as $dnnum) {
4582
		if (($dnnum - $dnnumber) > 1) {
4583
			$dnnumber = $dnnum - 1;
4584
			$found = true;
4585
			break;
4586
		} else {
4587
			$dnnumber = $dnnum;
4588
		}
4589
	}
4590

    
4591
	if ($found == false) {
4592
		$dnnumber++;
4593
	}
4594

    
4595
	unset($dnused, $dnnum, $found);
4596
	return $dnnumber;
4597
}
4598

    
4599
function filter_generate_dummynet_rules() {
4600
	global $g, $dummynet_pipe_list;
4601

    
4602
	read_dummynet_config();
4603

    
4604
	$dn_rules = "";
4605
	foreach ($dummynet_pipe_list as $dn) {
4606
		$dn_rules .= $dn->build_rules();
4607
	}
4608

    
4609
	if (!empty($dn_rules)) {
4610
		if (!is_module_loaded("dummynet.ko")) {
4611
			mwexec("/sbin/kldload dummynet");
4612
			set_sysctl(array(
4613
				"net.inet.ip.dummynet.io_fast" => "1",
4614
				"net.inet.ip.dummynet.hash_size" => "256"
4615
			));
4616
		}
4617
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4618
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4619
	}
4620
}
4621

    
4622
function build_iface_without_this_queue($iface, $qname) {
4623
	global $g, $altq_list_queues;
4624
	global $shaperIFlist;
4625

    
4626
	$altq =& $altq_list_queues[$iface];
4627

    
4628
	if ($altq) {
4629
		$scheduler = $altq->GetScheduler();
4630
	}
4631

    
4632
	$form = '<dl class="dl-horizontal">';
4633

    
4634
	$form .= '	<dt>';
4635
	$form .= '		<a href="firewall_shaper.php?interface=' . $iface . '&amp;queue=' . $iface . '&amp;action=show">' . $shaperIFlist[$iface] . '</a>';
4636
	$form .= '	</dt>';
4637
	$form .= '	<dd>';
4638
	$form .=		$scheduler;
4639
	$form .= '	</dd>';
4640

    
4641
	$form .= '	<dt>';
4642
	$form .= 'Clone';
4643
	$form .= '	</dt>';
4644
	$form .= '	<dd>';
4645
	$form .= '<a class="btn btn-info btn-xs" href="firewall_shaper_queues.php?interface=';
4646
	$form .= $iface . '&amp;queue=';
4647
	$form .= $qname . '&amp;action=add">';
4648
	$form .= gettext("Clone shaper on the I/F") . '</a>';
4649
	$form .= '	</dd>';
4650

    
4651
	$form .= '</dl>';
4652

    
4653
	return $form;
4654

    
4655
}
4656

    
4657
$default_shaper_msg = sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "<br />";
4658
$default_shaper_msg .= gettext("The tree on the left helps you navigate through the queues.<br />"
4659
	. "Buttons at the bottom represent queue actions and are activated accordingly.");
4660

    
4661
$dn_default_shaper_msg = $default_shaper_msg;
4662

    
4663
?>
(50-50/65)