Projet

Général

Profil

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

univnautes / etc / inc / shaper.inc @ d0f365c2

1
<?php
2
/*
3
	Copyright (C) 2008 Ermal Luçi
4
	All rights reserved.
5

    
6
	Redistribution and use in source and binary forms, with or without
7
	modification, are permitted provided that the following conditions are met:
8

    
9
	1. Redistributions of source code must retain the above copyright notice,
10
	   this list of conditions and the following disclaimer.
11

    
12
	2. Redistributions in binary form must reproduce the above copyright
13
	   notice, this list of conditions and the following disclaimer in the
14
	   documentation and/or other materials provided with the distribution.
15

    
16
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
20
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
	POSSIBILITY OF SUCH DAMAGE.
26

    
27
	pfSense_BUILDER_BINARIES:	/bin/kill	/sbin/kldload	/bin/rm	/bin/ps
28
	pfSense_MODULE:	shaper
29
*/
30

    
31
/* XXX: needs some reducing on include. */
32
/* include all configuration functions. */
33
require_once("globals.inc");
34
require_once("functions.inc");
35
require_once("util.inc");
36
require_once("notices.inc");
37

    
38
/*
39
 * I admit :) this is derived from xmplparse.inc StartElement()
40
 */
41
function &get_reference_to_me_in_config(&$mypath) 
42
{
43
	global $config;
44

    
45
	 $ptr =& $config['shaper'];
46
	foreach ($mypath as $indeks) {
47
		$ptr =& $ptr['queue'][$indeks];
48
	}
49

    
50
	return $ptr;
51
}
52

    
53
function unset_object_by_reference(&$mypath) 
54
{
55
	global $config;
56

    
57
	$ptr =& $config['shaper'];
58
	for ($i = 0; $i < count($mypath) - 1; $i++) {
59
		$ptr =& $ptr['queue'][$mypath[$i]];
60
	}
61
	unset($ptr['queue'][$mypath[$i]]);
62
}
63

    
64
function &get_dn_reference_to_me_in_config(&$mypath) 
65
{
66
	global $config;
67

    
68
	$ptr =& $config['dnshaper'];
69
	foreach ($mypath as $indeks) {
70
		$ptr =& $ptr['queue'][$indeks];
71
	}
72

    
73
	return $ptr;
74
}
75

    
76
function unset_dn_object_by_reference(&$mypath) 
77
{
78
	global $config;
79

    
80
	$ptr =& $config['dnshaper'];
81
	for ($i = 0; $i < count($mypath) - 1; $i++) {
82
		$ptr =& $ptr['queue'][$mypath[$i]];
83
	}
84
	unset($ptr['queue'][$mypath[$i]]);
85
}
86

    
87
function clean_child_queues($type, $mypath) 
88
{
89
	$ref = &get_reference_to_me_in_config($mypath);
90

    
91
	switch ($type) {
92
	case 'HFSC':
93
		if (isset($ref['borrow'])) unset($ref['borrow']);		
94
		if (isset($ref['hogs'])) unset($ref['hogs']);
95
		if (isset($ref['buckets'])) unset($ref['buckets']);
96
		break;
97
	case 'PRIQ':
98
		if (isset($ref['borrow'])) unset($ref['borrow']);		
99
		if (isset($ref['bandwidth'])) unset($ref['bandwidth']);
100
		if (isset($ref['bandwidthtype'])) unset($ref['bandwidthtype']);
101
		/* fall through */
102
	case 'FAIRQ':
103
		if (isset($ref['borrow'])) unset($ref['borrow']);		
104
		/* fall through */
105
	case 'CBQ':
106
		if (isset($ref['realtime'])) unset($ref['realtime']);	
107
		if (isset($ref['realtime1'])) unset($ref['realtime1']);
108
		if (isset($ref['realtime2'])) unset($ref['realtime2']);
109
		if (isset($ref['realtime3'])) unset($ref['realtime3']);
110
		if (isset($ref['upperlimit'])) unset($ref['upperlimit']);
111
		if (isset($ref['upperlimit1'])) unset($ref['upperlimit1']);
112
		if (isset($ref['upperlimit2'])) unset($ref['upperlimit2']);
113
		if (isset($ref['upperlimit3'])) unset($ref['upperlimit3']);
114
		if (isset($ref['linkshare'])) unset($ref['linkshare']);
115
		if (isset($ref['linkshare1'])) unset($ref['linkshare1']);
116
		if (isset($ref['linkshare2'])) unset($ref['linkshare2']);
117
		if (isset($ref['linkshare3'])) unset($ref['linkshare3']);	
118
		if (isset($ref['hogs'])) unset($ref['hogs']);
119
		if (isset($ref['buckets'])) unset($ref['buckets']);
120
		break;
121
	}
122
}
123

    
124
function get_bandwidthtype_scale($type) 
125
{
126
        switch ($type) {
127
        case "Gb":
128
                $factor = 1024 * 1024 * 1024;
129
        	break;
130
        case "Mb":
131
                $factor = 1024 * 1024;
132
        	break;
133
        case "Kb":
134
                $factor = 1024;
135
        	break;
136
        case "b":
137
        default:
138
                $factor = 1;
139
        	break;
140
        }
141
        return intval($factor);
142
}
143

    
144
function get_hfsc_bandwidth($object, $bw) 
145
{
146
	$pattern= "/[0-9]+/";
147
        if (preg_match($pattern, $bw, $match))
148
                $bw_1 = $match[1];
149
        else
150
                return 0;
151
        $pattern= "/(b|Kb|Mb|Gb|%)/";
152
        if (preg_match($pattern, $bw, $match)) {
153
                switch ($match[1]) {
154
                case '%':
155
                        $bw_1 = $bw_1 / 100 * get_interface_bandwidth($object);
156
                        break;
157
                default:
158
                        $bw_1 = $bw_1 * get_bandwidthtype_scale($match[0]);
159
                        break;
160
                }
161
		return floatval($bw_1);
162
        } else
163
                return 0;
164
}
165

    
166
function get_interface_bandwidth($object) 
167
{
168
	global $altq_list_queues;
169

    
170
        $int = $object->GetInterface();
171
        $altq =& $altq_list_queues[$int];
172
        if ($altq) {
173
                $bw_3 = $altq->GetBandwidth();
174
                $bw_3 = $bw_3 *  get_bandwidthtype_scale($altq->GetBwscale());
175
		return floatval($bw_3);
176
        } else
177
		return 0;
178
}
179

    
180
/*
181
 * This is duplicated here since we cannot include guiconfig.inc.
182
 * Including it makes all stuff break.
183
 */
184
function shaper_do_input_validation($postdata, $reqdfields, $reqdfieldsn, $input_errors) 
185
{
186

    
187
        /* check for bad control characters */
188
        foreach ($postdata as $pn => $pd) {
189
                if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
190
                        $input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $pn);
191
                }
192
        }
193

    
194
        for ($i = 0; $i < count($reqdfields); $i++) {
195
                if ($postdata[$reqdfields[$i]] == "") {
196
                        $input_errors[] = sprintf(gettext("The field '%s' is required."), $reqdfieldsn[$i]);
197
                }
198
        }
199
}
200

    
201
function cleanup_queue_from_rules($queue) 
202
{
203
	global $config;
204

    
205
	foreach ($config['filter']['rule'] as $rule) {
206
		if ($rule['defaultqueue'] == $queue)
207
			unset($rule['defaultqueue']);
208
		if ($rule['ackqueue'] == $queue)
209
			unset($rule['ackqueue']);
210
	}
211
}
212

    
213
function cleanup_dnqueue_from_rules($queue) 
214
{
215
	global $config;
216

    
217
	foreach ($config['filter']['rule'] as $rule) {
218
		if ($rule['dnpipe'] == $queue)
219
			unset($rule['dnpipe']);
220
		if ($rule['pdnpipe'] == $queue)
221
			unset($rule['pdnpipe']);
222
	}
223
}
224

    
225
class altq_root_queue {
226
	var $interface;
227
	var $tbrconfig ;
228
	var $bandwidth;
229
	var $bandwidthtype; /* b, Kb, Mb */
230
	var $scheduler;
231
	var $qlimit;
232
	var $queues = array();
233
	var $qenabled = false;
234
	var $link;
235
	var $available_bw; /* in b/s */
236

    
237
	/* Accesor functions */
238
	function GetAvailableBandwidth() {
239
		return $this->available_bw;
240
	}
241
	function SetAvailableBandwidth($bw) {
242
		$this->available_bw = $bw;
243
	}
244
	function GetDefaultQueuePresent() {
245
		if (!empty($this->queues)) {
246
			foreach ($this->queues as $q) {
247
				if ($q->GetDefault())
248
					return true;
249
			}
250
		}
251

    
252
		return false;
253
	}
254
	function SetLink($link) {
255
		$this->link = $link;
256
	}
257
	function GetLink() {
258
		return $this->link;
259
	}	
260
	function GetEnabled() {
261
		return $this->qenabled;
262
	}
263
	function SetEnabled($value) {
264
		$this->qenabled = $value;
265
	}
266
	function CanHaveChildren() {
267
		if ($this->GetScheduler() == "CODELQ")
268
			return false;
269
		else
270
			return true;
271
	}
272
	function CanBeDeleted() {
273
		return false;
274
	}
275
	function GetQname() {
276
		return $this->interface;
277
	}
278
	function SetQname($name) {
279
		$this->interface = trim($name);
280
	}
281
	function GetInterface() {
282
		return $this->interface;
283
	}
284
	function SetInterface($name) {
285
		$this->interface = trim($name);
286
	}
287
	function GetTbrConfig() {
288
		return $this->tbrconfig;
289
	}
290
	function SetTbrConfig($tbrconfig) {
291
		$this->tbrconfig = $tbrconfig;
292
	}
293
	function GetBandwidth() {
294
		return $this->bandwidth;
295
	}
296
	function SetBandwidth($bw) {
297
		$this->bandwidth = $bw;
298
	}
299
	function GetBwscale() {
300
		return $this->bandwidthtype;
301
	}
302
	function SetBwscale($bwscale) {
303
		$this->bandwidthtype = $bwscale;
304
	}
305
	function GetScheduler() {
306
		return $this->scheduler;
307
	}
308
	function SetScheduler($scheduler) {
309
		$this->scheduler = trim($scheduler);
310
	}
311
	function GetQlimit() {
312
		return $this->qlimit;
313
	}
314
	function SetQlimit($limit) {
315
		$this->qlimit = $limit;
316
	}
317

    
318
	function validate_input($data, &$input_errors) {
319

    
320
		$reqdfields[] = "bandwidth";
321
		$reqdfieldsn[] = gettext("Bandwidth");
322
		$reqdfields[] = "bandwidthtype";
323
		$reqdfieldsn[] = gettext("Bandwidthtype");
324

    
325
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
326

    
327
                if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
328
			$input_errors[] = gettext("Bandwidth must be an integer.");
329
                if ($data['bandwidth'] < 0)
330
			$input_errors[] = gettext("Bandwidth cannot be negative.");
331
                if ($data['qlimit'] && (!is_numeric($data['qlimit'])))
332
			$input_errors[] = gettext("Qlimit must be an integer.");
333
	 	if ($data['qlimit'] < 0)
334
			$input_errors[] = gettext("Qlimit must be positive.");
335
                if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig'])))
336
			$input_errors[] = gettext("Tbrsize must be an integer.");
337
                if ($data['tbrconfig'] < 0)
338
			$input_errors[] = gettext("Tbrsize must be positive.");
339
	}
340

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

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

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

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

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

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

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

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

    
456
		return $q;
457
	}
458

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

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

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

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

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

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

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

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

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

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

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

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

    
603
		return $javascript;
604
	}
605

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

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

    
628
		return $form;
629

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

    
721

    
722
		return $form;
723
	}
724

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

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

    
753
}
754

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

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

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

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

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

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

    
925
		return $javascript;
926
	}
927

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

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

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

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

    
956
	 }
957

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

    
966
        function &get_queue_list(&$qlist) {
967

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

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

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

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

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

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

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

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

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

    
1075
	}
1076

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

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

    
1097
		return $tree;
1098
	}
1099

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

    
1151
		$pfq_rule .= " \n";
1152

    
1153
		return $pfq_rule;
1154
	}
1155

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

    
1238
		return $form;
1239
	}
1240

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

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

    
1275
		return $form;
1276

    
1277
	}
1278

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

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

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

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

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

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

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

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

    
1461
		return $q;
1462
	}
1463

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1860
		 $pfq_rule .= " \n";
1861

    
1862
		return $pfq_rule;
1863
	}
1864

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

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

    
1906
		return $javascript;
1907
	}
1908

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

    
2010
		return $form;
2011
	}
2012

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

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

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

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

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

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

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

    
2173
		return $q;
2174
	}
2175

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

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

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

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

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

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

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

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

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

    
2266

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

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

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

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

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

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

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

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

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

    
2432
		return $form;
2433
	}
2434

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

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

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

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

    
2500

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

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

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

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

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

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

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

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

    
2549

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

    
2553

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

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

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

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

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

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

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

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

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

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

    
2764

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

    
2769

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3138
        }
3139

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

    
3152
		return $tree;
3153
	}
3154

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

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

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

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

    
3208
		$pfq_rule .= "\n";
3209

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

    
3216
		return $pfq_rule;
3217
        }
3218

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

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

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

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

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

    
3282
EOD;
3283

    
3284
	       return $javasr;
3285
	}
3286

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

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

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

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

    
3461
		return $form;
3462

    
3463
		}
3464

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

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

    
3492
}
3493

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

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

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

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

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

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

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

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

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

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

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

    
3599
		return $tree;
3600
	}
3601

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

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

    
3617
		return $pfq_rule;
3618
	}
3619

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

    
3624

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

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

    
3744
		return $form;
3745

    
3746
	}
3747

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4042
	$ptr = NULL;
4043

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

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

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

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

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

    
4113
function layer7_start_l7daemon() {
4114
    global $layer7_rules_list, $g;
4115

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

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

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

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

    
4155
function get_l7_unique_list() {
4156
	global $layer7_rules_list;
4157

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

    
4164
	return $l7list;
4165
}
4166

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

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

    
4178
function get_dummynet_name_list() {
4179

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

    
4186
	return $dn_name;
4187

    
4188
}
4189

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

    
4197
	return $altq_name;
4198
}
4199

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

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

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

    
4219
function altq_check_default_queues() {
4220
	global $altq_list_queues;
4221

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

    
4231
	return 0;
4232
}
4233

    
4234
function &get_unique_queue_list() {
4235
	global $altq_list_queues;
4236

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

    
4252
function &get_unique_dnqueue_list() {
4253
	global $dummynet_pipe_list;
4254

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

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

    
4275
	unref_on_altq_queue_list($parent);
4276
}
4277

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

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

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

    
4294
	$altq_list_queues = array();
4295

    
4296
	if (!is_array($config['shaper']['queue']))
4297
		return;
4298

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

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

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

    
4332
	$dummynet_pipe_list = array();
4333

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

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

    
4361
function get_interface_list_to_show() {
4362
	global $altq_list_queues, $config;
4363
	global $shaperIFlist;
4364

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

    
4376
	return $tree;
4377
}
4378

    
4379
function filter_generate_altq_queues() {
4380
	global $altq_list_queues;
4381

    
4382
	read_altq_config();
4383

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

    
4388
	return $altq_rules;
4389
}
4390

    
4391
function dnqueue_find_nextnumber() {
4392
	global $dummynet_pipe_list;
4393

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

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

    
4417
	if ($found == false)
4418
		$dnnumber++;
4419

    
4420
	unset($dnused, $dnnum, $found);
4421
	return $dnnumber;
4422
}
4423

    
4424
function dnpipe_find_nextnumber() {
4425
	global $dummynet_pipe_list;
4426

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

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

    
4443
	if ($found == false)
4444
		$dnnumber++;
4445

    
4446
	unset($dnused, $dnnum, $found);
4447
	return $dnnumber;
4448
}
4449

    
4450
function filter_generate_dummynet_rules() {
4451
	global $g, $dummynet_pipe_list;
4452

    
4453
	read_dummynet_config();
4454

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

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

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

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

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

    
4490
	return $form;
4491

    
4492
}
4493

    
4494

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

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

    
4509
?>
(50-50/66)