Project

General

Profile

Download (138 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	Copyright (C) 2008 Ermal Luçi
4
	All rights reserved.
5

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

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

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

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

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

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

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

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

    
50
	return $ptr;
51
}
52

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

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

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

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

    
73
	return $ptr;
74
}
75

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
315
	function validate_input($data, &$input_errors) {
316

    
317
		$reqdfields[] = "bandwidth";
318
		$reqdfieldsn[] = gettext("Bandwidth");
319
		$reqdfields[] = "bandwidthtype";
320
		$reqdfieldsn[] = gettext("Bandwidthtype");
321

    
322
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
323

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

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

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

    
386
	function &get_queue_list($q = null) {
387
		$qlist = array();
388

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

    
397
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
398

    
399
		if (!is_array($this->queues))
400
			$this->queues = array();
401

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

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

    
453
		return $q;
454
	}
455

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

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

    
482
	function build_tree() {
483
		global $shaperIFlist;
484

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

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

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

    
517
	/*
518
	 * First it spits:
519
	 * altq on $interface ..............
520
	 *      then it goes like
521
	 *      foreach ($queues as $qkey => $queue)
522
	 *              this->queues[$qkey]->build_rule();
523
	 */
524
	function build_rules(&$default = false) {
525
		if (count($this->queues) > 0 && $this->GetEnabled() == "on") {
526
			$default = false;
527
			$rules = " altq on  " . get_real_interface($this->GetInterface());
528
			if ($this->GetScheduler())
529
				$rules .= " ".strtolower($this->GetScheduler());
530
			if ($this->GetBandwidth()) {
531
				$rules .= " bandwidth ".trim($this->GetBandwidth());
532
				if ($this->GetBwscale())
533
					$rules .= $this->GetBwscale();
534
			}
535
			if ($this->GetTbrConfig())
536
				$rules .= " tbrsize ".$this->GetTbrConfig();
537
			if (count($this->queues)) {
538
				$i = count($this->queues);
539
				$rules .= " queue { ";
540
				foreach ($this->queues as $qkey => $qnone) {
541
					if ($i > 1) {
542
						$i--;
543
						$rules .= " {$qkey}, ";
544
					} else
545
						$rules .= " {$qkey} ";
546
				}
547
				$rules .= " } \n";
548
				foreach ($this->queues as $q) {
549
					$rules .= $q->build_rules($default);
550
				}
551
			}
552
			if ($default == false) {
553
				$error = "SHAPER: no default queue specified for interface ". $this->GetInterface() . ". The interface queue will be enforced as default.";
554
				file_notice("Shaper", $error, "Error occurred", "");
555
				unset($error);
556
				return "\n";
557
			} 
558
			$frule .= $rules;
559
		}
560
		$rules .= " \n";
561
		return $rules;
562
	}
563

    
564
	function build_javascript() {
565
		$javascript = "<script type=\"text/javascript\">";
566
		$javascript .= "//<![CDATA[";
567
		$javascript .= "function mySuspend() {";
568
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
569
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden'; ";
570
		$javascript .= "else if (document.all)";
571
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
572
		$javascript .= "}";
573

    
574
		$javascript .= "function myResume() {";
575
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
576
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';";
577
		$javascript .= "else if (document.all) ";
578
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';";
579
		$javascript .= "}";
580
		$javascript .= "//]]>";
581
		$javascript .= "</script>";
582

    
583
		return $javascript;
584
	}
585

    
586
	function build_shortform() {
587
		global $g;
588

    
589
		$altq =& $this;
590
		if ($altq)
591
			$scheduler = ": " . $altq->GetScheduler();
592
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
593
		$form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=". $this->GetInterface()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .": ".$scheduler."</a>";
594
		$form .= "</td></tr>";
595
		$form .= "<tr>";
596
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
597
		$form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale();
598
		$form .= "</td><td width=\"50%\"></td></tr>";
599
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
600
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
601
		$form .= $this->GetInterface() . "&amp;queue=";
602
		$form .= $this->GetQname() . "&amp;action=delete\">";
603
		$form .= "<img src=\"";
604
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
605
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Disable shaper on interface\" alt=\"disable\" />";
606
		$form .= "<span>Disable shaper on interface</span></a></td></tr>";
607

    
608
		return $form;
609

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

    
697

    
698
		return $form;
699
	}
700

    
701
	function update_altq_queue_data(&$data) { 
702
		$this->ReadConfig($data);
703
	}
704

    
705
	/*
706
	 * Should call on each of it queues and subqueues
707
	 * the same function much like build_rules();
708
	 */
709
	function wconfig() { 
710
		$cflink = &get_reference_to_me_in_config($this->GetLink());
711
		if (!is_array($cflink))
712
			$cflink = array();
713
		$cflink['interface'] = $this->GetInterface();	
714
		$cflink['name'] = $this->GetQname();
715
		$cflink['scheduler'] = $this->GetScheduler();
716
		$cflink['bandwidth'] = $this->GetBandwidth();
717
		$cflink['bandwidthtype'] = $this->GetBwscale();
718
		$cflink['qlimit'] = trim($this->GetQlimit());
719
		if (empty($cflink['qlimit']))
720
			unset($cflink['qlimit']);
721
		$cflink['tbrconfig'] = trim($this->GetTbrConfig());
722
		if (empty($cflink['tbrconfig']))
723
			unset($cflink['tbrconfig']);
724
		$cflink['enabled'] = $this->GetEnabled();
725
		if (empty($cflink['enabled']))
726
			unset($cflink['enabled']);
727
	}
728

    
729
}
730

    
731
class priq_queue {
732
	var $qname;
733
	var $qinterface; 
734
	var $qlimit;
735
	var $qpriority;
736
	var $description;
737
	var $isparent;
738
	var $qbandwidth;
739
	var $qbandwidthtype;
740
	var $qdefault = "";
741
	var $qrio = "";
742
	var $qred = "";
743
	var $qecn = "";
744
	var $qack;
745
	var $qenabled = "";
746
	var $qparent;
747
	var $link;
748
	var $available_bw; /* in b/s */
749

    
750
	/* This is here to help with form building and building rules/lists */
751
	var $subqueues = array();
752

    
753
	/* Accesor functions */
754
	function GetAvailableBandwidth() {
755
		return $this->available_bw;
756
	}
757
	function SetAvailableBandwidth($bw) {
758
		$this->available_bw = $bw;
759
	}
760
	function SetLink($link) {
761
		$this->link = $link;
762
	}
763
	function GetLink() {
764
		return $this->link;
765
	}
766
	function &GetParent() {
767
		return $this->qparent;
768
	}
769
	function SetParent(&$parent) {
770
		$this->qparent = &$parent;
771
	}
772
	function GetEnabled() {
773
		return $this->qenabled;
774
	}
775
	function SetEnabled($value) {
776
		$this->qenabled = $value;
777
	}
778
	function CanHaveChildren() {
779
		return false;
780
	}
781
	function CanBeDeleted() {
782
		return true;
783
	}
784
	function GetQname() {
785
		return $this->qname;
786
	}
787
	function SetQname($name) {
788
		$this->qname = trim($name);
789
	}
790
	function GetBandwidth() {
791
		return $this->qbandwidth;
792
	}
793
	function SetBandwidth($bandwidth) {
794
		$this->qbandwidth = $bandwidth;
795
	}
796
	function GetInterface() {
797
		return $this->qinterface;
798
	}
799
	function SetInterface($name) {
800
		$this->qinterface = trim($name);
801
	}
802
	function GetQlimit() {
803
		return $this->qlimit;
804
	}
805
	function SetQlimit($limit) {
806
		$this->qlimit = $limit;
807
	}
808
	function GetQpriority() {
809
		return $this->qpriority;
810
	}
811
	function SetQpriority($priority) {
812
		$this->qpriority = $priority;
813
	}
814
	function GetDescription() {
815
		return $this->description;
816
	}
817
	function SetDescription($str) {
818
		$this->description = trim($str);
819
	}
820
	function GetFirstime() {
821
		return $this->firsttime;
822
	}
823
	function SetFirsttime($number) {
824
		$this->firsttime = $number;
825
	}
826
	function GetBwscale() {
827
		return $this->qbandwidthtype;
828
	}
829
	function SetBwscale($scale) {
830
		$this->qbandwidthtype = $scale;
831
	}
832
	function GetDefaultQueuePresent() {
833
		if ($this->GetDefault())
834
			return true;
835
		if (!empty($this->subqueues)) {
836
			foreach ($this->subqueues as $q) {
837
				if ($q->GetDefault())
838
					return true;
839
			}
840
		}
841

    
842
		return false;
843
	}
844
	function GetDefault() {
845
		return $this->qdefault;
846
	}
847
	function SetDefault($value = false) {
848
		$this->qdefault = $value;
849
	}
850
	function GetRed() {
851
		return $this->qred;
852
	}
853
	function SetRed($red = false) {
854
		$this->qred = $red;
855
	}
856
	function GetRio() {
857
		return $this->qrio;
858
	}
859
	function SetRio($rio = false) {
860
		$this->qrio = $rio;
861
	}
862
	function GetEcn() {
863
		return $this->qecn;
864
	}
865
	function SetEcn($ecn = false) {
866
		$this->qecn = $ecn;
867
	}
868
	function GetAck() {
869
		return $this->qack;
870
	}
871
	function SetAck($ack = false) {
872
		$this->qack = $ack;
873
	}
874

    
875
	function build_javascript() {
876
		$javascript = "<script type=\"text/javascript\">";
877
		$javascript .= "//<![CDATA[";
878
		$javascript .= "function mySuspend() { \n";
879
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
880
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
881
		$javascript .= "else if (document.all)\n";
882
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
883
		$javascript .= "}\n";
884

    
885
		$javascript .= "function myResume() {\n";
886
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
887
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
888
		$javascript .= "else if (document.all)\n";
889
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
890
		$javascript .= "}\n";
891
		$javascript .= "//]]>";
892
		$javascript .= "</script>";
893

    
894
		return $javascript;
895
	}
896

    
897
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
898

    
899
	/* 
900
	 * Currently this will not be called unless we decide to clone a whole 
901
	 * queue tree on the 'By Queues' view or support drag&drop on the tree/list
902
	 */
903
	 function copy_queue($interface, &$cflink) {
904

    
905
 		$cflink['name'] = $this->GetQname();
906
                $cflink['interface'] = $interface;
907
                $cflink['qlimit'] = $this->GetQlimit();
908
                $cflink['priority'] = $this->GetQpriority();
909
                $cflink['description'] = $this->GetDescription();
910
                $cflink['enabled'] = $this->GetEnabled();
911
                $cflink['default'] = $this->GetDefault();
912
                $cflink['red'] = $this->GetRed();
913
                $cflink['rio'] = $this->GetRio();
914
                $cflink['ecn'] = $this->GetEcn();
915

    
916
                if (is_array($this->subqueues)) {
917
                        $cflinkp['queue'] = array();
918
                        foreach ($this->subqueues as $q) {
919
				 $cflink['queue'][$q->GetQname()] = array();
920
                                $q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
921
			}
922
                }
923

    
924
	 }
925

    
926
	function clean_queue($sched) {
927
		clean_child_queues($sched, $this->GetLink());
928
		if (is_array($this->subqueues)) {
929
			foreach ($this->subqueues as $q)
930
				$q->clean_queue($sched);
931
		}
932
	}
933

    
934
        function &get_queue_list(&$qlist) {
935

    
936
		$qlist[$this->GetQname()] = & $this;
937
		if (is_array($this->subqueues)) {
938
			foreach ($this->subqueues as $queue)
939
				$queue->get_queue_list($qlist);
940
		}
941
	}
942

    
943
	function delete_queue() {
944
		unref_on_altq_queue_list($this->GetQname());
945
		cleanup_queue_from_rules($this->GetQname());
946
		unset_object_by_reference($this->GetLink());
947
	}
948

    
949
	function delete_all() {
950
                if (count($this->subqueues)) {
951
                        foreach ($this->subqueues as $q) {
952
                                $q->delete_all();
953
                                unset_object_by_reference($q->GetLink());
954
                                unset($q);
955
                        }
956
                        unset($this->subqueues);
957
                }
958
        }
959

    
960
	 function &find_queue($interface, $qname) { 
961
		if ($qname == $this->GetQname())
962
			return $this; 
963
	}
964

    
965
	function find_parentqueue($interface, $qname) { return; }
966

    
967
	function validate_input($data, &$input_errors) {
968

    
969
		$reqdfields[] = "name";
970
		$reqdfieldsn[] = gettext("Name");
971
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
972

    
973
                if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
974
			$input_errors[] = "Bandwidth must be an integer.";
975
                if ($data['bandwidth'] < 0)
976
			$input_errors[] = "Bandwidth cannot be negative.";
977
                if ($data['qlimit'] && (!is_numeric($data['qlimit'])))
978
			$input_errors[] = "Qlimit must be an integer.";
979
	 	if ($data['qlimit'] < 0)
980
			$input_errors[] = "Qlimit must be an positive.";
981
		if ($data['priority'] && (!is_numeric($data['priority'])
982
		    || ($data['priority'] < 1) || ($data['priority'] > 15))) {
983
			$input_errors[] = gettext("The priority must be an integer between 1 and 15.");
984
		}
985
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) 
986
				$input_errors[] = gettext("Queue limit must be an integer");
987
		if ($data['qlimit'] < 0)
988
				$input_errors[] = gettext("Queue limit must be positive");
989
		if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['newname']))
990
			 $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
991
		if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]*$/", $data['name']))
992
			 $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
993
		$default = $this->GetDefault();
994
		if (!empty($data['default']) && altq_get_default_queue($data['interface']) && empty($default))
995
			$input_errors[] = gettext("Only one default queue per interface is allowed.");
996
	}
997

    
998
	function ReadConfig(&$q) {
999
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
1000
			$this->SetQname($q['newname']);
1001
		} else if (!empty($q['newname'])) {
1002
			$this->SetQname($q['newname']);
1003
		} else if (isset($q['name']))
1004
			$this->SetQname($q['name']);
1005
		if (isset($q['interface']))
1006
			$this->SetInterface($q['interface']);
1007
		$this->SetBandwidth($q['bandwidth']);
1008
		if ($q['bandwidthtype'] <> "")
1009
			$this->SetBwscale($q['bandwidthtype']);
1010
		if (!empty($q['qlimit']))
1011
			$this->SetQlimit($q['qlimit']);
1012
		else
1013
			$this->SetQlimit(""); // Default
1014
		if (!empty($q['priority']))
1015
			$this->SetQPriority($q['priority']);
1016
		else
1017
			$this->SetQpriority("");
1018
		if (!empty($q['description']))
1019
			$this->SetDescription($q['description']);
1020
		else
1021
			$this->SetDescription("");
1022
		if (!empty($q['red']))
1023
			$this->SetRed($q['red']);
1024
		else
1025
			$this->SetRed();
1026
		if (!empty($q['rio']))
1027
			$this->SetRio($q['rio']);
1028
		else
1029
			$this->SetRio();
1030
		if (!empty($q['ecn']))
1031
			$this->SetEcn($q['ecn']);
1032
		else
1033
			$this->SetEcn();
1034
		if (!empty($q['default']))
1035
			$this->SetDefault($q['default']);
1036
		else
1037
			$this->SetDefault();
1038
		if (!empty($q['enabled']))
1039
			$this->SetEnabled($q['enabled']);
1040
		else
1041
			$this->SetEnabled("");
1042

    
1043
	}
1044

    
1045
	function build_tree() {
1046
		$tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&amp;queue=". $this->GetQname()."&amp;action=show"; 
1047
		$tree .= "\" ";
1048
		$tmpvalue = $this->GetDefault();
1049
		if (!empty($tmpvalue))
1050
			$tree .= " class=\"navlnk\"";
1051
		$tree .= " >" . $this->GetQname() . "</a>";
1052
		/* 
1053
		 * Not needed here!
1054
		 * if (is_array($queues) {
1055
		 *	  $tree .= "<ul>";
1056
		 *	  foreach ($q as $queues) 
1057
		 *		  $tree .= $queues['$q->GetName()']->build_tree();
1058
		 *	  endforeach	
1059
		 *	  $tree .= "</ul>";
1060
		 * }
1061
		 */
1062

    
1063
		$tree .= "</li>"; 
1064

    
1065
		return $tree;
1066
	}
1067

    
1068
	/* Should return something like:
1069
	 * queue $qname on $qinterface bandwidth ....
1070
	 */
1071
	function build_rules(&$default = false) {
1072
		$pfq_rule = " queue ". $this->qname;
1073
		if ($this->GetInterface())
1074
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1075
		$tmpvalue = $this->GetQpriority();
1076
		if (!empty($tmpvalue))
1077
			$pfq_rule .= " priority ".$this->GetQpriority();
1078
		$tmpvalue = $this->GetQlimit();
1079
		if (!empty($tmpvalue))
1080
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1081
		if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault()) {
1082
			$pfq_rule .= " priq ( ";
1083
			$tmpvalue = $this->GetRed();
1084
			if (!empty($tmpvalue)) {
1085
				$comma = 1;
1086
				$pfq_rule .= " red ";
1087
			}
1088
			$tmpvalue = $this->GetRio();
1089
			if (!empty($tmpvalue)) {
1090
				if ($comma) 
1091
					$pfq_rule .= " ,";
1092
				$comma = 1;
1093
				$pfq_rule .= " rio ";
1094
			}
1095
			$tmpvalue = $this->GetEcn();
1096
			if (!empty($tmpvalue)) {
1097
				if ($comma) 
1098
					$pfq_rule .= " ,";
1099
				$comma = 1;
1100
				$pfq_rule .= " ecn ";
1101
			}
1102
			$tmpvalue = $this->GetDefault();
1103
			if (!empty($tmpvalue)) {
1104
				if ($comma)
1105
					$pfq_rule .= " ,";
1106
				$pfq_rule .= " default ";
1107
				$default = true;
1108
			}
1109
			$pfq_rule .= " ) ";
1110
		}
1111

    
1112
		$pfq_rule .= " \n";
1113

    
1114
		return $pfq_rule;
1115
	}
1116

    
1117
	/*
1118
	 * To return the html form to show to user
1119
	 * for getting the parameters.
1120
	 * Should do even for first time when the
1121
	 * object is created and later when we may
1122
	 * need to update it.
1123
	 */
1124
	function build_form() {
1125
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br/>";
1126
                $form .= gettext("Enable/Disable");
1127
                $form .= "<br/></td><td class=\"vncellreq\">";
1128
                $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
1129
                if ($this->GetEnabled() == "on")
1130
                        $form .=  " checked=\"checked\"";
1131
                $form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue and its children") . "</span>";
1132
                $form .= "</td></tr>";
1133
		$form .= "<tr>";
1134
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">";
1135
		$form .= gettext("Queue Name") . "</td><td width=\"78%\" class=\"vtable\">";
1136
		$form .= "<input name=\"newname\" type=\"text\" id=\"newname\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
1137
		$form .= htmlspecialchars($this->GetQname());
1138
		$form .= "\" />";
1139
		$form .= "<input name=\"name\" type=\"hidden\" id=\"name\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
1140
		$form .= htmlspecialchars($this->GetQname());
1141
		$form .= "\" />";
1142
		$form .= "<br /> <span class=\"vexpl\">" . gettext("Enter the name of the queue here.  Do not use spaces and limit the size to 15 characters.");
1143
		$form .= "</span><br /></td>";
1144
		$form .= "</tr><tr>";
1145
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Priority") . "</td>";
1146
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"priority\" type=\"text\" id=\"priority\" size=\"5\" value=\"";
1147
		$form .= htmlspecialchars($this->GetQpriority());
1148
		$form .= "\" />";
1149
		$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>";
1150
		$form .= "</tr>";
1151
		$form .= "<tr>";
1152
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Queue limit") . "</td>";
1153
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"qlimit\" type=\"text\" id=\"qlimit\" size=\"8\" value=\"";
1154
		$form .= htmlspecialchars($this->GetQlimit());
1155
		$form .= "\" />";
1156
		$form .= "<br/> <span class=\"vexpl\">" . gettext("Queue limit in packets per second."); 
1157
		$form .= "</span></td>";
1158
		$form .= "<tr>";
1159
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncell\">" . gettext("Scheduler options") . "</td>";
1160
		$form .= "<td width=\"78%\" class=\"vtable\">";
1161
		if (empty($this->subqueues)) {
1162
			if ($this->GetDefault()) { 
1163
				$form .= "<input type=\"checkbox\" id=\"default\" checked=\"checked\" name=\"default\" value=\"default\"";
1164
				$form .= " /> " . gettext("Default queue") . "<br/>";
1165
			} else {
1166
				$form .= "<input type=\"checkbox\" id=\"default\" name=\"default\" value=\"default\"";
1167
				$form .= " /> " . gettext("Default queue") . "<br/>";
1168
			}
1169
		}
1170
		$form .= "<input type=\"checkbox\" id=\"red\" name=\"red\" value=\"red\" ";
1171
		$tmpvalue = $this->GetRed();
1172
		if(!empty($tmpvalue)) 
1173
			$form .=  " checked=\"checked\"";
1174
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#red\">" . gettext("Random Early Detection") . "</a><br/>";
1175
		$form .= "<input type=\"checkbox\" id=\"rio\" name=\"rio\" value=\"rio\"";
1176
		$tmpvalue = $this->GetRio();
1177
		if(!empty($tmpvalue)) 
1178
			$form .=  " checked=\"checked\"";
1179
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#rio\">" . gettext("Random Early Detection In and Out") . "</a><br/>";
1180
		$form .= "<input type=\"checkbox\" id=\"ecn\" name=\"ecn\" value=\"ecn\"";
1181
		$tmpvalue = $this->GetEcn();
1182
		if(!empty($tmpvalue)) 
1183
			$form .=  " checked=\"checked\"";
1184
		$form .= " /> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#ecn\">" . gettext("Explicit Congestion Notification") . "</a><br/>";
1185
		$form .= "<span class=\"vexpl\"><br/>" . gettext("Select options for this queue");
1186
		$form .= "</tr><tr>";
1187
		$form .= "<td width=\"22%\" class=\"vncellreq\">" . gettext("Description") . "</td>";
1188
		$form .= "<td width=\"78%\" class=\"vtable\">";
1189
		$form .= "<input type=\"text\" name=\"description\" size=\"50%\" class=\"formfld unknown\" value=\"" . $this->GetDescription() . "\" />";
1190
		$form .= "</td></tr>";
1191
		$form .= "<input type=\"hidden\" name=\"interface\" id=\"interface\"";
1192
		$form .= " value=\"".$this->GetInterface()."\" />";
1193

    
1194
		return $form;
1195
	}
1196

    
1197
	function build_shortform() {
1198
		/* XXX: Hacks in site. Mostly layer violations!  */
1199
		global $g, $altq_list_queues;
1200
		global $shaperIFlist;
1201

    
1202
		$altq =& $altq_list_queues[$this->GetInterface()];
1203
		if ($altq)
1204
			$scheduler = ": " . $altq->GetScheduler();
1205
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
1206
		$form .= "<a href=\"firewall_shaper.php?interface=" . $this->GetInterface() . "&amp;queue=" . $this->GetQname()."&amp;action=show\">". $shaperIFlist[$this->GetInterface()] .$scheduler."</a>";
1207
		$form .= "</td></tr>";
1208
		/* 
1209
		 * XXX: Hack in sight maybe fix with a class that wraps all
1210
		 * of this layer violations
1211
		 */
1212
		$form .= "<tr>";
1213
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
1214
		$form .= gettext("Bandwidth:") . " " . $this->GetBandwidth().$this->GetBwscale();
1215
		$form .= "</td><td width=\"50%\"></td></tr>";
1216
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
1217
		$tmpvalue = $this->GetQpriority();
1218
		if (!empty($tmpvalue))
1219
			$form .= gettext("Priority: on") . " </td></tr>";
1220
		$tmpvalue = $this->GetDefault();
1221
		if (!empty($tmpvalue))
1222
			$form .= "<tr><td class=\"vncellreq\">" . gettext("Default: on") . " </td></tr>";
1223
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
1224
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
1225
		$form .= $this->GetInterface() . "&amp;queue=";
1226
		$form .= $this->GetQname() . "&amp;action=delete\">";
1227
		$form .= "<img src=\"";
1228
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
1229
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("Delete queue from interface") . "\" alt=\"delete\" />";
1230
		$form .= "<span>" . gettext("Delete queue from interface") . "</span></a></td></tr>";
1231

    
1232
		return $form;
1233

    
1234
	}
1235

    
1236
		function update_altq_queue_data(&$q) { 
1237
		$this->ReadConfig($q);
1238
	}
1239

    
1240
	function wconfig() {
1241
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1242
		if (!is_array($cflink))
1243
			$cflink = array();
1244
		$cflink['name'] = $this->GetQname();
1245
		$cflink['interface'] = $this->GetInterface();
1246
		$cflink['qlimit'] = trim($this->GetQlimit());
1247
		if (empty($cflink['qlimit']))
1248
			unset($cflink['qlimit']);
1249
		$cflink['priority'] = trim($this->GetQpriority());
1250
		if (empty($cflink['priority']))
1251
			unset($cflink['priority']);
1252
		$cflink['description'] = trim($this->GetDescription());
1253
		if (empty($cflink['description']))
1254
			unset($cflink['description']);
1255
		$cflink['enabled'] = trim($this->GetEnabled());
1256
		if (empty($cflink['enabled']))
1257
			unset($cflink['enabled']);
1258
		$cflink['default'] = trim($this->GetDefault());
1259
		if (empty($cflink['default']))
1260
			unset($cflink['default']);
1261
		$cflink['red'] = trim($this->GetRed());
1262
		if (empty($cflink['red']))
1263
			unset($cflink['red']);
1264
		$cflink['rio'] = trim($this->GetRio());
1265
		if (empty($cflink['rio']))
1266
			unset($cflink['rio']);
1267
		$cflink['ecn'] = trim($this->GetEcn());
1268
		if (empty($cflink['ecn']))
1269
			unset($cflink['ecn']);
1270
	}
1271
}
1272

    
1273
class hfsc_queue extends priq_queue {
1274
	/* realtime */
1275
	var $realtime;
1276
	var $r_m1;
1277
	var $r_d;
1278
	var $r_m2;
1279
	/* linkshare */
1280
	var $linkshare;
1281
	var $l_m1;
1282
	var $l_d;
1283
	var $l_m2;
1284
	/* upperlimit */
1285
	var $upperlimit;
1286
	var $u_m1;
1287
	var $u_d;
1288
	var $u_m2;
1289

    
1290
	/*
1291
	 * HFSC can have nested queues.
1292
	 */
1293
	function CanHaveChildren() {
1294
		return true;
1295
	}
1296
	function GetRealtime() {
1297
           return $this->realtime;
1298
	}
1299
	function GetR_m1() {
1300
		return $this->r_m1;
1301
	}
1302
	function GetR_d() {
1303
		return $this->r_d;
1304
	}
1305
	function GetR_m2() {
1306
		return $this->r_m2;
1307
	}
1308
	function SetRealtime() {
1309
		$this->realtime = "on";
1310
	}
1311
	function DisableRealtime() {
1312
		$this->realtime = "";
1313
	}
1314
	function SetR_m1($value) {
1315
		$this->r_m1 = $value;
1316
	}
1317
	function SetR_d($value) {
1318
		$this->r_d = $value;
1319
	}
1320
	function SetR_m2($value) {
1321
		$this->r_m2 = $value;
1322
	}
1323
	function GetLinkshare() {
1324
		return $this->linkshare;
1325
	}
1326
	function DisableLinkshare() {
1327
		$this->linkshare = "";
1328
	}
1329
	function GetL_m1() {
1330
		return $this->l_m1;
1331
	}
1332
	function GetL_d() {
1333
		return $this->l_d;
1334
	}
1335
	function GetL_m2() {
1336
		return $this->l_m2;
1337
	}
1338
	function SetLinkshare() {
1339
		$this->linkshare = "on";
1340
	}
1341
	function SetL_m1($value) {
1342
		$this->l_m1 = $value;
1343
	}
1344
	function SetL_d($value) {
1345
		$this->l_d = $value;
1346
	}
1347
	function SetL_m2($value) {
1348
		$this->l_m2 = $value;
1349
	}
1350
	function GetUpperlimit() {
1351
		return $this->upperlimit;
1352
	}
1353
	function GetU_m1() {
1354
		return $this->u_m1;
1355
	}
1356
	function GetU_d() {
1357
		return $this->u_d;
1358
	}
1359
	function GetU_m2() {
1360
		return $this->u_m2;
1361
	}
1362
	function SetUpperlimit() {
1363
		$this->upperlimit = "on";
1364
	}
1365
	function DisableUpperlimit() {
1366
		$this->upperlimit = "";
1367
	}
1368
	function SetU_m1($value) {
1369
		$this->u_m1 = $value;
1370
	}
1371
	function SetU_d($value) {
1372
		$this->u_d = $value;
1373
	}
1374
	function SetU_m2($value) {
1375
		$this->u_m2 = $value;
1376
	}
1377

    
1378
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1379

    
1380
		if (!is_array($this->subqueues))
1381
			$this->subqueues = array();
1382
		$q =& new hfsc_queue();
1383
		$q->SetInterface($this->GetInterface());
1384
		$q->SetParent(&$this);
1385
		$q->ReadConfig($qname);
1386
		$q->validate_input($qname, $input_errors);
1387
		if (count($input_errors)) {
1388
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
1389
			return $q;
1390
		}
1391

    
1392
		$q->SetEnabled("on");
1393
		$q->SetLink($path);
1394
		switch ($q->GetBwscale()) {
1395
		case "%":
1396
			$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
1397
			break;
1398
		default:
1399
			$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
1400
			break;
1401
		}
1402
		$q->SetAvailableBandwidth($myBw);
1403
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
1404

    
1405
		$this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue()
1406
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
1407
		if (is_array($qname['queue'])) {
1408
			foreach ($qname['queue'] as $key1 => $que) {
1409
				array_push($path, $key1);
1410
				$q->add_queue($q->GetInterface(), &$que, &$path, $input_errors);
1411
				array_pop($path);
1412
			}
1413
		}
1414

    
1415
		return $q;
1416
	}
1417

    
1418
        function copy_queue($interface, &$cflink) {
1419

    
1420
		$cflink['name'] = $this->GetQname();
1421
		$cflink['interface'] = $interface;
1422
		$cflink['qlimit'] = trim($this->GetQlimit());
1423
		if (empty($cflink['qlimit']))
1424
			unset($cflink['qlimit']);
1425
		$cflink['priority'] = trim($this->GetQpriority());
1426
		if (empty($cflink['priority']))
1427
			unset($cflink['priority']);
1428
		$cflink['description'] = trim($this->GetDescription());
1429
		if (empty($cflink['description']))
1430
			unset($cflink['description']);
1431
		$cflink['bandwidth'] = $this->GetBandwidth();
1432
		$cflink['bandwidthtype'] = $this->GetBwscale();
1433
		$cflink['enabled'] = trim($this->GetEnabled());
1434
		if (empty($cflink['enabled']))
1435
			unset($cflink['enabled']);
1436
		$cflink['default'] = trim($this->GetDefault());
1437
		if (empty($cflink['default']))
1438
			unset($cflink['default']);
1439
		$cflink['red'] = trim($this->GetRed());
1440
		if (empty($cflink['red']))
1441
			unset($cflink['red']);
1442
		$cflink['rio'] = trim($this->GetRio());
1443
		if (empty($cflink['rio']))
1444
			unset($cflink['rio']);
1445
		$cflink['ecn'] = trim($this->GetEcn());
1446
		if (empty($cflink['ecn']))
1447
			unset($cflink['ecn']);
1448
		if ($this->GetLinkshare() <> "") {
1449
			if ($this->GetL_m1() <> "") {
1450
				$cflink['linkshare1'] = $this->GetL_m1();
1451
				$cflink['linkshare2'] = $this->GetL_d();
1452
				$cflink['linkshare'] = "on";
1453
			} else {
1454
				unset($cflink['linkshare1']);
1455
				unset($cflink['linkshare2']);
1456
				unset($cflink['linkshare']);
1457
			}
1458
			if ($this->GetL_m2() <> "") {
1459
				$cflink['linkshare3'] = $this->GetL_m2();
1460
				$cflink['linkshare'] = "on";
1461
			} else {
1462
				unset($cflink['linkshare3']);
1463
				unset($cflink['linkshare']);
1464
			}
1465
		}
1466
		if ($this->GetRealtime() <> "") {
1467
			if ($this->GetR_m1() <> "") {
1468
				$cflink['realtime1'] = $this->GetR_m1();
1469
				$cflink['realtime2'] = $this->GetR_d();
1470
				$cflink['realtime'] = "on";
1471
			} else {
1472
				unset($cflink['realtime1']);
1473
                                unset($cflink['realtime2']);
1474
                                unset($cflink['realtime']);
1475
			}
1476
			if ($this->GetR_m2() <> "") {
1477
				$cflink['realtime3'] = $this->GetR_m2();
1478
				$cflink['realtime'] = "on";
1479
			} else {
1480
				unset($cflink['realtime3']);
1481
				unset($cflink['realtime']);
1482
			}
1483
		}
1484
		if ($this->GetUpperlimit() <> "") {
1485
			if ($this->GetU_m1() <> "") {
1486
				$cflink['upperlimit1'] = $this->GetU_m1();
1487
				$cflink['upperlimit2'] = $this->GetU_d();
1488
				$cflink['upperlimit'] = "on";
1489
			} else {
1490
				unset($cflink['upperlimit']);
1491
				unset($cflink['upperlimit1']);
1492
				unset($cflink['upperlimit2']);
1493
			}
1494
			if ($this->GetU_m2() <> "") {
1495
				$cflink['upperlimit3'] = $this->GetU_m2();
1496
				$cflink['upperlimit'] = "on";
1497
			} else {
1498
				unset($cflink['upperlimit3']);
1499
				unset($cflink['upperlimit']);
1500
			}
1501
		}
1502

    
1503
		if (is_array($this->subqueues)) {
1504
			$cflinkp['queue'] = array();
1505
			foreach ($this->subqueues as $q) {
1506
				$cflink['queue'][$q->GetQname()] = array();
1507
				$q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
1508
			}
1509
		}
1510
	}
1511

    
1512
	function delete_queue() { 
1513
		unref_on_altq_queue_list($this->GetQname());
1514
		cleanup_queue_from_rules($this->GetQname());
1515
		$parent =& $this->GetParent();
1516
		foreach ($this->subqueues as $q)  {
1517
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
1518
			$q->delete_queue();
1519
		}
1520
		unset_object_by_reference($this->GetLink());
1521
	}
1522

    
1523
	/*
1524
	 * Should search even its children
1525
	 */
1526
	function &find_queue($interface, $qname) {
1527
		if ($qname == $this->GetQname()) 
1528
			return $this;
1529

    
1530
		foreach ($this->subqueues as $q) {
1531
			$result =& $q->find_queue("", $qname);
1532
			if ($result)
1533
				return $result;
1534
		}
1535
	}
1536

    
1537
	function &find_parentqueue($interface, $qname) {
1538
		if ($this->subqueues[$qname]) 
1539
			return $this;
1540
		foreach ($this->subqueues as $q) {
1541
			$result = $q->find_parentqueue("", $qname);
1542
			if ($result)
1543
				return $result;
1544
		}
1545
	}
1546

    
1547
	function validate_input($data, &$input_errors) {
1548
		parent::validate_input($data, $input_errors);
1549

    
1550
		$reqdfields[] = "bandwidth";
1551
		$reqdfieldsn[] = gettext("Bandwidth");
1552
		$reqdfields[] = "bandwidthtype";
1553
		$reqdfieldsn[] = gettext("Bandwidthtype");
1554

    
1555
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1556

    
1557
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1558
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
1559
				$input_errors[] = gettext("Bandwidth must be an integer.");
1560

    
1561
			if ($data['bandwidth'] < 0)
1562
				$input_errors[] = gettext("Bandwidth cannot be negative.");
1563

    
1564
			if ($data['bandwidthtype'] == "%") {
1565
				if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
1566
					$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
1567
			}
1568
		/*
1569
			$parent =& $this->GetParent();
1570
			switch ($data['bandwidthtype']) {
1571
			case "%":
1572
				$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
1573
			default:
1574
				$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
1575
				break;
1576
			}
1577
			if ($parent->GetAvailableBandwidth() < $myBw)
1578
				$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
1579
		*/
1580
		}
1581

    
1582
		if ($data['upperlimit1'] <> "" &&  $data['upperlimit2'] == "")
1583
			$input_errors[] = gettext("upperlimit service curve defined but missing (d) value");
1584
		if ($data['upperlimit2'] <> "" &&  $data['upperlimit1'] == "")
1585
			$input_errors[] = gettext("upperlimit service curve defined but missing initial bandwidth (m1) value");
1586
		if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1']))
1587
			$input_errors[] = gettext("upperlimit m1 value needs to be Kb, Mb, Gb, or %");
1588
		if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2']))
1589
			$input_errors[] = gettext("upperlimit d value needs to be numeric");
1590
		if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3']))
1591
			$input_errors[] = gettext("upperlimit m2 value needs to be Kb, Mb, Gb, or %");
1592

    
1593
		/*
1594
		if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") {
1595
			$bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']);
1596
			$bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']);
1597
			if (floatval($bw_1) < floatval($bw_2)) 
1598
				$input_errors[] = ("upperlimit m1 cannot be smaller than m2");
1599

    
1600
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1601
				$input_errors[] = ("upperlimit specification excedd 80% of allowable allocation.");
1602
		}
1603
		*/
1604
		if ($data['linkshare1'] <> "" &&  $data['linkshare2'] == "")
1605
			$input_errors[] = gettext("linkshare service curve defined but missing (d) value");
1606
		if ($data['linkshare2'] <> "" &&  $data['linkshare1'] == "")
1607
			$input_errors[] = gettext("linkshare service curve defined but missing initial bandwidth (m1) value");
1608
		if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1']))
1609
			$input_errors[] = gettext("linkshare m1 value needs to be Kb, Mb, Gb, or %");
1610
		if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2']))
1611
			$input_errors[] = gettext("linkshare d value needs to be numeric");
1612
		if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3']))
1613
			$input_errors[] = gettext("linkshare m2 value needs to be Kb, Mb, Gb, or %");
1614
		if ($data['realtime1'] <> "" &&  $data['realtime2'] == "")
1615
			$input_errors[] = gettext("realtime service curve defined but missing (d) value");
1616
		if ($data['realtime2'] <> "" &&  $data['realtime1'] == "")
1617
			$input_errors[] = gettext("realtime service curve defined but missing initial bandwidth (m1) value");
1618

    
1619
		/*
1620
		if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) {
1621
			$bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']);
1622
                	$bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']);
1623
                	if (floatval($bw_1) < floatval($bw_2))
1624
                        	$input_errors[] = ("linkshare m1 cannot be smaller than m2");
1625

    
1626
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1627
                        	$input_errors[] = ("linkshare specification excedd 80% of allowable allocation.");
1628
		}
1629
		*/
1630

    
1631
		if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1']))
1632
			$input_errors[] = gettext("realtime m1 value needs to be Kb, Mb, Gb, or %");
1633
		if ($data['realtime2'] <> "" && !is_numeric($data['realtime2']))
1634
			$input_errors[] = gettext("realtime d value needs to be numeric");
1635
		if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3']))
1636
			$input_errors[] = gettext("realtime m2 value needs to be Kb, Mb, Gb, or %");
1637

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

    
1645
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1646
				$input_errors[] = ("realtime specification excedd 80% of allowable allocation.");
1647
		}
1648
		*/
1649
	}
1650

    
1651
	function ReadConfig(&$cflink) {
1652
		if (!empty($cflink['linkshare'])) {
1653
			if (!empty($cflink['linkshare1'])) {
1654
				$this->SetL_m1($cflink['linkshare1']);
1655
                                $this->SetL_d($cflink['linkshare2']);
1656
				$this->SetLinkshare();
1657
			} else {
1658
				$this->SetL_m1("");
1659
                                $this->SetL_d("");
1660
				$this->DisableLinkshare();
1661
			}
1662
			if (!empty($cflink['linkshare3'])) {
1663
                                $this->SetL_m2($cflink['linkshare3']);
1664
				$this->SetLinkshare();
1665
			}
1666
		} else
1667
			$this->DisableLinkshare();
1668
		if (!empty($cflink['realtime'])) {
1669
                        if (!empty($cflink['realtime1'])) {
1670
                                $this->SetR_m1($cflink['realtime1']);
1671
                                $this->SetR_d($cflink['realtime2']);
1672
				$this->SetRealtime();
1673
			} else {
1674
                                $this->SetR_m1("");
1675
                                $this->SetR_d("");
1676
				$this->DisableRealtime();
1677
			}
1678
                        if (!empty($cflink['realtime3'])) {
1679
                                $this->SetR_m2($cflink['realtime3']);
1680
				$this->SetRealtime();
1681
			}
1682
		} else
1683
			$this->DisableRealtime(); 
1684
		if (!empty($cflink['upperlimit'])) {
1685
                        if (!empty($cflink['upperlimit1'])) {
1686
                                $this->SetU_m1($cflink['upperlimit1']);
1687
                                $this->SetU_d($cflink['upperlimit2']);
1688
				$this->SetUpperlimit();
1689
			} else {
1690
                                $this->SetU_m1("");
1691
                                $this->SetU_d("");
1692
				$this->DisableUpperlimit();
1693
			}
1694
                        if (!empty($cflink['upperlimit3'])) {
1695
                                $this->SetU_m2($cflink['upperlimit3']);
1696
				$this->SetUpperlimit();
1697
			}
1698
		} else
1699
			$this->DisableUpperlimit();
1700
		parent::ReadConfig($cflink);
1701
	}
1702

    
1703
	function build_tree() {
1704
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface() ."&amp;queue=" . $this->GetQname()."&amp;action=show"; 
1705
		$tree .= "\" ";
1706
		$tmpvalue = $this->GetDefault();
1707
		if (!empty($tmpvalue))
1708
			$tree .= " class=\"navlnk\"";
1709
		$tree .= " >" . $this->GetQname() . "</a>";
1710
		if (is_array($this->subqueues)) {
1711
			$tree .= "<ul>";
1712
			foreach ($this->subqueues as $q)  {
1713
				$tree .= $q->build_tree();
1714
			}	
1715
			$tree .= "</ul>";
1716
		}
1717
		$tree .= "</li>";
1718
		return $tree;
1719
	}
1720

    
1721
	/* Even this should take children into consideration */
1722
	function build_rules(&$default = false) {
1723

    
1724
		$pfq_rule = " queue ". $this->qname;
1725
		if ($this->GetInterface())
1726
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1727
		if ($this->GetBandwidth() && $this->GetBwscale())
1728
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
1729

    
1730
		$tmpvalue = $this->GetQlimit();
1731
		if (!empty($tmpvalue))
1732
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1733
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
1734
			$pfq_rule .= " hfsc ( ";
1735
			$tmpvalue = $this->GetRed();
1736
			if (!empty($tmpvalue)) {
1737
				$comma = 1;
1738
				$pfq_rule .= " red ";
1739
			}
1740

    
1741
			$tmpvalue = $this->GetRio();
1742
			if (!empty($tmpvalue)) {
1743
				if ($comma) 
1744
					$pfq_rule .= " ,";
1745
				$comma = 1;
1746
				$pfq_rule .= " rio ";
1747
			}
1748
			$tmpvalue = $this->GetEcn();
1749
			if (!empty($tmpvalue)) {
1750
				if ($comma) 
1751
					$pfq_rule .= " ,";
1752
				$comma = 1;
1753
				$pfq_rule .= " ecn ";
1754
			}
1755
			$tmpvalue = $this->GetDefault();
1756
			if (!empty($tmpvalue)) {
1757
				if ($comma)
1758
					$pfq_rule .= " ,";
1759
				$comma = 1;
1760
				$pfq_rule .= " default ";
1761
				$default = true;
1762
			}
1763

    
1764
			if ($this->GetRealtime() <> "")  {
1765
				if ($comma) 
1766
					$pfq_rule .= " , ";
1767
				if ($this->GetR_m1()  <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "")
1768
					$pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") ";
1769
				else  if ($this->GetR_m2() <> "")
1770
					$pfq_rule .= " realtime " . $this->GetR_m2();
1771
				$comma = 1;
1772
			}
1773
			if ($this->GetLinkshare() <> "") {
1774
				if ($comma)
1775
					$pfq_rule .= " ,";
1776
				if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "")
1777
					$pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") ";
1778
				else if ($this->GetL_m2() <> "")
1779
					$pfq_rule .= " linkshare " . $this->GetL_m2() . " ";
1780
				$comma = 1;
1781
			}
1782
			if ($this->GetUpperlimit() <> "") {
1783
				if ($comma)
1784
					$pfq_rule .= " ,";
1785
				if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "")
1786
							$pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") ";
1787
				else if ($this->GetU_m2() <> "")
1788
					$pfq_rule .= " upperlimit " . $this->GetU_m2() . " ";
1789
			}
1790
			$pfq_rule .= " ) ";
1791
		}
1792
		if (count($this->subqueues)) {
1793
			$i = count($this->subqueues);
1794
			$pfq_rule .= " { ";
1795
			foreach ($this->subqueues as $qkey => $qnone) {
1796
				if ($i > 1) {
1797
					$i--;
1798
					$pfq_rule .= " {$qkey}, ";
1799
				} else
1800
					$pfq_rule .= " {$qkey} ";
1801
			}
1802
			$pfq_rule .= " } \n";
1803
			foreach ($this->subqueues as $q)
1804
				$pfq_rule .= $q->build_rules(&$default);
1805
		}
1806

    
1807
		 $pfq_rule .= " \n";
1808

    
1809
		return $pfq_rule;
1810
	}
1811

    
1812
	function build_javascript() {
1813
		$javascript = parent::build_javascript();
1814
		$javascript .= "<script type=\"text/javascript\">";
1815
		$javascript .= "//<![CDATA[";
1816
		$javascript .= "function enable_realtime(enable_over) { \n";
1817
		$javascript .= "if (document.iform.realtime.checked || enable_over) { \n";
1818
		$javascript .= "document.iform.realtime1.disabled = 0;\n";
1819
		$javascript .= "document.iform.realtime2.disabled = 0;\n";
1820
		$javascript .= "document.iform.realtime3.disabled = 0;\n";
1821
		$javascript .= " } else { \n";
1822
		$javascript .= "document.iform.realtime1.disabled = 1;\n";
1823
		$javascript .= "document.iform.realtime2.disabled = 1;\n";
1824
		$javascript .= "document.iform.realtime3.disabled = 1;\n";
1825
		$javascript .= " } \n";
1826
		$javascript .= " } \n";
1827
		$javascript .= "function enable_linkshare(enable_over) { \n";
1828
		$javascript .= "if (document.iform.linkshare.checked || enable_over) { \n";
1829
		$javascript .= "document.iform.linkshare1.disabled = 0;\n";
1830
		$javascript .= "document.iform.linkshare2.disabled = 0;\n";
1831
		$javascript .= "document.iform.linkshare3.disabled = 0;\n";
1832
		$javascript .= " } else { \n";
1833
		$javascript .= "document.iform.linkshare1.disabled = 1;\n";
1834
		$javascript .= "document.iform.linkshare2.disabled = 1;\n";
1835
		$javascript .= "document.iform.linkshare3.disabled = 1;\n";
1836
		$javascript .= " } \n";
1837
		$javascript .= " } \n";
1838
		$javascript .= "function enable_upperlimit(enable_over) { \n";
1839
		$javascript .= "if (document.iform.upperlimit.checked || enable_over) { \n";
1840
		$javascript .= "document.iform.upperlimit1.disabled = 0;\n";
1841
		$javascript .= "document.iform.upperlimit2.disabled = 0;\n";
1842
		$javascript .= "document.iform.upperlimit3.disabled = 0;\n";
1843
		$javascript .= " } else { \n";
1844
		$javascript .= "document.iform.upperlimit1.disabled = 1;\n";
1845
		$javascript .= "document.iform.upperlimit2.disabled = 1;\n";
1846
		$javascript .= "document.iform.upperlimit3.disabled = 1;\n";
1847
		$javascript .= " } \n";
1848

    
1849
		$javascript .= "} \n";
1850
		$javascript .= "//]]>";
1851
		$javascript .= "</script>";
1852

    
1853
		return $javascript;
1854
	}
1855

    
1856
	function build_form() {
1857
		$form = parent::build_form();
1858
		$form .= "<tr>";
1859
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
1860
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
1861
		$form .= htmlspecialchars($this->GetBandwidth());
1862
		$form .= "\" />";
1863
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
1864
		$form .= "<option value=\"Gb\"";
1865
		if ($this->GetBwscale() == "Gb")
1866
			$form .= " selected=\"selected\"";
1867
		$form .= ">" . gettext("Gbit/s") . "</option>";
1868
		$form .= "<option value=\"Mb\"";
1869
		if ($this->GetBwscale() == "Mb")
1870
			$form .= " selected=\"selected\"";
1871
		$form .= ">" . gettext("Mbit/s") . "</option>";
1872
		$form .= "<option value=\"Kb\"";
1873
		if ($this->GetBwscale() == "Kb")
1874
			$form .= " selected=\"selected\"";
1875
		$form .= ">" . gettext("Kbit/s") . "</option>";
1876
		$form .= "<option value=\"b\"";
1877
		if ($this->GetBwscale() == "b")
1878
			$form .= " selected=\"selected\"";
1879
		$form .= ">" . gettext("Bit/s") . "</option>";
1880
		$form .= "<option value=\"%\"";
1881
		if ($this->GetBwscale() == "%")
1882
			$form .= " selected=\"selected\"";
1883
		$form .= ">%</option>";
1884
		$form .= "</select> <br/>";
1885
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
1886
		$form .= "</span></td></tr>";
1887
		$form .= "<tr>";
1888
		$form .= "<td width=\"22%\" valign=\"middle\" class=\"vncellreq\">" . gettext("Service Curve (sc)") . "</td>";
1889
		$form .= "<td width=\"78%\" class=\"vtable\">";
1890
		$form .= "<table>";
1891
		$form .= "<tr><td>&nbsp;</td><td><center>m1</center></td><td><center>d</center></td><td><center><b>m2</b></center></td></tr>";
1892
		$form .= "<tr><td><input type=\"checkbox\" id=\"upperlimit\" name=\"upperlimit\"";
1893
		if($this->GetUpperlimit()<> "") 
1894
			$form .=  " checked=\"checked\" ";
1895
		$form .= "onchange=\"enable_upperlimit()\" /> " . gettext("Upperlimit:") . "</td><td><input size=\"6\" value=\"";
1896
		$form .= htmlspecialchars($this->GetU_m1());
1897
		$form .= "\" id=\"upperlimit1\" name=\"upperlimit1\" ";
1898
		if ($this->GetUpperlimit() == "")
1899
			$form .= " disabled=\"disabled\"";
1900
		$form .= " /></td><td><input size=\"6\" value=\"";
1901
		$form .= htmlspecialchars($this->GetU_d());
1902
		$form .= "\" id=\"upperlimi2\" name=\"upperlimit2\" ";
1903
		if ($this->GetUpperlimit() == "")
1904
			$form .= " disabled=\"disabled\"";
1905
		$form .= " /></td><td><input size=\"6\" value=\"";
1906
		$form .= htmlspecialchars($this->GetU_m2());
1907
		$form .= "\" id=\"upperlimit3\" name=\"upperlimit3\" ";
1908
		if ($this->GetUpperlimit() == "")
1909
			$form .= " disabled=\"disabled\"";
1910
		$form .= " /></td><td>" . gettext("The maximum allowed bandwidth for the queue.") . "</td></tr>";
1911
		$form .= "<tr><td><input type=\"checkbox\" id=\"realtime\" name=\"realtime\"";
1912
		if($this->GetRealtime() <> "") 
1913
			$form .=  " checked=\"checked\" ";
1914
		$form .= "onchange=\"enable_realtime()\" /> " . gettext("Real time:") . "</td><td><input size=\"6\" value=\"";
1915
		$form .= htmlspecialchars($this->GetR_m1());
1916
		$form .= "\" id=\"realtime1\" name=\"realtime1\" ";
1917
		if ($this->GetRealtime() == "")
1918
			$form .= " disabled=\"disabled\"";
1919
		$form .= " /></td><td><input size=\"6\" value=\"";
1920
		$form .= htmlspecialchars($this->GetR_d());
1921
		$form .= "\" id=\"realtime2\" name=\"realtime2\" ";
1922
		if ($this->GetRealtime() == "")
1923
			$form .= " disabled=\"disabled\"";
1924
		$form .= " /></td><td><input size=\"6\" value=\"";
1925
		$form .= htmlspecialchars($this->GetR_m2());
1926
		$form .= "\" id=\"realtime3\" name=\"realtime3\" ";
1927
		if ($this->GetRealtime() == "")
1928
			$form .= " disabled=\"disabled\"";
1929
		$form .= " /></td><td>" . gettext("The minimum required bandwidth for the queue.") . "</td></tr>";
1930
		$form .= "<tr><td><input type=\"checkbox\" id=\"linkshare\" id=\"linkshare\" name=\"linkshare\"";
1931
		if($this->GetLinkshare() <> "") 
1932
			$form .=  " checked=\"checked\" ";
1933
		$form .= "onchange=\"enable_linkshare()\" /> " . gettext("Link share:") . "</td><td><input size=\"6\" value=\"";
1934
		$form .= htmlspecialchars($this->GetL_m1());
1935
		$form .= "\" id=\"linkshare1\" name=\"linkshare1\" ";
1936
		if ($this->GetLinkshare() == "")
1937
			$form .= " disabled=\"disabled\"";
1938
		$form .= " /></td><td><input size=\"6\" value=\"";
1939
		$form .= htmlspecialchars($this->GetL_d());
1940
		$form .= "\" id=\"linkshare2\" name=\"linkshare2\" ";
1941
		if ($this->GetLinkshare() == "")
1942
			$form .= " disabled=\"disabled\"";
1943
		$form .= " /></td><td><input size=\"6\" value=\"";
1944
		$form .= htmlspecialchars($this->GetL_m2());
1945
		$form .= "\" id=\"linkshare3\" name=\"linkshare3\" ";
1946
		if ($this->GetLinkshare() == "")
1947
			$form .= " disabled=\"disabled\"";
1948
		$form .= " /></td><td>" . gettext("The bandwidth share of a backlogged queue - this overrides priority.") . "</td></tr>";
1949
		$form .= "</table><br/>";
1950
		$form .= gettext("The format for service curve specifications is (m1, d, m2).  m2 controls "
1951
		      .  "the bandwidth assigned to the queue.  m1 and d are optional and can be "
1952
		      .  "used to control the initial bandwidth assignment.  For the first d milliseconds the queue gets the bandwidth given as m1, afterwards the value "
1953
		      .  "given in m2.");
1954
		$form .= "</span></td>";
1955
		$form .= "</tr>";
1956

    
1957
		return $form;
1958
	}
1959

    
1960
	function update_altq_queue_data(&$data) { 
1961
		$this->ReadConfig($data);
1962
	}
1963

    
1964
	function wconfig() {
1965
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1966
		if (!is_array($cflink))
1967
			$cflink = array();
1968
		$cflink['name'] = $this->GetQname();
1969
		$cflink['interface'] = $this->GetInterface();
1970
		$cflink['qlimit'] = trim($this->GetQlimit());
1971
		if (empty($cflink['qlimit']))
1972
			unset($cflink['qlimit']);
1973
		$cflink['priority'] = $this->GetQpriority();
1974
		if (empty($cflink['priority']))
1975
			unset($cflink['priority']);
1976
		$cflink['description'] = $this->GetDescription();
1977
		if (empty($cflink['description']))
1978
			unset($cflink['description']);
1979
		$cflink['bandwidth'] = $this->GetBandwidth();
1980
		$cflink['bandwidthtype'] = $this->GetBwscale();
1981
		$cflink['enabled'] = $this->GetEnabled();
1982
		if (empty($cflink['enabled']))
1983
			unset($cflink['enabled']);
1984
		$cflink['default'] = $this->GetDefault();
1985
		if (empty($cflink['default']))
1986
			unset($cflink['default']);
1987
		$cflink['red'] = trim($this->GetRed());
1988
		if (empty($cflink['red']))
1989
			unset($cflink['red']);
1990
		$cflink['rio'] = $this->GetRio();
1991
		if (empty($cflink['rio']))
1992
			unset($cflink['rio']);
1993
		$cflink['ecn'] = trim($this->GetEcn());
1994
		if (empty($cflink['ecn']))
1995
			unset($cflink['ecn']);
1996
		if ($this->GetLinkshare() <> "") {
1997
			if ($this->GetL_m1() <> "") {
1998
				$cflink['linkshare1'] = $this->GetL_m1();
1999
				$cflink['linkshare2'] = $this->GetL_d();
2000
				$cflink['linkshare'] = "on";
2001
			} else {
2002
				unset($cflink['linkshare']);
2003
				unset($cflink['linkshare1']);
2004
				unset($cflink['linkshare2']);
2005
			}
2006
			if ($this->GetL_m2() <> "") {
2007
				$cflink['linkshare3'] = $this->GetL_m2();
2008
				$cflink['linkshare'] = "on";
2009
			} else {
2010
				unset($cflink['linkshare']);
2011
				unset($cflink['linkshare3']);
2012
			}
2013
		} else {
2014
			unset($cflink['linkshare']);
2015
			unset($cflink['linkshare1']);
2016
			unset($cflink['linkshare2']);
2017
			unset($cflink['linkshare3']);
2018
		}
2019
		if ($this->GetRealtime() <> "") {
2020
			if ($this->GetR_m1() <> "") {
2021
				$cflink['realtime1'] = $this->GetR_m1();
2022
				$cflink['realtime2'] = $this->GetR_d();
2023
				$cflink['realtime'] = "on";
2024
			} else {
2025
				unset($cflink['realtime']);
2026
				unset($cflink['realtime1']);
2027
				unset($cflink['realtime2']);
2028
			}
2029
			if ($this->GetR_m2() <> "") {
2030
				$cflink['realtime3'] = $this->GetR_m2();
2031
				$cflink['realtime'] = "on";
2032
			} else {
2033
				unset($cflink['realtime']);
2034
				unset($cflink['realtime3']);
2035
			}
2036
		} else {
2037
			unset($cflink['realtime']);
2038
			unset($cflink['realtime1']);
2039
			unset($cflink['realtime2']);
2040
			unset($cflink['realtime3']);
2041
		}
2042
		if ($this->GetUpperlimit() <> "") {
2043
			if ($this->GetU_m1() <> "") {
2044
				$cflink['upperlimit1'] = $this->GetU_m1();
2045
				$cflink['upperlimit2'] = $this->GetU_d();
2046
				$cflink['upperlimit'] = "on";
2047
			} else {
2048
				unset($cflink['upperlimit']);
2049
				unset($cflink['upperlimit1']);
2050
				unset($cflink['upperlimit2']);
2051
			}
2052
			if ($this->GetU_m2() <> "") {
2053
				$cflink['upperlimit3'] = $this->GetU_m2();
2054
				$cflink['upperlimit'] = "on";
2055
			} else {
2056
				unset($cflink['upperlimit']);
2057
				unset($cflink['upperlimit3']);
2058
			}
2059
		} else {
2060
			unset($cflink['upperlimit']);
2061
			unset($cflink['upperlimit1']);
2062
			unset($cflink['upperlimit2']);
2063
			unset($cflink['upperlimit3']);
2064
		}
2065
	}
2066
}
2067

    
2068
class cbq_queue extends priq_queue {
2069
	var $qborrow = "";
2070

    
2071
	function GetBorrow() {
2072
		return $this->qborrow;
2073
	}
2074
	function SetBorrow($borrow) {
2075
		$this->qborrow = $borrow;
2076
	}
2077
	function CanHaveChildren() {
2078
		return true;
2079
	}
2080

    
2081
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2082

    
2083
		if (!is_array($this->subqueues))
2084
			$this->subqueues = array();
2085
		$q =& new cbq_queue();
2086
		$q->SetInterface($this->GetInterface());
2087
		$q->SetParent(&$this);
2088
		$q->ReadConfig($qname);
2089
                $q->validate_input($qname, $input_errors);
2090
                if (count($input_errors)) {
2091
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
2092
                        return $q;
2093
                }
2094
                switch ($q->GetBwscale()) {
2095
                case "%":
2096
                	$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
2097
                        break;
2098
                default:
2099
                	$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
2100
                        break;
2101
                }
2102
                $q->SetAvailableBandwidth($myBw);
2103
                $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
2104

    
2105
		$q->SetEnabled("on");
2106
		$q->SetLink($path);
2107
		$this->subqueues[$q->GetQName()] = &$q;
2108
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2109
		if (is_array($qname['queue'])) {
2110
			foreach ($qname['queue'] as $key1 => $que) {
2111
				array_push($path, $key1);
2112
				$q->add_queue($q->GetInterface(), &$que, &$path, $input_errors);
2113
				array_pop($path);
2114
			}
2115
		}
2116

    
2117
		return $q;
2118
	}
2119

    
2120
	function copy_queue($interface, &$cflink) {
2121

    
2122
		$cflink['interface'] = $interface;
2123
		$cflink['qlimit'] = trim($this->GetQlimit());
2124
		if (empty($clink['qlimit']))
2125
			unset($cflink['qlimit']);
2126
		$cflink['priority'] = trim($this->GetQpriority());
2127
		if (empty($cflink['priority']))
2128
			unset($cflink['priority']);
2129
		$cflink['name'] = $this->GetQname();
2130
		$cflink['description'] = trim($this->GetDescription());
2131
		if (empty($cflink['description']))
2132
			unset($cflink['description']);
2133
		$cflink['bandwidth'] = $this->GetBandwidth();
2134
		$cflink['bandwidthtype'] = $this->GetBwscale();
2135
		$cflink['enabled'] = trim($this->GetEnabled());
2136
		if (empty($cflink['enabled']))
2137
			unset($cflink['enabled']);
2138
		$cflink['default'] = trim($this->GetDefault());
2139
		if (empty($cflink['default']))
2140
			unset($cflink['default']);
2141
		$cflink['red'] = trim($this->GetRed());
2142
		if (empty($cflink['red']))
2143
			unset($cflink['red']);
2144
		$cflink['rio'] = trim($this->GetRio());
2145
		if (empty($cflink['rio']))
2146
			unset($cflink['rio']);
2147
		$cflink['ecn'] = trim($this->GetEcn());
2148
		if (empty($cflink['ecn']))
2149
			unset($cflink['ecn']);
2150
		$cflink['borrow'] = trim($this->GetBorrow());
2151
		if (empty($cflink['borrow']))
2152
			unset($cflink['borrow']);
2153
		if (is_array($this->queues)) {
2154
			$cflinkp['queue'] = array();
2155
			foreach ($this->subqueues as $q) {
2156
				$cflink['queue'][$q->GetQname()] = array();
2157
				$q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
2158
			}
2159
		}
2160
	}
2161

    
2162
	/*
2163
	 * Should search even its children
2164
	 */
2165
	function &find_queue($interface, $qname) {
2166
		if ($qname == $this->GetQname())
2167
			return $this;
2168
		foreach ($this->subqueues as $q) {
2169
			$result =& $q->find_queue("", $qname);
2170
			if ($result)
2171
				return $result;
2172
		}
2173
	}
2174

    
2175
	function &find_parentqueue($interface, $qname) {
2176
		if ($this->subqueues[$qname])
2177
			return $this;
2178
		foreach ($this->subqueues as $q) {
2179
			$result = $q->find_parentqueue("", $qname);
2180
			if ($result)
2181
				return $result;
2182
		}
2183
	}
2184

    
2185
	function delete_queue() {
2186
		unref_on_altq_queue_list($this->GetQname());
2187
		cleanup_queue_from_rules($this->GetQname());
2188
		foreach ($this->subqueues as $q) {
2189
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
2190
			$q->delete_queue();
2191
		}
2192
		unset_object_by_reference($this->GetLink());
2193
	}
2194

    
2195
	function validate_input($data, &$input_errors) {
2196
		parent::validate_input($data, $input_errors);
2197

    
2198
		if ($data['priority'] > 7)
2199
				$input_errors[] = gettext("Priority must be an integer between 1 and 7.");
2200
		$reqdfields[] = "bandwidth";
2201
		$reqdfieldsn[] = gettext("Bandwidth");
2202
		$reqdfields[] = "bandwidthtype";
2203
		$reqdfieldsn[] = gettext("Bandwidthtype");
2204

    
2205
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2206

    
2207
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2208
			$input_errors[] = gettext("Bandwidth must be an integer.");
2209

    
2210

    
2211
		if ($data['bandwidth'] < 0)
2212
                       $input_errors[] = gettext("Bandwidth cannot be negative.");
2213

    
2214
		if ($data['bandwidthtype'] == "%") {
2215
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2216
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2217
		}
2218

    
2219
/*
2220
		$parent =& $this->GetParent();
2221
		switch ($data['bandwidthtype']) {
2222
		case "%":
2223
			$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2224
			break;
2225
		default:
2226
			$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2227
			break;
2228
		}
2229
                if ($parent->GetAvailableBandwidth() < floatval($myBw))
2230
                        $input_errors[] = "The sum of the children bandwidth exceeds that of the parent.";
2231
*/
2232
	}
2233

    
2234
	function ReadConfig(&$q) {
2235
		parent::ReadConfig($q);
2236
		if (!empty($q['borrow']))
2237
			$this->SetBorrow("on");
2238
		else
2239
			$this->SetBorrow("");
2240
	}
2241

    
2242
	function build_javascript() {
2243
		return parent::build_javascript();
2244
	}
2245

    
2246
	function build_tree() {
2247
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show"; 
2248
		$tree .= "\" ";
2249
		$tmpvalue = trim($this->GetDefault());
2250
		if (!empty($tmpvalue))
2251
			$tree .= " class=\"navlnk\"";
2252
		$tree .= " >" . $this->GetQname() . "</a>";
2253
		if (is_array($this->subqueues)) {
2254
			$tree .= "<ul>";
2255
			foreach ($this->subqueues as $q)  {
2256
				$tree .= $q->build_tree();
2257
			}	
2258
			$tree .= "</ul>";
2259
		}
2260
		$tree .= "</li>";
2261
		return $tree;
2262
	}
2263

    
2264
	/* Even this should take children into consideration */
2265
	function build_rules(&$default = false) {
2266
		$pfq_rule = "queue ". $this->qname;
2267
		if ($this->GetInterface())
2268
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2269
		if ($this->GetBandwidth() && $this->GetBwscale())
2270
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2271
		$tmpvalue = $this->GetQpriority();
2272
		if (!empty($tmpvalue))
2273
			$pfq_rule .= " priority " . $this->GetQpriority();
2274
		$tmpvalue = trim($this->GetQlimit());
2275
		if (!empty($tmpvalue))
2276
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2277
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow()) {
2278
			$pfq_rule .= " cbq ( ";
2279
			$tmpvalue = trim($this->GetRed());
2280
			if (!empty($tmpvalue)) {
2281
				$comma = 1;
2282
				$pfq_rule .= " red ";
2283
			}
2284
			$tmpvalue = trim($this->GetRio());
2285
			if (!empty($tmpvalue)) {
2286
				if ($comma) 
2287
					$pfq_rule .= " ,";
2288
				$comma = 1;
2289
				$pfq_rule .= " rio ";
2290
			}
2291
			$tmpvalue = trim($this->GetEcn());
2292
			if (!empty($tmpvalue)) {
2293
				if ($comma) 
2294
					$pfq_rule .= " ,";
2295
				$comma = 1;
2296
				$pfq_rule .= " ecn ";
2297
			}
2298
			$tmpvalue = trim($this->GetDefault());
2299
			if (!empty($tmpvalue)) {
2300
				if ($comma)
2301
					$pfq_rule .= " ,";
2302
				$comma = 1;
2303
				$pfq_rule .= " default ";
2304
				$default = true;
2305
			}
2306
			$tmpvalue = trim($this->GetBorrow());
2307
			if (!empty($tmpvalue)) {
2308
				if ($comma)
2309
					$pfq_rule .= ", ";
2310
				$pfq_rule .= " borrow ";
2311
			}
2312
			$pfq_rule .= " ) ";
2313
		} 
2314
		if (count($this->subqueues)) {
2315
			$i = count($this->subqueues);
2316
			$pfq_rule .= " { ";
2317
			foreach ($this->subqueues as $qkey => $qnone) {
2318
				if ($i > 1) {
2319
					$i--;
2320
					$pfq_rule .= " {$qkey}, ";
2321
				} else
2322
					$pfq_rule .= " {$qkey} ";
2323
			}
2324
			$pfq_rule .= " } \n";
2325
			foreach ($this->subqueues as $q)
2326
				$pfq_rule .= $q->build_rules($default);
2327
		}
2328

    
2329
		$pfq_rule .= " \n";
2330
		return $pfq_rule;
2331
	}
2332

    
2333
	function build_form() {
2334
		$form = parent::build_form();
2335
		$form .= "<tr>";
2336
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
2337
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2338
		if ($this->GetBandwidth() > 0)
2339
			$form .= htmlspecialchars($this->GetBandwidth());
2340
		$form .= "\" />";
2341
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2342
		$form .= "<option value=\"Gb\"";
2343
		if ($this->GetBwscale() == "Gb")
2344
			$form .= " selected=\"selected\"";
2345
		$form .= ">" . gettext("Gbit/s") . "</option>";
2346
		$form .= "<option value=\"Mb\"";
2347
		if ($this->GetBwscale() == "Mb")
2348
			$form .= " selected=\"selected\"";
2349
		$form .= ">" . gettext("Mbit/s") . "</option>";
2350
		$form .= "<option value=\"Kb\"";
2351
		if ($this->GetBwscale() == "Kb")
2352
			$form .= " selected=\"selected\"";
2353
		$form .= ">" . gettext("Kbit/s") . "</option>";
2354
		$form .= "<option value=\"b\"";
2355
		if ($this->GetBwscale() == "b")
2356
			$form .= " selected=\"selected\"";
2357
		$form .= ">" . gettext("Bit/s") . "</option>";
2358
		$form .= "<option value=\"%\"";
2359
		if ($this->GetBwscale() == "%")
2360
			$form .= " selected=\"selected\"";
2361
		$form .= ">%</option>";
2362
		$form .= "</select> <br/>";
2363
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
2364
		$form .= "</span></td></tr>";
2365
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
2366
		$form .= "<td class=\"vtable\"><input type=\"checkbox\" id=\"borrow\" name=\"borrow\"";
2367
		if($this->GetBorrow() == "on") 
2368
			$form .=  " checked=\"checked\" ";
2369
		$form .= " /> " . gettext("Borrow from other queues when available") . "<br/></td></tr>";
2370

    
2371
		return $form;
2372
	}
2373

    
2374
	function update_altq_queue_data(&$data) { 
2375
		$this->ReadConfig($data);
2376
	}
2377

    
2378
	function wconfig() {
2379
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2380
		if (!is_array($cflink))
2381
			$cflink = array();
2382
		$cflink['interface'] = $this->GetInterface();
2383
		$cflink['qlimit'] = trim($this->GetQlimit());
2384
		if (empty($cflink['qlimit']))
2385
			unset($cflink['qlimit']);
2386
		$cflink['priority'] = $this->GetQpriority();
2387
		if (empty($cflink['priority']))
2388
			unset($cflink['priority']);
2389
		$cflink['name'] = $this->GetQname();
2390
		$cflink['description'] = $this->GetDescription();
2391
		if (empty($cflink['description']))
2392
			unset($cflink['description']);
2393
		$cflink['bandwidth'] = $this->GetBandwidth();
2394
		$cflink['bandwidthtype'] = $this->GetBwscale();
2395
		$cflink['enabled'] = trim($this->GetEnabled());
2396
		if (empty($cflink['enabled']))
2397
			unset($cflink['enabled']);
2398
		$cflink['default'] = trim($this->GetDefault());
2399
		if (empty($cflink['default']))
2400
			unset($cflink['default']);
2401
		$cflink['red'] = trim($this->GetRed());
2402
		if (empty($cflink['red']))
2403
			unset($cflink['red']);
2404
		$cflink['rio'] = trim($this->GetRio());
2405
		if (empty($cflink['rio']))
2406
			unset($cflink['rio']);
2407
		$cflink['ecn'] = trim($this->GetEcn());
2408
		if (empty($cflink['ecn']))
2409
			unset($cflink['ecn']);
2410
		$cflink['borrow'] = trim($this->GetBorrow());
2411
		if (empty($cflink['borrow']))
2412
			unset($cflink['borrow']);
2413
	}
2414
}
2415

    
2416
class fairq_queue extends priq_queue {
2417
	var $hogs;
2418
	var $buckets;
2419

    
2420
	function GetBuckets() {
2421
		return $this->buckets;
2422
	}
2423
	function SetBuckets($buckets) {
2424
		$this->buckets = $buckets;
2425
	}
2426
	function GetHogs() {
2427
		return $this->hogs;
2428
	}
2429
	function SetHogs($hogs) {
2430
		$this->hogs = $hogs;
2431
	}
2432
	function CanHaveChildren() {
2433
		return false;
2434
	}
2435

    
2436

    
2437
	function copy_queue($interface, &$cflink) {
2438
                $cflink['interface'] = $interface;
2439
                $cflink['qlimit'] = $this->GetQlimit();
2440
                $cflink['priority'] = $this->GetQpriority();
2441
                $cflink['name'] = $this->GetQname();
2442
                $cflink['description'] = $this->GetDescription();
2443
                $cflink['bandwidth'] = $this->GetBandwidth();
2444
                $cflink['bandwidthtype'] = $this->GetBwscale();
2445
                $cflink['enabled'] = $this->GetEnabled();
2446
                $cflink['default'] = $this->GetDefault();
2447
                $cflink['red'] = $this->GetRed();
2448
                $cflink['rio'] = $this->GetRio();
2449
                $cflink['ecn'] = $this->GetEcn();
2450
                $cflink['buckets'] = $this->GetBuckets();
2451
		$cflink['hogs'] = $this->GetHogs();
2452
	}
2453

    
2454
	/*
2455
	 * Should search even its children
2456
	 */
2457
	function &find_queue($interface, $qname) {
2458
		if ($qname == $this->GetQname())
2459
			return $this;
2460
	}
2461

    
2462
	function find_parentqueue($interface, $qname) { return; }
2463

    
2464
	function delete_queue() {
2465
		unref_on_altq_queue_list($this->GetQname());
2466
		cleanup_queue_from_rules($this->GetQname());
2467
		unset_object_by_reference($this->GetLink());
2468
	}
2469

    
2470
	function validate_input($data, &$input_errors) {
2471
		parent::validate_input($data, $input_errors);
2472

    
2473
		if ($data['priority'] > 255)
2474
				$input_errors[] = gettext("Priority must be an integer between 1 and 255.");
2475
		$reqdfields[] = "bandwidth";
2476
		$reqdfieldsn[] = gettext("Bandwidth");
2477
		$reqdfields[] = "bandwidthtype";
2478
		$reqdfieldsn[] = gettext("Bandwidthtype");
2479

    
2480
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2481

    
2482
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2483
			$input_errors[] = gettext("Bandwidth must be an integer.");
2484

    
2485

    
2486
		if ($data['bandwidth'] < 0)
2487
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2488

    
2489

    
2490
		if ($data['bandwidthtype'] == "%") {
2491
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2492
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2493
		}
2494

    
2495
/*
2496
           	$parent =& $this->GetParent();
2497
           	switch ($data['bandwidthtype']) {
2498
                       case "%":
2499
                             $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2500
                       default:
2501
                             $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2502
                             break;
2503
           	}
2504
                if ($parent->GetAvailableBandwidth() < floatval($myBw))
2505
                        $input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
2506
*/
2507
	}
2508

    
2509
	function ReadConfig(&$q) {
2510
		parent::ReadConfig($q);
2511
		if (!empty($q['buckets']))
2512
			$this->SetBuckets($q['buckets']);
2513
		else
2514
			$this->SetBuckets("");
2515
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs']))
2516
			$this->SetHogs($q['hogs']);
2517
		else
2518
			$this->SetHogs("");
2519
	}
2520

    
2521
	function build_javascript() {
2522
		return parent::build_javascript();
2523
	}
2524

    
2525
	function build_tree() {
2526
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . 
2527
		$this->GetInterface()."&amp;queue=" . $this->GetQname()."&amp;action=show"; 
2528
		$tree .= "\" ";
2529
		$tmpvalue = trim($this->GetDefault());
2530
		if (!empty($tmpvalue))
2531
			$tree .= " class=\"navlnk\"";
2532
		$tree .= " >" . $this->GetQname() . "</a>";
2533
		$tree .= "</li>";
2534
		return $tree;
2535
	}
2536

    
2537
	/* Even this should take children into consideration */
2538
	function build_rules(&$default = false) {
2539
		$pfq_rule = "queue ". $this->qname;
2540
		if ($this->GetInterface())
2541
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2542
		if ($this->GetBandwidth() && $this->GetBwscale())
2543
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2544
		$tmpvalue = trim($this->GetQpriority());
2545
		if (!empty($tmpvalue))
2546
			$pfq_rule .= " priority " . $this->GetQpriority();
2547
		$tmpvalue = trim($this->GetQlimit());
2548
		if (!empty($tmpvalue))
2549
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2550
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() 
2551
			|| $this->GetEcn() || $this->GetBuckets() || $this->GetHogs()) {
2552
			$pfq_rule .= " fairq ( ";
2553
			$tmpvalue = trim($this->GetRed());
2554
			if (!empty($tmpvalue)) {
2555
				$comma = 1;
2556
				$pfq_rule .= " red ";
2557
			}
2558
			$tmpvalue = trim($this->GetRio());
2559
			if (!empty($tmpvalue)) {
2560
				if ($comma) 
2561
					$pfq_rule .= " ,";
2562
				$comma = 1;
2563
				$pfq_rule .= " rio ";
2564
			}
2565
			$tmpvalue = trim($this->GetEcn());
2566
			if (!empty($tmpvalue)) {
2567
				if ($comma) 
2568
					$pfq_rule .= " ,";
2569
				$comma = 1;
2570
				$pfq_rule .= " ecn ";
2571
			}
2572
			$tmpvalue = trim($this->GetDefault());
2573
			if (!empty($tmpvalue)) {
2574
				if ($comma)
2575
					$pfq_rule .= " ,";
2576
				$comma = 1;
2577
				$pfq_rule .= " default ";
2578
				$default = true;
2579
			}
2580
			$tmpvalue = trim($this->GetBuckets());
2581
			if (!empty($tmpvalue)) {
2582
				if ($comma)
2583
					$pfq_rule .= ", ";
2584
				$pfq_rule .= " buckets " . $this->GetBuckets() . " ";
2585
			}
2586
			$tmpvalue = trim($this->GetHogs());
2587
			if (!empty($tmpvalue)) {
2588
				if ($comma)
2589
					$pfq_rule .= ", ";
2590
				$pfq_rule .= " hogs " . $this->GetHogs() . " ";
2591
			}
2592
				$pfq_rule .= " ) ";
2593
		} 
2594

    
2595
		$pfq_rule .= " \n";
2596
		return $pfq_rule;
2597
	}
2598

    
2599
	function build_form() {
2600
		$form = parent::build_form();
2601
		$form .= "<tr>";
2602
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth") . "</td>";
2603
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2604
		if ($this->GetBandwidth() > 0)
2605
			$form .= htmlspecialchars($this->GetBandwidth());
2606
		$form .= "\" />";
2607
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2608
		$form .= "<option value=\"Gb\"";
2609
		if ($this->GetBwscale() == "Gb")
2610
			$form .= " selected=\"selected\"";
2611
		$form .= ">" . gettext("Gbit/s") . "</option>";
2612
		$form .= "<option value=\"Mb\"";
2613
		if ($this->GetBwscale() == "Mb")
2614
			$form .= " selected=\"selected\"";
2615
		$form .= ">" . gettext("Mbit/s") . "</option>";
2616
		$form .= "<option value=\"Kb\"";
2617
		if ($this->GetBwscale() == "Kb")
2618
			$form .= " selected=\"selected\"";
2619
		$form .= ">" . gettext("Kbit/s") . "</option>";
2620
		$form .= "<option value=\"b\"";
2621
		if ($this->GetBwscale() == "b")
2622
			$form .= " selected=\"selected\"";
2623
		$form .= ">" . gettext("Bit/s") . "</option>";
2624
		$form .= "<option value=\"%\"";
2625
		if ($this->GetBwscale() == "%")
2626
			$form .= " selected=\"selected\"";
2627
		$form .= ">%</option>";
2628
		$form .= "</select> <br/>";
2629
		$form .= "<span class=\"vexpl\">" . gettext("Choose the amount of bandwidth for this queue");
2630
		$form .= "</span></td></tr>";
2631
		$form .= "<tr><td class=\"vncellreq\">" . gettext("Scheduler specific options") . "</td>";
2632
		$form .= "<td class=\"vtable\"><table><tr><td>";
2633
		$form .= "<input id=\"buckets\" name=\"buckets\" value=\"";
2634
		$tmpvalue = trim($this->GetBuckets());
2635
		if(!empty($tmpvalue)) 
2636
			$form .=  $this->GetBuckets();
2637
		$form .= "\" /> " . gettext("Number of buckets available.") . "<br/></td></tr>";
2638
		$form .= "<tr><td class=\"vtable\"><input id=\"hogs\" name=\"hogs\" value=\"";
2639
		$tmpvalue = trim($this->GetHogs());
2640
		if(!empty($tmpvalue)) 
2641
			$form .=  $this->GetHogs();
2642
		$form .= "\" /> " . gettext("Bandwidth limit for hosts to not saturate link.") . "<br/></td></tr>";
2643
		$form .= "</table></td></tr>";
2644
		return $form;
2645
	}
2646

    
2647
	function update_altq_queue_data(&$data) { 
2648
		$this->ReadConfig($data);
2649
	}
2650

    
2651
	function wconfig() {
2652
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2653
		if (!is_array($cflink))
2654
			$cflink = array();
2655
		$cflink['interface'] = $this->GetInterface();
2656
		$cflink['qlimit'] = trim($this->GetQlimit());
2657
		if (empty($cflink['qlimit']))
2658
			unset($cflink['qlimit']);
2659
		$cflink['priority'] = trim($this->GetQpriority());
2660
		if (empty($cflink['priority']))
2661
			unset($cflink['priority']);
2662
		$cflink['name'] = $this->GetQname();
2663
		$cflink['description'] = trim($this->GetDescription());
2664
		if (empty($cflink['description']))
2665
			unset($cflink['description']);
2666
		$cflink['bandwidth'] = $this->GetBandwidth();
2667
		$cflink['bandwidthtype'] = $this->GetBwscale();
2668
		$cflink['enabled'] = $this->GetEnabled();
2669
		if (empty($cflink['enabled']))
2670
			unset($cflink['enabled']);
2671
		$cflink['default'] = trim($this->GetDefault());
2672
		if (empty($cflink['default']))
2673
			unset($cflink['default']);
2674
		$cflink['red'] = trim($this->GetRed());
2675
		if (empty($cflink['red']))
2676
			unset($cflink['red']);
2677
		$cflink['rio'] = trim($this->GetRio());
2678
		if (empty($cflink['rio']))
2679
			unset($cflink['rio']);
2680
		$cflink['ecn'] = trim($this->GetEcn());
2681
		if (empty($cflink['ecn']))
2682
			unset($cflink['ecn']);
2683
		$cflink['buckets'] = trim($this->GetBuckets());
2684
		if (empty($cflink['buckets']))
2685
			unset($cflink['buckets']);
2686
		$cflink['hogs'] = trim($this->GetHogs());
2687
		if (empty($cflink['hogs']))
2688
			unset($cflink['hogs']);
2689
	}
2690
}
2691

    
2692

    
2693
/*
2694
 * dummynet(4) wrappers.
2695
 */
2696

    
2697

    
2698
/*
2699
 * List of respective objects!
2700
 */
2701
$dummynet_pipe_list = array();
2702

    
2703
class dummynet_class {
2704
        var $qname;
2705
	var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
2706
        var $qlimit;
2707
        var $description;
2708
	var $qenabled;
2709
	var $link;
2710
	var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
2711
        var $plr;
2712

    
2713
        var $buckets;
2714
        /* mask parameters */
2715
        var $mask;
2716
        var $noerror;
2717

    
2718
        /* Accessor functions */
2719
        function SetLink($link) {
2720
                $this->link = $link;
2721
        }
2722
        function GetLink() {
2723
                return $this->link;
2724
        }
2725
	function Getmask() {
2726
		return $this->mask;
2727
	}
2728
	function SetMask($mask) {
2729
		$this->mask = $mask;
2730
	}
2731
	function &GetParent() {
2732
		return $this->qparent;
2733
	}
2734
	function SetParent(&$parent) {
2735
		$this->qparent = &$parent;
2736
	}
2737
        function GetEnabled() {
2738
                return $this->qenabled;
2739
        }
2740
        function SetEnabled($value) {
2741
                $this->qenabled = $value;
2742
        }
2743
	function CanHaveChildren() {
2744
		return false;
2745
        }
2746
	function CanBeDeleted() {
2747
                return true;
2748
        }
2749
        function GetQname() {
2750
                return $this->qname;
2751
        }
2752
        function SetQname($name) {
2753
                $this->qname = trim($name);
2754
        }
2755
        function GetQlimit() {
2756
                return $this->qlimit;
2757
        }
2758
        function SetQlimit($limit) {
2759
               	$this->qlimit = $limit;
2760
        }
2761
        function GetDescription() {
2762
                return $this->description;
2763
        }
2764
        function SetDescription($str) {
2765
                $this->description = trim($str);
2766
        }
2767
        function GetFirstime() {
2768
                return $this->firsttime;
2769
        }
2770
        function SetFirsttime($number) {
2771
                $this->firsttime = $number;
2772
        }
2773
        function GetBuckets() {
2774
                return $this->buckets;
2775
        }
2776
        function SetBuckets($buckets) {
2777
                $this->buckets = $buckets;
2778
        }
2779
	function SetNumber($number) {
2780
		$this->qnumber = $number;
2781
	}
2782
	function GetNumber() {
2783
		return $this->qnumber;
2784
	}
2785
        function GetPlr() {
2786
                return $this->plr;
2787
        }
2788
        function SetPlr($plr) {
2789
                $this->plr = $plr;
2790
        }
2791

    
2792
	function build_javascript() { return; } /* Do not remove */
2793

    
2794
	function validate_input($data, &$input_errors) {
2795
		$reqdfields[] = "bandwidth";
2796
		$reqdfieldsn[] = gettext("Bandwidth");
2797
		$reqdfields[] = "bandwidthtype";
2798
		$reqdfieldsn[] = gettext("Bandwidthtype");
2799
		$reqdfields[] = "newname";
2800
		$reqdfieldsn[] = gettext("Name");
2801

    
2802
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2803

    
2804
		if ($data['plr'] && ((!is_numeric($data['plr'])) ||
2805
			($data['plr'] <= 0 && $data['plr'] > 1))) 
2806
				$input_errors[] = gettext("Plr must be an integer between 1 and 100.");
2807
		if (($data['buckets'] && (!is_numeric($data['buckets']))) ||
2808
			($data['buckets'] < 1 && $data['buckets'] > 100)) 
2809
				$input_errors[] = gettext("Buckets must be an integer between 16 and 65535.");
2810
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) 
2811
            		$input_errors[] = gettext("Queue limit must be an integer");
2812
        	if (!empty($data['newname']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['newname']))
2813
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2814
        	if (!empty($data['name']) && !preg_match("/^[a-zA-Z0-9_-]+$/", $data['name']))
2815
			$input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
2816
	}
2817
}
2818

    
2819
class dnpipe_class extends dummynet_class {
2820
        var $delay;
2821
	var $qbandwidth = array();
2822
	var $qbandwidthtype;
2823

    
2824
		/* This is here to help on form building and building rules/lists */
2825
        var $subqueues = array();
2826

    
2827
	function CanHaveChildren() {
2828
	        return true;
2829
        }
2830
	function SetDelay($delay) {
2831
		$this->delay = $delay;
2832
	}
2833
	function GetDelay() {
2834
		return $this->delay;
2835
	}
2836
	function delete_queue() {
2837
		cleanup_dnqueue_from_rules($this->GetQname());
2838
		foreach ($this->subqueues as $q)
2839
			$q->delete_queue();
2840
		unset_dn_object_by_reference($this->GetLink());
2841
		mwexec("/sbin/ipfw pipe delete " . $this->GetNumber());
2842
        }
2843
        function GetBandwidth() {
2844
                return $this->qbandwidth;
2845
        }
2846
        function SetBandwidth($bandwidth) {
2847
                $this->qbandwidth = $bandwidth;
2848
        }
2849

    
2850
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
2851

    
2852
		if (!is_array($this->subqueues))
2853
			$this->subqueues = array();
2854

    
2855
		$q =& new dnqueue_class();
2856
		$q->SetLink($path);
2857
		$q->SetEnabled("on");
2858
		$q->SetPipe($this->GetQname());
2859
		$q->SetParent(&$this);
2860
		$q->ReadConfig($queue);
2861
		$q->validate_input($queue, $input_errors);
2862
		if (count($input_errors)) {
2863
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
2864
			return $q;
2865
		}
2866
		$number = dnqueue_find_nextnumber();
2867
		$q->SetNumber($number);
2868
		$this->subqueues[$q->GetQname()] = &$q;
2869
            
2870
		return $q;
2871
	}
2872

    
2873
	function &get_queue_list($q = null) {
2874
		$qlist = array();
2875

    
2876
		$qlist[$this->GetQname()] = $this->GetNumber();
2877
		if (is_array($this->subqueues)) {
2878
			foreach ($this->subqueues as $queue)
2879
				$queue->get_queue_list(&$qlist);
2880
		}
2881
		return $qlist;
2882
	}
2883

    
2884
        /*
2885
         * Should search even its children
2886
         */
2887
        function &find_queue($pipe, $qname) {
2888
                if ($qname == $this->GetQname()) 
2889
                        return $this;
2890
               	foreach ($this->subqueues as $q) {
2891
                       	$result =& $q->find_queue("", $qname);
2892
						if ($result)
2893
                       	        return $result;
2894
               	}
2895
        }
2896

    
2897
	function &find_parentqueue($pipe, $qname) {
2898
		return NULL;
2899
       	}
2900

    
2901
	function validate_input($data, &$input_errors) {
2902
		parent::validate_input($data, $input_errors);
2903

    
2904
		$schedule = 0;
2905
		$schedulenone = 0;
2906
		$entries = 0;
2907
		for ($i = 0; $i < 30; $i++) {
2908
			if (!empty($data["bwsched{$i}"])) {
2909
				if ($data["bwsched{$i}"] != "none")
2910
					$schedule++;
2911
				else
2912
					$schedulenone++;
2913
			}
2914
			if (!empty($data["bandwidth{$i}"])) {
2915
				if (!is_numeric($data["bandwidth{$i}"]))
2916
					$input_errors[] = sprintf(gettext("Bandwidth for schedule %s must be an integer."), $data["bwsched{$i}"]);
2917
				else
2918
					$entries++;
2919
			}
2920
		}
2921
		if ($schedule == 0 && $entries > 1)
2922
			$input_errors[] = gettext("You need to specify a schedule for every additional entry");
2923
		if ($schedulenone > 0 && $entries > 1)
2924
			$input_errors[] = gettext("If more than one bandwidth configured all schedules need to be selected");
2925
		if ($entries == 0)
2926
			$input_errors[] = gettext("At least one bw specification is necessary");
2927
		if ($data['delay'] && (!is_numeric($data['delay'])))
2928
			$input_errors[] = gettext("Delay must be an integer.");
2929
	}
2930

    
2931
	function ReadConfig(&$q) {
2932
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
2933
			$this->SetQname($q['newname']);
2934
		} else if (!empty($q['newname'])) {
2935
			$this->SetQname($q['newname']);
2936
		} else {
2937
			$this->SetQname($q['name']);
2938
		}
2939
		$this->SetNumber($q['number']);
2940

    
2941
		if (!empty($_POST)) {
2942
			$bandwidth = array();
2943
			for ($i = 0; $i < 30; $i++) {
2944
				if (isset($q["bandwidth{$i}"]) && $q["bandwidth{$i}"] <> "") { 
2945
					$bw = array();
2946
					$bw['bw'] = $q["bandwidth{$i}"];
2947
					if (isset($q["bwtype{$i}"]) && $q["bwtype{$i}"])
2948
						$bw['bwscale'] = $q["bwtype{$i}"];
2949
					if (isset($q["bwsched{$i}"]) && $q["bwsched{$i}"])
2950
						$bw['bwsched'] = $q["bwsched{$i}"];
2951
					$bandwidth[] = $bw;
2952
				}
2953
			}
2954
			$this->SetBandwidth($bandwidth);
2955
		}
2956
		if (is_array($q['bandwidth']) && is_array($q['bandwidth']['item']))
2957
			$this->SetBandwidth($q['bandwidth']['item']);
2958

    
2959
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
2960
              		$this->SetQlimit($q['qlimit']);
2961
		else
2962
              		$this->SetQlimit("");
2963
		if (isset($q['mask']) && $q['mask'] <> "")
2964
              		$this->SetMask($q['mask']);
2965
		else
2966
              		$this->SetMask("");
2967
		if (isset($q['buckets']) && $q['buckets'] <> "")
2968
              		$this->SetBuckets($q['buckets']);
2969
		else
2970
              		$this->SetBuckets("");
2971
            	if (isset($q['plr']) && $q['plr'] <> "")
2972
            		$this->SetPlr($q['plr']);
2973
		else
2974
            		$this->SetPlr("");
2975
		if (isset($q['delay']) && $q['delay'] <> "")
2976
            		$this->SetDelay($q['delay']);
2977
		else
2978
			$this->SetDelay(0);
2979
            	if (isset($q['description']) && $q['description'] <> "")
2980
			$this->SetDescription($q['description']);
2981
		else
2982
			$this->SetDescription("");
2983
		$this->SetEnabled($q['enabled']);
2984

    
2985
        }
2986

    
2987
	function build_tree() {
2988
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&amp;queue=".$this->GetQname() ."&amp;action=show\">"; 
2989
		$tree .= $this->GetQname() . "</a>";
2990
		if (is_array($this->subqueues)) {
2991
			$tree .= "<ul>";
2992
			foreach ($this->subqueues as $q)  {
2993
				$tree .= $q->build_tree();
2994
			}	
2995
			$tree .= "</ul>";
2996
		}
2997
		$tree .= "</li>";
2998

    
2999
		return $tree;
3000
	}
3001

    
3002
        function build_rules() {
3003
		global $config, $time_based_rules;
3004

    
3005
		if ($this->GetEnabled() == "")
3006
			return;
3007

    
3008
		$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
3009
		$found = false;
3010
		$bandwidth = $this->GetBandwidth();
3011
		if (is_array($bandwidth)) {
3012
			foreach ($bandwidth as $bw) {
3013
				if ($bw['bwsched'] != "none") {
3014
					$time_based_rules = true;
3015
					if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3016
						foreach ($config['schedules']['schedule'] as $schedule) {
3017
							if ($bw['bwsched'] == $schedule['name']) {
3018
								if (filter_get_time_based_rule_status($schedule)) {
3019
									$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3020
									$found = true;
3021
									break;
3022
								}
3023
							}
3024
						}
3025
					} else {
3026
						$pfq_rule .= " bw 0";
3027
						$found = true;
3028
						break;
3029
					}
3030
				} else {
3031
					$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3032
					$found = true;
3033
					break;
3034
				}
3035
			}
3036
			if ($found == false)
3037
				$pfq_rule .= " bw 0";
3038
		} else
3039
			$pfq_rule .= " bw 0";
3040

    
3041
		if ($this->GetQlimit())
3042
                    	$pfq_rule .= " queue " . $this->GetQlimit();
3043
		if ($this->GetPlr())
3044
			$pfq_rule .= " plr " . $this->GetPlr();
3045
		if ($this->GetBuckets())
3046
			$pfq_rule .= " buckets " . $this->GetBuckets();
3047
		if ($this->GetDelay())
3048
			$pfq_rule .= " delay " . $this->GetDelay();
3049

    
3050
		$mask = $this->GetMask();
3051
		if (!empty($mask)) {
3052
			/* XXX TODO extend this to support more complicated masks */
3053
			switch ($mask) {
3054
			case 'srcaddress':
3055
				$pfq_rule .= " mask src-ip 0xffffffff ";
3056
				break;
3057
			case 'dstaddress':
3058
				$pfq_rule .= " mask dst-ip 0xffffffff ";
3059
				break;
3060
			default:
3061
				break;
3062
			}
3063
    		}            
3064
		$pfq_rule .= "\n";
3065

    
3066
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3067
			foreach ($this->subqueues as $q)
3068
			$pfq_rule .= $q->build_rules();
3069
		}
3070
		$pfq_rule .= " \n";
3071

    
3072
		return $pfq_rule;
3073
        }
3074

    
3075
	function update_dn_data(&$data) { 
3076
		$this->ReadConfig($data);
3077
	}
3078

    
3079
	function build_javascript() {
3080
		global $g, $config;
3081

    
3082
		//build list of schedules
3083
		$schedules = "<option value='none'>none</option>";
3084
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3085
			foreach ($config['schedules']['schedule'] as $schedule) {
3086
				if ($schedule['name'] <> "")
3087
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3088
			}
3089
		}
3090
		$bwopt = "";
3091
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw)
3092
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3093

    
3094
		$javasr = <<<EOD
3095
<script type='text/javascript'>
3096
//<![CDATA[
3097
var addBwRowTo = (function() {
3098
	return (function (tableId) {
3099
	var d, tbody, tr, td;
3100
	d = document;
3101
	tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0);
3102
	tr = d.createElement("tr");
3103
	td = d.createElement("td");
3104
	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 + "' />";
3105
	tr.appendChild(td);
3106
	td = d.createElement("td");
3107
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "' /><select class='formselect' name='bwtype" + totalrows + "'>{$bwopt}</select>";
3108
	tr.appendChild(td);
3109
	td = d.createElement("td");
3110
	td.innerHTML="<input type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "' /><select class='formselect' name='bwsched" + totalrows + "'>{$schedules}</select>";
3111
	tr.appendChild(td);
3112
	td = d.createElement("td");
3113
	td.rowSpan = "1";
3114
	td.innerHTML = '<a onclick="removeBwRow(this); return false;" href="#"><img border="0" src="/themes/{$g['theme']}/images/icons/icon_x.gif" alt="remove" /></a>';
3115
	tr.appendChild(td);
3116
	tbody.appendChild(tr);
3117
	totalrows++;
3118
	});
3119
})();
3120

    
3121
function removeBwRow(el) {
3122
	var cel;
3123
	while (el && el.nodeName.toLowerCase() != "tr")
3124
	    el = el.parentNode;
3125
		if (el && el.parentNode) {
3126
			cel = el.getElementsByTagName("td").item(0);
3127
			el.parentNode.removeChild(el);
3128
		}
3129
}
3130
//]]>
3131
</script>
3132

    
3133
EOD;
3134

    
3135
	       return $javasr;
3136
	}
3137

    
3138
        function build_form() { 
3139
		global $g, $config;
3140

    
3141
		//build list of schedules
3142
		$schedules = array();
3143
		$schedules[] = "none";//leave none to leave rule enabled all the time
3144
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3145
			foreach ($config['schedules']['schedule'] as $schedule) {
3146
				if ($schedule['name'] <> "")
3147
					$schedules[] = $schedule['name'];
3148
			}
3149
		}
3150

    
3151
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br/>";
3152
                $form .= gettext("Enable");
3153
                $form .= "</td><td class=\"vncellreq\">";
3154
                $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
3155
                if ($this->GetEnabled() == "on")
3156
                        $form .=  " checked=\"checked\"";
3157
                $form .= " /><span class=\"vexpl\"> " . gettext("Enable limiter and its children") . "</span>";
3158
                $form .= "</td></tr>";
3159
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br/><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3160
		$form .= "<td class=\"vncellreq\">";
3161
		$form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
3162
		$form .= $this->GetQname()."\" />";
3163
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
3164
		$form .= $this->GetQname()."\" />";
3165
		if ($this->GetNumber() > 0) {
3166
			$form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
3167
			$form .= $this->GetNumber()."\" />";
3168
		}
3169
		$form .= "</td></tr>";
3170
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Bandwidth");
3171
		$bandwidth = $this->GetBandwidth();
3172
		$form .= "</td><td class=\"vncellreq\">";
3173
		$form .= "<table id='maintable'>";
3174
		$form .= "<tbody><tr>";
3175
		$form .= "<td width='40%'><div id='onecolumn'>Bandwidth</div></td>";
3176
		$form .= "<td width='20%'><div id='twocolumn'>Bw type</div></td>";
3177
		$form .= "<td width='35%' ><div id='thirdcolumn'>Schedule</div></td>";
3178
		$form .= "<td width='5%'><div id='fourthcolumn'></div></td>";
3179
		$form .= "</tr>";
3180
		if (is_array($bandwidth)) {
3181
			foreach ($bandwidth as $bwidx => $bw) {
3182
				$form .= "\n<tr><td width='40%'>";
3183
				$form .= "<input class='formfld unknown' size='10' type=\"text\" id=\"bandwidth{$bwidx}\" name=\"bandwidth{$bwidx}\" value=\"{$bw['bw']}\" />";
3184
				$form .= "</td><td width='20%'>";
3185
				$form .= "<select id=\"bwtype{$bwidx}\" name=\"bwtype{$bwidx}\" class=\"formselect\">";
3186
				foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwsidx => $bwscale) {
3187
					$form .= "<option value=\"{$bwsidx}\"";
3188
					if ($bw['bwscale'] == $bwsidx)
3189
						$form .= " selected=\"selected\"";
3190
					$form .= ">{$bwscale}</option>";
3191
				}
3192
				$form .= "</select>";
3193
				$form .= "</td><td width='35%' >";
3194
				$form .= "<select id=\"bwsched{$bwidx}\" name=\"bwsched{$bwidx}\" class=\"formselect\">";
3195
				foreach ($schedules as $schd) {
3196
					$selected = "";
3197
					if ($bw['bwsched'] == $schd)
3198
						$selected = "selected=\"selected\"";
3199
					$form .= "<option value='{$schd}' {$selected}>{$schd}</option>";
3200
				}
3201
				$form .= "</select>";
3202
				$form .= "</td><td width='5%' >";
3203
				$form .= "<a onclick=\"removeBwRow(this); return false;\" href='#'><img border='0' src='/themes/{$g['theme']}/images/icons/icon_x.gif' alt='remove' /></a>";
3204
				$form .= "</td></tr>";
3205
			}
3206
		}
3207
		$form .= "</tbody></table>";
3208
		$form .= "<a onclick=\"javascript:addBwRowTo('maintable'); return false;\" href='#'>";
3209
		$form .= "<img border='0' src='/themes/{$g['theme']}/images/icons/icon_plus.gif' alt='add' title='" . gettext("add another schedule") . "' /></a>";
3210
		$form .= "</td></tr>";
3211
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
3212
		$form .= "<td class=\"vncellreq\">";
3213
		$form .= "<select name=\"mask\" class=\"formselect\">";
3214
		$form .= "<option value=\"none\"";
3215
		if ($this->GetMask() == "none")
3216
			$form .= " selected=\"selected\"";
3217
		$form .= ">none</option>";
3218
		$form .= "<option value=\"srcaddress\"";
3219
		if ($this->GetMask() == "srcaddress")
3220
			$form .= " selected=\"selected\"";
3221
		$form .= ">" . gettext("Source addresses") . "</option>";
3222
		$form .= "<option value=\"dstaddress\"";
3223
		if ($this->GetMask() == "dstaddress")
3224
			$form .= " selected=\"selected\"";
3225
		$form .= ">" . gettext("Destination addresses") . "</option>";
3226
		$form .= "</select>";
3227
		$form .= "&nbsp;<br/>";
3228
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' is chosen, \n"
3229
		      .  "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
3230
		      .  "be created for each source/destination IP address encountered, \n"
3231
		      .  "respectively. This makes it possible to easily specify bandwidth \n"
3232
		      .  "limits per host.") . "</span>";
3233
		$form .= "</td></tr>";
3234
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3235
		$form .= "<td class=\"vncellreq\">";
3236
		$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"50%\" id=\"description\" name=\"description\" value=\"";
3237
		$form .= $this->GetDescription();
3238
		$form .= "\" />";
3239
		$form .= "<br/> <span class=\"vexpl\">";
3240
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3241
		$form .= "</td></tr>";
3242
      		$form .= "<tr id=\"sprtable4\" name=\"sprtable4\">";
3243
		$form .= "<td></td>";
3244
                $form .= "<td><div id=\"showadvancedboxspr\">";
3245
                $form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
3246
		$form .= " value=\"" . gettext("Show advanced options") . "\" />";
3247
                $form .= "</div></td></tr>";
3248
                $form .= "<tr style=\"display:none\" id=\"sprtable\" name=\"sprtable\">";
3249

    
3250
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Delay") . "</td>";
3251
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3252
		$form .= "<input name=\"delay\" type=\"text\" id=\"delay\" size=\"5\" value=\"";
3253
		$form .= $this->GetDelay() . "\" />";
3254
		$form .= "&nbsp;ms<br/> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3255
			  .  "should specify 0 here (or leave the field empty)") . "</span>";
3256
		$form .= "</td></tr><br/>";
3257
      		$form .= "<tr style=\"display:none\" id=\"sprtable1\" name=\"sprtable1\">";
3258
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
3259
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3260
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
3261
		$form .= $this->GetPlr() . "\" />";
3262
		$form .= "&nbsp;<br/> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3263
			  .  "should specify 0 here (or leave the field empty). "
3264
		      .  "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
3265
		$form .= "</td></tr>";
3266
		$form .= "<tr style=\"display:none\" id=\"sprtable2\" name=\"sprtable2\">";
3267
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
3268
		$form .= "<td class=\"vncellreq\">";
3269
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
3270
		$form .= $this->GetQlimit() . "\" />";
3271
		$form .= "&nbsp;slots<br/>";
3272
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3273
		      .  "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
3274
	              .  "then they are delayed by value specified in the Delay field, and then they "
3275
		      .  "are delivered to their destination.") . "</span>";
3276
		$form .= "</td></tr>";
3277
		$form .= "<tr style=\"display:none\" id=\"sprtable5\" name=\"sprtable5\">";
3278
                $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
3279
                $form .= "<td class=\"vncellreq\">";
3280
                $form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
3281
                $form .= $this->GetBuckets() . "\" />";
3282
                $form .= "&nbsp;slots<br/>";
3283
                $form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3284
                      .  "should leave the field empty. It increases the hash size set.");
3285
                $form .= "</td></tr>";
3286

    
3287
		return $form;
3288

    
3289
		}
3290

    
3291
	function wconfig() {
3292
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3293
            	if (!is_array($cflink))
3294
            		$cflink = array();
3295
		$cflink['name'] = $this->GetQname();
3296
		$cflink['number'] = $this->GetNumber();
3297
            	$cflink['qlimit'] = $this->GetQlimit();
3298
            	$cflink['plr'] = $this->GetPlr();
3299
            	$cflink['description'] = $this->GetDescription();
3300
               
3301
		$bandwidth = $this->GetBandwidth();
3302
		if (is_array($bandwidth)) {
3303
			$cflink['bandwidth'] = array();
3304
			$cflink['bandwidth']['item'] = array();
3305
			foreach ($bandwidth as $bwidx => $bw)
3306
				$cflink['bandwidth']['item'][] = $bw;
3307
		}
3308

    
3309
		$cflink['enabled'] = $this->GetEnabled();
3310
		$cflink['buckets'] = $this->GetBuckets();
3311
		$cflink['mask'] = $this->GetMask();
3312
		$cflink['delay'] = $this->GetDelay();
3313
	}
3314

    
3315
}
3316

    
3317
class dnqueue_class extends dummynet_class {
3318
        var $pipeparent;
3319
        var $weight;
3320

    
3321
        function GetWeight() {
3322
                return $this->weight;
3323
        }
3324
        function SetWeight($weight) {
3325
                $this->weight = $weight;
3326
        }
3327
	function GetPipe() {
3328
		return $this->pipeparent;
3329
	}
3330
	function SetPipe($pipe) {
3331
		$this->pipeparent = $pipe;
3332
	}
3333

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

    
3337
	function delete_queue() {
3338
		cleanup_dnqueue_from_rules($this->GetQname());
3339
		unset_dn_object_by_reference($this->GetLink());
3340
		mwexec("/sbin/ipfw queue delete " . $this->GetNumber());
3341
        }
3342

    
3343
	function validate_input($data, &$input_errors) {
3344
		parent::validate_input($data, $input_errors);
3345

    
3346
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3347
			($data['weight'] < 1 && $data['weight'] > 100))) 
3348
				$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
3349
	}
3350

    
3351
        /*
3352
         * Should search even its children
3353
         */
3354
        function &find_queue($pipe, $qname) {
3355
                if ($qname == $this->GetQname()) 
3356
                	return $this;
3357
		else
3358
			return NULL;
3359
        }
3360

    
3361
	function &find_parentqueue($pipe, $qname) {
3362
		return $this->qparent;
3363
        }
3364

    
3365
        function &get_queue_list(&$qlist) {
3366
		if ($this->GetEnabled() == "")
3367
			return;
3368
        	$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3369
        }		
3370

    
3371
	function ReadConfig(&$q) {
3372
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3373
			$this->SetQname($q['newname']);
3374
		} else if (!empty($q['newname'])) {
3375
			$this->SetQname($q['newname']);
3376
		} else {
3377
			$this->SetQname($q['name']);
3378
		}
3379
		$this->SetNumber($q['number']);
3380
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
3381
       		       	$this->SetQlimit($q['qlimit']);
3382
		else
3383
       		       	$this->SetQlimit("");
3384
		if (isset($q['mask']) && $q['mask'] <> "")
3385
              		$this->SetMask($q['mask']);
3386
		else
3387
              		$this->SetMask("");
3388
       		if (isset($q['weight']) && $q['weight'] <> "")
3389
            		$this->SetWeight($q['weight']);
3390
		else
3391
            		$this->SetWeight("");
3392
            	if (isset($q['description']) && $q['description'] <> "")
3393
			$this->SetDescription($q['description']);
3394
		else
3395
			$this->SetDescription("");
3396
		$this->SetEnabled($q['enabled']);
3397
        }
3398

    
3399
	function build_tree() {
3400
		$parent =& $this->GetParent();
3401
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&amp;queue=" . $this->GetQname() ."&amp;action=show\">"; 
3402
		$tree .= $this->GetQname() . "</a>";
3403
		$tree .= "</li>";
3404

    
3405
		return $tree;
3406
	}
3407

    
3408
        function build_rules() {
3409
		if ($this->GetEnabled() == "")
3410
			return; 
3411

    
3412
		$parent =& $this->GetParent();
3413
            	$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
3414
		if ($this->GetQlimit())
3415
                    	$pfq_rule .= " queue " . $this->GetQlimit();
3416
		if ($this->GetWeight())
3417
			$pfq_rule .= " weight " . $this->GetWeight();
3418
		if ($this->GetBuckets())
3419
			$pfq_rule .= " buckets " . $this->GetBuckets();
3420
		$mask = $this->GetMask();
3421
		if (!empty($mask)) {
3422
			/* XXX TODO extend this to support more complicated masks */
3423
			switch ($mask) {
3424
			case 'srcaddress':
3425
				$pfq_rule .= " mask src-ip 0xffffffff ";
3426
				break;
3427
			case 'dstaddress':
3428
				$pfq_rule .= " mask dst-ip 0xffffffff ";
3429
				break;
3430
			default:
3431
				break;
3432
			}
3433
		}
3434
		$pfq_rule .= "\n";
3435

    
3436
		return $pfq_rule;
3437
	}
3438

    
3439
        function build_form() { 
3440
		$form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br/>";
3441
                $form .= gettext("Enable/Disable");
3442
                $form .= "</td><td class=\"vncellreq\">";
3443
                $form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\"";
3444
                if ($this->GetEnabled() == "on")
3445
                        $form .=  " checked=\"checked\"";
3446
                $form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable queue") . "</span>";
3447
                $form .= "</td></tr>";
3448
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br/><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3449
		$form .= "<td class=\"vncellreq\">";
3450
		$form .= "<input type=\"text\" id=\"newname\" name=\"newname\" value=\"";
3451
		$form .= $this->GetQname()."\" />";
3452
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"";
3453
		$form .= $this->GetQname()."\" />";
3454
		if ($this->GetNumber() > 0) {
3455
			$form .= "<input type=\"hidden\" id=\"number\" name=\"number\" value=\"";
3456
			$form .= $this->GetNumber()."\" />";
3457
		}
3458
		$form .= "</td></tr>";
3459
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Mask") . "</td>";
3460
		$form .= "<td class=\"vncellreq\">";
3461
		$form .= "<select name=\"mask\" class=\"formselect\">";
3462
		$form .= "<option value=\"none\"";
3463
		if ($this->GetMask() == "none")
3464
			$form .= " selected=\"selected\"";
3465
		$form .= ">" . gettext("none") . "</option>";
3466
		$form .= "<option value=\"srcaddress\"";
3467
		if ($this->GetMask() == "srcaddress")
3468
			$form .= " selected=\"selected\"";
3469
		$form .= ">" . gettext("Source addresses") . "</option>";
3470
		$form .= "<option value=\"dstaddress\"";
3471
		if ($this->GetMask() == "dstaddress")
3472
			$form .= " selected=\"selected\"";
3473
		$form .= ">" . gettext("Destination addresses") . "</option>";
3474
		$form .= "</select>";
3475
		$form .= "&nbsp;slots<br/>";
3476
		$form .= "<span class=\"vexpl\">" . gettext("If 'source' or 'destination' is chosen, \n"
3477
		      .  "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n"
3478
		      .  "be created for each source/destination IP address encountered, \n"
3479
		      .  "respectively. This makes it possible to easily specify bandwidth \n"
3480
		      .  "limits per host.") . "</span>";
3481
		$form .= "</td></tr>";
3482
		$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">Description</td>";
3483
		$form .= "<td class=\"vncellreq\">";
3484
		$form .= "<input type=\"text\" id=\"description\" class=\"formfld unknown\" size=\"50%\" name=\"description\" value=\"";
3485
		$form .= $this->GetDescription();
3486
		$form .= "\" />";
3487
		$form .= "<br/> <span class=\"vexpl\">";
3488
		$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3489
		$form .= "</td></tr>";
3490
		$form .= "<tr id=\"sprtable4\" name=\"sprtable4\">";
3491
		$form .= "<td></td>";
3492
                $form .= "<td><div id=\"showadvancedboxspr\">";
3493
                $form .= "<p><input type=\"button\" onclick=\"show_source_port_range()\"";
3494
		$form .= " value=\"" . gettext("Show advanced options") . "\" />";
3495
                $form .= "</div></td></tr>";
3496
		$form .= "<tr style=\"display:none\" id=\"sprtable\" name=\"sprtable\">";
3497
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Weight") . "</td>";
3498
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3499
		$form .= "<input name=\"weight\" type=\"text\" id=\"weight\" size=\"5\" value=\"";
3500
		$form .= $this->GetWeight() . "\" />";
3501
		$form .= "&nbsp;<br/> <span class=\"vexpl\">" . gettext("Hint: For queues under the same parent "
3502
		      .  "this specifies the share that a queue gets(values range from 1 to 100, you can leave it blank otherwise)") . "</span>";
3503
		$form .= "</td></tr>";
3504
		$form .= "<tr style=\"display:none\" id=\"sprtable1\" name=\"sprtable1\">";
3505
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Packet loss rate") . "</td>";
3506
		$form .= "<td valign=\"middle\" class=\"vncellreq\">";
3507
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
3508
		$form .= $this->GetPlr() . "\" />";
3509
		$form .= "&nbsp;<br/> <span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3510
			  .  "should specify 0 here (or leave the field empty). "
3511
			  .  "A value of 0.001 means one packet in 1000 gets dropped") . "</span>";
3512
		$form .= "</td></tr>";
3513
		$form .= "<tr style=\"display:none\" id=\"sprtable2\" name=\"sprtable2\">";
3514
		$form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Queue Size") . "</td>";
3515
		$form .= "<td class=\"vncellreq\">";
3516
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
3517
		$form .= $this->GetQlimit() . "\" />";
3518
		$form .= "&nbsp;slots<br/>";
3519
		$form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3520
			  .  "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, "
3521
			  .  "then they are delayed by value specified in the Delay field, and then they "
3522
			  .  "are delivered to their destination.") . "</span>";
3523
		$form .= "</td></tr>";
3524
		$form .= "<tr style=\"display:none\" id=\"sprtable5\" name=\"sprtable5\">";
3525
                $form .= "<td valign=\"middle\" class=\"vncellreq\">" . gettext("Bucket Size") . "</td>";
3526
                $form .= "<td class=\"vncellreq\">";
3527
                $form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
3528
                $form .= $this->GetBuckets() . "\" />";
3529
                $form .= "&nbsp;" . gettext("slots") . "<br/>";
3530
                $form .= "<span class=\"vexpl\">" . gettext("Hint: in most cases, you "
3531
                      .  "should leave the field empty. It increases the hash size set.");
3532
                $form .= "</td></tr>";
3533

    
3534
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3535
		$form .= " value=\"" . $this->GetPipe() . "\" />";
3536

    
3537
		return $form;
3538

    
3539
	}
3540

    
3541
        function update_dn_data(&$data) { 
3542
		$this->ReadConfig($data);
3543
	}
3544

    
3545
	function wconfig() {
3546
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3547
            	if (!is_array($cflink))
3548
            		$cflink = array();
3549
		$cflink['name'] = $this->GetQname();
3550
		$cflink['number'] = $this->GetNumber();
3551
            	$cflink['qlimit'] = $this->GetQlimit();
3552
            	$cflink['description'] = $this->GetDescription();
3553
		$cflink['weight'] = $this->GetWeight();
3554
		$cflink['enabled'] = $this->GetEnabled();
3555
		$cflink['buckets'] = $this->GetBuckets();
3556
		$cflink['mask'] = $this->GetMask();
3557
	}
3558
}
3559

    
3560
// List of layer7 objects
3561
$layer7_rules_list = array();
3562

    
3563
class layer7 {
3564
    
3565
    var $rname; //alias
3566
    var $rdescription; //alias description
3567
    var $rport; //divert port
3568
    var $renabled; //rule enabled
3569
    var $rsets = array(); //array of l7 associations
3570
    
3571
    // Auxiliary functions
3572
    
3573
    function GetRName() {
3574
        return $this->rname;
3575
    }
3576
    function SetRName($rname) {
3577
        $this->rname = $rname;
3578
    }
3579
    function GetRDescription() {
3580
        return $this->rdescription;
3581
    }
3582
    function SetRDescription($rdescription) {
3583
        $this->rdescription = $rdescription;
3584
    }
3585
    function GetRPort() {
3586
        return $this->rport;
3587
    }
3588
    function SetRPort($rport) {
3589
        $this->rport = $rport;
3590
    }
3591
    function GetREnabled() {
3592
        return $this->renabled;
3593
    }
3594
    function SetREnabled($value) {
3595
        $this->renabled = $value;
3596
    }
3597
    function GetRl7() {
3598
        return $this->rsets;
3599
    }
3600
    function SetRl7($rsets) {
3601
        $this->rsets = $rsets;
3602
    }
3603
    
3604
    //Add a tuple (rule,sctructure,element) to the $rsets
3605
    
3606
    function add_rule($l7set) {
3607
       	$this->rsets[] = $l7set;
3608
    }
3609
    
3610
    // Build the layer7 rules
3611
    function build_l7_rules() {
3612
        if($this->GetREnabled() == "") {
3613
            return;
3614
        }
3615
        //$l7rules = "#" . $this->rdescription . "\n";
3616
        foreach ($this->rsets as $rl7) {
3617
            $l7rules .= $rl7->build_rules();
3618
        }
3619
        return $l7rules;
3620
    }
3621
    
3622
    // Read the config from array
3623
    function ReadConfig(&$qname, &$q) {
3624
        $this->SetRName($qname);
3625
        $this->SetREnabled($q['enabled']);
3626
        $this->SetRPort($q['divert_port']);
3627
        if(isset($q['description']) && $q['description'] <> "")
3628
            $this->SetRDescription($q['description']);
3629
        $rsets = $q['l7rules'];
3630
        //Put individual rules in the array
3631
	if(is_array($rsets)) {
3632
	    $this->rsets = array(); // XXX: ugly hack
3633
	    foreach($rsets as $l7r) {
3634
	        $l7obj = new l7rule();
3635
	        $l7obj->SetRProtocol($l7r['protocol']);
3636
	        $l7obj->SetRStructure($l7r['structure']);
3637
	        $l7obj->SetRBehaviour($l7r['behaviour']);
3638
	        $this->add_rule($l7obj);
3639
	    }
3640
	}
3641
    }
3642
    
3643
    //Generate a random port for the divert socket
3644
    function gen_divert_port() {
3645
        $dports = get_divert_ports(); //array of used ports
3646
	$divert_port = 1; // Initialize
3647
	while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) {
3648
		$divert_port = rand(40000, 60000);
3649
	}
3650
        return $divert_port;
3651
    }
3652
    
3653
    //Helps building the left tree
3654
    function build_tree() {
3655
        $tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&amp;action=show\">"; 
3656
        $tree .= $this->GetRName() . "</a>";
3657
	$tree .= "</li>";
3658

    
3659
	return $tree;
3660
    }
3661
    
3662
    function build_form() {
3663
        $form = "<tr><td valign=\"middle\" class=\"vncellreq\"><br/>";
3664
	$form .= gettext("Enable/Disable");
3665
	$form .= "</td><td class=\"vncellreq\">";
3666
	$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\" ";
3667
	if ($this->GetREnabled() == "on") {
3668
       	    $form .=  "checked=\"checked\"";
3669
	}
3670
	$form .= " /><span class=\"vexpl\"> " . gettext("Enable/Disable layer7 Container") . "</span>";
3671
	$form .= "</td></tr>";
3672
        $form .= "<tr><td valign=\"middle\" class=\"vncellreq\"><br/><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3673
	$form .= "<td class=\"vncellreq\">";
3674
	$form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
3675
	$form .= $this->GetRName()."\" />";
3676
	$form .= "</td></tr>";
3677
	$form .= "<tr><td valign=\"middle\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3678
	$form .= "<td class=\"vncellreq\">";
3679
	$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"50%\" id=\"description\" name=\"description\" value=\"";
3680
	$form .= $this->GetRDescription();
3681
	$form .= "\" />";
3682
	$form .= "<br/> <span class=\"vexpl\">";
3683
	$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3684
	$form .= "</td></tr>";
3685

    
3686
	return $form;
3687
    }
3688
    
3689
    //Write the setting to the $config array
3690
    function wconfig() {
3691
	global $config;
3692

    
3693
	if(!is_array($config['l7shaper']['container'])) {
3694
		$config['l7shaper']['container'] = array();
3695
	}
3696
        //
3697
        $cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
3698
	// Test if this rule does exists already
3699
	if(!$cflink) {
3700
		$cflink =& $config['l7shaper']['container'][];
3701
	}
3702
	$cflink['name'] = $this->GetRName();
3703
        $cflink['enabled'] = $this->GetREnabled();
3704
        $cflink['description'] = $this->GetRDescription();
3705
        $cflink['divert_port'] = $this->GetRPort();
3706
        
3707
	//Destroy previously existent rules
3708
	if(is_array($cflink['rules'])) {
3709
		unset($cflink['l7rules']);
3710
	}
3711

    
3712
        $cflink['l7rules'] = array();
3713

    
3714
        $i = 0;
3715
        foreach($this->rsets as $rulel7) {
3716
            $cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
3717
            $cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
3718
            $cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
3719
            $i++;
3720
        }
3721
    }
3722
    
3723
    //This function is necessary to help producing the overload options for keep state
3724
    function get_unique_structures() {
3725
        
3726
        $unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
3727
        foreach($this->rsets as $l7rule) {
3728
		if($l7rule->GetRStructure() == "action")
3729
			$unique_structures['action'] = true;
3730
		else if($l7rule->GetRStructure() == "limiter")
3731
			$unique_structures['dummynet'] = true;
3732
		else
3733
			$unique_structures['altq'] = true;
3734
        }
3735
	//Delete non used structures so we don't have to check this in filter.inc
3736
	foreach($unique_structures as $key => $value)
3737
		if(!$value)
3738
			unset($unique_structures[$key]);
3739
        return $unique_structures;
3740
    }
3741
    
3742
    function validate_input($data, &$input_errors) {
3743
	$reqdfields[] = "container";
3744
	$reqdfieldsn[] = gettext("Name");
3745

    
3746
	shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3747
        
3748
        if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container']))
3749
            $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3750
    }
3751
    
3752
    function delete_l7c() {
3753
	mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
3754
	unset_l7_object_by_reference($this->GetRName());
3755
	cleanup_l7_from_rules($this->GetRName());
3756
    }
3757
}
3758

    
3759
class l7rule {
3760
    
3761
    var $rprotocol; //protocol
3762
    var $rstructure; //action, limiter, queue
3763
    var $rbehaviour; //allow, block, queue_name, pipe_number ...
3764
    
3765
    //Auxiliary Functions
3766
    
3767
    function GetRProtocol() {
3768
        return $this->rprotocol;
3769
    }
3770
    function SetRProtocol($rprotocol) {
3771
        $this->rprotocol = $rprotocol;
3772
    }
3773
    function GetRStructure() {
3774
        return $this->rstructure;
3775
    }
3776
    function SetRStructure($rstructure) {
3777
        $this->rstructure = $rstructure;
3778
    }
3779
    function GetRBehaviour() {
3780
        return $this->rbehaviour;
3781
    }
3782
    function SetRBehaviour($rbehaviour) {
3783
        $this->rbehaviour = $rbehaviour;
3784
    }
3785
    
3786
    //XXX Do we need to test any particularity for AltQ queues?
3787
    function build_rules() {
3788
	global $dummynet_pipe_list;
3789
	switch ($this->GetRStructure()) {
3790
		case "limiter":
3791
			read_dummynet_config();
3792
			$dn_list =& get_unique_dnqueue_list();
3793
			$found = false;
3794
			if(is_array($dn_list)) {
3795
				foreach($dn_list as $key => $value) {
3796
					if($key == $this->GetRBehaviour()) {
3797
						if($value[0] == "?")
3798
							$l7rule = $this->GetRProtocol() . " = dnqueue " . substr($value, 1) . "\n";
3799
						else
3800
							$l7rule = $this->GetRProtocol() . " = dnpipe " . $value . "\n";
3801
						$found = true;
3802
					}
3803
					if($found)
3804
						break;
3805
				}
3806
			}
3807
			break;
3808
		default: //This is for action and for altq
3809
			$l7rule = $this->GetRProtocol() . " = " . $this->GetRStructure() . " " . $this->GetRBehaviour() . "\n";
3810
			break;
3811
	}
3812
        return $l7rule;
3813
    }
3814
}
3815

    
3816
/*
3817
 * This function allows to return an array with all the used divert socket ports
3818
 */
3819
function get_divert_ports() {
3820
    global $layer7_rules_list;
3821
    $dports = array();
3822
    
3823
    foreach($layer7_rules_list as $l7r)
3824
        $dports[] = $l7r->GetRPort();
3825
    
3826
    return $dports;
3827
}
3828

    
3829
function &get_l7c_reference_to_me_in_config(&$name) {
3830
	global $config;
3831

    
3832
	$ptr = NULL;
3833

    
3834
	if(is_array($config['l7shaper']['container'])) {
3835
		foreach($config['l7shaper']['container'] as $key => $value) {
3836
			if($value['name'] == $name)
3837
				$ptr =& $config['l7shaper']['container'][$key];
3838
		}
3839
	}	
3840
	return $ptr;
3841
// $ptr can be null. has to be checked later
3842
}
3843

    
3844
function unset_l7_object_by_reference(&$name) {
3845
	global $config;
3846
        
3847
	if(is_array($config['l7shaper']['container'])) {
3848
		foreach($config['l7shaper']['container'] as $key => $value) {
3849
			if($value['name'] == $name) {
3850
				unset($config['l7shaper']['container'][$key]['l7rules']);
3851
				unset($config['l7shaper']['container'][$key]);
3852
				break;
3853
			}
3854
		}
3855
	}
3856
}
3857

    
3858
function read_layer7_config() {
3859
    global $layer7_rules_list, $config;
3860
    
3861
    $l7cs = &$config['l7shaper']['container'];
3862
    
3863
    $layer7_rules_list = array();
3864
    
3865
    if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container']))
3866
	return;
3867
    
3868
    foreach ($l7cs as $conf) {
3869
	if (empty($conf['name']))
3870
		continue; /* XXX: grrrrrr at php */ 
3871
        $root =& new layer7();
3872
        $root->ReadConfig($conf['name'],$conf);
3873
        $layer7_rules_list[$root->GetRName()] = &$root;
3874
    }
3875
}
3876

    
3877
function generate_layer7_files() {
3878
    global $layer7_rules_list, $g;
3879
    
3880
    read_layer7_config();
3881
    
3882
    if (!empty($layer7_rules_list)) {
3883
	if (!is_module_loaded("ipdivert.ko"))
3884
		mwexec("/sbin/kldload ipdivert.ko");
3885

    
3886
	mwexec("rm -f {$g['tmp_path']}/*.l7");
3887
    }
3888
    
3889
    foreach($layer7_rules_list as $l7rules) {
3890
        if($l7rules->GetREnabled()) {
3891
            $filename = $l7rules->GetRName() . ".l7";
3892
            $path = "{$g['tmp_path']}/" . $filename;
3893
        
3894
            $rules = $l7rules->build_l7_rules();
3895
        
3896
            $fp = fopen($path,'w');
3897
            fwrite($fp,$rules);
3898
            fclose($fp);
3899
        }
3900
    }
3901
}
3902

    
3903
function layer7_start_l7daemon() {
3904
    global $layer7_rules_list, $g;
3905

    
3906
    /*
3907
     * XXX: ermal - Needed ?!
3908
     * read_layer7_config();
3909
     */
3910

    
3911
    foreach($layer7_rules_list as $l7rules) {
3912
        if($l7rules->GetREnabled()) {
3913
            $filename = $l7rules->GetRName() . ".l7";
3914
            $path = "{$g['tmp_path']}/" . $filename;
3915

    
3916
	    unset($l7pid);
3917
	    /* Only reread the configuration rather than restart to avoid loosing information. */
3918
	    exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid);
3919
	    if (count($l7pid) > 0) {
3920
		log_error(sprintf(gettext("Sending HUP signal to %s"), $l7pid[0]));
3921
		mwexec("/bin/kill -HUP {$l7pid[0]}");
3922
	    } else {
3923
		// XXX: Hardcoded number of packets to garbage collect and queue length..
3924
		$ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 8 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
3925
		mwexec_bg($ipfw_classifyd_init);
3926
	    }
3927
        }
3928
    }
3929
}
3930

    
3931
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
3932
function generate_protocols_array() {
3933
	$protocols = return_dir_as_array("/usr/local/share/protocols");
3934
	$protocols_new = array();
3935
	if(is_array($protocols)) {
3936
		foreach($protocols as $key => $proto) {
3937
			if (strstr($proto, ".pat"))
3938
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
3939
		}
3940
		sort($protocols_new);
3941
	}		
3942
	return $protocols_new;
3943
}
3944

    
3945
function get_l7_unique_list() {
3946
	global $layer7_rules_list;
3947

    
3948
	$l7list = array();
3949
	if(is_array($layer7_rules_list)) 
3950
		foreach($layer7_rules_list as $l7c)
3951
			if($l7c->GetREnabled())
3952
				$l7list[] = $l7c->GetRName();
3953

    
3954
	return $l7list;
3955
}
3956

    
3957
// Disable a removed l7 container from the filter
3958
function cleanup_l7_from_rules(&$name) {
3959
	global $config;
3960

    
3961
	if(is_array($config['filter']['rule']))
3962
		foreach ($config['filter']['rule'] as $key => $rule) {
3963
			if ($rule['l7container'] == $name)
3964
				unset($config['filter']['rule'][$key]['l7container']);
3965
		}
3966
}
3967

    
3968
function get_dummynet_name_list() {
3969

    
3970
	$dn_name_list =& get_unique_dnqueue_list();
3971
	$dn_name = array();
3972
	if(is_array($dn_name_list))
3973
		foreach($dn_name_list as $key => $value)
3974
			$dn_name[] = $key;
3975

    
3976
	return $dn_name;
3977

    
3978
}
3979

    
3980
function get_altq_name_list() {
3981
	$altq_name_list =& get_unique_queue_list();
3982
	$altq_name = array();
3983
	if(is_array($altq_name_list))
3984
		foreach($altq_name_list as $key => $aqobj)
3985
			$altq_name[] = $key;
3986

    
3987
	return $altq_name;
3988
}
3989

    
3990
/*
3991
 * XXX: TODO Make a class shaper to hide all these function
3992
 * from the global namespace.
3993
 */
3994

    
3995
/* 
3996
 * This is a layer violation but for now there is no way 
3997
 * i can find to properly do this with PHP.
3998
 */
3999
function altq_get_default_queue($interface) {
4000
	global $altq_list_queues;
4001

    
4002
	$altq_tmp = $altq_list_queues[$interface];
4003
	if ($altq_tmp)
4004
		return $altq_tmp->GetDefaultQueuePresent(); 
4005
	else
4006
		return false;
4007
}
4008

    
4009
function altq_check_default_queues() {
4010
	global $altq_list_queues;
4011

    
4012
	$count = 0;
4013
	if (is_array($altq_list_queues)) {
4014
		foreach($altq_list_queues as $altq) {
4015
			if ($altq->GetDefaultQueuePresent())
4016
				$count++;
4017
		}
4018
	}
4019
	else  $count++;;
4020

    
4021
	return 0;
4022
}
4023

    
4024
function &get_unique_queue_list() {
4025
	global $altq_list_queues;
4026

    
4027
	$qlist = array();
4028
	if (is_array($altq_list_queues)) {
4029
		foreach ($altq_list_queues as $altq) {
4030
			if ($altq->GetEnabled() == "")
4031
				continue;
4032
			$tmplist =& $altq->get_queue_list();
4033
			foreach ($tmplist as $qname => $link) {
4034
				if ($link->GetEnabled() <> "")
4035
					$qlist[$qname] = $link;	
4036
			}
4037
		}
4038
	}
4039
	return $qlist;
4040
}
4041

    
4042
function &get_unique_dnqueue_list() {
4043
	global $dummynet_pipe_list;
4044

    
4045
	$qlist = array();
4046
	if (is_array($dummynet_pipe_list)) {
4047
		foreach ($dummynet_pipe_list as $dn) {
4048
			if ($dn->GetEnabled() == "")
4049
				continue;
4050
			$tmplist =& $dn->get_queue_list();
4051
			foreach ($tmplist as $qname => $link) {
4052
				$qlist[$qname] = $link;	
4053
			}
4054
		}
4055
	}
4056
	return $qlist;
4057
}
4058

    
4059
function ref_on_altq_queue_list($parent, $qname) {
4060
	if (isset($GLOBALS['queue_list'][$qname]))
4061
		$GLOBALS['queue_list'][$qname]++;
4062
	else
4063
		$GLOBALS['queue_list'][$qname] = 1;
4064

    
4065
	unref_on_altq_queue_list($parent);
4066
}
4067

    
4068
function unref_on_altq_queue_list($qname) {
4069
	$GLOBALS['queue_list'][$qname]--;
4070
	if ($GLOBALS['queue_list'][$qname] <= 1)
4071
		unset($GLOBALS['queue_list'][$qname]);	
4072
}
4073

    
4074
function read_altq_config() {
4075
	global $altq_list_queues, $config;
4076
	$path = array();
4077

    
4078
	if (!is_array($config['shaper']))
4079
		$config['shaper'] = array();
4080
	if (!is_array($config['shaper']['queue']))
4081
		$config['shaper']['queue'] = array();
4082
	$a_int = &$config['shaper']['queue'];
4083

    
4084
	$altq_list_queues = array();
4085

    
4086
	if (!is_array($config['shaper']['queue']))
4087
		return;
4088

    
4089
	foreach ($a_int as $key => $conf) {
4090
		$int = $conf['interface'];
4091
		$root =& new altq_root_queue();
4092
		$root->SetInterface($int);
4093
		$altq_list_queues[$root->GetInterface()] = &$root;
4094
		$root->ReadConfig($conf);
4095
		array_push($path, $key);
4096
		$root->SetLink($path);
4097
		if (is_array($conf['queue'])) {
4098
			foreach ($conf['queue'] as $key1 => $q) {
4099
				array_push($path, $key1);
4100
				/* 
4101
				 * XXX: we compeletely ignore errors here but anyway we must have 
4102
				 *	checked them before so no harm should be come from this.
4103
				 */
4104
				$root->add_queue($root->GetInterface(), $q, &$path, $input_errors);
4105
				array_pop($path);
4106
			} 	
4107
		}
4108
		array_pop($path);
4109
	}
4110
}
4111

    
4112
function read_dummynet_config() {
4113
	global $dummynet_pipe_list, $config;
4114
	$path = array();
4115

    
4116
	if (!is_array($config['dnshaper']))
4117
		$config['dnshaper'] = array();
4118
	if (!is_array($config['dnshaper']['queue']))
4119
		$config['dnshaper']['queue'] = array();
4120
	$a_int = &$config['dnshaper']['queue'];
4121

    
4122
	$dummynet_pipe_list = array();
4123

    
4124
	if (!is_array($config['dnshaper']['queue'])
4125
		|| !count($config['dnshaper']['queue']))
4126
		return;
4127

    
4128
	foreach ($a_int as $key => $conf) {
4129
		if (empty($conf['name']))
4130
			continue; /* XXX: grrrrrr at php */ 
4131
		$root =& new dnpipe_class();
4132
		$root->ReadConfig($conf);
4133
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4134
		array_push($path, $key);
4135
		$root->SetLink($path);
4136
		if (is_array($conf['queue'])) {
4137
			foreach ($conf['queue'] as $key1 => $q) {
4138
				array_push($path, $key1);
4139
				/* 
4140
				 * XXX: we compeletely ignore errors here but anyway we must have 
4141
				 *	checked them before so no harm should be come from this.
4142
				 */	
4143
				$root->add_queue($root->GetQname(), $q, &$path, $input_errors);
4144
				array_pop($path);
4145
			} 	
4146
		}
4147
		array_pop($path);
4148
	}
4149
}
4150

    
4151
function get_interface_list_to_show() {
4152
	global $altq_list_queues, $config;
4153
	global $shaperIFlist;
4154

    
4155
	$tree = "";
4156
	foreach ($shaperIFlist as $shif => $shDescr) {
4157
		if ($altq_list_queues[$shif]) {
4158
			continue;
4159
		} else  {
4160
			if (!is_altq_capable(get_real_interface($shif)))
4161
				continue;
4162
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&amp;action=add\">".$shDescr."</a></li>";
4163
		}
4164
	}
4165

    
4166
	return $tree;
4167
}
4168

    
4169
function filter_generate_altq_queues() {
4170
	global $altq_list_queues;
4171

    
4172
	read_altq_config();
4173

    
4174
	$altq_rules = "";
4175
	foreach ($altq_list_queues as $altq) 
4176
		$altq_rules .= $altq->build_rules();
4177

    
4178
	return $altq_rules;
4179
}
4180

    
4181
function dnqueue_find_nextnumber() {
4182
	global $dummynet_pipe_list;
4183

    
4184
	$dnused = array();
4185
	if (is_array($dummynet_pipe_list)) {
4186
		foreach ($dummynet_pipe_list as $dn) {
4187
			$tmplist =& $dn->get_queue_list();
4188
			foreach ($tmplist as $qname => $link) {
4189
				if ($link[0] == "?")
4190
					$dnused[$qname] = substr($link, 1);
4191
			}
4192
		}
4193
	}
4194

    
4195
	sort($dnused, SORT_NUMERIC);
4196
	$dnnumber = 0;
4197
	$found = false;
4198
	foreach ($dnused as $dnnum) {
4199
		if (($dnnum - $dnnumber) > 1) {
4200
			$dnnumber = $dnnum + 1;
4201
			$found = true;
4202
			break;
4203
		} else
4204
			$dnnumber = $dnnum;
4205
	}
4206

    
4207
	if ($found == false)
4208
		$dnnumber++;
4209

    
4210
	unset($dnused, $dnnum, $found);
4211
	return $dnnumber;
4212
}
4213

    
4214
function dnpipe_find_nextnumber() {
4215
	global $dummynet_pipe_list;
4216

    
4217
	$dnused = array();
4218
	foreach ($dummynet_pipe_list as $dn)
4219
		$dnused[] = $dn->GetNumber();
4220

    
4221
	sort($dnused, SORT_NUMERIC);
4222
	$dnnumber = 0;
4223
	$found = false;
4224
	foreach ($dnused as $dnnum) {
4225
		if (($dnnum - $dnnumber) > 1) {
4226
			$dnnumber = $dnnum + 1;
4227
			$found = true;
4228
			break;
4229
		} else
4230
			$dnnumber = $dnnum;
4231
	}
4232

    
4233
	if ($found == false)
4234
		$dnnumber++;
4235

    
4236
	unset($dnused, $dnnum, $found);
4237
	return $dnnumber;
4238
}
4239

    
4240
function filter_generate_dummynet_rules() {
4241
	global $g, $dummynet_pipe_list;
4242

    
4243
	read_dummynet_config();
4244

    
4245
	if (!empty($dummynet_pipe_list)) {
4246
		if (!is_module_loaded("dummynet.ko")) {
4247
			mwexec("/sbin/kldload dummynet");
4248
			mwexec("/sbin/sysctl net.inet.ip.dummynet.io_fast=1 net.inet.ip.dummynet.hash_size=256");
4249
		}
4250
	}
4251

    
4252
	$dn_rules = "";
4253
	foreach ($dummynet_pipe_list as $dn) 
4254
		$dn_rules .= $dn->build_rules();
4255

    
4256
	if (!empty($dn_rules)) {
4257
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4258
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4259
	}
4260
}
4261

    
4262
function build_iface_without_this_queue($iface, $qname) {
4263
	global $g, $altq_list_queues;
4264
	global $shaperIFlist;
4265

    
4266
	$altq =& $altq_list_queues[$iface];
4267
	if ($altq)
4268
		$scheduler = ": " . $altq->GetScheduler();
4269
	$form = "<tr><td width=\"20%\" >";
4270
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&amp;queue=" . $iface."&amp;action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4271
	$form .= "</td></tr>";
4272
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4273
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4274
	$form .= $iface . "&amp;queue=". $qname . "&amp;action=add\">";
4275
	$form .= "<img src=\"";
4276
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4277
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\" alt=\"clone\" />";
4278
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4279

    
4280
	return $form;
4281

    
4282
}
4283

    
4284

    
4285
$default_shaper_msg =	"<tr><td align=\"center\" width=\"80%\" >";
4286
$default_shaper_msg .= "<span class=\"vexpl\"><strong><p><b>" . sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "</b><br />";
4287
$default_shaper_msg .= gettext("The tree on the left helps you navigate through the queues <br />"
4288
                    .  "buttons at the bottom represent queue actions and are activated accordingly.");
4289
$default_shaper_msg .= " </p></strong></span>";
4290
$default_shaper_msg .= "</td></tr>";
4291

    
4292
$dn_default_shaper_msg =	"<tr><td align=\"center\" width=\"80%\" >";
4293
$dn_default_shaper_msg .= "<span class=\"vexpl\"><strong><p><b>" . sprintf(gettext("Welcome to the %s Traffic Shaper."), $g['product_name']) . "</b><br />";
4294
$dn_default_shaper_msg .= gettext("The tree on the left helps you navigate through the queues <br />"
4295
                       .  "buttons at the bottom represent queue actions and are activated accordingly.");
4296
$dn_default_shaper_msg .= " </p></strong></span>";
4297
$dn_default_shaper_msg .= "</td></tr>";
4298

    
4299
?>
(50-50/66)