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 positive.");
335
                if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig'])))
336
			$input_errors[] = gettext("Tbrsize must be an integer.");
337
                if ($data['tbrconfig'] < 0)
338
			$input_errors[] = gettext("Tbrsize must be positive.");
339
	}
340

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

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

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

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

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

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

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

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

    
456
		return $q;
457
	}
458

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

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

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

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

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

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

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

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

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

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

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

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

    
603
		return $javascript;
604
	}
605

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

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

    
628
		return $form;
629

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

    
721

    
722
		return $form;
723
	}
724

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

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

    
753
}
754

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

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

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

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

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

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

    
925
		return $javascript;
926
	}
927

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

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

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

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

    
956
	 }
957

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

    
966
        function &get_queue_list(&$qlist) {
967

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

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

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

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

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

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

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

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

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

    
1075
	}
1076

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

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

    
1097
		return $tree;
1098
	}
1099

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

    
1151
		$pfq_rule .= " \n";
1152

    
1153
		return $pfq_rule;
1154
	}
1155

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

    
1238
		return $form;
1239
	}
1240

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

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

    
1275
		return $form;
1276

    
1277
	}
1278

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

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

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

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

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

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

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

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

    
1461
		return $q;
1462
	}
1463

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1860
		 $pfq_rule .= " \n";
1861

    
1862
		return $pfq_rule;
1863
	}
1864

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

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

    
1906
		return $javascript;
1907
	}
1908

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

    
2010
		return $form;
2011
	}
2012

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

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

    
2121
class cbq_queue extends priq_queue {
2122
	var $qborrow = "";
2123

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

    
2134
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2135

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

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

    
2170
		return $q;
2171
	}
2172

    
2173
	function copy_queue($interface, &$cflink) {
2174

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

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

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

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

    
2248
	function validate_input($data, &$input_errors) {
2249
		parent::validate_input($data, $input_errors);
2250

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

    
2258
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2259

    
2260
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2261
			$input_errors[] = gettext("Bandwidth must be an integer.");
2262

    
2263

    
2264
		if ($data['bandwidth'] < 0)
2265
                       $input_errors[] = gettext("Bandwidth cannot be negative.");
2266

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

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

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

    
2295
	function build_javascript() {
2296
		return parent::build_javascript();
2297
	}
2298

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

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

    
2387
		$pfq_rule .= " \n";
2388
		return $pfq_rule;
2389
	}
2390

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

    
2429
		return $form;
2430
	}
2431

    
2432
	function update_altq_queue_data(&$data) { 
2433
		$this->ReadConfig($data);
2434
	}
2435

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

    
2474
class fairq_queue extends priq_queue {
2475
	var $hogs;
2476
	var $buckets;
2477

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

    
2494

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

    
2512
	/*
2513
	 * Should search even its children
2514
	 */
2515
	function &find_queue($interface, $qname) {
2516
		if ($qname == $this->GetQname())
2517
			return $this;
2518
	}
2519

    
2520
	function find_parentqueue($interface, $qname) { return; }
2521

    
2522
	function delete_queue() {
2523
		unref_on_altq_queue_list($this->GetQname());
2524
		cleanup_queue_from_rules($this->GetQname());
2525
		unset_object_by_reference($this->GetLink());
2526
	}
2527

    
2528
	function validate_input($data, &$input_errors) {
2529
		parent::validate_input($data, $input_errors);
2530

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

    
2538
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2539

    
2540
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2541
			$input_errors[] = gettext("Bandwidth must be an integer.");
2542

    
2543

    
2544
		if ($data['bandwidth'] < 0)
2545
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2546

    
2547

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

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

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

    
2579
	function build_javascript() {
2580
		return parent::build_javascript();
2581
	}
2582

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

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

    
2658
		$pfq_rule .= " \n";
2659
		return $pfq_rule;
2660
	}
2661

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

    
2710
	function update_altq_queue_data(&$data) { 
2711
		$this->ReadConfig($data);
2712
	}
2713

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

    
2755

    
2756
/*
2757
 * dummynet(4) wrappers.
2758
 */
2759

    
2760

    
2761
/*
2762
 * List of respective objects!
2763
 */
2764
$dummynet_pipe_list = array();
2765

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

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

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

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

    
2886
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2887

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

    
2942
class dnpipe_class extends dummynet_class {
2943
        var $delay;
2944
	var $qbandwidth = array();
2945
	var $qbandwidthtype;
2946

    
2947
		/* This is here to help on form building and building rules/lists */
2948
        var $subqueues = array();
2949

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

    
2979
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
2980

    
2981
		if (!is_array($this->subqueues))
2982
			$this->subqueues = array();
2983

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

    
3002
	function &get_queue_list($q = null) {
3003
		$qlist = array();
3004

    
3005
		$qlist[$this->GetQname()] = $this->GetNumber();
3006
		if (is_array($this->subqueues)) {
3007
			foreach ($this->subqueues as $queue)
3008
				$queue->get_queue_list(&$qlist);
3009
		}
3010
		return $qlist;
3011
	}
3012

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

    
3026
	function &find_parentqueue($pipe, $qname) {
3027
		return NULL;
3028
       	}
3029

    
3030
	function validate_input($data, &$input_errors) {
3031
		parent::validate_input($data, $input_errors);
3032

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

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

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

    
3129
        }
3130

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

    
3143
		return $tree;
3144
	}
3145

    
3146
        function build_rules() {
3147
		global $config, $time_based_rules;
3148

    
3149
		if ($this->GetEnabled() == "")
3150
			return;
3151

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

    
3189
		if ($this->GetQlimit())
3190
			$pfq_rule .= " queue " . $this->GetQlimit();
3191
		if ($this->GetPlr())
3192
			$pfq_rule .= " plr " . $this->GetPlr();
3193
		if ($this->GetBuckets())
3194
			$pfq_rule .= " buckets " . $this->GetBuckets();
3195
		if ($this->GetDelay())
3196
			$pfq_rule .= " delay " . $this->GetDelay();
3197
		$this->build_mask_rules($pfq_rule);
3198

    
3199
		$pfq_rule .= "\n";
3200

    
3201
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3202
			foreach ($this->subqueues as $q)
3203
			$pfq_rule .= $q->build_rules();
3204
		}
3205
		$pfq_rule .= " \n";
3206

    
3207
		return $pfq_rule;
3208
        }
3209

    
3210
	function update_dn_data(&$data) { 
3211
		$this->ReadConfig($data);
3212
	}
3213

    
3214
	function build_javascript() {
3215
		global $g, $config;
3216

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

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

    
3261
function removeBwRow(el) {
3262
	var cel;
3263
	while (el && el.nodeName.toLowerCase() != "tr")
3264
	    el = el.parentNode;
3265
		if (el && el.parentNode) {
3266
			cel = el.getElementsByTagName("td").item(0);
3267
			el.parentNode.removeChild(el);
3268
		}
3269
}
3270
//]]>
3271
</script>
3272

    
3273
EOD;
3274

    
3275
	       return $javasr;
3276
	}
3277

    
3278
        function build_form() { 
3279
		global $g, $config;
3280

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

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

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

    
3452
		return $form;
3453

    
3454
		}
3455

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

    
3474
		$cflink['enabled'] = $this->GetEnabled();
3475
		$cflink['buckets'] = $this->GetBuckets();
3476
		$mask = $this->GetMask();
3477
		$cflink['mask'] = $mask['type'];
3478
		$cflink['maskbits'] = $mask['bits'];
3479
                $cflink['maskbitsv6'] = $mask['bitsv6'];
3480
		$cflink['delay'] = $this->GetDelay();
3481
	}
3482

    
3483
}
3484

    
3485
class dnqueue_class extends dummynet_class {
3486
        var $pipeparent;
3487
        var $weight;
3488

    
3489
        function GetWeight() {
3490
                return $this->weight;
3491
        }
3492
        function SetWeight($weight) {
3493
                $this->weight = $weight;
3494
        }
3495
	function GetPipe() {
3496
		return $this->pipeparent;
3497
	}
3498
	function SetPipe($pipe) {
3499
		$this->pipeparent = $pipe;
3500
	}
3501

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

    
3505
	function delete_queue() {
3506
		cleanup_dnqueue_from_rules($this->GetQname());
3507
		unset_dn_object_by_reference($this->GetLink());
3508
		mwexec("/sbin/ipfw queue delete " . $this->GetNumber());
3509
        }
3510

    
3511
	function validate_input($data, &$input_errors) {
3512
		parent::validate_input($data, $input_errors);
3513

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

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

    
3529
	function &find_parentqueue($pipe, $qname) {
3530
		return $this->qparent;
3531
        }
3532

    
3533
        function &get_queue_list(&$qlist) {
3534
		if ($this->GetEnabled() == "")
3535
			return;
3536
        	$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3537
        }		
3538

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

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

    
3582
		return $tree;
3583
	}
3584

    
3585
        function build_rules() {
3586
		if ($this->GetEnabled() == "")
3587
			return; 
3588

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

    
3600
		return $pfq_rule;
3601
	}
3602

    
3603
        function build_javascript() {
3604
		return parent::build_javascript();
3605
	}
3606

    
3607

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

    
3724
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3725
		$form .= " value=\"" . $this->GetPipe() . "\" />";
3726

    
3727
		return $form;
3728

    
3729
	}
3730

    
3731
        function update_dn_data(&$data) { 
3732
		$this->ReadConfig($data);
3733
	}
3734

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

    
3753
// List of layer7 objects
3754
$layer7_rules_list = array();
3755

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

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

    
3879
	return $form;
3880
    }
3881
    
3882
    //Write the setting to the $config array
3883
    function wconfig() {
3884
	global $config;
3885

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

    
3905
        $cflink['l7rules'] = array();
3906

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

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

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

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

    
4022
function &get_l7c_reference_to_me_in_config(&$name) {
4023
	global $config;
4024

    
4025
	$ptr = NULL;
4026

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

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

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

    
4070
function generate_layer7_files() {
4071
    global $layer7_rules_list, $g;
4072
    
4073
    read_layer7_config();
4074
    
4075
    if (!empty($layer7_rules_list)) {
4076
	if (!is_module_loaded("ipdivert.ko"))
4077
		mwexec("/sbin/kldload ipdivert.ko");
4078

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

    
4096
function layer7_start_l7daemon() {
4097
    global $layer7_rules_list, $g;
4098

    
4099
    /*
4100
     * XXX: ermal - Needed ?!
4101
     * read_layer7_config();
4102
     */
4103

    
4104
    foreach($layer7_rules_list as $l7rules) {
4105
        if($l7rules->GetREnabled()) {
4106
            $filename = $l7rules->GetRName() . ".l7";
4107
            $path = "{$g['tmp_path']}/" . $filename;
4108

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

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

    
4138
function get_l7_unique_list() {
4139
	global $layer7_rules_list;
4140

    
4141
	$l7list = array();
4142
	if(is_array($layer7_rules_list)) 
4143
		foreach($layer7_rules_list as $l7c)
4144
			if($l7c->GetREnabled())
4145
				$l7list[] = $l7c->GetRName();
4146

    
4147
	return $l7list;
4148
}
4149

    
4150
// Disable a removed l7 container from the filter
4151
function cleanup_l7_from_rules(&$name) {
4152
	global $config;
4153

    
4154
	if(is_array($config['filter']['rule']))
4155
		foreach ($config['filter']['rule'] as $key => $rule) {
4156
			if ($rule['l7container'] == $name)
4157
				unset($config['filter']['rule'][$key]['l7container']);
4158
		}
4159
}
4160

    
4161
function get_dummynet_name_list() {
4162

    
4163
	$dn_name_list =& get_unique_dnqueue_list();
4164
	$dn_name = array();
4165
	if(is_array($dn_name_list))
4166
		foreach($dn_name_list as $key => $value)
4167
			$dn_name[] = $key;
4168

    
4169
	return $dn_name;
4170

    
4171
}
4172

    
4173
function get_altq_name_list() {
4174
	$altq_name_list =& get_unique_queue_list();
4175
	$altq_name = array();
4176
	if(is_array($altq_name_list))
4177
		foreach($altq_name_list as $key => $aqobj)
4178
			$altq_name[] = $key;
4179

    
4180
	return $altq_name;
4181
}
4182

    
4183
/*
4184
 * XXX: TODO Make a class shaper to hide all these function
4185
 * from the global namespace.
4186
 */
4187

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

    
4195
	$altq_tmp = $altq_list_queues[$interface];
4196
	if ($altq_tmp)
4197
		return $altq_tmp->GetDefaultQueuePresent(); 
4198
	else
4199
		return false;
4200
}
4201

    
4202
function altq_check_default_queues() {
4203
	global $altq_list_queues;
4204

    
4205
	$count = 0;
4206
	if (is_array($altq_list_queues)) {
4207
		foreach($altq_list_queues as $altq) {
4208
			if ($altq->GetDefaultQueuePresent())
4209
				$count++;
4210
		}
4211
	}
4212
	else  $count++;;
4213

    
4214
	return 0;
4215
}
4216

    
4217
function &get_unique_queue_list() {
4218
	global $altq_list_queues;
4219

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

    
4235
function &get_unique_dnqueue_list() {
4236
	global $dummynet_pipe_list;
4237

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

    
4252
function ref_on_altq_queue_list($parent, $qname) {
4253
	if (isset($GLOBALS['queue_list'][$qname]))
4254
		$GLOBALS['queue_list'][$qname]++;
4255
	else
4256
		$GLOBALS['queue_list'][$qname] = 1;
4257

    
4258
	unref_on_altq_queue_list($parent);
4259
}
4260

    
4261
function unref_on_altq_queue_list($qname) {
4262
	$GLOBALS['queue_list'][$qname]--;
4263
	if ($GLOBALS['queue_list'][$qname] <= 1)
4264
		unset($GLOBALS['queue_list'][$qname]);	
4265
}
4266

    
4267
function read_altq_config() {
4268
	global $altq_list_queues, $config;
4269
	$path = array();
4270

    
4271
	if (!is_array($config['shaper']))
4272
		$config['shaper'] = array();
4273
	if (!is_array($config['shaper']['queue']))
4274
		$config['shaper']['queue'] = array();
4275
	$a_int = &$config['shaper']['queue'];
4276

    
4277
	$altq_list_queues = array();
4278

    
4279
	if (!is_array($config['shaper']['queue']))
4280
		return;
4281

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

    
4305
function read_dummynet_config() {
4306
	global $dummynet_pipe_list, $config;
4307
	$path = array();
4308

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

    
4315
	$dummynet_pipe_list = array();
4316

    
4317
	if (!is_array($config['dnshaper']['queue'])
4318
		|| !count($config['dnshaper']['queue']))
4319
		return;
4320

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

    
4344
function get_interface_list_to_show() {
4345
	global $altq_list_queues, $config;
4346
	global $shaperIFlist;
4347

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

    
4359
	return $tree;
4360
}
4361

    
4362
function filter_generate_altq_queues() {
4363
	global $altq_list_queues;
4364

    
4365
	read_altq_config();
4366

    
4367
	$altq_rules = "";
4368
	foreach ($altq_list_queues as $altq) 
4369
		$altq_rules .= $altq->build_rules();
4370

    
4371
	return $altq_rules;
4372
}
4373

    
4374
function dnqueue_find_nextnumber() {
4375
	global $dummynet_pipe_list;
4376

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

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

    
4400
	if ($found == false)
4401
		$dnnumber++;
4402

    
4403
	unset($dnused, $dnnum, $found);
4404
	return $dnnumber;
4405
}
4406

    
4407
function dnpipe_find_nextnumber() {
4408
	global $dummynet_pipe_list;
4409

    
4410
	$dnused = array();
4411
	foreach ($dummynet_pipe_list as $dn)
4412
		$dnused[] = $dn->GetNumber();
4413

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

    
4426
	if ($found == false)
4427
		$dnnumber++;
4428

    
4429
	unset($dnused, $dnnum, $found);
4430
	return $dnnumber;
4431
}
4432

    
4433
function filter_generate_dummynet_rules() {
4434
	global $g, $dummynet_pipe_list;
4435

    
4436
	read_dummynet_config();
4437

    
4438
	if (!empty($dummynet_pipe_list)) {
4439
		if (!is_module_loaded("dummynet.ko")) {
4440
			mwexec("/sbin/kldload dummynet");
4441
			mwexec("/sbin/sysctl net.inet.ip.dummynet.io_fast=1 net.inet.ip.dummynet.hash_size=256");
4442
		}
4443
	}
4444

    
4445
	$dn_rules = "";
4446
	foreach ($dummynet_pipe_list as $dn) 
4447
		$dn_rules .= $dn->build_rules();
4448

    
4449
	if (!empty($dn_rules)) {
4450
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4451
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4452
	}
4453
}
4454

    
4455
function build_iface_without_this_queue($iface, $qname) {
4456
	global $g, $altq_list_queues;
4457
	global $shaperIFlist;
4458

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

    
4473
	return $form;
4474

    
4475
}
4476

    
4477

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

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

    
4492
?>
(50-50/66)