Projet

Général

Profil

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

univnautes / etc / inc / shaper.inc @ 89cf3dc0

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

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

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

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

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

    
3142
	}
3143

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

    
3156
		return $tree;
3157
	}
3158

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

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

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

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

    
3212
		$pfq_rule .= "\n";
3213

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

    
3220
		return $pfq_rule;
3221
	}
3222

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

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

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

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

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

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

    
3286
EOD;
3287

    
3288
		return $javasr;
3289
	}
3290

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

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

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

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

    
3466
		return $form;
3467

    
3468
		}
3469

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

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

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

    
3497
}
3498

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

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

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

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

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

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

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

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

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

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

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

    
3604
		return $tree;
3605
	}
3606

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

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

    
3622
		return $pfq_rule;
3623
	}
3624

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

    
3629

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

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

    
3749
		return $form;
3750

    
3751
	}
3752

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

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

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

    
3778
class layer7 {
3779

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

    
3786
	// Auxiliary functions
3787

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

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

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

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

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

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

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

    
3874
		return $tree;
3875
	}
3876

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

    
3901
		return $form;
3902
	}
3903

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

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

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

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

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

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

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

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

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

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

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

    
3974
class l7rule {
3975

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

    
3980
	//Auxiliary Functions
3981

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

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

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

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

    
4041
	return $dports;
4042
}
4043

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

    
4047
	$ptr = NULL;
4048

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

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

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

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

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

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

    
4083
	$layer7_rules_list = array();
4084

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

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

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

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

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

    
4108
	read_layer7_config();
4109

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

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

    
4117
	update_layer7_custom_patterns();
4118

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

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

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

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

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

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

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

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

    
4164
	update_layer7_custom_patterns();
4165

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

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

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

    
4187
	return $l7list;
4188
}
4189

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

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

    
4201
function get_dummynet_name_list() {
4202

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

    
4209
	return $dn_name;
4210

    
4211
}
4212

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

    
4220
	return $altq_name;
4221
}
4222

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

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

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

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

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

    
4254
	return 0;
4255
}
4256

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

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

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

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

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

    
4298
	unref_on_altq_queue_list($parent);
4299
}
4300

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

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

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

    
4317
	$altq_list_queues = array();
4318

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

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

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

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

    
4355
	$dummynet_pipe_list = array();
4356

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

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

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

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

    
4399
	return $tree;
4400
}
4401

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

    
4405
	read_altq_config();
4406

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

    
4411
	return $altq_rules;
4412
}
4413

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

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

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

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

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

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

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

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

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

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

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

    
4476
	read_dummynet_config();
4477

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

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

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

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

    
4513
	return $form;
4514

    
4515
}
4516

    
4517

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

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

    
4532
?>
(51-51/68)