Project

General

Profile

Download (144 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	shaper.inc
4
	Copyright (C) 2008 Ermal Luçi
5
	All rights reserved.
6

    
7
	Redistribution and use in source and binary forms, with or without
8
	modification, are permitted provided that the following conditions are met:
9

    
10
	1. Redistributions of source code must retain the above copyright notice,
11
	   this list of conditions and the following disclaimer.
12

    
13
	2. Redistributions in binary form must reproduce the above copyright
14
	   notice, this list of conditions and the following disclaimer in the
15
	   documentation and/or other materials provided with the distribution.
16

    
17
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
	POSSIBILITY OF SUCH DAMAGE.
27

    
28
	pfSense_BUILDER_BINARIES:	/bin/kill	/sbin/kldload	/bin/rm	/bin/ps
29
	pfSense_MODULE:	shaper
30
*/
31

    
32
/* XXX: needs some reducing on include. */
33
/* include all configuration functions. */
34
require_once("globals.inc");
35
require_once("functions.inc");
36
require_once("util.inc");
37
require_once("notices.inc");
38

    
39
/*
40
 * I admit :) this is derived from xmlparse.inc StartElement()
41
 */
42
function &get_reference_to_me_in_config(&$mypath) {
43
	global $config;
44

    
45
	$ptr =& $config['shaper'];
46
	foreach ($mypath as $indeks) {
47
		$ptr =& $ptr['queue'][$indeks];
48
	}
49

    
50
	return $ptr;
51
}
52

    
53
function unset_object_by_reference(&$mypath) {
54
	global $config;
55

    
56
	$ptr =& $config['shaper'];
57
	for ($i = 0; $i < count($mypath) - 1; $i++) {
58
		$ptr =& $ptr['queue'][$mypath[$i]];
59
	}
60
	unset($ptr['queue'][$mypath[$i]]);
61
}
62

    
63
function &get_dn_reference_to_me_in_config(&$mypath) {
64
	global $config;
65

    
66
	$ptr =& $config['dnshaper'];
67
	foreach ($mypath as $indeks) {
68
		$ptr =& $ptr['queue'][$indeks];
69
	}
70

    
71
	return $ptr;
72
}
73

    
74
function unset_dn_object_by_reference(&$mypath) {
75
	global $config;
76

    
77
	$ptr =& $config['dnshaper'];
78
	for ($i = 0; $i < count($mypath) - 1; $i++) {
79
		$ptr =& $ptr['queue'][$mypath[$i]];
80
	}
81
	unset($ptr['queue'][$mypath[$i]]);
82
}
83

    
84
function clean_child_queues($type, $mypath) {
85
	$ref = &get_reference_to_me_in_config($mypath);
86

    
87
	switch ($type) {
88
		case 'HFSC':
89
			if (isset($ref['borrow'])) {
90
				unset($ref['borrow']);
91
			}
92
			if (isset($ref['hogs'])) {
93
				unset($ref['hogs']);
94
			}
95
			if (isset($ref['buckets'])) {
96
				unset($ref['buckets']);
97
			}
98
			break;
99
		case 'PRIQ':
100
			if (isset($ref['borrow'])) {
101
				unset($ref['borrow']);
102
			}
103
			if (isset($ref['bandwidth'])) {
104
				unset($ref['bandwidth']);
105
			}
106
			if (isset($ref['bandwidthtype'])) {
107
				unset($ref['bandwidthtype']);
108
			}
109
			/* fall through */
110
		case 'FAIRQ':
111
			if (isset($ref['borrow'])) {
112
				unset($ref['borrow']);
113
			}
114
			/* fall through */
115
		case 'CBQ':
116
			if (isset($ref['realtime'])) {
117
				unset($ref['realtime']);
118
			}
119
			if (isset($ref['realtime1'])) {
120
				unset($ref['realtime1']);
121
			}
122
			if (isset($ref['realtime2'])) {
123
				unset($ref['realtime2']);
124
			}
125
			if (isset($ref['realtime3'])) {
126
				unset($ref['realtime3']);
127
			}
128
			if (isset($ref['upperlimit'])) {
129
				unset($ref['upperlimit']);
130
			}
131
			if (isset($ref['upperlimit1'])) {
132
				unset($ref['upperlimit1']);
133
			}
134
			if (isset($ref['upperlimit2'])) {
135
				unset($ref['upperlimit2']);
136
			}
137
			if (isset($ref['upperlimit3'])) {
138
				unset($ref['upperlimit3']);
139
			}
140
			if (isset($ref['linkshare'])) {
141
				unset($ref['linkshare']);
142
			}
143
			if (isset($ref['linkshare1'])) {
144
				unset($ref['linkshare1']);
145
			}
146
			if (isset($ref['linkshare2'])) {
147
				unset($ref['linkshare2']);
148
			}
149
			if (isset($ref['linkshare3'])) {
150
				unset($ref['linkshare3']);
151
			}
152
			if (isset($ref['hogs'])) {
153
				unset($ref['hogs']);
154
			}
155
			if (isset($ref['buckets'])) {
156
				unset($ref['buckets']);
157
			}
158
			break;
159
	}
160
}
161

    
162
function get_bandwidthtype_scale($type) {
163
	switch ($type) {
164
		case "Gb":
165
			$factor = 1024 * 1024 * 1024;
166
			break;
167
		case "Mb":
168
			$factor = 1024 * 1024;
169
			break;
170
		case "Kb":
171
			$factor = 1024;
172
			break;
173
		case "b":
174
		default:
175
			$factor = 1;
176
			break;
177
	}
178
	return intval($factor);
179
}
180

    
181
function get_hfsc_bandwidth($object, $bw) {
182
	$pattern= "/[0-9]+/";
183
	if (preg_match($pattern, $bw, $match)) {
184
		$bw_1 = $match[1];
185
	} else {
186
		return 0;
187
	}
188
	$pattern= "/(b|Kb|Mb|Gb|%)/";
189
	if (preg_match($pattern, $bw, $match)) {
190
		switch ($match[1]) {
191
			case '%':
192
				$bw_1 = $bw_1 / 100 * get_interface_bandwidth($object);
193
				break;
194
			default:
195
				$bw_1 = $bw_1 * get_bandwidthtype_scale($match[0]);
196
				break;
197
		}
198
		return floatval($bw_1);
199
	} else {
200
		return 0;
201
	}
202
}
203

    
204
function get_interface_bandwidth($object) {
205
	global $altq_list_queues;
206

    
207
	$int = $object->GetInterface();
208
	$altq =& $altq_list_queues[$int];
209
	if ($altq) {
210
		$bw_3 = $altq->GetBandwidth();
211
		$bw_3 = $bw_3 *  get_bandwidthtype_scale($altq->GetBwscale());
212
		return floatval($bw_3);
213
	} else {
214
		return 0;
215
	}
216
}
217

    
218
/*
219
 * This is duplicated here since we cannot include guiconfig.inc.
220
 * Including it makes all stuff break.
221
 */
222
function shaper_do_input_validation($postdata, $reqdfields, $reqdfieldsn, $input_errors) {
223

    
224
	/* check for bad control characters */
225
	foreach ($postdata as $pn => $pd) {
226
		if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
227
			$input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $pn);
228
		}
229
	}
230

    
231
	for ($i = 0; $i < count($reqdfields); $i++) {
232
		if ($postdata[$reqdfields[$i]] == "") {
233
			$input_errors[] = sprintf(gettext("The field '%s' is required."), $reqdfieldsn[$i]);
234
		}
235
	}
236
}
237

    
238
function cleanup_queue_from_rules($queue) {
239
	global $config;
240

    
241
	foreach ($config['filter']['rule'] as $rule) {
242
		if ($rule['defaultqueue'] == $queue) {
243
			unset($rule['defaultqueue']);
244
		}
245
		if ($rule['ackqueue'] == $queue) {
246
			unset($rule['ackqueue']);
247
		}
248
	}
249
}
250

    
251
function cleanup_dnqueue_from_rules($queue) {
252
	global $config;
253

    
254
	foreach ($config['filter']['rule'] as $rule) {
255
		if ($rule['dnpipe'] == $queue) {
256
			unset($rule['dnpipe']);
257
		}
258
		if ($rule['pdnpipe'] == $queue) {
259
			unset($rule['pdnpipe']);
260
		}
261
	}
262
}
263

    
264
class altq_root_queue {
265
	var $interface;
266
	var $tbrconfig ;
267
	var $bandwidth;
268
	var $bandwidthtype; /* b, Kb, Mb */
269
	var $scheduler;
270
	var $qlimit;
271
	var $queues = array();
272
	var $qenabled = false;
273
	var $link;
274
	var $available_bw; /* in b/s */
275

    
276
	/* Accesor functions */
277
	function GetAvailableBandwidth() {
278
		return $this->available_bw;
279
	}
280
	function SetAvailableBandwidth($bw) {
281
		$this->available_bw = $bw;
282
	}
283
	function GetDefaultQueuePresent() {
284
		if (!empty($this->queues)) {
285
			foreach ($this->queues as $q) {
286
				if ($q->GetDefault()) {
287
					return true;
288
				}
289
			}
290
		}
291

    
292
		return false;
293
	}
294
	function SetLink($link) {
295
		$this->link = $link;
296
	}
297
	function GetLink() {
298
		return $this->link;
299
	}
300
	function GetEnabled() {
301
		return $this->qenabled;
302
	}
303
	function SetEnabled($value) {
304
		$this->qenabled = $value;
305
	}
306
	function CanHaveChildren() {
307
		if ($this->GetScheduler() == "CODELQ") {
308
			return false;
309
		} else {
310
			return true;
311
		}
312
	}
313
	function CanBeDeleted() {
314
		return false;
315
	}
316
	function GetQname() {
317
		return $this->interface;
318
	}
319
	function SetQname($name) {
320
		$this->interface = trim($name);
321
	}
322
	function GetInterface() {
323
		return $this->interface;
324
	}
325
	function SetInterface($name) {
326
		$this->interface = trim($name);
327
	}
328
	function GetTbrConfig() {
329
		return $this->tbrconfig;
330
	}
331
	function SetTbrConfig($tbrconfig) {
332
		$this->tbrconfig = $tbrconfig;
333
	}
334
	function GetBandwidth() {
335
		return $this->bandwidth;
336
	}
337
	function SetBandwidth($bw) {
338
		$this->bandwidth = $bw;
339
	}
340
	function GetBwscale() {
341
		return $this->bandwidthtype;
342
	}
343
	function SetBwscale($bwscale) {
344
		$this->bandwidthtype = $bwscale;
345
	}
346
	function GetScheduler() {
347
		return $this->scheduler;
348
	}
349
	function SetScheduler($scheduler) {
350
		$this->scheduler = trim($scheduler);
351
	}
352
	function GetQlimit() {
353
		return $this->qlimit;
354
	}
355
	function SetQlimit($limit) {
356
		$this->qlimit = $limit;
357
	}
358

    
359
	function validate_input($data, &$input_errors) {
360

    
361
		$reqdfields[] = "bandwidth";
362
		$reqdfieldsn[] = gettext("Bandwidth");
363
		$reqdfields[] = "bandwidthtype";
364
		$reqdfieldsn[] = gettext("Bandwidthtype");
365

    
366
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
367

    
368
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
369
			$input_errors[] = gettext("Bandwidth must be an integer.");
370
		}
371
		if ($data['bandwidth'] < 0) {
372
			$input_errors[] = gettext("Bandwidth cannot be negative.");
373
		}
374
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
375
			$input_errors[] = gettext("Qlimit must be an integer.");
376
		}
377
		if ($data['qlimit'] < 0) {
378
			$input_errors[] = gettext("Qlimit must be positive.");
379
		}
380
		if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig']))) {
381
			$input_errors[] = gettext("Tbrsize must be an integer.");
382
		}
383
		if ($data['tbrconfig'] < 0) {
384
			$input_errors[] = gettext("Tbrsize must be positive.");
385
		}
386
	}
387

    
388
	/* Implement this to shorten some code on the frontend page */
389
	function ReadConfig(&$conf) {
390
		if (isset($conf['tbrconfig'])) {
391
			$this->SetTbrConfig($conf['tbrconfig']);
392
		} else {
393
			$this->SetTbrConfig($conf['tbrconfig']);
394
		}
395
		$this->SetBandwidth($conf['bandwidth']);
396
		if ($conf['bandwidthtype'] <> "") {
397
			$this->SetBwscale($conf['bandwidthtype']);
398
		}
399
		if (isset($conf['scheduler'])) {
400
			if ($this->GetScheduler() != $conf['scheduler']) {
401
				foreach ($this->queues as $q) {
402
					clean_child_queues($conf['scheduler'], $this->GetLink());
403
					$q->clean_queue($conf['scheduler']);
404
				}
405
			}
406
			$this->SetScheduler($conf['scheduler']);
407
		}
408
		if (isset($conf['qlimit']) && $conf['qlimit'] <> "") {
409
			$this->SetQlimit($conf['qlimit']);
410
		} else {
411
			$this->SetQlimit("");
412
		}
413
		if (isset($conf['name'])) {
414
			$this->SetQname($conf['name']);
415
		}
416
		if (!empty($conf['enabled'])) {
417
			$this->SetEnabled($conf['enabled']);
418
		} else {
419
			$this->SetEnabled("");
420
		}
421
	}
422

    
423
	function copy_queue($interface, &$cflink) {
424
		$cflink['interface'] = $interface;
425
		$cflink['name'] = $interface;
426
		$cflink['scheduler'] = $this->GetScheduler();
427
		$cflink['bandwidth'] = $this->GetBandwidth();
428
		$cflink['bandwidthtype'] = $this->GetBwscale();
429
		$cflink['qlimit'] = $this->GetQlimit();
430
		$cflink['tbrconfig'] = $this->GetTbrConfig();
431
		$cflink['enabled'] = $this->GetEnabled();
432
		if (is_array($this->queues)) {
433
			$cflink['queue'] = array();
434
			foreach ($this->queues as $q) {
435
				$cflink['queue'][$q->GetQname()] = array();
436
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
437
			}
438
		}
439
	}
440

    
441
	function &get_queue_list(&$q = null) {
442
		$qlist = array();
443

    
444
		//$qlist[$this->GetQname()] = & $this;
445
		if (is_array($this->queues)) {
446
			foreach ($this->queues as $queue) {
447
				$queue->get_queue_list($qlist);
448
			}
449
		}
450
		return $qlist;
451
	}
452

    
453
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
454

    
455
		if (!is_array($this->queues)) {
456
			$this->queues = array();
457
		}
458

    
459
		switch ($this->GetScheduler()) {
460
			case "PRIQ":
461
				$q =& new priq_queue();
462
				break;
463
			case "HFSC":
464
				$q =& new hfsc_queue();
465
				break;
466
			case "CBQ":
467
				$q =& new cbq_queue();
468
				break;
469
			case "FAIRQ":
470
				$q =& new fairq_queue();
471
				break;
472
			default:
473
				/* XXX: but should not happen anyway */
474
				return;
475
				break;
476
		}
477
		$q->SetLink($path);
478
		$q->SetInterface($this->GetInterface());
479
		$q->SetEnabled("on");
480
		$q->SetParent($this);
481
		$q->ReadConfig($queue);
482
		$q->validate_input($queue, $input_errors);
483
		if (count($input_errors)) {
484
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
485
			return $q;
486
		}
487

    
488
		if (isset($queue['bandwidth'])) {
489
			switch ($queue['bandwidthtype']) {
490
				case "%":
491
					$myBw = $this->GetAvailableBandwidth() * $queue['bandwidth'] / 100;
492
					break;
493
				default:
494
					$myBw = $queue['bandwidth'] * get_bandwidthtype_scale($queue['bandwdithtype']);
495
					break;
496
			}
497
		}
498
		$q->SetAvailableBandwidth($myBw);
499
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
500
		$this->queues[$q->GetQname()] = &$q;
501
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
502
		if (is_array($queue['queue'])) {
503
			foreach ($queue['queue'] as $key1 => $que) {
504
				array_push($path, $key1);
505
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
506
				array_pop($path);
507
			}
508
		}
509

    
510
		return $q;
511
	}
512

    
513
	/* interface here might be optional */
514
	function &find_queue($interface, $qname) {
515
		if ($qname == $this->GetQname()) {
516
			return $this;
517
		}
518
		foreach ($this->queues as $q) {
519
			$result =& $q->find_queue("", $qname);
520
			if ($result) {
521
				return $result;
522
			}
523
		}
524
	}
525

    
526
	function &find_parentqueue($interface, $qname) {
527
		if ($qname == $interface) {
528
			$result =  NULL;
529
		} else if ($this->queues[$qname]) {
530
			$result = $this;
531
		} else if ($this->GetScheduler() <> "PRIQ") {
532
			foreach ($this->queues as $q) {
533
				$result = $q->find_parentqueue("", $qname);
534
				if ($result) {
535
					return $result;
536
				}
537
			}
538
		}
539
	}
540

    
541
	function build_tree() {
542
		global $shaperIFlist;
543

    
544
		$tree = " <li><a href=\"firewall_shaper.php?interface=".$this->GetInterface()."&amp;queue=". $this->GetInterface()."&amp;action=show";
545
		$tree .= "\">" . $shaperIFlist[$this->GetInterface()] . "</a>";
546
		if (is_array($this->queues)) {
547
			$tree .= "<ul>";
548
			foreach ($this->queues as $q)  {
549
				$tree .= $q->build_tree();
550
			}
551
			$tree .= "</ul>";
552
		}
553
		$tree .= "</li>";
554
		return $tree;
555
	}
556

    
557
	function delete_queue() {
558
		foreach ($this->queues as $q) {
559
			$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
560
			$q->delete_queue();
561
		}
562
		unset_object_by_reference($this->GetLink());
563
	}
564

    
565
	function delete_all() {
566
		if (count($this->queues)) {
567
			foreach ($this->queues as $q) {
568
				$q->delete_all();
569
				unset_object_by_reference($q->GetLink());
570
				unset($q);
571
			}
572
			unset($this->queues);
573
		}
574
	}
575

    
576
	/*
577
	 * First it spits:
578
	 * altq on $interface ..............
579
	 *      then it goes like
580
	 *      foreach ($queues as $qkey => $queue) {
581
	 *              this->queues[$qkey]->build_rule();
582
	 *      }
583
	 */
584
	function build_rules(&$default = false) {
585
		if (count($this->queues) > 0 && $this->GetEnabled() == "on") {
586
			$default = false;
587
			$rules = " altq on  " . get_real_interface($this->GetInterface());
588
			if ($this->GetScheduler()) {
589
				$rules .= " ".strtolower($this->GetScheduler());
590
			}
591
			if ($this->GetQlimit() > 0) {
592
				$rules .= " qlimit " . $this->GetQlimit() . " ";
593
			}
594
			if ($this->GetBandwidth()) {
595
				$rules .= " bandwidth ".trim($this->GetBandwidth());
596
				if ($this->GetBwscale()) {
597
					$rules .= $this->GetBwscale();
598
				}
599
			}
600
			if ($this->GetTbrConfig()) {
601
				$rules .= " tbrsize ".$this->GetTbrConfig();
602
			}
603
			if (count($this->queues)) {
604
				$i = count($this->queues);
605
				$rules .= " queue { ";
606
				foreach ($this->queues as $qkey => $qnone) {
607
					if ($i > 1) {
608
						$i--;
609
						$rules .= " {$qkey}, ";
610
					} else {
611
						$rules .= " {$qkey} ";
612
					}
613
				}
614
				$rules .= " } \n";
615
				foreach ($this->queues as $q) {
616
					$rules .= $q->build_rules($default);
617
				}
618
			}
619

    
620
			if ($default == false) {
621
				$error = "SHAPER: no default queue specified for interface ". $this->GetInterface() . ". The interface queue will be enforced as default.";
622
				file_notice("Shaper", $error, "Error occurred", "");
623
				unset($error);
624
				return "\n";
625
			}
626
			$frule .= $rules;
627
		} else if ($this->GetEnabled() == "on" && $this->GetScheduler() == "CODELQ") {
628
			$rules = " altq on  " . get_real_interface($this->GetInterface());
629
			if ($this->GetScheduler()) {
630
				$rules .= " ".strtolower($this->GetScheduler());
631
			}
632
			if ($this->GetQlimit() > 0) {
633
				$rules .= " ( qlimit " . $this->GetQlimit() . " ) ";
634
			}
635
			if ($this->GetBandwidth()) {
636
				$rules .= " bandwidth ".trim($this->GetBandwidth());
637
				if ($this->GetBwscale()) {
638
					$rules .= $this->GetBwscale();
639
				}
640
			}
641
			if ($this->GetTbrConfig()) {
642
				$rules .= " tbrsize ".$this->GetTbrConfig();
643
			}
644

    
645
			$rules .= " queue";
646
		}
647

    
648
		$rules .= " \n";
649
		return $rules;
650
	}
651

    
652
	function build_javascript() {
653
		$javascript = "<script type=\"text/javascript\">";
654
		$javascript .= "//<![CDATA[\n";
655
		$javascript .= "function mySuspend() {";
656
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
657
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden'; ";
658
		$javascript .= "else if (document.all)";
659
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
660
		$javascript .= "}";
661

    
662
		$javascript .= "function myResume() {";
663
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
664
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';";
665
		$javascript .= "else if (document.all) ";
666
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';";
667
		$javascript .= "}";
668
		$javascript .= "//]]>";
669
		$javascript .= "</script>";
670

    
671
		return $javascript;
672
	}
673

    
674
	function build_shortform() {
675
		global $g;
676

    
677
		$altq =& $this;
678
		if ($altq) {
679
			$scheduler = ": " . $altq->GetScheduler();
680
		}
681
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
682
		$form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=". $this->GetInterface()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .": ".$scheduler."</a>";
683
		$form .= "</td></tr>";
684
		$form .= "<tr>";
685
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
686
		$form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale();
687
		$form .= "</td><td width=\"50%\"></td></tr>";
688
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
689
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
690
		$form .= $this->GetInterface() . "&amp;queue=";
691
		$form .= $this->GetQname() . "&amp;action=delete\">";
692
		$form .= "<img src=\"";
693
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
694
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Disable shaper on interface\" alt=\"disable\" />";
695
		$form .= "<span>Disable shaper on interface</span></a></td></tr>";
696

    
697
		return $form;
698

    
699
	}
700
	/*
701
	 * For requesting the parameters of the root queues
702
	 * to the user like the traffic wizard does.
703
	 */
704
	function build_form() {
705
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
706
		$form .= gettext("Enable/Disable");
707
		$form .= "<br /></td><td class=\"vncellreq\">";
708
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
709
		if ($this->GetEnabled() == "on") {
710
			$form .=  " checked=\"checked\"";
711
		}
712
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/disable discipline and its children") . "</span>";
713
		$form .= "</td></tr>";
714
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
715
		$form .= "<td class=\"vncellreq\">";
716
		$form .= "<strong>".$this->GetQname()."</strong>";
717
		$form .= "</td></tr>";
718
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Scheduler Type ");
719
		$form .= "</td>";
720
		$form .= "<td class=\"vncellreq\">";
721
		$form .= "<select id=\"scheduler\" name=\"scheduler\" class=\"formselect\">";
722
		$form .= "<option value=\"HFSC\"";
723
		if ($this->GetScheduler() == "HFSC") {
724
			$form .= " selected=\"selected\"";
725
		}
726
		$form .= ">HFSC</option>";
727
		$form .= "<option value=\"CBQ\"";
728
		if ($this->GetScheduler() == "CBQ") {
729
			$form .= " selected=\"selected\"";
730
		}
731
		$form .= ">CBQ</option>";
732
		$form .= "<option value=\"FAIRQ\"";
733
		if ($this->GetScheduler() == "FAIRQ") {
734
			$form .= " selected=\"selected\"";
735
		}
736
		$form .= ">FAIRQ</option>";
737
		$form .= "<option value=\"CODELQ\"";
738
		if ($this->GetScheduler() == "CODELQ") {
739
			$form .= " selected=\"selected\"";
740
		}
741
		$form .= ">CODELQ</option>";
742
		$form .= "<option value=\"PRIQ\"";
743
		if ($this->GetScheduler() == "PRIQ") {
744
			$form .= " selected=\"selected\"";
745
		}
746
		$form .= ">PRIQ</option>";
747
		$form .= "</select>";
748
		$form .= "<br /> <span class=\"vexpl\">";
749
		$form .= gettext("NOTE: Changing this changes all child queues!");
750
		$form .= gettext(" Beware you can lose information.");
751
		$form .= "</span>";
752
		$form .= "</td></tr>";
753
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth");
754
		$form .= "</td><td class=\"vncellreq\">";
755
		$form .= "<input type=\"text\" id=\"bandwidth\" name=\"bandwidth\" value=\"";
756
		$form .= $this->GetBandwidth() . "\" />";
757
		$form .= "<select id=\"bandwidthtype\" name=\"bandwidthtype\" class=\"formselect\">";
758
		$form .= "<option value=\"Kb\"";
759
		if ($this->GetBwscale() == "Kb") {
760
			$form .= " selected=\"selected\"";
761
		}
762
		$form .= ">Kbit/s</option>";
763
		$form .= "<option value=\"Mb\"";
764
		if ($this->GetBwscale() == "Mb") {
765
			$form .= " selected=\"selected\"";
766
		}
767
		$form .= ">Mbit/s</option>";
768
		$form .= "<option value=\"Gb\"";
769
		if ($this->GetBwscale() == "Gb") {
770
			$form .= " selected=\"selected\"";
771
		}
772
		$form .= ">Gbit/s</option>";
773
		$form .= "<option value=\"b\"";
774
		if ($this->GetBwscale() == "b") {
775
			$form .= " selected=\"selected\"";
776
		}
777
		$form .= ">Bit/s</option>";
778
		$form .= "</select>";
779
		$form .= "</td></tr>";
780
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">Queue Limit</td>";
781
		$form .= "<td class=\"vncellreq\">";
782
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
783
		$form .= $this->GetQlimit();
784
		$form .= "\" />";
785
		$form .= "</td></tr>";
786
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">TBR Size</td>";
787
		$form .= "<td class=\"vncellreq\">";
788
		$form .= "<br /><input type=\"text\" id=\"tbrconfig\" name=\"tbrconfig\" value=\"";
789
		$form .= $this->GetTbrConfig();
790
		$form .= "\" />";
791
		$form .= "<br /> <span class=\"vexpl\">";
792
		$form .= gettext("Adjusts the size, in bytes, of the token bucket regulator. "
793
			  .  "If not specified, heuristics based on the interface "
794
			  .  "bandwidth are used to determine the size.");
795
		$form .= "</span></td></tr>";
796
		$form .= "<input type=\"hidden\" id=\"interface\" name=\"interface\"";
797
		$form .= " value=\"" . $this->GetInterface() . "\" />";
798
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"".$this->GetQname()."\" />";
799

    
800
		return $form;
801
	}
802

    
803
	function update_altq_queue_data(&$data) {
804
		$this->ReadConfig($data);
805
	}
806

    
807
	/*
808
	 * Should call on each of it queues and subqueues
809
	 * the same function much like build_rules();
810
	 */
811
	function wconfig() {
812
		$cflink = &get_reference_to_me_in_config($this->GetLink());
813
		if (!is_array($cflink)) {
814
			$cflink = array();
815
		}
816
		$cflink['interface'] = $this->GetInterface();
817
		$cflink['name'] = $this->GetQname();
818
		$cflink['scheduler'] = $this->GetScheduler();
819
		$cflink['bandwidth'] = $this->GetBandwidth();
820
		$cflink['bandwidthtype'] = $this->GetBwscale();
821
		$cflink['qlimit'] = trim($this->GetQlimit());
822
		if (empty($cflink['qlimit'])) {
823
			unset($cflink['qlimit']);
824
		}
825
		$cflink['tbrconfig'] = trim($this->GetTbrConfig());
826
		if (empty($cflink['tbrconfig'])) {
827
			unset($cflink['tbrconfig']);
828
		}
829
		$cflink['enabled'] = $this->GetEnabled();
830
		if (empty($cflink['enabled'])) {
831
			unset($cflink['enabled']);
832
		}
833
	}
834

    
835
}
836

    
837
class priq_queue {
838
	var $qname;
839
	var $qinterface;
840
	var $qlimit;
841
	var $qpriority;
842
	var $description;
843
	var $isparent;
844
	var $qbandwidth;
845
	var $qbandwidthtype;
846
	var $qdefault = "";
847
	var $qrio = "";
848
	var $qred = "";
849
	var $qcodel = "";
850
	var $qecn = "";
851
	var $qack;
852
	var $qenabled = "";
853
	var $qparent;
854
	var $link;
855
	var $available_bw; /* in b/s */
856

    
857
	/* This is here to help with form building and building rules/lists */
858
	var $subqueues = array();
859

    
860
	/* Accesor functions */
861
	function GetAvailableBandwidth() {
862
		return $this->available_bw;
863
	}
864
	function SetAvailableBandwidth($bw) {
865
		$this->available_bw = $bw;
866
	}
867
	function SetLink($link) {
868
		$this->link = $link;
869
	}
870
	function GetLink() {
871
		return $this->link;
872
	}
873
	function &GetParent() {
874
		return $this->qparent;
875
	}
876
	function SetParent(&$parent) {
877
		$this->qparent = &$parent;
878
	}
879
	function GetEnabled() {
880
		return $this->qenabled;
881
	}
882
	function SetEnabled($value) {
883
		$this->qenabled = $value;
884
	}
885
	function CanHaveChildren() {
886
		return false;
887
	}
888
	function CanBeDeleted() {
889
		return true;
890
	}
891
	function GetQname() {
892
		return $this->qname;
893
	}
894
	function SetQname($name) {
895
		$this->qname = trim($name);
896
	}
897
	function GetBandwidth() {
898
		return $this->qbandwidth;
899
	}
900
	function SetBandwidth($bandwidth) {
901
		$this->qbandwidth = $bandwidth;
902
	}
903
	function GetInterface() {
904
		return $this->qinterface;
905
	}
906
	function SetInterface($name) {
907
		$this->qinterface = trim($name);
908
	}
909
	function GetQlimit() {
910
		return $this->qlimit;
911
	}
912
	function SetQlimit($limit) {
913
		$this->qlimit = $limit;
914
	}
915
	function GetQpriority() {
916
		return $this->qpriority;
917
	}
918
	function SetQpriority($priority) {
919
		$this->qpriority = $priority;
920
	}
921
	function GetDescription() {
922
		return $this->description;
923
	}
924
	function SetDescription($str) {
925
		$this->description = trim($str);
926
	}
927
	function GetFirstime() {
928
		return $this->firsttime;
929
	}
930
	function SetFirsttime($number) {
931
		$this->firsttime = $number;
932
	}
933
	function GetBwscale() {
934
		return $this->qbandwidthtype;
935
	}
936
	function SetBwscale($scale) {
937
		$this->qbandwidthtype = $scale;
938
	}
939
	function GetDefaultQueuePresent() {
940
		if ($this->GetDefault()) {
941
			return true;
942
		}
943
		if (!empty($this->subqueues)) {
944
			foreach ($this->subqueues as $q) {
945
				if ($q->GetDefault()) {
946
					return true;
947
				}
948
			}
949
		}
950

    
951
		return false;
952
	}
953
	function GetDefault() {
954
		return $this->qdefault;
955
	}
956
	function SetDefault($value = false) {
957
		$this->qdefault = $value;
958
	}
959
	function GetCodel() {
960
		return $this->codel;
961
	}
962
	function SetCodel($codel = false) {
963
		$this->codel = $codel;
964
	}
965
	function GetRed() {
966
		return $this->qred;
967
	}
968
	function SetRed($red = false) {
969
		$this->qred = $red;
970
	}
971
	function GetRio() {
972
		return $this->qrio;
973
	}
974
	function SetRio($rio = false) {
975
		$this->qrio = $rio;
976
	}
977
	function GetEcn() {
978
		return $this->qecn;
979
	}
980
	function SetEcn($ecn = false) {
981
		$this->qecn = $ecn;
982
	}
983
	function GetAck() {
984
		return $this->qack;
985
	}
986
	function SetAck($ack = false) {
987
		$this->qack = $ack;
988
	}
989

    
990
	function build_javascript() {
991
		$javascript = "<script type=\"text/javascript\">";
992
		$javascript .= "//<![CDATA[\n";
993
		$javascript .= "function mySuspend() { \n";
994
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
995
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
996
		$javascript .= "else if (document.all)\n";
997
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
998
		$javascript .= "}\n";
999

    
1000
		$javascript .= "function myResume() {\n";
1001
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
1002
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
1003
		$javascript .= "else if (document.all)\n";
1004
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
1005
		$javascript .= "}\n";
1006
		$javascript .= "//]]>";
1007
		$javascript .= "</script>";
1008

    
1009
		return $javascript;
1010
	}
1011

    
1012
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
1013

    
1014
	/*
1015
	 * Currently this will not be called unless we decide to clone a whole
1016
	 * queue tree on the 'By Queues' view or support drag&drop on the tree/list
1017
	 */
1018
	function copy_queue($interface, &$cflink) {
1019

    
1020
		$cflink['name'] = $this->GetQname();
1021
		$cflink['interface'] = $interface;
1022
		$cflink['qlimit'] = $this->GetQlimit();
1023
		$cflink['priority'] = $this->GetQpriority();
1024
		$cflink['description'] = $this->GetDescription();
1025
		$cflink['enabled'] = $this->GetEnabled();
1026
		$cflink['default'] = $this->GetDefault();
1027
		$cflink['red'] = $this->GetRed();
1028
		$cflink['codel'] = $this->GetCodel();
1029
		$cflink['rio'] = $this->GetRio();
1030
		$cflink['ecn'] = $this->GetEcn();
1031

    
1032
		if (is_array($this->subqueues)) {
1033
			$cflinkp['queue'] = array();
1034
			foreach ($this->subqueues as $q) {
1035
				$cflink['queue'][$q->GetQname()] = array();
1036
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1037
			}
1038
		}
1039
	}
1040

    
1041
	function clean_queue($sched) {
1042
		clean_child_queues($sched, $this->GetLink());
1043
		if (is_array($this->subqueues)) {
1044
			foreach ($this->subqueues as $q) {
1045
				$q->clean_queue($sched);
1046
			}
1047
		}
1048
	}
1049

    
1050
	function &get_queue_list(&$qlist) {
1051

    
1052
		$qlist[$this->GetQname()] = & $this;
1053
		if (is_array($this->subqueues)) {
1054
			foreach ($this->subqueues as $queue) {
1055
				$queue->get_queue_list($qlist);
1056
			}
1057
		}
1058
	}
1059

    
1060
	function delete_queue() {
1061
		unref_on_altq_queue_list($this->GetQname());
1062
		cleanup_queue_from_rules($this->GetQname());
1063
		unset_object_by_reference($this->GetLink());
1064
	}
1065

    
1066
	function delete_all() {
1067
		if (count($this->subqueues)) {
1068
			foreach ($this->subqueues as $q) {
1069
				$q->delete_all();
1070
				unset_object_by_reference($q->GetLink());
1071
				unset($q);
1072
			}
1073
			unset($this->subqueues);
1074
		}
1075
	}
1076

    
1077
	function &find_queue($interface, $qname) {
1078
		if ($qname == $this->GetQname()) {
1079
			return $this;
1080
		}
1081
	}
1082

    
1083
	function find_parentqueue($interface, $qname) { return; }
1084

    
1085
	function validate_input($data, &$input_errors) {
1086

    
1087
		$reqdfields[] = "name";
1088
		$reqdfieldsn[] = gettext("Name");
1089
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1090

    
1091
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
1092
			$input_errors[] = "Bandwidth must be an integer.";
1093
		}
1094
		if ($data['bandwidth'] < 0) {
1095
			$input_errors[] = "Bandwidth cannot be negative.";
1096
		}
1097
		if ($data['priority'] && (!is_numeric($data['priority']) ||
1098
		    ($data['priority'] < 1) || ($data['priority'] > 15))) {
1099
			$input_errors[] = gettext("The priority must be an integer between 1 and 15.");
1100
		}
1101
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
1102
				$input_errors[] = gettext("Queue limit must be an integer");
1103
		}
1104
		if ($data['qlimit'] < 0) {
1105
				$input_errors[] = gettext("Queue limit must be positive");
1106
		}
1107
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['newname'])) {
1108
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1109
		}
1110
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['name'])) {
1111
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1112
		}
1113
		$default = $this->GetDefault();
1114
		if (!empty($data['default']) && altq_get_default_queue($data['interface']) && empty($default)) {
1115
			$input_errors[] = gettext("Only one default queue per interface is allowed.");
1116
		}
1117
	}
1118

    
1119
	function ReadConfig(&$q) {
1120
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
1121
			$this->SetQname($q['newname']);
1122
		} else if (!empty($q['newname'])) {
1123
			$this->SetQname($q['newname']);
1124
		} else if (isset($q['name'])) {
1125
			$this->SetQname($q['name']);
1126
		}
1127
		if (isset($q['interface'])) {
1128
			$this->SetInterface($q['interface']);
1129
		}
1130
		$this->SetBandwidth($q['bandwidth']);
1131
		if ($q['bandwidthtype'] <> "") {
1132
			$this->SetBwscale($q['bandwidthtype']);
1133
		}
1134
		if (!empty($q['qlimit'])) {
1135
			$this->SetQlimit($q['qlimit']);
1136
		} else {
1137
			$this->SetQlimit(""); // Default
1138
		}
1139
		if (!empty($q['priority'])) {
1140
			$this->SetQPriority($q['priority']);
1141
		} else {
1142
			$this->SetQpriority("");
1143
		}
1144
		if (!empty($q['description'])) {
1145
			$this->SetDescription($q['description']);
1146
		} else {
1147
			$this->SetDescription("");
1148
		}
1149
		if (!empty($q['red'])) {
1150
			$this->SetRed($q['red']);
1151
		} else {
1152
			$this->SetRed();
1153
		}
1154
		if (!empty($q['codel'])) {
1155
			$this->SetCodel($q['codel']);
1156
		} else {
1157
			$this->SetCodel();
1158
		}
1159
		if (!empty($q['rio'])) {
1160
			$this->SetRio($q['rio']);
1161
		} else {
1162
			$this->SetRio();
1163
		}
1164
		if (!empty($q['ecn'])) {
1165
			$this->SetEcn($q['ecn']);
1166
		} else {
1167
			$this->SetEcn();
1168
		}
1169
		if (!empty($q['default'])) {
1170
			$this->SetDefault($q['default']);
1171
		} else {
1172
			$this->SetDefault();
1173
		}
1174
		if (!empty($q['enabled'])) {
1175
			$this->SetEnabled($q['enabled']);
1176
		} else {
1177
			$this->SetEnabled("");
1178
		}
1179
	}
1180

    
1181
	function build_tree() {
1182
		$tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&amp;queue=". $this->GetQname()."&amp;action=show";
1183
		$tree .= "\" ";
1184
		$tmpvalue = $this->GetDefault();
1185
		if (!empty($tmpvalue)) {
1186
			$tree .= " class=\"navlnk\"";
1187
		}
1188
		$tree .= " >" . $this->GetQname() . "</a>";
1189
		/*
1190
		 * Not needed here!
1191
		 * if (is_array($queues) {
1192
		 *	  $tree .= "<ul>";
1193
		 *	  foreach ($q as $queues)
1194
		 *		  $tree .= $queues['$q->GetName()']->build_tree();
1195
		 *	  endforeach
1196
		 *	  $tree .= "</ul>";
1197
		 * }
1198
		 */
1199

    
1200
		$tree .= "</li>";
1201

    
1202
		return $tree;
1203
	}
1204

    
1205
	/* Should return something like:
1206
	 * queue $qname on $qinterface bandwidth ....
1207
	 */
1208
	function build_rules(&$default = false) {
1209
		$pfq_rule = " queue ". $this->qname;
1210
		if ($this->GetInterface()) {
1211
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1212
		}
1213
		$tmpvalue = $this->GetQpriority();
1214
		if (!empty($tmpvalue)) {
1215
			$pfq_rule .= " priority ".$this->GetQpriority();
1216
		}
1217
		$tmpvalue = $this->GetQlimit();
1218
		if (!empty($tmpvalue)) {
1219
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1220
		}
1221
		if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault() || $this->GetCodel()) {
1222
			$pfq_rule .= " priq ( ";
1223
			$tmpvalue = $this->GetRed();
1224
			if (!empty($tmpvalue)) {
1225
				$comma = 1;
1226
				$pfq_rule .= " red ";
1227
			}
1228
			$tmpvalue = $this->GetRio();
1229
			if (!empty($tmpvalue)) {
1230
				if ($comma) {
1231
					$pfq_rule .= " ,";
1232
				}
1233
				$comma = 1;
1234
				$pfq_rule .= " rio ";
1235
			}
1236
			$tmpvalue = $this->GetEcn();
1237
			if (!empty($tmpvalue)) {
1238
				if ($comma) {
1239
					$pfq_rule .= " ,";
1240
				}
1241
				$comma = 1;
1242
				$pfq_rule .= " ecn ";
1243
			}
1244
			$tmpvalue = $this->GetCodel();
1245
			if (!empty($tmpvalue)) {
1246
				if ($comma) {
1247
					$pfq_rule .= " ,";
1248
				}
1249
				$comma = 1;
1250
				$pfq_rule .= " codel ";
1251
			}
1252
			$tmpvalue = $this->GetDefault();
1253
			if (!empty($tmpvalue)) {
1254
				if ($comma) {
1255
					$pfq_rule .= " ,";
1256
				}
1257
				$pfq_rule .= " default ";
1258
				$default = true;
1259
			}
1260
			$pfq_rule .= " ) ";
1261
		}
1262

    
1263
		$pfq_rule .= " \n";
1264

    
1265
		return $pfq_rule;
1266
	}
1267

    
1268
	/*
1269
	 * To return the html form to show to user
1270
	 * for getting the parameters.
1271
	 * Should do even for first time when the
1272
	 * object is created and later when we may
1273
	 * need to update it.
1274
	 */
1275
	function build_form() {
1276
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
1277
		$form .= gettext("Enable/Disable");
1278
		$form .= "<br /></td><td class=\"vncellreq\">";
1279
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
1280
		if ($this->GetEnabled() == "on") {
1281
			$form .=  " checked=\"checked\"";
1282
		}
1283
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue and its children") . "</span>";
1284
		$form .= "</td></tr>";
1285
		$form .= "<tr>";
1286
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">";
1287
		$form .= gettext("Queue Name") . "</td><td width=\"78%\" class=\"vtable\">";
1288
		$form .= "<input name=\"newname\" type=\"text\" id=\"newname\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
1289
		$form .= htmlspecialchars($this->GetQname());
1290
		$form .= "\" />";
1291
		$form .= "<input name=\"name\" type=\"hidden\" id=\"name\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
1292
		$form .= htmlspecialchars($this->GetQname());
1293
		$form .= "\" />";
1294
		$form .= "<br /> <span class=\"vexpl\">" . gettext("Enter the name of the queue here.  Do not use spaces and limit the size to 15 characters.");
1295
		$form .= "</span><br /></td>";
1296
		$form .= "</tr><tr>";
1297
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Priority") . "</td>";
1298
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"priority\" type=\"text\" id=\"priority\" size=\"5\" value=\"";
1299
		$form .= htmlspecialchars($this->GetQpriority());
1300
		$form .= "\" />";
1301
		$form .= "<br /> <span class=\"vexpl\">" . gettext("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.") . "</span></td>";
1302
		$form .= "</tr>";
1303
		$form .= "<tr>";
1304
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Queue limit") . "</td>";
1305
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"qlimit\" type=\"text\" id=\"qlimit\" size=\"8\" value=\"";
1306
		$form .= htmlspecialchars($this->GetQlimit());
1307
		$form .= "\" />";
1308
		$form .= "<br /> <span class=\"vexpl\">" . gettext("Queue limit in packets.");
1309
		$form .= "</span></td></tr>";
1310
		$form .= "<tr>";
1311
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncell\">" . gettext("Scheduler options") . "</td>";
1312
		$form .= "<td width=\"78%\" class=\"vtable\">";
1313
		if (empty($this->subqueues)) {
1314
			if ($this->GetDefault()) {
1315
				$form .= "<input type=\"checkbox\" id=\"default\" checked=\"checked\" name=\"default\" value=\"default\"";
1316
				$form .= " /> " . gettext("Default queue") . "<br />";
1317
			} else {
1318
				$form .= "<input type=\"checkbox\" id=\"default\" name=\"default\" value=\"default\"";
1319
				$form .= " /> " . gettext("Default queue") . "<br />";
1320
			}
1321
		}
1322
		$form .= "<input type=\"checkbox\" id=\"red\" name=\"red\" value=\"red\" ";
1323
		$tmpvalue = $this->GetRed();
1324
		if (!empty($tmpvalue)) {
1325
			$form .=  " checked=\"checked\"";
1326
		}
1327
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#red\">" . gettext("Random Early Detection") . "</a><br />";
1328
		$form .= "<input type=\"checkbox\" id=\"rio\" name=\"rio\" value=\"rio\"";
1329
		$tmpvalue = $this->GetRio();
1330
		if (!empty($tmpvalue)) {
1331
			$form .=  " checked=\"checked\"";
1332
		}
1333
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#rio\">" . gettext("Random Early Detection In and Out") . "</a><br />";
1334
		$form .= "<input type=\"checkbox\" id=\"ecn\" name=\"ecn\" value=\"ecn\"";
1335
		$tmpvalue = $this->GetEcn();
1336
		if (!empty($tmpvalue)) {
1337
			$form .=  " checked=\"checked\"";
1338
		}
1339
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#ecn\">" . gettext("Explicit Congestion Notification") . "</a><br />";
1340
		$form .= "<input type=\"checkbox\" id=\"codel\" name=\"codel\" value=\"codel\"";
1341
		$tmpvalue = $this->GetCodel();
1342
		if (!empty($tmpvalue)) {
1343
			$form .=  " checked=\"checked\"";
1344
		}
1345
		$form .= " /> <a target=\"_new\" href=\"http://www.bufferbloat.net/projects/codel/wiki\">" . gettext("Codel Active Queue") . "</a><br />";
1346
		$form .= "<span class=\"vexpl\"><br />" . gettext("Select options for this queue");
1347
		$form .= "</span></td></tr><tr>";
1348
		$form .= "<td width=\"22%\" class=\"vncellreq\">" . gettext("Description") . "</td>";
1349
		$form .= "<td width=\"78%\" class=\"vtable\">";
1350
		$form .= "<input type=\"text\" name=\"description\" size=\"40\" class=\"formfld unknown\" value=\"" . $this->GetDescription() . "\" />";
1351
		$form .= "</td></tr>";
1352
		$form .= "<input type=\"hidden\" name=\"interface\" id=\"interface\"";
1353
		$form .= " value=\"".$this->GetInterface()."\" />";
1354

    
1355
		return $form;
1356
	}
1357

    
1358
	function build_shortform() {
1359
		/* XXX: Hacks in sight. Mostly layer violations!  */
1360
		global $g, $altq_list_queues;
1361
		global $shaperIFlist;
1362

    
1363
		$altq =& $altq_list_queues[$this->GetInterface()];
1364
		if ($altq) {
1365
			$scheduler = ": " . $altq->GetScheduler();
1366
		}
1367
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
1368
		$form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=" . $this->GetQname()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .$scheduler."</a>";
1369
		$form .= "</td></tr>";
1370
		/*
1371
		 * XXX: Hack in sight maybe fix with a class that wraps all
1372
		 * of this layer violations
1373
		 */
1374
		$form .= "<tr>";
1375
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
1376
		$form .= gettext("Bandwidth:") . " " . $this->GetBandwidth().$this->GetBwscale();
1377
		$form .= "</td><td width=\"50%\"></td></tr>";
1378
		$tmpvalue = $this->GetQpriority();
1379
		if (!empty($tmpvalue)) {
1380
			$form .= "<tr><td width=\"20%\" class=\"vncellreq\">" .gettext("Priority: on") . " </td></tr>";
1381
		}
1382
		$tmpvalue = $this->GetDefault();
1383
		if (!empty($tmpvalue)) {
1384
			$form .= "<tr><td class=\"vncellreq\">" . gettext("Default: on") . " </td></tr>";
1385
		}
1386
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
1387
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
1388
		$form .= $this->GetInterface() . "&amp;queue=";
1389
		$form .= $this->GetQname() . "&amp;action=delete\">";
1390
		$form .= "<img src=\"";
1391
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
1392
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("Delete queue from interface") . "\" alt=\"delete\" />";
1393
		$form .= "<span>" . gettext("Delete queue from interface") . "</span></a></td></tr>";
1394

    
1395
		return $form;
1396

    
1397
	}
1398

    
1399
	function update_altq_queue_data(&$q) {
1400
		$this->ReadConfig($q);
1401
	}
1402

    
1403
	function wconfig() {
1404
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1405
		if (!is_array($cflink)) {
1406
			$cflink = array();
1407
		}
1408
		$cflink['name'] = $this->GetQname();
1409
		$cflink['interface'] = $this->GetInterface();
1410
		$cflink['qlimit'] = trim($this->GetQlimit());
1411
		if (empty($cflink['qlimit'])) {
1412
			unset($cflink['qlimit']);
1413
		}
1414
		$cflink['priority'] = trim($this->GetQpriority());
1415
		if (empty($cflink['priority'])) {
1416
			unset($cflink['priority']);
1417
		}
1418
		$cflink['description'] = trim($this->GetDescription());
1419
		if (empty($cflink['description'])) {
1420
			unset($cflink['description']);
1421
		}
1422
		$cflink['enabled'] = trim($this->GetEnabled());
1423
		if (empty($cflink['enabled'])) {
1424
			unset($cflink['enabled']);
1425
		}
1426
		$cflink['default'] = trim($this->GetDefault());
1427
		if (empty($cflink['default'])) {
1428
			unset($cflink['default']);
1429
		}
1430
		$cflink['red'] = trim($this->GetRed());
1431
		if (empty($cflink['red'])) {
1432
			unset($cflink['red']);
1433
		}
1434
		$cflink['codel'] = trim($this->GetCodel());
1435
		if (empty($cflink['codel'])) {
1436
			unset($cflink['codel']);
1437
		}
1438
		$cflink['rio'] = trim($this->GetRio());
1439
		if (empty($cflink['rio'])) {
1440
			unset($cflink['rio']);
1441
		}
1442
		$cflink['ecn'] = trim($this->GetEcn());
1443
		if (empty($cflink['ecn'])) {
1444
			unset($cflink['ecn']);
1445
		}
1446
	}
1447
}
1448

    
1449
class hfsc_queue extends priq_queue {
1450
	/* realtime */
1451
	var $realtime;
1452
	var $r_m1;
1453
	var $r_d;
1454
	var $r_m2;
1455
	/* linkshare */
1456
	var $linkshare;
1457
	var $l_m1;
1458
	var $l_d;
1459
	var $l_m2;
1460
	/* upperlimit */
1461
	var $upperlimit;
1462
	var $u_m1;
1463
	var $u_d;
1464
	var $u_m2;
1465

    
1466
	/*
1467
	 * HFSC can have nested queues.
1468
	 */
1469
	function CanHaveChildren() {
1470
		return true;
1471
	}
1472
	function GetRealtime() {
1473
		return $this->realtime;
1474
	}
1475
	function GetR_m1() {
1476
		return $this->r_m1;
1477
	}
1478
	function GetR_d() {
1479
		return $this->r_d;
1480
	}
1481
	function GetR_m2() {
1482
		return $this->r_m2;
1483
	}
1484
	function SetRealtime() {
1485
		$this->realtime = "on";
1486
	}
1487
	function DisableRealtime() {
1488
		$this->realtime = "";
1489
	}
1490
	function SetR_m1($value) {
1491
		$this->r_m1 = $value;
1492
	}
1493
	function SetR_d($value) {
1494
		$this->r_d = $value;
1495
	}
1496
	function SetR_m2($value) {
1497
		$this->r_m2 = $value;
1498
	}
1499
	function GetLinkshare() {
1500
		return $this->linkshare;
1501
	}
1502
	function DisableLinkshare() {
1503
		$this->linkshare = "";
1504
	}
1505
	function GetL_m1() {
1506
		return $this->l_m1;
1507
	}
1508
	function GetL_d() {
1509
		return $this->l_d;
1510
	}
1511
	function GetL_m2() {
1512
		return $this->l_m2;
1513
	}
1514
	function SetLinkshare() {
1515
		$this->linkshare = "on";
1516
	}
1517
	function SetL_m1($value) {
1518
		$this->l_m1 = $value;
1519
	}
1520
	function SetL_d($value) {
1521
		$this->l_d = $value;
1522
	}
1523
	function SetL_m2($value) {
1524
		$this->l_m2 = $value;
1525
	}
1526
	function GetUpperlimit() {
1527
		return $this->upperlimit;
1528
	}
1529
	function GetU_m1() {
1530
		return $this->u_m1;
1531
	}
1532
	function GetU_d() {
1533
		return $this->u_d;
1534
	}
1535
	function GetU_m2() {
1536
		return $this->u_m2;
1537
	}
1538
	function SetUpperlimit() {
1539
		$this->upperlimit = "on";
1540
	}
1541
	function DisableUpperlimit() {
1542
		$this->upperlimit = "";
1543
	}
1544
	function SetU_m1($value) {
1545
		$this->u_m1 = $value;
1546
	}
1547
	function SetU_d($value) {
1548
		$this->u_d = $value;
1549
	}
1550
	function SetU_m2($value) {
1551
		$this->u_m2 = $value;
1552
	}
1553

    
1554
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1555

    
1556
		if (!is_array($this->subqueues)) {
1557
			$this->subqueues = array();
1558
		}
1559
		$q =& new hfsc_queue();
1560
		$q->SetInterface($this->GetInterface());
1561
		$q->SetParent($this);
1562
		$q->ReadConfig($qname);
1563
		$q->validate_input($qname, $input_errors);
1564
		if (count($input_errors)) {
1565
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
1566
			return $q;
1567
		}
1568

    
1569
		$q->SetEnabled("on");
1570
		$q->SetLink($path);
1571
		switch ($q->GetBwscale()) {
1572
			case "%":
1573
				$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
1574
				break;
1575
			default:
1576
				$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
1577
				break;
1578
		}
1579
		$q->SetAvailableBandwidth($myBw);
1580
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
1581

    
1582
		$this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue()
1583
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
1584
		if (is_array($qname['queue'])) {
1585
			foreach ($qname['queue'] as $key1 => $que) {
1586
				array_push($path, $key1);
1587
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
1588
				array_pop($path);
1589
			}
1590
		}
1591

    
1592
		return $q;
1593
	}
1594

    
1595
	function copy_queue($interface, &$cflink) {
1596

    
1597
		$cflink['name'] = $this->GetQname();
1598
		$cflink['interface'] = $interface;
1599
		$cflink['qlimit'] = trim($this->GetQlimit());
1600
		if (empty($cflink['qlimit'])) {
1601
			unset($cflink['qlimit']);
1602
		}
1603
		$cflink['priority'] = trim($this->GetQpriority());
1604
		if (empty($cflink['priority'])) {
1605
			unset($cflink['priority']);
1606
		}
1607
		$cflink['description'] = trim($this->GetDescription());
1608
		if (empty($cflink['description'])) {
1609
			unset($cflink['description']);
1610
		}
1611
		$cflink['bandwidth'] = $this->GetBandwidth();
1612
		$cflink['bandwidthtype'] = $this->GetBwscale();
1613
		$cflink['enabled'] = trim($this->GetEnabled());
1614
		if (empty($cflink['enabled'])) {
1615
			unset($cflink['enabled']);
1616
		}
1617
		$cflink['default'] = trim($this->GetDefault());
1618
		if (empty($cflink['default'])) {
1619
			unset($cflink['default']);
1620
		}
1621
		$cflink['red'] = trim($this->GetRed());
1622
		if (empty($cflink['red'])) {
1623
			unset($cflink['red']);
1624
		}
1625
		$cflink['rio'] = trim($this->GetRio());
1626
		if (empty($cflink['rio'])) {
1627
			unset($cflink['rio']);
1628
		}
1629
		$cflink['ecn'] = trim($this->GetEcn());
1630
		if (empty($cflink['ecn'])) {
1631
			unset($cflink['ecn']);
1632
		}
1633
		if ($this->GetLinkshare() <> "") {
1634
			if ($this->GetL_m1() <> "") {
1635
				$cflink['linkshare1'] = $this->GetL_m1();
1636
				$cflink['linkshare2'] = $this->GetL_d();
1637
				$cflink['linkshare'] = "on";
1638
			} else {
1639
				unset($cflink['linkshare1']);
1640
				unset($cflink['linkshare2']);
1641
				unset($cflink['linkshare']);
1642
			}
1643
			if ($this->GetL_m2() <> "") {
1644
				$cflink['linkshare3'] = $this->GetL_m2();
1645
				$cflink['linkshare'] = "on";
1646
			} else {
1647
				unset($cflink['linkshare3']);
1648
				unset($cflink['linkshare']);
1649
			}
1650
		}
1651
		if ($this->GetRealtime() <> "") {
1652
			if ($this->GetR_m1() <> "") {
1653
				$cflink['realtime1'] = $this->GetR_m1();
1654
				$cflink['realtime2'] = $this->GetR_d();
1655
				$cflink['realtime'] = "on";
1656
			} else {
1657
				unset($cflink['realtime1']);
1658
				unset($cflink['realtime2']);
1659
				unset($cflink['realtime']);
1660
			}
1661
			if ($this->GetR_m2() <> "") {
1662
				$cflink['realtime3'] = $this->GetR_m2();
1663
				$cflink['realtime'] = "on";
1664
			} else {
1665
				unset($cflink['realtime3']);
1666
				unset($cflink['realtime']);
1667
			}
1668
		}
1669
		if ($this->GetUpperlimit() <> "") {
1670
			if ($this->GetU_m1() <> "") {
1671
				$cflink['upperlimit1'] = $this->GetU_m1();
1672
				$cflink['upperlimit2'] = $this->GetU_d();
1673
				$cflink['upperlimit'] = "on";
1674
			} else {
1675
				unset($cflink['upperlimit']);
1676
				unset($cflink['upperlimit1']);
1677
				unset($cflink['upperlimit2']);
1678
			}
1679
			if ($this->GetU_m2() <> "") {
1680
				$cflink['upperlimit3'] = $this->GetU_m2();
1681
				$cflink['upperlimit'] = "on";
1682
			} else {
1683
				unset($cflink['upperlimit3']);
1684
				unset($cflink['upperlimit']);
1685
			}
1686
		}
1687

    
1688
		if (is_array($this->subqueues)) {
1689
			$cflinkp['queue'] = array();
1690
			foreach ($this->subqueues as $q) {
1691
				$cflink['queue'][$q->GetQname()] = array();
1692
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1693
			}
1694
		}
1695
	}
1696

    
1697
	function delete_queue() {
1698
		unref_on_altq_queue_list($this->GetQname());
1699
		cleanup_queue_from_rules($this->GetQname());
1700
		$parent =& $this->GetParent();
1701
		foreach ($this->subqueues as $q)  {
1702
			$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
1703
				$q->delete_queue();
1704
		}
1705
		unset_object_by_reference($this->GetLink());
1706
	}
1707

    
1708
	/*
1709
	 * Should search even its children
1710
	 */
1711
	function &find_queue($interface, $qname) {
1712
		if ($qname == $this->GetQname()) {
1713
			return $this;
1714
		}
1715

    
1716
		foreach ($this->subqueues as $q) {
1717
			$result =& $q->find_queue("", $qname);
1718
			if ($result) {
1719
				return $result;
1720
			}
1721
		}
1722
	}
1723

    
1724
	function &find_parentqueue($interface, $qname) {
1725
		if ($this->subqueues[$qname]) {
1726
			return $this;
1727
		}
1728
		foreach ($this->subqueues as $q) {
1729
			$result = $q->find_parentqueue("", $qname);
1730
			if ($result) {
1731
				return $result;
1732
			}
1733
		}
1734
	}
1735

    
1736
	function validate_input($data, &$input_errors) {
1737
		parent::validate_input($data, $input_errors);
1738

    
1739
		$reqdfields[] = "bandwidth";
1740
		$reqdfieldsn[] = gettext("Bandwidth");
1741
		$reqdfields[] = "bandwidthtype";
1742
		$reqdfieldsn[] = gettext("Bandwidthtype");
1743

    
1744
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1745

    
1746
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1747
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
1748
				$input_errors[] = gettext("Bandwidth must be an integer.");
1749
			}
1750

    
1751
			if ($data['bandwidth'] < 0) {
1752
				$input_errors[] = gettext("Bandwidth cannot be negative.");
1753
			}
1754

    
1755
			if ($data['bandwidthtype'] == "%") {
1756
				if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
1757
					$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
1758
				}
1759
			}
1760
		/*
1761
			$parent =& $this->GetParent();
1762
			switch ($data['bandwidthtype']) {
1763
			case "%":
1764
				$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
1765
			default:
1766
				$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
1767
				break;
1768
			}
1769
			if ($parent->GetAvailableBandwidth() < $myBw) {
1770
				$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
1771
			}
1772
		*/
1773
		}
1774

    
1775
		if ($data['upperlimit1'] <> "" &&  $data['upperlimit2'] == "") {
1776
			$input_errors[] = gettext("upperlimit service curve defined but missing (d) value");
1777
		}
1778
		if ($data['upperlimit2'] <> "" &&  $data['upperlimit1'] == "") {
1779
			$input_errors[] = gettext("upperlimit service curve defined but missing initial bandwidth (m1) value");
1780
		}
1781
		if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1'])) {
1782
			$input_errors[] = gettext("upperlimit m1 value needs to be Kb, Mb, Gb, or %");
1783
		}
1784
		if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2'])) {
1785
			$input_errors[] = gettext("upperlimit d value needs to be numeric");
1786
		}
1787
		if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3'])) {
1788
			$input_errors[] = gettext("upperlimit m2 value needs to be Kb, Mb, Gb, or %");
1789
		}
1790

    
1791
		/*
1792
		if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") {
1793
			$bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']);
1794
			$bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']);
1795
			if (floatval($bw_1) < floatval($bw_2)) {
1796
				$input_errors[] = ("upperlimit m1 cannot be smaller than m2");
1797
			}
1798

    
1799
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
1800
				$input_errors[] = ("upperlimit specification exceeds 80% of allowable allocation.");
1801
			}
1802
		}
1803
		*/
1804
		if ($data['linkshare1'] <> "" &&  $data['linkshare2'] == "") {
1805
			$input_errors[] = gettext("linkshare service curve defined but missing (d) value");
1806
		}
1807
		if ($data['linkshare2'] <> "" &&  $data['linkshare1'] == "") {
1808
			$input_errors[] = gettext("linkshare service curve defined but missing initial bandwidth (m1) value");
1809
		}
1810
		if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1'])) {
1811
			$input_errors[] = gettext("linkshare m1 value needs to be Kb, Mb, Gb, or %");
1812
		}
1813
		if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2'])) {
1814
			$input_errors[] = gettext("linkshare d value needs to be numeric");
1815
		}
1816
		if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3'])) {
1817
			$input_errors[] = gettext("linkshare m2 value needs to be Kb, Mb, Gb, or %");
1818
		}
1819
		if ($data['realtime1'] <> "" &&  $data['realtime2'] == "") {
1820
			$input_errors[] = gettext("realtime service curve defined but missing (d) value");
1821
		}
1822
		if ($data['realtime2'] <> "" &&  $data['realtime1'] == "") {
1823
			$input_errors[] = gettext("realtime service curve defined but missing initial bandwidth (m1) value");
1824
		}
1825

    
1826
		/*
1827
		if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) {
1828
			$bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']);
1829
			$bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']);
1830
			if (floatval($bw_1) < floatval($bw_2)) {
1831
				$input_errors[] = ("linkshare m1 cannot be smaller than m2");
1832
			}
1833

    
1834
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
1835
				$input_errors[] = ("linkshare specification exceeds 80% of allowable allocation.");
1836
			}
1837
		}
1838
		*/
1839

    
1840
		if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1'])) {
1841
			$input_errors[] = gettext("realtime m1 value needs to be Kb, Mb, Gb, or %");
1842
		}
1843
		if ($data['realtime2'] <> "" && !is_numeric($data['realtime2'])) {
1844
			$input_errors[] = gettext("realtime d value needs to be numeric");
1845
		}
1846
		if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3'])) {
1847
			$input_errors[] = gettext("realtime m2 value needs to be Kb, Mb, Gb, or %");
1848
		}
1849

    
1850
		/*
1851
		if (isset($data['realtime']) && $data['realtime3'] <> "" && $data['realtime1'] <> "" && 0) {
1852
			$bw_1 = get_hfsc_bandwidth($this, $data['realtime1']);
1853
			$bw_2 = get_hfsc_bandwidth($this, $data['realtime3']);
1854
			if (floatval($bw_1) < floatval($bw_2)) {
1855
				$input_errors[] = ("realtime m1 cannot be smaller than m2");
1856
			}
1857

    
1858
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2)))) {
1859
				$input_errors[] = ("realtime specification exceeds 80% of allowable allocation.");
1860
			}
1861
		}
1862
		*/
1863
	}
1864

    
1865
	function ReadConfig(&$cflink) {
1866
		if (!empty($cflink['linkshare'])) {
1867
			if (!empty($cflink['linkshare1'])) {
1868
				$this->SetL_m1($cflink['linkshare1']);
1869
				$this->SetL_d($cflink['linkshare2']);
1870
				$this->SetLinkshare();
1871
			} else {
1872
				$this->SetL_m1("");
1873
				$this->SetL_d("");
1874
				$this->DisableLinkshare();
1875
			}
1876
			if (!empty($cflink['linkshare3'])) {
1877
				$this->SetL_m2($cflink['linkshare3']);
1878
				$this->SetLinkshare();
1879
			}
1880
		} else {
1881
			$this->DisableLinkshare();
1882
		}
1883
		if (!empty($cflink['realtime'])) {
1884
			if (!empty($cflink['realtime1'])) {
1885
				$this->SetR_m1($cflink['realtime1']);
1886
				$this->SetR_d($cflink['realtime2']);
1887
				$this->SetRealtime();
1888
			} else {
1889
				$this->SetR_m1("");
1890
				$this->SetR_d("");
1891
				$this->DisableRealtime();
1892
			}
1893
			if (!empty($cflink['realtime3'])) {
1894
				$this->SetR_m2($cflink['realtime3']);
1895
				$this->SetRealtime();
1896
			}
1897
		} else {
1898
			$this->DisableRealtime();
1899
		}
1900
		if (!empty($cflink['upperlimit'])) {
1901
			if (!empty($cflink['upperlimit1'])) {
1902
				$this->SetU_m1($cflink['upperlimit1']);
1903
				$this->SetU_d($cflink['upperlimit2']);
1904
				$this->SetUpperlimit();
1905
			} else {
1906
				$this->SetU_m1("");
1907
				$this->SetU_d("");
1908
				$this->DisableUpperlimit();
1909
			}
1910
			if (!empty($cflink['upperlimit3'])) {
1911
				$this->SetU_m2($cflink['upperlimit3']);
1912
				$this->SetUpperlimit();
1913
			}
1914
		} else {
1915
			$this->DisableUpperlimit();
1916
		}
1917
		parent::ReadConfig($cflink);
1918
	}
1919

    
1920
	function build_tree() {
1921
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface() ."&amp;queue=" . $this->GetQname()."&amp;action=show";
1922
		$tree .= "\" ";
1923
		$tmpvalue = $this->GetDefault();
1924
		if (!empty($tmpvalue)) {
1925
			$tree .= " class=\"navlnk\"";
1926
		}
1927
		$tree .= " >" . $this->GetQname() . "</a>";
1928
		if (is_array($this->subqueues)) {
1929
			$tree .= "<ul>";
1930
			foreach ($this->subqueues as $q)  {
1931
				$tree .= $q->build_tree();
1932
			}
1933
			$tree .= "</ul>";
1934
		}
1935
		$tree .= "</li>";
1936
		return $tree;
1937
	}
1938

    
1939
	/* Even this should take children into consideration */
1940
	function build_rules(&$default = false) {
1941

    
1942
		$pfq_rule = " queue ". $this->qname;
1943
		if ($this->GetInterface()) {
1944
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1945
		}
1946
		if ($this->GetBandwidth() && $this->GetBwscale()) {
1947
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
1948
		}
1949

    
1950
		$tmpvalue = $this->GetQlimit();
1951
		if (!empty($tmpvalue)) {
1952
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1953
		}
1954
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetCodel() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
1955
			$pfq_rule .= " hfsc ( ";
1956
			$tmpvalue = $this->GetRed();
1957
			if (!empty($tmpvalue)) {
1958
				$comma = 1;
1959
				$pfq_rule .= " red ";
1960
			}
1961

    
1962
			$tmpvalue = $this->GetRio();
1963
			if (!empty($tmpvalue)) {
1964
				if ($comma) {
1965
					$pfq_rule .= " ,";
1966
				}
1967
				$comma = 1;
1968
				$pfq_rule .= " rio ";
1969
			}
1970
			$tmpvalue = $this->GetEcn();
1971
			if (!empty($tmpvalue)) {
1972
				if ($comma) {
1973
					$pfq_rule .= " ,";
1974
				}
1975
				$comma = 1;
1976
				$pfq_rule .= " ecn ";
1977
			}
1978
			$tmpvalue = $this->GetCodel();
1979
			if (!empty($tmpvalue)) {
1980
				if ($comma) {
1981
					$pfq_rule .= " ,";
1982
				}
1983
				$comma = 1;
1984
				$pfq_rule .= " codel ";
1985
			}
1986
			$tmpvalue = $this->GetDefault();
1987
			if (!empty($tmpvalue)) {
1988
				if ($comma) {
1989
					$pfq_rule .= " ,";
1990
				}
1991
				$comma = 1;
1992
				$pfq_rule .= " default ";
1993
				$default = true;
1994
			}
1995

    
1996
			if ($this->GetRealtime() <> "")  {
1997
				if ($comma) {
1998
					$pfq_rule .= " , ";
1999
				}
2000
				if ($this->GetR_m1()  <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "") {
2001
					$pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") ";
2002
				} else  if ($this->GetR_m2() <> "") {
2003
					$pfq_rule .= " realtime " . $this->GetR_m2();
2004
				}
2005
				$comma = 1;
2006
			}
2007
			if ($this->GetLinkshare() <> "") {
2008
				if ($comma) {
2009
					$pfq_rule .= " ,";
2010
				}
2011
				if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "") {
2012
					$pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") ";
2013
				} else if ($this->GetL_m2() <> "") {
2014
					$pfq_rule .= " linkshare " . $this->GetL_m2() . " ";
2015
				}
2016
				$comma = 1;
2017
			}
2018
			if ($this->GetUpperlimit() <> "") {
2019
				if ($comma) {
2020
					$pfq_rule .= " ,";
2021
				}
2022
				if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "") {
2023
							$pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") ";
2024
				} else if ($this->GetU_m2() <> "") {
2025
					$pfq_rule .= " upperlimit " . $this->GetU_m2() . " ";
2026
				}
2027
			}
2028
			$pfq_rule .= " ) ";
2029
		}
2030
		if (count($this->subqueues)) {
2031
			$i = count($this->subqueues);
2032
			$pfq_rule .= " { ";
2033
			foreach ($this->subqueues as $qkey => $qnone) {
2034
				if ($i > 1) {
2035
					$i--;
2036
					$pfq_rule .= " {$qkey}, ";
2037
				} else {
2038
					$pfq_rule .= " {$qkey} ";
2039
				}
2040
			}
2041
			$pfq_rule .= " } \n";
2042
			foreach ($this->subqueues as $q) {
2043
				$pfq_rule .= $q->build_rules($default);
2044
			}
2045
		}
2046

    
2047
		$pfq_rule .= " \n";
2048

    
2049
		return $pfq_rule;
2050
	}
2051

    
2052
	function build_javascript() {
2053
		$javascript = parent::build_javascript();
2054
		$javascript .= "<script type=\"text/javascript\">";
2055
		$javascript .= "//<![CDATA[\n";
2056
		$javascript .= "function enable_realtime(enable_over) { \n";
2057
		$javascript .= "if (document.iform.realtime.checked || enable_over) { \n";
2058
		$javascript .= "document.iform.realtime1.disabled = 0;\n";
2059
		$javascript .= "document.iform.realtime2.disabled = 0;\n";
2060
		$javascript .= "document.iform.realtime3.disabled = 0;\n";
2061
		$javascript .= " } else { \n";
2062
		$javascript .= "document.iform.realtime1.disabled = 1;\n";
2063
		$javascript .= "document.iform.realtime2.disabled = 1;\n";
2064
		$javascript .= "document.iform.realtime3.disabled = 1;\n";
2065
		$javascript .= " } \n";
2066
		$javascript .= " } \n";
2067
		$javascript .= "function enable_linkshare(enable_over) { \n";
2068
		$javascript .= "if (document.iform.linkshare.checked || enable_over) { \n";
2069
		$javascript .= "document.iform.linkshare1.disabled = 0;\n";
2070
		$javascript .= "document.iform.linkshare2.disabled = 0;\n";
2071
		$javascript .= "document.iform.linkshare3.disabled = 0;\n";
2072
		$javascript .= " } else { \n";
2073
		$javascript .= "document.iform.linkshare1.disabled = 1;\n";
2074
		$javascript .= "document.iform.linkshare2.disabled = 1;\n";
2075
		$javascript .= "document.iform.linkshare3.disabled = 1;\n";
2076
		$javascript .= " } \n";
2077
		$javascript .= " } \n";
2078
		$javascript .= "function enable_upperlimit(enable_over) { \n";
2079
		$javascript .= "if (document.iform.upperlimit.checked || enable_over) { \n";
2080
		$javascript .= "document.iform.upperlimit1.disabled = 0;\n";
2081
		$javascript .= "document.iform.upperlimit2.disabled = 0;\n";
2082
		$javascript .= "document.iform.upperlimit3.disabled = 0;\n";
2083
		$javascript .= " } else { \n";
2084
		$javascript .= "document.iform.upperlimit1.disabled = 1;\n";
2085
		$javascript .= "document.iform.upperlimit2.disabled = 1;\n";
2086
		$javascript .= "document.iform.upperlimit3.disabled = 1;\n";
2087
		$javascript .= " } \n";
2088

    
2089
		$javascript .= "} \n";
2090
		$javascript .= "//]]>";
2091
		$javascript .= "</script>";
2092

    
2093
		return $javascript;
2094
	}
2095

    
2096
	function build_form() {
2097
		$form = parent::build_form();
2098
		$form .= "<tr>";
2099
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
2100
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2101
		$form .= htmlspecialchars($this->GetBandwidth());
2102
		$form .= "\" />";
2103
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2104
		$form .= "<option value=\"Gb\"";
2105
		if ($this->GetBwscale() == "Gb") {
2106
			$form .= " selected=\"selected\"";
2107
		}
2108
		$form .= ">" . gettext("Gbit/s") . "</option>";
2109
		$form .= "<option value=\"Mb\"";
2110
		if ($this->GetBwscale() == "Mb") {
2111
			$form .= " selected=\"selected\"";
2112
		}
2113
		$form .= ">" . gettext("Mbit/s") . "</option>";
2114
		$form .= "<option value=\"Kb\"";
2115
		if ($this->GetBwscale() == "Kb") {
2116
			$form .= " selected=\"selected\"";
2117
		}
2118
		$form .= ">" . gettext("Kbit/s") . "</option>";
2119
		$form .= "<option value=\"b\"";
2120
		if ($this->GetBwscale() == "b") {
2121
			$form .= " selected=\"selected\"";
2122
		}
2123
		$form .= ">" . gettext("Bit/s") . "</option>";
2124
		$form .= "<option value=\"%\"";
2125
		if ($this->GetBwscale() == "%") {
2126
			$form .= " selected=\"selected\"";
2127
		}
2128
		$form .= ">%</option>";
2129
		$form .= "</select> <br />";
2130
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
2131
		$form .= "</span></td></tr>";
2132
		$form .= "<tr>";
2133
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Service Curve (sc)") . "</td>";
2134
		$form .= "<td width=\"78%\" class=\"vtable\">";
2135
		$form .= "<table>";
2136
		$form .= "<tr><td>&nbsp;</td><td><center>m1</center></td><td><center>d</center></td><td><center><b>m2</b></center></td></tr>";
2137
		$form .= "<tr><td><input type=\"checkbox\" id=\"upperlimit\" name=\"upperlimit\"";
2138
		if ($this->GetUpperlimit()<> "") {
2139
			$form .=  " checked=\"checked\" ";
2140
		}
2141
		$form .= "onchange=\"enable_upperlimit()\" /> " . gettext("Upperlimit:") . "</td><td><input size=\"6\" value=\"";
2142
		$form .= htmlspecialchars($this->GetU_m1());
2143
		$form .= "\" id=\"upperlimit1\" name=\"upperlimit1\" ";
2144
		if ($this->GetUpperlimit() == "") {
2145
			$form .= " disabled=\"disabled\"";
2146
		}
2147
		$form .= " /></td><td><input size=\"6\" value=\"";
2148
		$form .= htmlspecialchars($this->GetU_d());
2149
		$form .= "\" id=\"upperlimi2\" name=\"upperlimit2\" ";
2150
		if ($this->GetUpperlimit() == "") {
2151
			$form .= " disabled=\"disabled\"";
2152
		}
2153
		$form .= " /></td><td><input size=\"6\" value=\"";
2154
		$form .= htmlspecialchars($this->GetU_m2());
2155
		$form .= "\" id=\"upperlimit3\" name=\"upperlimit3\" ";
2156
		if ($this->GetUpperlimit() == "") {
2157
			$form .= " disabled=\"disabled\"";
2158
		}
2159
		$form .= " /></td><td>" . gettext("The maximum allowed bandwidth for the queue.") . "</td></tr>";
2160
		$form .= "<tr><td><input type=\"checkbox\" id=\"realtime\" name=\"realtime\"";
2161
		if ($this->GetRealtime() <> "") {
2162
			$form .=  " checked=\"checked\" ";
2163
		}
2164
		$form .= "onchange=\"enable_realtime()\" /> " . gettext("Real time:") . "</td><td><input size=\"6\" value=\"";
2165
		$form .= htmlspecialchars($this->GetR_m1());
2166
		$form .= "\" id=\"realtime1\" name=\"realtime1\" ";
2167
		if ($this->GetRealtime() == "") {
2168
			$form .= " disabled=\"disabled\"";
2169
		}
2170
		$form .= " /></td><td><input size=\"6\" value=\"";
2171
		$form .= htmlspecialchars($this->GetR_d());
2172
		$form .= "\" id=\"realtime2\" name=\"realtime2\" ";
2173
		if ($this->GetRealtime() == "") {
2174
			$form .= " disabled=\"disabled\"";
2175
		}
2176
		$form .= " /></td><td><input size=\"6\" value=\"";
2177
		$form .= htmlspecialchars($this->GetR_m2());
2178
		$form .= "\" id=\"realtime3\" name=\"realtime3\" ";
2179
		if ($this->GetRealtime() == "") {
2180
			$form .= " disabled=\"disabled\"";
2181
		}
2182
		$form .= " /></td><td>" . gettext("The minimum required bandwidth for the queue.") . "</td></tr>";
2183
		$form .= "<tr><td><input type=\"checkbox\" id=\"linkshare\" name=\"linkshare\"";
2184
		if ($this->GetLinkshare() <> "") {
2185
			$form .=  " checked=\"checked\" ";
2186
		}
2187
		$form .= "onchange=\"enable_linkshare()\" /> " . gettext("Link share:") . "</td><td><input size=\"6\" value=\"";
2188
		$form .= htmlspecialchars($this->GetL_m1());
2189
		$form .= "\" id=\"linkshare1\" name=\"linkshare1\" ";
2190
		if ($this->GetLinkshare() == "") {
2191
			$form .= " disabled=\"disabled\"";
2192
		}
2193
		$form .= " /></td><td><input size=\"6\" value=\"";
2194
		$form .= htmlspecialchars($this->GetL_d());
2195
		$form .= "\" id=\"linkshare2\" name=\"linkshare2\" ";
2196
		if ($this->GetLinkshare() == "") {
2197
			$form .= " disabled=\"disabled\"";
2198
		}
2199
		$form .= " /></td><td><input size=\"6\" value=\"";
2200
		$form .= htmlspecialchars($this->GetL_m2());
2201
		$form .= "\" id=\"linkshare3\" name=\"linkshare3\" ";
2202
		if ($this->GetLinkshare() == "") {
2203
			$form .= " disabled=\"disabled\"";
2204
		}
2205
		$form .= " /></td><td>" . gettext("The bandwidth share of a backlogged queue - this overrides priority.") . "</td></tr>";
2206
		$form .= "</table><br />";
2207
		$form .= gettext("The format for service curve specifications is (m1, d, m2).  m2 controls "
2208
			  .  "the bandwidth assigned to the queue.  m1 and d are optional and can be "
2209
			  .  "used to control the initial bandwidth assignment.  For the first d milliseconds the queue gets the bandwidth given as m1, afterwards the value "
2210
			  .  "given in m2.");
2211
		$form .= "</td>";
2212
		$form .= "</tr>";
2213

    
2214
		return $form;
2215
	}
2216

    
2217
	function update_altq_queue_data(&$data) {
2218
		$this->ReadConfig($data);
2219
	}
2220

    
2221
	function wconfig() {
2222
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2223
		if (!is_array($cflink)) {
2224
			$cflink = array();
2225
		}
2226
		$cflink['name'] = $this->GetQname();
2227
		$cflink['interface'] = $this->GetInterface();
2228
		$cflink['qlimit'] = trim($this->GetQlimit());
2229
		if (empty($cflink['qlimit'])) {
2230
			unset($cflink['qlimit']);
2231
		}
2232
		$cflink['priority'] = $this->GetQpriority();
2233
		if (empty($cflink['priority'])) {
2234
			unset($cflink['priority']);
2235
		}
2236
		$cflink['description'] = $this->GetDescription();
2237
		if (empty($cflink['description'])) {
2238
			unset($cflink['description']);
2239
		}
2240
		$cflink['bandwidth'] = $this->GetBandwidth();
2241
		$cflink['bandwidthtype'] = $this->GetBwscale();
2242
		$cflink['enabled'] = $this->GetEnabled();
2243
		if (empty($cflink['enabled'])) {
2244
			unset($cflink['enabled']);
2245
		}
2246
		$cflink['default'] = $this->GetDefault();
2247
		if (empty($cflink['default'])) {
2248
			unset($cflink['default']);
2249
		}
2250
		$cflink['red'] = trim($this->GetRed());
2251
		if (empty($cflink['red'])) {
2252
			unset($cflink['red']);
2253
		}
2254
		$cflink['rio'] = $this->GetRio();
2255
		if (empty($cflink['rio'])) {
2256
			unset($cflink['rio']);
2257
		}
2258
		$cflink['ecn'] = trim($this->GetEcn());
2259
		if (empty($cflink['ecn'])) {
2260
			unset($cflink['ecn']);
2261
		}
2262
		$cflink['codel'] = trim($this->GetCodel());
2263
		if (empty($cflink['codel'])) {
2264
			unset($cflink['codel']);
2265
		}
2266
		if ($this->GetLinkshare() <> "") {
2267
			if ($this->GetL_m1() <> "") {
2268
				$cflink['linkshare1'] = $this->GetL_m1();
2269
				$cflink['linkshare2'] = $this->GetL_d();
2270
				$cflink['linkshare'] = "on";
2271
			} else {
2272
				unset($cflink['linkshare']);
2273
				unset($cflink['linkshare1']);
2274
				unset($cflink['linkshare2']);
2275
			}
2276
			if ($this->GetL_m2() <> "") {
2277
				$cflink['linkshare3'] = $this->GetL_m2();
2278
				$cflink['linkshare'] = "on";
2279
			} else {
2280
				unset($cflink['linkshare']);
2281
				unset($cflink['linkshare3']);
2282
			}
2283
		} else {
2284
			unset($cflink['linkshare']);
2285
			unset($cflink['linkshare1']);
2286
			unset($cflink['linkshare2']);
2287
			unset($cflink['linkshare3']);
2288
		}
2289
		if ($this->GetRealtime() <> "") {
2290
			if ($this->GetR_m1() <> "") {
2291
				$cflink['realtime1'] = $this->GetR_m1();
2292
				$cflink['realtime2'] = $this->GetR_d();
2293
				$cflink['realtime'] = "on";
2294
			} else {
2295
				unset($cflink['realtime']);
2296
				unset($cflink['realtime1']);
2297
				unset($cflink['realtime2']);
2298
			}
2299
			if ($this->GetR_m2() <> "") {
2300
				$cflink['realtime3'] = $this->GetR_m2();
2301
				$cflink['realtime'] = "on";
2302
			} else {
2303
				unset($cflink['realtime']);
2304
				unset($cflink['realtime3']);
2305
			}
2306
		} else {
2307
			unset($cflink['realtime']);
2308
			unset($cflink['realtime1']);
2309
			unset($cflink['realtime2']);
2310
			unset($cflink['realtime3']);
2311
		}
2312
		if ($this->GetUpperlimit() <> "") {
2313
			if ($this->GetU_m1() <> "") {
2314
				$cflink['upperlimit1'] = $this->GetU_m1();
2315
				$cflink['upperlimit2'] = $this->GetU_d();
2316
				$cflink['upperlimit'] = "on";
2317
			} else {
2318
				unset($cflink['upperlimit']);
2319
				unset($cflink['upperlimit1']);
2320
				unset($cflink['upperlimit2']);
2321
			}
2322
			if ($this->GetU_m2() <> "") {
2323
				$cflink['upperlimit3'] = $this->GetU_m2();
2324
				$cflink['upperlimit'] = "on";
2325
			} else {
2326
				unset($cflink['upperlimit']);
2327
				unset($cflink['upperlimit3']);
2328
			}
2329
		} else {
2330
			unset($cflink['upperlimit']);
2331
			unset($cflink['upperlimit1']);
2332
			unset($cflink['upperlimit2']);
2333
			unset($cflink['upperlimit3']);
2334
		}
2335
	}
2336
}
2337

    
2338
class cbq_queue extends priq_queue {
2339
	var $qborrow = "";
2340

    
2341
	function GetBorrow() {
2342
		return $this->qborrow;
2343
	}
2344
	function SetBorrow($borrow) {
2345
		$this->qborrow = $borrow;
2346
	}
2347
	function CanHaveChildren() {
2348
		return true;
2349
	}
2350

    
2351
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2352

    
2353
		if (!is_array($this->subqueues)) {
2354
			$this->subqueues = array();
2355
		}
2356
		$q =& new cbq_queue();
2357
		$q->SetInterface($this->GetInterface());
2358
		$q->SetParent($this);
2359
		$q->ReadConfig($qname);
2360
		$q->validate_input($qname, $input_errors);
2361
		if (count($input_errors)) {
2362
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
2363
			return $q;
2364
		}
2365
		switch ($q->GetBwscale()) {
2366
			case "%":
2367
				$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
2368
				break;
2369
			default:
2370
				$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
2371
				break;
2372
		}
2373
		$q->SetAvailableBandwidth($myBw);
2374
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
2375

    
2376
		$q->SetEnabled("on");
2377
		$q->SetLink($path);
2378
		$this->subqueues[$q->GetQName()] = &$q;
2379
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2380
		if (is_array($qname['queue'])) {
2381
			foreach ($qname['queue'] as $key1 => $que) {
2382
				array_push($path, $key1);
2383
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
2384
				array_pop($path);
2385
			}
2386
		}
2387

    
2388
		return $q;
2389
	}
2390

    
2391
	function copy_queue($interface, &$cflink) {
2392

    
2393
		$cflink['interface'] = $interface;
2394
		$cflink['qlimit'] = trim($this->GetQlimit());
2395
		if (empty($clink['qlimit'])) {
2396
			unset($cflink['qlimit']);
2397
		}
2398
		$cflink['priority'] = trim($this->GetQpriority());
2399
		if (empty($cflink['priority'])) {
2400
			unset($cflink['priority']);
2401
		}
2402
		$cflink['name'] = $this->GetQname();
2403
		$cflink['description'] = trim($this->GetDescription());
2404
		if (empty($cflink['description'])) {
2405
			unset($cflink['description']);
2406
		}
2407
		$cflink['bandwidth'] = $this->GetBandwidth();
2408
		$cflink['bandwidthtype'] = $this->GetBwscale();
2409
		$cflink['enabled'] = trim($this->GetEnabled());
2410
		if (empty($cflink['enabled'])) {
2411
			unset($cflink['enabled']);
2412
		}
2413
		$cflink['default'] = trim($this->GetDefault());
2414
		if (empty($cflink['default'])) {
2415
			unset($cflink['default']);
2416
		}
2417
		$cflink['red'] = trim($this->GetRed());
2418
		if (empty($cflink['red'])) {
2419
			unset($cflink['red']);
2420
		}
2421
		$cflink['rio'] = trim($this->GetRio());
2422
		if (empty($cflink['rio'])) {
2423
			unset($cflink['rio']);
2424
		}
2425
		$cflink['ecn'] = trim($this->GetEcn());
2426
		if (empty($cflink['ecn'])) {
2427
			unset($cflink['ecn']);
2428
		}
2429
		$cflink['borrow'] = trim($this->GetBorrow());
2430
		if (empty($cflink['borrow'])) {
2431
			unset($cflink['borrow']);
2432
		}
2433
		if (is_array($this->queues)) {
2434
			$cflinkp['queue'] = array();
2435
			foreach ($this->subqueues as $q) {
2436
				$cflink['queue'][$q->GetQname()] = array();
2437
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
2438
			}
2439
		}
2440
	}
2441

    
2442
	/*
2443
	 * Should search even its children
2444
	 */
2445
	function &find_queue($interface, $qname) {
2446
		if ($qname == $this->GetQname()) {
2447
			return $this;
2448
		}
2449
		foreach ($this->subqueues as $q) {
2450
			$result =& $q->find_queue("", $qname);
2451
			if ($result) {
2452
				return $result;
2453
			}
2454
		}
2455
	}
2456

    
2457
	function &find_parentqueue($interface, $qname) {
2458
		if ($this->subqueues[$qname]) {
2459
			return $this;
2460
		}
2461
		foreach ($this->subqueues as $q) {
2462
			$result = $q->find_parentqueue("", $qname);
2463
			if ($result) {
2464
				return $result;
2465
			}
2466
		}
2467
	}
2468

    
2469
	function delete_queue() {
2470
		unref_on_altq_queue_list($this->GetQname());
2471
		cleanup_queue_from_rules($this->GetQname());
2472
		foreach ($this->subqueues as $q) {
2473
			$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
2474
				$q->delete_queue();
2475
		}
2476
		unset_object_by_reference($this->GetLink());
2477
	}
2478

    
2479
	function validate_input($data, &$input_errors) {
2480
		parent::validate_input($data, $input_errors);
2481

    
2482
		if ($data['priority'] > 7) {
2483
				$input_errors[] = gettext("Priority must be an integer between 1 and 7.");
2484
		}
2485
		$reqdfields[] = "bandwidth";
2486
		$reqdfieldsn[] = gettext("Bandwidth");
2487
		$reqdfields[] = "bandwidthtype";
2488
		$reqdfieldsn[] = gettext("Bandwidthtype");
2489

    
2490
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2491

    
2492
		if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
2493
			$input_errors[] = gettext("Bandwidth must be an integer.");
2494
		}
2495

    
2496

    
2497
		if ($data['bandwidth'] < 0) {
2498
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2499
		}
2500

    
2501
		if ($data['bandwidthtype'] == "%") {
2502
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
2503
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2504
			}
2505
		}
2506

    
2507
/*
2508
		$parent =& $this->GetParent();
2509
		switch ($data['bandwidthtype']) {
2510
		case "%":
2511
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2512
			break;
2513
		default:
2514
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2515
			break;
2516
		}
2517
		if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
2518
			$input_errors[] = "The sum of the children bandwidth exceeds that of the parent.";
2519
		}
2520
 */
2521
	}
2522

    
2523
	function ReadConfig(&$q) {
2524
		parent::ReadConfig($q);
2525
		if (!empty($q['borrow'])) {
2526
			$this->SetBorrow("on");
2527
		} else {
2528
			$this->SetBorrow("");
2529
		}
2530
	}
2531

    
2532
	function build_javascript() {
2533
		return parent::build_javascript();
2534
	}
2535

    
2536
	function build_tree() {
2537
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2538
		$tree .= "\" ";
2539
		$tmpvalue = trim($this->GetDefault());
2540
		if (!empty($tmpvalue)) {
2541
			$tree .= " class=\"navlnk\"";
2542
		}
2543
		$tree .= " >" . $this->GetQname() . "</a>";
2544
		if (is_array($this->subqueues)) {
2545
			$tree .= "<ul>";
2546
			foreach ($this->subqueues as $q)  {
2547
				$tree .= $q->build_tree();
2548
			}
2549
			$tree .= "</ul>";
2550
		}
2551
		$tree .= "</li>";
2552
		return $tree;
2553
	}
2554

    
2555
	/* Even this should take children into consideration */
2556
	function build_rules(&$default = false) {
2557
		$pfq_rule = "queue ". $this->qname;
2558
		if ($this->GetInterface()) {
2559
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2560
		}
2561
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2562
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2563
		}
2564
		$tmpvalue = $this->GetQpriority();
2565
		if (!empty($tmpvalue)) {
2566
			$pfq_rule .= " priority " . $this->GetQpriority();
2567
		}
2568
		$tmpvalue = trim($this->GetQlimit());
2569
		if (!empty($tmpvalue)) {
2570
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2571
		}
2572
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow() || $this->GetCodel()) {
2573
			$pfq_rule .= " cbq ( ";
2574
			$tmpvalue = trim($this->GetRed());
2575
			if (!empty($tmpvalue)) {
2576
				$comma = 1;
2577
				$pfq_rule .= " red ";
2578
			}
2579
			$tmpvalue = trim($this->GetCodel());
2580
			if (!empty($tmpvalue)) {
2581
				$comma = 1;
2582
				$pfq_rule .= " codel ";
2583
			}
2584
			$tmpvalue = trim($this->GetRio());
2585
			if (!empty($tmpvalue)) {
2586
				if ($comma) {
2587
					$pfq_rule .= " ,";
2588
				}
2589
				$comma = 1;
2590
				$pfq_rule .= " rio ";
2591
			}
2592
			$tmpvalue = trim($this->GetEcn());
2593
			if (!empty($tmpvalue)) {
2594
				if ($comma) {
2595
					$pfq_rule .= " ,";
2596
				}
2597
				$comma = 1;
2598
				$pfq_rule .= " ecn ";
2599
			}
2600
			$tmpvalue = trim($this->GetDefault());
2601
			if (!empty($tmpvalue)) {
2602
				if ($comma) {
2603
					$pfq_rule .= " ,";
2604
				}
2605
				$comma = 1;
2606
				$pfq_rule .= " default ";
2607
				$default = true;
2608
			}
2609
			$tmpvalue = trim($this->GetBorrow());
2610
			if (!empty($tmpvalue)) {
2611
				if ($comma) {
2612
					$pfq_rule .= ", ";
2613
				}
2614
				$pfq_rule .= " borrow ";
2615
			}
2616
			$pfq_rule .= " ) ";
2617
		}
2618
		if (count($this->subqueues)) {
2619
			$i = count($this->subqueues);
2620
			$pfq_rule .= " { ";
2621
			foreach ($this->subqueues as $qkey => $qnone) {
2622
				if ($i > 1) {
2623
					$i--;
2624
					$pfq_rule .= " {$qkey}, ";
2625
				} else {
2626
					$pfq_rule .= " {$qkey} ";
2627
				}
2628
			}
2629
			$pfq_rule .= " } \n";
2630
			foreach ($this->subqueues as $q) {
2631
				$pfq_rule .= $q->build_rules($default);
2632
			}
2633
		}
2634

    
2635
		$pfq_rule .= " \n";
2636
		return $pfq_rule;
2637
	}
2638

    
2639
	function build_form() {
2640
		$form = parent::build_form();
2641
		$form .= "<tr>";
2642
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
2643
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2644
		if ($this->GetBandwidth() > 0) {
2645
			$form .= htmlspecialchars($this->GetBandwidth());
2646
		}
2647
		$form .= "\" />";
2648
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2649
		$form .= "<option value=\"Gb\"";
2650
		if ($this->GetBwscale() == "Gb") {
2651
			$form .= " selected=\"selected\"";
2652
		}
2653
		$form .= ">" . gettext("Gbit/s") . "</option>";
2654
		$form .= "<option value=\"Mb\"";
2655
		if ($this->GetBwscale() == "Mb") {
2656
			$form .= " selected=\"selected\"";
2657
		}
2658
		$form .= ">" . gettext("Mbit/s") . "</option>";
2659
		$form .= "<option value=\"Kb\"";
2660
		if ($this->GetBwscale() == "Kb") {
2661
			$form .= " selected=\"selected\"";
2662
		}
2663
		$form .= ">" . gettext("Kbit/s") . "</option>";
2664
		$form .= "<option value=\"b\"";
2665
		if ($this->GetBwscale() == "b") {
2666
			$form .= " selected=\"selected\"";
2667
		}
2668
		$form .= ">" . gettext("Bit/s") . "</option>";
2669
		$form .= "<option value=\"%\"";
2670
		if ($this->GetBwscale() == "%") {
2671
			$form .= " selected=\"selected\"";
2672
		}
2673
		$form .= ">%</option>";
2674
		$form .= "</select> <br />";
2675
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
2676
		$form .= "</span></td></tr>";
2677
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
2678
		$form .= "<td class=\"vtable\"><input type=\"checkbox\" id=\"borrow\" name=\"borrow\"";
2679
		if ($this->GetBorrow() == "on") {
2680
			$form .=  " checked=\"checked\" ";
2681
		}
2682
		$form .= " /> " . gettext("Borrow from other queues when available") . "<br /></td></tr>";
2683

    
2684
		return $form;
2685
	}
2686

    
2687
	function update_altq_queue_data(&$data) {
2688
		$this->ReadConfig($data);
2689
	}
2690

    
2691
	function wconfig() {
2692
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2693
		if (!is_array($cflink)) {
2694
			$cflink = array();
2695
		}
2696
		$cflink['interface'] = $this->GetInterface();
2697
		$cflink['qlimit'] = trim($this->GetQlimit());
2698
		if (empty($cflink['qlimit'])) {
2699
			unset($cflink['qlimit']);
2700
		}
2701
		$cflink['priority'] = $this->GetQpriority();
2702
		if (empty($cflink['priority'])) {
2703
			unset($cflink['priority']);
2704
		}
2705
		$cflink['name'] = $this->GetQname();
2706
		$cflink['description'] = $this->GetDescription();
2707
		if (empty($cflink['description'])) {
2708
			unset($cflink['description']);
2709
		}
2710
		$cflink['bandwidth'] = $this->GetBandwidth();
2711
		$cflink['bandwidthtype'] = $this->GetBwscale();
2712
		$cflink['enabled'] = trim($this->GetEnabled());
2713
		if (empty($cflink['enabled'])) {
2714
			unset($cflink['enabled']);
2715
		}
2716
		$cflink['default'] = trim($this->GetDefault());
2717
		if (empty($cflink['default'])) {
2718
			unset($cflink['default']);
2719
		}
2720
		$cflink['red'] = trim($this->GetRed());
2721
		if (empty($cflink['red'])) {
2722
			unset($cflink['red']);
2723
		}
2724
		$cflink['rio'] = trim($this->GetRio());
2725
		if (empty($cflink['rio'])) {
2726
			unset($cflink['rio']);
2727
		}
2728
		$cflink['ecn'] = trim($this->GetEcn());
2729
		if (empty($cflink['ecn'])) {
2730
			unset($cflink['ecn']);
2731
		}
2732
		$cflink['codel'] = trim($this->GetCodel());
2733
		if (empty($cflink['codel'])) {
2734
			unset($cflink['codel']);
2735
		}
2736
		$cflink['borrow'] = trim($this->GetBorrow());
2737
		if (empty($cflink['borrow'])) {
2738
			unset($cflink['borrow']);
2739
		}
2740
	}
2741
}
2742

    
2743
class fairq_queue extends priq_queue {
2744
	var $hogs;
2745
	var $buckets;
2746

    
2747
	function GetBuckets() {
2748
		return $this->buckets;
2749
	}
2750
	function SetBuckets($buckets) {
2751
		$this->buckets = $buckets;
2752
	}
2753
	function GetHogs() {
2754
		return $this->hogs;
2755
	}
2756
	function SetHogs($hogs) {
2757
		$this->hogs = $hogs;
2758
	}
2759
	function CanHaveChildren() {
2760
		return false;
2761
	}
2762

    
2763

    
2764
	function copy_queue($interface, &$cflink) {
2765
		$cflink['interface'] = $interface;
2766
		$cflink['qlimit'] = $this->GetQlimit();
2767
		$cflink['priority'] = $this->GetQpriority();
2768
		$cflink['name'] = $this->GetQname();
2769
		$cflink['description'] = $this->GetDescription();
2770
		$cflink['bandwidth'] = $this->GetBandwidth();
2771
		$cflink['bandwidthtype'] = $this->GetBwscale();
2772
		$cflink['enabled'] = $this->GetEnabled();
2773
		$cflink['default'] = $this->GetDefault();
2774
		$cflink['red'] = $this->GetRed();
2775
		$cflink['rio'] = $this->GetRio();
2776
		$cflink['ecn'] = $this->GetEcn();
2777
		$cflink['buckets'] = $this->GetBuckets();
2778
		$cflink['hogs'] = $this->GetHogs();
2779
	}
2780

    
2781
	/*
2782
	 * Should search even its children
2783
	 */
2784
	function &find_queue($interface, $qname) {
2785
		if ($qname == $this->GetQname()) {
2786
			return $this;
2787
		}
2788
	}
2789

    
2790
	function find_parentqueue($interface, $qname) { return; }
2791

    
2792
	function delete_queue() {
2793
		unref_on_altq_queue_list($this->GetQname());
2794
		cleanup_queue_from_rules($this->GetQname());
2795
		unset_object_by_reference($this->GetLink());
2796
	}
2797

    
2798
	function validate_input($data, &$input_errors) {
2799
		parent::validate_input($data, $input_errors);
2800

    
2801
		if ($data['priority'] > 255) {
2802
				$input_errors[] = gettext("Priority must be an integer between 1 and 255.");
2803
		}
2804
		$reqdfields[] = "bandwidth";
2805
		$reqdfieldsn[] = gettext("Bandwidth");
2806
		$reqdfields[] = "bandwidthtype";
2807
		$reqdfieldsn[] = gettext("Bandwidthtype");
2808

    
2809
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2810

    
2811
		if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
2812
			$input_errors[] = gettext("Bandwidth must be an integer.");
2813
		}
2814

    
2815

    
2816
		if ($data['bandwidth'] < 0) {
2817
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2818
		}
2819

    
2820

    
2821
		if ($data['bandwidthtype'] == "%") {
2822
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
2823
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2824
			}
2825
		}
2826

    
2827
/*
2828
		$parent =& $this->GetParent();
2829
		switch ($data['bandwidthtype']) {
2830
		case "%":
2831
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2832
		default:
2833
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2834
			break;
2835
		}
2836
		if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
2837
			$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
2838
		}
2839
*/
2840
	}
2841

    
2842
	function ReadConfig(&$q) {
2843
		parent::ReadConfig($q);
2844
		if (!empty($q['buckets'])) {
2845
			$this->SetBuckets($q['buckets']);
2846
		} else {
2847
			$this->SetBuckets("");
2848
		}
2849
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs'])) {
2850
			$this->SetHogs($q['hogs']);
2851
		} else {
2852
			$this->SetHogs("");
2853
		}
2854
	}
2855

    
2856
	function build_javascript() {
2857
		return parent::build_javascript();
2858
	}
2859

    
2860
	function build_tree() {
2861
		$tree = " <li><a href=\"firewall_shaper.php?interface=" .
2862
		$this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2863
		$tree .= "\" ";
2864
		$tmpvalue = trim($this->GetDefault());
2865
		if (!empty($tmpvalue)) {
2866
			$tree .= " class=\"navlnk\"";
2867
		}
2868
		$tree .= " >" . $this->GetQname() . "</a>";
2869
		$tree .= "</li>";
2870
		return $tree;
2871
	}
2872

    
2873
	/* Even this should take children into consideration */
2874
	function build_rules(&$default = false) {
2875
		$pfq_rule = "queue ". $this->qname;
2876
		if ($this->GetInterface()) {
2877
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2878
		}
2879
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2880
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2881
		}
2882
		$tmpvalue = trim($this->GetQpriority());
2883
		if (!empty($tmpvalue)) {
2884
			$pfq_rule .= " priority " . $this->GetQpriority();
2885
		}
2886
		$tmpvalue = trim($this->GetQlimit());
2887
		if (!empty($tmpvalue)) {
2888
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2889
		}
2890
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() ||
2891
		    $this->GetEcn() || $this->GetBuckets() || $this->GetHogs() || $this->GetCodel()) {
2892
			$pfq_rule .= " fairq ( ";
2893
			$tmpvalue = trim($this->GetRed());
2894
			if (!empty($tmpvalue)) {
2895
				$comma = 1;
2896
				$pfq_rule .= " red ";
2897
			}
2898
			$tmpvalue = trim($this->GetCodel());
2899
			if (!empty($tmpvalue)) {
2900
				$comma = 1;
2901
				$pfq_rule .= " codel ";
2902
			}
2903
			$tmpvalue = trim($this->GetRio());
2904
			if (!empty($tmpvalue)) {
2905
				if ($comma) {
2906
					$pfq_rule .= " ,";
2907
				}
2908
				$comma = 1;
2909
				$pfq_rule .= " rio ";
2910
			}
2911
			$tmpvalue = trim($this->GetEcn());
2912
			if (!empty($tmpvalue)) {
2913
				if ($comma) {
2914
					$pfq_rule .= " ,";
2915
				}
2916
				$comma = 1;
2917
				$pfq_rule .= " ecn ";
2918
			}
2919
			$tmpvalue = trim($this->GetDefault());
2920
			if (!empty($tmpvalue)) {
2921
				if ($comma) {
2922
					$pfq_rule .= " ,";
2923
				}
2924
				$comma = 1;
2925
				$pfq_rule .= " default ";
2926
				$default = true;
2927
			}
2928
			$tmpvalue = trim($this->GetBuckets());
2929
			if (!empty($tmpvalue)) {
2930
				if ($comma) {
2931
					$pfq_rule .= ", ";
2932
				}
2933
				$pfq_rule .= " buckets " . $this->GetBuckets() . " ";
2934
			}
2935
			$tmpvalue = trim($this->GetHogs());
2936
			if (!empty($tmpvalue)) {
2937
				if ($comma) {
2938
					$pfq_rule .= ", ";
2939
				}
2940
				$pfq_rule .= " hogs " . $this->GetHogs() . " ";
2941
			}
2942
			$pfq_rule .= " ) ";
2943
		}
2944

    
2945
		$pfq_rule .= " \n";
2946
		return $pfq_rule;
2947
	}
2948

    
2949
	function build_form() {
2950
		$form = parent::build_form();
2951
		$form .= "<tr>";
2952
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
2953
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2954
		if ($this->GetBandwidth() > 0) {
2955
			$form .= htmlspecialchars($this->GetBandwidth());
2956
		}
2957
		$form .= "\" />";
2958
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2959
		$form .= "<option value=\"Gb\"";
2960
		if ($this->GetBwscale() == "Gb") {
2961
			$form .= " selected=\"selected\"";
2962
		}
2963
		$form .= ">" . gettext("Gbit/s") . "</option>";
2964
		$form .= "<option value=\"Mb\"";
2965
		if ($this->GetBwscale() == "Mb") {
2966
			$form .= " selected=\"selected\"";
2967
		}
2968
		$form .= ">" . gettext("Mbit/s") . "</option>";
2969
		$form .= "<option value=\"Kb\"";
2970
		if ($this->GetBwscale() == "Kb") {
2971
			$form .= " selected=\"selected\"";
2972
		}
2973
		$form .= ">" . gettext("Kbit/s") . "</option>";
2974
		$form .= "<option value=\"b\"";
2975
		if ($this->GetBwscale() == "b") {
2976
			$form .= " selected=\"selected\"";
2977
		}
2978
		$form .= ">" . gettext("Bit/s") . "</option>";
2979
		$form .= "<option value=\"%\"";
2980
		if ($this->GetBwscale() == "%") {
2981
			$form .= " selected=\"selected\"";
2982
		}
2983
		$form .= ">%</option>";
2984
		$form .= "</select> <br />";
2985
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
2986
		$form .= "</span></td></tr>";
2987
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
2988
		$form .= "<td class=\"vtable\"><table><tr><td>";
2989
		$form .= "<input id=\"buckets\" name=\"buckets\" value=\"";
2990
		$tmpvalue = trim($this->GetBuckets());
2991
		if (!empty($tmpvalue)) {
2992
			$form .=  $this->GetBuckets();
2993
		}
2994
		$form .= "\" /> " . gettext("Number of buckets available.") . "<br /></td></tr>";
2995
		$form .= "<tr><td class=\"vtable\"><input id=\"hogs\" name=\"hogs\" value=\"";
2996
		$tmpvalue = trim($this->GetHogs());
2997
		if (!empty($tmpvalue)) {
2998
			$form .=  $this->GetHogs();
2999
		}
3000
		$form .= "\" /> " . gettext("Bandwidth limit for hosts to not saturate link.") . "<br /></td></tr>";
3001
		$form .= "</table></td></tr>";
3002
		return $form;
3003
	}
3004

    
3005
	function update_altq_queue_data(&$data) {
3006
		$this->ReadConfig($data);
3007
	}
3008

    
3009
	function wconfig() {
3010
		$cflink =& get_reference_to_me_in_config($this->GetLink());
3011
		if (!is_array($cflink)) {
3012
			$cflink = array();
3013
		}
3014
		$cflink['interface'] = $this->GetInterface();
3015
		$cflink['qlimit'] = trim($this->GetQlimit());
3016
		if (empty($cflink['qlimit'])) {
3017
			unset($cflink['qlimit']);
3018
		}
3019
		$cflink['priority'] = trim($this->GetQpriority());
3020
		if (empty($cflink['priority'])) {
3021
			unset($cflink['priority']);
3022
		}
3023
		$cflink['name'] = $this->GetQname();
3024
		$cflink['description'] = trim($this->GetDescription());
3025
		if (empty($cflink['description'])) {
3026
			unset($cflink['description']);
3027
		}
3028
		$cflink['bandwidth'] = $this->GetBandwidth();
3029
		$cflink['bandwidthtype'] = $this->GetBwscale();
3030
		$cflink['enabled'] = $this->GetEnabled();
3031
		if (empty($cflink['enabled'])) {
3032
			unset($cflink['enabled']);
3033
		}
3034
		$cflink['default'] = trim($this->GetDefault());
3035
		if (empty($cflink['default'])) {
3036
			unset($cflink['default']);
3037
		}
3038
		$cflink['red'] = trim($this->GetRed());
3039
		if (empty($cflink['red'])) {
3040
			unset($cflink['red']);
3041
		}
3042
		$cflink['rio'] = trim($this->GetRio());
3043
		if (empty($cflink['rio'])) {
3044
			unset($cflink['rio']);
3045
		}
3046
		$cflink['ecn'] = trim($this->GetEcn());
3047
		if (empty($cflink['ecn'])) {
3048
			unset($cflink['ecn']);
3049
		}
3050
		$cflink['codel'] = trim($this->GetCodel());
3051
		if (empty($cflink['codel'])) {
3052
			unset($cflink['codel']);
3053
		}
3054
		$cflink['buckets'] = trim($this->GetBuckets());
3055
		if (empty($cflink['buckets'])) {
3056
			unset($cflink['buckets']);
3057
		}
3058
		$cflink['hogs'] = trim($this->GetHogs());
3059
		if (empty($cflink['hogs'])) {
3060
			unset($cflink['hogs']);
3061
		}
3062
	}
3063
}
3064

    
3065

    
3066
/*
3067
 * dummynet(4) wrappers.
3068
 */
3069

    
3070

    
3071
/*
3072
 * List of respective objects!
3073
 */
3074
$dummynet_pipe_list = array();
3075

    
3076
class dummynet_class {
3077
	var $qname;
3078
	var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
3079
	var $qlimit;
3080
	var $description;
3081
	var $qenabled;
3082
	var $link;
3083
	var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
3084
	var $plr;
3085

    
3086
	var $buckets;
3087
	/* mask parameters */
3088
	var $mask;
3089
	var $noerror;
3090

    
3091
	/* Accessor functions */
3092
	function SetLink($link) {
3093
		$this->link = $link;
3094
	}
3095
	function GetLink() {
3096
		return $this->link;
3097
	}
3098
	function GetMask() {
3099
		if (!isset($this->mask["type"])) {
3100
			$this->mask["type"] = "none";
3101
		}
3102
		return $this->mask;
3103
	}
3104
	function SetMask($mask) {
3105
		$this->mask = $mask;
3106
	}
3107
	function &GetParent() {
3108
		return $this->qparent;
3109
	}
3110
	function SetParent(&$parent) {
3111
		$this->qparent = &$parent;
3112
	}
3113
	function GetEnabled() {
3114
		return $this->qenabled;
3115
	}
3116
	function SetEnabled($value) {
3117
		$this->qenabled = $value;
3118
	}
3119
	function CanHaveChildren() {
3120
		return false;
3121
	}
3122
	function CanBeDeleted() {
3123
		return true;
3124
	}
3125
	function GetQname() {
3126
		return $this->qname;
3127
	}
3128
	function SetQname($name) {
3129
		$this->qname = trim($name);
3130
	}
3131
	function GetQlimit() {
3132
		return $this->qlimit;
3133
	}
3134
	function SetQlimit($limit) {
3135
		$this->qlimit = $limit;
3136
	}
3137
	function GetDescription() {
3138
		return $this->description;
3139
	}
3140
	function SetDescription($str) {
3141
		$this->description = trim($str);
3142
	}
3143
	function GetFirstime() {
3144
		return $this->firsttime;
3145
	}
3146
	function SetFirsttime($number) {
3147
		$this->firsttime = $number;
3148
	}
3149
	function GetBuckets() {
3150
		return $this->buckets;
3151
	}
3152
	function SetBuckets($buckets) {
3153
		$this->buckets = $buckets;
3154
	}
3155
	function SetNumber($number) {
3156
		$this->qnumber = $number;
3157
	}
3158
	function GetNumber() {
3159
		return $this->qnumber;
3160
	}
3161
	function GetPlr() {
3162
		return $this->plr;
3163
	}
3164
	function SetPlr($plr) {
3165
		$this->plr = $plr;
3166
	}
3167

    
3168
	function build_javascript() {
3169
		$javascript .= "<script type=\"text/javascript\">\n";
3170
		$javascript .= "//<![CDATA[\n";
3171
		$javascript .= "function enable_maskbits(enable_over) {\n";
3172
		$javascript .= "var e = document.getElementById(\"mask\");\n";
3173
		$javascript .= "if ((e.options[e.selectedIndex].text == \"none\") || enable_over) {\n";
3174
		$javascript .= "document.iform.maskbits.disabled = 1;\n";
3175
		$javascript .= "document.iform.maskbits.value = \"\";\n";
3176
		$javascript .= "document.iform.maskbitsv6.disabled = 1;\n";
3177
		$javascript .= "document.iform.maskbitsv6.value = \"\";\n";
3178
		$javascript .= "} else {\n";
3179
		$javascript .= "document.iform.maskbits.disabled = 0;\n";
3180
		$javascript .= "document.iform.maskbitsv6.disabled = 0;\n";
3181
		$javascript .= "}}\n";
3182
		$javascript .= "//]]>\n";
3183
		$javascript .= "</script>\n";
3184
		return $javascript;
3185
	}
3186

    
3187
	function validate_input($data, &$input_errors) {
3188
		$reqdfields[] = "bandwidth";
3189
		$reqdfieldsn[] = gettext("Bandwidth");
3190
		/*$reqdfields[] = "burst";
3191
		$reqdfieldsn[] = gettext("Burst"); */
3192
		$reqdfields[] = "bandwidthtype";
3193
		$reqdfieldsn[] = gettext("Bandwidthtype");
3194
		$reqdfields[] = "newname";
3195
		$reqdfieldsn[] = gettext("Name");
3196

    
3197
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3198

    
3199
		if ($data['plr'] && (!is_numeric($data['plr']) ||
3200
		    ($data['plr'] < 0) || ($data['plr'] > 1))) {
3201
				$input_errors[] = gettext("Plr must be a value between 0 and 1.");
3202
		}
3203
		if ($data['buckets'] && (!is_numeric($data['buckets']) ||
3204
		    ($data['buckets'] < 16) || ($data['buckets'] > 65535))) {
3205
				$input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
3206
		}
3207
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
3208
			$input_errors[] = gettext("Queue limit must be an integer");
3209
		}
3210
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname'])) {
3211
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3212
		}
3213
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name'])) {
3214
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3215
		}
3216
		if (isset($data['maskbits']) && ($data['maskbits'] <> "")) {
3217
			if ((!is_numeric($data['maskbits'])) || ($data['maskbits'] <= 0) || ($data['maskbits'] > 32)) {
3218
				$input_errors[] = gettext("IPV4 bit mask must be blank or numeric value between 1 and 32.");
3219
			}
3220
		}
3221
		if (isset($data['maskbitsv6']) && ($data['maskbitsv6'] <> "")) {
3222
			if ((!is_numeric($data['maskbitsv6'])) || ($data['maskbitsv6'] <= 0) || ($data['maskbitsv6'] > 128)) {
3223
				$input_errors[] = gettext("IPV6 bit mask must be blank or numeric value between 1 and 128.");
3224
			}
3225
		}
3226
	}
3227

    
3228
	function build_mask_rules(&$pfq_rule) {
3229
		$mask = $this->GetMask();
3230
		if (!empty($mask['type'])) {
3231
			if ($mask['type'] <> 'none') {
3232
				$pfq_rule .= " mask";
3233
			}
3234
			switch ($mask['type']) {
3235
				case 'srcaddress':
3236
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3237
						$pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
3238
					} else {
3239
						$pfq_rule .= " src-ip6 /128";
3240
					}
3241
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3242
						$pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3243
					} else {
3244
						$pfq_rule .= " src-ip 0xffffffff";
3245
					}
3246
					break;
3247
				case 'dstaddress':
3248
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3249
						$pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
3250
					} else {
3251
						$pfq_rule .= " dst-ip6 /128";
3252
					}
3253
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3254
						$pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3255
					} else {
3256
						$pfq_rule .= " dst-ip 0xffffffff";
3257
					}
3258
					break;
3259
				default:
3260
					break;
3261
			}
3262
		}
3263
	}
3264

    
3265
}
3266

    
3267
class dnpipe_class extends dummynet_class {
3268
	var $delay;
3269
	var $qbandwidth = array();
3270
	var $qbandwidthtype;
3271

    
3272
		/* This is here to help on form building and building rules/lists */
3273
	var $subqueues = array();
3274

    
3275
	function CanHaveChildren() {
3276
		return true;
3277
	}
3278
	function SetDelay($delay) {
3279
		$this->delay = $delay;
3280
	}
3281
	function GetDelay() {
3282
		return $this->delay;
3283
	}
3284
	function delete_queue() {
3285
		cleanup_dnqueue_from_rules($this->GetQname());
3286
		foreach ($this->subqueues as $q) {
3287
			$q->delete_queue();
3288
		}
3289
		unset_dn_object_by_reference($this->GetLink());
3290
		@pfSense_pipe_action("pipe delete " . $this->GetNumber());
3291
	}
3292
	function GetBandwidth() {
3293
		return $this->qbandwidth;
3294
	}
3295
	function SetBandwidth($bandwidth) {
3296
		$this->qbandwidth = $bandwidth;
3297
	}
3298
	function GetBurst() {
3299
		return $this->qburst;
3300
	}
3301
	function SetBurst($burst) {
3302
		$this->qburst = $burst;
3303
	}
3304

    
3305
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
3306

    
3307
		if (!is_array($this->subqueues)) {
3308
			$this->subqueues = array();
3309
		}
3310

    
3311
		$q =& new dnqueue_class();
3312
		$q->SetLink($path);
3313
		$q->SetEnabled("on");
3314
		$q->SetPipe($this->GetQname());
3315
		$q->SetParent($this);
3316
		$q->ReadConfig($queue);
3317
		$q->validate_input($queue, $input_errors);
3318
		if (count($input_errors)) {
3319
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
3320
			return $q;
3321
		}
3322
		$number = dnqueue_find_nextnumber();
3323
		$q->SetNumber($number);
3324
		$this->subqueues[$q->GetQname()] = &$q;
3325

    
3326
		return $q;
3327
	}
3328

    
3329
	function &get_queue_list(&$q = null) {
3330
		$qlist = array();
3331

    
3332
		$qlist[$this->GetQname()] = $this->GetNumber();
3333
		if (is_array($this->subqueues)) {
3334
			foreach ($this->subqueues as $queue) {
3335
				$queue->get_queue_list($qlist);
3336
			}
3337
		}
3338
		return $qlist;
3339
	}
3340

    
3341
	/*
3342
	 * Should search even its children
3343
	 */
3344
	function &find_queue($pipe, $qname) {
3345
		if ($qname == $this->GetQname()) {
3346
			return $this;
3347
		}
3348
		foreach ($this->subqueues as $q) {
3349
			$result =& $q->find_queue("", $qname);
3350
			if ($result) {
3351
				return $result;
3352
			}
3353
		}
3354
	}
3355

    
3356
	function &find_parentqueue($pipe, $qname) {
3357
		return NULL;
3358
	}
3359

    
3360
	function validate_input($data, &$input_errors) {
3361
		parent::validate_input($data, $input_errors);
3362

    
3363
		$schedule = 0;
3364
		$schedulenone = 0;
3365
		$entries = 0;
3366
		/* XXX: Really no better way? */
3367
		for ($i = 0; $i < 2900; $i++) {
3368
			if (!empty($data["bwsched{$i}"])) {
3369
				if ($data["bwsched{$i}"] != "none") {
3370
					$schedule++;
3371
				} else {
3372
					$schedulenone++;
3373
				}
3374
			}
3375
			if (!empty($data["bandwidth{$i}"])) {
3376
				if (!is_numeric($data["bandwidth{$i}"])) {
3377
					$input_errors[] = sprintf(gettext("Bandwidth for schedule %s must be an integer."), $data["bwsched{$i}"]);
3378
				} else if (($data["burst{$i}"] != "") && (!is_numeric($data["burst{$i}"]))) {
3379
					$input_errors[] = sprintf(gettext("Burst for schedule %s must be an integer."), $data["bwsched{$i}"]);
3380
				} else {
3381
					$entries++;
3382
				}
3383
			}
3384
		}
3385
		if ($schedule == 0 && $entries > 1) {
3386
			$input_errors[] = gettext("You need to specify a schedule for every additional entry");
3387
		}
3388
		if ($schedulenone > 0 && $entries > 1) {
3389
			$input_errors[] = gettext("If more than one bandwidth configured all schedules need to be selected");
3390
		}
3391
		if ($entries == 0) {
3392
			$input_errors[] = gettext("At least one bw specification is necessary");
3393
		}
3394
		if ($data['delay'] && (!is_numeric($data['delay']))) {
3395
			$input_errors[] = gettext("Delay must be an integer.");
3396
		}
3397
	}
3398

    
3399
	function ReadConfig(&$q) {
3400
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3401
			$this->SetQname($q['newname']);
3402
		} else if (!empty($q['newname'])) {
3403
			$this->SetQname($q['newname']);
3404
		} else {
3405
			$this->SetQname($q['name']);
3406
		}
3407
		$this->SetNumber($q['number']);
3408

    
3409
		if (!empty($_POST)) {
3410
			$bandwidth = array();
3411
			/* XXX: Really no better way? */
3412
			for ($i = 0; $i < 2900; $i++) {
3413
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") {
3414
					$bw = array();
3415
					$bw['bw'] = $q["bandwidth{$i}"];
3416
					$bw['burst'] = $q["burst{$i}"];
3417
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"]) {
3418
						$bw['bwscale'] = $q["bwtype{$i}"];
3419
					}
3420
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"]) {
3421
						$bw['bwsched'] = $q["bwsched{$i}"];
3422
					}
3423
					$bandwidth[] = $bw;
3424
				}
3425
			}
3426
			$this->SetBandwidth($bandwidth);
3427
		}
3428

    
3429
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
3430
			$this->SetBandwidth($q['bandwidth']['item']);
3431
			$this->SetBurst($q['burst']['item']);
3432
		}
3433

    
3434
		if (isset($q['qlimit']) && $q['qlimit'] <> "") {
3435
			$this->SetQlimit($q['qlimit']);
3436
		} else {
3437
			$this->SetQlimit("");
3438
		}
3439
		if (isset($q['mask']) && $q['mask'] <> "") {
3440
			$masktype = $q['mask'];
3441
		} else {
3442
			$masktype = "";
3443
		}
3444
		if (isset($q['maskbits']) && $q['maskbits'] <> "") {
3445
			$maskbits = $q['maskbits'];
3446
		} else {
3447
			$maskbits = "";
3448
		}
3449
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
3450
			$maskbitsv6 = $q['maskbitsv6'];
3451
		} else {
3452
			$maskbitsv6 = "";
3453
		}
3454
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3455
		if (isset($q['buckets']) && $q['buckets'] <> "") {
3456
			$this->SetBuckets($q['buckets']);
3457
		} else {
3458
			$this->SetBuckets("");
3459
		}
3460
		if (isset($q['plr']) && $q['plr'] <> "") {
3461
			$this->SetPlr($q['plr']);
3462
		} else {
3463
			$this->SetPlr("");
3464
		}
3465
		if (isset($q['delay']) && $q['delay'] <> "") {
3466
			$this->SetDelay($q['delay']);
3467
		} else {
3468
			$this->SetDelay(0);
3469
		}
3470
		if (isset($q['description']) && $q['description'] <> "") {
3471
			$this->SetDescription($q['description']);
3472
		} else {
3473
			$this->SetDescription("");
3474
		}
3475
		$this->SetEnabled($q['enabled']);
3476

    
3477
	}
3478

    
3479
	function build_tree() {
3480
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&amp;queue=".$this->GetQname() ."&amp;action=show\">";
3481
		$tree .= $this->GetQname() . "</a>";
3482
		if (is_array($this->subqueues)) {
3483
			$tree .= "<ul>";
3484
			foreach ($this->subqueues as $q)  {
3485
				$tree .= $q->build_tree();
3486
			}
3487
			$tree .= "</ul>";
3488
		}
3489
		$tree .= "</li>";
3490

    
3491
		return $tree;
3492
	}
3493

    
3494
	function build_rules() {
3495
		global $config, $time_based_rules;
3496

    
3497
		if ($this->GetEnabled() == "") {
3498
			return;
3499
		}
3500

    
3501
		$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
3502
		$found = false;
3503
		$bandwidth = $this->GetBandwidth();
3504
		if (is_array($bandwidth)) {
3505
			foreach ($bandwidth as $bw) {
3506
				if ($bw['bwsched'] != "none") {
3507
					$time_based_rules = true;
3508
					if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3509
						foreach ($config['schedules']['schedule'] as $schedule) {
3510
							if ($bw['bwsched'] == $schedule['name']) {
3511
								if (filter_get_time_based_rule_status($schedule)) {
3512
									$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3513
									if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3514
										$pfq_rule .= " burst ".trim($bw['burst']);
3515
									}
3516
									$found = true;
3517
									break;
3518
								}
3519
							}
3520
						}
3521
					} else {
3522
						$pfq_rule .= " bw 0";
3523
						$found = true;
3524
						break;
3525
					}
3526
				} else {
3527
					$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3528
					if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3529
						$pfq_rule .= " burst ".trim($bw['burst']);
3530
					}
3531
					$found = true;
3532
					break;
3533
				}
3534
			}
3535
			if ($found == false) {
3536
				$pfq_rule .= " bw 0";
3537
			}
3538
		} else {
3539
			$pfq_rule .= " bw 0";
3540
		}
3541

    
3542
		if ($this->GetQlimit()) {
3543
			$pfq_rule .= " queue " . $this->GetQlimit();
3544
		}
3545
		if ($this->GetPlr()) {
3546
			$pfq_rule .= " plr " . $this->GetPlr();
3547
		}
3548
		if ($this->GetBuckets()) {
3549
			$pfq_rule .= " buckets " . $this->GetBuckets();
3550
		}
3551
		if ($this->GetDelay()) {
3552
			$pfq_rule .= " delay " . $this->GetDelay();
3553
		}
3554
		$this->build_mask_rules($pfq_rule);
3555

    
3556
		$pfq_rule .= "\n";
3557

    
3558
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3559
			foreach ($this->subqueues as $q) {
3560
				$pfq_rule .= $q->build_rules();
3561
			}
3562
		}
3563
		$pfq_rule .= " \n";
3564

    
3565
		return $pfq_rule;
3566
	}
3567

    
3568
	function update_dn_data(&$data) {
3569
		$this->ReadConfig($data);
3570
	}
3571

    
3572
	function build_javascript() {
3573
		global $g, $config;
3574

    
3575
		$javasr = parent::build_javascript();
3576

    
3577
		//build list of schedules
3578
		$schedules = "<option value='none'>none</option>";
3579
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3580
			foreach ($config['schedules']['schedule'] as $schedule) {
3581
				if ($schedule['name'] <> "") {
3582
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3583
				}
3584
			}
3585
		}
3586
		$bwopt = "";
3587
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw) {
3588
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3589
		}
3590

    
3591
		$javasr .= <<<EOD
3592
<script type='text/javascript'>
3593
//<![CDATA[
3594
var addBwRowTo = (function() {
3595
	return (function (tableId) {
3596
	var d, tbody, tr, td;
3597
	d = document;
3598
	tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0);
3599
	tr = d.createElement("tr");
3600
	td = d.createElement("td");
3601
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bandwidth_row-" + totalrows + "' /><input size='10' type='text' class='formfld unknown' name='bandwidth" + totalrows + "' id='bandwidth" + totalrows + "' />";
3602
	tr.appendChild(td);
3603
	//td = d.createElement("td");
3604
	//td.innerHTML="<input type='hidden' value='" + totalrows +"' name='burst_row-" + totalrows + "' /><input size='10' type='text' class='formfld unknown' name='burst" + totalrows + "' id='burst" + totalrows + "' />";
3605
	//tr.appendChild(td);
3606
	td = d.createElement("td");
3607
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "' /><select class='formselect' name='bwtype" + totalrows + "'>{$bwopt}</select>";
3608
	tr.appendChild(td);
3609
	td = d.createElement("td");
3610
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "' /><select class='formselect' name='bwsched" + totalrows + "'>{$schedules}</select>";
3611
	tr.appendChild(td);
3612
	td = d.createElement("td");
3613
	td.rowSpan = "1";
3614
	td.innerHTML = '<a onclick="removeBwRow(this); return false;" href="#"><img border="0" src="/themes/{$g['theme']}/images/icons/icon_x.gif" alt="remove" /></a>';
3615
	tr.appendChild(td);
3616
	tbody.appendChild(tr);
3617
	totalrows++;
3618
	});
3619
})();
3620

    
3621
function removeBwRow(el) {
3622
	var cel;
3623
	while (el && el.nodeName.toLowerCase() != "tr") {
3624
		el = el.parentNode;
3625
		if (el && el.parentNode) {
3626
			cel = el.getElementsByTagName("td").item(0);
3627
			el.parentNode.removeChild(el);
3628
		}
3629
	}
3630
}
3631
//]]>
3632
</script>
3633

    
3634
EOD;
3635

    
3636
		return $javasr;
3637
	}
3638

    
3639
	function build_form() {
3640
		global $g, $config;
3641

    
3642
		//build list of schedules
3643
		$schedules = array();
3644
		$schedules[] = "none";//leave none to leave rule enabled all the time
3645
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3646
			foreach ($config['schedules']['schedule'] as $schedule) {
3647
				if ($schedule['name'] <> "") {
3648
					$schedules[] = $schedule['name'];
3649
				}
3650
			}
3651
		}
3652

    
3653
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
3654
		$form .= gettext("Enable");
3655
		$form .= "</td><td class=\"vncellreq\">";
3656
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
3657
		if ($this->GetEnabled() == "on") {
3658
			$form .=  " checked=\"checked\"";
3659
		}
3660
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable limiter and its children") . "</span>";
3661
		$form .= "</td></tr>";
3662
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3663
		$form .= "<td class=\"vncellreq\">";
3664
		$form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
3665
		$form .= $this->GetQname()."\" />";
3666
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
3667
		$form .= $this->GetQname()."\" />";
3668
		if ($this->GetNumber() > 0) {
3669
			$form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
3670
			$form .= $this->GetNumber()."\" />";
3671
		}
3672
		$form .= "</td></tr>";
3673
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth");
3674
		$bandwidth = $this->GetBandwidth();
3675
		$form .= "</td><td class=\"vncellreq\">";
3676
		$form .= "<table id='maintable'>";
3677
		$form .= "<tbody><tr>";
3678
		$form .= "<td width='35%'><div id='onecolumn'>Bandwidth</div></td>";
3679
		//$form .= "<td width='35%'><div id='fifthcolumn'>Burst</div></td>";
3680
		$form .= "<td width='20%'><div id='twocolumn'>Bw type</div></td>";
3681
		$form .= "<td width='35%' ><div id='thirdcolumn'>Schedule</div></td>";
3682
		$form .= "<td width='5%'><div id='fourthcolumn'></div></td>";
3683
		$form .= "</tr>";
3684
		if (is_array($bandwidth)) {
3685
			foreach ($bandwidth as $bwidx => $bw) {
3686
				$form .= "\n<tr><td width='40%'>";
3687
				$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"bandwidth{$bwidx}\" name=\"bandwidth{$bwidx}\" value=\"{$bw['bw']}\" />";
3688
				//$form .= "</td><td width='20%'>";
3689
				//$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"burst{$bwidx}\" name=\"burst{$bwidx}\" value=\"{$bw['burst']}\" />";
3690
				$form .= "</td><td width='20%'>";
3691
				$form .= "<select id=\"bwtype{$bwidx}\" name=\"bwtype{$bwidx}\" class=\"formselect\">";
3692
				foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwsidx => $bwscale) {
3693
					$form .= "<option value=\"{$bwsidx}\"";
3694
					if ($bw['bwscale'] == $bwsidx) {
3695
						$form .= " selected=\"selected\"";
3696
					}
3697
					$form .= ">{$bwscale}</option>";
3698
				}
3699
				$form .= "</select>";
3700
				$form .= "</td><td width='35%' >";
3701
				$form .= "<select id=\"bwsched{$bwidx}\" name=\"bwsched{$bwidx}\" class=\"formselect\">";
3702
				foreach ($schedules as $schd) {
3703
					$selected = "";
3704
					if ($bw['bwsched'] == $schd) {
3705
						$selected = "selected=\"selected\"";
3706
					}
3707
					$form .= "<option value='{$schd}' {$selected}>{$schd}</option>";
3708
				}
3709
				$form .= "</select>";
3710
				$form .= "</td><td width='5%' >";
3711
				$form .= "<a onclick=\"removeBwRow(this); return false;\" href='#'><img border='0' src='/themes/{$g['theme']}/images/icons/icon_x.gif' alt='remove' /></a>";
3712
				$form .= "</td></tr>";
3713
			}
3714
		}
3715
		$form .= "</tbody></table>";
3716
		$form .= "<a onclick=\"javascript:addBwRowTo('maintable'); return false;\" href='#'>";
3717
		$form .= "<img border='0' src='/themes/{$g['theme']}/images/icons/icon_plus.gif' alt='add' title='" . gettext("add another schedule") . "' /></a>";
3718
		//$form .= "<br /><span class=\"vexpl\">" . gettext("Bandwidth is a rate (e.g. Mbit/s), burst is a total amount of data that will be transferred at full speed after an idle period.") . "</span><br />";
3719
		$form .= "<br /><span class=\"vexpl\">" . gettext("Bandwidth is the rate (e.g. Mbit/s) to which traffic in this limiter will be restricted.") . "</span><br />";
3720
		$form .= "</td></tr>";
3721
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
3722
		$form .= "<td class=\"vncellreq\">";
3723
		$form .= "<select name=\"mask\" id=\"mask\" class=\"formselect\" onchange=\"enable_maskbits();\" >";
3724
		$form .= "<option value=\"none\"";
3725
		$mask = $this->GetMask();
3726
		if ($mask['type'] == "none") {
3727
			$form .= " selected=\"selected\"";
3728
		}
3729
		$form .= ">none</option>";
3730
		$form .= "<option value=\"srcaddress\"";
3731
		if ($mask['type'] == "srcaddress") {
3732
			$form .= " selected=\"selected\"";
3733
		}
3734
		$form .= ">" . gettext("Source addresses") . "</option>";
3735
		$form .= "<option value=\"dstaddress\"";
3736
		if ($mask['type'] == "dstaddress") {
3737
			$form .= " selected=\"selected\"";
3738
		}
3739
		$form .= ">" . gettext("Destination addresses") . "</option>";
3740
		$form .= "</select>";
3741
		$form .= "&nbsp;<br />";
3742
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
3743
			  .  "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
3744
			  .  "be created for each source/destination IP address encountered, \n"
3745
			  .  "respectively. This makes it possible to easily specify bandwidth \n"
3746
			  .  "limits per host.") . "</span><br />";
3747
		$form .= "255.255.255.255/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbits\" name=\"maskbits\" value=\"";
3748
		if ($mask['type'] <> "none") {
3749
			$form .= $mask['bits'];
3750
		}
3751
		$form .= "\"";
3752
		if ($mask['type'] == "none") {
3753
			$form .= " disabled";
3754
		}
3755
		$form .= " />";
3756
		$form .= "&nbsp; IPV4 mask bits (1-32)<br />";
3757
		$form .= "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbitsv6\" name=\"maskbitsv6\" value=\"";
3758
		if ($mask['type'] <> "none") {
3759
			$form .= $mask['bitsv6'];
3760
		}
3761
		$form .= "\"";
3762
		if ($mask['type'] == "none") {
3763
			$form .= " disabled";
3764
		}
3765
		$form .= " />";
3766
		$form .= "&nbsp; IPV6 mask bits (1-128)<br />";
3767
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
3768
			  .  "leaving the mask bits blank will create one pipe per host. Otherwise specify \n"
3769
			  .  "the number of 'one' bits in the subnet mask used to group multiple hosts \n"
3770
			  .  "per pipe.") . "</span>";
3771
		$form .= "</td></tr>";
3772
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3773
		$form .= "<td class=\"vncellreq\">";
3774
		$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
3775
		$form .= $this->GetDescription();
3776
		$form .= "\" />";
3777
		$form .= "<br /> <span class=\"vexpl\">";
3778
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3779
		$form .= "</td></tr>";
3780
		$form .= "<tr id=\"sprtable4\">";
3781
		$form .= "<td></td>";
3782
		$form .= "<td><div id=\"showadvancedboxspr\">";
3783
		$form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
3784
		$form .= " value=\"" . gettext("Show advanced options") . "\" />";
3785
		$form .= "</p></div></td></tr>";
3786
		$form .= "<tr style=\"display:none\" id=\"sprtable\">";
3787

    
3788
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Delay") . "</td>";
3789
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3790
		$form .= "<input name=\"delay\" type=\"text\" id=\"delay\" size=\"5\" value=\"";
3791
		$form .= $this->GetDelay() . "\" />";
3792
		$form .= "&nbsp;ms<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3793
			  .  "should specify 0 here (or leave the field empty)") . "</span><br />";
3794
		$form .= "</td></tr>";
3795
		$form .= "<tr style=\"display:none\" id=\"sprtable1\">";
3796
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
3797
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3798
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
3799
		$form .= $this->GetPlr() . "\" />";
3800
		$form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3801
			  .  "should specify 0 here (or leave the field empty). "
3802
			  .  "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
3803
		$form .= "</td></tr>";
3804
		$form .= "<tr style=\"display:none\" id=\"sprtable2\">";
3805
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
3806
		$form .= "<td class=\"vncellreq\">";
3807
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
3808
		$form .= $this->GetQlimit() . "\" />";
3809
		$form .= "&nbsp;slots<br />";
3810
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3811
			  .  "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
3812
			  .  "then they are delayed by value specified in the Delay field, and then they "
3813
			  .  "are delivered to their destination.") . "</span>";
3814
		$form .= "</td></tr>";
3815
		$form .= "<tr style=\"display:none\" id=\"sprtable5\">";
3816
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
3817
		$form .= "<td class=\"vncellreq\">";
3818
		$form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
3819
		$form .= $this->GetBuckets() . "\" />";
3820
		$form .= "&nbsp;slots<br />";
3821
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3822
			.  "should leave the field empty. It increases the hash size set.");
3823
		$form .= "</span></td></tr>";
3824

    
3825
		return $form;
3826

    
3827
		}
3828

    
3829
	function wconfig() {
3830
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3831
		if (!is_array($cflink)) {
3832
			$cflink = array();
3833
		}
3834
		$cflink['name'] = $this->GetQname();
3835
		$cflink['number'] = $this->GetNumber();
3836
		$cflink['qlimit'] = $this->GetQlimit();
3837
		$cflink['plr'] = $this->GetPlr();
3838
		$cflink['description'] = $this->GetDescription();
3839

    
3840
		$bandwidth = $this->GetBandwidth();
3841
		if (is_array($bandwidth)) {
3842
			$cflink['bandwidth'] = array();
3843
			$cflink['bandwidth']['item'] = array();
3844
			foreach ($bandwidth as $bwidx => $bw) {
3845
				$cflink['bandwidth']['item'][] = $bw;
3846
			}
3847
		}
3848

    
3849
		$cflink['enabled'] = $this->GetEnabled();
3850
		$cflink['buckets'] = $this->GetBuckets();
3851
		$mask = $this->GetMask();
3852
		$cflink['mask'] = $mask['type'];
3853
		$cflink['maskbits'] = $mask['bits'];
3854
		$cflink['maskbitsv6'] = $mask['bitsv6'];
3855
		$cflink['delay'] = $this->GetDelay();
3856
	}
3857

    
3858
}
3859

    
3860
class dnqueue_class extends dummynet_class {
3861
	var $pipeparent;
3862
	var $weight;
3863

    
3864
	function GetWeight() {
3865
		return $this->weight;
3866
	}
3867
	function SetWeight($weight) {
3868
		$this->weight = $weight;
3869
	}
3870
	function GetPipe() {
3871
		return $this->pipeparent;
3872
	}
3873
	function SetPipe($pipe) {
3874
		$this->pipeparent = $pipe;
3875
	}
3876

    
3877
	/* Just a stub in case we ever try to call this from the frontend. */
3878
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
3879
		return;
3880
	}
3881

    
3882
	function delete_queue() {
3883
		cleanup_dnqueue_from_rules($this->GetQname());
3884
		unset_dn_object_by_reference($this->GetLink());
3885
		@pfSense_pipe_action("queue delete " . $this->GetNumber());
3886
	}
3887

    
3888
	function validate_input($data, &$input_errors) {
3889
		parent::validate_input($data, $input_errors);
3890

    
3891
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3892
		    ($data['weight'] < 1 && $data['weight'] > 100))) {
3893
			$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
3894
		}
3895
	}
3896

    
3897
	/*
3898
	 * Should search even its children
3899
	 */
3900
	function &find_queue($pipe, $qname) {
3901
		if ($qname == $this->GetQname()) {
3902
			return $this;
3903
		} else {
3904
			return NULL;
3905
		}
3906
	}
3907

    
3908
	function &find_parentqueue($pipe, $qname) {
3909
		return $this->qparent;
3910
	}
3911

    
3912
	function &get_queue_list(&$qlist) {
3913
		if ($this->GetEnabled() == "") {
3914
			return;
3915
		}
3916
		$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3917
	}
3918

    
3919
	function ReadConfig(&$q) {
3920
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3921
			$this->SetQname($q['newname']);
3922
		} else if (!empty($q['newname'])) {
3923
			$this->SetQname($q['newname']);
3924
		} else {
3925
			$this->SetQname($q['name']);
3926
		}
3927
		$this->SetNumber($q['number']);
3928
		if (isset($q['qlimit']) && $q['qlimit'] <> "") {
3929
			$this->SetQlimit($q['qlimit']);
3930
		} else {
3931
			$this->SetQlimit("");
3932
		}
3933
		if (isset($q['mask']) && $q['mask'] <> "") {
3934
			$masktype = $q['mask'];
3935
		} else {
3936
			$masktype = "";
3937
		}
3938
		if (isset($q['maskbits']) && $q['maskbits'] <> "") {
3939
			$maskbits = $q['maskbits'];
3940
		} else {
3941
			$maskbits = "";
3942
		}
3943
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
3944
			$maskbitsv6 = $q['maskbitsv6'];
3945
		} else {
3946
			$maskbitsv6 = "";
3947
		}
3948
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3949
		if (isset($q['buckets']) && $q['buckets'] <> "") {
3950
			$this->SetBuckets($q['buckets']);
3951
		} else {
3952
			$this->SetBuckets("");
3953
		}
3954
		if (isset($q['plr']) && $q['plr'] <> "") {
3955
			$this->SetPlr($q['plr']);
3956
		} else {
3957
			$this->SetPlr("");
3958
		}
3959
		if (isset($q['weight']) && $q['weight'] <> "") {
3960
			$this->SetWeight($q['weight']);
3961
		} else {
3962
			$this->SetWeight("");
3963
		}
3964
		if (isset($q['description']) && $q['description'] <> "") {
3965
			$this->SetDescription($q['description']);
3966
		} else {
3967
			$this->SetDescription("");
3968
		}
3969
		$this->SetEnabled($q['enabled']);
3970
	}
3971

    
3972
	function build_tree() {
3973
		$parent =& $this->GetParent();
3974
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">";
3975
		$tree .= $this->GetQname() . "</a>";
3976
		$tree .= "</li>";
3977

    
3978
		return $tree;
3979
	}
3980

    
3981
	function build_rules() {
3982
		if ($this->GetEnabled() == "") {
3983
			return;
3984
		}
3985

    
3986
		$parent =& $this->GetParent();
3987
		$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
3988
		if ($this->GetQlimit()) {
3989
			$pfq_rule .= " queue " . $this->GetQlimit();
3990
		}
3991
		if ($this->GetWeight()) {
3992
			$pfq_rule .= " weight " . $this->GetWeight();
3993
		}
3994
		if ($this->GetBuckets()) {
3995
			$pfq_rule .= " buckets " . $this->GetBuckets();
3996
		}
3997
		$this->build_mask_rules($pfq_rule);
3998
		$pfq_rule .= "\n";
3999

    
4000
		return $pfq_rule;
4001
	}
4002

    
4003
	function build_javascript() {
4004
		return parent::build_javascript();
4005
	}
4006

    
4007

    
4008
	function build_form() {
4009
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
4010
		$form .= gettext("Enable/Disable");
4011
		$form .= "</td><td class=\"vncellreq\">";
4012
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
4013
		if ($this->GetEnabled() == "on") {
4014
			$form .=  " checked=\"checked\"";
4015
		}
4016
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue") . "</span>";
4017
		$form .= "</td></tr>";
4018
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
4019
		$form .= "<td class=\"vncellreq\">";
4020
		$form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
4021
		$form .= $this->GetQname()."\" />";
4022
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
4023
		$form .= $this->GetQname()."\" />";
4024
		if ($this->GetNumber() > 0) {
4025
			$form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
4026
			$form .= $this->GetNumber()."\" />";
4027
		}
4028
		$form .= "</td></tr>";
4029
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
4030
		$form .= "<td class=\"vncellreq\">";
4031
		$form .= "<select name=\"mask\" id=\"mask\" class=\"formselect\" onchange=\"enable_maskbits();\" >";
4032
		$form .= "<option value=\"none\"";
4033
		$mask = $this->GetMask();
4034
		if ($mask['type'] == "none") {
4035
			$form .= " selected=\"selected\"";
4036
		}
4037
		$form .= ">" . gettext("none") . "</option>";
4038
		$form .= "<option value=\"srcaddress\"";
4039
		if ($mask['type'] == "srcaddress") {
4040
			$form .= " selected=\"selected\"";
4041
		}
4042
		$form .= ">" . gettext("Source addresses") . "</option>";
4043
		$form .= "<option value=\"dstaddress\"";
4044
		if ($mask['type'] == "dstaddress") {
4045
			$form .= " selected=\"selected\"";
4046
		}
4047
		$form .= ">" . gettext("Destination addresses") . "</option>";
4048
		$form .= "</select>";
4049
		$form .= "&nbsp;slots<br />";
4050
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
4051
			.  "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
4052
			.  "be created for each source/destination IP address encountered, \n"
4053
			.  "respectively. This makes it possible to easily specify bandwidth \n"
4054
			.  "limits per host.") . "</span><br />";
4055
		$form .= "255.255.255.255/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbits\" name=\"maskbits\" value=\"";
4056
		if ($mask['type'] <> "none") {
4057
			$form .= $mask['bits'];
4058
		}
4059
		$form .= "\"";
4060
		if ($mask['type'] == "none") {
4061
			$form .= " disabled";
4062
		}
4063
		$form .= " />";
4064
		$form .= "&nbsp; IPV4 mask bits (1-32)<br />";
4065
		$form .= "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbitsv6\" name=\"maskbitsv6\" value=\"";
4066
		if ($mask['type'] <> "none") {
4067
			$form .= $mask['bitsv6'];
4068
		}
4069
		$form .= "\"";
4070
		if ($mask['type'] == "none") {
4071
			$form .= " disabled";
4072
		}
4073
		$form .= " />";
4074
		$form .= "&nbsp; IPV6 mask bits (1-128)<br />";
4075
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
4076
			.  "leaving the mask bits blank will create one pipe per host. Otherwise specify \n"
4077
			.  "the number of 'one' bits in the subnet mask used to group multiple hosts \n"
4078
			.  "per queue.") . "</span>";
4079
		$form .= "</td></tr>";
4080
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
4081
		$form .= "<td class=\"vncellreq\">";
4082
		$form .= "<input type=\"text\" id=\"description\" class=\"formfld unknown\" size=\"40\" name=\"description\" value=\"";
4083
		$form .= $this->GetDescription();
4084
		$form .= "\" />";
4085
		$form .= "<br /> <span class=\"vexpl\">";
4086
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
4087
		$form .= "</td></tr>";
4088
		$form .= "<tr id=\"sprtable4\">";
4089
		$form .= "<td></td>";
4090
		$form .= "<td><div id=\"showadvancedboxspr\">";
4091
		$form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
4092
		$form .= " value=\"" . gettext("Show advanced options") . "\" />";
4093
		$form .= "</p></div></td></tr>";
4094
		$form .= "<tr style=\"display:none\" id=\"sprtable\">";
4095
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Weight") . "</td>";
4096
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
4097
		$form .= "<input name=\"weight\" type=\"text\" id=\"weight\" size=\"5\" value=\"";
4098
		$form .= $this->GetWeight() . "\" />";
4099
		$form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: For queues under the same parent "
4100
			.  "this specifies the share that a queue gets(values range from 1 to 100, you can leave it blank otherwise)") . "</span>";
4101
		$form .= "</td></tr>";
4102
		$form .= "<tr style=\"display:none\" id=\"sprtable1\">";
4103
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
4104
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
4105
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
4106
		$form .= $this->GetPlr() . "\" />";
4107
		$form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
4108
			.  "should specify 0 here (or leave the field empty). "
4109
			.  "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
4110
		$form .= "</td></tr>";
4111
		$form .= "<tr style=\"display:none\" id=\"sprtable2\">";
4112
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
4113
		$form .= "<td class=\"vncellreq\">";
4114
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
4115
		$form .= $this->GetQlimit() . "\" />";
4116
		$form .= "&nbsp;slots<br />";
4117
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
4118
			.  "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
4119
			.  "then they are delayed by value specified in the Delay field, and then they "
4120
			.  "are delivered to their destination.") . "</span>";
4121
		$form .= "</td></tr>";
4122
		$form .= "<tr style=\"display:none\" id=\"sprtable5\">";
4123
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
4124
		$form .= "<td class=\"vncellreq\">";
4125
		$form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
4126
		$form .= $this->GetBuckets() . "\" />";
4127
		$form .= "&nbsp;" . gettext("slots") . "<br />";
4128
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
4129
			.  "should leave the field empty. It increases the hash size set.");
4130
		$form .= "</span></td></tr>";
4131

    
4132
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
4133
		$form .= " value=\"" . $this->GetPipe() . "\" />";
4134

    
4135
		return $form;
4136

    
4137
	}
4138

    
4139
	function update_dn_data(&$data) {
4140
		$this->ReadConfig($data);
4141
	}
4142

    
4143
	function wconfig() {
4144
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
4145
		if (!is_array($cflink)) {
4146
			$cflink = array();
4147
		}
4148
		$cflink['name'] = $this->GetQname();
4149
		$cflink['number'] = $this->GetNumber();
4150
		$cflink['qlimit'] = $this->GetQlimit();
4151
		$cflink['description'] = $this->GetDescription();
4152
		$cflink['weight'] = $this->GetWeight();
4153
		$cflink['enabled'] = $this->GetEnabled();
4154
		$cflink['buckets'] = $this->GetBuckets();
4155
		$mask = $this->GetMask();
4156
		$cflink['mask'] = $mask['type'];
4157
		$cflink['maskbits'] = $mask['bits'];
4158
		$cflink['maskbitsv6'] = $mask['bitsv6'];
4159
	}
4160
}
4161

    
4162
// List of layer7 objects
4163
$layer7_rules_list = array();
4164

    
4165
class layer7 {
4166

    
4167
	var $rname; //alias
4168
	var $rdescription; //alias description
4169
	var $rport; //divert port
4170
	var $renabled; //rule enabled
4171
	var $rsets = array(); //array of l7 associations
4172

    
4173
	// Auxiliary functions
4174

    
4175
	function GetRName() {
4176
		return $this->rname;
4177
	}
4178
	function SetRName($rname) {
4179
		$this->rname = $rname;
4180
	}
4181
	function GetRDescription() {
4182
		return $this->rdescription;
4183
	}
4184
	function SetRDescription($rdescription) {
4185
		$this->rdescription = $rdescription;
4186
	}
4187
	function GetRPort() {
4188
		return $this->rport;
4189
	}
4190
	function SetRPort($rport) {
4191
		$this->rport = $rport;
4192
	}
4193
	function GetREnabled() {
4194
		return $this->renabled;
4195
	}
4196
	function SetREnabled($value) {
4197
		$this->renabled = $value;
4198
	}
4199
	function GetRl7() {
4200
		return $this->rsets;
4201
	}
4202
	function SetRl7($rsets) {
4203
		$this->rsets = $rsets;
4204
	}
4205

    
4206
	//Add a tuple (rule,structure,element) to the $rsets
4207

    
4208
	function add_rule($l7set) {
4209
		$this->rsets[] = $l7set;
4210
	}
4211

    
4212
	// Build the layer7 rules
4213
	function build_l7_rules() {
4214
		if ($this->GetREnabled() == "") {
4215
			return;
4216
		}
4217
		//$l7rules = "#" . $this->rdescription . "\n";
4218
		foreach ($this->rsets as $rl7) {
4219
			$l7rules .= $rl7->build_rules();
4220
		}
4221
		return $l7rules;
4222
	}
4223

    
4224
	// Read the config from array
4225
	function ReadConfig(&$qname, &$q) {
4226
		$this->SetRName($qname);
4227
		$this->SetREnabled($q['enabled']);
4228
		$this->SetRPort($q['divert_port']);
4229
		if (isset($q['description']) && $q['description'] <> "") {
4230
			$this->SetRDescription($q['description']);
4231
		}
4232
		$rsets = $q['l7rules'];
4233
		//Put individual rules in the array
4234
		if (is_array($rsets)) {
4235
			$this->rsets = array(); // XXX: ugly hack
4236
			foreach ($rsets as $l7r) {
4237
				$l7obj = new l7rule();
4238
				$l7obj->SetRProtocol($l7r['protocol']);
4239
				$l7obj->SetRStructure($l7r['structure']);
4240
				$l7obj->SetRBehaviour($l7r['behaviour']);
4241
				$this->add_rule($l7obj);
4242
			}
4243
		}
4244
	}
4245

    
4246
	//Generate a random port for the divert socket
4247
	function gen_divert_port() {
4248
		$dports = get_divert_ports(); //array of used ports
4249
		$divert_port = 1; // Initialize
4250
		while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) {
4251
			$divert_port = rand(40000, 60000);
4252
		}
4253
		return $divert_port;
4254
	}
4255

    
4256
	//Helps building the left tree
4257
	function build_tree() {
4258
		$tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&amp;action=show\">";
4259
		$tree .= $this->GetRName() . "</a>";
4260
		$tree .= "</li>";
4261

    
4262
		return $tree;
4263
	}
4264

    
4265
	function build_form() {
4266
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
4267
		$form .= gettext("Enable/Disable");
4268
		$form .= "</td><td class=\"vncellreq\">";
4269
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\" ";
4270
		if ($this->GetREnabled() == "on") {
4271
			$form .=  "checked=\"checked\"";
4272
		}
4273
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable layer7 Container") . "</span>";
4274
		$form .= "</td></tr>";
4275
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
4276
		$form .= "<td class=\"vncellreq\">";
4277
		$form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
4278
		$form .= $this->GetRName()."\" />";
4279
		$form .= "</td></tr>";
4280
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
4281
		$form .= "<td class=\"vncellreq\">";
4282
		$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
4283
		$form .= $this->GetRDescription();
4284
		$form .= "\" />";
4285
		$form .= "<br /> <span class=\"vexpl\">";
4286
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
4287
		$form .= "</td></tr>";
4288

    
4289
		return $form;
4290
	}
4291

    
4292
	//Write the setting to the $config array
4293
	function wconfig() {
4294
		global $config;
4295

    
4296
		if (!is_array($config['l7shaper']['container'])) {
4297
			$config['l7shaper']['container'] = array();
4298
		}
4299
		//
4300
		$cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
4301
		// Test if this rule exists already
4302
		if (!$cflink) {
4303
			$cflink =& $config['l7shaper']['container'][];
4304
		}
4305
		$cflink['name'] = $this->GetRName();
4306
		$cflink['enabled'] = $this->GetREnabled();
4307
		$cflink['description'] = $this->GetRDescription();
4308
		$cflink['divert_port'] = $this->GetRPort();
4309

    
4310
		// Destroy previously existent rules
4311
		if (is_array($cflink['rules'])) {
4312
			unset($cflink['l7rules']);
4313
		}
4314

    
4315
		$cflink['l7rules'] = array();
4316

    
4317
		$i = 0;
4318
		foreach ($this->rsets as $rulel7) {
4319
			$cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
4320
			$cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
4321
			$cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
4322
			$i++;
4323
		}
4324
	}
4325

    
4326
	//This function is necessary to help producing the overload options for keep state
4327
	function get_unique_structures() {
4328

    
4329
		$unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
4330
		foreach ($this->rsets as $l7rule) {
4331
			if ($l7rule->GetRStructure() == "action") {
4332
				$unique_structures['action'] = true;
4333
			} else if ($l7rule->GetRStructure() == "limiter") {
4334
				$unique_structures['dummynet'] = true;
4335
			} else {
4336
				$unique_structures['altq'] = true;
4337
			}
4338
		}
4339
		//Delete non used structures so we don't have to check this in filter.inc
4340
		foreach ($unique_structures as $key => $value) {
4341
			if (!$value) {
4342
				unset($unique_structures[$key]);
4343
			}
4344
		}
4345
		return $unique_structures;
4346
	}
4347

    
4348
	function validate_input($data, &$input_errors) {
4349
		$reqdfields[] = "container";
4350
		$reqdfieldsn[] = gettext("Name");
4351

    
4352
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
4353

    
4354
		if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container'])) {
4355
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
4356
		}
4357
	}
4358

    
4359
	function delete_l7c() {
4360
		mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
4361
		unset_l7_object_by_reference($this->GetRName());
4362
		cleanup_l7_from_rules($this->GetRName());
4363
	}
4364
}
4365

    
4366
class l7rule {
4367

    
4368
	var $rprotocol; //protocol
4369
	var $rstructure; //action, limiter, queue
4370
	var $rbehaviour; //allow, block, queue_name, pipe_number ...
4371

    
4372
	//Auxiliary Functions
4373

    
4374
	function GetRProtocol() {
4375
		return $this->rprotocol;
4376
	}
4377
	function SetRProtocol($rprotocol) {
4378
		$this->rprotocol = $rprotocol;
4379
	}
4380
	function GetRStructure() {
4381
		return $this->rstructure;
4382
	}
4383
	function SetRStructure($rstructure) {
4384
		$this->rstructure = $rstructure;
4385
	}
4386
	function GetRBehaviour() {
4387
		return $this->rbehaviour;
4388
	}
4389
	function SetRBehaviour($rbehaviour) {
4390
		$this->rbehaviour = $rbehaviour;
4391
	}
4392

    
4393
	//XXX Do we need to test any particularity for AltQ queues?
4394
	function build_rules() {
4395
		global $dummynet_pipe_list;
4396
		switch ($this->GetRStructure()) {
4397
		case "limiter":
4398
			read_dummynet_config();
4399
			$dn_list =& get_unique_dnqueue_list();
4400
			$found = false;
4401
			if (is_array($dn_list)) {
4402
				foreach ($dn_list as $key => $value) {
4403
					if ($key == $this->GetRBehaviour()) {
4404
						if ($value[0] == "?") {
4405
							$l7rule = $this->GetRProtocol() . " = dnqueue " . substr($value, 1) . "\n";
4406
						} else {
4407
							$l7rule = $this->GetRProtocol() . " = dnpipe " . $value . "\n";
4408
						}
4409
						$found = true;
4410
					}
4411
					if ($found) {
4412
						break;
4413
					}
4414
				}
4415
			}
4416
			break;
4417
		default: //This is for action and for altq
4418
			$l7rule = $this->GetRProtocol() . " = " . $this->GetRStructure() . " " . $this->GetRBehaviour() . "\n";
4419
			break;
4420
		}
4421
		return $l7rule;
4422
	}
4423
}
4424

    
4425
/*
4426
 * This function allows to return an array with all the used divert socket ports
4427
 */
4428
function get_divert_ports() {
4429
	global $layer7_rules_list;
4430
	$dports = array();
4431

    
4432
	foreach ($layer7_rules_list as $l7r) {
4433
		$dports[] = $l7r->GetRPort();
4434
	}
4435

    
4436
	return $dports;
4437
}
4438

    
4439
function &get_l7c_reference_to_me_in_config(&$name) {
4440
	global $config;
4441

    
4442
	$ptr = NULL;
4443

    
4444
	if (is_array($config['l7shaper']['container'])) {
4445
		foreach ($config['l7shaper']['container'] as $key => $value) {
4446
			if ($value['name'] == $name) {
4447
				$ptr =& $config['l7shaper']['container'][$key];
4448
			}
4449
		}
4450
	}
4451
	return $ptr;
4452
	// $ptr can be null. has to be checked later
4453
}
4454

    
4455
function unset_l7_object_by_reference(&$name) {
4456
	global $config;
4457

    
4458
	if (is_array($config['l7shaper']['container'])) {
4459
		foreach ($config['l7shaper']['container'] as $key => $value) {
4460
			if ($value['name'] == $name) {
4461
				unset($config['l7shaper']['container'][$key]['l7rules']);
4462
				unset($config['l7shaper']['container'][$key]);
4463
				break;
4464
			}
4465
		}
4466
	}
4467
}
4468

    
4469
function read_layer7_config() {
4470
	global $layer7_rules_list, $config;
4471

    
4472
	if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container'])) {
4473
		$layer7_rules_list = array();
4474
		return;
4475
	}
4476

    
4477
	$l7cs = &$config['l7shaper']['container'];
4478

    
4479
	$layer7_rules_list = array();
4480

    
4481
	foreach ($l7cs as $conf) {
4482
		if (empty($conf['name'])) {
4483
			continue; /* XXX: grrrrrr at php */
4484
		}
4485
		$root =& new layer7();
4486
		$root->ReadConfig($conf['name'],$conf);
4487
		$layer7_rules_list[$root->GetRName()] = &$root;
4488
	}
4489
}
4490

    
4491
function update_layer7_custom_patterns() {
4492
	global $config;
4493

    
4494
	if (!is_array($config['l7shaper']['custom_pat'])) {
4495
		return;
4496
	}
4497

    
4498
	foreach ($config['l7shaper']['custom_pat'] as $filename => $filecontent) {
4499
		if (!file_exists("/usr/local/share/protocols/" . $filename)) {
4500
			@file_put_contents("/usr/local/share/protocols/" . $filename, base64_decode($filecontent));
4501
		}
4502
	}
4503
}
4504

    
4505
function generate_layer7_files() {
4506
	global $layer7_rules_list, $g;
4507

    
4508
	read_layer7_config();
4509

    
4510
	if (!empty($layer7_rules_list)) {
4511
		if (!is_module_loaded("ipdivert.ko")) {
4512
			mwexec("/sbin/kldload ipdivert.ko");
4513
		}
4514

    
4515
		array_map('unlink', glob("{$g['tmp_path']}/*.l7"));
4516
	}
4517

    
4518
	update_layer7_custom_patterns();
4519

    
4520
	foreach ($layer7_rules_list as $l7rules) {
4521
		if ($l7rules->GetREnabled()) {
4522
			$filename = $l7rules->GetRName() . ".l7";
4523
			$path = "{$g['tmp_path']}/" . $filename;
4524

    
4525
			$rules = $l7rules->build_l7_rules();
4526

    
4527
			$fp = fopen($path,'w');
4528
			fwrite($fp,$rules);
4529
			fclose($fp);
4530
		}
4531
	}
4532
}
4533

    
4534
function layer7_start_l7daemon() {
4535
	global $layer7_rules_list, $g;
4536

    
4537
	/*
4538
	 * XXX: ermal - Needed ?!
4539
	 * read_layer7_config();
4540
	 */
4541

    
4542
	foreach ($layer7_rules_list as $l7rules) {
4543
		if ($l7rules->GetREnabled()) {
4544
			$filename = $l7rules->GetRName() . ".l7";
4545
			$path = "{$g['tmp_path']}/" . $filename;
4546

    
4547
			unset($l7pid);
4548
			/* Only reread the configuration rather than restart to avoid losing information. */
4549
			exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid);
4550
			if (count($l7pid) > 0) {
4551
				log_error(sprintf(gettext("Sending HUP signal to %s"), $l7pid[0]));
4552
				mwexec("/bin/kill -HUP {$l7pid[0]}");
4553
			} else {
4554
				// XXX: Hardcoded number of packets to garbage collect and queue length.
4555
				$ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 8 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
4556
				mwexec_bg($ipfw_classifyd_init);
4557
			}
4558
		}
4559
	}
4560
}
4561

    
4562
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
4563
function generate_protocols_array() {
4564

    
4565
	update_layer7_custom_patterns();
4566

    
4567
	$protocols = return_dir_as_array("/usr/local/share/protocols");
4568
	$protocols_new = array();
4569
	if (is_array($protocols)) {
4570
		foreach ($protocols as $key => $proto) {
4571
			if (strstr($proto, ".pat")) {
4572
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
4573
			}
4574
		}
4575
		sort($protocols_new);
4576
	}
4577
	return $protocols_new;
4578
}
4579

    
4580
function get_l7_unique_list() {
4581
	global $layer7_rules_list;
4582

    
4583
	$l7list = array();
4584
	if (is_array($layer7_rules_list)) {
4585
		foreach ($layer7_rules_list as $l7c) {
4586
			if ($l7c->GetREnabled()) {
4587
				$l7list[] = $l7c->GetRName();
4588
			}
4589
		}
4590
	}
4591

    
4592
	return $l7list;
4593
}
4594

    
4595
// Disable a removed l7 container from the filter
4596
function cleanup_l7_from_rules(&$name) {
4597
	global $config;
4598

    
4599
	if (is_array($config['filter']['rule'])) {
4600
		foreach ($config['filter']['rule'] as $key => $rule) {
4601
			if ($rule['l7container'] == $name) {
4602
				unset($config['filter']['rule'][$key]['l7container']);
4603
			}
4604
		}
4605
	}
4606
}
4607

    
4608
function get_dummynet_name_list() {
4609

    
4610
	$dn_name_list =& get_unique_dnqueue_list();
4611
	$dn_name = array();
4612
	if (is_array($dn_name_list)) {
4613
		foreach ($dn_name_list as $key => $value) {
4614
			$dn_name[] = $key;
4615
		}
4616
	}
4617

    
4618
	return $dn_name;
4619

    
4620
}
4621

    
4622
function get_altq_name_list() {
4623
	$altq_name_list =& get_unique_queue_list();
4624
	$altq_name = array();
4625
	if (is_array($altq_name_list)) {
4626
		foreach ($altq_name_list as $key => $aqobj) {
4627
			$altq_name[] = $key;
4628
		}
4629
	}
4630

    
4631
	return $altq_name;
4632
}
4633

    
4634
/*
4635
 * XXX: TODO Make a class shaper to hide all these functions
4636
 * from the global namespace.
4637
 */
4638

    
4639
/*
4640
 * This is a layer violation but for now there is no way
4641
 * I can find to properly do this with PHP.
4642
 */
4643
function altq_get_default_queue($interface) {
4644
	global $altq_list_queues;
4645

    
4646
	$altq_tmp = $altq_list_queues[$interface];
4647
	if ($altq_tmp) {
4648
		return $altq_tmp->GetDefaultQueuePresent();
4649
	} else {
4650
		return false;
4651
	}
4652
}
4653

    
4654
function altq_check_default_queues() {
4655
	global $altq_list_queues;
4656

    
4657
	$count = 0;
4658
	if (is_array($altq_list_queues)) {
4659
		foreach ($altq_list_queues as $altq) {
4660
			if ($altq->GetDefaultQueuePresent()) {
4661
				$count++;
4662
			}
4663
		}
4664
	}
4665
	else {
4666
		$count++;
4667
	}
4668

    
4669
	return 0;
4670
}
4671

    
4672
function &get_unique_queue_list() {
4673
	global $altq_list_queues;
4674

    
4675
	$qlist = array();
4676
	if (is_array($altq_list_queues)) {
4677
		foreach ($altq_list_queues as $altq) {
4678
			if ($altq->GetEnabled() == "") {
4679
				continue;
4680
			}
4681
			$tmplist =& $altq->get_queue_list();
4682
			foreach ($tmplist as $qname => $link) {
4683
				if ($link->GetEnabled() <> "") {
4684
					$qlist[$qname] = $link;
4685
				}
4686
			}
4687
		}
4688
	}
4689
	return $qlist;
4690
}
4691

    
4692
function &get_unique_dnqueue_list() {
4693
	global $dummynet_pipe_list;
4694

    
4695
	$qlist = array();
4696
	if (is_array($dummynet_pipe_list)) {
4697
		foreach ($dummynet_pipe_list as $dn) {
4698
			if ($dn->GetEnabled() == "") {
4699
				continue;
4700
			}
4701
			$tmplist =& $dn->get_queue_list();
4702
			foreach ($tmplist as $qname => $link) {
4703
				$qlist[$qname] = $link;
4704
			}
4705
		}
4706
	}
4707
	return $qlist;
4708
}
4709

    
4710
function ref_on_altq_queue_list($parent, $qname) {
4711
	if (isset($GLOBALS['queue_list'][$qname])) {
4712
		$GLOBALS['queue_list'][$qname]++;
4713
	} else {
4714
		$GLOBALS['queue_list'][$qname] = 1;
4715
	}
4716

    
4717
	unref_on_altq_queue_list($parent);
4718
}
4719

    
4720
function unref_on_altq_queue_list($qname) {
4721
	$GLOBALS['queue_list'][$qname]--;
4722
	if ($GLOBALS['queue_list'][$qname] <= 1) {
4723
		unset($GLOBALS['queue_list'][$qname]);
4724
	}
4725
}
4726

    
4727
function read_altq_config() {
4728
	global $altq_list_queues, $config;
4729
	$path = array();
4730

    
4731
	if (!is_array($config['shaper'])) {
4732
		$config['shaper'] = array();
4733
	}
4734
	if (!is_array($config['shaper']['queue'])) {
4735
		$config['shaper']['queue'] = array();
4736
	}
4737
	$a_int = &$config['shaper']['queue'];
4738

    
4739
	$altq_list_queues = array();
4740

    
4741
	if (!is_array($config['shaper']['queue'])) {
4742
		return;
4743
	}
4744

    
4745
	foreach ($a_int as $key => $conf) {
4746
		$int = $conf['interface'];
4747
		$root =& new altq_root_queue();
4748
		$root->SetInterface($int);
4749
		$altq_list_queues[$root->GetInterface()] = &$root;
4750
		$root->ReadConfig($conf);
4751
		array_push($path, $key);
4752
		$root->SetLink($path);
4753
		if (is_array($conf['queue'])) {
4754
			foreach ($conf['queue'] as $key1 => $q) {
4755
				array_push($path, $key1);
4756
				/*
4757
				 * XXX: we completely ignore errors here but anyway we must have
4758
				 *	checked them before so no harm should be come from this.
4759
				 */
4760
				$root->add_queue($root->GetInterface(), $q, $path, $input_errors);
4761
				array_pop($path);
4762
			}
4763
		}
4764
		array_pop($path);
4765
	}
4766
}
4767

    
4768
function read_dummynet_config() {
4769
	global $dummynet_pipe_list, $config;
4770
	$path = array();
4771

    
4772
	if (!is_array($config['dnshaper'])) {
4773
		$config['dnshaper'] = array();
4774
	}
4775
	if (!is_array($config['dnshaper']['queue'])) {
4776
		$config['dnshaper']['queue'] = array();
4777
	}
4778
	$a_int = &$config['dnshaper']['queue'];
4779

    
4780
	$dummynet_pipe_list = array();
4781

    
4782
	if (!is_array($config['dnshaper']['queue']) ||
4783
	    !count($config['dnshaper']['queue'])) {
4784
		return;
4785
	}
4786

    
4787
	foreach ($a_int as $key => $conf) {
4788
		if (empty($conf['name'])) {
4789
			continue; /* XXX: grrrrrr at php */
4790
		}
4791
		$root =& new dnpipe_class();
4792
		$root->ReadConfig($conf);
4793
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4794
		array_push($path, $key);
4795
		$root->SetLink($path);
4796
		if (is_array($conf['queue'])) {
4797
			foreach ($conf['queue'] as $key1 => $q) {
4798
				array_push($path, $key1);
4799
				/*
4800
				 * XXX: we completely ignore errors here but anyway we must have
4801
				 *	checked them before so no harm should be come from this.
4802
				 */
4803
				$root->add_queue($root->GetQname(), $q, $path, $input_errors);
4804
				array_pop($path);
4805
			}
4806
		}
4807
		array_pop($path);
4808
	}
4809
}
4810

    
4811
function get_interface_list_to_show() {
4812
	global $altq_list_queues, $config;
4813
	global $shaperIFlist;
4814

    
4815
	$tree = "";
4816
	foreach ($shaperIFlist as $shif => $shDescr) {
4817
		if ($altq_list_queues[$shif]) {
4818
			continue;
4819
		} else  {
4820
			if (!is_altq_capable(get_real_interface($shif))) {
4821
				continue;
4822
			}
4823
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4824
		}
4825
	}
4826

    
4827
	return $tree;
4828
}
4829

    
4830
function filter_generate_altq_queues() {
4831
	global $altq_list_queues;
4832

    
4833
	read_altq_config();
4834

    
4835
	$altq_rules = "";
4836
	foreach ($altq_list_queues as $altq) {
4837
		$altq_rules .= $altq->build_rules();
4838
	}
4839

    
4840
	return $altq_rules;
4841
}
4842

    
4843
function dnqueue_find_nextnumber() {
4844
	global $dummynet_pipe_list;
4845

    
4846
	$dnused = array();
4847
	if (is_array($dummynet_pipe_list)) {
4848
		foreach ($dummynet_pipe_list as $dn) {
4849
			$tmplist =& $dn->get_queue_list();
4850
			foreach ($tmplist as $qname => $link) {
4851
				if ($link[0] == "?") {
4852
					$dnused[$qname] = substr($link, 1);
4853
				}
4854
			}
4855
		}
4856
	}
4857

    
4858
	sort($dnused, SORT_NUMERIC);
4859
	$dnnumber = 0;
4860
	$found = false;
4861
	foreach ($dnused as $dnnum) {
4862
		if (($dnnum - $dnnumber) > 1) {
4863
			$dnnumber = $dnnum - 1;
4864
			$found = true;
4865
			break;
4866
		} else {
4867
			$dnnumber = $dnnum;
4868
		}
4869
	}
4870

    
4871
	if ($found == false) {
4872
		$dnnumber++;
4873
	}
4874

    
4875
	unset($dnused, $dnnum, $found);
4876
	return $dnnumber;
4877
}
4878

    
4879
function dnpipe_find_nextnumber() {
4880
	global $dummynet_pipe_list;
4881

    
4882
	$dnused = array();
4883
	foreach ($dummynet_pipe_list as $dn) {
4884
		$dnused[] = $dn->GetNumber();
4885
	}
4886

    
4887
	sort($dnused, SORT_NUMERIC);
4888
	$dnnumber = 0;
4889
	$found = false;
4890
	foreach ($dnused as $dnnum) {
4891
		if (($dnnum - $dnnumber) > 1) {
4892
			$dnnumber = $dnnum - 1;
4893
			$found = true;
4894
			break;
4895
		} else {
4896
			$dnnumber = $dnnum;
4897
		}
4898
	}
4899

    
4900
	if ($found == false) {
4901
		$dnnumber++;
4902
	}
4903

    
4904
	unset($dnused, $dnnum, $found);
4905
	return $dnnumber;
4906
}
4907

    
4908
function filter_generate_dummynet_rules() {
4909
	global $g, $dummynet_pipe_list;
4910

    
4911
	read_dummynet_config();
4912

    
4913
	$dn_rules = "";
4914
	foreach ($dummynet_pipe_list as $dn) {
4915
		$dn_rules .= $dn->build_rules();
4916
	}
4917

    
4918
	if (!empty($dn_rules)) {
4919
		if (!is_module_loaded("dummynet.ko")) {
4920
			mwexec("/sbin/kldload dummynet");
4921
			set_sysctl(array(
4922
				"net.inet.ip.dummynet.io_fast" => "1",
4923
				"net.inet.ip.dummynet.hash_size" => "256"
4924
			));
4925
		}
4926
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4927
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4928
	}
4929
}
4930

    
4931
function build_iface_without_this_queue($iface, $qname) {
4932
	global $g, $altq_list_queues;
4933
	global $shaperIFlist;
4934

    
4935
	$altq =& $altq_list_queues[$iface];
4936
	if ($altq) {
4937
		$scheduler = ": " . $altq->GetScheduler();
4938
	}
4939
	$form = "<tr><td width=\"20%\" >";
4940
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&amp;queue=" . $iface."&amp;action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4941
	$form .= "</td></tr>";
4942
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4943
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4944
	$form .= $iface . "&amp;queue=". $qname . "&amp;action=add\">";
4945
	$form .= "<img src=\"";
4946
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4947
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\" alt=\"clone\" />";
4948
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4949

    
4950
	return $form;
4951

    
4952
}
4953

    
4954

    
4955
$default_shaper_msg =  "<tr><td align=\"center\" width=\"80%\">";
4956
$default_shaper_msg .= "<span class=\"vexpl\"><strong><b>" . sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "</b><br />";
4957
$default_shaper_msg .= gettext("The tree on the left helps you navigate through the queues <br />"
4958
	. "buttons at the bottom represent queue actions and are activated accordingly.");
4959
$default_shaper_msg .= "</strong></span>";
4960
$default_shaper_msg .= "</td></tr>";
4961

    
4962
$dn_default_shaper_msg =  "<tr><td align=\"center\" width=\"80%\">";
4963
$dn_default_shaper_msg .= "<span class=\"vexpl\"><strong><b>" . sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "</b><br />";
4964
$dn_default_shaper_msg .= gettext("The tree on the left helps you navigate through the queues <br />"
4965
	. "buttons at the bottom represent queue actions and are activated accordingly.");
4966
$dn_default_shaper_msg .= "</strong></span>";
4967
$dn_default_shaper_msg .= "</td></tr>";
4968

    
4969
?>
(51-51/68)