Project

General

Profile

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

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

    
1079
	}
1080

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

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

    
1101
		return $tree;
1102
	}
1103

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

    
1155
		$pfq_rule .= " \n";
1156

    
1157
		return $pfq_rule;
1158
	}
1159

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

    
1242
		return $form;
1243
	}
1244

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

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

    
1279
		return $form;
1280

    
1281
	}
1282

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

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

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

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

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

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

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

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

    
1465
		return $q;
1466
	}
1467

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1864
		 $pfq_rule .= " \n";
1865

    
1866
		return $pfq_rule;
1867
	}
1868

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

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

    
1910
		return $javascript;
1911
	}
1912

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

    
2014
		return $form;
2015
	}
2016

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

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

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

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

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

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

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

    
2174
		return $q;
2175
	}
2176

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

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

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

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

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

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

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

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

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

    
2267

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

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

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

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

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

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

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

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

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

    
2433
		return $form;
2434
	}
2435

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

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

    
2478
class fairq_queue extends priq_queue {
2479
	var $hogs;
2480
	var $buckets;
2481

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

    
2498

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

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

    
2524
	function find_parentqueue($interface, $qname) { return; }
2525

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

    
2532
	function validate_input($data, &$input_errors) {
2533
		parent::validate_input($data, $input_errors);
2534

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

    
2542
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2543

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

    
2547

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

    
2551

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

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

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

    
2583
	function build_javascript() {
2584
		return parent::build_javascript();
2585
	}
2586

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

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

    
2662
		$pfq_rule .= " \n";
2663
		return $pfq_rule;
2664
	}
2665

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

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

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

    
2759

    
2760
/*
2761
 * dummynet(4) wrappers.
2762
 */
2763

    
2764

    
2765
/*
2766
 * List of respective objects!
2767
 */
2768
$dummynet_pipe_list = array();
2769

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

    
2780
        var $buckets;
2781
        /* mask parameters */
2782
        var $mask;
2783
        var $noerror;
2784
        
2785
        var $ipv6allow;
2786
        
2787
        /* constructor */
2788
                
2789
        function __construct() {
2790
                global $config;
2791
                if (isset($config['system']['ipv6allow']))
2792
                        $this->ipv6allow = True;
2793
                else
2794
                        $this->ipv6allow = False;
2795

    
2796
        }
2797

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

    
2878
	function build_javascript() {
2879
		$javascript .= "<script type=\"text/javascript\">\n";
2880
		$javascript .= "//<![CDATA[\n";
2881
		$javascript .= "function enable_maskbits(enable_over) {\n";
2882
		$javascript .= "var e = document.getElementById(\"mask\");\n";
2883
		$javascript .= "if ((e.options[e.selectedIndex].text == \"none\") || enable_over) {\n";
2884
		$javascript .= "document.iform.maskbits.disabled = 1;\n";
2885
		$javascript .= "document.iform.maskbits.value = \"\";\n";
2886
                if ($this->IPV6Enabled()) {
2887
                        $javascript .= "document.iform.maskbitsv6.disabled = 1;\n";
2888
                        $javascript .= "document.iform.maskbitsv6.value = \"\";\n";
2889
                }
2890
		$javascript .= "} else {\n";
2891
		$javascript .= "document.iform.maskbits.disabled = 0;\n";
2892
                if ($this->IPV6Enabled())
2893
                        $javascript .= "document.iform.maskbitsv6.disabled = 0;\n";
2894
		$javascript .= "}}\n";
2895
		$javascript .= "//]]>\n";
2896
		$javascript .= "</script>\n";
2897
		return $javascript;
2898
	}
2899

    
2900
	function validate_input($data, &$input_errors) {
2901
		$reqdfields[] = "bandwidth";
2902
		$reqdfieldsn[] = gettext("Bandwidth");
2903
		$reqdfields[] = "bandwidthtype";
2904
		$reqdfieldsn[] = gettext("Bandwidthtype");
2905
		$reqdfields[] = "newname";
2906
		$reqdfieldsn[] = gettext("Name");
2907

    
2908
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2909

    
2910
		if ($data['plr'] && ((!is_numeric($data['plr'])) ||
2911
			($data['plr'] <= 0 && $data['plr'] > 1))) 
2912
				$input_errors[] = gettext("Plr must be an integer between 1 and 100.");
2913
		if (($data['buckets'] && (!is_numeric($data['buckets']))) ||
2914
			($data['buckets'] < 1 && $data['buckets'] > 100)) 
2915
				$input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
2916
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) 
2917
            		$input_errors[] = gettext("Queue limit must be an integer");
2918
        	if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname']))
2919
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2920
        	if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name']))
2921
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2922
                if (isset($data['maskbits']) && ($data['maskbits'] <> ""))
2923
			if ((!is_numeric($data['maskbits'])) || ($data['maskbits'] <= 0) || ($data['maskbits'] > 32))
2924
				$input_errors[] = gettext("IPV4 bit mask must be blank or numeric value between 1 and 32.");
2925
                if ($this->IPV6Enabled())
2926
                        if (isset($data['maskbitsv6']) && ($data['maskbitsv6'] <> "")) {
2927
				if ((!is_numeric($data['maskbitsv6'])) || ($data['maskbitsv6'] <= 0) || ($data['maskbitsv6'] > 128))
2928
					$input_errors[] = gettext("IPV6 bit mask must be blank or numeric value between 1 and 128.");
2929
			}
2930
	}
2931
	
2932
	function build_mask_rules(&$pfq_rule) {
2933
		$mask = $this->GetMask();
2934
		if (!empty($mask['type'])) {
2935
			if ($mask['type'] <> 'none')
2936
				$pfq_rule .= " mask";
2937
			switch ($mask['type']) {
2938
			case 'srcaddress':
2939
                                if ($this->IPV6Enabled()) {
2940
                                        if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> ""))
2941
                                                $pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
2942
					else
2943
						$pfq_rule .= " src-ip6 /128";
2944
                                }
2945
                                if (!empty($mask['bits']) && ($mask['bits'] <> ""))
2946
                                        $pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
2947
                                else
2948
					$pfq_rule .= " src-ip 0xffffffff";
2949
				break;
2950
			case 'dstaddress':
2951
                                if ($this->IPV6Enabled()) {
2952
                                        if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> ""))
2953
                                                $pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
2954
					else
2955
						$pfq_rule .= " dst-ip6 /128";
2956
                                }
2957
                                if (!empty($mask['bits']) && ($mask['bits'] <> ""))
2958
                                        $pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
2959
                                else
2960
					$pfq_rule .= " dst-ip 0xffffffff";
2961
				break;
2962
			default:
2963
				break;
2964
			}
2965
		}            
2966
	}
2967
        
2968
}
2969

    
2970
class dnpipe_class extends dummynet_class {
2971
        var $delay;
2972
	var $qbandwidth = array();
2973
	var $qbandwidthtype;
2974

    
2975
		/* This is here to help on form building and building rules/lists */
2976
        var $subqueues = array();
2977

    
2978
	function CanHaveChildren() {
2979
	        return true;
2980
        }
2981
	function SetDelay($delay) {
2982
		$this->delay = $delay;
2983
	}
2984
	function GetDelay() {
2985
		return $this->delay;
2986
	}
2987
	function delete_queue() {
2988
		cleanup_dnqueue_from_rules($this->GetQname());
2989
		foreach ($this->subqueues as $q)
2990
			$q->delete_queue();
2991
		unset_dn_object_by_reference($this->GetLink());
2992
		mwexec("/sbin/ipfw pipe delete " . $this->GetNumber());
2993
        }
2994
        function GetBandwidth() {
2995
                return $this->qbandwidth;
2996
        }
2997
        function SetBandwidth($bandwidth) {
2998
                $this->qbandwidth = $bandwidth;
2999
        }
3000

    
3001
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
3002

    
3003
		if (!is_array($this->subqueues))
3004
			$this->subqueues = array();
3005

    
3006
		$q =& new dnqueue_class();
3007
		$q->SetLink($path);
3008
		$q->SetEnabled("on");
3009
		$q->SetPipe($this->GetQname());
3010
		$q->SetParent(&$this);
3011
		$q->ReadConfig($queue);
3012
		$q->validate_input($queue, $input_errors);
3013
		if (count($input_errors)) {
3014
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
3015
			return $q;
3016
		}
3017
		$number = dnqueue_find_nextnumber();
3018
		$q->SetNumber($number);
3019
		$this->subqueues[$q->GetQname()] = &$q;
3020
            
3021
		return $q;
3022
	}
3023

    
3024
	function &get_queue_list($q = null) {
3025
		$qlist = array();
3026

    
3027
		$qlist[$this->GetQname()] = $this->GetNumber();
3028
		if (is_array($this->subqueues)) {
3029
			foreach ($this->subqueues as $queue)
3030
				$queue->get_queue_list(&$qlist);
3031
		}
3032
		return $qlist;
3033
	}
3034

    
3035
        /*
3036
         * Should search even its children
3037
         */
3038
        function &find_queue($pipe, $qname) {
3039
                if ($qname == $this->GetQname()) 
3040
                        return $this;
3041
               	foreach ($this->subqueues as $q) {
3042
                       	$result =& $q->find_queue("", $qname);
3043
						if ($result)
3044
                       	        return $result;
3045
               	}
3046
        }
3047

    
3048
	function &find_parentqueue($pipe, $qname) {
3049
		return NULL;
3050
       	}
3051

    
3052
	function validate_input($data, &$input_errors) {
3053
		parent::validate_input($data, $input_errors);
3054

    
3055
		$schedule = 0;
3056
		$schedulenone = 0;
3057
		$entries = 0;
3058
		for ($i = 0; $i < 30; $i++) {
3059
			if (!empty($data["bwsched{$i}"])) {
3060
				if ($data["bwsched{$i}"] != "none")
3061
					$schedule++;
3062
				else
3063
					$schedulenone++;
3064
			}
3065
			if (!empty($data["bandwidth{$i}"])) {
3066
				if (!is_numeric($data["bandwidth{$i}"]))
3067
					$input_errors[] = sprintf(gettext("Bandwidth for schedule %s must be an integer."), $data["bwsched{$i}"]);
3068
				else
3069
					$entries++;
3070
			}
3071
		}
3072
		if ($schedule == 0 && $entries > 1)
3073
			$input_errors[] = gettext("You need to specify a schedule for every additional entry");
3074
		if ($schedulenone > 0 && $entries > 1)
3075
			$input_errors[] = gettext("If more than one bandwidth configured all schedules need to be selected");
3076
		if ($entries == 0)
3077
			$input_errors[] = gettext("At least one bw specification is necessary");
3078
		if ($data['delay'] && (!is_numeric($data['delay'])))
3079
			$input_errors[] = gettext("Delay must be an integer.");
3080
	}
3081

    
3082
	function ReadConfig(&$q) {
3083
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3084
			$this->SetQname($q['newname']);
3085
		} else if (!empty($q['newname'])) {
3086
			$this->SetQname($q['newname']);
3087
		} else {
3088
			$this->SetQname($q['name']);
3089
		}
3090
		$this->SetNumber($q['number']);
3091

    
3092
		if (!empty($_POST)) {
3093
			$bandwidth = array();
3094
			for ($i = 0; $i < 30; $i++) {
3095
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") { 
3096
					$bw = array();
3097
					$bw['bw'] = $q["bandwidth{$i}"];
3098
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"])
3099
						$bw['bwscale'] = $q["bwtype{$i}"];
3100
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"])
3101
						$bw['bwsched'] = $q["bwsched{$i}"];
3102
					$bandwidth[] = $bw;
3103
				}
3104
			}
3105
			$this->SetBandwidth($bandwidth);
3106
		}
3107
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item']))
3108
			$this->SetBandwidth($q['bandwidth']['item']);
3109

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

    
3145
        }
3146

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

    
3159
		return $tree;
3160
	}
3161

    
3162
        function build_rules() {
3163
		global $config, $time_based_rules;
3164

    
3165
		if ($this->GetEnabled() == "")
3166
			return;
3167

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

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

    
3211
		$pfq_rule .= "\n";
3212

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

    
3219
		return $pfq_rule;
3220
        }
3221

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

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

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

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

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

    
3459
		return $form;
3460

    
3461
		}
3462

    
3463
	function wconfig() {
3464
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3465
            	if (!is_array($cflink))
3466
            		$cflink = array();
3467
		$cflink['name'] = $this->GetQname();
3468
		$cflink['number'] = $this->GetNumber();
3469
            	$cflink['qlimit'] = $this->GetQlimit();
3470
            	$cflink['plr'] = $this->GetPlr();
3471
            	$cflink['description'] = $this->GetDescription();
3472
               
3473
		$bandwidth = $this->GetBandwidth();
3474
		if (is_array($bandwidth)) {
3475
			$cflink['bandwidth'] = array();
3476
			$cflink['bandwidth']['item'] = array();
3477
			foreach ($bandwidth as $bwidx => $bw)
3478
				$cflink['bandwidth']['item'][] = $bw;
3479
		}
3480

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

    
3493
}
3494

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

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

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

    
3515
	function delete_queue() {
3516
		cleanup_dnqueue_from_rules($this->GetQname());
3517
		unset_dn_object_by_reference($this->GetLink());
3518
		mwexec("/sbin/ipfw queue delete " . $this->GetNumber());
3519
        }
3520

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

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

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

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

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

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

    
3586
	function build_tree() {
3587
		$parent =& $this->GetParent();
3588
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">"; 
3589
		$tree .= $this->GetQname() . "</a>";
3590
		$tree .= "</li>";
3591

    
3592
		return $tree;
3593
	}
3594

    
3595
        function build_rules() {
3596
		if ($this->GetEnabled() == "")
3597
			return; 
3598

    
3599
		$parent =& $this->GetParent();
3600
            	$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
3601
		if ($this->GetQlimit())
3602
                    	$pfq_rule .= " queue " . $this->GetQlimit();
3603
		if ($this->GetWeight())
3604
			$pfq_rule .= " weight " . $this->GetWeight();
3605
		if ($this->GetBuckets())
3606
			$pfq_rule .= " buckets " . $this->GetBuckets();
3607
		$this->build_mask_rules($pfq_rule);
3608
		$pfq_rule .= "\n";
3609

    
3610
		return $pfq_rule;
3611
	}
3612

    
3613
        function build_javascript() {
3614
		return parent::build_javascript();
3615
	}
3616

    
3617

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

    
3736
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3737
		$form .= " value=\"" . $this->GetPipe() . "\" />";
3738

    
3739
		return $form;
3740

    
3741
	}
3742

    
3743
        function update_dn_data(&$data) { 
3744
		$this->ReadConfig($data);
3745
	}
3746

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

    
3768
// List of layer7 objects
3769
$layer7_rules_list = array();
3770

    
3771
class layer7 {
3772
    
3773
    var $rname; //alias
3774
    var $rdescription; //alias description
3775
    var $rport; //divert port
3776
    var $renabled; //rule enabled
3777
    var $rsets = array(); //array of l7 associations
3778
    
3779
    // Auxiliary functions
3780
    
3781
    function GetRName() {
3782
        return $this->rname;
3783
    }
3784
    function SetRName($rname) {
3785
        $this->rname = $rname;
3786
    }
3787
    function GetRDescription() {
3788
        return $this->rdescription;
3789
    }
3790
    function SetRDescription($rdescription) {
3791
        $this->rdescription = $rdescription;
3792
    }
3793
    function GetRPort() {
3794
        return $this->rport;
3795
    }
3796
    function SetRPort($rport) {
3797
        $this->rport = $rport;
3798
    }
3799
    function GetREnabled() {
3800
        return $this->renabled;
3801
    }
3802
    function SetREnabled($value) {
3803
        $this->renabled = $value;
3804
    }
3805
    function GetRl7() {
3806
        return $this->rsets;
3807
    }
3808
    function SetRl7($rsets) {
3809
        $this->rsets = $rsets;
3810
    }
3811
    
3812
    //Add a tuple (rule,sctructure,element) to the $rsets
3813
    
3814
    function add_rule($l7set) {
3815
       	$this->rsets[] = $l7set;
3816
    }
3817
    
3818
    // Build the layer7 rules
3819
    function build_l7_rules() {
3820
        if($this->GetREnabled() == "") {
3821
            return;
3822
        }
3823
        //$l7rules = "#" . $this->rdescription . "\n";
3824
        foreach ($this->rsets as $rl7) {
3825
            $l7rules .= $rl7->build_rules();
3826
        }
3827
        return $l7rules;
3828
    }
3829
    
3830
    // Read the config from array
3831
    function ReadConfig(&$qname, &$q) {
3832
        $this->SetRName($qname);
3833
        $this->SetREnabled($q['enabled']);
3834
        $this->SetRPort($q['divert_port']);
3835
        if(isset($q['description']) && $q['description'] <> "")
3836
            $this->SetRDescription($q['description']);
3837
        $rsets = $q['l7rules'];
3838
        //Put individual rules in the array
3839
	if(is_array($rsets)) {
3840
	    $this->rsets = array(); // XXX: ugly hack
3841
	    foreach($rsets as $l7r) {
3842
	        $l7obj = new l7rule();
3843
	        $l7obj->SetRProtocol($l7r['protocol']);
3844
	        $l7obj->SetRStructure($l7r['structure']);
3845
	        $l7obj->SetRBehaviour($l7r['behaviour']);
3846
	        $this->add_rule($l7obj);
3847
	    }
3848
	}
3849
    }
3850
    
3851
    //Generate a random port for the divert socket
3852
    function gen_divert_port() {
3853
        $dports = get_divert_ports(); //array of used ports
3854
	$divert_port = 1; // Initialize
3855
	while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) {
3856
		$divert_port = rand(40000, 60000);
3857
	}
3858
        return $divert_port;
3859
    }
3860
    
3861
    //Helps building the left tree
3862
    function build_tree() {
3863
        $tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&amp;action=show\">"; 
3864
        $tree .= $this->GetRName() . "</a>";
3865
	$tree .= "</li>";
3866

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

    
3894
	return $form;
3895
    }
3896
    
3897
    //Write the setting to the $config array
3898
    function wconfig() {
3899
	global $config;
3900

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

    
3920
        $cflink['l7rules'] = array();
3921

    
3922
        $i = 0;
3923
        foreach($this->rsets as $rulel7) {
3924
            $cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
3925
            $cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
3926
            $cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
3927
            $i++;
3928
        }
3929
    }
3930
    
3931
    //This function is necessary to help producing the overload options for keep state
3932
    function get_unique_structures() {
3933
        
3934
        $unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
3935
        foreach($this->rsets as $l7rule) {
3936
		if($l7rule->GetRStructure() == "action")
3937
			$unique_structures['action'] = true;
3938
		else if($l7rule->GetRStructure() == "limiter")
3939
			$unique_structures['dummynet'] = true;
3940
		else
3941
			$unique_structures['altq'] = true;
3942
        }
3943
	//Delete non used structures so we don't have to check this in filter.inc
3944
	foreach($unique_structures as $key => $value)
3945
		if(!$value)
3946
			unset($unique_structures[$key]);
3947
        return $unique_structures;
3948
    }
3949
    
3950
    function validate_input($data, &$input_errors) {
3951
	$reqdfields[] = "container";
3952
	$reqdfieldsn[] = gettext("Name");
3953

    
3954
	shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3955
        
3956
        if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container']))
3957
            $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3958
    }
3959
    
3960
    function delete_l7c() {
3961
	mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
3962
	unset_l7_object_by_reference($this->GetRName());
3963
	cleanup_l7_from_rules($this->GetRName());
3964
    }
3965
}
3966

    
3967
class l7rule {
3968
    
3969
    var $rprotocol; //protocol
3970
    var $rstructure; //action, limiter, queue
3971
    var $rbehaviour; //allow, block, queue_name, pipe_number ...
3972
    
3973
    //Auxiliary Functions
3974
    
3975
    function GetRProtocol() {
3976
        return $this->rprotocol;
3977
    }
3978
    function SetRProtocol($rprotocol) {
3979
        $this->rprotocol = $rprotocol;
3980
    }
3981
    function GetRStructure() {
3982
        return $this->rstructure;
3983
    }
3984
    function SetRStructure($rstructure) {
3985
        $this->rstructure = $rstructure;
3986
    }
3987
    function GetRBehaviour() {
3988
        return $this->rbehaviour;
3989
    }
3990
    function SetRBehaviour($rbehaviour) {
3991
        $this->rbehaviour = $rbehaviour;
3992
    }
3993
    
3994
    //XXX Do we need to test any particularity for AltQ queues?
3995
    function build_rules() {
3996
	global $dummynet_pipe_list;
3997
	switch ($this->GetRStructure()) {
3998
		case "limiter":
3999
			read_dummynet_config();
4000
			$dn_list =& get_unique_dnqueue_list();
4001
			$found = false;
4002
			if(is_array($dn_list)) {
4003
				foreach($dn_list as $key => $value) {
4004
					if($key == $this->GetRBehaviour()) {
4005
						if($value[0] == "?")
4006
							$l7rule = $this->GetRProtocol() . " = dnqueue " . substr($value, 1) . "\n";
4007
						else
4008
							$l7rule = $this->GetRProtocol() . " = dnpipe " . $value . "\n";
4009
						$found = true;
4010
					}
4011
					if($found)
4012
						break;
4013
				}
4014
			}
4015
			break;
4016
		default: //This is for action and for altq
4017
			$l7rule = $this->GetRProtocol() . " = " . $this->GetRStructure() . " " . $this->GetRBehaviour() . "\n";
4018
			break;
4019
	}
4020
        return $l7rule;
4021
    }
4022
}
4023

    
4024
/*
4025
 * This function allows to return an array with all the used divert socket ports
4026
 */
4027
function get_divert_ports() {
4028
    global $layer7_rules_list;
4029
    $dports = array();
4030
    
4031
    foreach($layer7_rules_list as $l7r)
4032
        $dports[] = $l7r->GetRPort();
4033
    
4034
    return $dports;
4035
}
4036

    
4037
function &get_l7c_reference_to_me_in_config(&$name) {
4038
	global $config;
4039

    
4040
	$ptr = NULL;
4041

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

    
4052
function unset_l7_object_by_reference(&$name) {
4053
	global $config;
4054
        
4055
	if(is_array($config['l7shaper']['container'])) {
4056
		foreach($config['l7shaper']['container'] as $key => $value) {
4057
			if($value['name'] == $name) {
4058
				unset($config['l7shaper']['container'][$key]['l7rules']);
4059
				unset($config['l7shaper']['container'][$key]);
4060
				break;
4061
			}
4062
		}
4063
	}
4064
}
4065

    
4066
function read_layer7_config() {
4067
    global $layer7_rules_list, $config;
4068
    
4069
    $l7cs = &$config['l7shaper']['container'];
4070
    
4071
    $layer7_rules_list = array();
4072
    
4073
    if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container']))
4074
	return;
4075
    
4076
    foreach ($l7cs as $conf) {
4077
	if (empty($conf['name']))
4078
		continue; /* XXX: grrrrrr at php */ 
4079
        $root =& new layer7();
4080
        $root->ReadConfig($conf['name'],$conf);
4081
        $layer7_rules_list[$root->GetRName()] = &$root;
4082
    }
4083
}
4084

    
4085
function generate_layer7_files() {
4086
    global $layer7_rules_list, $g;
4087
    
4088
    read_layer7_config();
4089
    
4090
    if (!empty($layer7_rules_list)) {
4091
	if (!is_module_loaded("ipdivert.ko"))
4092
		mwexec("/sbin/kldload ipdivert.ko");
4093

    
4094
	mwexec("rm -f {$g['tmp_path']}/*.l7");
4095
    }
4096
    
4097
    foreach($layer7_rules_list as $l7rules) {
4098
        if($l7rules->GetREnabled()) {
4099
            $filename = $l7rules->GetRName() . ".l7";
4100
            $path = "{$g['tmp_path']}/" . $filename;
4101
        
4102
            $rules = $l7rules->build_l7_rules();
4103
        
4104
            $fp = fopen($path,'w');
4105
            fwrite($fp,$rules);
4106
            fclose($fp);
4107
        }
4108
    }
4109
}
4110

    
4111
function layer7_start_l7daemon() {
4112
    global $layer7_rules_list, $g;
4113

    
4114
    /*
4115
     * XXX: ermal - Needed ?!
4116
     * read_layer7_config();
4117
     */
4118

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

    
4124
	    unset($l7pid);
4125
	    /* Only reread the configuration rather than restart to avoid loosing information. */
4126
	    exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid);
4127
	    if (count($l7pid) > 0) {
4128
		log_error(sprintf(gettext("Sending HUP signal to %s"), $l7pid[0]));
4129
		mwexec("/bin/kill -HUP {$l7pid[0]}");
4130
	    } else {
4131
		// XXX: Hardcoded number of packets to garbage collect and queue length..
4132
		$ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 8 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
4133
		mwexec_bg($ipfw_classifyd_init);
4134
	    }
4135
        }
4136
    }
4137
}
4138

    
4139
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
4140
function generate_protocols_array() {
4141
	$protocols = return_dir_as_array("/usr/local/share/protocols");
4142
	$protocols_new = array();
4143
	if(is_array($protocols)) {
4144
		foreach($protocols as $key => $proto) {
4145
			if (strstr($proto, ".pat"))
4146
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
4147
		}
4148
		sort($protocols_new);
4149
	}		
4150
	return $protocols_new;
4151
}
4152

    
4153
function get_l7_unique_list() {
4154
	global $layer7_rules_list;
4155

    
4156
	$l7list = array();
4157
	if(is_array($layer7_rules_list)) 
4158
		foreach($layer7_rules_list as $l7c)
4159
			if($l7c->GetREnabled())
4160
				$l7list[] = $l7c->GetRName();
4161

    
4162
	return $l7list;
4163
}
4164

    
4165
// Disable a removed l7 container from the filter
4166
function cleanup_l7_from_rules(&$name) {
4167
	global $config;
4168

    
4169
	if(is_array($config['filter']['rule']))
4170
		foreach ($config['filter']['rule'] as $key => $rule) {
4171
			if ($rule['l7container'] == $name)
4172
				unset($config['filter']['rule'][$key]['l7container']);
4173
		}
4174
}
4175

    
4176
function get_dummynet_name_list() {
4177

    
4178
	$dn_name_list =& get_unique_dnqueue_list();
4179
	$dn_name = array();
4180
	if(is_array($dn_name_list))
4181
		foreach($dn_name_list as $key => $value)
4182
			$dn_name[] = $key;
4183

    
4184
	return $dn_name;
4185

    
4186
}
4187

    
4188
function get_altq_name_list() {
4189
	$altq_name_list =& get_unique_queue_list();
4190
	$altq_name = array();
4191
	if(is_array($altq_name_list))
4192
		foreach($altq_name_list as $key => $aqobj)
4193
			$altq_name[] = $key;
4194

    
4195
	return $altq_name;
4196
}
4197

    
4198
/*
4199
 * XXX: TODO Make a class shaper to hide all these function
4200
 * from the global namespace.
4201
 */
4202

    
4203
/* 
4204
 * This is a layer violation but for now there is no way 
4205
 * i can find to properly do this with PHP.
4206
 */
4207
function altq_get_default_queue($interface) {
4208
	global $altq_list_queues;
4209

    
4210
	$altq_tmp = $altq_list_queues[$interface];
4211
	if ($altq_tmp)
4212
		return $altq_tmp->GetDefaultQueuePresent(); 
4213
	else
4214
		return false;
4215
}
4216

    
4217
function altq_check_default_queues() {
4218
	global $altq_list_queues;
4219

    
4220
	$count = 0;
4221
	if (is_array($altq_list_queues)) {
4222
		foreach($altq_list_queues as $altq) {
4223
			if ($altq->GetDefaultQueuePresent())
4224
				$count++;
4225
		}
4226
	}
4227
	else  $count++;;
4228

    
4229
	return 0;
4230
}
4231

    
4232
function &get_unique_queue_list() {
4233
	global $altq_list_queues;
4234

    
4235
	$qlist = array();
4236
	if (is_array($altq_list_queues)) {
4237
		foreach ($altq_list_queues as $altq) {
4238
			if ($altq->GetEnabled() == "")
4239
				continue;
4240
			$tmplist =& $altq->get_queue_list();
4241
			foreach ($tmplist as $qname => $link) {
4242
				if ($link->GetEnabled() <> "")
4243
					$qlist[$qname] = $link;	
4244
			}
4245
		}
4246
	}
4247
	return $qlist;
4248
}
4249

    
4250
function &get_unique_dnqueue_list() {
4251
	global $dummynet_pipe_list;
4252

    
4253
	$qlist = array();
4254
	if (is_array($dummynet_pipe_list)) {
4255
		foreach ($dummynet_pipe_list as $dn) {
4256
			if ($dn->GetEnabled() == "")
4257
				continue;
4258
			$tmplist =& $dn->get_queue_list();
4259
			foreach ($tmplist as $qname => $link) {
4260
				$qlist[$qname] = $link;	
4261
			}
4262
		}
4263
	}
4264
	return $qlist;
4265
}
4266

    
4267
function ref_on_altq_queue_list($parent, $qname) {
4268
	if (isset($GLOBALS['queue_list'][$qname]))
4269
		$GLOBALS['queue_list'][$qname]++;
4270
	else
4271
		$GLOBALS['queue_list'][$qname] = 1;
4272

    
4273
	unref_on_altq_queue_list($parent);
4274
}
4275

    
4276
function unref_on_altq_queue_list($qname) {
4277
	$GLOBALS['queue_list'][$qname]--;
4278
	if ($GLOBALS['queue_list'][$qname] <= 1)
4279
		unset($GLOBALS['queue_list'][$qname]);	
4280
}
4281

    
4282
function read_altq_config() {
4283
	global $altq_list_queues, $config;
4284
	$path = array();
4285

    
4286
	if (!is_array($config['shaper']))
4287
		$config['shaper'] = array();
4288
	if (!is_array($config['shaper']['queue']))
4289
		$config['shaper']['queue'] = array();
4290
	$a_int = &$config['shaper']['queue'];
4291

    
4292
	$altq_list_queues = array();
4293

    
4294
	if (!is_array($config['shaper']['queue']))
4295
		return;
4296

    
4297
	foreach ($a_int as $key => $conf) {
4298
		$int = $conf['interface'];
4299
		$root =& new altq_root_queue();
4300
		$root->SetInterface($int);
4301
		$altq_list_queues[$root->GetInterface()] = &$root;
4302
		$root->ReadConfig($conf);
4303
		array_push($path, $key);
4304
		$root->SetLink($path);
4305
		if (is_array($conf['queue'])) {
4306
			foreach ($conf['queue'] as $key1 => $q) {
4307
				array_push($path, $key1);
4308
				/* 
4309
				 * XXX: we compeletely ignore errors here but anyway we must have 
4310
				 *	checked them before so no harm should be come from this.
4311
				 */
4312
				$root->add_queue($root->GetInterface(), $q, &$path, $input_errors);
4313
				array_pop($path);
4314
			} 	
4315
		}
4316
		array_pop($path);
4317
	}
4318
}
4319

    
4320
function read_dummynet_config() {
4321
	global $dummynet_pipe_list, $config;
4322
	$path = array();
4323

    
4324
	if (!is_array($config['dnshaper']))
4325
		$config['dnshaper'] = array();
4326
	if (!is_array($config['dnshaper']['queue']))
4327
		$config['dnshaper']['queue'] = array();
4328
	$a_int = &$config['dnshaper']['queue'];
4329

    
4330
	$dummynet_pipe_list = array();
4331

    
4332
	if (!is_array($config['dnshaper']['queue'])
4333
		|| !count($config['dnshaper']['queue']))
4334
		return;
4335

    
4336
	foreach ($a_int as $key => $conf) {
4337
		if (empty($conf['name']))
4338
			continue; /* XXX: grrrrrr at php */ 
4339
		$root =& new dnpipe_class();
4340
		$root->ReadConfig($conf);
4341
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4342
		array_push($path, $key);
4343
		$root->SetLink($path);
4344
		if (is_array($conf['queue'])) {
4345
			foreach ($conf['queue'] as $key1 => $q) {
4346
				array_push($path, $key1);
4347
				/* 
4348
				 * XXX: we compeletely ignore errors here but anyway we must have 
4349
				 *	checked them before so no harm should be come from this.
4350
				 */	
4351
				$root->add_queue($root->GetQname(), $q, &$path, $input_errors);
4352
				array_pop($path);
4353
			} 	
4354
		}
4355
		array_pop($path);
4356
	}
4357
}
4358

    
4359
function get_interface_list_to_show() {
4360
	global $altq_list_queues, $config;
4361
	global $shaperIFlist;
4362

    
4363
	$tree = "";
4364
	foreach ($shaperIFlist as $shif => $shDescr) {
4365
		if ($altq_list_queues[$shif]) {
4366
			continue;
4367
		} else  {
4368
			if (!is_altq_capable(get_real_interface($shif)))
4369
				continue;
4370
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4371
		}
4372
	}
4373

    
4374
	return $tree;
4375
}
4376

    
4377
function filter_generate_altq_queues() {
4378
	global $altq_list_queues;
4379

    
4380
	read_altq_config();
4381

    
4382
	$altq_rules = "";
4383
	foreach ($altq_list_queues as $altq) 
4384
		$altq_rules .= $altq->build_rules();
4385

    
4386
	return $altq_rules;
4387
}
4388

    
4389
function dnqueue_find_nextnumber() {
4390
	global $dummynet_pipe_list;
4391

    
4392
	$dnused = array();
4393
	if (is_array($dummynet_pipe_list)) {
4394
		foreach ($dummynet_pipe_list as $dn) {
4395
			$tmplist =& $dn->get_queue_list();
4396
			foreach ($tmplist as $qname => $link) {
4397
				if ($link[0] == "?")
4398
					$dnused[$qname] = substr($link, 1);
4399
			}
4400
		}
4401
	}
4402

    
4403
	sort($dnused, SORT_NUMERIC);
4404
	$dnnumber = 0;
4405
	$found = false;
4406
	foreach ($dnused as $dnnum) {
4407
		if (($dnnum - $dnnumber) > 1) {
4408
			$dnnumber = $dnnum + 1;
4409
			$found = true;
4410
			break;
4411
		} else
4412
			$dnnumber = $dnnum;
4413
	}
4414

    
4415
	if ($found == false)
4416
		$dnnumber++;
4417

    
4418
	unset($dnused, $dnnum, $found);
4419
	return $dnnumber;
4420
}
4421

    
4422
function dnpipe_find_nextnumber() {
4423
	global $dummynet_pipe_list;
4424

    
4425
	$dnused = array();
4426
	foreach ($dummynet_pipe_list as $dn)
4427
		$dnused[] = $dn->GetNumber();
4428

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

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

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

    
4448
function filter_generate_dummynet_rules() {
4449
	global $g, $dummynet_pipe_list;
4450

    
4451
	read_dummynet_config();
4452

    
4453
	if (!empty($dummynet_pipe_list)) {
4454
		if (!is_module_loaded("dummynet.ko")) {
4455
			mwexec("/sbin/kldload dummynet");
4456
			mwexec("/sbin/sysctl net.inet.ip.dummynet.io_fast=1 net.inet.ip.dummynet.hash_size=256");
4457
		}
4458
	}
4459

    
4460
	$dn_rules = "";
4461
	foreach ($dummynet_pipe_list as $dn) 
4462
		$dn_rules .= $dn->build_rules();
4463

    
4464
	if (!empty($dn_rules)) {
4465
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4466
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4467
	}
4468
}
4469

    
4470
function build_iface_without_this_queue($iface, $qname) {
4471
	global $g, $altq_list_queues;
4472
	global $shaperIFlist;
4473

    
4474
	$altq =& $altq_list_queues[$iface];
4475
	if ($altq)
4476
		$scheduler = ": " . $altq->GetScheduler();
4477
	$form = "<tr><td width=\"20%\" >";
4478
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&amp;queue=" . $iface."&amp;action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4479
	$form .= "</td></tr>";
4480
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4481
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4482
	$form .= $iface . "&amp;queue=". $qname . "&amp;action=add\">";
4483
	$form .= "<img src=\"";
4484
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4485
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\" alt=\"clone\" />";
4486
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4487

    
4488
	return $form;
4489

    
4490
}
4491

    
4492

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

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

    
4507
?>
(50-50/66)