Project

General

Profile

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

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

    
2880
	function validate_input($data, &$input_errors) {
2881
		$reqdfields[] = "bandwidth";
2882
		$reqdfieldsn[] = gettext("Bandwidth");
2883
		$reqdfields[] = "burst";
2884
		$reqdfieldsn[] = gettext("Burst");
2885
		$reqdfields[] = "bandwidthtype";
2886
		$reqdfieldsn[] = gettext("Bandwidthtype");
2887
		$reqdfields[] = "newname";
2888
		$reqdfieldsn[] = gettext("Name");
2889

    
2890
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2891

    
2892
		if ($data['plr'] && ((!is_numeric($data['plr'])) ||
2893
			($data['plr'] <= 0 && $data['plr'] > 1))) 
2894
				$input_errors[] = gettext("Plr must be an integer between 1 and 100.");
2895
		if (($data['buckets'] && (!is_numeric($data['buckets']))) ||
2896
			($data['buckets'] < 1 && $data['buckets'] > 100)) 
2897
				$input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
2898
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) 
2899
            		$input_errors[] = gettext("Queue limit must be an integer");
2900
        	if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname']))
2901
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2902
        	if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name']))
2903
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2904
                if (isset($data['maskbits']) && ($data['maskbits'] <> ""))
2905
			if ((!is_numeric($data['maskbits'])) || ($data['maskbits'] <= 0) || ($data['maskbits'] > 32))
2906
				$input_errors[] = gettext("IPV4 bit mask must be blank or numeric value between 1 and 32.");
2907
		if (isset($data['maskbitsv6']) && ($data['maskbitsv6'] <> ""))
2908
			if ((!is_numeric($data['maskbitsv6'])) || ($data['maskbitsv6'] <= 0) || ($data['maskbitsv6'] > 128))
2909
				$input_errors[] = gettext("IPV6 bit mask must be blank or numeric value between 1 and 128.");
2910
	}
2911
	
2912
	function build_mask_rules(&$pfq_rule) {
2913
		$mask = $this->GetMask();
2914
		if (!empty($mask['type'])) {
2915
			if ($mask['type'] <> 'none')
2916
				$pfq_rule .= " mask";
2917
			switch ($mask['type']) {
2918
			case 'srcaddress':
2919
				if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> ""))
2920
					$pfq_rule .= " src-ip6 /" . $mask['bitsv6'];
2921
				else
2922
					$pfq_rule .= " src-ip6 /128";
2923
                                if (!empty($mask['bits']) && ($mask['bits'] <> ""))
2924
                                        $pfq_rule .= sprintf(" src-ip 0x%x", gen_subnet_mask_long($mask['bits']));
2925
                                else
2926
					$pfq_rule .= " src-ip 0xffffffff";
2927
				break;
2928
			case 'dstaddress':
2929
				if (!empty($mask['bitsv6']) && ($mask['bitsv6'] <> ""))
2930
					$pfq_rule .= " dst-ip6 /" . $mask['bitsv6'];
2931
				else
2932
					$pfq_rule .= " dst-ip6 /128";
2933
                                if (!empty($mask['bits']) && ($mask['bits'] <> ""))
2934
                                        $pfq_rule .= sprintf(" dst-ip 0x%x", gen_subnet_mask_long($mask['bits']));
2935
                                else
2936
					$pfq_rule .= " dst-ip 0xffffffff";
2937
				break;
2938
			default:
2939
				break;
2940
			}
2941
		}            
2942
	}
2943
        
2944
}
2945

    
2946
class dnpipe_class extends dummynet_class {
2947
        var $delay;
2948
	var $qbandwidth = array();
2949
	var $qbandwidthtype;
2950

    
2951
		/* This is here to help on form building and building rules/lists */
2952
        var $subqueues = array();
2953

    
2954
	function CanHaveChildren() {
2955
	        return true;
2956
        }
2957
	function SetDelay($delay) {
2958
		$this->delay = $delay;
2959
	}
2960
	function GetDelay() {
2961
		return $this->delay;
2962
	}
2963
	function delete_queue() {
2964
		cleanup_dnqueue_from_rules($this->GetQname());
2965
		foreach ($this->subqueues as $q)
2966
			$q->delete_queue();
2967
		unset_dn_object_by_reference($this->GetLink());
2968
		mwexec("/sbin/ipfw pipe delete " . $this->GetNumber());
2969
        }
2970
        function GetBandwidth() {
2971
                return $this->qbandwidth;
2972
        }
2973
        function SetBandwidth($bandwidth) {
2974
                $this->qbandwidth = $bandwidth;
2975
        }
2976
		function GetBurst() {
2977
				return $this->qburst;
2978
		}
2979
		function SetBurst($burst) {
2980
				$this->qburst = $burst;
2981
		}
2982

    
2983
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
2984

    
2985
		if (!is_array($this->subqueues))
2986
			$this->subqueues = array();
2987

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

    
3006
	function &get_queue_list($q = null) {
3007
		$qlist = array();
3008

    
3009
		$qlist[$this->GetQname()] = $this->GetNumber();
3010
		if (is_array($this->subqueues)) {
3011
			foreach ($this->subqueues as $queue)
3012
				$queue->get_queue_list(&$qlist);
3013
		}
3014
		return $qlist;
3015
	}
3016

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

    
3030
	function &find_parentqueue($pipe, $qname) {
3031
		return NULL;
3032
       	}
3033

    
3034
	function validate_input($data, &$input_errors) {
3035
		parent::validate_input($data, $input_errors);
3036

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

    
3066
	function ReadConfig(&$q) {
3067
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3068
			$this->SetQname($q['newname']);
3069
		} else if (!empty($q['newname'])) {
3070
			$this->SetQname($q['newname']);
3071
		} else {
3072
			$this->SetQname($q['name']);
3073
		}
3074
		$this->SetNumber($q['number']);
3075

    
3076
		if (!empty($_POST)) {
3077
			$bandwidth = array();
3078
			for ($i = 0; $i < 30; $i++) {
3079
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") { 
3080
					$bw = array();
3081
					$bw['bw'] = $q["bandwidth{$i}"];
3082
					$bw['burst'] = $q["burst{$i}"];
3083
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"])
3084
						$bw['bwscale'] = $q["bwtype{$i}"];
3085
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"])
3086
						$bw['bwsched'] = $q["bwsched{$i}"];
3087
					$bandwidth[] = $bw;
3088
				}
3089
			}
3090
			$this->SetBandwidth($bandwidth);
3091
		}
3092
		
3093
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item'])) {
3094
			$this->SetBandwidth($q['bandwidth']['item']);
3095
			$this->SetBurst($q['burst']['item']);
3096
		}
3097
			
3098
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
3099
              		$this->SetQlimit($q['qlimit']);
3100
		else
3101
              		$this->SetQlimit("");
3102
		if (isset($q['mask']) && $q['mask'] <> "")
3103
			$masktype = $q['mask'];
3104
		else
3105
			$masktype = "";
3106
		if (isset($q['maskbits']) && $q['maskbits'] <> "")
3107
			$maskbits = $q['maskbits'];
3108
		else
3109
			$maskbits = "";
3110
		if (isset($q['maskbitsv6']) && $q['maskbitsv6'] <> "")
3111
			$maskbitsv6 = $q['maskbitsv6'];
3112
		else
3113
			$maskbitsv6 = "";
3114
		$this->SetMask(array("type" => $masktype, "bits" => $maskbits, "bitsv6" => $maskbitsv6));
3115
		if (isset($q['buckets']) && $q['buckets'] <> "")
3116
              		$this->SetBuckets($q['buckets']);
3117
		else
3118
              		$this->SetBuckets("");
3119
            	if (isset($q['plr']) && $q['plr'] <> "")
3120
            		$this->SetPlr($q['plr']);
3121
		else
3122
            		$this->SetPlr("");
3123
		if (isset($q['delay']) && $q['delay'] <> "")
3124
            		$this->SetDelay($q['delay']);
3125
		else
3126
			$this->SetDelay(0);
3127
            	if (isset($q['description']) && $q['description'] <> "")
3128
			$this->SetDescription($q['description']);
3129
		else
3130
			$this->SetDescription("");
3131
		$this->SetEnabled($q['enabled']);
3132

    
3133
        }
3134

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

    
3147
		return $tree;
3148
	}
3149

    
3150
        function build_rules() {
3151
		global $config, $time_based_rules;
3152

    
3153
		if ($this->GetEnabled() == "")
3154
			return;
3155

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

    
3194
		if ($this->GetQlimit())
3195
			$pfq_rule .= " queue " . $this->GetQlimit();
3196
		if ($this->GetPlr())
3197
			$pfq_rule .= " plr " . $this->GetPlr();
3198
		if ($this->GetBuckets())
3199
			$pfq_rule .= " buckets " . $this->GetBuckets();
3200
		if ($this->GetDelay())
3201
			$pfq_rule .= " delay " . $this->GetDelay();
3202
		$this->build_mask_rules($pfq_rule);
3203

    
3204
		$pfq_rule .= "\n";
3205

    
3206
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3207
			foreach ($this->subqueues as $q)
3208
			$pfq_rule .= $q->build_rules();
3209
		}
3210
		$pfq_rule .= " \n";
3211

    
3212
		return $pfq_rule;
3213
        }
3214

    
3215
	function update_dn_data(&$data) { 
3216
		$this->ReadConfig($data);
3217
	}
3218

    
3219
	function build_javascript() {
3220
		global $g, $config;
3221

    
3222
		$javasr = parent::build_javascript();
3223
		
3224
		//build list of schedules
3225
		$schedules = "<option value='none'>none</option>";
3226
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3227
			foreach ($config['schedules']['schedule'] as $schedule) {
3228
				if ($schedule['name'] <> "")
3229
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3230
			}
3231
		}
3232
		$bwopt = "";
3233
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw)
3234
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3235

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

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

    
3278
EOD;
3279

    
3280
	       return $javasr;
3281
	}
3282

    
3283
        function build_form() { 
3284
		global $g, $config;
3285

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

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

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

    
3456
		return $form;
3457

    
3458
		}
3459

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

    
3478
		$cflink['enabled'] = $this->GetEnabled();
3479
		$cflink['buckets'] = $this->GetBuckets();
3480
		$mask = $this->GetMask();
3481
		$cflink['mask'] = $mask['type'];
3482
		$cflink['maskbits'] = $mask['bits'];
3483
                $cflink['maskbitsv6'] = $mask['bitsv6'];
3484
		$cflink['delay'] = $this->GetDelay();
3485
	}
3486

    
3487
}
3488

    
3489
class dnqueue_class extends dummynet_class {
3490
        var $pipeparent;
3491
        var $weight;
3492

    
3493
        function GetWeight() {
3494
                return $this->weight;
3495
        }
3496
        function SetWeight($weight) {
3497
                $this->weight = $weight;
3498
        }
3499
	function GetPipe() {
3500
		return $this->pipeparent;
3501
	}
3502
	function SetPipe($pipe) {
3503
		$this->pipeparent = $pipe;
3504
	}
3505

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

    
3509
	function delete_queue() {
3510
		cleanup_dnqueue_from_rules($this->GetQname());
3511
		unset_dn_object_by_reference($this->GetLink());
3512
		mwexec("/sbin/ipfw queue delete " . $this->GetNumber());
3513
        }
3514

    
3515
	function validate_input($data, &$input_errors) {
3516
		parent::validate_input($data, $input_errors);
3517

    
3518
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3519
			($data['weight'] < 1 && $data['weight'] > 100))) 
3520
				$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
3521
	}
3522

    
3523
        /*
3524
         * Should search even its children
3525
         */
3526
        function &find_queue($pipe, $qname) {
3527
                if ($qname == $this->GetQname()) 
3528
                	return $this;
3529
		else
3530
			return NULL;
3531
        }
3532

    
3533
	function &find_parentqueue($pipe, $qname) {
3534
		return $this->qparent;
3535
        }
3536

    
3537
        function &get_queue_list(&$qlist) {
3538
		if ($this->GetEnabled() == "")
3539
			return;
3540
        	$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3541
        }		
3542

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

    
3580
	function build_tree() {
3581
		$parent =& $this->GetParent();
3582
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">"; 
3583
		$tree .= $this->GetQname() . "</a>";
3584
		$tree .= "</li>";
3585

    
3586
		return $tree;
3587
	}
3588

    
3589
        function build_rules() {
3590
		if ($this->GetEnabled() == "")
3591
			return; 
3592

    
3593
		$parent =& $this->GetParent();
3594
            	$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
3595
		if ($this->GetQlimit())
3596
                    	$pfq_rule .= " queue " . $this->GetQlimit();
3597
		if ($this->GetWeight())
3598
			$pfq_rule .= " weight " . $this->GetWeight();
3599
		if ($this->GetBuckets())
3600
			$pfq_rule .= " buckets " . $this->GetBuckets();
3601
		$this->build_mask_rules($pfq_rule);
3602
		$pfq_rule .= "\n";
3603

    
3604
		return $pfq_rule;
3605
	}
3606

    
3607
        function build_javascript() {
3608
		return parent::build_javascript();
3609
	}
3610

    
3611

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

    
3728
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3729
		$form .= " value=\"" . $this->GetPipe() . "\" />";
3730

    
3731
		return $form;
3732

    
3733
	}
3734

    
3735
        function update_dn_data(&$data) { 
3736
		$this->ReadConfig($data);
3737
	}
3738

    
3739
	function wconfig() {
3740
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3741
            	if (!is_array($cflink))
3742
            		$cflink = array();
3743
		$cflink['name'] = $this->GetQname();
3744
		$cflink['number'] = $this->GetNumber();
3745
            	$cflink['qlimit'] = $this->GetQlimit();
3746
            	$cflink['description'] = $this->GetDescription();
3747
		$cflink['weight'] = $this->GetWeight();
3748
		$cflink['enabled'] = $this->GetEnabled();
3749
		$cflink['buckets'] = $this->GetBuckets();
3750
		$mask = $this->GetMask();
3751
		$cflink['mask'] = $mask['type'];
3752
		$cflink['maskbits'] = $mask['bits'];
3753
                $cflink['maskbitsv6'] = $mask['bitsv6'];
3754
	}
3755
}
3756

    
3757
// List of layer7 objects
3758
$layer7_rules_list = array();
3759

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

    
3856
	return $tree;
3857
    }
3858
    
3859
    function build_form() {
3860
        $form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br/>";
3861
	$form .= gettext("Enable/Disable");
3862
	$form .= "</td><td class=\"vncellreq\">";
3863
	$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\" ";
3864
	if ($this->GetREnabled() == "on") {
3865
       	    $form .=  "checked=\"checked\"";
3866
	}
3867
	$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable layer7 Container") . "</span>";
3868
	$form .= "</td></tr>";
3869
        $form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br/><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3870
	$form .= "<td class=\"vncellreq\">";
3871
	$form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
3872
	$form .= $this->GetRName()."\" />";
3873
	$form .= "</td></tr>";
3874
	$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3875
	$form .= "<td class=\"vncellreq\">";
3876
	$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"40\" id=\"description\" name=\"description\" value=\"";
3877
	$form .= $this->GetRDescription();
3878
	$form .= "\" />";
3879
	$form .= "<br/> <span class=\"vexpl\">";
3880
	$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3881
	$form .= "</td></tr>";
3882

    
3883
	return $form;
3884
    }
3885
    
3886
    //Write the setting to the $config array
3887
    function wconfig() {
3888
	global $config;
3889

    
3890
	if(!is_array($config['l7shaper']['container'])) {
3891
		$config['l7shaper']['container'] = array();
3892
	}
3893
        //
3894
        $cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
3895
	// Test if this rule does exists already
3896
	if(!$cflink) {
3897
		$cflink =& $config['l7shaper']['container'][];
3898
	}
3899
	$cflink['name'] = $this->GetRName();
3900
        $cflink['enabled'] = $this->GetREnabled();
3901
        $cflink['description'] = $this->GetRDescription();
3902
        $cflink['divert_port'] = $this->GetRPort();
3903
        
3904
	//Destroy previously existent rules
3905
	if(is_array($cflink['rules'])) {
3906
		unset($cflink['l7rules']);
3907
	}
3908

    
3909
        $cflink['l7rules'] = array();
3910

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

    
3943
	shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3944
        
3945
        if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container']))
3946
            $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3947
    }
3948
    
3949
    function delete_l7c() {
3950
	mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
3951
	unset_l7_object_by_reference($this->GetRName());
3952
	cleanup_l7_from_rules($this->GetRName());
3953
    }
3954
}
3955

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

    
4013
/*
4014
 * This function allows to return an array with all the used divert socket ports
4015
 */
4016
function get_divert_ports() {
4017
    global $layer7_rules_list;
4018
    $dports = array();
4019
    
4020
    foreach($layer7_rules_list as $l7r)
4021
        $dports[] = $l7r->GetRPort();
4022
    
4023
    return $dports;
4024
}
4025

    
4026
function &get_l7c_reference_to_me_in_config(&$name) {
4027
	global $config;
4028

    
4029
	$ptr = NULL;
4030

    
4031
	if(is_array($config['l7shaper']['container'])) {
4032
		foreach($config['l7shaper']['container'] as $key => $value) {
4033
			if($value['name'] == $name)
4034
				$ptr =& $config['l7shaper']['container'][$key];
4035
		}
4036
	}	
4037
	return $ptr;
4038
// $ptr can be null. has to be checked later
4039
}
4040

    
4041
function unset_l7_object_by_reference(&$name) {
4042
	global $config;
4043
        
4044
	if(is_array($config['l7shaper']['container'])) {
4045
		foreach($config['l7shaper']['container'] as $key => $value) {
4046
			if($value['name'] == $name) {
4047
				unset($config['l7shaper']['container'][$key]['l7rules']);
4048
				unset($config['l7shaper']['container'][$key]);
4049
				break;
4050
			}
4051
		}
4052
	}
4053
}
4054

    
4055
function read_layer7_config() {
4056
    global $layer7_rules_list, $config;
4057
    
4058
    $l7cs = &$config['l7shaper']['container'];
4059
    
4060
    $layer7_rules_list = array();
4061
    
4062
    if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container']))
4063
	return;
4064
    
4065
    foreach ($l7cs as $conf) {
4066
	if (empty($conf['name']))
4067
		continue; /* XXX: grrrrrr at php */ 
4068
        $root =& new layer7();
4069
        $root->ReadConfig($conf['name'],$conf);
4070
        $layer7_rules_list[$root->GetRName()] = &$root;
4071
    }
4072
}
4073

    
4074
function generate_layer7_files() {
4075
    global $layer7_rules_list, $g;
4076
    
4077
    read_layer7_config();
4078
    
4079
    if (!empty($layer7_rules_list)) {
4080
	if (!is_module_loaded("ipdivert.ko"))
4081
		mwexec("/sbin/kldload ipdivert.ko");
4082

    
4083
	mwexec("rm -f {$g['tmp_path']}/*.l7");
4084
    }
4085
    
4086
    foreach($layer7_rules_list as $l7rules) {
4087
        if($l7rules->GetREnabled()) {
4088
            $filename = $l7rules->GetRName() . ".l7";
4089
            $path = "{$g['tmp_path']}/" . $filename;
4090
        
4091
            $rules = $l7rules->build_l7_rules();
4092
        
4093
            $fp = fopen($path,'w');
4094
            fwrite($fp,$rules);
4095
            fclose($fp);
4096
        }
4097
    }
4098
}
4099

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

    
4103
    /*
4104
     * XXX: ermal - Needed ?!
4105
     * read_layer7_config();
4106
     */
4107

    
4108
    foreach($layer7_rules_list as $l7rules) {
4109
        if($l7rules->GetREnabled()) {
4110
            $filename = $l7rules->GetRName() . ".l7";
4111
            $path = "{$g['tmp_path']}/" . $filename;
4112

    
4113
	    unset($l7pid);
4114
	    /* Only reread the configuration rather than restart to avoid loosing information. */
4115
	    exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid);
4116
	    if (count($l7pid) > 0) {
4117
		log_error(sprintf(gettext("Sending HUP signal to %s"), $l7pid[0]));
4118
		mwexec("/bin/kill -HUP {$l7pid[0]}");
4119
	    } else {
4120
		// XXX: Hardcoded number of packets to garbage collect and queue length..
4121
		$ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 8 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
4122
		mwexec_bg($ipfw_classifyd_init);
4123
	    }
4124
        }
4125
    }
4126
}
4127

    
4128
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
4129
function generate_protocols_array() {
4130
	$protocols = return_dir_as_array("/usr/local/share/protocols");
4131
	$protocols_new = array();
4132
	if(is_array($protocols)) {
4133
		foreach($protocols as $key => $proto) {
4134
			if (strstr($proto, ".pat"))
4135
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
4136
		}
4137
		sort($protocols_new);
4138
	}		
4139
	return $protocols_new;
4140
}
4141

    
4142
function get_l7_unique_list() {
4143
	global $layer7_rules_list;
4144

    
4145
	$l7list = array();
4146
	if(is_array($layer7_rules_list)) 
4147
		foreach($layer7_rules_list as $l7c)
4148
			if($l7c->GetREnabled())
4149
				$l7list[] = $l7c->GetRName();
4150

    
4151
	return $l7list;
4152
}
4153

    
4154
// Disable a removed l7 container from the filter
4155
function cleanup_l7_from_rules(&$name) {
4156
	global $config;
4157

    
4158
	if(is_array($config['filter']['rule']))
4159
		foreach ($config['filter']['rule'] as $key => $rule) {
4160
			if ($rule['l7container'] == $name)
4161
				unset($config['filter']['rule'][$key]['l7container']);
4162
		}
4163
}
4164

    
4165
function get_dummynet_name_list() {
4166

    
4167
	$dn_name_list =& get_unique_dnqueue_list();
4168
	$dn_name = array();
4169
	if(is_array($dn_name_list))
4170
		foreach($dn_name_list as $key => $value)
4171
			$dn_name[] = $key;
4172

    
4173
	return $dn_name;
4174

    
4175
}
4176

    
4177
function get_altq_name_list() {
4178
	$altq_name_list =& get_unique_queue_list();
4179
	$altq_name = array();
4180
	if(is_array($altq_name_list))
4181
		foreach($altq_name_list as $key => $aqobj)
4182
			$altq_name[] = $key;
4183

    
4184
	return $altq_name;
4185
}
4186

    
4187
/*
4188
 * XXX: TODO Make a class shaper to hide all these function
4189
 * from the global namespace.
4190
 */
4191

    
4192
/* 
4193
 * This is a layer violation but for now there is no way 
4194
 * i can find to properly do this with PHP.
4195
 */
4196
function altq_get_default_queue($interface) {
4197
	global $altq_list_queues;
4198

    
4199
	$altq_tmp = $altq_list_queues[$interface];
4200
	if ($altq_tmp)
4201
		return $altq_tmp->GetDefaultQueuePresent(); 
4202
	else
4203
		return false;
4204
}
4205

    
4206
function altq_check_default_queues() {
4207
	global $altq_list_queues;
4208

    
4209
	$count = 0;
4210
	if (is_array($altq_list_queues)) {
4211
		foreach($altq_list_queues as $altq) {
4212
			if ($altq->GetDefaultQueuePresent())
4213
				$count++;
4214
		}
4215
	}
4216
	else  $count++;;
4217

    
4218
	return 0;
4219
}
4220

    
4221
function &get_unique_queue_list() {
4222
	global $altq_list_queues;
4223

    
4224
	$qlist = array();
4225
	if (is_array($altq_list_queues)) {
4226
		foreach ($altq_list_queues as $altq) {
4227
			if ($altq->GetEnabled() == "")
4228
				continue;
4229
			$tmplist =& $altq->get_queue_list();
4230
			foreach ($tmplist as $qname => $link) {
4231
				if ($link->GetEnabled() <> "")
4232
					$qlist[$qname] = $link;	
4233
			}
4234
		}
4235
	}
4236
	return $qlist;
4237
}
4238

    
4239
function &get_unique_dnqueue_list() {
4240
	global $dummynet_pipe_list;
4241

    
4242
	$qlist = array();
4243
	if (is_array($dummynet_pipe_list)) {
4244
		foreach ($dummynet_pipe_list as $dn) {
4245
			if ($dn->GetEnabled() == "")
4246
				continue;
4247
			$tmplist =& $dn->get_queue_list();
4248
			foreach ($tmplist as $qname => $link) {
4249
				$qlist[$qname] = $link;	
4250
			}
4251
		}
4252
	}
4253
	return $qlist;
4254
}
4255

    
4256
function ref_on_altq_queue_list($parent, $qname) {
4257
	if (isset($GLOBALS['queue_list'][$qname]))
4258
		$GLOBALS['queue_list'][$qname]++;
4259
	else
4260
		$GLOBALS['queue_list'][$qname] = 1;
4261

    
4262
	unref_on_altq_queue_list($parent);
4263
}
4264

    
4265
function unref_on_altq_queue_list($qname) {
4266
	$GLOBALS['queue_list'][$qname]--;
4267
	if ($GLOBALS['queue_list'][$qname] <= 1)
4268
		unset($GLOBALS['queue_list'][$qname]);	
4269
}
4270

    
4271
function read_altq_config() {
4272
	global $altq_list_queues, $config;
4273
	$path = array();
4274

    
4275
	if (!is_array($config['shaper']))
4276
		$config['shaper'] = array();
4277
	if (!is_array($config['shaper']['queue']))
4278
		$config['shaper']['queue'] = array();
4279
	$a_int = &$config['shaper']['queue'];
4280

    
4281
	$altq_list_queues = array();
4282

    
4283
	if (!is_array($config['shaper']['queue']))
4284
		return;
4285

    
4286
	foreach ($a_int as $key => $conf) {
4287
		$int = $conf['interface'];
4288
		$root =& new altq_root_queue();
4289
		$root->SetInterface($int);
4290
		$altq_list_queues[$root->GetInterface()] = &$root;
4291
		$root->ReadConfig($conf);
4292
		array_push($path, $key);
4293
		$root->SetLink($path);
4294
		if (is_array($conf['queue'])) {
4295
			foreach ($conf['queue'] as $key1 => $q) {
4296
				array_push($path, $key1);
4297
				/* 
4298
				 * XXX: we compeletely ignore errors here but anyway we must have 
4299
				 *	checked them before so no harm should be come from this.
4300
				 */
4301
				$root->add_queue($root->GetInterface(), $q, &$path, $input_errors);
4302
				array_pop($path);
4303
			} 	
4304
		}
4305
		array_pop($path);
4306
	}
4307
}
4308

    
4309
function read_dummynet_config() {
4310
	global $dummynet_pipe_list, $config;
4311
	$path = array();
4312

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

    
4319
	$dummynet_pipe_list = array();
4320

    
4321
	if (!is_array($config['dnshaper']['queue'])
4322
		|| !count($config['dnshaper']['queue']))
4323
		return;
4324

    
4325
	foreach ($a_int as $key => $conf) {
4326
		if (empty($conf['name']))
4327
			continue; /* XXX: grrrrrr at php */ 
4328
		$root =& new dnpipe_class();
4329
		$root->ReadConfig($conf);
4330
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4331
		array_push($path, $key);
4332
		$root->SetLink($path);
4333
		if (is_array($conf['queue'])) {
4334
			foreach ($conf['queue'] as $key1 => $q) {
4335
				array_push($path, $key1);
4336
				/* 
4337
				 * XXX: we compeletely ignore errors here but anyway we must have 
4338
				 *	checked them before so no harm should be come from this.
4339
				 */	
4340
				$root->add_queue($root->GetQname(), $q, &$path, $input_errors);
4341
				array_pop($path);
4342
			} 	
4343
		}
4344
		array_pop($path);
4345
	}
4346
}
4347

    
4348
function get_interface_list_to_show() {
4349
	global $altq_list_queues, $config;
4350
	global $shaperIFlist;
4351

    
4352
	$tree = "";
4353
	foreach ($shaperIFlist as $shif => $shDescr) {
4354
		if ($altq_list_queues[$shif]) {
4355
			continue;
4356
		} else  {
4357
			if (!is_altq_capable(get_real_interface($shif)))
4358
				continue;
4359
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4360
		}
4361
	}
4362

    
4363
	return $tree;
4364
}
4365

    
4366
function filter_generate_altq_queues() {
4367
	global $altq_list_queues;
4368

    
4369
	read_altq_config();
4370

    
4371
	$altq_rules = "";
4372
	foreach ($altq_list_queues as $altq) 
4373
		$altq_rules .= $altq->build_rules();
4374

    
4375
	return $altq_rules;
4376
}
4377

    
4378
function dnqueue_find_nextnumber() {
4379
	global $dummynet_pipe_list;
4380

    
4381
	$dnused = array();
4382
	if (is_array($dummynet_pipe_list)) {
4383
		foreach ($dummynet_pipe_list as $dn) {
4384
			$tmplist =& $dn->get_queue_list();
4385
			foreach ($tmplist as $qname => $link) {
4386
				if ($link[0] == "?")
4387
					$dnused[$qname] = substr($link, 1);
4388
			}
4389
		}
4390
	}
4391

    
4392
	sort($dnused, SORT_NUMERIC);
4393
	$dnnumber = 0;
4394
	$found = false;
4395
	foreach ($dnused as $dnnum) {
4396
		if (($dnnum - $dnnumber) > 1) {
4397
			$dnnumber = $dnnum + 1;
4398
			$found = true;
4399
			break;
4400
		} else
4401
			$dnnumber = $dnnum;
4402
	}
4403

    
4404
	if ($found == false)
4405
		$dnnumber++;
4406

    
4407
	unset($dnused, $dnnum, $found);
4408
	return $dnnumber;
4409
}
4410

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

    
4414
	$dnused = array();
4415
	foreach ($dummynet_pipe_list as $dn)
4416
		$dnused[] = $dn->GetNumber();
4417

    
4418
	sort($dnused, SORT_NUMERIC);
4419
	$dnnumber = 0;
4420
	$found = false;
4421
	foreach ($dnused as $dnnum) {
4422
		if (($dnnum - $dnnumber) > 1) {
4423
			$dnnumber = $dnnum + 1;
4424
			$found = true;
4425
			break;
4426
		} else
4427
			$dnnumber = $dnnum;
4428
	}
4429

    
4430
	if ($found == false)
4431
		$dnnumber++;
4432

    
4433
	unset($dnused, $dnnum, $found);
4434
	return $dnnumber;
4435
}
4436

    
4437
function filter_generate_dummynet_rules() {
4438
	global $g, $dummynet_pipe_list;
4439

    
4440
	read_dummynet_config();
4441

    
4442
	if (!empty($dummynet_pipe_list)) {
4443
		if (!is_module_loaded("dummynet.ko")) {
4444
			mwexec("/sbin/kldload dummynet");
4445
			mwexec("/sbin/sysctl net.inet.ip.dummynet.io_fast=1 net.inet.ip.dummynet.hash_size=256");
4446
		}
4447
	}
4448

    
4449
	$dn_rules = "";
4450
	foreach ($dummynet_pipe_list as $dn) 
4451
		$dn_rules .= $dn->build_rules();
4452

    
4453
	if (!empty($dn_rules)) {
4454
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4455
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4456
	}
4457
}
4458

    
4459
function build_iface_without_this_queue($iface, $qname) {
4460
	global $g, $altq_list_queues;
4461
	global $shaperIFlist;
4462

    
4463
	$altq =& $altq_list_queues[$iface];
4464
	if ($altq)
4465
		$scheduler = ": " . $altq->GetScheduler();
4466
	$form = "<tr><td width=\"20%\" >";
4467
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&amp;queue=" . $iface."&amp;action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4468
	$form .= "</td></tr>";
4469
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4470
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4471
	$form .= $iface . "&amp;queue=". $qname . "&amp;action=add\">";
4472
	$form .= "<img src=\"";
4473
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4474
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\" alt=\"clone\" />";
4475
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4476

    
4477
	return $form;
4478

    
4479
}
4480

    
4481

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

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

    
4496
?>
(50-50/66)