Project

General

Profile

Download (141 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 xmplparse.inc StartElement()
41
 */
42
function &get_reference_to_me_in_config(&$mypath)
43
{
44
	global $config;
45

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

    
51
	return $ptr;
52
}
53

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

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

    
65
function &get_dn_reference_to_me_in_config(&$mypath)
66
{
67
	global $config;
68

    
69
	$ptr =& $config['dnshaper'];
70
	foreach ($mypath as $indeks) {
71
		$ptr =& $ptr['queue'][$indeks];
72
	}
73

    
74
	return $ptr;
75
}
76

    
77
function unset_dn_object_by_reference(&$mypath)
78
{
79
	global $config;
80

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

    
88
function clean_child_queues($type, $mypath)
89
{
90
	$ref = &get_reference_to_me_in_config($mypath);
91

    
92
	switch ($type) {
93
	case 'HFSC':
94
		if (isset($ref['borrow'])) unset($ref['borrow']);
95
		if (isset($ref['hogs'])) unset($ref['hogs']);
96
		if (isset($ref['buckets'])) unset($ref['buckets']);
97
		break;
98
	case 'PRIQ':
99
		if (isset($ref['borrow'])) unset($ref['borrow']);
100
		if (isset($ref['bandwidth'])) unset($ref['bandwidth']);
101
		if (isset($ref['bandwidthtype'])) unset($ref['bandwidthtype']);
102
		/* fall through */
103
	case 'FAIRQ':
104
		if (isset($ref['borrow'])) unset($ref['borrow']);
105
		/* fall through */
106
	case 'CBQ':
107
		if (isset($ref['realtime'])) unset($ref['realtime']);
108
		if (isset($ref['realtime1'])) unset($ref['realtime1']);
109
		if (isset($ref['realtime2'])) unset($ref['realtime2']);
110
		if (isset($ref['realtime3'])) unset($ref['realtime3']);
111
		if (isset($ref['upperlimit'])) unset($ref['upperlimit']);
112
		if (isset($ref['upperlimit1'])) unset($ref['upperlimit1']);
113
		if (isset($ref['upperlimit2'])) unset($ref['upperlimit2']);
114
		if (isset($ref['upperlimit3'])) unset($ref['upperlimit3']);
115
		if (isset($ref['linkshare'])) unset($ref['linkshare']);
116
		if (isset($ref['linkshare1'])) unset($ref['linkshare1']);
117
		if (isset($ref['linkshare2'])) unset($ref['linkshare2']);
118
		if (isset($ref['linkshare3'])) unset($ref['linkshare3']);
119
		if (isset($ref['hogs'])) unset($ref['hogs']);
120
		if (isset($ref['buckets'])) unset($ref['buckets']);
121
		break;
122
	}
123
}
124

    
125
function get_bandwidthtype_scale($type)
126
{
127
	switch ($type) {
128
	case "Gb":
129
		$factor = 1024 * 1024 * 1024;
130
		break;
131
	case "Mb":
132
		$factor = 1024 * 1024;
133
		break;
134
	case "Kb":
135
		$factor = 1024;
136
		break;
137
	case "b":
138
	default:
139
		$factor = 1;
140
		break;
141
	}
142
	return intval($factor);
143
}
144

    
145
function get_hfsc_bandwidth($object, $bw)
146
{
147
	$pattern= "/[0-9]+/";
148
	if (preg_match($pattern, $bw, $match))
149
		$bw_1 = $match[1];
150
	else
151
		return 0;
152
	$pattern= "/(b|Kb|Mb|Gb|%)/";
153
	if (preg_match($pattern, $bw, $match)) {
154
		switch ($match[1]) {
155
		case '%':
156
			$bw_1 = $bw_1 / 100 * get_interface_bandwidth($object);
157
			break;
158
		default:
159
			$bw_1 = $bw_1 * get_bandwidthtype_scale($match[0]);
160
			break;
161
		}
162
		return floatval($bw_1);
163
	} else
164
		return 0;
165
}
166

    
167
function get_interface_bandwidth($object)
168
{
169
	global $altq_list_queues;
170

    
171
	$int = $object->GetInterface();
172
	$altq =& $altq_list_queues[$int];
173
	if ($altq) {
174
		$bw_3 = $altq->GetBandwidth();
175
		$bw_3 = $bw_3 *  get_bandwidthtype_scale($altq->GetBwscale());
176
		return floatval($bw_3);
177
	} else
178
		return 0;
179
}
180

    
181
/*
182
 * This is duplicated here since we cannot include guiconfig.inc.
183
 * Including it makes all stuff break.
184
 */
185
function shaper_do_input_validation($postdata, $reqdfields, $reqdfieldsn, $input_errors)
186
{
187

    
188
	/* check for bad control characters */
189
	foreach ($postdata as $pn => $pd) {
190
		if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
191
			$input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $pn);
192
		}
193
	}
194

    
195
	for ($i = 0; $i < count($reqdfields); $i++) {
196
		if ($postdata[$reqdfields[$i]] == "") {
197
			$input_errors[] = sprintf(gettext("The field '%s' is required."), $reqdfieldsn[$i]);
198
		}
199
	}
200
}
201

    
202
function cleanup_queue_from_rules($queue)
203
{
204
	global $config;
205

    
206
	foreach ($config['filter']['rule'] as $rule) {
207
		if ($rule['defaultqueue'] == $queue)
208
			unset($rule['defaultqueue']);
209
		if ($rule['ackqueue'] == $queue)
210
			unset($rule['ackqueue']);
211
	}
212
}
213

    
214
function cleanup_dnqueue_from_rules($queue)
215
{
216
	global $config;
217

    
218
	foreach ($config['filter']['rule'] as $rule) {
219
		if ($rule['dnpipe'] == $queue)
220
			unset($rule['dnpipe']);
221
		if ($rule['pdnpipe'] == $queue)
222
			unset($rule['pdnpipe']);
223
	}
224
}
225

    
226
class altq_root_queue {
227
	var $interface;
228
	var $tbrconfig ;
229
	var $bandwidth;
230
	var $bandwidthtype; /* b, Kb, Mb */
231
	var $scheduler;
232
	var $qlimit;
233
	var $queues = array();
234
	var $qenabled = false;
235
	var $link;
236
	var $available_bw; /* in b/s */
237

    
238
	/* Accesor functions */
239
	function GetAvailableBandwidth() {
240
		return $this->available_bw;
241
	}
242
	function SetAvailableBandwidth($bw) {
243
		$this->available_bw = $bw;
244
	}
245
	function GetDefaultQueuePresent() {
246
		if (!empty($this->queues)) {
247
			foreach ($this->queues as $q) {
248
				if ($q->GetDefault())
249
					return true;
250
			}
251
		}
252

    
253
		return false;
254
	}
255
	function SetLink($link) {
256
		$this->link = $link;
257
	}
258
	function GetLink() {
259
		return $this->link;
260
	}
261
	function GetEnabled() {
262
		return $this->qenabled;
263
	}
264
	function SetEnabled($value) {
265
		$this->qenabled = $value;
266
	}
267
	function CanHaveChildren() {
268
		if ($this->GetScheduler() == "CODELQ")
269
			return false;
270
		else
271
			return true;
272
	}
273
	function CanBeDeleted() {
274
		return false;
275
	}
276
	function GetQname() {
277
		return $this->interface;
278
	}
279
	function SetQname($name) {
280
		$this->interface = trim($name);
281
	}
282
	function GetInterface() {
283
		return $this->interface;
284
	}
285
	function SetInterface($name) {
286
		$this->interface = trim($name);
287
	}
288
	function GetTbrConfig() {
289
		return $this->tbrconfig;
290
	}
291
	function SetTbrConfig($tbrconfig) {
292
		$this->tbrconfig = $tbrconfig;
293
	}
294
	function GetBandwidth() {
295
		return $this->bandwidth;
296
	}
297
	function SetBandwidth($bw) {
298
		$this->bandwidth = $bw;
299
	}
300
	function GetBwscale() {
301
		return $this->bandwidthtype;
302
	}
303
	function SetBwscale($bwscale) {
304
		$this->bandwidthtype = $bwscale;
305
	}
306
	function GetScheduler() {
307
		return $this->scheduler;
308
	}
309
	function SetScheduler($scheduler) {
310
		$this->scheduler = trim($scheduler);
311
	}
312
	function GetQlimit() {
313
		return $this->qlimit;
314
	}
315
	function SetQlimit($limit) {
316
		$this->qlimit = $limit;
317
	}
318

    
319
	function validate_input($data, &$input_errors) {
320

    
321
		$reqdfields[] = "bandwidth";
322
		$reqdfieldsn[] = gettext("Bandwidth");
323
		$reqdfields[] = "bandwidthtype";
324
		$reqdfieldsn[] = gettext("Bandwidthtype");
325

    
326
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
327

    
328
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
329
			$input_errors[] = gettext("Bandwidth must be an integer.");
330
		if ($data['bandwidth'] < 0)
331
			$input_errors[] = gettext("Bandwidth cannot be negative.");
332
		if ($data['qlimit'] && (!is_numeric($data['qlimit'])))
333
			$input_errors[] = gettext("Qlimit must be an integer.");
334
		if ($data['qlimit'] < 0)
335
			$input_errors[] = gettext("Qlimit must be positive.");
336
		if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig'])))
337
			$input_errors[] = gettext("Tbrsize must be an integer.");
338
		if ($data['tbrconfig'] < 0)
339
			$input_errors[] = gettext("Tbrsize must be positive.");
340
	}
341

    
342
	/* Implement this to shorten some code on the frontend page */
343
	function ReadConfig(&$conf) {
344
		if (isset($conf['tbrconfig']))
345
			$this->SetTbrConfig($conf['tbrconfig']);
346
		else
347
			$this->SetTbrConfig($conf['tbrconfig']);
348
		$this->SetBandwidth($conf['bandwidth']);
349
		if ($conf['bandwidthtype'] <> "")
350
			$this->SetBwscale($conf['bandwidthtype']);
351
		if (isset($conf['scheduler'])) {
352
			if ($this->GetScheduler() != $conf['scheduler']) {
353
				foreach ($this->queues as $q) {
354
					clean_child_queues($conf['scheduler'], $this->GetLink());
355
					$q->clean_queue($conf['scheduler']);
356
				}
357
			}
358
			$this->SetScheduler($conf['scheduler']);
359
		}
360
		if (isset($conf['qlimit']) && $conf['qlimit'] <> "")
361
			$this->SetQlimit($conf['qlimit']);
362
		else
363
			$this->SetQlimit("");
364
		if (isset($conf['name']))
365
			$this->SetQname($conf['name']);
366
		if (!empty($conf['enabled']))
367
			$this->SetEnabled($conf['enabled']);
368
		else
369
			$this->SetEnabled("");
370
	}
371

    
372
	function copy_queue($interface, &$cflink) {
373
		$cflink['interface'] = $interface;
374
		$cflink['name'] = $interface;
375
		$cflink['scheduler'] = $this->GetScheduler();
376
		$cflink['bandwidth'] = $this->GetBandwidth();
377
		$cflink['bandwidthtype'] = $this->GetBwscale();
378
		$cflink['qlimit'] = $this->GetQlimit();
379
		$cflink['tbrconfig'] = $this->GetTbrConfig();
380
		$cflink['enabled'] = $this->GetEnabled();
381
		if (is_array($this->queues)) {
382
			$cflink['queue'] = array();
383
			foreach ($this->queues as $q) {
384
				$cflink['queue'][$q->GetQname()] = array();
385
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
386
			}
387
		}
388
	}
389

    
390
	function &get_queue_list(&$q = null) {
391
		$qlist = array();
392

    
393
		//$qlist[$this->GetQname()] = & $this;
394
		if (is_array($this->queues)) {
395
			foreach ($this->queues as $queue)
396
				$queue->get_queue_list($qlist);
397
		}
398
		return $qlist;
399
	}
400

    
401
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
402

    
403
		if (!is_array($this->queues))
404
			$this->queues = array();
405

    
406
		switch ($this->GetScheduler()) {
407
		case "PRIQ":
408
			$q =& new priq_queue();
409
			break;
410
		case "HFSC":
411
			$q =& new hfsc_queue();
412
			break;
413
		case "CBQ":
414
			$q =& new cbq_queue();
415
			break;
416
		case "FAIRQ":
417
			$q =& new fairq_queue();
418
			break;
419
		default:
420
			/* XXX: but should not happen anyway */
421
			return;
422
			break;
423
		}
424
		$q->SetLink($path);
425
		$q->SetInterface($this->GetInterface());
426
		$q->SetEnabled("on");
427
		$q->SetParent($this);
428
		$q->ReadConfig($queue);
429
		$q->validate_input($queue, $input_errors);
430
		if (count($input_errors)) {
431
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
432
			return $q;
433
		}
434

    
435
		if (isset($queue['bandwidth'])) {
436
			switch ($queue['bandwidthtype']) {
437
			case "%":
438
				$myBw = $this->GetAvailableBandwidth() * $queue['bandwidth'] / 100;
439
				break;
440
			default:
441
				$myBw = $queue['bandwidth'] * get_bandwidthtype_scale($queue['bandwdithtype']);
442
				break;
443
			}
444
		}
445
		$q->SetAvailableBandwidth($myBw);
446
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
447
		$this->queues[$q->GetQname()] = &$q;
448
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
449
		if (is_array($queue['queue'])) {
450
			foreach ($queue['queue'] as $key1 => $que) {
451
				array_push($path, $key1);
452
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
453
				array_pop($path);
454
			}
455
		}
456

    
457
		return $q;
458
	}
459

    
460
	/* interface here might be optional */
461
	function &find_queue($interface, $qname) {
462
		if ($qname == $this->GetQname()) {
463
			return $this;
464
		}
465
		foreach ($this->queues as $q) {
466
			$result =& $q->find_queue("", $qname);
467
			if ($result)
468
				return $result;
469
		}
470
	}
471

    
472
	function &find_parentqueue($interface, $qname) {
473
		if ($qname == $interface) {
474
			$result =  NULL;
475
		} else if ($this->queues[$qname]) {
476
			$result = $this;
477
		} else if ($this->GetScheduler() <> "PRIQ") {
478
			foreach ($this->queues as $q) {
479
				$result = $q->find_parentqueue("", $qname);
480
				if ($result)
481
					return $result;
482
			}
483
		}
484
	}
485

    
486
	function build_tree() {
487
		global $shaperIFlist;
488

    
489
		$tree = " <li><a href=\"firewall_shaper.php?interface=".$this->GetInterface()."&amp;queue=". $this->GetInterface()."&amp;action=show";
490
		$tree .= "\">" . $shaperIFlist[$this->GetInterface()] . "</a>";
491
		if (is_array($this->queues)) {
492
			$tree .= "<ul>";
493
			foreach ($this->queues as $q)  {
494
				$tree .= $q->build_tree();
495
			}
496
		$tree .= "</ul>";
497
		}
498
		$tree .= "</li>";
499
		return $tree;
500
	}
501

    
502
	function delete_queue() {
503
		foreach ($this->queues as $q) {
504
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
505
			$q->delete_queue();
506
		}
507
		unset_object_by_reference($this->GetLink());
508
	}
509

    
510
	function delete_all() {
511
		if (count($this->queues)) {
512
			foreach ($this->queues as $q) {
513
				$q->delete_all();
514
				unset_object_by_reference($q->GetLink());
515
				unset($q);
516
			}
517
			unset($this->queues);
518
		}
519
	}
520

    
521
	/*
522
	 * First it spits:
523
	 * altq on $interface ..............
524
	 *      then it goes like
525
	 *      foreach ($queues as $qkey => $queue)
526
	 *              this->queues[$qkey]->build_rule();
527
	 */
528
	function build_rules(&$default = false) {
529
		if (count($this->queues) > 0 && $this->GetEnabled() == "on") {
530
			$default = false;
531
			$rules = " altq on  " . get_real_interface($this->GetInterface());
532
			if ($this->GetScheduler())
533
				$rules .= " ".strtolower($this->GetScheduler());
534
			if ($this->GetQlimit() > 0)
535
				$rules .= " qlimit " . $this->GetQlimit() . " ";
536
			if ($this->GetBandwidth()) {
537
				$rules .= " bandwidth ".trim($this->GetBandwidth());
538
				if ($this->GetBwscale())
539
					$rules .= $this->GetBwscale();
540
			}
541
			if ($this->GetTbrConfig())
542
				$rules .= " tbrsize ".$this->GetTbrConfig();
543
			if (count($this->queues)) {
544
				$i = count($this->queues);
545
				$rules .= " queue { ";
546
				foreach ($this->queues as $qkey => $qnone) {
547
					if ($i > 1) {
548
						$i--;
549
						$rules .= " {$qkey}, ";
550
					} else
551
						$rules .= " {$qkey} ";
552
				}
553
				$rules .= " } \n";
554
				foreach ($this->queues as $q) {
555
					$rules .= $q->build_rules($default);
556
				}
557
			}
558

    
559
			if ($default == false) {
560
				$error = "SHAPER: no default queue specified for interface ". $this->GetInterface() . ". The interface queue will be enforced as default.";
561
				file_notice("Shaper", $error, "Error occurred", "");
562
				unset($error);
563
				return "\n";
564
			}
565
			$frule .= $rules;
566
		} else if ($this->GetEnabled() == "on" && $this->GetScheduler() == "CODELQ") {
567
			$rules = " altq on  " . get_real_interface($this->GetInterface());
568
			if ($this->GetScheduler())
569
				$rules .= " ".strtolower($this->GetScheduler());
570
			if ($this->GetQlimit() > 0)
571
				$rules .= " ( qlimit " . $this->GetQlimit() . " ) ";
572
			if ($this->GetBandwidth()) {
573
				$rules .= " bandwidth ".trim($this->GetBandwidth());
574
				if ($this->GetBwscale())
575
					$rules .= $this->GetBwscale();
576
			}
577
			if ($this->GetTbrConfig())
578
				$rules .= " tbrsize ".$this->GetTbrConfig();
579

    
580
			$rules .= " queue";
581
		}
582

    
583
		$rules .= " \n";
584
		return $rules;
585
	}
586

    
587
	function build_javascript() {
588
		$javascript = "<script type=\"text/javascript\">";
589
		$javascript .= "//<![CDATA[\n";
590
		$javascript .= "function mySuspend() {";
591
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
592
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden'; ";
593
		$javascript .= "else if (document.all)";
594
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
595
		$javascript .= "}";
596

    
597
		$javascript .= "function myResume() {";
598
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
599
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';";
600
		$javascript .= "else if (document.all) ";
601
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';";
602
		$javascript .= "}";
603
		$javascript .= "//]]>";
604
		$javascript .= "</script>";
605

    
606
		return $javascript;
607
	}
608

    
609
	function build_shortform() {
610
		global $g;
611

    
612
		$altq =& $this;
613
		if ($altq)
614
			$scheduler = ": " . $altq->GetScheduler();
615
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
616
		$form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=". $this->GetInterface()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .": ".$scheduler."</a>";
617
		$form .= "</td></tr>";
618
		$form .= "<tr>";
619
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
620
		$form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale();
621
		$form .= "</td><td width=\"50%\"></td></tr>";
622
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
623
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
624
		$form .= $this->GetInterface() . "&amp;queue=";
625
		$form .= $this->GetQname() . "&amp;action=delete\">";
626
		$form .= "<img src=\"";
627
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
628
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Disable shaper on interface\" alt=\"disable\" />";
629
		$form .= "<span>Disable shaper on interface</span></a></td></tr>";
630

    
631
		return $form;
632

    
633
	}
634
	/*
635
	 * For requesting the parameters of the root queues
636
	 * to the user like the traffic wizard does.
637
	 */
638
	function build_form() {
639
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
640
		$form .= gettext("Enable/Disable");
641
		$form .= "<br /></td><td class=\"vncellreq\">";
642
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
643
		if ($this->GetEnabled() == "on")
644
			$form .=  " checked=\"checked\"";
645
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/disable discipline and its children") . "</span>";
646
		$form .= "</td></tr>";
647
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
648
		$form .= "<td class=\"vncellreq\">";
649
		$form .= "<strong>".$this->GetQname()."</strong>";
650
		$form .= "</td></tr>";
651
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Scheduler Type ");
652
		$form .= "</td>";
653
		$form .= "<td class=\"vncellreq\">";
654
		$form .= "<select id=\"scheduler\" name=\"scheduler\" class=\"formselect\">";
655
		$form .= "<option value=\"HFSC\"";
656
		if ($this->GetScheduler() == "HFSC")
657
			$form .= " selected=\"selected\"";
658
		$form .= ">HFSC</option>";
659
		$form .= "<option value=\"CBQ\"";
660
		if ($this->GetScheduler() == "CBQ")
661
			$form .= " selected=\"selected\"";
662
		$form .= ">CBQ</option>";
663
		$form .= "<option value=\"FAIRQ\"";
664
		if ($this->GetScheduler() == "FAIRQ")
665
			$form .= " selected=\"selected\"";
666
		$form .= ">FAIRQ</option>";
667
		$form .= "<option value=\"CODELQ\"";
668
		if ($this->GetScheduler() == "CODELQ")
669
			$form .= " selected=\"selected\"";
670
		$form .= ">CODELQ</option>";
671
		$form .= "<option value=\"PRIQ\"";
672
		if ($this->GetScheduler() == "PRIQ")
673
			$form .= " selected=\"selected\"";
674
		$form .= ">PRIQ</option>";
675
		$form .= "</select>";
676
		$form .= "<br /> <span class=\"vexpl\">";
677
		$form .= gettext("NOTE: Changing this changes all child queues!");
678
		$form .= gettext(" Beware you can lose information.");
679
		$form .= "</span>";
680
		$form .= "</td></tr>";
681
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth");
682
		$form .= "</td><td class=\"vncellreq\">";
683
		$form .= "<input type=\"text\" id=\"bandwidth\" name=\"bandwidth\" value=\"";
684
		$form .= $this->GetBandwidth() . "\" />";
685
		$form .= "<select id=\"bandwidthtype\" name=\"bandwidthtype\" class=\"formselect\">";
686
		$form .= "<option value=\"Kb\"";
687
		if ($this->GetBwscale() == "Kb")
688
			$form .= " selected=\"selected\"";
689
		$form .= ">Kbit/s</option>";
690
		$form .= "<option value=\"Mb\"";
691
		if ($this->GetBwscale() == "Mb")
692
			$form .= " selected=\"selected\"";
693
		$form .= ">Mbit/s</option>";
694
		$form .= "<option value=\"Gb\"";
695
		if ($this->GetBwscale() == "Gb")
696
			$form .= " selected=\"selected\"";
697
		$form .= ">Gbit/s</option>";
698
		$form .= "<option value=\"b\"";
699
		if ($this->GetBwscale() == "b")
700
			$form .= " selected=\"selected\"";
701
		$form .= ">Bit/s</option>";
702
		$form .= "</select>";
703
		$form .= "</td></tr>";
704
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">Queue Limit</td>";
705
		$form .= "<td class=\"vncellreq\">";
706
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
707
		$form .= $this->GetQlimit();
708
		$form .= "\" />";
709
		$form .= "</td></tr>";
710
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">TBR Size</td>";
711
		$form .= "<td class=\"vncellreq\">";
712
		$form .= "<br /><input type=\"text\" id=\"tbrconfig\" name=\"tbrconfig\" value=\"";
713
		$form .= $this->GetTbrConfig();
714
		$form .= "\" />";
715
		$form .= "<br /> <span class=\"vexpl\">";
716
		$form .= gettext("Adjusts the size, in bytes, of the token bucket regulator. "
717
		      .  "If not specified, heuristics based on the interface "
718
		      .  "bandwidth are used to determine the size.");
719
		$form .= "</span></td></tr>";
720
		$form .= "<input type=\"hidden\" id=\"interface\" name=\"interface\"";
721
		$form .= " value=\"" . $this->GetInterface() . "\" />";
722
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"".$this->GetQname()."\" />";
723

    
724

    
725
		return $form;
726
	}
727

    
728
	function update_altq_queue_data(&$data) {
729
		$this->ReadConfig($data);
730
	}
731

    
732
	/*
733
	 * Should call on each of it queues and subqueues
734
	 * the same function much like build_rules();
735
	 */
736
	function wconfig() {
737
		$cflink = &get_reference_to_me_in_config($this->GetLink());
738
		if (!is_array($cflink))
739
			$cflink = array();
740
		$cflink['interface'] = $this->GetInterface();
741
		$cflink['name'] = $this->GetQname();
742
		$cflink['scheduler'] = $this->GetScheduler();
743
		$cflink['bandwidth'] = $this->GetBandwidth();
744
		$cflink['bandwidthtype'] = $this->GetBwscale();
745
		$cflink['qlimit'] = trim($this->GetQlimit());
746
		if (empty($cflink['qlimit']))
747
			unset($cflink['qlimit']);
748
		$cflink['tbrconfig'] = trim($this->GetTbrConfig());
749
		if (empty($cflink['tbrconfig']))
750
			unset($cflink['tbrconfig']);
751
		$cflink['enabled'] = $this->GetEnabled();
752
		if (empty($cflink['enabled']))
753
			unset($cflink['enabled']);
754
	}
755

    
756
}
757

    
758
class priq_queue {
759
	var $qname;
760
	var $qinterface;
761
	var $qlimit;
762
	var $qpriority;
763
	var $description;
764
	var $isparent;
765
	var $qbandwidth;
766
	var $qbandwidthtype;
767
	var $qdefault = "";
768
	var $qrio = "";
769
	var $qred = "";
770
	var $qcodel = "";
771
	var $qecn = "";
772
	var $qack;
773
	var $qenabled = "";
774
	var $qparent;
775
	var $link;
776
	var $available_bw; /* in b/s */
777

    
778
	/* This is here to help with form building and building rules/lists */
779
	var $subqueues = array();
780

    
781
	/* Accesor functions */
782
	function GetAvailableBandwidth() {
783
		return $this->available_bw;
784
	}
785
	function SetAvailableBandwidth($bw) {
786
		$this->available_bw = $bw;
787
	}
788
	function SetLink($link) {
789
		$this->link = $link;
790
	}
791
	function GetLink() {
792
		return $this->link;
793
	}
794
	function &GetParent() {
795
		return $this->qparent;
796
	}
797
	function SetParent(&$parent) {
798
		$this->qparent = &$parent;
799
	}
800
	function GetEnabled() {
801
		return $this->qenabled;
802
	}
803
	function SetEnabled($value) {
804
		$this->qenabled = $value;
805
	}
806
	function CanHaveChildren() {
807
		return false;
808
	}
809
	function CanBeDeleted() {
810
		return true;
811
	}
812
	function GetQname() {
813
		return $this->qname;
814
	}
815
	function SetQname($name) {
816
		$this->qname = trim($name);
817
	}
818
	function GetBandwidth() {
819
		return $this->qbandwidth;
820
	}
821
	function SetBandwidth($bandwidth) {
822
		$this->qbandwidth = $bandwidth;
823
	}
824
	function GetInterface() {
825
		return $this->qinterface;
826
	}
827
	function SetInterface($name) {
828
		$this->qinterface = trim($name);
829
	}
830
	function GetQlimit() {
831
		return $this->qlimit;
832
	}
833
	function SetQlimit($limit) {
834
		$this->qlimit = $limit;
835
	}
836
	function GetQpriority() {
837
		return $this->qpriority;
838
	}
839
	function SetQpriority($priority) {
840
		$this->qpriority = $priority;
841
	}
842
	function GetDescription() {
843
		return $this->description;
844
	}
845
	function SetDescription($str) {
846
		$this->description = trim($str);
847
	}
848
	function GetFirstime() {
849
		return $this->firsttime;
850
	}
851
	function SetFirsttime($number) {
852
		$this->firsttime = $number;
853
	}
854
	function GetBwscale() {
855
		return $this->qbandwidthtype;
856
	}
857
	function SetBwscale($scale) {
858
		$this->qbandwidthtype = $scale;
859
	}
860
	function GetDefaultQueuePresent() {
861
		if ($this->GetDefault())
862
			return true;
863
		if (!empty($this->subqueues)) {
864
			foreach ($this->subqueues as $q) {
865
				if ($q->GetDefault())
866
					return true;
867
			}
868
		}
869

    
870
		return false;
871
	}
872
	function GetDefault() {
873
		return $this->qdefault;
874
	}
875
	function SetDefault($value = false) {
876
		$this->qdefault = $value;
877
	}
878
	function GetCodel() {
879
		return $this->codel;
880
	}
881
	function SetCodel($codel = false) {
882
		$this->codel = $codel;
883
	}
884
	function GetRed() {
885
		return $this->qred;
886
	}
887
	function SetRed($red = false) {
888
		$this->qred = $red;
889
	}
890
	function GetRio() {
891
		return $this->qrio;
892
	}
893
	function SetRio($rio = false) {
894
		$this->qrio = $rio;
895
	}
896
	function GetEcn() {
897
		return $this->qecn;
898
	}
899
	function SetEcn($ecn = false) {
900
		$this->qecn = $ecn;
901
	}
902
	function GetAck() {
903
		return $this->qack;
904
	}
905
	function SetAck($ack = false) {
906
		$this->qack = $ack;
907
	}
908

    
909
	function build_javascript() {
910
		$javascript = "<script type=\"text/javascript\">";
911
		$javascript .= "//<![CDATA[\n";
912
		$javascript .= "function mySuspend() { \n";
913
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
914
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
915
		$javascript .= "else if (document.all)\n";
916
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
917
		$javascript .= "}\n";
918

    
919
		$javascript .= "function myResume() {\n";
920
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
921
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
922
		$javascript .= "else if (document.all)\n";
923
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
924
		$javascript .= "}\n";
925
		$javascript .= "//]]>";
926
		$javascript .= "</script>";
927

    
928
		return $javascript;
929
	}
930

    
931
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
932

    
933
	/*
934
	 * Currently this will not be called unless we decide to clone a whole
935
	 * queue tree on the 'By Queues' view or support drag&drop on the tree/list
936
	 */
937
	function copy_queue($interface, &$cflink) {
938

    
939
		$cflink['name'] = $this->GetQname();
940
		$cflink['interface'] = $interface;
941
		$cflink['qlimit'] = $this->GetQlimit();
942
		$cflink['priority'] = $this->GetQpriority();
943
		$cflink['description'] = $this->GetDescription();
944
		$cflink['enabled'] = $this->GetEnabled();
945
		$cflink['default'] = $this->GetDefault();
946
		$cflink['red'] = $this->GetRed();
947
		$cflink['codel'] = $this->GetCodel();
948
		$cflink['rio'] = $this->GetRio();
949
		$cflink['ecn'] = $this->GetEcn();
950

    
951
		if (is_array($this->subqueues)) {
952
			$cflinkp['queue'] = array();
953
			foreach ($this->subqueues as $q) {
954
				$cflink['queue'][$q->GetQname()] = array();
955
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
956
			}
957
		}
958

    
959
	}
960

    
961
	function clean_queue($sched) {
962
		clean_child_queues($sched, $this->GetLink());
963
		if (is_array($this->subqueues)) {
964
			foreach ($this->subqueues as $q)
965
				$q->clean_queue($sched);
966
		}
967
	}
968

    
969
	function &get_queue_list(&$qlist) {
970

    
971
		$qlist[$this->GetQname()] = & $this;
972
		if (is_array($this->subqueues)) {
973
			foreach ($this->subqueues as $queue)
974
				$queue->get_queue_list($qlist);
975
		}
976
	}
977

    
978
	function delete_queue() {
979
		unref_on_altq_queue_list($this->GetQname());
980
		cleanup_queue_from_rules($this->GetQname());
981
		unset_object_by_reference($this->GetLink());
982
	}
983

    
984
	function delete_all() {
985
		if (count($this->subqueues)) {
986
			foreach ($this->subqueues as $q) {
987
				$q->delete_all();
988
				unset_object_by_reference($q->GetLink());
989
				unset($q);
990
			}
991
			unset($this->subqueues);
992
		}
993
	}
994

    
995
	function &find_queue($interface, $qname) {
996
		if ($qname == $this->GetQname())
997
			return $this;
998
	}
999

    
1000
	function find_parentqueue($interface, $qname) { return; }
1001

    
1002
	function validate_input($data, &$input_errors) {
1003

    
1004
		$reqdfields[] = "name";
1005
		$reqdfieldsn[] = gettext("Name");
1006
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1007

    
1008
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
1009
			$input_errors[] = "Bandwidth must be an integer.";
1010
		if ($data['bandwidth'] < 0)
1011
			$input_errors[] = "Bandwidth cannot be negative.";
1012
		if ($data['priority'] && (!is_numeric($data['priority'])
1013
		    || ($data['priority'] < 1) || ($data['priority'] > 15))) {
1014
			$input_errors[] = gettext("The priority must be an integer between 1 and 15.");
1015
		}
1016
		if ($data['qlimit'] && (!is_numeric($data['qlimit'])))
1017
				$input_errors[] = gettext("Queue limit must be an integer");
1018
		if ($data['qlimit'] < 0)
1019
				$input_errors[] = gettext("Queue limit must be positive");
1020
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['newname']))
1021
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1022
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['name']))
1023
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
1024
		$default = $this->GetDefault();
1025
		if (!empty($data['default']) && altq_get_default_queue($data['interface']) && empty($default))
1026
			$input_errors[] = gettext("Only one default queue per interface is allowed.");
1027
	}
1028

    
1029
	function ReadConfig(&$q) {
1030
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
1031
			$this->SetQname($q['newname']);
1032
		} else if (!empty($q['newname'])) {
1033
			$this->SetQname($q['newname']);
1034
		} else if (isset($q['name']))
1035
			$this->SetQname($q['name']);
1036
		if (isset($q['interface']))
1037
			$this->SetInterface($q['interface']);
1038
		$this->SetBandwidth($q['bandwidth']);
1039
		if ($q['bandwidthtype'] <> "")
1040
			$this->SetBwscale($q['bandwidthtype']);
1041
		if (!empty($q['qlimit']))
1042
			$this->SetQlimit($q['qlimit']);
1043
		else
1044
			$this->SetQlimit(""); // Default
1045
		if (!empty($q['priority']))
1046
			$this->SetQPriority($q['priority']);
1047
		else
1048
			$this->SetQpriority("");
1049
		if (!empty($q['description']))
1050
			$this->SetDescription($q['description']);
1051
		else
1052
			$this->SetDescription("");
1053
		if (!empty($q['red']))
1054
			$this->SetRed($q['red']);
1055
		else
1056
			$this->SetRed();
1057
		if (!empty($q['codel']))
1058
			$this->SetCodel($q['codel']);
1059
		else
1060
			$this->SetCodel();
1061
		if (!empty($q['rio']))
1062
			$this->SetRio($q['rio']);
1063
		else
1064
			$this->SetRio();
1065
		if (!empty($q['ecn']))
1066
			$this->SetEcn($q['ecn']);
1067
		else
1068
			$this->SetEcn();
1069
		if (!empty($q['default']))
1070
			$this->SetDefault($q['default']);
1071
		else
1072
			$this->SetDefault();
1073
		if (!empty($q['enabled']))
1074
			$this->SetEnabled($q['enabled']);
1075
		else
1076
			$this->SetEnabled("");
1077

    
1078
	}
1079

    
1080
	function build_tree() {
1081
		$tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&amp;queue=". $this->GetQname()."&amp;action=show";
1082
		$tree .= "\" ";
1083
		$tmpvalue = $this->GetDefault();
1084
		if (!empty($tmpvalue))
1085
			$tree .= " class=\"navlnk\"";
1086
		$tree .= " >" . $this->GetQname() . "</a>";
1087
		/*
1088
		 * Not needed here!
1089
		 * if (is_array($queues) {
1090
		 *	  $tree .= "<ul>";
1091
		 *	  foreach ($q as $queues)
1092
		 *		  $tree .= $queues['$q->GetName()']->build_tree();
1093
		 *	  endforeach
1094
		 *	  $tree .= "</ul>";
1095
		 * }
1096
		 */
1097

    
1098
		$tree .= "</li>";
1099

    
1100
		return $tree;
1101
	}
1102

    
1103
	/* Should return something like:
1104
	 * queue $qname on $qinterface bandwidth ....
1105
	 */
1106
	function build_rules(&$default = false) {
1107
		$pfq_rule = " queue ". $this->qname;
1108
		if ($this->GetInterface())
1109
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1110
		$tmpvalue = $this->GetQpriority();
1111
		if (!empty($tmpvalue))
1112
			$pfq_rule .= " priority ".$this->GetQpriority();
1113
		$tmpvalue = $this->GetQlimit();
1114
		if (!empty($tmpvalue))
1115
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1116
		if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault() || $this->GetCodel()) {
1117
			$pfq_rule .= " priq ( ";
1118
			$tmpvalue = $this->GetRed();
1119
			if (!empty($tmpvalue)) {
1120
				$comma = 1;
1121
				$pfq_rule .= " red ";
1122
			}
1123
			$tmpvalue = $this->GetRio();
1124
			if (!empty($tmpvalue)) {
1125
				if ($comma)
1126
					$pfq_rule .= " ,";
1127
				$comma = 1;
1128
				$pfq_rule .= " rio ";
1129
			}
1130
			$tmpvalue = $this->GetEcn();
1131
			if (!empty($tmpvalue)) {
1132
				if ($comma)
1133
					$pfq_rule .= " ,";
1134
				$comma = 1;
1135
				$pfq_rule .= " ecn ";
1136
			}
1137
			$tmpvalue = $this->GetCodel();
1138
			if (!empty($tmpvalue)) {
1139
				if ($comma)
1140
					$pfq_rule .= " ,";
1141
				$comma = 1;
1142
				$pfq_rule .= " codel ";
1143
			}
1144
			$tmpvalue = $this->GetDefault();
1145
			if (!empty($tmpvalue)) {
1146
				if ($comma)
1147
					$pfq_rule .= " ,";
1148
				$pfq_rule .= " default ";
1149
				$default = true;
1150
			}
1151
			$pfq_rule .= " ) ";
1152
		}
1153

    
1154
		$pfq_rule .= " \n";
1155

    
1156
		return $pfq_rule;
1157
	}
1158

    
1159
	/*
1160
	 * To return the html form to show to user
1161
	 * for getting the parameters.
1162
	 * Should do even for first time when the
1163
	 * object is created and later when we may
1164
	 * need to update it.
1165
	 */
1166
	function build_form() {
1167
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
1168
		$form .= gettext("Enable/Disable");
1169
		$form .= "<br /></td><td class=\"vncellreq\">";
1170
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
1171
		if ($this->GetEnabled() == "on")
1172
			$form .=  " checked=\"checked\"";
1173
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue and its children") . "</span>";
1174
		$form .= "</td></tr>";
1175
		$form .= "<tr>";
1176
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">";
1177
		$form .= gettext("Queue Name") . "</td><td width=\"78%\" class=\"vtable\">";
1178
		$form .= "<input name=\"newname\" type=\"text\" id=\"newname\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
1179
		$form .= htmlspecialchars($this->GetQname());
1180
		$form .= "\" />";
1181
		$form .= "<input name=\"name\" type=\"hidden\" id=\"name\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
1182
		$form .= htmlspecialchars($this->GetQname());
1183
		$form .= "\" />";
1184
		$form .= "<br /> <span class=\"vexpl\">" . gettext("Enter the name of the queue here.  Do not use spaces and limit the size to 15 characters.");
1185
		$form .= "</span><br /></td>";
1186
		$form .= "</tr><tr>";
1187
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Priority") . "</td>";
1188
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"priority\" type=\"text\" id=\"priority\" size=\"5\" value=\"";
1189
		$form .= htmlspecialchars($this->GetQpriority());
1190
		$form .= "\" />";
1191
		$form .= "<br /> <span class=\"vexpl\">" . gettext("For hfsc, the range is 0 to 7. The default is 1.  Hfsc queues with a higher priority are preferred in the case of overload.") . "</span></td>";
1192
		$form .= "</tr>";
1193
		$form .= "<tr>";
1194
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Queue limit") . "</td>";
1195
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"qlimit\" type=\"text\" id=\"qlimit\" size=\"8\" value=\"";
1196
		$form .= htmlspecialchars($this->GetQlimit());
1197
		$form .= "\" />";
1198
		$form .= "<br /> <span class=\"vexpl\">" . gettext("Queue limit in packets.");
1199
		$form .= "</span></td></tr>";
1200
		$form .= "<tr>";
1201
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncell\">" . gettext("Scheduler options") . "</td>";
1202
		$form .= "<td width=\"78%\" class=\"vtable\">";
1203
		if (empty($this->subqueues)) {
1204
			if ($this->GetDefault()) {
1205
				$form .= "<input type=\"checkbox\" id=\"default\" checked=\"checked\" name=\"default\" value=\"default\"";
1206
				$form .= " /> " . gettext("Default queue") . "<br />";
1207
			} else {
1208
				$form .= "<input type=\"checkbox\" id=\"default\" name=\"default\" value=\"default\"";
1209
				$form .= " /> " . gettext("Default queue") . "<br />";
1210
			}
1211
		}
1212
		$form .= "<input type=\"checkbox\" id=\"red\" name=\"red\" value=\"red\" ";
1213
		$tmpvalue = $this->GetRed();
1214
		if(!empty($tmpvalue))
1215
			$form .=  " checked=\"checked\"";
1216
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#red\">" . gettext("Random Early Detection") . "</a><br />";
1217
		$form .= "<input type=\"checkbox\" id=\"rio\" name=\"rio\" value=\"rio\"";
1218
		$tmpvalue = $this->GetRio();
1219
		if(!empty($tmpvalue))
1220
			$form .=  " checked=\"checked\"";
1221
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#rio\">" . gettext("Random Early Detection In and Out") . "</a><br />";
1222
		$form .= "<input type=\"checkbox\" id=\"ecn\" name=\"ecn\" value=\"ecn\"";
1223
		$tmpvalue = $this->GetEcn();
1224
		if(!empty($tmpvalue))
1225
			$form .=  " checked=\"checked\"";
1226
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#ecn\">" . gettext("Explicit Congestion Notification") . "</a><br />";
1227
		$form .= "<input type=\"checkbox\" id=\"codel\" name=\"codel\" value=\"codel\"";
1228
		$tmpvalue = $this->GetCodel();
1229
		if(!empty($tmpvalue))
1230
			$form .=  " checked=\"checked\"";
1231
		$form .= " /> <a target=\"_new\" href=\"http://www.bufferbloat.net/projects/codel/wiki\">" . gettext("Codel Active Queue") . "</a><br />";
1232
		$form .= "<span class=\"vexpl\"><br />" . gettext("Select options for this queue");
1233
		$form .= "</span></td></tr><tr>";
1234
		$form .= "<td width=\"22%\" class=\"vncellreq\">" . gettext("Description") . "</td>";
1235
		$form .= "<td width=\"78%\" class=\"vtable\">";
1236
		$form .= "<input type=\"text\" name=\"description\" size=\"40\" class=\"formfld unknown\" value=\"" . $this->GetDescription() . "\" />";
1237
		$form .= "</td></tr>";
1238
		$form .= "<input type=\"hidden\" name=\"interface\" id=\"interface\"";
1239
		$form .= " value=\"".$this->GetInterface()."\" />";
1240

    
1241
		return $form;
1242
	}
1243

    
1244
	function build_shortform() {
1245
		/* XXX: Hacks in site. Mostly layer violations!  */
1246
		global $g, $altq_list_queues;
1247
		global $shaperIFlist;
1248

    
1249
		$altq =& $altq_list_queues[$this->GetInterface()];
1250
		if ($altq)
1251
			$scheduler = ": " . $altq->GetScheduler();
1252
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
1253
		$form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=" . $this->GetQname()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .$scheduler."</a>";
1254
		$form .= "</td></tr>";
1255
		/*
1256
		 * XXX: Hack in sight maybe fix with a class that wraps all
1257
		 * of this layer violations
1258
		 */
1259
		$form .= "<tr>";
1260
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
1261
		$form .= gettext("Bandwidth:") . " " . $this->GetBandwidth().$this->GetBwscale();
1262
		$form .= "</td><td width=\"50%\"></td></tr>";
1263
		$tmpvalue = $this->GetQpriority();
1264
		if (!empty($tmpvalue))
1265
			$form .= "<tr><td width=\"20%\" class=\"vncellreq\">" .gettext("Priority: on") . " </td></tr>";
1266
		$tmpvalue = $this->GetDefault();
1267
		if (!empty($tmpvalue))
1268
			$form .= "<tr><td class=\"vncellreq\">" . gettext("Default: on") . " </td></tr>";
1269
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
1270
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
1271
		$form .= $this->GetInterface() . "&amp;queue=";
1272
		$form .= $this->GetQname() . "&amp;action=delete\">";
1273
		$form .= "<img src=\"";
1274
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
1275
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("Delete queue from interface") . "\" alt=\"delete\" />";
1276
		$form .= "<span>" . gettext("Delete queue from interface") . "</span></a></td></tr>";
1277

    
1278
		return $form;
1279

    
1280
	}
1281

    
1282
		function update_altq_queue_data(&$q) {
1283
		$this->ReadConfig($q);
1284
	}
1285

    
1286
	function wconfig() {
1287
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1288
		if (!is_array($cflink))
1289
			$cflink = array();
1290
		$cflink['name'] = $this->GetQname();
1291
		$cflink['interface'] = $this->GetInterface();
1292
		$cflink['qlimit'] = trim($this->GetQlimit());
1293
		if (empty($cflink['qlimit']))
1294
			unset($cflink['qlimit']);
1295
		$cflink['priority'] = trim($this->GetQpriority());
1296
		if (empty($cflink['priority']))
1297
			unset($cflink['priority']);
1298
		$cflink['description'] = trim($this->GetDescription());
1299
		if (empty($cflink['description']))
1300
			unset($cflink['description']);
1301
		$cflink['enabled'] = trim($this->GetEnabled());
1302
		if (empty($cflink['enabled']))
1303
			unset($cflink['enabled']);
1304
		$cflink['default'] = trim($this->GetDefault());
1305
		if (empty($cflink['default']))
1306
			unset($cflink['default']);
1307
		$cflink['red'] = trim($this->GetRed());
1308
		if (empty($cflink['red']))
1309
			unset($cflink['red']);
1310
		$cflink['codel'] = trim($this->GetCodel());
1311
		if (empty($cflink['codel']))
1312
			unset($cflink['codel']);
1313
		$cflink['rio'] = trim($this->GetRio());
1314
		if (empty($cflink['rio']))
1315
			unset($cflink['rio']);
1316
		$cflink['ecn'] = trim($this->GetEcn());
1317
		if (empty($cflink['ecn']))
1318
			unset($cflink['ecn']);
1319
	}
1320
}
1321

    
1322
class hfsc_queue extends priq_queue {
1323
	/* realtime */
1324
	var $realtime;
1325
	var $r_m1;
1326
	var $r_d;
1327
	var $r_m2;
1328
	/* linkshare */
1329
	var $linkshare;
1330
	var $l_m1;
1331
	var $l_d;
1332
	var $l_m2;
1333
	/* upperlimit */
1334
	var $upperlimit;
1335
	var $u_m1;
1336
	var $u_d;
1337
	var $u_m2;
1338

    
1339
	/*
1340
	 * HFSC can have nested queues.
1341
	 */
1342
	function CanHaveChildren() {
1343
		return true;
1344
	}
1345
	function GetRealtime() {
1346
		return $this->realtime;
1347
	}
1348
	function GetR_m1() {
1349
		return $this->r_m1;
1350
	}
1351
	function GetR_d() {
1352
		return $this->r_d;
1353
	}
1354
	function GetR_m2() {
1355
		return $this->r_m2;
1356
	}
1357
	function SetRealtime() {
1358
		$this->realtime = "on";
1359
	}
1360
	function DisableRealtime() {
1361
		$this->realtime = "";
1362
	}
1363
	function SetR_m1($value) {
1364
		$this->r_m1 = $value;
1365
	}
1366
	function SetR_d($value) {
1367
		$this->r_d = $value;
1368
	}
1369
	function SetR_m2($value) {
1370
		$this->r_m2 = $value;
1371
	}
1372
	function GetLinkshare() {
1373
		return $this->linkshare;
1374
	}
1375
	function DisableLinkshare() {
1376
		$this->linkshare = "";
1377
	}
1378
	function GetL_m1() {
1379
		return $this->l_m1;
1380
	}
1381
	function GetL_d() {
1382
		return $this->l_d;
1383
	}
1384
	function GetL_m2() {
1385
		return $this->l_m2;
1386
	}
1387
	function SetLinkshare() {
1388
		$this->linkshare = "on";
1389
	}
1390
	function SetL_m1($value) {
1391
		$this->l_m1 = $value;
1392
	}
1393
	function SetL_d($value) {
1394
		$this->l_d = $value;
1395
	}
1396
	function SetL_m2($value) {
1397
		$this->l_m2 = $value;
1398
	}
1399
	function GetUpperlimit() {
1400
		return $this->upperlimit;
1401
	}
1402
	function GetU_m1() {
1403
		return $this->u_m1;
1404
	}
1405
	function GetU_d() {
1406
		return $this->u_d;
1407
	}
1408
	function GetU_m2() {
1409
		return $this->u_m2;
1410
	}
1411
	function SetUpperlimit() {
1412
		$this->upperlimit = "on";
1413
	}
1414
	function DisableUpperlimit() {
1415
		$this->upperlimit = "";
1416
	}
1417
	function SetU_m1($value) {
1418
		$this->u_m1 = $value;
1419
	}
1420
	function SetU_d($value) {
1421
		$this->u_d = $value;
1422
	}
1423
	function SetU_m2($value) {
1424
		$this->u_m2 = $value;
1425
	}
1426

    
1427
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1428

    
1429
		if (!is_array($this->subqueues))
1430
			$this->subqueues = array();
1431
		$q =& new hfsc_queue();
1432
		$q->SetInterface($this->GetInterface());
1433
		$q->SetParent($this);
1434
		$q->ReadConfig($qname);
1435
		$q->validate_input($qname, $input_errors);
1436
		if (count($input_errors)) {
1437
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
1438
			return $q;
1439
		}
1440

    
1441
		$q->SetEnabled("on");
1442
		$q->SetLink($path);
1443
		switch ($q->GetBwscale()) {
1444
		case "%":
1445
			$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
1446
			break;
1447
		default:
1448
			$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
1449
			break;
1450
		}
1451
		$q->SetAvailableBandwidth($myBw);
1452
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
1453

    
1454
		$this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue()
1455
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
1456
		if (is_array($qname['queue'])) {
1457
			foreach ($qname['queue'] as $key1 => $que) {
1458
				array_push($path, $key1);
1459
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
1460
				array_pop($path);
1461
			}
1462
		}
1463

    
1464
		return $q;
1465
	}
1466

    
1467
	function copy_queue($interface, &$cflink) {
1468

    
1469
		$cflink['name'] = $this->GetQname();
1470
		$cflink['interface'] = $interface;
1471
		$cflink['qlimit'] = trim($this->GetQlimit());
1472
		if (empty($cflink['qlimit']))
1473
			unset($cflink['qlimit']);
1474
		$cflink['priority'] = trim($this->GetQpriority());
1475
		if (empty($cflink['priority']))
1476
			unset($cflink['priority']);
1477
		$cflink['description'] = trim($this->GetDescription());
1478
		if (empty($cflink['description']))
1479
			unset($cflink['description']);
1480
		$cflink['bandwidth'] = $this->GetBandwidth();
1481
		$cflink['bandwidthtype'] = $this->GetBwscale();
1482
		$cflink['enabled'] = trim($this->GetEnabled());
1483
		if (empty($cflink['enabled']))
1484
			unset($cflink['enabled']);
1485
		$cflink['default'] = trim($this->GetDefault());
1486
		if (empty($cflink['default']))
1487
			unset($cflink['default']);
1488
		$cflink['red'] = trim($this->GetRed());
1489
		if (empty($cflink['red']))
1490
			unset($cflink['red']);
1491
		$cflink['rio'] = trim($this->GetRio());
1492
		if (empty($cflink['rio']))
1493
			unset($cflink['rio']);
1494
		$cflink['ecn'] = trim($this->GetEcn());
1495
		if (empty($cflink['ecn']))
1496
			unset($cflink['ecn']);
1497
		if ($this->GetLinkshare() <> "") {
1498
			if ($this->GetL_m1() <> "") {
1499
				$cflink['linkshare1'] = $this->GetL_m1();
1500
				$cflink['linkshare2'] = $this->GetL_d();
1501
				$cflink['linkshare'] = "on";
1502
			} else {
1503
				unset($cflink['linkshare1']);
1504
				unset($cflink['linkshare2']);
1505
				unset($cflink['linkshare']);
1506
			}
1507
			if ($this->GetL_m2() <> "") {
1508
				$cflink['linkshare3'] = $this->GetL_m2();
1509
				$cflink['linkshare'] = "on";
1510
			} else {
1511
				unset($cflink['linkshare3']);
1512
				unset($cflink['linkshare']);
1513
			}
1514
		}
1515
		if ($this->GetRealtime() <> "") {
1516
			if ($this->GetR_m1() <> "") {
1517
				$cflink['realtime1'] = $this->GetR_m1();
1518
				$cflink['realtime2'] = $this->GetR_d();
1519
				$cflink['realtime'] = "on";
1520
			} else {
1521
				unset($cflink['realtime1']);
1522
				unset($cflink['realtime2']);
1523
				unset($cflink['realtime']);
1524
			}
1525
			if ($this->GetR_m2() <> "") {
1526
				$cflink['realtime3'] = $this->GetR_m2();
1527
				$cflink['realtime'] = "on";
1528
			} else {
1529
				unset($cflink['realtime3']);
1530
				unset($cflink['realtime']);
1531
			}
1532
		}
1533
		if ($this->GetUpperlimit() <> "") {
1534
			if ($this->GetU_m1() <> "") {
1535
				$cflink['upperlimit1'] = $this->GetU_m1();
1536
				$cflink['upperlimit2'] = $this->GetU_d();
1537
				$cflink['upperlimit'] = "on";
1538
			} else {
1539
				unset($cflink['upperlimit']);
1540
				unset($cflink['upperlimit1']);
1541
				unset($cflink['upperlimit2']);
1542
			}
1543
			if ($this->GetU_m2() <> "") {
1544
				$cflink['upperlimit3'] = $this->GetU_m2();
1545
				$cflink['upperlimit'] = "on";
1546
			} else {
1547
				unset($cflink['upperlimit3']);
1548
				unset($cflink['upperlimit']);
1549
			}
1550
		}
1551

    
1552
		if (is_array($this->subqueues)) {
1553
			$cflinkp['queue'] = array();
1554
			foreach ($this->subqueues as $q) {
1555
				$cflink['queue'][$q->GetQname()] = array();
1556
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
1557
			}
1558
		}
1559
	}
1560

    
1561
	function delete_queue() {
1562
		unref_on_altq_queue_list($this->GetQname());
1563
		cleanup_queue_from_rules($this->GetQname());
1564
		$parent =& $this->GetParent();
1565
		foreach ($this->subqueues as $q)  {
1566
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
1567
			$q->delete_queue();
1568
		}
1569
		unset_object_by_reference($this->GetLink());
1570
	}
1571

    
1572
	/*
1573
	 * Should search even its children
1574
	 */
1575
	function &find_queue($interface, $qname) {
1576
		if ($qname == $this->GetQname())
1577
			return $this;
1578

    
1579
		foreach ($this->subqueues as $q) {
1580
			$result =& $q->find_queue("", $qname);
1581
			if ($result)
1582
				return $result;
1583
		}
1584
	}
1585

    
1586
	function &find_parentqueue($interface, $qname) {
1587
		if ($this->subqueues[$qname])
1588
			return $this;
1589
		foreach ($this->subqueues as $q) {
1590
			$result = $q->find_parentqueue("", $qname);
1591
			if ($result)
1592
				return $result;
1593
		}
1594
	}
1595

    
1596
	function validate_input($data, &$input_errors) {
1597
		parent::validate_input($data, $input_errors);
1598

    
1599
		$reqdfields[] = "bandwidth";
1600
		$reqdfieldsn[] = gettext("Bandwidth");
1601
		$reqdfields[] = "bandwidthtype";
1602
		$reqdfieldsn[] = gettext("Bandwidthtype");
1603

    
1604
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1605

    
1606
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1607
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
1608
				$input_errors[] = gettext("Bandwidth must be an integer.");
1609

    
1610
			if ($data['bandwidth'] < 0)
1611
				$input_errors[] = gettext("Bandwidth cannot be negative.");
1612

    
1613
			if ($data['bandwidthtype'] == "%") {
1614
				if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
1615
					$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
1616
			}
1617
		/*
1618
			$parent =& $this->GetParent();
1619
			switch ($data['bandwidthtype']) {
1620
			case "%":
1621
				$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
1622
			default:
1623
				$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
1624
				break;
1625
			}
1626
			if ($parent->GetAvailableBandwidth() < $myBw)
1627
				$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
1628
		*/
1629
		}
1630

    
1631
		if ($data['upperlimit1'] <> "" &&  $data['upperlimit2'] == "")
1632
			$input_errors[] = gettext("upperlimit service curve defined but missing (d) value");
1633
		if ($data['upperlimit2'] <> "" &&  $data['upperlimit1'] == "")
1634
			$input_errors[] = gettext("upperlimit service curve defined but missing initial bandwidth (m1) value");
1635
		if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1']))
1636
			$input_errors[] = gettext("upperlimit m1 value needs to be Kb, Mb, Gb, or %");
1637
		if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2']))
1638
			$input_errors[] = gettext("upperlimit d value needs to be numeric");
1639
		if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3']))
1640
			$input_errors[] = gettext("upperlimit m2 value needs to be Kb, Mb, Gb, or %");
1641

    
1642
		/*
1643
		if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") {
1644
			$bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']);
1645
			$bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']);
1646
			if (floatval($bw_1) < floatval($bw_2))
1647
				$input_errors[] = ("upperlimit m1 cannot be smaller than m2");
1648

    
1649
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1650
				$input_errors[] = ("upperlimit specification exceeds 80% of allowable allocation.");
1651
		}
1652
		*/
1653
		if ($data['linkshare1'] <> "" &&  $data['linkshare2'] == "")
1654
			$input_errors[] = gettext("linkshare service curve defined but missing (d) value");
1655
		if ($data['linkshare2'] <> "" &&  $data['linkshare1'] == "")
1656
			$input_errors[] = gettext("linkshare service curve defined but missing initial bandwidth (m1) value");
1657
		if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1']))
1658
			$input_errors[] = gettext("linkshare m1 value needs to be Kb, Mb, Gb, or %");
1659
		if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2']))
1660
			$input_errors[] = gettext("linkshare d value needs to be numeric");
1661
		if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3']))
1662
			$input_errors[] = gettext("linkshare m2 value needs to be Kb, Mb, Gb, or %");
1663
		if ($data['realtime1'] <> "" &&  $data['realtime2'] == "")
1664
			$input_errors[] = gettext("realtime service curve defined but missing (d) value");
1665
		if ($data['realtime2'] <> "" &&  $data['realtime1'] == "")
1666
			$input_errors[] = gettext("realtime service curve defined but missing initial bandwidth (m1) value");
1667

    
1668
		/*
1669
		if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) {
1670
			$bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']);
1671
			$bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']);
1672
			if (floatval($bw_1) < floatval($bw_2))
1673
				$input_errors[] = ("linkshare m1 cannot be smaller than m2");
1674

    
1675
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1676
				$input_errors[] = ("linkshare specification exceeds 80% of allowable allocation.");
1677
		}
1678
		*/
1679

    
1680
		if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1']))
1681
			$input_errors[] = gettext("realtime m1 value needs to be Kb, Mb, Gb, or %");
1682
		if ($data['realtime2'] <> "" && !is_numeric($data['realtime2']))
1683
			$input_errors[] = gettext("realtime d value needs to be numeric");
1684
		if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3']))
1685
			$input_errors[] = gettext("realtime m2 value needs to be Kb, Mb, Gb, or %");
1686

    
1687
		/*
1688
		if (isset($data['realtime']) && $data['realtime3'] <> "" && $data['realtime1'] <> "" && 0) {
1689
			$bw_1 = get_hfsc_bandwidth($this, $data['realtime1']);
1690
			$bw_2 = get_hfsc_bandwidth($this, $data['realtime3']);
1691
			if (floatval($bw_1) < floatval($bw_2))
1692
				$input_errors[] = ("realtime m1 cannot be smaller than m2");
1693

    
1694
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1695
				$input_errors[] = ("realtime specification exceeds 80% of allowable allocation.");
1696
		}
1697
		*/
1698
	}
1699

    
1700
	function ReadConfig(&$cflink) {
1701
		if (!empty($cflink['linkshare'])) {
1702
			if (!empty($cflink['linkshare1'])) {
1703
				$this->SetL_m1($cflink['linkshare1']);
1704
				$this->SetL_d($cflink['linkshare2']);
1705
				$this->SetLinkshare();
1706
			} else {
1707
				$this->SetL_m1("");
1708
				$this->SetL_d("");
1709
				$this->DisableLinkshare();
1710
			}
1711
			if (!empty($cflink['linkshare3'])) {
1712
				$this->SetL_m2($cflink['linkshare3']);
1713
				$this->SetLinkshare();
1714
			}
1715
		} else
1716
			$this->DisableLinkshare();
1717
		if (!empty($cflink['realtime'])) {
1718
			if (!empty($cflink['realtime1'])) {
1719
				$this->SetR_m1($cflink['realtime1']);
1720
				$this->SetR_d($cflink['realtime2']);
1721
				$this->SetRealtime();
1722
			} else {
1723
				$this->SetR_m1("");
1724
				$this->SetR_d("");
1725
				$this->DisableRealtime();
1726
			}
1727
			if (!empty($cflink['realtime3'])) {
1728
				$this->SetR_m2($cflink['realtime3']);
1729
				$this->SetRealtime();
1730
			}
1731
		} else
1732
			$this->DisableRealtime();
1733
		if (!empty($cflink['upperlimit'])) {
1734
			if (!empty($cflink['upperlimit1'])) {
1735
				$this->SetU_m1($cflink['upperlimit1']);
1736
				$this->SetU_d($cflink['upperlimit2']);
1737
				$this->SetUpperlimit();
1738
			} else {
1739
				$this->SetU_m1("");
1740
				$this->SetU_d("");
1741
				$this->DisableUpperlimit();
1742
			}
1743
			if (!empty($cflink['upperlimit3'])) {
1744
				$this->SetU_m2($cflink['upperlimit3']);
1745
				$this->SetUpperlimit();
1746
			}
1747
		} else
1748
			$this->DisableUpperlimit();
1749
		parent::ReadConfig($cflink);
1750
	}
1751

    
1752
	function build_tree() {
1753
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface() ."&amp;queue=" . $this->GetQname()."&amp;action=show";
1754
		$tree .= "\" ";
1755
		$tmpvalue = $this->GetDefault();
1756
		if (!empty($tmpvalue))
1757
			$tree .= " class=\"navlnk\"";
1758
		$tree .= " >" . $this->GetQname() . "</a>";
1759
		if (is_array($this->subqueues)) {
1760
			$tree .= "<ul>";
1761
			foreach ($this->subqueues as $q)  {
1762
				$tree .= $q->build_tree();
1763
			}
1764
			$tree .= "</ul>";
1765
		}
1766
		$tree .= "</li>";
1767
		return $tree;
1768
	}
1769

    
1770
	/* Even this should take children into consideration */
1771
	function build_rules(&$default = false) {
1772

    
1773
		$pfq_rule = " queue ". $this->qname;
1774
		if ($this->GetInterface())
1775
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1776
		if ($this->GetBandwidth() && $this->GetBwscale())
1777
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
1778

    
1779
		$tmpvalue = $this->GetQlimit();
1780
		if (!empty($tmpvalue))
1781
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1782
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetCodel() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
1783
			$pfq_rule .= " hfsc ( ";
1784
			$tmpvalue = $this->GetRed();
1785
			if (!empty($tmpvalue)) {
1786
				$comma = 1;
1787
				$pfq_rule .= " red ";
1788
			}
1789

    
1790
			$tmpvalue = $this->GetRio();
1791
			if (!empty($tmpvalue)) {
1792
				if ($comma)
1793
					$pfq_rule .= " ,";
1794
				$comma = 1;
1795
				$pfq_rule .= " rio ";
1796
			}
1797
			$tmpvalue = $this->GetEcn();
1798
			if (!empty($tmpvalue)) {
1799
				if ($comma)
1800
					$pfq_rule .= " ,";
1801
				$comma = 1;
1802
				$pfq_rule .= " ecn ";
1803
			}
1804
			$tmpvalue = $this->GetCodel();
1805
			if (!empty($tmpvalue)) {
1806
				if ($comma)
1807
					$pfq_rule .= " ,";
1808
				$comma = 1;
1809
				$pfq_rule .= " codel ";
1810
			}
1811
			$tmpvalue = $this->GetDefault();
1812
			if (!empty($tmpvalue)) {
1813
				if ($comma)
1814
					$pfq_rule .= " ,";
1815
				$comma = 1;
1816
				$pfq_rule .= " default ";
1817
				$default = true;
1818
			}
1819

    
1820
			if ($this->GetRealtime() <> "")  {
1821
				if ($comma)
1822
					$pfq_rule .= " , ";
1823
				if ($this->GetR_m1()  <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "")
1824
					$pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") ";
1825
				else  if ($this->GetR_m2() <> "")
1826
					$pfq_rule .= " realtime " . $this->GetR_m2();
1827
				$comma = 1;
1828
			}
1829
			if ($this->GetLinkshare() <> "") {
1830
				if ($comma)
1831
					$pfq_rule .= " ,";
1832
				if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "")
1833
					$pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") ";
1834
				else if ($this->GetL_m2() <> "")
1835
					$pfq_rule .= " linkshare " . $this->GetL_m2() . " ";
1836
				$comma = 1;
1837
			}
1838
			if ($this->GetUpperlimit() <> "") {
1839
				if ($comma)
1840
					$pfq_rule .= " ,";
1841
				if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "")
1842
							$pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") ";
1843
				else if ($this->GetU_m2() <> "")
1844
					$pfq_rule .= " upperlimit " . $this->GetU_m2() . " ";
1845
			}
1846
			$pfq_rule .= " ) ";
1847
		}
1848
		if (count($this->subqueues)) {
1849
			$i = count($this->subqueues);
1850
			$pfq_rule .= " { ";
1851
			foreach ($this->subqueues as $qkey => $qnone) {
1852
				if ($i > 1) {
1853
					$i--;
1854
					$pfq_rule .= " {$qkey}, ";
1855
				} else
1856
					$pfq_rule .= " {$qkey} ";
1857
			}
1858
			$pfq_rule .= " } \n";
1859
			foreach ($this->subqueues as $q)
1860
				$pfq_rule .= $q->build_rules($default);
1861
		}
1862

    
1863
		$pfq_rule .= " \n";
1864

    
1865
		return $pfq_rule;
1866
	}
1867

    
1868
	function build_javascript() {
1869
		$javascript = parent::build_javascript();
1870
		$javascript .= "<script type=\"text/javascript\">";
1871
		$javascript .= "//<![CDATA[\n";
1872
		$javascript .= "function enable_realtime(enable_over) { \n";
1873
		$javascript .= "if (document.iform.realtime.checked || enable_over) { \n";
1874
		$javascript .= "document.iform.realtime1.disabled = 0;\n";
1875
		$javascript .= "document.iform.realtime2.disabled = 0;\n";
1876
		$javascript .= "document.iform.realtime3.disabled = 0;\n";
1877
		$javascript .= " } else { \n";
1878
		$javascript .= "document.iform.realtime1.disabled = 1;\n";
1879
		$javascript .= "document.iform.realtime2.disabled = 1;\n";
1880
		$javascript .= "document.iform.realtime3.disabled = 1;\n";
1881
		$javascript .= " } \n";
1882
		$javascript .= " } \n";
1883
		$javascript .= "function enable_linkshare(enable_over) { \n";
1884
		$javascript .= "if (document.iform.linkshare.checked || enable_over) { \n";
1885
		$javascript .= "document.iform.linkshare1.disabled = 0;\n";
1886
		$javascript .= "document.iform.linkshare2.disabled = 0;\n";
1887
		$javascript .= "document.iform.linkshare3.disabled = 0;\n";
1888
		$javascript .= " } else { \n";
1889
		$javascript .= "document.iform.linkshare1.disabled = 1;\n";
1890
		$javascript .= "document.iform.linkshare2.disabled = 1;\n";
1891
		$javascript .= "document.iform.linkshare3.disabled = 1;\n";
1892
		$javascript .= " } \n";
1893
		$javascript .= " } \n";
1894
		$javascript .= "function enable_upperlimit(enable_over) { \n";
1895
		$javascript .= "if (document.iform.upperlimit.checked || enable_over) { \n";
1896
		$javascript .= "document.iform.upperlimit1.disabled = 0;\n";
1897
		$javascript .= "document.iform.upperlimit2.disabled = 0;\n";
1898
		$javascript .= "document.iform.upperlimit3.disabled = 0;\n";
1899
		$javascript .= " } else { \n";
1900
		$javascript .= "document.iform.upperlimit1.disabled = 1;\n";
1901
		$javascript .= "document.iform.upperlimit2.disabled = 1;\n";
1902
		$javascript .= "document.iform.upperlimit3.disabled = 1;\n";
1903
		$javascript .= " } \n";
1904

    
1905
		$javascript .= "} \n";
1906
		$javascript .= "//]]>";
1907
		$javascript .= "</script>";
1908

    
1909
		return $javascript;
1910
	}
1911

    
1912
	function build_form() {
1913
		$form = parent::build_form();
1914
		$form .= "<tr>";
1915
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
1916
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
1917
		$form .= htmlspecialchars($this->GetBandwidth());
1918
		$form .= "\" />";
1919
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
1920
		$form .= "<option value=\"Gb\"";
1921
		if ($this->GetBwscale() == "Gb")
1922
			$form .= " selected=\"selected\"";
1923
		$form .= ">" . gettext("Gbit/s") . "</option>";
1924
		$form .= "<option value=\"Mb\"";
1925
		if ($this->GetBwscale() == "Mb")
1926
			$form .= " selected=\"selected\"";
1927
		$form .= ">" . gettext("Mbit/s") . "</option>";
1928
		$form .= "<option value=\"Kb\"";
1929
		if ($this->GetBwscale() == "Kb")
1930
			$form .= " selected=\"selected\"";
1931
		$form .= ">" . gettext("Kbit/s") . "</option>";
1932
		$form .= "<option value=\"b\"";
1933
		if ($this->GetBwscale() == "b")
1934
			$form .= " selected=\"selected\"";
1935
		$form .= ">" . gettext("Bit/s") . "</option>";
1936
		$form .= "<option value=\"%\"";
1937
		if ($this->GetBwscale() == "%")
1938
			$form .= " selected=\"selected\"";
1939
		$form .= ">%</option>";
1940
		$form .= "</select> <br />";
1941
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
1942
		$form .= "</span></td></tr>";
1943
		$form .= "<tr>";
1944
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Service Curve (sc)") . "</td>";
1945
		$form .= "<td width=\"78%\" class=\"vtable\">";
1946
		$form .= "<table>";
1947
		$form .= "<tr><td>&nbsp;</td><td><center>m1</center></td><td><center>d</center></td><td><center><b>m2</b></center></td></tr>";
1948
		$form .= "<tr><td><input type=\"checkbox\" id=\"upperlimit\" name=\"upperlimit\"";
1949
		if($this->GetUpperlimit()<> "")
1950
			$form .=  " checked=\"checked\" ";
1951
		$form .= "onchange=\"enable_upperlimit()\" /> " . gettext("Upperlimit:") . "</td><td><input size=\"6\" value=\"";
1952
		$form .= htmlspecialchars($this->GetU_m1());
1953
		$form .= "\" id=\"upperlimit1\" name=\"upperlimit1\" ";
1954
		if ($this->GetUpperlimit() == "")
1955
			$form .= " disabled=\"disabled\"";
1956
		$form .= " /></td><td><input size=\"6\" value=\"";
1957
		$form .= htmlspecialchars($this->GetU_d());
1958
		$form .= "\" id=\"upperlimi2\" name=\"upperlimit2\" ";
1959
		if ($this->GetUpperlimit() == "")
1960
			$form .= " disabled=\"disabled\"";
1961
		$form .= " /></td><td><input size=\"6\" value=\"";
1962
		$form .= htmlspecialchars($this->GetU_m2());
1963
		$form .= "\" id=\"upperlimit3\" name=\"upperlimit3\" ";
1964
		if ($this->GetUpperlimit() == "")
1965
			$form .= " disabled=\"disabled\"";
1966
		$form .= " /></td><td>" . gettext("The maximum allowed bandwidth for the queue.") . "</td></tr>";
1967
		$form .= "<tr><td><input type=\"checkbox\" id=\"realtime\" name=\"realtime\"";
1968
		if($this->GetRealtime() <> "")
1969
			$form .=  " checked=\"checked\" ";
1970
		$form .= "onchange=\"enable_realtime()\" /> " . gettext("Real time:") . "</td><td><input size=\"6\" value=\"";
1971
		$form .= htmlspecialchars($this->GetR_m1());
1972
		$form .= "\" id=\"realtime1\" name=\"realtime1\" ";
1973
		if ($this->GetRealtime() == "")
1974
			$form .= " disabled=\"disabled\"";
1975
		$form .= " /></td><td><input size=\"6\" value=\"";
1976
		$form .= htmlspecialchars($this->GetR_d());
1977
		$form .= "\" id=\"realtime2\" name=\"realtime2\" ";
1978
		if ($this->GetRealtime() == "")
1979
			$form .= " disabled=\"disabled\"";
1980
		$form .= " /></td><td><input size=\"6\" value=\"";
1981
		$form .= htmlspecialchars($this->GetR_m2());
1982
		$form .= "\" id=\"realtime3\" name=\"realtime3\" ";
1983
		if ($this->GetRealtime() == "")
1984
			$form .= " disabled=\"disabled\"";
1985
		$form .= " /></td><td>" . gettext("The minimum required bandwidth for the queue.") . "</td></tr>";
1986
		$form .= "<tr><td><input type=\"checkbox\" id=\"linkshare\" name=\"linkshare\"";
1987
		if($this->GetLinkshare() <> "")
1988
			$form .=  " checked=\"checked\" ";
1989
		$form .= "onchange=\"enable_linkshare()\" /> " . gettext("Link share:") . "</td><td><input size=\"6\" value=\"";
1990
		$form .= htmlspecialchars($this->GetL_m1());
1991
		$form .= "\" id=\"linkshare1\" name=\"linkshare1\" ";
1992
		if ($this->GetLinkshare() == "")
1993
			$form .= " disabled=\"disabled\"";
1994
		$form .= " /></td><td><input size=\"6\" value=\"";
1995
		$form .= htmlspecialchars($this->GetL_d());
1996
		$form .= "\" id=\"linkshare2\" name=\"linkshare2\" ";
1997
		if ($this->GetLinkshare() == "")
1998
			$form .= " disabled=\"disabled\"";
1999
		$form .= " /></td><td><input size=\"6\" value=\"";
2000
		$form .= htmlspecialchars($this->GetL_m2());
2001
		$form .= "\" id=\"linkshare3\" name=\"linkshare3\" ";
2002
		if ($this->GetLinkshare() == "")
2003
			$form .= " disabled=\"disabled\"";
2004
		$form .= " /></td><td>" . gettext("The bandwidth share of a backlogged queue - this overrides priority.") . "</td></tr>";
2005
		$form .= "</table><br />";
2006
		$form .= gettext("The format for service curve specifications is (m1, d, m2).  m2 controls "
2007
		      .  "the bandwidth assigned to the queue.  m1 and d are optional and can be "
2008
		      .  "used to control the initial bandwidth assignment.  For the first d milliseconds the queue gets the bandwidth given as m1, afterwards the value "
2009
		      .  "given in m2.");
2010
		$form .= "</td>";
2011
		$form .= "</tr>";
2012

    
2013
		return $form;
2014
	}
2015

    
2016
	function update_altq_queue_data(&$data) {
2017
		$this->ReadConfig($data);
2018
	}
2019

    
2020
	function wconfig() {
2021
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2022
		if (!is_array($cflink))
2023
			$cflink = array();
2024
		$cflink['name'] = $this->GetQname();
2025
		$cflink['interface'] = $this->GetInterface();
2026
		$cflink['qlimit'] = trim($this->GetQlimit());
2027
		if (empty($cflink['qlimit']))
2028
			unset($cflink['qlimit']);
2029
		$cflink['priority'] = $this->GetQpriority();
2030
		if (empty($cflink['priority']))
2031
			unset($cflink['priority']);
2032
		$cflink['description'] = $this->GetDescription();
2033
		if (empty($cflink['description']))
2034
			unset($cflink['description']);
2035
		$cflink['bandwidth'] = $this->GetBandwidth();
2036
		$cflink['bandwidthtype'] = $this->GetBwscale();
2037
		$cflink['enabled'] = $this->GetEnabled();
2038
		if (empty($cflink['enabled']))
2039
			unset($cflink['enabled']);
2040
		$cflink['default'] = $this->GetDefault();
2041
		if (empty($cflink['default']))
2042
			unset($cflink['default']);
2043
		$cflink['red'] = trim($this->GetRed());
2044
		if (empty($cflink['red']))
2045
			unset($cflink['red']);
2046
		$cflink['rio'] = $this->GetRio();
2047
		if (empty($cflink['rio']))
2048
			unset($cflink['rio']);
2049
		$cflink['ecn'] = trim($this->GetEcn());
2050
		if (empty($cflink['ecn']))
2051
			unset($cflink['ecn']);
2052
		$cflink['codel'] = trim($this->GetCodel());
2053
		if (empty($cflink['codel']))
2054
			unset($cflink['codel']);
2055
		if ($this->GetLinkshare() <> "") {
2056
			if ($this->GetL_m1() <> "") {
2057
				$cflink['linkshare1'] = $this->GetL_m1();
2058
				$cflink['linkshare2'] = $this->GetL_d();
2059
				$cflink['linkshare'] = "on";
2060
			} else {
2061
				unset($cflink['linkshare']);
2062
				unset($cflink['linkshare1']);
2063
				unset($cflink['linkshare2']);
2064
			}
2065
			if ($this->GetL_m2() <> "") {
2066
				$cflink['linkshare3'] = $this->GetL_m2();
2067
				$cflink['linkshare'] = "on";
2068
			} else {
2069
				unset($cflink['linkshare']);
2070
				unset($cflink['linkshare3']);
2071
			}
2072
		} else {
2073
			unset($cflink['linkshare']);
2074
			unset($cflink['linkshare1']);
2075
			unset($cflink['linkshare2']);
2076
			unset($cflink['linkshare3']);
2077
		}
2078
		if ($this->GetRealtime() <> "") {
2079
			if ($this->GetR_m1() <> "") {
2080
				$cflink['realtime1'] = $this->GetR_m1();
2081
				$cflink['realtime2'] = $this->GetR_d();
2082
				$cflink['realtime'] = "on";
2083
			} else {
2084
				unset($cflink['realtime']);
2085
				unset($cflink['realtime1']);
2086
				unset($cflink['realtime2']);
2087
			}
2088
			if ($this->GetR_m2() <> "") {
2089
				$cflink['realtime3'] = $this->GetR_m2();
2090
				$cflink['realtime'] = "on";
2091
			} else {
2092
				unset($cflink['realtime']);
2093
				unset($cflink['realtime3']);
2094
			}
2095
		} else {
2096
			unset($cflink['realtime']);
2097
			unset($cflink['realtime1']);
2098
			unset($cflink['realtime2']);
2099
			unset($cflink['realtime3']);
2100
		}
2101
		if ($this->GetUpperlimit() <> "") {
2102
			if ($this->GetU_m1() <> "") {
2103
				$cflink['upperlimit1'] = $this->GetU_m1();
2104
				$cflink['upperlimit2'] = $this->GetU_d();
2105
				$cflink['upperlimit'] = "on";
2106
			} else {
2107
				unset($cflink['upperlimit']);
2108
				unset($cflink['upperlimit1']);
2109
				unset($cflink['upperlimit2']);
2110
			}
2111
			if ($this->GetU_m2() <> "") {
2112
				$cflink['upperlimit3'] = $this->GetU_m2();
2113
				$cflink['upperlimit'] = "on";
2114
			} else {
2115
				unset($cflink['upperlimit']);
2116
				unset($cflink['upperlimit3']);
2117
			}
2118
		} else {
2119
			unset($cflink['upperlimit']);
2120
			unset($cflink['upperlimit1']);
2121
			unset($cflink['upperlimit2']);
2122
			unset($cflink['upperlimit3']);
2123
		}
2124
	}
2125
}
2126

    
2127
class cbq_queue extends priq_queue {
2128
	var $qborrow = "";
2129

    
2130
	function GetBorrow() {
2131
		return $this->qborrow;
2132
	}
2133
	function SetBorrow($borrow) {
2134
		$this->qborrow = $borrow;
2135
	}
2136
	function CanHaveChildren() {
2137
		return true;
2138
	}
2139

    
2140
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2141

    
2142
		if (!is_array($this->subqueues))
2143
			$this->subqueues = array();
2144
		$q =& new cbq_queue();
2145
		$q->SetInterface($this->GetInterface());
2146
		$q->SetParent($this);
2147
		$q->ReadConfig($qname);
2148
		$q->validate_input($qname, $input_errors);
2149
		if (count($input_errors)) {
2150
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
2151
			return $q;
2152
		}
2153
		switch ($q->GetBwscale()) {
2154
		case "%":
2155
			$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
2156
			break;
2157
		default:
2158
			$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
2159
			break;
2160
		}
2161
		$q->SetAvailableBandwidth($myBw);
2162
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
2163

    
2164
		$q->SetEnabled("on");
2165
		$q->SetLink($path);
2166
		$this->subqueues[$q->GetQName()] = &$q;
2167
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2168
		if (is_array($qname['queue'])) {
2169
			foreach ($qname['queue'] as $key1 => $que) {
2170
				array_push($path, $key1);
2171
				$q->add_queue($q->GetInterface(), $que, $path, $input_errors);
2172
				array_pop($path);
2173
			}
2174
		}
2175

    
2176
		return $q;
2177
	}
2178

    
2179
	function copy_queue($interface, &$cflink) {
2180

    
2181
		$cflink['interface'] = $interface;
2182
		$cflink['qlimit'] = trim($this->GetQlimit());
2183
		if (empty($clink['qlimit']))
2184
			unset($cflink['qlimit']);
2185
		$cflink['priority'] = trim($this->GetQpriority());
2186
		if (empty($cflink['priority']))
2187
			unset($cflink['priority']);
2188
		$cflink['name'] = $this->GetQname();
2189
		$cflink['description'] = trim($this->GetDescription());
2190
		if (empty($cflink['description']))
2191
			unset($cflink['description']);
2192
		$cflink['bandwidth'] = $this->GetBandwidth();
2193
		$cflink['bandwidthtype'] = $this->GetBwscale();
2194
		$cflink['enabled'] = trim($this->GetEnabled());
2195
		if (empty($cflink['enabled']))
2196
			unset($cflink['enabled']);
2197
		$cflink['default'] = trim($this->GetDefault());
2198
		if (empty($cflink['default']))
2199
			unset($cflink['default']);
2200
		$cflink['red'] = trim($this->GetRed());
2201
		if (empty($cflink['red']))
2202
			unset($cflink['red']);
2203
		$cflink['rio'] = trim($this->GetRio());
2204
		if (empty($cflink['rio']))
2205
			unset($cflink['rio']);
2206
		$cflink['ecn'] = trim($this->GetEcn());
2207
		if (empty($cflink['ecn']))
2208
			unset($cflink['ecn']);
2209
		$cflink['borrow'] = trim($this->GetBorrow());
2210
		if (empty($cflink['borrow']))
2211
			unset($cflink['borrow']);
2212
		if (is_array($this->queues)) {
2213
			$cflinkp['queue'] = array();
2214
			foreach ($this->subqueues as $q) {
2215
				$cflink['queue'][$q->GetQname()] = array();
2216
				$q->copy_queue($interface, $cflink['queue'][$q->GetQname()]);
2217
			}
2218
		}
2219
	}
2220

    
2221
	/*
2222
	 * Should search even its children
2223
	 */
2224
	function &find_queue($interface, $qname) {
2225
		if ($qname == $this->GetQname())
2226
			return $this;
2227
		foreach ($this->subqueues as $q) {
2228
			$result =& $q->find_queue("", $qname);
2229
			if ($result)
2230
				return $result;
2231
		}
2232
	}
2233

    
2234
	function &find_parentqueue($interface, $qname) {
2235
		if ($this->subqueues[$qname])
2236
			return $this;
2237
		foreach ($this->subqueues as $q) {
2238
			$result = $q->find_parentqueue("", $qname);
2239
			if ($result)
2240
				return $result;
2241
		}
2242
	}
2243

    
2244
	function delete_queue() {
2245
		unref_on_altq_queue_list($this->GetQname());
2246
		cleanup_queue_from_rules($this->GetQname());
2247
		foreach ($this->subqueues as $q) {
2248
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
2249
			$q->delete_queue();
2250
		}
2251
		unset_object_by_reference($this->GetLink());
2252
	}
2253

    
2254
	function validate_input($data, &$input_errors) {
2255
		parent::validate_input($data, $input_errors);
2256

    
2257
		if ($data['priority'] > 7)
2258
				$input_errors[] = gettext("Priority must be an integer between 1 and 7.");
2259
		$reqdfields[] = "bandwidth";
2260
		$reqdfieldsn[] = gettext("Bandwidth");
2261
		$reqdfields[] = "bandwidthtype";
2262
		$reqdfieldsn[] = gettext("Bandwidthtype");
2263

    
2264
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2265

    
2266
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2267
			$input_errors[] = gettext("Bandwidth must be an integer.");
2268

    
2269

    
2270
		if ($data['bandwidth'] < 0)
2271
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2272

    
2273
		if ($data['bandwidthtype'] == "%") {
2274
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2275
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2276
		}
2277

    
2278
/*
2279
		$parent =& $this->GetParent();
2280
		switch ($data['bandwidthtype']) {
2281
		case "%":
2282
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2283
			break;
2284
		default:
2285
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2286
			break;
2287
		}
2288
		if ($parent->GetAvailableBandwidth() < floatval($myBw))
2289
			$input_errors[] = "The sum of the children bandwidth exceeds that of the parent.";
2290
 */
2291
	}
2292

    
2293
	function ReadConfig(&$q) {
2294
		parent::ReadConfig($q);
2295
		if (!empty($q['borrow']))
2296
			$this->SetBorrow("on");
2297
		else
2298
			$this->SetBorrow("");
2299
	}
2300

    
2301
	function build_javascript() {
2302
		return parent::build_javascript();
2303
	}
2304

    
2305
	function build_tree() {
2306
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2307
		$tree .= "\" ";
2308
		$tmpvalue = trim($this->GetDefault());
2309
		if (!empty($tmpvalue))
2310
			$tree .= " class=\"navlnk\"";
2311
		$tree .= " >" . $this->GetQname() . "</a>";
2312
		if (is_array($this->subqueues)) {
2313
			$tree .= "<ul>";
2314
			foreach ($this->subqueues as $q)  {
2315
				$tree .= $q->build_tree();
2316
			}
2317
			$tree .= "</ul>";
2318
		}
2319
		$tree .= "</li>";
2320
		return $tree;
2321
	}
2322

    
2323
	/* Even this should take children into consideration */
2324
	function build_rules(&$default = false) {
2325
		$pfq_rule = "queue ". $this->qname;
2326
		if ($this->GetInterface())
2327
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2328
		if ($this->GetBandwidth() && $this->GetBwscale())
2329
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2330
		$tmpvalue = $this->GetQpriority();
2331
		if (!empty($tmpvalue))
2332
			$pfq_rule .= " priority " . $this->GetQpriority();
2333
		$tmpvalue = trim($this->GetQlimit());
2334
		if (!empty($tmpvalue))
2335
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2336
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow() || $this->GetCodel()) {
2337
			$pfq_rule .= " cbq ( ";
2338
			$tmpvalue = trim($this->GetRed());
2339
			if (!empty($tmpvalue)) {
2340
				$comma = 1;
2341
				$pfq_rule .= " red ";
2342
			}
2343
			$tmpvalue = trim($this->GetCodel());
2344
			if (!empty($tmpvalue)) {
2345
				$comma = 1;
2346
				$pfq_rule .= " codel ";
2347
			}
2348
			$tmpvalue = trim($this->GetRio());
2349
			if (!empty($tmpvalue)) {
2350
				if ($comma)
2351
					$pfq_rule .= " ,";
2352
				$comma = 1;
2353
				$pfq_rule .= " rio ";
2354
			}
2355
			$tmpvalue = trim($this->GetEcn());
2356
			if (!empty($tmpvalue)) {
2357
				if ($comma)
2358
					$pfq_rule .= " ,";
2359
				$comma = 1;
2360
				$pfq_rule .= " ecn ";
2361
			}
2362
			$tmpvalue = trim($this->GetDefault());
2363
			if (!empty($tmpvalue)) {
2364
				if ($comma)
2365
					$pfq_rule .= " ,";
2366
				$comma = 1;
2367
				$pfq_rule .= " default ";
2368
				$default = true;
2369
			}
2370
			$tmpvalue = trim($this->GetBorrow());
2371
			if (!empty($tmpvalue)) {
2372
				if ($comma)
2373
					$pfq_rule .= ", ";
2374
				$pfq_rule .= " borrow ";
2375
			}
2376
			$pfq_rule .= " ) ";
2377
		}
2378
		if (count($this->subqueues)) {
2379
			$i = count($this->subqueues);
2380
			$pfq_rule .= " { ";
2381
			foreach ($this->subqueues as $qkey => $qnone) {
2382
				if ($i > 1) {
2383
					$i--;
2384
					$pfq_rule .= " {$qkey}, ";
2385
				} else
2386
					$pfq_rule .= " {$qkey} ";
2387
			}
2388
			$pfq_rule .= " } \n";
2389
			foreach ($this->subqueues as $q)
2390
				$pfq_rule .= $q->build_rules($default);
2391
		}
2392

    
2393
		$pfq_rule .= " \n";
2394
		return $pfq_rule;
2395
	}
2396

    
2397
	function build_form() {
2398
		$form = parent::build_form();
2399
		$form .= "<tr>";
2400
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
2401
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2402
		if ($this->GetBandwidth() > 0)
2403
			$form .= htmlspecialchars($this->GetBandwidth());
2404
		$form .= "\" />";
2405
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2406
		$form .= "<option value=\"Gb\"";
2407
		if ($this->GetBwscale() == "Gb")
2408
			$form .= " selected=\"selected\"";
2409
		$form .= ">" . gettext("Gbit/s") . "</option>";
2410
		$form .= "<option value=\"Mb\"";
2411
		if ($this->GetBwscale() == "Mb")
2412
			$form .= " selected=\"selected\"";
2413
		$form .= ">" . gettext("Mbit/s") . "</option>";
2414
		$form .= "<option value=\"Kb\"";
2415
		if ($this->GetBwscale() == "Kb")
2416
			$form .= " selected=\"selected\"";
2417
		$form .= ">" . gettext("Kbit/s") . "</option>";
2418
		$form .= "<option value=\"b\"";
2419
		if ($this->GetBwscale() == "b")
2420
			$form .= " selected=\"selected\"";
2421
		$form .= ">" . gettext("Bit/s") . "</option>";
2422
		$form .= "<option value=\"%\"";
2423
		if ($this->GetBwscale() == "%")
2424
			$form .= " selected=\"selected\"";
2425
		$form .= ">%</option>";
2426
		$form .= "</select> <br />";
2427
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
2428
		$form .= "</span></td></tr>";
2429
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
2430
		$form .= "<td class=\"vtable\"><input type=\"checkbox\" id=\"borrow\" name=\"borrow\"";
2431
		if($this->GetBorrow() == "on")
2432
			$form .=  " checked=\"checked\" ";
2433
		$form .= " /> " . gettext("Borrow from other queues when available") . "<br /></td></tr>";
2434

    
2435
		return $form;
2436
	}
2437

    
2438
	function update_altq_queue_data(&$data) {
2439
		$this->ReadConfig($data);
2440
	}
2441

    
2442
	function wconfig() {
2443
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2444
		if (!is_array($cflink))
2445
			$cflink = array();
2446
		$cflink['interface'] = $this->GetInterface();
2447
		$cflink['qlimit'] = trim($this->GetQlimit());
2448
		if (empty($cflink['qlimit']))
2449
			unset($cflink['qlimit']);
2450
		$cflink['priority'] = $this->GetQpriority();
2451
		if (empty($cflink['priority']))
2452
			unset($cflink['priority']);
2453
		$cflink['name'] = $this->GetQname();
2454
		$cflink['description'] = $this->GetDescription();
2455
		if (empty($cflink['description']))
2456
			unset($cflink['description']);
2457
		$cflink['bandwidth'] = $this->GetBandwidth();
2458
		$cflink['bandwidthtype'] = $this->GetBwscale();
2459
		$cflink['enabled'] = trim($this->GetEnabled());
2460
		if (empty($cflink['enabled']))
2461
			unset($cflink['enabled']);
2462
		$cflink['default'] = trim($this->GetDefault());
2463
		if (empty($cflink['default']))
2464
			unset($cflink['default']);
2465
		$cflink['red'] = trim($this->GetRed());
2466
		if (empty($cflink['red']))
2467
			unset($cflink['red']);
2468
		$cflink['rio'] = trim($this->GetRio());
2469
		if (empty($cflink['rio']))
2470
			unset($cflink['rio']);
2471
		$cflink['ecn'] = trim($this->GetEcn());
2472
		if (empty($cflink['ecn']))
2473
			unset($cflink['ecn']);
2474
		$cflink['codel'] = trim($this->GetCodel());
2475
		if (empty($cflink['codel']))
2476
			unset($cflink['codel']);
2477
		$cflink['borrow'] = trim($this->GetBorrow());
2478
		if (empty($cflink['borrow']))
2479
			unset($cflink['borrow']);
2480
	}
2481
}
2482

    
2483
class fairq_queue extends priq_queue {
2484
	var $hogs;
2485
	var $buckets;
2486

    
2487
	function GetBuckets() {
2488
		return $this->buckets;
2489
	}
2490
	function SetBuckets($buckets) {
2491
		$this->buckets = $buckets;
2492
	}
2493
	function GetHogs() {
2494
		return $this->hogs;
2495
	}
2496
	function SetHogs($hogs) {
2497
		$this->hogs = $hogs;
2498
	}
2499
	function CanHaveChildren() {
2500
		return false;
2501
	}
2502

    
2503

    
2504
	function copy_queue($interface, &$cflink) {
2505
		$cflink['interface'] = $interface;
2506
		$cflink['qlimit'] = $this->GetQlimit();
2507
		$cflink['priority'] = $this->GetQpriority();
2508
		$cflink['name'] = $this->GetQname();
2509
		$cflink['description'] = $this->GetDescription();
2510
		$cflink['bandwidth'] = $this->GetBandwidth();
2511
		$cflink['bandwidthtype'] = $this->GetBwscale();
2512
		$cflink['enabled'] = $this->GetEnabled();
2513
		$cflink['default'] = $this->GetDefault();
2514
		$cflink['red'] = $this->GetRed();
2515
		$cflink['rio'] = $this->GetRio();
2516
		$cflink['ecn'] = $this->GetEcn();
2517
		$cflink['buckets'] = $this->GetBuckets();
2518
		$cflink['hogs'] = $this->GetHogs();
2519
	}
2520

    
2521
	/*
2522
	 * Should search even its children
2523
	 */
2524
	function &find_queue($interface, $qname) {
2525
		if ($qname == $this->GetQname())
2526
			return $this;
2527
	}
2528

    
2529
	function find_parentqueue($interface, $qname) { return; }
2530

    
2531
	function delete_queue() {
2532
		unref_on_altq_queue_list($this->GetQname());
2533
		cleanup_queue_from_rules($this->GetQname());
2534
		unset_object_by_reference($this->GetLink());
2535
	}
2536

    
2537
	function validate_input($data, &$input_errors) {
2538
		parent::validate_input($data, $input_errors);
2539

    
2540
		if ($data['priority'] > 255)
2541
				$input_errors[] = gettext("Priority must be an integer between 1 and 255.");
2542
		$reqdfields[] = "bandwidth";
2543
		$reqdfieldsn[] = gettext("Bandwidth");
2544
		$reqdfields[] = "bandwidthtype";
2545
		$reqdfieldsn[] = gettext("Bandwidthtype");
2546

    
2547
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2548

    
2549
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2550
			$input_errors[] = gettext("Bandwidth must be an integer.");
2551

    
2552

    
2553
		if ($data['bandwidth'] < 0)
2554
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2555

    
2556

    
2557
		if ($data['bandwidthtype'] == "%") {
2558
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2559
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2560
		}
2561

    
2562
/*
2563
		$parent =& $this->GetParent();
2564
		switch ($data['bandwidthtype']) {
2565
		case "%":
2566
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2567
		default:
2568
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2569
			break;
2570
		}
2571
		if ($parent->GetAvailableBandwidth() < floatval($myBw))
2572
			$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
2573
*/
2574
	}
2575

    
2576
	function ReadConfig(&$q) {
2577
		parent::ReadConfig($q);
2578
		if (!empty($q['buckets']))
2579
			$this->SetBuckets($q['buckets']);
2580
		else
2581
			$this->SetBuckets("");
2582
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs']))
2583
			$this->SetHogs($q['hogs']);
2584
		else
2585
			$this->SetHogs("");
2586
	}
2587

    
2588
	function build_javascript() {
2589
		return parent::build_javascript();
2590
	}
2591

    
2592
	function build_tree() {
2593
		$tree = " <li><a href=\"firewall_shaper.php?interface=" .
2594
		$this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show";
2595
		$tree .= "\" ";
2596
		$tmpvalue = trim($this->GetDefault());
2597
		if (!empty($tmpvalue))
2598
			$tree .= " class=\"navlnk\"";
2599
		$tree .= " >" . $this->GetQname() . "</a>";
2600
		$tree .= "</li>";
2601
		return $tree;
2602
	}
2603

    
2604
	/* Even this should take children into consideration */
2605
	function build_rules(&$default = false) {
2606
		$pfq_rule = "queue ". $this->qname;
2607
		if ($this->GetInterface())
2608
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2609
		if ($this->GetBandwidth() && $this->GetBwscale())
2610
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2611
		$tmpvalue = trim($this->GetQpriority());
2612
		if (!empty($tmpvalue))
2613
			$pfq_rule .= " priority " . $this->GetQpriority();
2614
		$tmpvalue = trim($this->GetQlimit());
2615
		if (!empty($tmpvalue))
2616
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2617
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio()
2618
			|| $this->GetEcn() || $this->GetBuckets() || $this->GetHogs() || $this->GetCodel()) {
2619
			$pfq_rule .= " fairq ( ";
2620
			$tmpvalue = trim($this->GetRed());
2621
			if (!empty($tmpvalue)) {
2622
				$comma = 1;
2623
				$pfq_rule .= " red ";
2624
			}
2625
			$tmpvalue = trim($this->GetCodel());
2626
			if (!empty($tmpvalue)) {
2627
				$comma = 1;
2628
				$pfq_rule .= " codel ";
2629
			}
2630
			$tmpvalue = trim($this->GetRio());
2631
			if (!empty($tmpvalue)) {
2632
				if ($comma)
2633
					$pfq_rule .= " ,";
2634
				$comma = 1;
2635
				$pfq_rule .= " rio ";
2636
			}
2637
			$tmpvalue = trim($this->GetEcn());
2638
			if (!empty($tmpvalue)) {
2639
				if ($comma)
2640
					$pfq_rule .= " ,";
2641
				$comma = 1;
2642
				$pfq_rule .= " ecn ";
2643
			}
2644
			$tmpvalue = trim($this->GetDefault());
2645
			if (!empty($tmpvalue)) {
2646
				if ($comma)
2647
					$pfq_rule .= " ,";
2648
				$comma = 1;
2649
				$pfq_rule .= " default ";
2650
				$default = true;
2651
			}
2652
			$tmpvalue = trim($this->GetBuckets());
2653
			if (!empty($tmpvalue)) {
2654
				if ($comma)
2655
					$pfq_rule .= ", ";
2656
				$pfq_rule .= " buckets " . $this->GetBuckets() . " ";
2657
			}
2658
			$tmpvalue = trim($this->GetHogs());
2659
			if (!empty($tmpvalue)) {
2660
				if ($comma)
2661
					$pfq_rule .= ", ";
2662
				$pfq_rule .= " hogs " . $this->GetHogs() . " ";
2663
			}
2664
				$pfq_rule .= " ) ";
2665
		}
2666

    
2667
		$pfq_rule .= " \n";
2668
		return $pfq_rule;
2669
	}
2670

    
2671
	function build_form() {
2672
		$form = parent::build_form();
2673
		$form .= "<tr>";
2674
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
2675
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2676
		if ($this->GetBandwidth() > 0)
2677
			$form .= htmlspecialchars($this->GetBandwidth());
2678
		$form .= "\" />";
2679
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2680
		$form .= "<option value=\"Gb\"";
2681
		if ($this->GetBwscale() == "Gb")
2682
			$form .= " selected=\"selected\"";
2683
		$form .= ">" . gettext("Gbit/s") . "</option>";
2684
		$form .= "<option value=\"Mb\"";
2685
		if ($this->GetBwscale() == "Mb")
2686
			$form .= " selected=\"selected\"";
2687
		$form .= ">" . gettext("Mbit/s") . "</option>";
2688
		$form .= "<option value=\"Kb\"";
2689
		if ($this->GetBwscale() == "Kb")
2690
			$form .= " selected=\"selected\"";
2691
		$form .= ">" . gettext("Kbit/s") . "</option>";
2692
		$form .= "<option value=\"b\"";
2693
		if ($this->GetBwscale() == "b")
2694
			$form .= " selected=\"selected\"";
2695
		$form .= ">" . gettext("Bit/s") . "</option>";
2696
		$form .= "<option value=\"%\"";
2697
		if ($this->GetBwscale() == "%")
2698
			$form .= " selected=\"selected\"";
2699
		$form .= ">%</option>";
2700
		$form .= "</select> <br />";
2701
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
2702
		$form .= "</span></td></tr>";
2703
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
2704
		$form .= "<td class=\"vtable\"><table><tr><td>";
2705
		$form .= "<input id=\"buckets\" name=\"buckets\" value=\"";
2706
		$tmpvalue = trim($this->GetBuckets());
2707
		if(!empty($tmpvalue))
2708
			$form .=  $this->GetBuckets();
2709
		$form .= "\" /> " . gettext("Number of buckets available.") . "<br /></td></tr>";
2710
		$form .= "<tr><td class=\"vtable\"><input id=\"hogs\" name=\"hogs\" value=\"";
2711
		$tmpvalue = trim($this->GetHogs());
2712
		if(!empty($tmpvalue))
2713
			$form .=  $this->GetHogs();
2714
		$form .= "\" /> " . gettext("Bandwidth limit for hosts to not saturate link.") . "<br /></td></tr>";
2715
		$form .= "</table></td></tr>";
2716
		return $form;
2717
	}
2718

    
2719
	function update_altq_queue_data(&$data) {
2720
		$this->ReadConfig($data);
2721
	}
2722

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

    
2767

    
2768
/*
2769
 * dummynet(4) wrappers.
2770
 */
2771

    
2772

    
2773
/*
2774
 * List of respective objects!
2775
 */
2776
$dummynet_pipe_list = array();
2777

    
2778
class dummynet_class {
2779
	var $qname;
2780
	var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
2781
	var $qlimit;
2782
	var $description;
2783
	var $qenabled;
2784
	var $link;
2785
	var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
2786
	var $plr;
2787

    
2788
	var $buckets;
2789
	/* mask parameters */
2790
	var $mask;
2791
	var $noerror;
2792

    
2793
	/* Accessor functions */
2794
	function SetLink($link) {
2795
		$this->link = $link;
2796
	}
2797
	function GetLink() {
2798
		return $this->link;
2799
	}
2800
	function GetMask() {
2801
		if (!isset($this->mask["type"]))
2802
			$this->mask["type"] = "none";
2803
		return $this->mask;
2804
	}
2805
	function SetMask($mask) {
2806
		$this->mask = $mask;
2807
	}
2808
	function &GetParent() {
2809
		return $this->qparent;
2810
	}
2811
	function SetParent(&$parent) {
2812
		$this->qparent = &$parent;
2813
	}
2814
	function GetEnabled() {
2815
		return $this->qenabled;
2816
	}
2817
	function SetEnabled($value) {
2818
		$this->qenabled = $value;
2819
	}
2820
	function CanHaveChildren() {
2821
		return false;
2822
	}
2823
	function CanBeDeleted() {
2824
		return true;
2825
	}
2826
	function GetQname() {
2827
		return $this->qname;
2828
	}
2829
	function SetQname($name) {
2830
		$this->qname = trim($name);
2831
	}
2832
	function GetQlimit() {
2833
		return $this->qlimit;
2834
	}
2835
	function SetQlimit($limit) {
2836
		$this->qlimit = $limit;
2837
	}
2838
	function GetDescription() {
2839
		return $this->description;
2840
	}
2841
	function SetDescription($str) {
2842
		$this->description = trim($str);
2843
	}
2844
	function GetFirstime() {
2845
		return $this->firsttime;
2846
	}
2847
	function SetFirsttime($number) {
2848
		$this->firsttime = $number;
2849
	}
2850
	function GetBuckets() {
2851
		return $this->buckets;
2852
	}
2853
	function SetBuckets($buckets) {
2854
		$this->buckets = $buckets;
2855
	}
2856
	function SetNumber($number) {
2857
		$this->qnumber = $number;
2858
	}
2859
	function GetNumber() {
2860
		return $this->qnumber;
2861
	}
2862
	function GetPlr() {
2863
		return $this->plr;
2864
	}
2865
	function SetPlr($plr) {
2866
		$this->plr = $plr;
2867
	}
2868

    
2869
	function build_javascript() {
2870
		$javascript .= "<script type=\"text/javascript\">\n";
2871
		$javascript .= "//<![CDATA[\n";
2872
		$javascript .= "function enable_maskbits(enable_over) {\n";
2873
		$javascript .= "var e = document.getElementById(\"mask\");\n";
2874
		$javascript .= "if ((e.options[e.selectedIndex].text == \"none\") || enable_over) {\n";
2875
		$javascript .= "document.iform.maskbits.disabled = 1;\n";
2876
		$javascript .= "document.iform.maskbits.value = \"\";\n";
2877
		$javascript .= "document.iform.maskbitsv6.disabled = 1;\n";
2878
		$javascript .= "document.iform.maskbitsv6.value = \"\";\n";
2879
		$javascript .= "} else {\n";
2880
		$javascript .= "document.iform.maskbits.disabled = 0;\n";
2881
		$javascript .= "document.iform.maskbitsv6.disabled = 0;\n";
2882
		$javascript .= "}}\n";
2883
		$javascript .= "//]]>\n";
2884
		$javascript .= "</script>\n";
2885
		return $javascript;
2886
	}
2887

    
2888
	function validate_input($data, &$input_errors) {
2889
		$reqdfields[] = "bandwidth";
2890
		$reqdfieldsn[] = gettext("Bandwidth");
2891
		/*$reqdfields[] = "burst";
2892
		$reqdfieldsn[] = gettext("Burst"); */
2893
		$reqdfields[] = "bandwidthtype";
2894
		$reqdfieldsn[] = gettext("Bandwidthtype");
2895
		$reqdfields[] = "newname";
2896
		$reqdfieldsn[] = gettext("Name");
2897

    
2898
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2899

    
2900
		if ($data['plr'] && (!is_numeric($data['plr']) ||
2901
			($data['plr'] < 0) || ($data['plr'] > 1)))
2902
				$input_errors[] = gettext("Plr must be a value between 0 and 1.");
2903
		if ($data['buckets'] && (!is_numeric($data['buckets']) ||
2904
			($data['buckets'] < 16) || ($data['buckets'] > 65535)))
2905
				$input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
2906
		if ($data['qlimit'] && (!is_numeric($data['qlimit'])))
2907
			$input_errors[] = gettext("Queue limit must be an integer");
2908
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname']))
2909
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2910
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name']))
2911
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2912
		if (isset($data['maskbits']) && ($data['maskbits'] <> ""))
2913
			if ((!is_numeric($data['maskbits'])) || ($data['maskbits'] <= 0) || ($data['maskbits'] > 32))
2914
				$input_errors[] = gettext("IPV4 bit mask must be blank or numeric value between 1 and 32.");
2915
		if (isset($data['maskbitsv6']) && ($data['maskbitsv6'] <> ""))
2916
			if ((!is_numeric($data['maskbitsv6'])) || ($data['maskbitsv6'] <= 0) || ($data['maskbitsv6'] > 128))
2917
				$input_errors[] = gettext("IPV6 bit mask must be blank or numeric value between 1 and 128.");
2918
	}
2919

    
2920
	function build_mask_rules(&$pfq_rule) {
2921
		$mask = $this->GetMask();
2922
		if (!empty($mask['type'])) {
2923
			if ($mask['type'] <> 'none')
2924
				$pfq_rule .= " mask";
2925
			switch ($mask['type']) {
2926
			case 'srcaddress':
2927
				if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> ""))
2928
					$pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
2929
				else
2930
					$pfq_rule .= " src-ip6 /128";
2931
				if (!empty($mask['bits']) && ($mask['bits'] <> ""))
2932
					$pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
2933
				else
2934
					$pfq_rule .= " src-ip 0xffffffff";
2935
				break;
2936
			case 'dstaddress':
2937
				if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> ""))
2938
					$pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
2939
				else
2940
					$pfq_rule .= " dst-ip6 /128";
2941
				if (!empty($mask['bits']) && ($mask['bits'] <> ""))
2942
					$pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
2943
				else
2944
					$pfq_rule .= " dst-ip 0xffffffff";
2945
				break;
2946
			default:
2947
				break;
2948
			}
2949
		}
2950
	}
2951

    
2952
}
2953

    
2954
class dnpipe_class extends dummynet_class {
2955
	var $delay;
2956
	var $qbandwidth = array();
2957
	var $qbandwidthtype;
2958

    
2959
		/* This is here to help on form building and building rules/lists */
2960
	var $subqueues = array();
2961

    
2962
	function CanHaveChildren() {
2963
		return true;
2964
	}
2965
	function SetDelay($delay) {
2966
		$this->delay = $delay;
2967
	}
2968
	function GetDelay() {
2969
		return $this->delay;
2970
	}
2971
	function delete_queue() {
2972
		cleanup_dnqueue_from_rules($this->GetQname());
2973
		foreach ($this->subqueues as $q)
2974
			$q->delete_queue();
2975
		unset_dn_object_by_reference($this->GetLink());
2976
		@pfSense_pipe_action("pipe delete " . $this->GetNumber());
2977
	}
2978
	function GetBandwidth() {
2979
		return $this->qbandwidth;
2980
	}
2981
	function SetBandwidth($bandwidth) {
2982
		$this->qbandwidth = $bandwidth;
2983
	}
2984
		function GetBurst() {
2985
				return $this->qburst;
2986
		}
2987
		function SetBurst($burst) {
2988
				$this->qburst = $burst;
2989
		}
2990

    
2991
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
2992

    
2993
		if (!is_array($this->subqueues))
2994
			$this->subqueues = array();
2995

    
2996
		$q =& new dnqueue_class();
2997
		$q->SetLink($path);
2998
		$q->SetEnabled("on");
2999
		$q->SetPipe($this->GetQname());
3000
		$q->SetParent($this);
3001
		$q->ReadConfig($queue);
3002
		$q->validate_input($queue, $input_errors);
3003
		if (count($input_errors)) {
3004
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
3005
			return $q;
3006
		}
3007
		$number = dnqueue_find_nextnumber();
3008
		$q->SetNumber($number);
3009
		$this->subqueues[$q->GetQname()] = &$q;
3010

    
3011
		return $q;
3012
	}
3013

    
3014
	function &get_queue_list(&$q = null) {
3015
		$qlist = array();
3016

    
3017
		$qlist[$this->GetQname()] = $this->GetNumber();
3018
		if (is_array($this->subqueues)) {
3019
			foreach ($this->subqueues as $queue)
3020
				$queue->get_queue_list($qlist);
3021
		}
3022
		return $qlist;
3023
	}
3024

    
3025
	/*
3026
	 * Should search even its children
3027
	 */
3028
	function &find_queue($pipe, $qname) {
3029
		if ($qname == $this->GetQname())
3030
			return $this;
3031
		foreach ($this->subqueues as $q) {
3032
			$result =& $q->find_queue("", $qname);
3033
			if ($result)
3034
				return $result;
3035
		}
3036
	}
3037

    
3038
	function &find_parentqueue($pipe, $qname) {
3039
		return NULL;
3040
	}
3041

    
3042
	function validate_input($data, &$input_errors) {
3043
		parent::validate_input($data, $input_errors);
3044

    
3045
		$schedule = 0;
3046
		$schedulenone = 0;
3047
		$entries = 0;
3048
		/* XXX: Really no better way? */
3049
		for ($i = 0; $i < 2900; $i++) {
3050
			if (!empty($data["bwsched{$i}"])) {
3051
				if ($data["bwsched{$i}"] != "none")
3052
					$schedule++;
3053
				else
3054
					$schedulenone++;
3055
			}
3056
			if (!empty($data["bandwidth{$i}"])) {
3057
				if (!is_numeric($data["bandwidth{$i}"]))
3058
					$input_errors[] = sprintf(gettext("Bandwidth for schedule %s must be an integer."), $data["bwsched{$i}"]);
3059
				else if (($data["burst{$i}"] != "") && (!is_numeric($data["burst{$i}"])))
3060
					$input_errors[] = sprintf(gettext("Burst for schedule %s must be an integer."), $data["bwsched{$i}"]);
3061
				else
3062
					$entries++;
3063
			}
3064
		}
3065
		if ($schedule == 0 && $entries > 1)
3066
			$input_errors[] = gettext("You need to specify a schedule for every additional entry");
3067
		if ($schedulenone > 0 && $entries > 1)
3068
			$input_errors[] = gettext("If more than one bandwidth configured all schedules need to be selected");
3069
		if ($entries == 0)
3070
			$input_errors[] = gettext("At least one bw specification is necessary");
3071
		if ($data['delay'] && (!is_numeric($data['delay'])))
3072
			$input_errors[] = gettext("Delay must be an integer.");
3073
	}
3074

    
3075
	function ReadConfig(&$q) {
3076
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3077
			$this->SetQname($q['newname']);
3078
		} else if (!empty($q['newname'])) {
3079
			$this->SetQname($q['newname']);
3080
		} else {
3081
			$this->SetQname($q['name']);
3082
		}
3083
		$this->SetNumber($q['number']);
3084

    
3085
		if (!empty($_POST)) {
3086
			$bandwidth = array();
3087
			/* XXX: Really no better way? */
3088
			for ($i = 0; $i < 2900; $i++) {
3089
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") {
3090
					$bw = array();
3091
					$bw['bw'] = $q["bandwidth{$i}"];
3092
					$bw['burst'] = $q["burst{$i}"];
3093
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"])
3094
						$bw['bwscale'] = $q["bwtype{$i}"];
3095
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"])
3096
						$bw['bwsched'] = $q["bwsched{$i}"];
3097
					$bandwidth[] = $bw;
3098
				}
3099
			}
3100
			$this->SetBandwidth($bandwidth);
3101
		}
3102

    
3103
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
3104
			$this->SetBandwidth($q['bandwidth']['item']);
3105
			$this->SetBurst($q['burst']['item']);
3106
		}
3107

    
3108
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
3109
			$this->SetQlimit($q['qlimit']);
3110
		else
3111
			$this->SetQlimit("");
3112
		if (isset($q['mask']) && $q['mask'] <> "")
3113
			$masktype = $q['mask'];
3114
		else
3115
			$masktype = "";
3116
		if (isset($q['maskbits']) && $q['maskbits'] <> "")
3117
			$maskbits = $q['maskbits'];
3118
		else
3119
			$maskbits = "";
3120
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "")
3121
			$maskbitsv6 = $q['maskbitsv6'];
3122
		else
3123
			$maskbitsv6 = "";
3124
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3125
		if (isset($q['buckets']) && $q['buckets'] <> "")
3126
			$this->SetBuckets($q['buckets']);
3127
		else
3128
			$this->SetBuckets("");
3129
		if (isset($q['plr']) && $q['plr'] <> "")
3130
			$this->SetPlr($q['plr']);
3131
		else
3132
			$this->SetPlr("");
3133
		if (isset($q['delay']) && $q['delay'] <> "")
3134
			$this->SetDelay($q['delay']);
3135
		else
3136
			$this->SetDelay(0);
3137
		if (isset($q['description']) && $q['description'] <> "")
3138
			$this->SetDescription($q['description']);
3139
		else
3140
			$this->SetDescription("");
3141
		$this->SetEnabled($q['enabled']);
3142

    
3143
	}
3144

    
3145
	function build_tree() {
3146
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&amp;queue=".$this->GetQname() ."&amp;action=show\">";
3147
		$tree .= $this->GetQname() . "</a>";
3148
		if (is_array($this->subqueues)) {
3149
			$tree .= "<ul>";
3150
			foreach ($this->subqueues as $q)  {
3151
				$tree .= $q->build_tree();
3152
			}
3153
			$tree .= "</ul>";
3154
		}
3155
		$tree .= "</li>";
3156

    
3157
		return $tree;
3158
	}
3159

    
3160
	function build_rules() {
3161
		global $config, $time_based_rules;
3162

    
3163
		if ($this->GetEnabled() == "")
3164
			return;
3165

    
3166
		$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
3167
		$found = false;
3168
		$bandwidth = $this->GetBandwidth();
3169
		if (is_array($bandwidth)) {
3170
			foreach ($bandwidth as $bw) {
3171
				if ($bw['bwsched'] != "none") {
3172
					$time_based_rules = true;
3173
					if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3174
						foreach ($config['schedules']['schedule'] as $schedule) {
3175
							if ($bw['bwsched'] == $schedule['name']) {
3176
								if (filter_get_time_based_rule_status($schedule)) {
3177
									$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3178
									if (is_numeric($bw['burst']) && ($bw['burst'] > 0))
3179
										$pfq_rule .= " burst ".trim($bw['burst']);
3180
									$found = true;
3181
									break;
3182
								}
3183
							}
3184
						}
3185
					} else {
3186
						$pfq_rule .= " bw 0";
3187
						$found = true;
3188
						break;
3189
					}
3190
				} else {
3191
					$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3192
					if (is_numeric($bw['burst']) && ($bw['burst'] > 0))
3193
						$pfq_rule .= " burst ".trim($bw['burst']);
3194
					$found = true;
3195
					break;
3196
				}
3197
			}
3198
			if ($found == false)
3199
				$pfq_rule .= " bw 0";
3200
		} else
3201
			$pfq_rule .= " bw 0";
3202

    
3203
		if ($this->GetQlimit())
3204
			$pfq_rule .= " queue " . $this->GetQlimit();
3205
		if ($this->GetPlr())
3206
			$pfq_rule .= " plr " . $this->GetPlr();
3207
		if ($this->GetBuckets())
3208
			$pfq_rule .= " buckets " . $this->GetBuckets();
3209
		if ($this->GetDelay())
3210
			$pfq_rule .= " delay " . $this->GetDelay();
3211
		$this->build_mask_rules($pfq_rule);
3212

    
3213
		$pfq_rule .= "\n";
3214

    
3215
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3216
			foreach ($this->subqueues as $q)
3217
			$pfq_rule .= $q->build_rules();
3218
		}
3219
		$pfq_rule .= " \n";
3220

    
3221
		return $pfq_rule;
3222
	}
3223

    
3224
	function update_dn_data(&$data) {
3225
		$this->ReadConfig($data);
3226
	}
3227

    
3228
	function build_javascript() {
3229
		global $g, $config;
3230

    
3231
		$javasr = parent::build_javascript();
3232

    
3233
		//build list of schedules
3234
		$schedules = "<option value='none'>none</option>";
3235
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3236
			foreach ($config['schedules']['schedule'] as $schedule) {
3237
				if ($schedule['name'] <> "")
3238
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3239
			}
3240
		}
3241
		$bwopt = "";
3242
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw)
3243
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3244

    
3245
		$javasr .= <<<EOD
3246
<script type='text/javascript'>
3247
//<![CDATA[
3248
var addBwRowTo = (function() {
3249
	return (function (tableId) {
3250
	var d, tbody, tr, td;
3251
	d = document;
3252
	tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0);
3253
	tr = d.createElement("tr");
3254
	td = d.createElement("td");
3255
	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 + "' />";
3256
	tr.appendChild(td);
3257
	//td = d.createElement("td");
3258
	//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 + "' />";
3259
	//tr.appendChild(td);
3260
	td = d.createElement("td");
3261
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "' /><select class='formselect' name='bwtype" + totalrows + "'>{$bwopt}</select>";
3262
	tr.appendChild(td);
3263
	td = d.createElement("td");
3264
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "' /><select class='formselect' name='bwsched" + totalrows + "'>{$schedules}</select>";
3265
	tr.appendChild(td);
3266
	td = d.createElement("td");
3267
	td.rowSpan = "1";
3268
	td.innerHTML = '<a onclick="removeBwRow(this); return false;" href="#"><img border="0" src="/themes/{$g['theme']}/images/icons/icon_x.gif" alt="remove" /></a>';
3269
	tr.appendChild(td);
3270
	tbody.appendChild(tr);
3271
	totalrows++;
3272
	});
3273
})();
3274

    
3275
function removeBwRow(el) {
3276
	var cel;
3277
	while (el && el.nodeName.toLowerCase() != "tr")
3278
		el = el.parentNode;
3279
		if (el && el.parentNode) {
3280
			cel = el.getElementsByTagName("td").item(0);
3281
			el.parentNode.removeChild(el);
3282
		}
3283
}
3284
//]]>
3285
</script>
3286

    
3287
EOD;
3288

    
3289
		return $javasr;
3290
	}
3291

    
3292
	function build_form() {
3293
		global $g, $config;
3294

    
3295
		//build list of schedules
3296
		$schedules = array();
3297
		$schedules[] = "none";//leave none to leave rule enabled all the time
3298
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3299
			foreach ($config['schedules']['schedule'] as $schedule) {
3300
				if ($schedule['name'] <> "")
3301
					$schedules[] = $schedule['name'];
3302
			}
3303
		}
3304

    
3305
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
3306
		$form .= gettext("Enable");
3307
		$form .= "</td><td class=\"vncellreq\">";
3308
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
3309
		if ($this->GetEnabled() == "on")
3310
			$form .=  " checked=\"checked\"";
3311
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable limiter and its children") . "</span>";
3312
		$form .= "</td></tr>";
3313
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3314
		$form .= "<td class=\"vncellreq\">";
3315
		$form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
3316
		$form .= $this->GetQname()."\" />";
3317
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
3318
		$form .= $this->GetQname()."\" />";
3319
		if ($this->GetNumber() > 0) {
3320
			$form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
3321
			$form .= $this->GetNumber()."\" />";
3322
		}
3323
		$form .= "</td></tr>";
3324
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth");
3325
		$bandwidth = $this->GetBandwidth();
3326
		$form .= "</td><td class=\"vncellreq\">";
3327
		$form .= "<table id='maintable'>";
3328
		$form .= "<tbody><tr>";
3329
		$form .= "<td width='35%'><div id='onecolumn'>Bandwidth</div></td>";
3330
		//$form .= "<td width='35%'><div id='fifthcolumn'>Burst</div></td>";
3331
		$form .= "<td width='20%'><div id='twocolumn'>Bw type</div></td>";
3332
		$form .= "<td width='35%' ><div id='thirdcolumn'>Schedule</div></td>";
3333
		$form .= "<td width='5%'><div id='fourthcolumn'></div></td>";
3334
		$form .= "</tr>";
3335
		if (is_array($bandwidth)) {
3336
			foreach ($bandwidth as $bwidx => $bw) {
3337
				$form .= "\n<tr><td width='40%'>";
3338
				$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"bandwidth{$bwidx}\" name=\"bandwidth{$bwidx}\" value=\"{$bw['bw']}\" />";
3339
				//$form .= "</td><td width='20%'>";
3340
				//$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"burst{$bwidx}\" name=\"burst{$bwidx}\" value=\"{$bw['burst']}\" />";
3341
				$form .= "</td><td width='20%'>";
3342
				$form .= "<select id=\"bwtype{$bwidx}\" name=\"bwtype{$bwidx}\" class=\"formselect\">";
3343
				foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwsidx => $bwscale) {
3344
					$form .= "<option value=\"{$bwsidx}\"";
3345
					if ($bw['bwscale'] == $bwsidx)
3346
						$form .= " selected=\"selected\"";
3347
					$form .= ">{$bwscale}</option>";
3348
				}
3349
				$form .= "</select>";
3350
				$form .= "</td><td width='35%' >";
3351
				$form .= "<select id=\"bwsched{$bwidx}\" name=\"bwsched{$bwidx}\" class=\"formselect\">";
3352
				foreach ($schedules as $schd) {
3353
					$selected = "";
3354
					if ($bw['bwsched'] == $schd)
3355
						$selected = "selected=\"selected\"";
3356
					$form .= "<option value='{$schd}' {$selected}>{$schd}</option>";
3357
				}
3358
				$form .= "</select>";
3359
				$form .= "</td><td width='5%' >";
3360
				$form .= "<a onclick=\"removeBwRow(this); return false;\" href='#'><img border='0' src='/themes/{$g['theme']}/images/icons/icon_x.gif' alt='remove' /></a>";
3361
				$form .= "</td></tr>";
3362
			}
3363
		}
3364
		$form .= "</tbody></table>";
3365
		$form .= "<a onclick=\"javascript:addBwRowTo('maintable'); return false;\" href='#'>";
3366
		$form .= "<img border='0' src='/themes/{$g['theme']}/images/icons/icon_plus.gif' alt='add' title='" . gettext("add another schedule") . "' /></a>";
3367
		//$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 />";
3368
		$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 />";
3369
		$form .= "</td></tr>";
3370
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
3371
		$form .= "<td class=\"vncellreq\">";
3372
		$form .= "<select name=\"mask\" id=\"mask\" class=\"formselect\" onchange=\"enable_maskbits();\" >";
3373
		$form .= "<option value=\"none\"";
3374
		$mask = $this->GetMask();
3375
		if ($mask['type'] == "none")
3376
			$form .= " selected=\"selected\"";
3377
		$form .= ">none</option>";
3378
		$form .= "<option value=\"srcaddress\"";
3379
		if ($mask['type'] == "srcaddress")
3380
			$form .= " selected=\"selected\"";
3381
		$form .= ">" . gettext("Source addresses") . "</option>";
3382
		$form .= "<option value=\"dstaddress\"";
3383
		if ($mask['type'] == "dstaddress")
3384
			$form .= " selected=\"selected\"";
3385
		$form .= ">" . gettext("Destination addresses") . "</option>";
3386
		$form .= "</select>";
3387
		$form .= "&nbsp;<br />";
3388
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
3389
		      .  "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
3390
		      .  "be created for each source/destination IP address encountered, \n"
3391
		      .  "respectively. This makes it possible to easily specify bandwidth \n"
3392
		      .  "limits per host.") . "</span><br />";
3393
		$form .= "255.255.255.255/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbits\" name=\"maskbits\" value=\"";
3394
		if ($mask['type'] <> "none")
3395
		$form .= $mask['bits'];
3396
		$form .= "\"";
3397
		if ($mask['type'] == "none")
3398
			$form .= " disabled";
3399
		$form .= " />";
3400
		$form .= "&nbsp; IPV4 mask bits (1-32)<br />";
3401
		$form .= "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbitsv6\" name=\"maskbitsv6\" value=\"";
3402
		if ($mask['type'] <> "none")
3403
		$form .= $mask['bitsv6'];
3404
		$form .= "\"";
3405
		if ($mask['type'] == "none")
3406
			$form .= " disabled";
3407
		$form .= " />";
3408
		$form .= "&nbsp; IPV6 mask bits (1-128)<br />";
3409
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
3410
		      .  "leaving the mask bits blank will create one pipe per host. Otherwise specify \n"
3411
		      .  "the number of 'one' bits in the subnet mask used to group multiple hosts \n"
3412
		      .  "per pipe.") . "</span>";
3413
		$form .= "</td></tr>";
3414
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3415
		$form .= "<td class=\"vncellreq\">";
3416
		$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
3417
		$form .= $this->GetDescription();
3418
		$form .= "\" />";
3419
		$form .= "<br /> <span class=\"vexpl\">";
3420
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3421
		$form .= "</td></tr>";
3422
		$form .= "<tr id=\"sprtable4\">";
3423
		$form .= "<td></td>";
3424
		$form .= "<td><div id=\"showadvancedboxspr\">";
3425
		$form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
3426
		$form .= " value=\"" . gettext("Show advanced options") . "\" />";
3427
		$form .= "</p></div></td></tr>";
3428
		$form .= "<tr style=\"display:none\" id=\"sprtable\">";
3429

    
3430
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Delay") . "</td>";
3431
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3432
		$form .= "<input name=\"delay\" type=\"text\" id=\"delay\" size=\"5\" value=\"";
3433
		$form .= $this->GetDelay() . "\" />";
3434
		$form .= "&nbsp;ms<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3435
		      .  "should specify 0 here (or leave the field empty)") . "</span><br />";
3436
		$form .= "</td></tr>";
3437
		$form .= "<tr style=\"display:none\" id=\"sprtable1\">";
3438
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
3439
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3440
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
3441
		$form .= $this->GetPlr() . "\" />";
3442
		$form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3443
		      .  "should specify 0 here (or leave the field empty). "
3444
		      .  "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
3445
		$form .= "</td></tr>";
3446
		$form .= "<tr style=\"display:none\" id=\"sprtable2\">";
3447
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
3448
		$form .= "<td class=\"vncellreq\">";
3449
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
3450
		$form .= $this->GetQlimit() . "\" />";
3451
		$form .= "&nbsp;slots<br />";
3452
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3453
		      .  "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
3454
		      .  "then they are delayed by value specified in the Delay field, and then they "
3455
		      .  "are delivered to their destination.") . "</span>";
3456
		$form .= "</td></tr>";
3457
		$form .= "<tr style=\"display:none\" id=\"sprtable5\">";
3458
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
3459
		$form .= "<td class=\"vncellreq\">";
3460
		$form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
3461
		$form .= $this->GetBuckets() . "\" />";
3462
		$form .= "&nbsp;slots<br />";
3463
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3464
			.  "should leave the field empty. It increases the hash size set.");
3465
		$form .= "</span></td></tr>";
3466

    
3467
		return $form;
3468

    
3469
		}
3470

    
3471
	function wconfig() {
3472
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3473
		if (!is_array($cflink))
3474
			$cflink = array();
3475
		$cflink['name'] = $this->GetQname();
3476
		$cflink['number'] = $this->GetNumber();
3477
		$cflink['qlimit'] = $this->GetQlimit();
3478
		$cflink['plr'] = $this->GetPlr();
3479
		$cflink['description'] = $this->GetDescription();
3480

    
3481
		$bandwidth = $this->GetBandwidth();
3482
		if (is_array($bandwidth)) {
3483
			$cflink['bandwidth'] = array();
3484
			$cflink['bandwidth']['item'] = array();
3485
			foreach ($bandwidth as $bwidx => $bw)
3486
				$cflink['bandwidth']['item'][] = $bw;
3487
		}
3488

    
3489
		$cflink['enabled'] = $this->GetEnabled();
3490
		$cflink['buckets'] = $this->GetBuckets();
3491
		$mask = $this->GetMask();
3492
		$cflink['mask'] = $mask['type'];
3493
		$cflink['maskbits'] = $mask['bits'];
3494
		$cflink['maskbitsv6'] = $mask['bitsv6'];
3495
		$cflink['delay'] = $this->GetDelay();
3496
	}
3497

    
3498
}
3499

    
3500
class dnqueue_class extends dummynet_class {
3501
	var $pipeparent;
3502
	var $weight;
3503

    
3504
	function GetWeight() {
3505
		return $this->weight;
3506
	}
3507
	function SetWeight($weight) {
3508
		$this->weight = $weight;
3509
	}
3510
	function GetPipe() {
3511
		return $this->pipeparent;
3512
	}
3513
	function SetPipe($pipe) {
3514
		$this->pipeparent = $pipe;
3515
	}
3516

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

    
3520
	function delete_queue() {
3521
		cleanup_dnqueue_from_rules($this->GetQname());
3522
		unset_dn_object_by_reference($this->GetLink());
3523
		@pfSense_pipe_action("queue delete " . $this->GetNumber());
3524
	}
3525

    
3526
	function validate_input($data, &$input_errors) {
3527
		parent::validate_input($data, $input_errors);
3528

    
3529
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3530
			($data['weight'] < 1 && $data['weight'] > 100)))
3531
			$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
3532
	}
3533

    
3534
	/*
3535
	 * Should search even its children
3536
	 */
3537
	function &find_queue($pipe, $qname) {
3538
		if ($qname == $this->GetQname())
3539
			return $this;
3540
		else
3541
			return NULL;
3542
	}
3543

    
3544
	function &find_parentqueue($pipe, $qname) {
3545
		return $this->qparent;
3546
	}
3547

    
3548
	function &get_queue_list(&$qlist) {
3549
		if ($this->GetEnabled() == "")
3550
			return;
3551
		$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3552
	}
3553

    
3554
	function ReadConfig(&$q) {
3555
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3556
			$this->SetQname($q['newname']);
3557
		} else if (!empty($q['newname'])) {
3558
			$this->SetQname($q['newname']);
3559
		} else {
3560
			$this->SetQname($q['name']);
3561
		}
3562
		$this->SetNumber($q['number']);
3563
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
3564
			$this->SetQlimit($q['qlimit']);
3565
		else
3566
			$this->SetQlimit("");
3567
		if (isset($q['mask']) && $q['mask'] <> "")
3568
			$masktype = $q['mask'];
3569
		else
3570
			$masktype = "";
3571
		if (isset($q['maskbits']) && $q['maskbits'] <> "")
3572
			$maskbits = $q['maskbits'];
3573
		else
3574
			$maskbits = "";
3575
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "")
3576
			$maskbitsv6 = $q['maskbitsv6'];
3577
		else
3578
			$maskbitsv6 = "";
3579
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3580
		if (isset($q['buckets']) && $q['buckets'] <> "")
3581
			$this->SetBuckets($q['buckets']);
3582
		else
3583
			$this->SetBuckets("");
3584
		if (isset($q['plr']) && $q['plr'] <> "")
3585
			$this->SetPlr($q['plr']);
3586
		else
3587
			$this->SetPlr("");
3588
		if (isset($q['weight']) && $q['weight'] <> "")
3589
			$this->SetWeight($q['weight']);
3590
		else
3591
			$this->SetWeight("");
3592
		if (isset($q['description']) && $q['description'] <> "")
3593
			$this->SetDescription($q['description']);
3594
		else
3595
			$this->SetDescription("");
3596
		$this->SetEnabled($q['enabled']);
3597
	}
3598

    
3599
	function build_tree() {
3600
		$parent =& $this->GetParent();
3601
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">";
3602
		$tree .= $this->GetQname() . "</a>";
3603
		$tree .= "</li>";
3604

    
3605
		return $tree;
3606
	}
3607

    
3608
	function build_rules() {
3609
		if ($this->GetEnabled() == "")
3610
			return;
3611

    
3612
		$parent =& $this->GetParent();
3613
		$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
3614
		if ($this->GetQlimit())
3615
			$pfq_rule .= " queue " . $this->GetQlimit();
3616
		if ($this->GetWeight())
3617
			$pfq_rule .= " weight " . $this->GetWeight();
3618
		if ($this->GetBuckets())
3619
			$pfq_rule .= " buckets " . $this->GetBuckets();
3620
		$this->build_mask_rules($pfq_rule);
3621
		$pfq_rule .= "\n";
3622

    
3623
		return $pfq_rule;
3624
	}
3625

    
3626
	function build_javascript() {
3627
		return parent::build_javascript();
3628
	}
3629

    
3630

    
3631
	function build_form() {
3632
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
3633
		$form .= gettext("Enable/Disable");
3634
		$form .= "</td><td class=\"vncellreq\">";
3635
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
3636
		if ($this->GetEnabled() == "on")
3637
			$form .=  " checked=\"checked\"";
3638
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue") . "</span>";
3639
		$form .= "</td></tr>";
3640
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3641
		$form .= "<td class=\"vncellreq\">";
3642
		$form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
3643
		$form .= $this->GetQname()."\" />";
3644
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
3645
		$form .= $this->GetQname()."\" />";
3646
		if ($this->GetNumber() > 0) {
3647
			$form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
3648
			$form .= $this->GetNumber()."\" />";
3649
		}
3650
		$form .= "</td></tr>";
3651
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
3652
		$form .= "<td class=\"vncellreq\">";
3653
		$form .= "<select name=\"mask\" id=\"mask\" class=\"formselect\" onchange=\"enable_maskbits();\" >";
3654
		$form .= "<option value=\"none\"";
3655
		$mask = $this->GetMask();
3656
		if ($mask['type'] == "none")
3657
			$form .= " selected=\"selected\"";
3658
		$form .= ">" . gettext("none") . "</option>";
3659
		$form .= "<option value=\"srcaddress\"";
3660
		if ($mask['type'] == "srcaddress")
3661
			$form .= " selected=\"selected\"";
3662
		$form .= ">" . gettext("Source addresses") . "</option>";
3663
		$form .= "<option value=\"dstaddress\"";
3664
		if ($mask['type'] == "dstaddress")
3665
			$form .= " selected=\"selected\"";
3666
		$form .= ">" . gettext("Destination addresses") . "</option>";
3667
		$form .= "</select>";
3668
		$form .= "&nbsp;slots<br />";
3669
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
3670
			.  "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
3671
			.  "be created for each source/destination IP address encountered, \n"
3672
			.  "respectively. This makes it possible to easily specify bandwidth \n"
3673
			.  "limits per host.") . "</span><br />";
3674
		$form .= "255.255.255.255/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbits\" name=\"maskbits\" value=\"";
3675
		if ($mask['type'] <> "none")
3676
			$form .= $mask['bits'];
3677
		$form .= "\"";
3678
		if ($mask['type'] == "none")
3679
			$form .= " disabled";
3680
		$form .= " />";
3681
		$form .= "&nbsp; IPV4 mask bits (1-32)<br />";
3682
		$form .= "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/&nbsp;<input type=\"text\" class=\"formfld unknown\" size=\"2\" id=\"maskbitsv6\" name=\"maskbitsv6\" value=\"";
3683
		if ($mask['type'] <> "none")
3684
			$form .= $mask['bitsv6'];
3685
		$form .= "\"";
3686
		if ($mask['type'] == "none")
3687
			$form .= " disabled";
3688
		$form .= " />";
3689
		$form .= "&nbsp; IPV6 mask bits (1-128)<br />";
3690
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' slots is chosen, \n"
3691
			.  "leaving the mask bits blank will create one pipe per host. Otherwise specify \n"
3692
			.  "the number of 'one' bits in the subnet mask used to group multiple hosts \n"
3693
			.  "per queue.") . "</span>";
3694
		$form .= "</td></tr>";
3695
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3696
		$form .= "<td class=\"vncellreq\">";
3697
		$form .= "<input type=\"text\" id=\"description\" class=\"formfld unknown\" size=\"40\" name=\"description\" value=\"";
3698
		$form .= $this->GetDescription();
3699
		$form .= "\" />";
3700
		$form .= "<br /> <span class=\"vexpl\">";
3701
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3702
		$form .= "</td></tr>";
3703
		$form .= "<tr id=\"sprtable4\">";
3704
		$form .= "<td></td>";
3705
		$form .= "<td><div id=\"showadvancedboxspr\">";
3706
		$form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
3707
		$form .= " value=\"" . gettext("Show advanced options") . "\" />";
3708
		$form .= "</p></div></td></tr>";
3709
		$form .= "<tr style=\"display:none\" id=\"sprtable\">";
3710
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Weight") . "</td>";
3711
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3712
		$form .= "<input name=\"weight\" type=\"text\" id=\"weight\" size=\"5\" value=\"";
3713
		$form .= $this->GetWeight() . "\" />";
3714
		$form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: For queues under the same parent "
3715
			.  "this specifies the share that a queue gets(values range from 1 to 100, you can leave it blank otherwise)") . "</span>";
3716
		$form .= "</td></tr>";
3717
		$form .= "<tr style=\"display:none\" id=\"sprtable1\">";
3718
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
3719
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3720
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
3721
		$form .= $this->GetPlr() . "\" />";
3722
		$form .= "&nbsp;<br /> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3723
			.  "should specify 0 here (or leave the field empty). "
3724
			.  "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
3725
		$form .= "</td></tr>";
3726
		$form .= "<tr style=\"display:none\" id=\"sprtable2\">";
3727
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
3728
		$form .= "<td class=\"vncellreq\">";
3729
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
3730
		$form .= $this->GetQlimit() . "\" />";
3731
		$form .= "&nbsp;slots<br />";
3732
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3733
			.  "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
3734
			.  "then they are delayed by value specified in the Delay field, and then they "
3735
			.  "are delivered to their destination.") . "</span>";
3736
		$form .= "</td></tr>";
3737
		$form .= "<tr style=\"display:none\" id=\"sprtable5\">";
3738
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
3739
		$form .= "<td class=\"vncellreq\">";
3740
		$form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
3741
		$form .= $this->GetBuckets() . "\" />";
3742
		$form .= "&nbsp;" . gettext("slots") . "<br />";
3743
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3744
			.  "should leave the field empty. It increases the hash size set.");
3745
		$form .= "</span></td></tr>";
3746

    
3747
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3748
		$form .= " value=\"" . $this->GetPipe() . "\" />";
3749

    
3750
		return $form;
3751

    
3752
	}
3753

    
3754
	function update_dn_data(&$data) {
3755
		$this->ReadConfig($data);
3756
	}
3757

    
3758
	function wconfig() {
3759
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3760
		if (!is_array($cflink))
3761
			$cflink = array();
3762
		$cflink['name'] = $this->GetQname();
3763
		$cflink['number'] = $this->GetNumber();
3764
		$cflink['qlimit'] = $this->GetQlimit();
3765
		$cflink['description'] = $this->GetDescription();
3766
		$cflink['weight'] = $this->GetWeight();
3767
		$cflink['enabled'] = $this->GetEnabled();
3768
		$cflink['buckets'] = $this->GetBuckets();
3769
		$mask = $this->GetMask();
3770
		$cflink['mask'] = $mask['type'];
3771
		$cflink['maskbits'] = $mask['bits'];
3772
		$cflink['maskbitsv6'] = $mask['bitsv6'];
3773
	}
3774
}
3775

    
3776
// List of layer7 objects
3777
$layer7_rules_list = array();
3778

    
3779
class layer7 {
3780

    
3781
	var $rname; //alias
3782
	var $rdescription; //alias description
3783
	var $rport; //divert port
3784
	var $renabled; //rule enabled
3785
	var $rsets = array(); //array of l7 associations
3786

    
3787
	// Auxiliary functions
3788

    
3789
	function GetRName() {
3790
		return $this->rname;
3791
	}
3792
	function SetRName($rname) {
3793
		$this->rname = $rname;
3794
	}
3795
	function GetRDescription() {
3796
		return $this->rdescription;
3797
	}
3798
	function SetRDescription($rdescription) {
3799
		$this->rdescription = $rdescription;
3800
	}
3801
	function GetRPort() {
3802
		return $this->rport;
3803
	}
3804
	function SetRPort($rport) {
3805
		$this->rport = $rport;
3806
	}
3807
	function GetREnabled() {
3808
		return $this->renabled;
3809
	}
3810
	function SetREnabled($value) {
3811
		$this->renabled = $value;
3812
	}
3813
	function GetRl7() {
3814
		return $this->rsets;
3815
	}
3816
	function SetRl7($rsets) {
3817
		$this->rsets = $rsets;
3818
	}
3819

    
3820
	//Add a tuple (rule,sctructure,element) to the $rsets
3821

    
3822
	function add_rule($l7set) {
3823
		$this->rsets[] = $l7set;
3824
	}
3825

    
3826
	// Build the layer7 rules
3827
	function build_l7_rules() {
3828
		if($this->GetREnabled() == "") {
3829
			return;
3830
		}
3831
		//$l7rules = "#" . $this->rdescription . "\n";
3832
		foreach ($this->rsets as $rl7) {
3833
			$l7rules .= $rl7->build_rules();
3834
		}
3835
		return $l7rules;
3836
	}
3837

    
3838
	// Read the config from array
3839
	function ReadConfig(&$qname, &$q) {
3840
		$this->SetRName($qname);
3841
		$this->SetREnabled($q['enabled']);
3842
		$this->SetRPort($q['divert_port']);
3843
		if(isset($q['description']) && $q['description'] <> "")
3844
			$this->SetRDescription($q['description']);
3845
		$rsets = $q['l7rules'];
3846
		//Put individual rules in the array
3847
		if(is_array($rsets)) {
3848
			$this->rsets = array(); // XXX: ugly hack
3849
			foreach($rsets as $l7r) {
3850
				$l7obj = new l7rule();
3851
				$l7obj->SetRProtocol($l7r['protocol']);
3852
				$l7obj->SetRStructure($l7r['structure']);
3853
				$l7obj->SetRBehaviour($l7r['behaviour']);
3854
				$this->add_rule($l7obj);
3855
			}
3856
		}
3857
	}
3858

    
3859
	//Generate a random port for the divert socket
3860
	function gen_divert_port() {
3861
		$dports = get_divert_ports(); //array of used ports
3862
		$divert_port = 1; // Initialize
3863
		while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) {
3864
			$divert_port = rand(40000, 60000);
3865
		}
3866
		return $divert_port;
3867
	}
3868

    
3869
	//Helps building the left tree
3870
	function build_tree() {
3871
		$tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&amp;action=show\">";
3872
		$tree .= $this->GetRName() . "</a>";
3873
		$tree .= "</li>";
3874

    
3875
		return $tree;
3876
	}
3877

    
3878
	function build_form() {
3879
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br />";
3880
		$form .= gettext("Enable/Disable");
3881
		$form .= "</td><td class=\"vncellreq\">";
3882
		$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\" ";
3883
		if ($this->GetREnabled() == "on") {
3884
			$form .=  "checked=\"checked\"";
3885
		}
3886
		$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable layer7 Container") . "</span>";
3887
		$form .= "</td></tr>";
3888
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br /><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3889
		$form .= "<td class=\"vncellreq\">";
3890
		$form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
3891
		$form .= $this->GetRName()."\" />";
3892
		$form .= "</td></tr>";
3893
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3894
		$form .= "<td class=\"vncellreq\">";
3895
		$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
3896
		$form .= $this->GetRDescription();
3897
		$form .= "\" />";
3898
		$form .= "<br /> <span class=\"vexpl\">";
3899
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3900
		$form .= "</td></tr>";
3901

    
3902
		return $form;
3903
	}
3904

    
3905
	//Write the setting to the $config array
3906
	function wconfig() {
3907
		global $config;
3908

    
3909
		if(!is_array($config['l7shaper']['container'])) {
3910
			$config['l7shaper']['container'] = array();
3911
		}
3912
		//
3913
		$cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
3914
		// Test if this rule does exists already
3915
		if(!$cflink) {
3916
			$cflink =& $config['l7shaper']['container'][];
3917
		}
3918
		$cflink['name'] = $this->GetRName();
3919
		$cflink['enabled'] = $this->GetREnabled();
3920
		$cflink['description'] = $this->GetRDescription();
3921
		$cflink['divert_port'] = $this->GetRPort();
3922

    
3923
		//Destroy previously existent rules
3924
		if(is_array($cflink['rules'])) {
3925
			unset($cflink['l7rules']);
3926
		}
3927

    
3928
		$cflink['l7rules'] = array();
3929

    
3930
		$i = 0;
3931
		foreach($this->rsets as $rulel7) {
3932
			$cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
3933
			$cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
3934
			$cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
3935
			$i++;
3936
		}
3937
	}
3938

    
3939
	//This function is necessary to help producing the overload options for keep state
3940
	function get_unique_structures() {
3941

    
3942
		$unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
3943
		foreach($this->rsets as $l7rule) {
3944
			if($l7rule->GetRStructure() == "action")
3945
				$unique_structures['action'] = true;
3946
			else if($l7rule->GetRStructure() == "limiter")
3947
				$unique_structures['dummynet'] = true;
3948
			else
3949
				$unique_structures['altq'] = true;
3950
		}
3951
		//Delete non used structures so we don't have to check this in filter.inc
3952
		foreach($unique_structures as $key => $value)
3953
			if(!$value)
3954
				unset($unique_structures[$key]);
3955
		return $unique_structures;
3956
	}
3957

    
3958
	function validate_input($data, &$input_errors) {
3959
		$reqdfields[] = "container";
3960
		$reqdfieldsn[] = gettext("Name");
3961

    
3962
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3963

    
3964
		if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container']))
3965
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3966
	}
3967

    
3968
	function delete_l7c() {
3969
		mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
3970
		unset_l7_object_by_reference($this->GetRName());
3971
		cleanup_l7_from_rules($this->GetRName());
3972
	}
3973
}
3974

    
3975
class l7rule {
3976

    
3977
	var $rprotocol; //protocol
3978
	var $rstructure; //action, limiter, queue
3979
	var $rbehaviour; //allow, block, queue_name, pipe_number ...
3980

    
3981
	//Auxiliary Functions
3982

    
3983
	function GetRProtocol() {
3984
		return $this->rprotocol;
3985
	}
3986
	function SetRProtocol($rprotocol) {
3987
		$this->rprotocol = $rprotocol;
3988
	}
3989
	function GetRStructure() {
3990
		return $this->rstructure;
3991
	}
3992
	function SetRStructure($rstructure) {
3993
		$this->rstructure = $rstructure;
3994
	}
3995
	function GetRBehaviour() {
3996
		return $this->rbehaviour;
3997
	}
3998
	function SetRBehaviour($rbehaviour) {
3999
		$this->rbehaviour = $rbehaviour;
4000
	}
4001

    
4002
	//XXX Do we need to test any particularity for AltQ queues?
4003
	function build_rules() {
4004
		global $dummynet_pipe_list;
4005
		switch ($this->GetRStructure()) {
4006
		case "limiter":
4007
			read_dummynet_config();
4008
			$dn_list =& get_unique_dnqueue_list();
4009
			$found = false;
4010
			if(is_array($dn_list)) {
4011
				foreach($dn_list as $key => $value) {
4012
					if($key == $this->GetRBehaviour()) {
4013
						if($value[0] == "?")
4014
							$l7rule = $this->GetRProtocol() . " = dnqueue " . substr($value, 1) . "\n";
4015
						else
4016
							$l7rule = $this->GetRProtocol() . " = dnpipe " . $value . "\n";
4017
						$found = true;
4018
					}
4019
					if($found)
4020
						break;
4021
				}
4022
			}
4023
			break;
4024
		default: //This is for action and for altq
4025
			$l7rule = $this->GetRProtocol() . " = " . $this->GetRStructure() . " " . $this->GetRBehaviour() . "\n";
4026
			break;
4027
		}
4028
		return $l7rule;
4029
	}
4030
}
4031

    
4032
/*
4033
 * This function allows to return an array with all the used divert socket ports
4034
 */
4035
function get_divert_ports() {
4036
	global $layer7_rules_list;
4037
	$dports = array();
4038

    
4039
	foreach($layer7_rules_list as $l7r)
4040
		$dports[] = $l7r->GetRPort();
4041

    
4042
	return $dports;
4043
}
4044

    
4045
function &get_l7c_reference_to_me_in_config(&$name) {
4046
	global $config;
4047

    
4048
	$ptr = NULL;
4049

    
4050
	if(is_array($config['l7shaper']['container'])) {
4051
		foreach($config['l7shaper']['container'] as $key => $value) {
4052
			if($value['name'] == $name)
4053
				$ptr =& $config['l7shaper']['container'][$key];
4054
		}
4055
	}
4056
	return $ptr;
4057
	// $ptr can be null. has to be checked later
4058
}
4059

    
4060
function unset_l7_object_by_reference(&$name) {
4061
	global $config;
4062

    
4063
	if(is_array($config['l7shaper']['container'])) {
4064
		foreach($config['l7shaper']['container'] as $key => $value) {
4065
			if($value['name'] == $name) {
4066
				unset($config['l7shaper']['container'][$key]['l7rules']);
4067
				unset($config['l7shaper']['container'][$key]);
4068
				break;
4069
			}
4070
		}
4071
	}
4072
}
4073

    
4074
function read_layer7_config() {
4075
	global $layer7_rules_list, $config;
4076

    
4077
	if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container'])) {
4078
		$layer7_rules_list = array();
4079
		return;
4080
	}
4081

    
4082
	$l7cs = &$config['l7shaper']['container'];
4083

    
4084
	$layer7_rules_list = array();
4085

    
4086
	foreach ($l7cs as $conf) {
4087
		if (empty($conf['name']))
4088
			continue; /* XXX: grrrrrr at php */
4089
		$root =& new layer7();
4090
		$root->ReadConfig($conf['name'],$conf);
4091
		$layer7_rules_list[$root->GetRName()] = &$root;
4092
	}
4093
}
4094

    
4095
function update_layer7_custom_patterns() {
4096
	global $config;
4097

    
4098
	if (!is_array($config['l7shaper']['custom_pat']))
4099
		return;
4100

    
4101
	foreach ($config['l7shaper']['custom_pat'] as $filename => $filecontent)
4102
		if (!file_exists("/usr/local/share/protocols/" . $filename))
4103
			@file_put_contents("/usr/local/share/protocols/" . $filename, base64_decode($filecontent));
4104
}
4105

    
4106
function generate_layer7_files() {
4107
	global $layer7_rules_list, $g;
4108

    
4109
	read_layer7_config();
4110

    
4111
	if (!empty($layer7_rules_list)) {
4112
		if (!is_module_loaded("ipdivert.ko"))
4113
			mwexec("/sbin/kldload ipdivert.ko");
4114

    
4115
		array_map('unlink', glob("{$g['tmp_path']}/*.l7"));
4116
	}
4117

    
4118
	update_layer7_custom_patterns();
4119

    
4120
	foreach($layer7_rules_list as $l7rules) {
4121
		if($l7rules->GetREnabled()) {
4122
			$filename = $l7rules->GetRName() . ".l7";
4123
			$path = "{$g['tmp_path']}/" . $filename;
4124

    
4125
			$rules = $l7rules->build_l7_rules();
4126

    
4127
			$fp = fopen($path,'w');
4128
			fwrite($fp,$rules);
4129
			fclose($fp);
4130
		}
4131
	}
4132
}
4133

    
4134
function layer7_start_l7daemon() {
4135
	global $layer7_rules_list, $g;
4136

    
4137
	/*
4138
	 * XXX: ermal - Needed ?!
4139
	 * read_layer7_config();
4140
	 */
4141

    
4142
	foreach($layer7_rules_list as $l7rules) {
4143
		if($l7rules->GetREnabled()) {
4144
			$filename = $l7rules->GetRName() . ".l7";
4145
			$path = "{$g['tmp_path']}/" . $filename;
4146

    
4147
			unset($l7pid);
4148
			/* Only reread the configuration rather than restart to avoid losing information. */
4149
			exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid);
4150
			if (count($l7pid) > 0) {
4151
				log_error(sprintf(gettext("Sending HUP signal to %s"), $l7pid[0]));
4152
				mwexec("/bin/kill -HUP {$l7pid[0]}");
4153
			} else {
4154
				// XXX: Hardcoded number of packets to garbage collect and queue length..
4155
				$ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 8 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
4156
				mwexec_bg($ipfw_classifyd_init);
4157
			}
4158
		}
4159
	}
4160
}
4161

    
4162
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
4163
function generate_protocols_array() {
4164

    
4165
	update_layer7_custom_patterns();
4166

    
4167
	$protocols = return_dir_as_array("/usr/local/share/protocols");
4168
	$protocols_new = array();
4169
	if(is_array($protocols)) {
4170
		foreach($protocols as $key => $proto) {
4171
			if (strstr($proto, ".pat"))
4172
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
4173
		}
4174
		sort($protocols_new);
4175
	}
4176
	return $protocols_new;
4177
}
4178

    
4179
function get_l7_unique_list() {
4180
	global $layer7_rules_list;
4181

    
4182
	$l7list = array();
4183
	if(is_array($layer7_rules_list))
4184
		foreach($layer7_rules_list as $l7c)
4185
			if($l7c->GetREnabled())
4186
				$l7list[] = $l7c->GetRName();
4187

    
4188
	return $l7list;
4189
}
4190

    
4191
// Disable a removed l7 container from the filter
4192
function cleanup_l7_from_rules(&$name) {
4193
	global $config;
4194

    
4195
	if(is_array($config['filter']['rule']))
4196
		foreach ($config['filter']['rule'] as $key => $rule) {
4197
			if ($rule['l7container'] == $name)
4198
				unset($config['filter']['rule'][$key]['l7container']);
4199
		}
4200
}
4201

    
4202
function get_dummynet_name_list() {
4203

    
4204
	$dn_name_list =& get_unique_dnqueue_list();
4205
	$dn_name = array();
4206
	if(is_array($dn_name_list))
4207
		foreach($dn_name_list as $key => $value)
4208
			$dn_name[] = $key;
4209

    
4210
	return $dn_name;
4211

    
4212
}
4213

    
4214
function get_altq_name_list() {
4215
	$altq_name_list =& get_unique_queue_list();
4216
	$altq_name = array();
4217
	if(is_array($altq_name_list))
4218
		foreach($altq_name_list as $key => $aqobj)
4219
			$altq_name[] = $key;
4220

    
4221
	return $altq_name;
4222
}
4223

    
4224
/*
4225
 * XXX: TODO Make a class shaper to hide all these function
4226
 * from the global namespace.
4227
 */
4228

    
4229
/*
4230
 * This is a layer violation but for now there is no way
4231
 * i can find to properly do this with PHP.
4232
 */
4233
function altq_get_default_queue($interface) {
4234
	global $altq_list_queues;
4235

    
4236
	$altq_tmp = $altq_list_queues[$interface];
4237
	if ($altq_tmp)
4238
		return $altq_tmp->GetDefaultQueuePresent();
4239
	else
4240
		return false;
4241
}
4242

    
4243
function altq_check_default_queues() {
4244
	global $altq_list_queues;
4245

    
4246
	$count = 0;
4247
	if (is_array($altq_list_queues)) {
4248
		foreach($altq_list_queues as $altq) {
4249
			if ($altq->GetDefaultQueuePresent())
4250
				$count++;
4251
		}
4252
	}
4253
	else  $count++;
4254

    
4255
	return 0;
4256
}
4257

    
4258
function &get_unique_queue_list() {
4259
	global $altq_list_queues;
4260

    
4261
	$qlist = array();
4262
	if (is_array($altq_list_queues)) {
4263
		foreach ($altq_list_queues as $altq) {
4264
			if ($altq->GetEnabled() == "")
4265
				continue;
4266
			$tmplist =& $altq->get_queue_list();
4267
			foreach ($tmplist as $qname => $link) {
4268
				if ($link->GetEnabled() <> "")
4269
					$qlist[$qname] = $link;
4270
			}
4271
		}
4272
	}
4273
	return $qlist;
4274
}
4275

    
4276
function &get_unique_dnqueue_list() {
4277
	global $dummynet_pipe_list;
4278

    
4279
	$qlist = array();
4280
	if (is_array($dummynet_pipe_list)) {
4281
		foreach ($dummynet_pipe_list as $dn) {
4282
			if ($dn->GetEnabled() == "")
4283
				continue;
4284
			$tmplist =& $dn->get_queue_list();
4285
			foreach ($tmplist as $qname => $link) {
4286
				$qlist[$qname] = $link;
4287
			}
4288
		}
4289
	}
4290
	return $qlist;
4291
}
4292

    
4293
function ref_on_altq_queue_list($parent, $qname) {
4294
	if (isset($GLOBALS['queue_list'][$qname]))
4295
		$GLOBALS['queue_list'][$qname]++;
4296
	else
4297
		$GLOBALS['queue_list'][$qname] = 1;
4298

    
4299
	unref_on_altq_queue_list($parent);
4300
}
4301

    
4302
function unref_on_altq_queue_list($qname) {
4303
	$GLOBALS['queue_list'][$qname]--;
4304
	if ($GLOBALS['queue_list'][$qname] <= 1)
4305
		unset($GLOBALS['queue_list'][$qname]);
4306
}
4307

    
4308
function read_altq_config() {
4309
	global $altq_list_queues, $config;
4310
	$path = array();
4311

    
4312
	if (!is_array($config['shaper']))
4313
		$config['shaper'] = array();
4314
	if (!is_array($config['shaper']['queue']))
4315
		$config['shaper']['queue'] = array();
4316
	$a_int = &$config['shaper']['queue'];
4317

    
4318
	$altq_list_queues = array();
4319

    
4320
	if (!is_array($config['shaper']['queue']))
4321
		return;
4322

    
4323
	foreach ($a_int as $key => $conf) {
4324
		$int = $conf['interface'];
4325
		$root =& new altq_root_queue();
4326
		$root->SetInterface($int);
4327
		$altq_list_queues[$root->GetInterface()] = &$root;
4328
		$root->ReadConfig($conf);
4329
		array_push($path, $key);
4330
		$root->SetLink($path);
4331
		if (is_array($conf['queue'])) {
4332
			foreach ($conf['queue'] as $key1 => $q) {
4333
				array_push($path, $key1);
4334
				/*
4335
				 * XXX: we completely ignore errors here but anyway we must have
4336
				 *	checked them before so no harm should be come from this.
4337
				 */
4338
				$root->add_queue($root->GetInterface(), $q, $path, $input_errors);
4339
				array_pop($path);
4340
			}
4341
		}
4342
		array_pop($path);
4343
	}
4344
}
4345

    
4346
function read_dummynet_config() {
4347
	global $dummynet_pipe_list, $config;
4348
	$path = array();
4349

    
4350
	if (!is_array($config['dnshaper']))
4351
		$config['dnshaper'] = array();
4352
	if (!is_array($config['dnshaper']['queue']))
4353
		$config['dnshaper']['queue'] = array();
4354
	$a_int = &$config['dnshaper']['queue'];
4355

    
4356
	$dummynet_pipe_list = array();
4357

    
4358
	if (!is_array($config['dnshaper']['queue'])
4359
		|| !count($config['dnshaper']['queue']))
4360
		return;
4361

    
4362
	foreach ($a_int as $key => $conf) {
4363
		if (empty($conf['name']))
4364
			continue; /* XXX: grrrrrr at php */
4365
		$root =& new dnpipe_class();
4366
		$root->ReadConfig($conf);
4367
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4368
		array_push($path, $key);
4369
		$root->SetLink($path);
4370
		if (is_array($conf['queue'])) {
4371
			foreach ($conf['queue'] as $key1 => $q) {
4372
				array_push($path, $key1);
4373
				/*
4374
				 * XXX: we completely ignore errors here but anyway we must have
4375
				 *	checked them before so no harm should be come from this.
4376
				 */
4377
				$root->add_queue($root->GetQname(), $q, $path, $input_errors);
4378
				array_pop($path);
4379
			}
4380
		}
4381
		array_pop($path);
4382
	}
4383
}
4384

    
4385
function get_interface_list_to_show() {
4386
	global $altq_list_queues, $config;
4387
	global $shaperIFlist;
4388

    
4389
	$tree = "";
4390
	foreach ($shaperIFlist as $shif => $shDescr) {
4391
		if ($altq_list_queues[$shif]) {
4392
			continue;
4393
		} else  {
4394
			if (!is_altq_capable(get_real_interface($shif)))
4395
				continue;
4396
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4397
		}
4398
	}
4399

    
4400
	return $tree;
4401
}
4402

    
4403
function filter_generate_altq_queues() {
4404
	global $altq_list_queues;
4405

    
4406
	read_altq_config();
4407

    
4408
	$altq_rules = "";
4409
	foreach ($altq_list_queues as $altq)
4410
		$altq_rules .= $altq->build_rules();
4411

    
4412
	return $altq_rules;
4413
}
4414

    
4415
function dnqueue_find_nextnumber() {
4416
	global $dummynet_pipe_list;
4417

    
4418
	$dnused = array();
4419
	if (is_array($dummynet_pipe_list)) {
4420
		foreach ($dummynet_pipe_list as $dn) {
4421
			$tmplist =& $dn->get_queue_list();
4422
			foreach ($tmplist as $qname => $link) {
4423
				if ($link[0] == "?")
4424
					$dnused[$qname] = substr($link, 1);
4425
			}
4426
		}
4427
	}
4428

    
4429
	sort($dnused, SORT_NUMERIC);
4430
	$dnnumber = 0;
4431
	$found = false;
4432
	foreach ($dnused as $dnnum) {
4433
		if (($dnnum - $dnnumber) > 1) {
4434
			$dnnumber = $dnnum - 1;
4435
			$found = true;
4436
			break;
4437
		} else
4438
			$dnnumber = $dnnum;
4439
	}
4440

    
4441
	if ($found == false)
4442
		$dnnumber++;
4443

    
4444
	unset($dnused, $dnnum, $found);
4445
	return $dnnumber;
4446
}
4447

    
4448
function dnpipe_find_nextnumber() {
4449
	global $dummynet_pipe_list;
4450

    
4451
	$dnused = array();
4452
	foreach ($dummynet_pipe_list as $dn)
4453
		$dnused[] = $dn->GetNumber();
4454

    
4455
	sort($dnused, SORT_NUMERIC);
4456
	$dnnumber = 0;
4457
	$found = false;
4458
	foreach ($dnused as $dnnum) {
4459
		if (($dnnum - $dnnumber) > 1) {
4460
			$dnnumber = $dnnum - 1;
4461
			$found = true;
4462
			break;
4463
		} else
4464
			$dnnumber = $dnnum;
4465
	}
4466

    
4467
	if ($found == false)
4468
		$dnnumber++;
4469

    
4470
	unset($dnused, $dnnum, $found);
4471
	return $dnnumber;
4472
}
4473

    
4474
function filter_generate_dummynet_rules() {
4475
	global $g, $dummynet_pipe_list;
4476

    
4477
	read_dummynet_config();
4478

    
4479
	$dn_rules = "";
4480
	foreach ($dummynet_pipe_list as $dn)
4481
		$dn_rules .= $dn->build_rules();
4482

    
4483
	if (!empty($dn_rules)) {
4484
		if (!is_module_loaded("dummynet.ko")) {
4485
			mwexec("/sbin/kldload dummynet");
4486
			set_sysctl(array(
4487
				"net.inet.ip.dummynet.io_fast" => "1",
4488
				"net.inet.ip.dummynet.hash_size" => "256"
4489
			));
4490
		}
4491
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4492
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4493
	}
4494
}
4495

    
4496
function build_iface_without_this_queue($iface, $qname) {
4497
	global $g, $altq_list_queues;
4498
	global $shaperIFlist;
4499

    
4500
	$altq =& $altq_list_queues[$iface];
4501
	if ($altq)
4502
		$scheduler = ": " . $altq->GetScheduler();
4503
	$form = "<tr><td width=\"20%\" >";
4504
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&amp;queue=" . $iface."&amp;action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4505
	$form .= "</td></tr>";
4506
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4507
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4508
	$form .= $iface . "&amp;queue=". $qname . "&amp;action=add\">";
4509
	$form .= "<img src=\"";
4510
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4511
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\" alt=\"clone\" />";
4512
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4513

    
4514
	return $form;
4515

    
4516
}
4517

    
4518

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

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

    
4533
?>
(51-51/68)