Projet

Général

Profil

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

univnautes / etc / inc / shaper.inc @ c90d37f3

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->GetBandwidth()) {
534
				$rules .= " bandwidth ".trim($this->GetBandwidth());
535
				if ($this->GetBwscale())
536
					$rules .= $this->GetBwscale();
537
			}
538
			if ($this->GetTbrConfig())
539
				$rules .= " tbrsize ".$this->GetTbrConfig();
540
			if (count($this->queues)) {
541
				$i = count($this->queues);
542
				$rules .= " queue { ";
543
				foreach ($this->queues as $qkey => $qnone) {
544
					if ($i > 1) {
545
						$i--;
546
						$rules .= " {$qkey}, ";
547
					} else
548
						$rules .= " {$qkey} ";
549
				}
550
				$rules .= " } \n";
551
				foreach ($this->queues as $q) {
552
					$rules .= $q->build_rules($default);
553
				}
554
			}
555

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

    
577
			$rules .= " queue";
578
		}
579

    
580
		$rules .= " \n";
581
		return $rules;
582
	}
583

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

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

    
603
		return $javascript;
604
	}
605

    
606
	function build_shortform() {
607
		global $g;
608

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

    
628
		return $form;
629

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

    
721

    
722
		return $form;
723
	}
724

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

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

    
753
}
754

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

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

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

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

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

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

    
925
		return $javascript;
926
	}
927

    
928
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
929

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

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

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

    
956
	}
957

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

    
966
	function &get_queue_list(&$qlist) {
967

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

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

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

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

    
997
	function find_parentqueue($interface, $qname) { return; }
998

    
999
	function validate_input($data, &$input_errors) {
1000

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

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

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

    
1075
	}
1076

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

    
1095
		$tree .= "</li>";
1096

    
1097
		return $tree;
1098
	}
1099

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

    
1151
		$pfq_rule .= " \n";
1152

    
1153
		return $pfq_rule;
1154
	}
1155

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

    
1238
		return $form;
1239
	}
1240

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

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

    
1275
		return $form;
1276

    
1277
	}
1278

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

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

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

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

    
1424
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1425

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

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

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

    
1461
		return $q;
1462
	}
1463

    
1464
	function copy_queue($interface, &$cflink) {
1465

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

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

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

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

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

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

    
1593
	function validate_input($data, &$input_errors) {
1594
		parent::validate_input($data, $input_errors);
1595

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

    
1601
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1602

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1860
		$pfq_rule .= " \n";
1861

    
1862
		return $pfq_rule;
1863
	}
1864

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

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

    
1906
		return $javascript;
1907
	}
1908

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

    
2010
		return $form;
2011
	}
2012

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

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

    
2124
class cbq_queue extends priq_queue {
2125
	var $qborrow = "";
2126

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

    
2137
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2138

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

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

    
2173
		return $q;
2174
	}
2175

    
2176
	function copy_queue($interface, &$cflink) {
2177

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

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

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

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

    
2251
	function validate_input($data, &$input_errors) {
2252
		parent::validate_input($data, $input_errors);
2253

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

    
2261
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2262

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

    
2266

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

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

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

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

    
2298
	function build_javascript() {
2299
		return parent::build_javascript();
2300
	}
2301

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

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

    
2390
		$pfq_rule .= " \n";
2391
		return $pfq_rule;
2392
	}
2393

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

    
2432
		return $form;
2433
	}
2434

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

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

    
2480
class fairq_queue extends priq_queue {
2481
	var $hogs;
2482
	var $buckets;
2483

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

    
2500

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

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

    
2526
	function find_parentqueue($interface, $qname) { return; }
2527

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

    
2534
	function validate_input($data, &$input_errors) {
2535
		parent::validate_input($data, $input_errors);
2536

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

    
2544
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2545

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

    
2549

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

    
2553

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

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

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

    
2585
	function build_javascript() {
2586
		return parent::build_javascript();
2587
	}
2588

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

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

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

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

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

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

    
2764

    
2765
/*
2766
 * dummynet(4) wrappers.
2767
 */
2768

    
2769

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

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

    
2785
	var $buckets;
2786
	/* mask parameters */
2787
	var $mask;
2788
	var $noerror;
2789

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

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

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

    
2895
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2896

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

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

    
2949
}
2950

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

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

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

    
2988
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
2989

    
2990
		if (!is_array($this->subqueues))
2991
			$this->subqueues = array();
2992

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

    
3008
		return $q;
3009
	}
3010

    
3011
	function &get_queue_list(&$q = null) {
3012
		$qlist = array();
3013

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

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

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

    
3039
	function validate_input($data, &$input_errors) {
3040
		parent::validate_input($data, $input_errors);
3041

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

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

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

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

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

    
3138
	}
3139

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

    
3152
		return $tree;
3153
	}
3154

    
3155
	function build_rules() {
3156
		global $config, $time_based_rules;
3157

    
3158
		if ($this->GetEnabled() == "")
3159
			return;
3160

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

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

    
3208
		$pfq_rule .= "\n";
3209

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

    
3216
		return $pfq_rule;
3217
	}
3218

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

    
3223
	function build_javascript() {
3224
		global $g, $config;
3225

    
3226
		$javasr = parent::build_javascript();
3227

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

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

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

    
3282
EOD;
3283

    
3284
		return $javasr;
3285
	}
3286

    
3287
	function build_form() {
3288
		global $g, $config;
3289

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

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

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

    
3461
		return $form;
3462

    
3463
		}
3464

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

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

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

    
3492
}
3493

    
3494
class dnqueue_class extends dummynet_class {
3495
	var $pipeparent;
3496
	var $weight;
3497

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

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

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

    
3520
	function validate_input($data, &$input_errors) {
3521
		parent::validate_input($data, $input_errors);
3522

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

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

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

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

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

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

    
3599
		return $tree;
3600
	}
3601

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

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

    
3617
		return $pfq_rule;
3618
	}
3619

    
3620
	function build_javascript() {
3621
		return parent::build_javascript();
3622
	}
3623

    
3624

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

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

    
3744
		return $form;
3745

    
3746
	}
3747

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

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

    
3770
// List of layer7 objects
3771
$layer7_rules_list = array();
3772

    
3773
class layer7 {
3774

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

    
3781
	// Auxiliary functions
3782

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

    
3814
	//Add a tuple (rule,sctructure,element) to the $rsets
3815

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

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

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

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

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

    
3869
		return $tree;
3870
	}
3871

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

    
3896
		return $form;
3897
	}
3898

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

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

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

    
3922
		$cflink['l7rules'] = array();
3923

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

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

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

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

    
3956
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3957

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

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

    
3969
class l7rule {
3970

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

    
3975
	//Auxiliary Functions
3976

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

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

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

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

    
4036
	return $dports;
4037
}
4038

    
4039
function &get_l7c_reference_to_me_in_config(&$name) {
4040
	global $config;
4041

    
4042
	$ptr = NULL;
4043

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

    
4054
function unset_l7_object_by_reference(&$name) {
4055
	global $config;
4056

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

    
4068
function read_layer7_config() {
4069
	global $layer7_rules_list, $config;
4070

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

    
4076
	$l7cs = &$config['l7shaper']['container'];
4077

    
4078
	$layer7_rules_list = array();
4079

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

    
4089
function update_layer7_custom_patterns() {
4090
	global $config;
4091

    
4092
	if (!is_array($config['l7shaper']['custom_pat']))
4093
		return;
4094

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

    
4100
function generate_layer7_files() {
4101
	global $layer7_rules_list, $g;
4102

    
4103
	read_layer7_config();
4104

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

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

    
4112
	update_layer7_custom_patterns();
4113

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

    
4119
			$rules = $l7rules->build_l7_rules();
4120

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

    
4128
function layer7_start_l7daemon() {
4129
	global $layer7_rules_list, $g;
4130

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

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

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

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

    
4159
	update_layer7_custom_patterns();
4160

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

    
4173
function get_l7_unique_list() {
4174
	global $layer7_rules_list;
4175

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

    
4182
	return $l7list;
4183
}
4184

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

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

    
4196
function get_dummynet_name_list() {
4197

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

    
4204
	return $dn_name;
4205

    
4206
}
4207

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

    
4215
	return $altq_name;
4216
}
4217

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

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

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

    
4237
function altq_check_default_queues() {
4238
	global $altq_list_queues;
4239

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

    
4249
	return 0;
4250
}
4251

    
4252
function &get_unique_queue_list() {
4253
	global $altq_list_queues;
4254

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

    
4270
function &get_unique_dnqueue_list() {
4271
	global $dummynet_pipe_list;
4272

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

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

    
4293
	unref_on_altq_queue_list($parent);
4294
}
4295

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

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

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

    
4312
	$altq_list_queues = array();
4313

    
4314
	if (!is_array($config['shaper']['queue']))
4315
		return;
4316

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

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

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

    
4350
	$dummynet_pipe_list = array();
4351

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

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

    
4379
function get_interface_list_to_show() {
4380
	global $altq_list_queues, $config;
4381
	global $shaperIFlist;
4382

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

    
4394
	return $tree;
4395
}
4396

    
4397
function filter_generate_altq_queues() {
4398
	global $altq_list_queues;
4399

    
4400
	read_altq_config();
4401

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

    
4406
	return $altq_rules;
4407
}
4408

    
4409
function dnqueue_find_nextnumber() {
4410
	global $dummynet_pipe_list;
4411

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

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

    
4435
	if ($found == false)
4436
		$dnnumber++;
4437

    
4438
	unset($dnused, $dnnum, $found);
4439
	return $dnnumber;
4440
}
4441

    
4442
function dnpipe_find_nextnumber() {
4443
	global $dummynet_pipe_list;
4444

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

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

    
4461
	if ($found == false)
4462
		$dnnumber++;
4463

    
4464
	unset($dnused, $dnnum, $found);
4465
	return $dnnumber;
4466
}
4467

    
4468
function filter_generate_dummynet_rules() {
4469
	global $g, $dummynet_pipe_list;
4470

    
4471
	read_dummynet_config();
4472

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

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

    
4487
function build_iface_without_this_queue($iface, $qname) {
4488
	global $g, $altq_list_queues;
4489
	global $shaperIFlist;
4490

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

    
4505
	return $form;
4506

    
4507
}
4508

    
4509

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

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

    
4524
?>
(50-50/67)