Projet

Général

Profil

Télécharger (141 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / shaper.inc @ c650b2f7

1
<?php
2
/*
3
	Copyright (C) 2008 Ermal Luçi
4
	All rights reserved.
5

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

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

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

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

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

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

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

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

    
50
	return $ptr;
51
}
52

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

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

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

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

    
73
	return $ptr;
74
}
75

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
456
		return $q;
457
	}
458

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

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

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

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

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

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

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

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

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

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

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

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

    
605
		return $javascript;
606
	}
607

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

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

    
630
		return $form;
631

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

    
723

    
724
		return $form;
725
	}
726

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

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

    
755
}
756

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

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

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

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

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

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

    
927
		return $javascript;
928
	}
929

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

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

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

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

    
958
	}
959

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

    
968
	function &get_queue_list(&$qlist) {
969

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

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

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

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

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

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

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

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

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

    
1077
	}
1078

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

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

    
1099
		return $tree;
1100
	}
1101

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

    
1153
		$pfq_rule .= " \n";
1154

    
1155
		return $pfq_rule;
1156
	}
1157

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

    
1240
		return $form;
1241
	}
1242

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

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

    
1277
		return $form;
1278

    
1279
	}
1280

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

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

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

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

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

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

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

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

    
1463
		return $q;
1464
	}
1465

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1862
		$pfq_rule .= " \n";
1863

    
1864
		return $pfq_rule;
1865
	}
1866

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

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

    
1908
		return $javascript;
1909
	}
1910

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

    
2012
		return $form;
2013
	}
2014

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

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

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

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

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

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

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

    
2175
		return $q;
2176
	}
2177

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

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

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

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

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

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

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

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

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

    
2268

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

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

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

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

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

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

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

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

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

    
2434
		return $form;
2435
	}
2436

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

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

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

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

    
2502

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

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

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

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

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

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

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

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

    
2551

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

    
2555

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

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

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

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

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

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

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

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

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

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

    
2766

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

    
2771

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

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

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

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

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

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

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

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

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

    
2951
}
2952

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

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

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

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

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

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

    
3010
		return $q;
3011
	}
3012

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

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

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

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

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

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

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

    
3083
		if (!empty($_POST)) {
3084
			$bandwidth = array();
3085
			for ($i = 0; $i < 30; $i++) {
3086
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") {
3087
					$bw = array();
3088
					$bw['bw'] = $q["bandwidth{$i}"];
3089
					$bw['burst'] = $q["burst{$i}"];
3090
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"])
3091
						$bw['bwscale'] = $q["bwtype{$i}"];
3092
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"])
3093
						$bw['bwsched'] = $q["bwsched{$i}"];
3094
					$bandwidth[] = $bw;
3095
				}
3096
			}
3097
			$this->SetBandwidth($bandwidth);
3098
		}
3099

    
3100
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
3101
			$this->SetBandwidth($q['bandwidth']['item']);
3102
			$this->SetBurst($q['burst']['item']);
3103
		}
3104

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

    
3140
	}
3141

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

    
3154
		return $tree;
3155
	}
3156

    
3157
	function build_rules() {
3158
		global $config, $time_based_rules;
3159

    
3160
		if ($this->GetEnabled() == "")
3161
			return;
3162

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

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

    
3210
		$pfq_rule .= "\n";
3211

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

    
3218
		return $pfq_rule;
3219
	}
3220

    
3221
	function update_dn_data(&$data) {
3222
		$this->ReadConfig($data);
3223
	}
3224

    
3225
	function build_javascript() {
3226
		global $g, $config;
3227

    
3228
		$javasr = parent::build_javascript();
3229

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

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

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

    
3284
EOD;
3285

    
3286
		return $javasr;
3287
	}
3288

    
3289
	function build_form() {
3290
		global $g, $config;
3291

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

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

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

    
3463
		return $form;
3464

    
3465
		}
3466

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

    
3477
		$bandwidth = $this->GetBandwidth();
3478
		if (is_array($bandwidth)) {
3479
			$cflink['bandwidth'] = array();
3480
			$cflink['bandwidth']['item'] = array();
3481
			foreach ($bandwidth as $bwidx => $bw)
3482
				$cflink['bandwidth']['item'][] = $bw;
3483
		}
3484

    
3485
		$cflink['enabled'] = $this->GetEnabled();
3486
		$cflink['buckets'] = $this->GetBuckets();
3487
		$mask = $this->GetMask();
3488
		$cflink['mask'] = $mask['type'];
3489
		$cflink['maskbits'] = $mask['bits'];
3490
		$cflink['maskbitsv6'] = $mask['bitsv6'];
3491
		$cflink['delay'] = $this->GetDelay();
3492
	}
3493

    
3494
}
3495

    
3496
class dnqueue_class extends dummynet_class {
3497
	var $pipeparent;
3498
	var $weight;
3499

    
3500
	function GetWeight() {
3501
		return $this->weight;
3502
	}
3503
	function SetWeight($weight) {
3504
		$this->weight = $weight;
3505
	}
3506
	function GetPipe() {
3507
		return $this->pipeparent;
3508
	}
3509
	function SetPipe($pipe) {
3510
		$this->pipeparent = $pipe;
3511
	}
3512

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

    
3516
	function delete_queue() {
3517
		cleanup_dnqueue_from_rules($this->GetQname());
3518
		unset_dn_object_by_reference($this->GetLink());
3519
		@pfSense_pipe_action("queue delete " . $this->GetNumber());
3520
	}
3521

    
3522
	function validate_input($data, &$input_errors) {
3523
		parent::validate_input($data, $input_errors);
3524

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

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

    
3540
	function &find_parentqueue($pipe, $qname) {
3541
		return $this->qparent;
3542
	}
3543

    
3544
	function &get_queue_list(&$qlist) {
3545
		if ($this->GetEnabled() == "")
3546
			return;
3547
		$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3548
	}
3549

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

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

    
3601
		return $tree;
3602
	}
3603

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

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

    
3619
		return $pfq_rule;
3620
	}
3621

    
3622
	function build_javascript() {
3623
		return parent::build_javascript();
3624
	}
3625

    
3626

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

    
3743
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3744
		$form .= " value=\"" . $this->GetPipe() . "\" />";
3745

    
3746
		return $form;
3747

    
3748
	}
3749

    
3750
	function update_dn_data(&$data) {
3751
		$this->ReadConfig($data);
3752
	}
3753

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

    
3772
// List of layer7 objects
3773
$layer7_rules_list = array();
3774

    
3775
class layer7 {
3776

    
3777
	var $rname; //alias
3778
	var $rdescription; //alias description
3779
	var $rport; //divert port
3780
	var $renabled; //rule enabled
3781
	var $rsets = array(); //array of l7 associations
3782

    
3783
	// Auxiliary functions
3784

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

    
3816
	//Add a tuple (rule,sctructure,element) to the $rsets
3817

    
3818
	function add_rule($l7set) {
3819
		$this->rsets[] = $l7set;
3820
	}
3821

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

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

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

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

    
3871
		return $tree;
3872
	}
3873

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

    
3898
		return $form;
3899
	}
3900

    
3901
	//Write the setting to the $config array
3902
	function wconfig() {
3903
		global $config;
3904

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

    
3919
		//Destroy previously existent rules
3920
		if(is_array($cflink['rules'])) {
3921
			unset($cflink['l7rules']);
3922
		}
3923

    
3924
		$cflink['l7rules'] = array();
3925

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

    
3935
	//This function is necessary to help producing the overload options for keep state
3936
	function get_unique_structures() {
3937

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

    
3954
	function validate_input($data, &$input_errors) {
3955
		$reqdfields[] = "container";
3956
		$reqdfieldsn[] = gettext("Name");
3957

    
3958
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3959

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

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

    
3971
class l7rule {
3972

    
3973
	var $rprotocol; //protocol
3974
	var $rstructure; //action, limiter, queue
3975
	var $rbehaviour; //allow, block, queue_name, pipe_number ...
3976

    
3977
	//Auxiliary Functions
3978

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

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

    
4028
/*
4029
 * This function allows to return an array with all the used divert socket ports
4030
 */
4031
function get_divert_ports() {
4032
	global $layer7_rules_list;
4033
	$dports = array();
4034

    
4035
	foreach($layer7_rules_list as $l7r)
4036
		$dports[] = $l7r->GetRPort();
4037

    
4038
	return $dports;
4039
}
4040

    
4041
function &get_l7c_reference_to_me_in_config(&$name) {
4042
	global $config;
4043

    
4044
	$ptr = NULL;
4045

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

    
4056
function unset_l7_object_by_reference(&$name) {
4057
	global $config;
4058

    
4059
	if(is_array($config['l7shaper']['container'])) {
4060
		foreach($config['l7shaper']['container'] as $key => $value) {
4061
			if($value['name'] == $name) {
4062
				unset($config['l7shaper']['container'][$key]['l7rules']);
4063
				unset($config['l7shaper']['container'][$key]);
4064
				break;
4065
			}
4066
		}
4067
	}
4068
}
4069

    
4070
function read_layer7_config() {
4071
	global $layer7_rules_list, $config;
4072

    
4073
	if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container'])) {
4074
		$layer7_rules_list = array();
4075
		return;
4076
	}
4077

    
4078
	$l7cs = &$config['l7shaper']['container'];
4079

    
4080
	$layer7_rules_list = array();
4081

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

    
4091
function update_layer7_custom_patterns() {
4092
	global $config;
4093

    
4094
	if (!is_array($config['l7shaper']['custom_pat']))
4095
		return;
4096

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

    
4102
function generate_layer7_files() {
4103
	global $layer7_rules_list, $g;
4104

    
4105
	read_layer7_config();
4106

    
4107
	if (!empty($layer7_rules_list)) {
4108
		if (!is_module_loaded("ipdivert.ko"))
4109
			mwexec("/sbin/kldload ipdivert.ko");
4110

    
4111
		array_map('unlink', glob("{$g['tmp_path']}/*.l7"));
4112
	}
4113

    
4114
	update_layer7_custom_patterns();
4115

    
4116
	foreach($layer7_rules_list as $l7rules) {
4117
		if($l7rules->GetREnabled()) {
4118
			$filename = $l7rules->GetRName() . ".l7";
4119
			$path = "{$g['tmp_path']}/" . $filename;
4120

    
4121
			$rules = $l7rules->build_l7_rules();
4122

    
4123
			$fp = fopen($path,'w');
4124
			fwrite($fp,$rules);
4125
			fclose($fp);
4126
		}
4127
	}
4128
}
4129

    
4130
function layer7_start_l7daemon() {
4131
	global $layer7_rules_list, $g;
4132

    
4133
	/*
4134
	 * XXX: ermal - Needed ?!
4135
	 * read_layer7_config();
4136
	 */
4137

    
4138
	foreach($layer7_rules_list as $l7rules) {
4139
		if($l7rules->GetREnabled()) {
4140
			$filename = $l7rules->GetRName() . ".l7";
4141
			$path = "{$g['tmp_path']}/" . $filename;
4142

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

    
4158
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
4159
function generate_protocols_array() {
4160

    
4161
	update_layer7_custom_patterns();
4162

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

    
4175
function get_l7_unique_list() {
4176
	global $layer7_rules_list;
4177

    
4178
	$l7list = array();
4179
	if(is_array($layer7_rules_list))
4180
		foreach($layer7_rules_list as $l7c)
4181
			if($l7c->GetREnabled())
4182
				$l7list[] = $l7c->GetRName();
4183

    
4184
	return $l7list;
4185
}
4186

    
4187
// Disable a removed l7 container from the filter
4188
function cleanup_l7_from_rules(&$name) {
4189
	global $config;
4190

    
4191
	if(is_array($config['filter']['rule']))
4192
		foreach ($config['filter']['rule'] as $key => $rule) {
4193
			if ($rule['l7container'] == $name)
4194
				unset($config['filter']['rule'][$key]['l7container']);
4195
		}
4196
}
4197

    
4198
function get_dummynet_name_list() {
4199

    
4200
	$dn_name_list =& get_unique_dnqueue_list();
4201
	$dn_name = array();
4202
	if(is_array($dn_name_list))
4203
		foreach($dn_name_list as $key => $value)
4204
			$dn_name[] = $key;
4205

    
4206
	return $dn_name;
4207

    
4208
}
4209

    
4210
function get_altq_name_list() {
4211
	$altq_name_list =& get_unique_queue_list();
4212
	$altq_name = array();
4213
	if(is_array($altq_name_list))
4214
		foreach($altq_name_list as $key => $aqobj)
4215
			$altq_name[] = $key;
4216

    
4217
	return $altq_name;
4218
}
4219

    
4220
/*
4221
 * XXX: TODO Make a class shaper to hide all these function
4222
 * from the global namespace.
4223
 */
4224

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

    
4232
	$altq_tmp = $altq_list_queues[$interface];
4233
	if ($altq_tmp)
4234
		return $altq_tmp->GetDefaultQueuePresent();
4235
	else
4236
		return false;
4237
}
4238

    
4239
function altq_check_default_queues() {
4240
	global $altq_list_queues;
4241

    
4242
	$count = 0;
4243
	if (is_array($altq_list_queues)) {
4244
		foreach($altq_list_queues as $altq) {
4245
			if ($altq->GetDefaultQueuePresent())
4246
				$count++;
4247
		}
4248
	}
4249
	else  $count++;
4250

    
4251
	return 0;
4252
}
4253

    
4254
function &get_unique_queue_list() {
4255
	global $altq_list_queues;
4256

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

    
4272
function &get_unique_dnqueue_list() {
4273
	global $dummynet_pipe_list;
4274

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

    
4289
function ref_on_altq_queue_list($parent, $qname) {
4290
	if (isset($GLOBALS['queue_list'][$qname]))
4291
		$GLOBALS['queue_list'][$qname]++;
4292
	else
4293
		$GLOBALS['queue_list'][$qname] = 1;
4294

    
4295
	unref_on_altq_queue_list($parent);
4296
}
4297

    
4298
function unref_on_altq_queue_list($qname) {
4299
	$GLOBALS['queue_list'][$qname]--;
4300
	if ($GLOBALS['queue_list'][$qname] <= 1)
4301
		unset($GLOBALS['queue_list'][$qname]);
4302
}
4303

    
4304
function read_altq_config() {
4305
	global $altq_list_queues, $config;
4306
	$path = array();
4307

    
4308
	if (!is_array($config['shaper']))
4309
		$config['shaper'] = array();
4310
	if (!is_array($config['shaper']['queue']))
4311
		$config['shaper']['queue'] = array();
4312
	$a_int = &$config['shaper']['queue'];
4313

    
4314
	$altq_list_queues = array();
4315

    
4316
	if (!is_array($config['shaper']['queue']))
4317
		return;
4318

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

    
4342
function read_dummynet_config() {
4343
	global $dummynet_pipe_list, $config;
4344
	$path = array();
4345

    
4346
	if (!is_array($config['dnshaper']))
4347
		$config['dnshaper'] = array();
4348
	if (!is_array($config['dnshaper']['queue']))
4349
		$config['dnshaper']['queue'] = array();
4350
	$a_int = &$config['dnshaper']['queue'];
4351

    
4352
	$dummynet_pipe_list = array();
4353

    
4354
	if (!is_array($config['dnshaper']['queue'])
4355
		|| !count($config['dnshaper']['queue']))
4356
		return;
4357

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

    
4381
function get_interface_list_to_show() {
4382
	global $altq_list_queues, $config;
4383
	global $shaperIFlist;
4384

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

    
4396
	return $tree;
4397
}
4398

    
4399
function filter_generate_altq_queues() {
4400
	global $altq_list_queues;
4401

    
4402
	read_altq_config();
4403

    
4404
	$altq_rules = "";
4405
	foreach ($altq_list_queues as $altq)
4406
		$altq_rules .= $altq->build_rules();
4407

    
4408
	return $altq_rules;
4409
}
4410

    
4411
function dnqueue_find_nextnumber() {
4412
	global $dummynet_pipe_list;
4413

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

    
4425
	sort($dnused, SORT_NUMERIC);
4426
	$dnnumber = 0;
4427
	$found = false;
4428
	foreach ($dnused as $dnnum) {
4429
		if (($dnnum - $dnnumber) > 1) {
4430
			$dnnumber = $dnnum + 1;
4431
			$found = true;
4432
			break;
4433
		} else
4434
			$dnnumber = $dnnum;
4435
	}
4436

    
4437
	if ($found == false)
4438
		$dnnumber++;
4439

    
4440
	unset($dnused, $dnnum, $found);
4441
	return $dnnumber;
4442
}
4443

    
4444
function dnpipe_find_nextnumber() {
4445
	global $dummynet_pipe_list;
4446

    
4447
	$dnused = array();
4448
	foreach ($dummynet_pipe_list as $dn)
4449
		$dnused[] = $dn->GetNumber();
4450

    
4451
	sort($dnused, SORT_NUMERIC);
4452
	$dnnumber = 0;
4453
	$found = false;
4454
	foreach ($dnused as $dnnum) {
4455
		if (($dnnum - $dnnumber) > 1) {
4456
			$dnnumber = $dnnum + 1;
4457
			$found = true;
4458
			break;
4459
		} else
4460
			$dnnumber = $dnnum;
4461
	}
4462

    
4463
	if ($found == false)
4464
		$dnnumber++;
4465

    
4466
	unset($dnused, $dnnum, $found);
4467
	return $dnnumber;
4468
}
4469

    
4470
function filter_generate_dummynet_rules() {
4471
	global $g, $dummynet_pipe_list;
4472

    
4473
	read_dummynet_config();
4474

    
4475
	$dn_rules = "";
4476
	foreach ($dummynet_pipe_list as $dn)
4477
		$dn_rules .= $dn->build_rules();
4478

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

    
4492
function build_iface_without_this_queue($iface, $qname) {
4493
	global $g, $altq_list_queues;
4494
	global $shaperIFlist;
4495

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

    
4510
	return $form;
4511

    
4512
}
4513

    
4514

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

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

    
4529
?>
(51-51/68)