Project

General

Profile

Download (134 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
	/*
702
	 * For requesting the parameters of the root queues
703
	 * to the user like the traffic wizard does.
704
	 */
705
	function build_form() {
706

    
707
		$sform = new Form(new Form_Button(
708
			'Submit',
709
			'Save'
710
		));
711

    
712
		$section = new Form_Section(null);
713

    
714
		$section->addInput(new Form_Checkbox(
715
			'enabled',
716
			'Enable/Disable',
717
			'Enable/disable discipline and its children',
718
			($this->GetEnabled() == "on"),
719
			'on'
720
		));
721

    
722
		$section->addInput(new Form_StaticText(
723
			'Name',
724
			$this->GetQname()
725
		));
726

    
727
		$section->addInput(new Form_Select(
728
			'scheduler',
729
			'Scheduler Type',
730
			$this->GetScheduler(),
731
			array('HFSC' => 'HFSC',
732
				  'CBQ' => 'CBQ',
733
				  'FAIRQ' => 'FAIRQ',
734
				  'CODELQ' => 'CODELQ',
735
				  'PRIQ' => 'PRIQ')
736
		))->setHelp('Changing this changes all child queues! Beware you can lose information.');
737

    
738
		$group = new Form_group('Bandwidth');
739

    
740
		$group->add(new Form_Input(
741
			'bandwidth',
742
			null,
743
			'number',
744
			$this->GetBandwidth()
745
		));
746

    
747
		$group->add(new Form_Select(
748
			'bandwidthtype',
749
			null,
750
			$this->GetBwscale(),
751
			array('Kb' => 'Kb',
752
				  'Mb' => 'Mb',
753
				  'Gb' => 'Gb',
754
				  'b' => 'b')
755
		));
756

    
757
		$section->add($group);
758

    
759
		$section->addInput(new Form_Input(
760
			'qlimit',
761
			'Queue Limit',
762
			'number',
763
			$this->GetQlimit()
764
		));
765

    
766
		$section->addInput(new Form_Input(
767
			'tbrconfig',
768
			'TRB Size',
769
			'number',
770
			$this->GetTbrConfig()
771
		))->setHelp('Adjusts the size, in bytes, of the token bucket regulator. If not specified, heuristics based on the interface ' .
772
					'bandwidth are used to determine the size.');
773

    
774
		$section->addInput(new Form_Input(
775
			'interface',
776
			null,
777
			'hidden',
778
			$this->GetInterface()
779
		));
780

    
781
		$section->addInput(new Form_Input(
782
			'name',
783
			null,
784
			'hidden',
785
			$this->GetQname()
786
		));
787

    
788
		$sform->add($section);
789

    
790
		return($sform);
791
	}
792

    
793
	function update_altq_queue_data(&$data) {
794
		$this->ReadConfig($data);
795
	}
796

    
797
	/*
798
	 * Should call on each of it queues and subqueues
799
	 * the same function much like build_rules();
800
	 */
801
	function wconfig() {
802
		$cflink = &get_reference_to_me_in_config($this->GetLink());
803
		if (!is_array($cflink)) {
804
			$cflink = array();
805
		}
806
		$cflink['interface'] = $this->GetInterface();
807
		$cflink['name'] = $this->GetQname();
808
		$cflink['scheduler'] = $this->GetScheduler();
809
		$cflink['bandwidth'] = $this->GetBandwidth();
810
		$cflink['bandwidthtype'] = $this->GetBwscale();
811
		$cflink['qlimit'] = trim($this->GetQlimit());
812
		if (empty($cflink['qlimit'])) {
813
			unset($cflink['qlimit']);
814
		}
815
		$cflink['tbrconfig'] = trim($this->GetTbrConfig());
816
		if (empty($cflink['tbrconfig'])) {
817
			unset($cflink['tbrconfig']);
818
		}
819
		$cflink['enabled'] = $this->GetEnabled();
820
		if (empty($cflink['enabled'])) {
821
			unset($cflink['enabled']);
822
		}
823
	}
824

    
825
}
826

    
827
class priq_queue {
828
	var $qname;
829
	var $qinterface;
830
	var $qlimit;
831
	var $qpriority;
832
	var $description;
833
	var $isparent;
834
	var $qbandwidth;
835
	var $qbandwidthtype;
836
	var $qdefault = "";
837
	var $qrio = "";
838
	var $qred = "";
839
	var $qcodel = "";
840
	var $qecn = "";
841
	var $qack;
842
	var $qenabled = "";
843
	var $qparent;
844
	var $link;
845
	var $available_bw; /* in b/s */
846

    
847
	/* This is here to help with form building and building rules/lists */
848
	var $subqueues = array();
849

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

    
941
		return false;
942
	}
943
	function GetDefault() {
944
		return $this->qdefault;
945
	}
946
	function SetDefault($value = false) {
947
		$this->qdefault = $value;
948
	}
949
	function GetCodel() {
950
		return $this->codel;
951
	}
952
	function SetCodel($codel = false) {
953
		$this->codel = $codel;
954
	}
955
	function GetRed() {
956
		return $this->qred;
957
	}
958
	function SetRed($red = false) {
959
		$this->qred = $red;
960
	}
961
	function GetRio() {
962
		return $this->qrio;
963
	}
964
	function SetRio($rio = false) {
965
		$this->qrio = $rio;
966
	}
967
	function GetEcn() {
968
		return $this->qecn;
969
	}
970
	function SetEcn($ecn = false) {
971
		$this->qecn = $ecn;
972
	}
973
	function GetAck() {
974
		return $this->qack;
975
	}
976
	function SetAck($ack = false) {
977
		$this->qack = $ack;
978
	}
979

    
980
	function build_javascript() {
981
		$javascript = "<script type=\"text/javascript\">";
982
		$javascript .= "//<![CDATA[\n";
983
		$javascript .= "function mySuspend() { \n";
984
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
985
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
986
		$javascript .= "else if (document.all)\n";
987
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
988
		$javascript .= "}\n";
989

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

    
999
		return $javascript;
1000
	}
1001

    
1002
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
1003

    
1004
	/*
1005
	 * Currently this will not be called unless we decide to clone a whole
1006
	 * queue tree on the 'By Queues' view or support drag&drop on the tree/list
1007
	 */
1008
	function copy_queue($interface, &$cflink) {
1009

    
1010
		$cflink['name'] = $this->GetQname();
1011
		$cflink['interface'] = $interface;
1012
		$cflink['qlimit'] = $this->GetQlimit();
1013
		$cflink['priority'] = $this->GetQpriority();
1014
		$cflink['description'] = $this->GetDescription();
1015
		$cflink['enabled'] = $this->GetEnabled();
1016
		$cflink['default'] = $this->GetDefault();
1017
		$cflink['red'] = $this->GetRed();
1018
		$cflink['codel'] = $this->GetCodel();
1019
		$cflink['rio'] = $this->GetRio();
1020
		$cflink['ecn'] = $this->GetEcn();
1021

    
1022
		if (is_array($this->subqueues)) {
1023
			$cflinkp['queue'] = array();
1024
			foreach ($this->subqueues as $q) {
1025
				$cflink['queue'][$q->GetQname()] = array();
1026
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1027
			}
1028
		}
1029
	}
1030

    
1031
	function clean_queue($sched) {
1032
		clean_child_queues($sched, $this->GetLink());
1033
		if (is_array($this->subqueues)) {
1034
			foreach ($this->subqueues as $q) {
1035
				$q->clean_queue($sched);
1036
			}
1037
		}
1038
	}
1039

    
1040
	function &get_queue_list(&$qlist) {
1041

    
1042
		$qlist[$this->GetQname()] = & $this;
1043
		if (is_array($this->subqueues)) {
1044
			foreach ($this->subqueues as $queue) {
1045
				$queue->get_queue_list($qlist);
1046
			}
1047
		}
1048
	}
1049

    
1050
	function delete_queue() {
1051
		unref_on_altq_queue_list($this->GetQname());
1052
		cleanup_queue_from_rules($this->GetQname());
1053
		unset_object_by_reference($this->GetLink());
1054
	}
1055

    
1056
	function delete_all() {
1057
		if (count($this->subqueues)) {
1058
			foreach ($this->subqueues as $q) {
1059
				$q->delete_all();
1060
				unset_object_by_reference($q->GetLink());
1061
				unset($q);
1062
			}
1063
			unset($this->subqueues);
1064
		}
1065
	}
1066

    
1067
	function &find_queue($interface, $qname) {
1068
		if ($qname == $this->GetQname()) {
1069
			return $this;
1070
		}
1071
	}
1072

    
1073
	function find_parentqueue($interface, $qname) { return; }
1074

    
1075
	function validate_input($data, &$input_errors) {
1076

    
1077
		$reqdfields[] = "name";
1078
		$reqdfieldsn[] = gettext("Name");
1079
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1080

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

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

    
1171
	function build_tree() {
1172
		$tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&amp;queue=". $this->GetQname()."&amp;action=show";
1173
		$tree .= "\" ";
1174
		$tmpvalue = $this->GetDefault();
1175
		if (!empty($tmpvalue)) {
1176
			$tree .= " class=\"navlnk\"";
1177
		}
1178
		$tree .= " >" . $this->GetQname() . "</a>";
1179
		/*
1180
		 * Not needed here!
1181
		 * if (is_array($queues) {
1182
		 *	  $tree .= "<ul>";
1183
		 *	  foreach ($q as $queues)
1184
		 *		  $tree .= $queues['$q->GetName()']->build_tree();
1185
		 *	  endforeach
1186
		 *	  $tree .= "</ul>";
1187
		 * }
1188
		 */
1189

    
1190
		$tree .= "</li>";
1191

    
1192
		return $tree;
1193
	}
1194

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

    
1253
		$pfq_rule .= " \n";
1254

    
1255
		return $pfq_rule;
1256
	}
1257

    
1258
	/*
1259
	 * To return the html form to show to user
1260
	 * for getting the parameters.
1261
	 * Should do even for first time when the
1262
	 * object is created and later when we may
1263
	 * need to update it. (2)
1264
	 */
1265

    
1266
	function build_form() {
1267

    
1268
		$sform = new Form();
1269

    
1270
		$section = new Form_Section(null);
1271

    
1272
		$section->addInput(new Form_Checkbox(
1273
			'enabled',
1274
			'Enable/Disable',
1275
			'Enable/disable discipline and its children',
1276
			($this->GetEnabled() == "on"),
1277
			'on'
1278
		));
1279

    
1280
		$section->addInput(new Form_StaticText(
1281
			'Name',
1282
			$this->GetQname()
1283
		))->setHelp('Enter the name of the queue here. Do not use spaces and limit the size to 15 characters.');
1284

    
1285
		$section->addInput(new Form_Input(
1286
			'priority',
1287
			'Priority',
1288
			'number',
1289
			$this->GetQpriority(),
1290
			['min' => '0', 'max'=> '7']
1291
		))->setHelp('For hfsc, the range is 0 to 7. The default is 1. Hfsc queues with a higher priority are preferred in the case of overload.');
1292

    
1293
		$section->addInput(new Form_Input(
1294
			'qlimit',
1295
			'Queue Limit',
1296
			'number',
1297
			$this->GetQlimit()
1298
		))->setHelp('Queue limit in packets.');
1299

    
1300
		$group = new Form_Group('Scheduler options');
1301

    
1302
		if (empty($this->subqueues)) {
1303
			$group->add(new Form_Checkbox(
1304
				'default',
1305
				null,
1306
				null,
1307
				$this->GetDefault()
1308
			))->setHelp('Default Queue');
1309
		}
1310

    
1311
		$group->add(new Form_Checkbox(
1312
			'red',
1313
			null,
1314
			null,
1315
			!empty($this->GetRed())
1316
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#red">' . gettext('Random Early Detection') . '</a>');
1317

    
1318
		$group->add(new Form_Checkbox(
1319
			'rio',
1320
			null,
1321
			null,
1322
			!empty($this->GetRio())
1323
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#rio">' . gettext('Random Early Detection In and Out') . '</a>');
1324

    
1325
		$group->add(new Form_Checkbox(
1326
			'ecn',
1327
			null,
1328
			null,
1329
			!empty($this->GetEcn())
1330
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#ecn">' . gettext('Explicit Congestion Notification') . '</a>');
1331

    
1332
		$group->add(new Form_Checkbox(
1333
			'codel',
1334
			null,
1335
			null,
1336
			!empty($this->GetCodel())
1337
		))->setHelp('<a target="_new" href="http://www.openbsd.org/faq/pf/queueing.html#ecn">' . gettext('Explicit Congestion Notification') . '</a>');
1338

    
1339
		$group->setHelp('Select options for this queue');
1340

    
1341
		$section->add($group);
1342

    
1343
		$section->addInput(new Form_Input(
1344
			'description',
1345
			'Description',
1346
			'text',
1347
			$this->GetDescription()
1348
		));
1349

    
1350
		$section->addInput(new Form_Input(
1351
			'interface',
1352
			null,
1353
			'hidden',
1354
			$this->GetInterface()
1355
		));
1356

    
1357
		$sform->add($section);
1358

    
1359
		return($sform);
1360
	}
1361

    
1362
	function build_shortform() {
1363
		/* XXX: Hacks in sight. Mostly layer violations!  */
1364
		global $g, $altq_list_queues;
1365
		global $shaperIFlist;
1366

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

    
1399
		return $form;
1400

    
1401
	}
1402

    
1403
	function update_altq_queue_data(&$q) {
1404
		$this->ReadConfig($q);
1405
	}
1406

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

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

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

    
1558
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1559

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

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

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

    
1596
		return $q;
1597
	}
1598

    
1599
	function copy_queue($interface, &$cflink) {
1600

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

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

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

    
1712
	/*
1713
	 * Should search even its children
1714
	 */
1715
	function &find_queue($interface, $qname) {
1716
		if ($qname == $this->GetQname()) {
1717
			return $this;
1718
		}
1719

    
1720
		foreach ($this->subqueues as $q) {
1721
			$result =& $q->find_queue("", $qname);
1722
			if ($result) {
1723
				return $result;
1724
			}
1725
		}
1726
	}
1727

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

    
1740
	function validate_input($data, &$input_errors) {
1741
		parent::validate_input($data, $input_errors);
1742

    
1743
		$reqdfields[] = "bandwidth";
1744
		$reqdfieldsn[] = gettext("Bandwidth");
1745
		$reqdfields[] = "bandwidthtype";
1746
		$reqdfieldsn[] = gettext("Bandwidthtype");
1747

    
1748
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1749

    
1750
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1751
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) {
1752
				$input_errors[] = gettext("Bandwidth must be an integer.");
1753
			}
1754

    
1755
			if ($data['bandwidth'] < 0) {
1756
				$input_errors[] = gettext("Bandwidth cannot be negative.");
1757
			}
1758

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

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

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

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

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

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

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

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

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

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

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

    
1943
	/* Even this should take children into consideration */
1944
	function build_rules(&$default = false) {
1945

    
1946
		$pfq_rule = " queue ". $this->qname;
1947
		if ($this->GetInterface()) {
1948
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1949
		}
1950
		if ($this->GetBandwidth() && $this->GetBwscale()) {
1951
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
1952
		}
1953

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

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

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

    
2051
		$pfq_rule .= " \n";
2052

    
2053
		return $pfq_rule;
2054
	}
2055

    
2056
	function build_javascript() {
2057

    
2058
		$javascript = <<<EOJS
2059
<script type="text/javascript">
2060
//<![CDATA[
2061
	events.push(function(){
2062

    
2063
		// Disables the specified input element
2064
		function disableInput(id, disable) {
2065
			$('#' + id).prop("disabled", disable);
2066
		}
2067

    
2068
		// Upperlimit
2069
		function enable_upperlimit() {
2070
			disableInput('upperlimit1', !$('#upperlimit').prop('checked'));
2071
			disableInput('upperlimit2', !$('#upperlimit').prop('checked'));
2072
			disableInput('upperlimit3', !$('#upperlimit').prop('checked'));
2073
		}
2074

    
2075
		$('#upperlimit').click(function () {
2076
			enable_upperlimit();
2077
		});
2078

    
2079
		enable_upperlimit();
2080

    
2081
		// realtime
2082
		function enable_realtime() {
2083
			disableInput('realtime1', !$('#realtime').prop('checked'));
2084
			disableInput('realtime2', !$('#realtime').prop('checked'));
2085
			disableInput('realtime3', !$('#realtime').prop('checked'));
2086
		}
2087

    
2088
		$('#realtime').click(function () {
2089
			enable_realtime();
2090
		});
2091

    
2092
		enable_realtime();
2093

    
2094
		// linkshare
2095
		function enable_linkshare() {
2096
			disableInput('linkshare1', !$('#linkshare').prop('checked'));
2097
			disableInput('linkshare2', !$('#linkshare').prop('checked'));
2098
			disableInput('linkshare3', !$('#linkshare').prop('checked'));
2099
		}
2100

    
2101
		$('#linkshare').click(function () {
2102
			enable_linkshare();
2103
		});
2104

    
2105
		enable_linkshare();
2106
	});
2107
//]]>
2108
</script>
2109
EOJS;
2110

    
2111
		return $javascript;
2112
	}
2113

    
2114
	function build_form() {
2115

    
2116
		$sform = parent::build_form();
2117

    
2118
		$section = new Form_Section('Service Curve (sc)');
2119

    
2120
		$group = new Form_Group('Bandwidth');
2121

    
2122
		$group->add(new Form_Input(
2123
			'bandwidth',
2124
			null,
2125
			'number',
2126
			$this->GetBandwidth()
2127
		));
2128

    
2129
		$group->add(new Form_Select(
2130
			'bandwidthtype',
2131
			null,
2132
			$this->GetBwscale(),
2133
			array('Kb' => 'Kb',
2134
				  'Mb' => 'Mb',
2135
				  'Gb' => 'Gb',
2136
				  'b' => 'b')
2137
		));
2138

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

    
2141
		$section->add($group);
2142

    
2143
		$group = new Form_Group('Max bandwidth for queue.');
2144

    
2145
		$group->add(new Form_Checkbox(
2146
			'upperlimit',
2147
			null,
2148
			'Upper Limit',
2149
			($this->GetUpperlimit()<> "")
2150
		));
2151

    
2152
		$group->add(new Form_Input(
2153
			'upperlimit1',
2154
			null,
2155
			'text',
2156
			$this->GetU_m1()
2157
		));
2158

    
2159
		$group->add(new Form_Input(
2160
			'upperlimit2',
2161
			null,
2162
			'text',
2163
			$this->GetU_d()
2164
		));
2165
		$group->add(new Form_Input(
2166
			'upperlimit3',
2167
			null,
2168
			'text',
2169
			$this->GetU_m2()
2170
		));
2171

    
2172

    
2173
		$section->add($group);
2174

    
2175
		$group = new Form_Group('Min bandwidth for queue.');
2176

    
2177
		$group->add(new Form_Checkbox(
2178
			'realtime',
2179
			null,
2180
			'Real Time',
2181
			($this->GetRealtime()<> "")
2182
		));
2183

    
2184
		$group->add(new Form_Input(
2185
			'realtime1',
2186
			null,
2187
			'text',
2188
			$this->GetR_m1()
2189
		));
2190

    
2191
		$group->add(new Form_Input(
2192
			'realtime2',
2193
			null,
2194
			'text',
2195
			$this->GetR_d()
2196
		));
2197
		$group->add(new Form_Input(
2198
			'realtime3',
2199
			null,
2200
			'text',
2201
			$this->GetR_m2()
2202
		));
2203

    
2204
		$section->add($group);
2205

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

    
2208
		$group->add(new Form_Checkbox(
2209
			'linkshare',
2210
			null,
2211
			'Link Share',
2212
			($this->GetLinkshare()<> "")
2213
		));
2214

    
2215
		$group->add(new Form_Input(
2216
			'linkshare1',
2217
			null,
2218
			'text',
2219
			$this->GetL_m1()
2220
		));
2221

    
2222
		$group->add(new Form_Input(
2223
			'linkshare2',
2224
			null,
2225
			'text',
2226
			$this->GetL_d()
2227
		));
2228
		$group->add(new Form_Input(
2229
			'linkshare3',
2230
			null,
2231
			'text',
2232
			$this->GetL_m2()
2233
		));
2234

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

    
2240
		$section->add($group);
2241

    
2242
		$sform->add($section);
2243

    
2244
		return($sform);
2245
	}
2246

    
2247
	function update_altq_queue_data(&$data) {
2248
		$this->ReadConfig($data);
2249
	}
2250

    
2251
	function wconfig() {
2252
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2253
		if (!is_array($cflink)) {
2254
			$cflink = array();
2255
		}
2256
		$cflink['name'] = $this->GetQname();
2257
		$cflink['interface'] = $this->GetInterface();
2258
		$cflink['qlimit'] = trim($this->GetQlimit());
2259
		if (empty($cflink['qlimit'])) {
2260
			unset($cflink['qlimit']);
2261
		}
2262
		$cflink['priority'] = $this->GetQpriority();
2263
		if (empty($cflink['priority'])) {
2264
			unset($cflink['priority']);
2265
		}
2266
		$cflink['description'] = $this->GetDescription();
2267
		if (empty($cflink['description'])) {
2268
			unset($cflink['description']);
2269
		}
2270
		$cflink['bandwidth'] = $this->GetBandwidth();
2271
		$cflink['bandwidthtype'] = $this->GetBwscale();
2272
		$cflink['enabled'] = $this->GetEnabled();
2273
		if (empty($cflink['enabled'])) {
2274
			unset($cflink['enabled']);
2275
		}
2276
		$cflink['default'] = $this->GetDefault();
2277
		if (empty($cflink['default'])) {
2278
			unset($cflink['default']);
2279
		}
2280
		$cflink['red'] = trim($this->GetRed());
2281
		if (empty($cflink['red'])) {
2282
			unset($cflink['red']);
2283
		}
2284
		$cflink['rio'] = $this->GetRio();
2285
		if (empty($cflink['rio'])) {
2286
			unset($cflink['rio']);
2287
		}
2288
		$cflink['ecn'] = trim($this->GetEcn());
2289
		if (empty($cflink['ecn'])) {
2290
			unset($cflink['ecn']);
2291
		}
2292
		$cflink['codel'] = trim($this->GetCodel());
2293
		if (empty($cflink['codel'])) {
2294
			unset($cflink['codel']);
2295
		}
2296
		if ($this->GetLinkshare() <> "") {
2297
			if ($this->GetL_m1() <> "") {
2298
				$cflink['linkshare1'] = $this->GetL_m1();
2299
				$cflink['linkshare2'] = $this->GetL_d();
2300
				$cflink['linkshare'] = "on";
2301
			} else {
2302
				unset($cflink['linkshare']);
2303
				unset($cflink['linkshare1']);
2304
				unset($cflink['linkshare2']);
2305
			}
2306
			if ($this->GetL_m2() <> "") {
2307
				$cflink['linkshare3'] = $this->GetL_m2();
2308
				$cflink['linkshare'] = "on";
2309
			} else {
2310
				unset($cflink['linkshare']);
2311
				unset($cflink['linkshare3']);
2312
			}
2313
		} else {
2314
			unset($cflink['linkshare']);
2315
			unset($cflink['linkshare1']);
2316
			unset($cflink['linkshare2']);
2317
			unset($cflink['linkshare3']);
2318
		}
2319
		if ($this->GetRealtime() <> "") {
2320
			if ($this->GetR_m1() <> "") {
2321
				$cflink['realtime1'] = $this->GetR_m1();
2322
				$cflink['realtime2'] = $this->GetR_d();
2323
				$cflink['realtime'] = "on";
2324
			} else {
2325
				unset($cflink['realtime']);
2326
				unset($cflink['realtime1']);
2327
				unset($cflink['realtime2']);
2328
			}
2329
			if ($this->GetR_m2() <> "") {
2330
				$cflink['realtime3'] = $this->GetR_m2();
2331
				$cflink['realtime'] = "on";
2332
			} else {
2333
				unset($cflink['realtime']);
2334
				unset($cflink['realtime3']);
2335
			}
2336
		} else {
2337
			unset($cflink['realtime']);
2338
			unset($cflink['realtime1']);
2339
			unset($cflink['realtime2']);
2340
			unset($cflink['realtime3']);
2341
		}
2342
		if ($this->GetUpperlimit() <> "") {
2343
			if ($this->GetU_m1() <> "") {
2344
				$cflink['upperlimit1'] = $this->GetU_m1();
2345
				$cflink['upperlimit2'] = $this->GetU_d();
2346
				$cflink['upperlimit'] = "on";
2347
			} else {
2348
				unset($cflink['upperlimit']);
2349
				unset($cflink['upperlimit1']);
2350
				unset($cflink['upperlimit2']);
2351
			}
2352
			if ($this->GetU_m2() <> "") {
2353
				$cflink['upperlimit3'] = $this->GetU_m2();
2354
				$cflink['upperlimit'] = "on";
2355
			} else {
2356
				unset($cflink['upperlimit']);
2357
				unset($cflink['upperlimit3']);
2358
			}
2359
		} else {
2360
			unset($cflink['upperlimit']);
2361
			unset($cflink['upperlimit1']);
2362
			unset($cflink['upperlimit2']);
2363
			unset($cflink['upperlimit3']);
2364
		}
2365
	}
2366
}
2367

    
2368
class cbq_queue extends priq_queue {
2369
	var $qborrow = "";
2370

    
2371
	function GetBorrow() {
2372
		return $this->qborrow;
2373
	}
2374
	function SetBorrow($borrow) {
2375
		$this->qborrow = $borrow;
2376
	}
2377
	function CanHaveChildren() {
2378
		return true;
2379
	}
2380

    
2381
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2382

    
2383
		if (!is_array($this->subqueues)) {
2384
			$this->subqueues = array();
2385
		}
2386
		$q =& new cbq_queue();
2387
		$q->SetInterface($this->GetInterface());
2388
		$q->SetParent($this);
2389
		$q->ReadConfig($qname);
2390
		$q->validate_input($qname, $input_errors);
2391
		if (count($input_errors)) {
2392
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
2393
			return $q;
2394
		}
2395
		switch ($q->GetBwscale()) {
2396
			case "%":
2397
				$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
2398
				break;
2399
			default:
2400
				$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
2401
				break;
2402
		}
2403
		$q->SetAvailableBandwidth($myBw);
2404
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
2405

    
2406
		$q->SetEnabled("on");
2407
		$q->SetLink($path);
2408
		$this->subqueues[$q->GetQName()] = &$q;
2409
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2410
		if (is_array($qname['queue'])) {
2411
			foreach ($qname['queue'] as $key1 => $que) {
2412
				array_push($path, $key1);
2413
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
2414
				array_pop($path);
2415
			}
2416
		}
2417

    
2418
		return $q;
2419
	}
2420

    
2421
	function copy_queue($interface, &$cflink) {
2422

    
2423
		$cflink['interface'] = $interface;
2424
		$cflink['qlimit'] = trim($this->GetQlimit());
2425
		if (empty($clink['qlimit'])) {
2426
			unset($cflink['qlimit']);
2427
		}
2428
		$cflink['priority'] = trim($this->GetQpriority());
2429
		if (empty($cflink['priority'])) {
2430
			unset($cflink['priority']);
2431
		}
2432
		$cflink['name'] = $this->GetQname();
2433
		$cflink['description'] = trim($this->GetDescription());
2434
		if (empty($cflink['description'])) {
2435
			unset($cflink['description']);
2436
		}
2437
		$cflink['bandwidth'] = $this->GetBandwidth();
2438
		$cflink['bandwidthtype'] = $this->GetBwscale();
2439
		$cflink['enabled'] = trim($this->GetEnabled());
2440
		if (empty($cflink['enabled'])) {
2441
			unset($cflink['enabled']);
2442
		}
2443
		$cflink['default'] = trim($this->GetDefault());
2444
		if (empty($cflink['default'])) {
2445
			unset($cflink['default']);
2446
		}
2447
		$cflink['red'] = trim($this->GetRed());
2448
		if (empty($cflink['red'])) {
2449
			unset($cflink['red']);
2450
		}
2451
		$cflink['rio'] = trim($this->GetRio());
2452
		if (empty($cflink['rio'])) {
2453
			unset($cflink['rio']);
2454
		}
2455
		$cflink['ecn'] = trim($this->GetEcn());
2456
		if (empty($cflink['ecn'])) {
2457
			unset($cflink['ecn']);
2458
		}
2459
		$cflink['borrow'] = trim($this->GetBorrow());
2460
		if (empty($cflink['borrow'])) {
2461
			unset($cflink['borrow']);
2462
		}
2463
		if (is_array($this->queues)) {
2464
			$cflinkp['queue'] = array();
2465
			foreach ($this->subqueues as $q) {
2466
				$cflink['queue'][$q->GetQname()] = array();
2467
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
2468
			}
2469
		}
2470
	}
2471

    
2472
	/*
2473
	 * Should search even its children
2474
	 */
2475
	function &find_queue($interface, $qname) {
2476
		if ($qname == $this->GetQname()) {
2477
			return $this;
2478
		}
2479
		foreach ($this->subqueues as $q) {
2480
			$result =& $q->find_queue("", $qname);
2481
			if ($result) {
2482
				return $result;
2483
			}
2484
		}
2485
	}
2486

    
2487
	function &find_parentqueue($interface, $qname) {
2488
		if ($this->subqueues[$qname]) {
2489
			return $this;
2490
		}
2491
		foreach ($this->subqueues as $q) {
2492
			$result = $q->find_parentqueue("", $qname);
2493
			if ($result) {
2494
				return $result;
2495
			}
2496
		}
2497
	}
2498

    
2499
	function delete_queue() {
2500
		unref_on_altq_queue_list($this->GetQname());
2501
		cleanup_queue_from_rules($this->GetQname());
2502
		foreach ($this->subqueues as $q) {
2503
			$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
2504
				$q->delete_queue();
2505
		}
2506
		unset_object_by_reference($this->GetLink());
2507
	}
2508

    
2509
	function validate_input($data, &$input_errors) {
2510
		parent::validate_input($data, $input_errors);
2511

    
2512
		if ($data['priority'] > 7) {
2513
				$input_errors[] = gettext("Priority must be an integer between 1 and 7.");
2514
		}
2515
		$reqdfields[] = "bandwidth";
2516
		$reqdfieldsn[] = gettext("Bandwidth");
2517
		$reqdfields[] = "bandwidthtype";
2518
		$reqdfieldsn[] = gettext("Bandwidthtype");
2519

    
2520
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2521

    
2522
		if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
2523
			$input_errors[] = gettext("Bandwidth must be an integer.");
2524
		}
2525

    
2526

    
2527
		if ($data['bandwidth'] < 0) {
2528
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2529
		}
2530

    
2531
		if ($data['bandwidthtype'] == "%") {
2532
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
2533
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2534
			}
2535
		}
2536

    
2537
/*
2538
		$parent =& $this->GetParent();
2539
		switch ($data['bandwidthtype']) {
2540
		case "%":
2541
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2542
			break;
2543
		default:
2544
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2545
			break;
2546
		}
2547
		if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
2548
			$input_errors[] = "The sum of the children bandwidth exceeds that of the parent.";
2549
		}
2550
 */
2551
	}
2552

    
2553
	function ReadConfig(&$q) {
2554
		parent::ReadConfig($q);
2555
		if (!empty($q['borrow'])) {
2556
			$this->SetBorrow("on");
2557
		} else {
2558
			$this->SetBorrow("");
2559
		}
2560
	}
2561

    
2562
	function build_javascript() {
2563
		return parent::build_javascript();
2564
	}
2565

    
2566
	function build_tree() {
2567
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2568
		$tree .= "\" ";
2569
		$tmpvalue = trim($this->GetDefault());
2570
		if (!empty($tmpvalue)) {
2571
			$tree .= " class=\"navlnk\"";
2572
		}
2573
		$tree .= " >" . $this->GetQname() . "</a>";
2574
		if (is_array($this->subqueues)) {
2575
			$tree .= "<ul>";
2576
			foreach ($this->subqueues as $q)  {
2577
				$tree .= $q->build_tree();
2578
			}
2579
			$tree .= "</ul>";
2580
		}
2581
		$tree .= "</li>";
2582
		return $tree;
2583
	}
2584

    
2585
	/* Even this should take children into consideration */
2586
	function build_rules(&$default = false) {
2587
		$pfq_rule = "queue ". $this->qname;
2588
		if ($this->GetInterface()) {
2589
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2590
		}
2591
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2592
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2593
		}
2594
		$tmpvalue = $this->GetQpriority();
2595
		if (!empty($tmpvalue)) {
2596
			$pfq_rule .= " priority " . $this->GetQpriority();
2597
		}
2598
		$tmpvalue = trim($this->GetQlimit());
2599
		if (!empty($tmpvalue)) {
2600
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2601
		}
2602
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow() || $this->GetCodel()) {
2603
			$pfq_rule .= " cbq ( ";
2604
			$tmpvalue = trim($this->GetRed());
2605
			if (!empty($tmpvalue)) {
2606
				$comma = 1;
2607
				$pfq_rule .= " red ";
2608
			}
2609
			$tmpvalue = trim($this->GetCodel());
2610
			if (!empty($tmpvalue)) {
2611
				$comma = 1;
2612
				$pfq_rule .= " codel ";
2613
			}
2614
			$tmpvalue = trim($this->GetRio());
2615
			if (!empty($tmpvalue)) {
2616
				if ($comma) {
2617
					$pfq_rule .= " ,";
2618
				}
2619
				$comma = 1;
2620
				$pfq_rule .= " rio ";
2621
			}
2622
			$tmpvalue = trim($this->GetEcn());
2623
			if (!empty($tmpvalue)) {
2624
				if ($comma) {
2625
					$pfq_rule .= " ,";
2626
				}
2627
				$comma = 1;
2628
				$pfq_rule .= " ecn ";
2629
			}
2630
			$tmpvalue = trim($this->GetDefault());
2631
			if (!empty($tmpvalue)) {
2632
				if ($comma) {
2633
					$pfq_rule .= " ,";
2634
				}
2635
				$comma = 1;
2636
				$pfq_rule .= " default ";
2637
				$default = true;
2638
			}
2639
			$tmpvalue = trim($this->GetBorrow());
2640
			if (!empty($tmpvalue)) {
2641
				if ($comma) {
2642
					$pfq_rule .= ", ";
2643
				}
2644
				$pfq_rule .= " borrow ";
2645
			}
2646
			$pfq_rule .= " ) ";
2647
		}
2648
		if (count($this->subqueues)) {
2649
			$i = count($this->subqueues);
2650
			$pfq_rule .= " { ";
2651
			foreach ($this->subqueues as $qkey => $qnone) {
2652
				if ($i > 1) {
2653
					$i--;
2654
					$pfq_rule .= " {$qkey}, ";
2655
				} else {
2656
					$pfq_rule .= " {$qkey} ";
2657
				}
2658
			}
2659
			$pfq_rule .= " } \n";
2660
			foreach ($this->subqueues as $q) {
2661
				$pfq_rule .= $q->build_rules($default);
2662
			}
2663
		}
2664

    
2665
		$pfq_rule .= " \n";
2666
		return $pfq_rule;
2667
	}
2668

    
2669
	function build_form() {
2670
		$sform = parent::build_form();
2671

    
2672
		$section = new Form_Section('');
2673

    
2674
		$group = new Form_Group('Bandwidth');
2675

    
2676
		$group->add(new Form_Input(
2677
			'bandwidth',
2678
			null,
2679
			'number',
2680
			$this->GetBandwidth()
2681
		));
2682

    
2683
		$group->add(new Form_Select(
2684
			'bandwidthtype',
2685
			null,
2686
			$this->GetBwscale(),
2687
			array('Kb' => 'Kb',
2688
				  'Mb' => 'Mb',
2689
				  'Gb' => 'Gb',
2690
				  'b' => 'b')
2691
		));
2692

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

    
2695
		$section->add($group);
2696

    
2697
		$section->addInput(new Form_Checkbox(
2698
			'borrow',
2699
			'Scheduler option',
2700
			'Borrow from other queues when available',
2701
			($this->GetBorrow() == "on")
2702
		));
2703

    
2704
		return $sform;
2705
	}
2706

    
2707
	function update_altq_queue_data(&$data) {
2708
		$this->ReadConfig($data);
2709
	}
2710

    
2711
	function wconfig() {
2712
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2713
		if (!is_array($cflink)) {
2714
			$cflink = array();
2715
		}
2716
		$cflink['interface'] = $this->GetInterface();
2717
		$cflink['qlimit'] = trim($this->GetQlimit());
2718
		if (empty($cflink['qlimit'])) {
2719
			unset($cflink['qlimit']);
2720
		}
2721
		$cflink['priority'] = $this->GetQpriority();
2722
		if (empty($cflink['priority'])) {
2723
			unset($cflink['priority']);
2724
		}
2725
		$cflink['name'] = $this->GetQname();
2726
		$cflink['description'] = $this->GetDescription();
2727
		if (empty($cflink['description'])) {
2728
			unset($cflink['description']);
2729
		}
2730
		$cflink['bandwidth'] = $this->GetBandwidth();
2731
		$cflink['bandwidthtype'] = $this->GetBwscale();
2732
		$cflink['enabled'] = trim($this->GetEnabled());
2733
		if (empty($cflink['enabled'])) {
2734
			unset($cflink['enabled']);
2735
		}
2736
		$cflink['default'] = trim($this->GetDefault());
2737
		if (empty($cflink['default'])) {
2738
			unset($cflink['default']);
2739
		}
2740
		$cflink['red'] = trim($this->GetRed());
2741
		if (empty($cflink['red'])) {
2742
			unset($cflink['red']);
2743
		}
2744
		$cflink['rio'] = trim($this->GetRio());
2745
		if (empty($cflink['rio'])) {
2746
			unset($cflink['rio']);
2747
		}
2748
		$cflink['ecn'] = trim($this->GetEcn());
2749
		if (empty($cflink['ecn'])) {
2750
			unset($cflink['ecn']);
2751
		}
2752
		$cflink['codel'] = trim($this->GetCodel());
2753
		if (empty($cflink['codel'])) {
2754
			unset($cflink['codel']);
2755
		}
2756
		$cflink['borrow'] = trim($this->GetBorrow());
2757
		if (empty($cflink['borrow'])) {
2758
			unset($cflink['borrow']);
2759
		}
2760
	}
2761
}
2762

    
2763
class fairq_queue extends priq_queue {
2764
	var $hogs;
2765
	var $buckets;
2766

    
2767
	function GetBuckets() {
2768
		return $this->buckets;
2769
	}
2770
	function SetBuckets($buckets) {
2771
		$this->buckets = $buckets;
2772
	}
2773
	function GetHogs() {
2774
		return $this->hogs;
2775
	}
2776
	function SetHogs($hogs) {
2777
		$this->hogs = $hogs;
2778
	}
2779
	function CanHaveChildren() {
2780
		return false;
2781
	}
2782

    
2783

    
2784
	function copy_queue($interface, &$cflink) {
2785
		$cflink['interface'] = $interface;
2786
		$cflink['qlimit'] = $this->GetQlimit();
2787
		$cflink['priority'] = $this->GetQpriority();
2788
		$cflink['name'] = $this->GetQname();
2789
		$cflink['description'] = $this->GetDescription();
2790
		$cflink['bandwidth'] = $this->GetBandwidth();
2791
		$cflink['bandwidthtype'] = $this->GetBwscale();
2792
		$cflink['enabled'] = $this->GetEnabled();
2793
		$cflink['default'] = $this->GetDefault();
2794
		$cflink['red'] = $this->GetRed();
2795
		$cflink['rio'] = $this->GetRio();
2796
		$cflink['ecn'] = $this->GetEcn();
2797
		$cflink['buckets'] = $this->GetBuckets();
2798
		$cflink['hogs'] = $this->GetHogs();
2799
	}
2800

    
2801
	/*
2802
	 * Should search even its children
2803
	 */
2804
	function &find_queue($interface, $qname) {
2805
		if ($qname == $this->GetQname()) {
2806
			return $this;
2807
		}
2808
	}
2809

    
2810
	function find_parentqueue($interface, $qname) { return; }
2811

    
2812
	function delete_queue() {
2813
		unref_on_altq_queue_list($this->GetQname());
2814
		cleanup_queue_from_rules($this->GetQname());
2815
		unset_object_by_reference($this->GetLink());
2816
	}
2817

    
2818
	function validate_input($data, &$input_errors) {
2819
		parent::validate_input($data, $input_errors);
2820

    
2821
		if ($data['priority'] > 255) {
2822
				$input_errors[] = gettext("Priority must be an integer between 1 and 255.");
2823
		}
2824
		$reqdfields[] = "bandwidth";
2825
		$reqdfieldsn[] = gettext("Bandwidth");
2826
		$reqdfields[] = "bandwidthtype";
2827
		$reqdfieldsn[] = gettext("Bandwidthtype");
2828

    
2829
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2830

    
2831
		if ($data['bandwidth'] && !is_numeric($data['bandwidth'])) {
2832
			$input_errors[] = gettext("Bandwidth must be an integer.");
2833
		}
2834

    
2835

    
2836
		if ($data['bandwidth'] < 0) {
2837
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2838
		}
2839

    
2840

    
2841
		if ($data['bandwidthtype'] == "%") {
2842
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0) {
2843
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2844
			}
2845
		}
2846

    
2847
/*
2848
		$parent =& $this->GetParent();
2849
		switch ($data['bandwidthtype']) {
2850
		case "%":
2851
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2852
		default:
2853
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2854
			break;
2855
		}
2856
		if ($parent->GetAvailableBandwidth() < floatval($myBw)) {
2857
			$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
2858
		}
2859
*/
2860
	}
2861

    
2862
	function ReadConfig(&$q) {
2863
		parent::ReadConfig($q);
2864
		if (!empty($q['buckets'])) {
2865
			$this->SetBuckets($q['buckets']);
2866
		} else {
2867
			$this->SetBuckets("");
2868
		}
2869
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs'])) {
2870
			$this->SetHogs($q['hogs']);
2871
		} else {
2872
			$this->SetHogs("");
2873
		}
2874
	}
2875

    
2876
	function build_javascript() {
2877
		return parent::build_javascript();
2878
	}
2879

    
2880
	function build_tree() {
2881
		$tree = " <li><a href=\"firewall_shaper.php?interface=" .
2882
		$this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2883
		$tree .= "\" ";
2884
		$tmpvalue = trim($this->GetDefault());
2885
		if (!empty($tmpvalue)) {
2886
			$tree .= " class=\"navlnk\"";
2887
		}
2888
		$tree .= " >" . $this->GetQname() . "</a>";
2889
		$tree .= "</li>";
2890
		return $tree;
2891
	}
2892

    
2893
	/* Even this should take children into consideration */
2894
	function build_rules(&$default = false) {
2895
		$pfq_rule = "queue ". $this->qname;
2896
		if ($this->GetInterface()) {
2897
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2898
		}
2899
		if ($this->GetBandwidth() && $this->GetBwscale()) {
2900
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2901
		}
2902
		$tmpvalue = trim($this->GetQpriority());
2903
		if (!empty($tmpvalue)) {
2904
			$pfq_rule .= " priority " . $this->GetQpriority();
2905
		}
2906
		$tmpvalue = trim($this->GetQlimit());
2907
		if (!empty($tmpvalue)) {
2908
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2909
		}
2910
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() ||
2911
			$this->GetEcn() || $this->GetBuckets() || $this->GetHogs() || $this->GetCodel()) {
2912
			$pfq_rule .= " fairq ( ";
2913
			$tmpvalue = trim($this->GetRed());
2914
			if (!empty($tmpvalue)) {
2915
				$comma = 1;
2916
				$pfq_rule .= " red ";
2917
			}
2918
			$tmpvalue = trim($this->GetCodel());
2919
			if (!empty($tmpvalue)) {
2920
				$comma = 1;
2921
				$pfq_rule .= " codel ";
2922
			}
2923
			$tmpvalue = trim($this->GetRio());
2924
			if (!empty($tmpvalue)) {
2925
				if ($comma) {
2926
					$pfq_rule .= " ,";
2927
				}
2928
				$comma = 1;
2929
				$pfq_rule .= " rio ";
2930
			}
2931
			$tmpvalue = trim($this->GetEcn());
2932
			if (!empty($tmpvalue)) {
2933
				if ($comma) {
2934
					$pfq_rule .= " ,";
2935
				}
2936
				$comma = 1;
2937
				$pfq_rule .= " ecn ";
2938
			}
2939
			$tmpvalue = trim($this->GetDefault());
2940
			if (!empty($tmpvalue)) {
2941
				if ($comma) {
2942
					$pfq_rule .= " ,";
2943
				}
2944
				$comma = 1;
2945
				$pfq_rule .= " default ";
2946
				$default = true;
2947
			}
2948
			$tmpvalue = trim($this->GetBuckets());
2949
			if (!empty($tmpvalue)) {
2950
				if ($comma) {
2951
					$pfq_rule .= ", ";
2952
				}
2953
				$pfq_rule .= " buckets " . $this->GetBuckets() . " ";
2954
			}
2955
			$tmpvalue = trim($this->GetHogs());
2956
			if (!empty($tmpvalue)) {
2957
				if ($comma) {
2958
					$pfq_rule .= ", ";
2959
				}
2960
				$pfq_rule .= " hogs " . $this->GetHogs() . " ";
2961
			}
2962
			$pfq_rule .= " ) ";
2963
		}
2964

    
2965
		$pfq_rule .= " \n";
2966
		return $pfq_rule;
2967
	}
2968

    
2969
	function build_form() {
2970
		$form = parent::build_form();
2971

    
2972
		$section = new Form_Section('');
2973

    
2974
		$group = new Form_Group('Bandwidth');
2975

    
2976
		$group->add(new Form_Input(
2977
			'bandwidth',
2978
			null,
2979
			'number',
2980
			$this->GetBandwidth()
2981
		));
2982

    
2983
		$group->add(new Form_Select(
2984
			'bandwidthtype',
2985
			null,
2986
			$this->GetBwscale(),
2987
			array('Kb' => 'Kb',
2988
				  'Mb' => 'Mb',
2989
				  'Gb' => 'Gb',
2990
				  'b' => 'b')
2991
		));
2992

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

    
2995
		$section->add($group);
2996

    
2997

    
2998
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
2999
		$form .= "<td class=\"vtable\"><table><tr><td>";
3000
		$form .= "<input id=\"buckets\" name=\"buckets\" value=\"";
3001
		$tmpvalue = trim($this->GetBuckets());
3002
		if (!empty($tmpvalue)) {
3003
			$form .=  $this->GetBuckets();
3004
		}
3005
		$form .= "\" /> " . gettext("Number of buckets available.") . "<br /></td></tr>";
3006
		$form .= "<tr><td class=\"vtable\"><input id=\"hogs\" name=\"hogs\" value=\"";
3007
		$tmpvalue = trim($this->GetHogs());
3008
		if (!empty($tmpvalue)) {
3009
			$form .=  $this->GetHogs();
3010
		}
3011
		$form .= "\" /> " . gettext("Bandwidth limit for hosts to not saturate link.") . "<br /></td></tr>";
3012
		$form .= "</table></td></tr>";
3013
		return $form;
3014
	}
3015

    
3016
	function update_altq_queue_data(&$data) {
3017
		$this->ReadConfig($data);
3018
	}
3019

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

    
3076

    
3077
/*
3078
 * dummynet(4) wrappers.
3079
 */
3080

    
3081

    
3082
/*
3083
 * List of respective objects!
3084
 */
3085
$dummynet_pipe_list = array();
3086

    
3087
class dummynet_class {
3088
	var $qname;
3089
	var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
3090
	var $qlimit;
3091
	var $description;
3092
	var $qenabled;
3093
	var $link;
3094
	var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
3095
	var $plr;
3096

    
3097
	var $buckets;
3098
	/* mask parameters */
3099
	var $mask;
3100
	var $noerror;
3101

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

    
3179
	function build_javascript() {
3180
		$javascript .= "<script type=\"text/javascript\">\n";
3181
		$javascript .= "//<![CDATA[\n";
3182
		$javascript .= "function enable_maskbits(enable_over) {\n";
3183
		$javascript .= "var e = document.getElementById(\"mask\");\n";
3184
		$javascript .= "if ((e.options[e.selectedIndex].text == \"none\") || enable_over) {\n";
3185
		$javascript .= "document.iform.maskbits.disabled = 1;\n";
3186
		$javascript .= "document.iform.maskbits.value = \"\";\n";
3187
		$javascript .= "document.iform.maskbitsv6.disabled = 1;\n";
3188
		$javascript .= "document.iform.maskbitsv6.value = \"\";\n";
3189
		$javascript .= "} else {\n";
3190
		$javascript .= "document.iform.maskbits.disabled = 0;\n";
3191
		$javascript .= "document.iform.maskbitsv6.disabled = 0;\n";
3192
		$javascript .= "}}\n";
3193
		$javascript .= "//]]>\n";
3194
		$javascript .= "</script>\n";
3195
		return $javascript;
3196
	}
3197

    
3198
	function validate_input($data, &$input_errors) {
3199
		$reqdfields[] = "bandwidth";
3200
		$reqdfieldsn[] = gettext("Bandwidth");
3201
		/*$reqdfields[] = "burst";
3202
		$reqdfieldsn[] = gettext("Burst"); */
3203
		$reqdfields[] = "bandwidthtype";
3204
		$reqdfieldsn[] = gettext("Bandwidthtype");
3205
		$reqdfields[] = "newname";
3206
		$reqdfieldsn[] = gettext("Name");
3207

    
3208
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3209

    
3210
		if ($data['plr'] && (!is_numeric($data['plr']) ||
3211
			($data['plr'] < 0) || ($data['plr'] > 1))) {
3212
				$input_errors[] = gettext("Plr must be a value between 0 and 1.");
3213
		}
3214
		if ($data['buckets'] && (!is_numeric($data['buckets']) ||
3215
			($data['buckets'] < 16) || ($data['buckets'] > 65535))) {
3216
				$input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
3217
		}
3218
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) {
3219
			$input_errors[] = gettext("Queue limit must be an integer");
3220
		}
3221
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname'])) {
3222
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3223
		}
3224
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name'])) {
3225
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3226
		}
3227
		if (isset($data['maskbits']) && ($data['maskbits'] <> "")) {
3228
			if ((!is_numeric($data['maskbits'])) || ($data['maskbits'] <= 0) || ($data['maskbits'] > 32)) {
3229
				$input_errors[] = gettext("IPV4 bit mask must be blank or numeric value between 1 and 32.");
3230
			}
3231
		}
3232
		if (isset($data['maskbitsv6']) && ($data['maskbitsv6'] <> "")) {
3233
			if ((!is_numeric($data['maskbitsv6'])) || ($data['maskbitsv6'] <= 0) || ($data['maskbitsv6'] > 128)) {
3234
				$input_errors[] = gettext("IPV6 bit mask must be blank or numeric value between 1 and 128.");
3235
			}
3236
		}
3237
	}
3238

    
3239
	function build_mask_rules(&$pfq_rule) {
3240
		$mask = $this->GetMask();
3241
		if (!empty($mask['type'])) {
3242
			if ($mask['type'] <> 'none') {
3243
				$pfq_rule .= " mask";
3244
			}
3245
			switch ($mask['type']) {
3246
				case 'srcaddress':
3247
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3248
						$pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
3249
					} else {
3250
						$pfq_rule .= " src-ip6 /128";
3251
					}
3252
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3253
						$pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3254
					} else {
3255
						$pfq_rule .= " src-ip 0xffffffff";
3256
					}
3257
					break;
3258
				case 'dstaddress':
3259
					if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> "")) {
3260
						$pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
3261
					} else {
3262
						$pfq_rule .= " dst-ip6 /128";
3263
					}
3264
					if (!empty($mask['bits']) && ($mask['bits'] <> "")) {
3265
						$pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
3266
					} else {
3267
						$pfq_rule .= " dst-ip 0xffffffff";
3268
					}
3269
					break;
3270
				default:
3271
					break;
3272
			}
3273
		}
3274
	}
3275

    
3276
}
3277

    
3278
class dnpipe_class extends dummynet_class {
3279
	var $delay;
3280
	var $qbandwidth = array();
3281
	var $qbandwidthtype;
3282

    
3283
		/* This is here to help on form building and building rules/lists */
3284
	var $subqueues = array();
3285

    
3286
	function CanHaveChildren() {
3287
		return true;
3288
	}
3289
	function SetDelay($delay) {
3290
		$this->delay = $delay;
3291
	}
3292
	function GetDelay() {
3293
		return $this->delay;
3294
	}
3295
	function delete_queue() {
3296
		cleanup_dnqueue_from_rules($this->GetQname());
3297
		foreach ($this->subqueues as $q) {
3298
			$q->delete_queue();
3299
		}
3300
		unset_dn_object_by_reference($this->GetLink());
3301
		@pfSense_pipe_action("pipe delete " . $this->GetNumber());
3302
	}
3303
	function GetBandwidth() {
3304
		return $this->qbandwidth;
3305
	}
3306
	function SetBandwidth($bandwidth) {
3307
		$this->qbandwidth = $bandwidth;
3308
	}
3309
	function GetBurst() {
3310
		return $this->qburst;
3311
	}
3312
	function SetBurst($burst) {
3313
		$this->qburst = $burst;
3314
	}
3315

    
3316
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
3317

    
3318
		if (!is_array($this->subqueues)) {
3319
			$this->subqueues = array();
3320
		}
3321

    
3322
		$q =& new dnqueue_class();
3323
		$q->SetLink($path);
3324
		$q->SetEnabled("on");
3325
		$q->SetPipe($this->GetQname());
3326
		$q->SetParent($this);
3327
		$q->ReadConfig($queue);
3328
		$q->validate_input($queue, $input_errors);
3329
		if (count($input_errors)) {
3330
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
3331
			return $q;
3332
		}
3333
		$number = dnqueue_find_nextnumber();
3334
		$q->SetNumber($number);
3335
		$this->subqueues[$q->GetQname()] = &$q;
3336

    
3337
		return $q;
3338
	}
3339

    
3340
	function &get_queue_list(&$q = null) {
3341
		$qlist = array();
3342

    
3343
		$qlist[$this->GetQname()] = $this->GetNumber();
3344
		if (is_array($this->subqueues)) {
3345
			foreach ($this->subqueues as $queue) {
3346
				$queue->get_queue_list($qlist);
3347
			}
3348
		}
3349
		return $qlist;
3350
	}
3351

    
3352
	/*
3353
	 * Should search even its children
3354
	 */
3355
	function &find_queue($pipe, $qname) {
3356
		if ($qname == $this->GetQname()) {
3357
			return $this;
3358
		}
3359
		foreach ($this->subqueues as $q) {
3360
			$result =& $q->find_queue("", $qname);
3361
			if ($result) {
3362
				return $result;
3363
			}
3364
		}
3365
	}
3366

    
3367
	function &find_parentqueue($pipe, $qname) {
3368
		return NULL;
3369
	}
3370

    
3371
	function validate_input($data, &$input_errors) {
3372
		parent::validate_input($data, $input_errors);
3373

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

    
3410
	function ReadConfig(&$q) {
3411
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3412
			$this->SetQname($q['newname']);
3413
		} else if (!empty($q['newname'])) {
3414
			$this->SetQname($q['newname']);
3415
		} else {
3416
			$this->SetQname($q['name']);
3417
		}
3418
		$this->SetNumber($q['number']);
3419

    
3420
		if (!empty($_POST)) {
3421
			$bandwidth = array();
3422
			/* XXX: Really no better way? */
3423
			for ($i = 0; $i < 2900; $i++) {
3424
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") {
3425
					$bw = array();
3426
					$bw['bw'] = $q["bandwidth{$i}"];
3427
					$bw['burst'] = $q["burst{$i}"];
3428
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"]) {
3429
						$bw['bwscale'] = $q["bwtype{$i}"];
3430
					}
3431
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"]) {
3432
						$bw['bwsched'] = $q["bwsched{$i}"];
3433
					}
3434
					$bandwidth[] = $bw;
3435
				}
3436
			}
3437
			$this->SetBandwidth($bandwidth);
3438
		}
3439

    
3440
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
3441
			$this->SetBandwidth($q['bandwidth']['item']);
3442
			$this->SetBurst($q['burst']['item']);
3443
		}
3444

    
3445
		if (isset($q['qlimit']) && $q['qlimit'] <> "") {
3446
			$this->SetQlimit($q['qlimit']);
3447
		} else {
3448
			$this->SetQlimit("");
3449
		}
3450
		if (isset($q['mask']) && $q['mask'] <> "") {
3451
			$masktype = $q['mask'];
3452
		} else {
3453
			$masktype = "";
3454
		}
3455
		if (isset($q['maskbits']) && $q['maskbits'] <> "") {
3456
			$maskbits = $q['maskbits'];
3457
		} else {
3458
			$maskbits = "";
3459
		}
3460
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "") {
3461
			$maskbitsv6 = $q['maskbitsv6'];
3462
		} else {
3463
			$maskbitsv6 = "";
3464
		}
3465
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3466
		if (isset($q['buckets']) && $q['buckets'] <> "") {
3467
			$this->SetBuckets($q['buckets']);
3468
		} else {
3469
			$this->SetBuckets("");
3470
		}
3471
		if (isset($q['plr']) && $q['plr'] <> "") {
3472
			$this->SetPlr($q['plr']);
3473
		} else {
3474
			$this->SetPlr("");
3475
		}
3476
		if (isset($q['delay']) && $q['delay'] <> "") {
3477
			$this->SetDelay($q['delay']);
3478
		} else {
3479
			$this->SetDelay(0);
3480
		}
3481
		if (isset($q['description']) && $q['description'] <> "") {
3482
			$this->SetDescription($q['description']);
3483
		} else {
3484
			$this->SetDescription("");
3485
		}
3486
		$this->SetEnabled($q['enabled']);
3487

    
3488
	}
3489

    
3490
	function build_tree() {
3491
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&amp;queue=".$this->GetQname() ."&amp;action=show\">";
3492
		$tree .= $this->GetQname() . "</a>";
3493
		if (is_array($this->subqueues)) {
3494
			$tree .= "<ul>";
3495
			foreach ($this->subqueues as $q)  {
3496
				$tree .= $q->build_tree();
3497
			}
3498
			$tree .= "</ul>";
3499
		}
3500
		$tree .= "</li>";
3501

    
3502
		return $tree;
3503
	}
3504

    
3505
	function build_rules() {
3506
		global $config, $time_based_rules;
3507

    
3508
		if ($this->GetEnabled() == "") {
3509
			return;
3510
		}
3511

    
3512
		$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
3513
		$found = false;
3514
		$bandwidth = $this->GetBandwidth();
3515
		if (is_array($bandwidth)) {
3516
			foreach ($bandwidth as $bw) {
3517
				if ($bw['bwsched'] != "none") {
3518
					$time_based_rules = true;
3519
					if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3520
						foreach ($config['schedules']['schedule'] as $schedule) {
3521
							if ($bw['bwsched'] == $schedule['name']) {
3522
								if (filter_get_time_based_rule_status($schedule)) {
3523
									$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3524
									if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3525
										$pfq_rule .= " burst ".trim($bw['burst']);
3526
									}
3527
									$found = true;
3528
									break;
3529
								}
3530
							}
3531
						}
3532
					} else {
3533
						$pfq_rule .= " bw 0";
3534
						$found = true;
3535
						break;
3536
					}
3537
				} else {
3538
					$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3539
					if (is_numeric($bw['burst']) && ($bw['burst'] > 0)) {
3540
						$pfq_rule .= " burst ".trim($bw['burst']);
3541
					}
3542
					$found = true;
3543
					break;
3544
				}
3545
			}
3546
			if ($found == false) {
3547
				$pfq_rule .= " bw 0";
3548
			}
3549
		} else {
3550
			$pfq_rule .= " bw 0";
3551
		}
3552

    
3553
		if ($this->GetQlimit()) {
3554
			$pfq_rule .= " queue " . $this->GetQlimit();
3555
		}
3556
		if ($this->GetPlr()) {
3557
			$pfq_rule .= " plr " . $this->GetPlr();
3558
		}
3559
		if ($this->GetBuckets()) {
3560
			$pfq_rule .= " buckets " . $this->GetBuckets();
3561
		}
3562
		if ($this->GetDelay()) {
3563
			$pfq_rule .= " delay " . $this->GetDelay();
3564
		}
3565
		$this->build_mask_rules($pfq_rule);
3566

    
3567
		$pfq_rule .= "\n";
3568

    
3569
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3570
			foreach ($this->subqueues as $q) {
3571
				$pfq_rule .= $q->build_rules();
3572
			}
3573
		}
3574
		$pfq_rule .= " \n";
3575

    
3576
		return $pfq_rule;
3577
	}
3578

    
3579
	function update_dn_data(&$data) {
3580
		$this->ReadConfig($data);
3581
	}
3582

    
3583
	function build_javascript() {
3584
		global $g, $config;
3585

    
3586
		$javasr = parent::build_javascript();
3587

    
3588
		//build list of schedules
3589
		$schedules = "<option value='none'>none</option>";
3590
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3591
			foreach ($config['schedules']['schedule'] as $schedule) {
3592
				if ($schedule['name'] <> "") {
3593
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3594
				}
3595
			}
3596
		}
3597
		$bwopt = "";
3598
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw) {
3599
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3600
		}
3601

    
3602
		$javasr .= <<<EOD
3603
<script type='text/javascript'>
3604
//<![CDATA[
3605
var addBwRowTo = (function() {
3606
	return (function (tableId) {
3607
	var d, tbody, tr, td;
3608
	d = document;
3609
	tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0);
3610
	tr = d.createElement("tr");
3611
	td = d.createElement("td");
3612
	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 + "' />";
3613
	tr.appendChild(td);
3614
	//td = d.createElement("td");
3615
	//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 + "' />";
3616
	//tr.appendChild(td);
3617
	td = d.createElement("td");
3618
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "' /><select class='formselect' name='bwtype" + totalrows + "'>{$bwopt}</select>";
3619
	tr.appendChild(td);
3620
	td = d.createElement("td");
3621
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "' /><select class='formselect' name='bwsched" + totalrows + "'>{$schedules}</select>";
3622
	tr.appendChild(td);
3623
	td = d.createElement("td");
3624
	td.rowSpan = "1";
3625
	td.innerHTML = '<a onclick="removeBwRow(this); return false;" href="#"><img border="0" src="/themes/{$g['theme']}/images/icons/icon_x.gif" alt="remove" /></a>';
3626
	tr.appendChild(td);
3627
	tbody.appendChild(tr);
3628
	totalrows++;
3629
	});
3630
})();
3631

    
3632
function removeBwRow(el) {
3633
	var cel;
3634
	while (el && el.nodeName.toLowerCase() != "tr") {
3635
		el = el.parentNode;
3636
		if (el && el.parentNode) {
3637
			cel = el.getElementsByTagName("td").item(0);
3638
			el.parentNode.removeChild(el);
3639
		}
3640
	}
3641
}
3642
//]]>
3643
</script>
3644

    
3645
EOD;
3646

    
3647
		return $javasr;
3648
	}
3649

    
3650
	function build_formX() {
3651
		global $g, $config;
3652

    
3653
		//build list of schedules
3654
		$schedules = array();
3655
		$schedules[] = "none";//leave none to leave rule enabled all the time
3656
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3657
			foreach ($config['schedules']['schedule'] as $schedule) {
3658
				if ($schedule['name'] <> "") {
3659
					$schedules[] = $schedule['name'];
3660
				}
3661
			}
3662
		}
3663

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

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

    
3836
		return $form;
3837

    
3838
		}
3839

    
3840
	function wconfig() {
3841
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3842
		if (!is_array($cflink)) {
3843
			$cflink = array();
3844
		}
3845
		$cflink['name'] = $this->GetQname();
3846
		$cflink['number'] = $this->GetNumber();
3847
		$cflink['qlimit'] = $this->GetQlimit();
3848
		$cflink['plr'] = $this->GetPlr();
3849
		$cflink['description'] = $this->GetDescription();
3850

    
3851
		$bandwidth = $this->GetBandwidth();
3852
		if (is_array($bandwidth)) {
3853
			$cflink['bandwidth'] = array();
3854
			$cflink['bandwidth']['item'] = array();
3855
			foreach ($bandwidth as $bwidx => $bw) {
3856
				$cflink['bandwidth']['item'][] = $bw;
3857
			}
3858
		}
3859

    
3860
		$cflink['enabled'] = $this->GetEnabled();
3861
		$cflink['buckets'] = $this->GetBuckets();
3862
		$mask = $this->GetMask();
3863
		$cflink['mask'] = $mask['type'];
3864
		$cflink['maskbits'] = $mask['bits'];
3865
		$cflink['maskbitsv6'] = $mask['bitsv6'];
3866
		$cflink['delay'] = $this->GetDelay();
3867
	}
3868

    
3869
}
3870

    
3871
class dnqueue_class extends dummynet_class {
3872
	var $pipeparent;
3873
	var $weight;
3874

    
3875
	function GetWeight() {
3876
		return $this->weight;
3877
	}
3878
	function SetWeight($weight) {
3879
		$this->weight = $weight;
3880
	}
3881
	function GetPipe() {
3882
		return $this->pipeparent;
3883
	}
3884
	function SetPipe($pipe) {
3885
		$this->pipeparent = $pipe;
3886
	}
3887

    
3888
	/* Just a stub in case we ever try to call this from the frontend. */
3889
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
3890
		return;
3891
	}
3892

    
3893
	function delete_queue() {
3894
		cleanup_dnqueue_from_rules($this->GetQname());
3895
		unset_dn_object_by_reference($this->GetLink());
3896
		@pfSense_pipe_action("queue delete " . $this->GetNumber());
3897
	}
3898

    
3899
	function validate_input($data, &$input_errors) {
3900
		parent::validate_input($data, $input_errors);
3901

    
3902
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3903
			($data['weight'] < 1 && $data['weight'] > 100))) {
3904
			$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
3905
		}
3906
	}
3907

    
3908
	/*
3909
	 * Should search even its children
3910
	 */
3911
	function &find_queue($pipe, $qname) {
3912
		if ($qname == $this->GetQname()) {
3913
			return $this;
3914
		} else {
3915
			return NULL;
3916
		}
3917
	}
3918

    
3919
	function &find_parentqueue($pipe, $qname) {
3920
		return $this->qparent;
3921
	}
3922

    
3923
	function &get_queue_list(&$qlist) {
3924
		if ($this->GetEnabled() == "") {
3925
			return;
3926
		}
3927
		$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3928
	}
3929

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

    
3983
	function build_tree() {
3984
		$parent =& $this->GetParent();
3985
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">";
3986
		$tree .= $this->GetQname() . "</a>";
3987
		$tree .= "</li>";
3988

    
3989
		return $tree;
3990
	}
3991

    
3992
	function build_rules() {
3993
		if ($this->GetEnabled() == "") {
3994
			return;
3995
		}
3996

    
3997
		$parent =& $this->GetParent();
3998
		$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
3999
		if ($this->GetQlimit()) {
4000
			$pfq_rule .= " queue " . $this->GetQlimit();
4001
		}
4002
		if ($this->GetWeight()) {
4003
			$pfq_rule .= " weight " . $this->GetWeight();
4004
		}
4005
		if ($this->GetBuckets()) {
4006
			$pfq_rule .= " buckets " . $this->GetBuckets();
4007
		}
4008
		$this->build_mask_rules($pfq_rule);
4009
		$pfq_rule .= "\n";
4010

    
4011
		return $pfq_rule;
4012
	}
4013

    
4014
	function build_javascript() {
4015
		return parent::build_javascript();
4016
	}
4017

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

    
4142
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
4143
		$form .= " value=\"" . $this->GetPipe() . "\" />";
4144

    
4145
		return $form;
4146

    
4147
	}
4148

    
4149
	function update_dn_data(&$data) {
4150
		$this->ReadConfig($data);
4151
	}
4152

    
4153
	function wconfig() {
4154
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
4155
		if (!is_array($cflink)) {
4156
			$cflink = array();
4157
		}
4158
		$cflink['name'] = $this->GetQname();
4159
		$cflink['number'] = $this->GetNumber();
4160
		$cflink['qlimit'] = $this->GetQlimit();
4161
		$cflink['description'] = $this->GetDescription();
4162
		$cflink['weight'] = $this->GetWeight();
4163
		$cflink['enabled'] = $this->GetEnabled();
4164
		$cflink['buckets'] = $this->GetBuckets();
4165
		$mask = $this->GetMask();
4166
		$cflink['mask'] = $mask['type'];
4167
		$cflink['maskbits'] = $mask['bits'];
4168
		$cflink['maskbitsv6'] = $mask['bitsv6'];
4169
	}
4170
}
4171

    
4172
// List of layer7 objects
4173
$layer7_rules_list = array();
4174

    
4175
class layer7 {
4176

    
4177
	var $rname; //alias
4178
	var $rdescription; //alias description
4179
	var $rport; //divert port
4180
	var $renabled; //rule enabled
4181
	var $rsets = array(); //array of l7 associations
4182

    
4183
	// Auxiliary functions
4184

    
4185
	function GetRName() {
4186
		return $this->rname;
4187
	}
4188
	function SetRName($rname) {
4189
		$this->rname = $rname;
4190
	}
4191
	function GetRDescription() {
4192
		return $this->rdescription;
4193
	}
4194
	function SetRDescription($rdescription) {
4195
		$this->rdescription = $rdescription;
4196
	}
4197
	function GetRPort() {
4198
		return $this->rport;
4199
	}
4200
	function SetRPort($rport) {
4201
		$this->rport = $rport;
4202
	}
4203
	function GetREnabled() {
4204
		return $this->renabled;
4205
	}
4206
	function SetREnabled($value) {
4207
		$this->renabled = $value;
4208
	}
4209
	function GetRl7() {
4210
		return $this->rsets;
4211
	}
4212
	function SetRl7($rsets) {
4213
		$this->rsets = $rsets;
4214
	}
4215

    
4216
	//Add a tuple (rule,structure,element) to the $rsets
4217

    
4218
	function add_rule($l7set) {
4219
		$this->rsets[] = $l7set;
4220
	}
4221

    
4222
	// Build the layer7 rules
4223
	function build_l7_rules() {
4224
		if ($this->GetREnabled() == "") {
4225
			return;
4226
		}
4227
		//$l7rules = "#" . $this->rdescription . "\n";
4228
		foreach ($this->rsets as $rl7) {
4229
			$l7rules .= $rl7->build_rules();
4230
		}
4231
		return $l7rules;
4232
	}
4233

    
4234
	// Read the config from array
4235
	function ReadConfig(&$qname, &$q) {
4236
		$this->SetRName($qname);
4237
		$this->SetREnabled($q['enabled']);
4238
		$this->SetRPort($q['divert_port']);
4239
		if (isset($q['description']) && $q['description'] <> "") {
4240
			$this->SetRDescription($q['description']);
4241
		}
4242
		$rsets = $q['l7rules'];
4243
		//Put individual rules in the array
4244
		if (is_array($rsets)) {
4245
			$this->rsets = array(); // XXX: ugly hack
4246
			foreach ($rsets as $l7r) {
4247
				$l7obj = new l7rule();
4248
				$l7obj->SetRProtocol($l7r['protocol']);
4249
				$l7obj->SetRStructure($l7r['structure']);
4250
				$l7obj->SetRBehaviour($l7r['behaviour']);
4251
				$this->add_rule($l7obj);
4252
			}
4253
		}
4254
	}
4255

    
4256
	//Generate a random port for the divert socket
4257
	function gen_divert_port() {
4258
		$dports = get_divert_ports(); //array of used ports
4259
		$divert_port = 1; // Initialize
4260
		while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) {
4261
			$divert_port = rand(40000, 60000);
4262
		}
4263
		return $divert_port;
4264
	}
4265

    
4266
	//Helps building the left tree
4267
	function build_tree() {
4268
		$tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&amp;action=show\">";
4269
		$tree .= $this->GetRName() . "</a>";
4270
		$tree .= "</li>";
4271

    
4272
		return $tree;
4273
	}
4274

    
4275
	function build_formX() {
4276
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
4277
		$form .= gettext("Enable/Disable");
4278
		$form .= "</td><td class=\"vncellreq\">";
4279
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\" ";
4280
		if ($this->GetREnabled() == "on") {
4281
			$form .=  "checked=\"checked\"";
4282
		}
4283
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable layer7 Container") . "</span>";
4284
		$form .= "</td></tr>";
4285
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
4286
		$form .= "<td class=\"vncellreq\">";
4287
		$form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
4288
		$form .= $this->GetRName()."\" />";
4289
		$form .= "</td></tr>";
4290
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
4291
		$form .= "<td class=\"vncellreq\">";
4292
		$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
4293
		$form .= $this->GetRDescription();
4294
		$form .= "\" />";
4295
		$form .= "<br /> <span class=\"vexpl\">";
4296
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
4297
		$form .= "</td></tr>";
4298

    
4299
		return $form;
4300
	}
4301

    
4302
	//Write the setting to the $config array
4303
	function wconfig() {
4304
		global $config;
4305

    
4306
		if (!is_array($config['l7shaper']['container'])) {
4307
			$config['l7shaper']['container'] = array();
4308
		}
4309
		//
4310
		$cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
4311
		// Test if this rule exists already
4312
		if (!$cflink) {
4313
			$cflink =& $config['l7shaper']['container'][];
4314
		}
4315
		$cflink['name'] = $this->GetRName();
4316
		$cflink['enabled'] = $this->GetREnabled();
4317
		$cflink['description'] = $this->GetRDescription();
4318
		$cflink['divert_port'] = $this->GetRPort();
4319

    
4320
		// Destroy previously existent rules
4321
		if (is_array($cflink['rules'])) {
4322
			unset($cflink['l7rules']);
4323
		}
4324

    
4325
		$cflink['l7rules'] = array();
4326

    
4327
		$i = 0;
4328
		foreach ($this->rsets as $rulel7) {
4329
			$cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
4330
			$cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
4331
			$cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
4332
			$i++;
4333
		}
4334
	}
4335

    
4336
	//This function is necessary to help producing the overload options for keep state
4337
	function get_unique_structures() {
4338

    
4339
		$unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
4340
		foreach ($this->rsets as $l7rule) {
4341
			if ($l7rule->GetRStructure() == "action") {
4342
				$unique_structures['action'] = true;
4343
			} else if ($l7rule->GetRStructure() == "limiter") {
4344
				$unique_structures['dummynet'] = true;
4345
			} else {
4346
				$unique_structures['altq'] = true;
4347
			}
4348
		}
4349
		//Delete non used structures so we don't have to check this in filter.inc
4350
		foreach ($unique_structures as $key => $value) {
4351
			if (!$value) {
4352
				unset($unique_structures[$key]);
4353
			}
4354
		}
4355
		return $unique_structures;
4356
	}
4357

    
4358
	function validate_input($data, &$input_errors) {
4359
		$reqdfields[] = "container";
4360
		$reqdfieldsn[] = gettext("Name");
4361

    
4362
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
4363

    
4364
		if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container'])) {
4365
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
4366
		}
4367
	}
4368

    
4369
	function delete_l7c() {
4370
		mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
4371
		unset_l7_object_by_reference($this->GetRName());
4372
		cleanup_l7_from_rules($this->GetRName());
4373
	}
4374
}
4375

    
4376
class l7rule {
4377

    
4378
	var $rprotocol; //protocol
4379
	var $rstructure; //action, limiter, queue
4380
	var $rbehaviour; //allow, block, queue_name, pipe_number ...
4381

    
4382
	//Auxiliary Functions
4383

    
4384
	function GetRProtocol() {
4385
		return $this->rprotocol;
4386
	}
4387
	function SetRProtocol($rprotocol) {
4388
		$this->rprotocol = $rprotocol;
4389
	}
4390
	function GetRStructure() {
4391
		return $this->rstructure;
4392
	}
4393
	function SetRStructure($rstructure) {
4394
		$this->rstructure = $rstructure;
4395
	}
4396
	function GetRBehaviour() {
4397
		return $this->rbehaviour;
4398
	}
4399
	function SetRBehaviour($rbehaviour) {
4400
		$this->rbehaviour = $rbehaviour;
4401
	}
4402

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

    
4435
/*
4436
 * This function allows to return an array with all the used divert socket ports
4437
 */
4438
function get_divert_ports() {
4439
	global $layer7_rules_list;
4440
	$dports = array();
4441

    
4442
	foreach ($layer7_rules_list as $l7r) {
4443
		$dports[] = $l7r->GetRPort();
4444
	}
4445

    
4446
	return $dports;
4447
}
4448

    
4449
function &get_l7c_reference_to_me_in_config(&$name) {
4450
	global $config;
4451

    
4452
	$ptr = NULL;
4453

    
4454
	if (is_array($config['l7shaper']['container'])) {
4455
		foreach ($config['l7shaper']['container'] as $key => $value) {
4456
			if ($value['name'] == $name) {
4457
				$ptr =& $config['l7shaper']['container'][$key];
4458
			}
4459
		}
4460
	}
4461
	return $ptr;
4462
	// $ptr can be null. has to be checked later
4463
}
4464

    
4465
function unset_l7_object_by_reference(&$name) {
4466
	global $config;
4467

    
4468
	if (is_array($config['l7shaper']['container'])) {
4469
		foreach ($config['l7shaper']['container'] as $key => $value) {
4470
			if ($value['name'] == $name) {
4471
				unset($config['l7shaper']['container'][$key]['l7rules']);
4472
				unset($config['l7shaper']['container'][$key]);
4473
				break;
4474
			}
4475
		}
4476
	}
4477
}
4478

    
4479
function read_layer7_config() {
4480
	global $layer7_rules_list, $config;
4481

    
4482
	if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container'])) {
4483
		$layer7_rules_list = array();
4484
		return;
4485
	}
4486

    
4487
	$l7cs = &$config['l7shaper']['container'];
4488

    
4489
	$layer7_rules_list = array();
4490

    
4491
	foreach ($l7cs as $conf) {
4492
		if (empty($conf['name'])) {
4493
			continue; /* XXX: grrrrrr at php */
4494
		}
4495
		$root =& new layer7();
4496
		$root->ReadConfig($conf['name'],$conf);
4497
		$layer7_rules_list[$root->GetRName()] = &$root;
4498
	}
4499
}
4500

    
4501
function update_layer7_custom_patterns() {
4502
	global $config;
4503

    
4504
	if (!is_array($config['l7shaper']['custom_pat'])) {
4505
		return;
4506
	}
4507

    
4508
	foreach ($config['l7shaper']['custom_pat'] as $filename => $filecontent) {
4509
		if (!file_exists("/usr/local/share/protocols/" . $filename)) {
4510
			@file_put_contents("/usr/local/share/protocols/" . $filename, base64_decode($filecontent));
4511
		}
4512
	}
4513
}
4514

    
4515
function generate_layer7_files() {
4516
	global $layer7_rules_list, $g;
4517

    
4518
	read_layer7_config();
4519

    
4520
	if (!empty($layer7_rules_list)) {
4521
		if (!is_module_loaded("ipdivert.ko")) {
4522
			mwexec("/sbin/kldload ipdivert.ko");
4523
		}
4524

    
4525
		array_map('unlink', glob("{$g['tmp_path']}/*.l7"));
4526
	}
4527

    
4528
	update_layer7_custom_patterns();
4529

    
4530
	foreach ($layer7_rules_list as $l7rules) {
4531
		if ($l7rules->GetREnabled()) {
4532
			$filename = $l7rules->GetRName() . ".l7";
4533
			$path = "{$g['tmp_path']}/" . $filename;
4534

    
4535
			$rules = $l7rules->build_l7_rules();
4536

    
4537
			$fp = fopen($path,'w');
4538
			fwrite($fp,$rules);
4539
			fclose($fp);
4540
		}
4541
	}
4542
}
4543

    
4544
function layer7_start_l7daemon() {
4545
	global $layer7_rules_list, $g;
4546

    
4547
	/*
4548
	 * XXX: ermal - Needed ?!
4549
	 * read_layer7_config();
4550
	 */
4551

    
4552
	foreach ($layer7_rules_list as $l7rules) {
4553
		if ($l7rules->GetREnabled()) {
4554
			$filename = $l7rules->GetRName() . ".l7";
4555
			$path = "{$g['tmp_path']}/" . $filename;
4556

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

    
4572
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
4573
function generate_protocols_array() {
4574

    
4575
	update_layer7_custom_patterns();
4576

    
4577
	$protocols = return_dir_as_array("/usr/local/share/protocols");
4578
	$protocols_new = array();
4579
	if (is_array($protocols)) {
4580
		foreach ($protocols as $key => $proto) {
4581
			if (strstr($proto, ".pat")) {
4582
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
4583
			}
4584
		}
4585
		sort($protocols_new);
4586
	}
4587
	return $protocols_new;
4588
}
4589

    
4590
function get_l7_unique_list() {
4591
	global $layer7_rules_list;
4592

    
4593
	$l7list = array();
4594
	if (is_array($layer7_rules_list)) {
4595
		foreach ($layer7_rules_list as $l7c) {
4596
			if ($l7c->GetREnabled()) {
4597
				$l7list[] = $l7c->GetRName();
4598
			}
4599
		}
4600
	}
4601

    
4602
	return $l7list;
4603
}
4604

    
4605
// Disable a removed l7 container from the filter
4606
function cleanup_l7_from_rules(&$name) {
4607
	global $config;
4608

    
4609
	if (is_array($config['filter']['rule'])) {
4610
		foreach ($config['filter']['rule'] as $key => $rule) {
4611
			if ($rule['l7container'] == $name) {
4612
				unset($config['filter']['rule'][$key]['l7container']);
4613
			}
4614
		}
4615
	}
4616
}
4617

    
4618
function get_dummynet_name_list() {
4619

    
4620
	$dn_name_list =& get_unique_dnqueue_list();
4621
	$dn_name = array();
4622
	if (is_array($dn_name_list)) {
4623
		foreach ($dn_name_list as $key => $value) {
4624
			$dn_name[] = $key;
4625
		}
4626
	}
4627

    
4628
	return $dn_name;
4629

    
4630
}
4631

    
4632
function get_altq_name_list() {
4633
	$altq_name_list =& get_unique_queue_list();
4634
	$altq_name = array();
4635
	if (is_array($altq_name_list)) {
4636
		foreach ($altq_name_list as $key => $aqobj) {
4637
			$altq_name[] = $key;
4638
		}
4639
	}
4640

    
4641
	return $altq_name;
4642
}
4643

    
4644
/*
4645
 * XXX: TODO Make a class shaper to hide all these functions
4646
 * from the global namespace.
4647
 */
4648

    
4649
/*
4650
 * This is a layer violation but for now there is no way
4651
 * I can find to properly do this with PHP.
4652
 */
4653
function altq_get_default_queue($interface) {
4654
	global $altq_list_queues;
4655

    
4656
	$altq_tmp = $altq_list_queues[$interface];
4657
	if ($altq_tmp) {
4658
		return $altq_tmp->GetDefaultQueuePresent();
4659
	} else {
4660
		return false;
4661
	}
4662
}
4663

    
4664
function altq_check_default_queues() {
4665
	global $altq_list_queues;
4666

    
4667
	$count = 0;
4668
	if (is_array($altq_list_queues)) {
4669
		foreach ($altq_list_queues as $altq) {
4670
			if ($altq->GetDefaultQueuePresent()) {
4671
				$count++;
4672
			}
4673
		}
4674
	}
4675
	else {
4676
		$count++;
4677
	}
4678

    
4679
	return 0;
4680
}
4681

    
4682
function &get_unique_queue_list() {
4683
	global $altq_list_queues;
4684

    
4685
	$qlist = array();
4686
	if (is_array($altq_list_queues)) {
4687
		foreach ($altq_list_queues as $altq) {
4688
			if ($altq->GetEnabled() == "") {
4689
				continue;
4690
			}
4691
			$tmplist =& $altq->get_queue_list();
4692
			foreach ($tmplist as $qname => $link) {
4693
				if ($link->GetEnabled() <> "") {
4694
					$qlist[$qname] = $link;
4695
				}
4696
			}
4697
		}
4698
	}
4699
	return $qlist;
4700
}
4701

    
4702
function &get_unique_dnqueue_list() {
4703
	global $dummynet_pipe_list;
4704

    
4705
	$qlist = array();
4706
	if (is_array($dummynet_pipe_list)) {
4707
		foreach ($dummynet_pipe_list as $dn) {
4708
			if ($dn->GetEnabled() == "") {
4709
				continue;
4710
			}
4711
			$tmplist =& $dn->get_queue_list();
4712
			foreach ($tmplist as $qname => $link) {
4713
				$qlist[$qname] = $link;
4714
			}
4715
		}
4716
	}
4717
	return $qlist;
4718
}
4719

    
4720
function ref_on_altq_queue_list($parent, $qname) {
4721
	if (isset($GLOBALS['queue_list'][$qname])) {
4722
		$GLOBALS['queue_list'][$qname]++;
4723
	} else {
4724
		$GLOBALS['queue_list'][$qname] = 1;
4725
	}
4726

    
4727
	unref_on_altq_queue_list($parent);
4728
}
4729

    
4730
function unref_on_altq_queue_list($qname) {
4731
	$GLOBALS['queue_list'][$qname]--;
4732
	if ($GLOBALS['queue_list'][$qname] <= 1) {
4733
		unset($GLOBALS['queue_list'][$qname]);
4734
	}
4735
}
4736

    
4737
function read_altq_config() {
4738
	global $altq_list_queues, $config;
4739
	$path = array();
4740

    
4741
	if (!is_array($config['shaper'])) {
4742
		$config['shaper'] = array();
4743
	}
4744
	if (!is_array($config['shaper']['queue'])) {
4745
		$config['shaper']['queue'] = array();
4746
	}
4747
	$a_int = &$config['shaper']['queue'];
4748

    
4749
	$altq_list_queues = array();
4750

    
4751
	if (!is_array($config['shaper']['queue'])) {
4752
		return;
4753
	}
4754

    
4755
	foreach ($a_int as $key => $conf) {
4756
		$int = $conf['interface'];
4757
		$root =& new altq_root_queue();
4758
		$root->SetInterface($int);
4759
		$altq_list_queues[$root->GetInterface()] = &$root;
4760
		$root->ReadConfig($conf);
4761
		array_push($path, $key);
4762
		$root->SetLink($path);
4763
		if (is_array($conf['queue'])) {
4764
			foreach ($conf['queue'] as $key1 => $q) {
4765
				array_push($path, $key1);
4766
				/*
4767
				 * XXX: we completely ignore errors here but anyway we must have
4768
				 *	checked them before so no harm should be come from this.
4769
				 */
4770
				$root->add_queue($root->GetInterface(), $q, $path, $input_errors);
4771
				array_pop($path);
4772
			}
4773
		}
4774
		array_pop($path);
4775
	}
4776
}
4777

    
4778
function read_dummynet_config() {
4779
	global $dummynet_pipe_list, $config;
4780
	$path = array();
4781

    
4782
	if (!is_array($config['dnshaper'])) {
4783
		$config['dnshaper'] = array();
4784
	}
4785
	if (!is_array($config['dnshaper']['queue'])) {
4786
		$config['dnshaper']['queue'] = array();
4787
	}
4788
	$a_int = &$config['dnshaper']['queue'];
4789

    
4790
	$dummynet_pipe_list = array();
4791

    
4792
	if (!is_array($config['dnshaper']['queue']) ||
4793
		!count($config['dnshaper']['queue'])) {
4794
		return;
4795
	}
4796

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

    
4821
function get_interface_list_to_show() {
4822
	global $altq_list_queues, $config;
4823
	global $shaperIFlist;
4824

    
4825
	$tree = "";
4826
	foreach ($shaperIFlist as $shif => $shDescr) {
4827
		if ($altq_list_queues[$shif]) {
4828
			continue;
4829
		} else	{
4830
			if (!is_altq_capable(get_real_interface($shif))) {
4831
				continue;
4832
			}
4833
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4834
		}
4835
	}
4836

    
4837
	return $tree;
4838
}
4839

    
4840
function filter_generate_altq_queues() {
4841
	global $altq_list_queues;
4842

    
4843
	read_altq_config();
4844

    
4845
	$altq_rules = "";
4846
	foreach ($altq_list_queues as $altq) {
4847
		$altq_rules .= $altq->build_rules();
4848
	}
4849

    
4850
	return $altq_rules;
4851
}
4852

    
4853
function dnqueue_find_nextnumber() {
4854
	global $dummynet_pipe_list;
4855

    
4856
	$dnused = array();
4857
	if (is_array($dummynet_pipe_list)) {
4858
		foreach ($dummynet_pipe_list as $dn) {
4859
			$tmplist =& $dn->get_queue_list();
4860
			foreach ($tmplist as $qname => $link) {
4861
				if ($link[0] == "?") {
4862
					$dnused[$qname] = substr($link, 1);
4863
				}
4864
			}
4865
		}
4866
	}
4867

    
4868
	sort($dnused, SORT_NUMERIC);
4869
	$dnnumber = 0;
4870
	$found = false;
4871
	foreach ($dnused as $dnnum) {
4872
		if (($dnnum - $dnnumber) > 1) {
4873
			$dnnumber = $dnnum - 1;
4874
			$found = true;
4875
			break;
4876
		} else {
4877
			$dnnumber = $dnnum;
4878
		}
4879
	}
4880

    
4881
	if ($found == false) {
4882
		$dnnumber++;
4883
	}
4884

    
4885
	unset($dnused, $dnnum, $found);
4886
	return $dnnumber;
4887
}
4888

    
4889
function dnpipe_find_nextnumber() {
4890
	global $dummynet_pipe_list;
4891

    
4892
	$dnused = array();
4893
	foreach ($dummynet_pipe_list as $dn) {
4894
		$dnused[] = $dn->GetNumber();
4895
	}
4896

    
4897
	sort($dnused, SORT_NUMERIC);
4898
	$dnnumber = 0;
4899
	$found = false;
4900
	foreach ($dnused as $dnnum) {
4901
		if (($dnnum - $dnnumber) > 1) {
4902
			$dnnumber = $dnnum - 1;
4903
			$found = true;
4904
			break;
4905
		} else {
4906
			$dnnumber = $dnnum;
4907
		}
4908
	}
4909

    
4910
	if ($found == false) {
4911
		$dnnumber++;
4912
	}
4913

    
4914
	unset($dnused, $dnnum, $found);
4915
	return $dnnumber;
4916
}
4917

    
4918
function filter_generate_dummynet_rules() {
4919
	global $g, $dummynet_pipe_list;
4920

    
4921
	read_dummynet_config();
4922

    
4923
	$dn_rules = "";
4924
	foreach ($dummynet_pipe_list as $dn) {
4925
		$dn_rules .= $dn->build_rules();
4926
	}
4927

    
4928
	if (!empty($dn_rules)) {
4929
		if (!is_module_loaded("dummynet.ko")) {
4930
			mwexec("/sbin/kldload dummynet");
4931
			set_sysctl(array(
4932
				"net.inet.ip.dummynet.io_fast" => "1",
4933
				"net.inet.ip.dummynet.hash_size" => "256"
4934
			));
4935
		}
4936
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4937
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4938
	}
4939
}
4940

    
4941
function build_iface_without_this_queue($iface, $qname) {
4942
	global $g, $altq_list_queues;
4943
	global $shaperIFlist;
4944

    
4945
	$altq =& $altq_list_queues[$iface];
4946
	if ($altq) {
4947
		$scheduler = ": " . $altq->GetScheduler();
4948
	}
4949
	$form = "<tr><td width=\"20%\" >";
4950
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&amp;queue=" . $iface."&amp;action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4951
	$form .= "</td></tr>";
4952
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4953
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4954
	$form .= $iface . "&amp;queue=". $qname . "&amp;action=add\">";
4955
	$form .= "<img src=\"";
4956
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4957
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\" alt=\"clone\" />";
4958
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4959

    
4960
	return $form;
4961

    
4962
}
4963

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

    
4968
$dn_default_shaper_msg = $default_shaper_msg;
4969

    
4970
?>
(50-50/67)