Project

General

Profile

Download (137 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()."&queue=". $this->GetInterface()."&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 .= "function mySuspend() {";
567
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null) ";
568
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden'; ";
569
		$javascript .= "else if (document.all)";
570
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
571
		$javascript .= "}";
572

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

    
581
		return $javascript;
582
	}
583
	
584
	function build_shortform() {
585
		global $g;
586

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

    
606
		return $form;
607

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

    
695

    
696
		return $form;
697
	}
698

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

    
727
}
728

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

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

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

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

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

    
882
		$javascript .= "function myResume() {\n";
883
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
884
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
885
		$javascript .= "else if (document.all)\n";
886
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
887
		$javascript .= "}\n";
888
		$javascript .= "</script>";
889
		
890
		return $javascript;
891
	}
892
	
893
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
894

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

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

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

    
920
	 }
921

    
922
	function clean_queue($sched) {
923
		clean_child_queues($sched, $this->GetLink());
924
		if (is_array($this->subqueues)) {
925
			foreach ($this->subqueues as $q)
926
				$q->clean_queue($sched);
927
		}
928
	}
929

    
930
        function &get_queue_list(&$qlist) {
931
		
932
		$qlist[$this->GetQname()] = & $this;
933
		if (is_array($this->subqueues)) {
934
			foreach ($this->subqueues as $queue)
935
				$queue->get_queue_list($qlist);
936
		}
937
	}
938

    
939
	function delete_queue() {
940
		unref_on_altq_queue_list($this->GetQname());
941
		cleanup_queue_from_rules($this->GetQname());
942
		unset_object_by_reference($this->GetLink());
943
	}
944
	
945
	function delete_all() {
946
                if (count($this->subqueues)) {
947
                        foreach ($this->subqueues as $q) {
948
                                $q->delete_all();
949
                                unset_object_by_reference($q->GetLink());
950
                                unset($q);
951
                        }
952
                        unset($this->subqueues);
953
                }
954
        }
955

    
956
	 function &find_queue($interface, $qname) { 
957
		if ($qname == $this->GetQname())
958
			return $this; 
959
	}
960
	
961
	function find_parentqueue($interface, $qname) { return; }
962
		
963
	function validate_input($data, &$input_errors) {
964
	
965
		$reqdfields[] = "name";
966
		$reqdfieldsn[] = gettext("Name");
967
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
968

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

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

    
1039
	}
1040

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

    
1059
		$tree .= "</li>"; 
1060

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

    
1108
		$pfq_rule .= " \n";
1109

    
1110
		return $pfq_rule;
1111
	}
1112

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

    
1190
		return $form;
1191
	}
1192

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

    
1230
	}
1231

    
1232
		function update_altq_queue_data(&$q) { 
1233
		$this->ReadConfig($q);
1234
	}
1235

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

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

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

    
1374
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1375

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

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

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

    
1414
        function copy_queue($interface, &$cflink) {
1415

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

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

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

    
1519
	/*
1520
	 * Should search even its children
1521
	 */
1522
	function &find_queue($interface, $qname) {
1523
		if ($qname == $this->GetQname()) 
1524
			return $this;
1525

    
1526
		foreach ($this->subqueues as $q) {
1527
			$result =& $q->find_queue("", $qname);
1528
			if ($result)
1529
				return $result;
1530
		}
1531
	}
1532

    
1533
	function &find_parentqueue($interface, $qname) {
1534
		if ($this->subqueues[$qname]) 
1535
			return $this;
1536
		foreach ($this->subqueues as $q) {
1537
			$result = $q->find_parentqueue("", $qname);
1538
			if ($result)
1539
				return $result;
1540
		}
1541
	}
1542
	
1543
	function validate_input($data, &$input_errors) {
1544
		parent::validate_input($data, $input_errors);
1545
		
1546
		$reqdfields[] = "bandwidth";
1547
		$reqdfieldsn[] = gettext("Bandwidth");
1548
		$reqdfields[] = "bandwidthtype";
1549
		$reqdfieldsn[] = gettext("Bandwidthtype");
1550

    
1551
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1552
		
1553
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1554
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
1555
				$input_errors[] = gettext("Bandwidth must be an integer.");
1556

    
1557
			if ($data['bandwidth'] < 0)
1558
				$input_errors[] = gettext("Bandwidth cannot be negative.");
1559

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

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

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

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

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

    
1622
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1623
                        	$input_errors[] = ("linkshare specification excedd 80% of allowable allocation.");
1624
		}
1625
		*/
1626

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

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

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

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

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

    
1717
	/* Even this should take children into consideration */
1718
	function build_rules(&$default = false) {
1719

    
1720
		$pfq_rule = " queue ". $this->qname;
1721
		if ($this->GetInterface())
1722
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1723
		if ($this->GetBandwidth() && $this->GetBwscale())
1724
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
1725
				
1726
		$tmpvalue = $this->GetQlimit();
1727
		if (!empty($tmpvalue))
1728
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1729
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
1730
			$pfq_rule .= " hfsc ( ";
1731
			$tmpvalue = $this->GetRed();
1732
			if (!empty($tmpvalue)) {
1733
				$comma = 1;
1734
				$pfq_rule .= " red ";
1735
			}
1736
			
1737
			$tmpvalue = $this->GetRio();
1738
			if (!empty($tmpvalue)) {
1739
				if ($comma) 
1740
					$pfq_rule .= " ,";
1741
				$comma = 1;
1742
				$pfq_rule .= " rio ";
1743
			}
1744
			$tmpvalue = $this->GetEcn();
1745
			if (!empty($tmpvalue)) {
1746
				if ($comma) 
1747
					$pfq_rule .= " ,";
1748
				$comma = 1;
1749
				$pfq_rule .= " ecn ";
1750
			}
1751
			$tmpvalue = $this->GetDefault();
1752
			if (!empty($tmpvalue)) {
1753
				if ($comma)
1754
					$pfq_rule .= " ,";
1755
				$comma = 1;
1756
				$pfq_rule .= " default ";
1757
				$default = true;
1758
			}
1759

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

    
1803
		 $pfq_rule .= " \n";
1804
			
1805
		return $pfq_rule;
1806
	}
1807

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

    
1847
		return $javascript;
1848
	}
1849

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

    
1951
		return $form;
1952
	}
1953

    
1954
	function update_altq_queue_data(&$data) { 
1955
		$this->ReadConfig($data);
1956
	}
1957

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

    
2062
class cbq_queue extends priq_queue {
2063
	var $qborrow = "";
2064

    
2065
	function GetBorrow() {
2066
		return $this->qborrow;
2067
	}
2068
	function SetBorrow($borrow) {
2069
		$this->qborrow = $borrow;
2070
	}
2071
	function CanHaveChildren() {
2072
		return true;
2073
	}
2074

    
2075
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
2076

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

    
2099
		$q->SetEnabled("on");
2100
		$q->SetLink($path);
2101
		$this->subqueues[$q->GetQName()] = &$q;
2102
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2103
		if (is_array($qname['queue'])) {
2104
			foreach ($qname['queue'] as $key1 => $que) {
2105
				array_push($path, $key1);
2106
				$q->add_queue($q->GetInterface(), &$que, &$path, $input_errors);
2107
				array_pop($path);
2108
			}
2109
		}
2110

    
2111
		return $q;
2112
	}
2113

    
2114
	function copy_queue($interface, &$cflink) {
2115

    
2116
		$cflink['interface'] = $interface;
2117
		$cflink['qlimit'] = trim($this->GetQlimit());
2118
		if (empty($clink['qlimit']))
2119
			unset($cflink['qlimit']);
2120
		$cflink['priority'] = trim($this->GetQpriority());
2121
		if (empty($cflink['priority']))
2122
			unset($cflink['priority']);
2123
		$cflink['name'] = $this->GetQname();
2124
		$cflink['description'] = trim($this->GetDescription());
2125
		if (empty($cflink['description']))
2126
			unset($cflink['description']);
2127
		$cflink['bandwidth'] = $this->GetBandwidth();
2128
		$cflink['bandwidthtype'] = $this->GetBwscale();
2129
		$cflink['enabled'] = trim($this->GetEnabled());
2130
		if (empty($cflink['enabled']))
2131
			unset($cflink['enabled']);
2132
		$cflink['default'] = trim($this->GetDefault());
2133
		if (empty($cflink['default']))
2134
			unset($cflink['default']);
2135
		$cflink['red'] = trim($this->GetRed());
2136
		if (empty($cflink['red']))
2137
			unset($cflink['red']);
2138
		$cflink['rio'] = trim($this->GetRio());
2139
		if (empty($cflink['rio']))
2140
			unset($cflink['rio']);
2141
		$cflink['ecn'] = trim($this->GetEcn());
2142
		if (empty($cflink['ecn']))
2143
			unset($cflink['ecn']);
2144
		$cflink['borrow'] = trim($this->GetBorrow());
2145
		if (empty($cflink['borrow']))
2146
			unset($cflink['borrow']);
2147
		if (is_array($this->queues)) {
2148
			$cflinkp['queue'] = array();
2149
			foreach ($this->subqueues as $q) {
2150
				$cflink['queue'][$q->GetQname()] = array();
2151
				$q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
2152
			}
2153
		}
2154
	}
2155
	
2156
	/*
2157
	 * Should search even its children
2158
	 */
2159
	function &find_queue($interface, $qname) {
2160
		if ($qname == $this->GetQname())
2161
			return $this;
2162
		foreach ($this->subqueues as $q) {
2163
			$result =& $q->find_queue("", $qname);
2164
			if ($result)
2165
				return $result;
2166
		}
2167
	}
2168

    
2169
	function &find_parentqueue($interface, $qname) {
2170
		if ($this->subqueues[$qname])
2171
			return $this;
2172
		foreach ($this->subqueues as $q) {
2173
			$result = $q->find_parentqueue("", $qname);
2174
			if ($result)
2175
				return $result;
2176
		}
2177
	}
2178

    
2179
	function delete_queue() {
2180
		unref_on_altq_queue_list($this->GetQname());
2181
		cleanup_queue_from_rules($this->GetQname());
2182
		foreach ($this->subqueues as $q) {
2183
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
2184
			$q->delete_queue();
2185
		}
2186
		unset_object_by_reference($this->GetLink());
2187
	}
2188
	
2189
	function validate_input($data, &$input_errors) {
2190
		parent::validate_input($data, $input_errors);
2191
		
2192
		if ($data['priority'] > 7)
2193
				$input_errors[] = gettext("Priority must be an integer between 1 and 7.");
2194
		$reqdfields[] = "bandwidth";
2195
		$reqdfieldsn[] = gettext("Bandwidth");
2196
		$reqdfields[] = "bandwidthtype";
2197
		$reqdfieldsn[] = gettext("Bandwidthtype");
2198

    
2199
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2200
		
2201
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2202
			$input_errors[] = gettext("Bandwidth must be an integer.");
2203

    
2204

    
2205
		if ($data['bandwidth'] < 0)
2206
                       $input_errors[] = gettext("Bandwidth cannot be negative.");
2207

    
2208
		if ($data['bandwidthtype'] == "%") {
2209
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2210
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2211
		}
2212

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

    
2228
	function ReadConfig(&$q) {
2229
		parent::ReadConfig($q);
2230
		if (!empty($q['borrow']))
2231
			$this->SetBorrow("on");
2232
		else
2233
			$this->SetBorrow("");
2234
	}
2235
		
2236
	function build_javascript() {
2237
		return parent::build_javascript();
2238
	}
2239

    
2240
	function build_tree() {
2241
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&queue=" . $this->GetQname()."&action=show"; 
2242
		$tree .= "\" ";
2243
		$tmpvalue = trim($this->GetDefault());
2244
		if (!empty($tmpvalue))
2245
			$tree .= " class=\"navlnk\"";
2246
		$tree .= " >" . $this->GetQname() . "</a>";
2247
		if (is_array($this->subqueues)) {
2248
			$tree .= "<ul>";
2249
			foreach ($this->subqueues as $q)  {
2250
				$tree .= $q->build_tree();
2251
			}	
2252
			$tree .= "</ul>";
2253
		}
2254
		$tree .= "</li>";
2255
		return $tree;
2256
	}
2257
		
2258
	/* Even this should take children into consideration */
2259
	function build_rules(&$default = false) {
2260
		$pfq_rule = "queue ". $this->qname;
2261
		if ($this->GetInterface())
2262
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2263
		if ($this->GetBandwidth() && $this->GetBwscale())
2264
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2265
		$tmpvalue = $this->GetQpriority();
2266
		if (!empty($tmpvalue))
2267
			$pfq_rule .= " priority " . $this->GetQpriority();
2268
		$tmpvalue = trim($this->GetQlimit());
2269
		if (!empty($tmpvalue))
2270
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2271
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow()) {
2272
			$pfq_rule .= " cbq ( ";
2273
			$tmpvalue = trim($this->GetRed());
2274
			if (!empty($tmpvalue)) {
2275
				$comma = 1;
2276
				$pfq_rule .= " red ";
2277
			}
2278
			$tmpvalue = trim($this->GetRio());
2279
			if (!empty($tmpvalue)) {
2280
				if ($comma) 
2281
					$pfq_rule .= " ,";
2282
				$comma = 1;
2283
				$pfq_rule .= " rio ";
2284
			}
2285
			$tmpvalue = trim($this->GetEcn());
2286
			if (!empty($tmpvalue)) {
2287
				if ($comma) 
2288
					$pfq_rule .= " ,";
2289
				$comma = 1;
2290
				$pfq_rule .= " ecn ";
2291
			}
2292
			$tmpvalue = trim($this->GetDefault());
2293
			if (!empty($tmpvalue)) {
2294
				if ($comma)
2295
					$pfq_rule .= " ,";
2296
				$comma = 1;
2297
				$pfq_rule .= " default ";
2298
				$default = true;
2299
			}
2300
			$tmpvalue = trim($this->GetBorrow());
2301
			if (!empty($tmpvalue)) {
2302
				if ($comma)
2303
					$pfq_rule .= ", ";
2304
				$pfq_rule .= " borrow ";
2305
			}
2306
			$pfq_rule .= " ) ";
2307
		} 
2308
		if (count($this->subqueues)) {
2309
			$i = count($this->subqueues);
2310
			$pfq_rule .= " { ";
2311
			foreach ($this->subqueues as $qkey => $qnone) {
2312
				if ($i > 1) {
2313
					$i--;
2314
					$pfq_rule .= " {$qkey}, ";
2315
				} else
2316
					$pfq_rule .= " {$qkey} ";
2317
			}
2318
			$pfq_rule .= " } \n";
2319
			foreach ($this->subqueues as $q)
2320
				$pfq_rule .= $q->build_rules($default);
2321
		}
2322

    
2323
		$pfq_rule .= " \n";
2324
		return $pfq_rule;
2325
	}
2326

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

    
2365
		return $form;
2366
	}
2367

    
2368
	function update_altq_queue_data(&$data) { 
2369
		$this->ReadConfig($data);
2370
	}
2371

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

    
2410
class fairq_queue extends priq_queue {
2411
	var $hogs;
2412
	var $buckets;
2413

    
2414
	function GetBuckets() {
2415
		return $this->buckets;
2416
	}
2417
	function SetBuckets($buckets) {
2418
		$this->buckets = $buckets;
2419
	}
2420
	function GetHogs() {
2421
		return $this->hogs;
2422
	}
2423
	function SetHogs($hogs) {
2424
		$this->hogs = $hogs;
2425
	}
2426
	function CanHaveChildren() {
2427
		return false;
2428
	}
2429

    
2430

    
2431
	function copy_queue($interface, &$cflink) {
2432
                $cflink['interface'] = $interface;
2433
                $cflink['qlimit'] = $this->GetQlimit();
2434
                $cflink['priority'] = $this->GetQpriority();
2435
                $cflink['name'] = $this->GetQname();
2436
                $cflink['description'] = $this->GetDescription();
2437
                $cflink['bandwidth'] = $this->GetBandwidth();
2438
                $cflink['bandwidthtype'] = $this->GetBwscale();
2439
                $cflink['enabled'] = $this->GetEnabled();
2440
                $cflink['default'] = $this->GetDefault();
2441
                $cflink['red'] = $this->GetRed();
2442
                $cflink['rio'] = $this->GetRio();
2443
                $cflink['ecn'] = $this->GetEcn();
2444
                $cflink['buckets'] = $this->GetBuckets();
2445
		$cflink['hogs'] = $this->GetHogs();
2446
	}
2447
	
2448
	/*
2449
	 * Should search even its children
2450
	 */
2451
	function &find_queue($interface, $qname) {
2452
		if ($qname == $this->GetQname())
2453
			return $this;
2454
	}
2455

    
2456
	function find_parentqueue($interface, $qname) { return; }
2457

    
2458
	function delete_queue() {
2459
		unref_on_altq_queue_list($this->GetQname());
2460
		cleanup_queue_from_rules($this->GetQname());
2461
		unset_object_by_reference($this->GetLink());
2462
	}
2463
	
2464
	function validate_input($data, &$input_errors) {
2465
		parent::validate_input($data, $input_errors);
2466
		
2467
		if ($data['priority'] > 255)
2468
				$input_errors[] = gettext("Priority must be an integer between 1 and 255.");
2469
		$reqdfields[] = "bandwidth";
2470
		$reqdfieldsn[] = gettext("Bandwidth");
2471
		$reqdfields[] = "bandwidthtype";
2472
		$reqdfieldsn[] = gettext("Bandwidthtype");
2473

    
2474
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2475
		
2476
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2477
			$input_errors[] = gettext("Bandwidth must be an integer.");
2478

    
2479

    
2480
		if ($data['bandwidth'] < 0)
2481
			$input_errors[] = gettext("Bandwidth cannot be negative.");
2482

    
2483

    
2484
		if ($data['bandwidthtype'] == "%") {
2485
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2486
				$input_errors[] = gettext("Bandwidth in percentage should be between 1 and 100 bounds.");
2487
		}
2488

    
2489
/*
2490
           	$parent =& $this->GetParent();
2491
           	switch ($data['bandwidthtype']) {
2492
                       case "%":
2493
                             $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2494
                       default:
2495
                             $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2496
                             break;
2497
           	}
2498
                if ($parent->GetAvailableBandwidth() < floatval($myBw))
2499
                        $input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
2500
*/
2501
	}
2502
	
2503
	function ReadConfig(&$q) {
2504
		parent::ReadConfig($q);
2505
		if (!empty($q['buckets']))
2506
			$this->SetBuckets($q['buckets']);
2507
		else
2508
			$this->SetBuckets("");
2509
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs']))
2510
			$this->SetHogs($q['hogs']);
2511
		else
2512
			$this->SetHogs("");
2513
	}
2514
		
2515
	function build_javascript() {
2516
		return parent::build_javascript();
2517
	}
2518

    
2519
	function build_tree() {
2520
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . 
2521
		$this->GetInterface()."&queue=" . $this->GetQname()."&action=show"; 
2522
		$tree .= "\" ";
2523
		$tmpvalue = trim($this->GetDefault());
2524
		if (!empty($tmpvalue))
2525
			$tree .= " class=\"navlnk\"";
2526
		$tree .= " >" . $this->GetQname() . "</a>";
2527
		$tree .= "</li>";
2528
		return $tree;
2529
	}
2530
		
2531
	/* Even this should take children into consideration */
2532
	function build_rules(&$default = false) {
2533
		$pfq_rule = "queue ". $this->qname;
2534
		if ($this->GetInterface())
2535
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2536
		if ($this->GetBandwidth() && $this->GetBwscale())
2537
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2538
		$tmpvalue = trim($this->GetQpriority());
2539
		if (!empty($tmpvalue))
2540
			$pfq_rule .= " priority " . $this->GetQpriority();
2541
		$tmpvalue = trim($this->GetQlimit());
2542
		if (!empty($tmpvalue))
2543
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2544
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() 
2545
			|| $this->GetEcn() || $this->GetBuckets() || $this->GetHogs()) {
2546
			$pfq_rule .= " fairq ( ";
2547
			$tmpvalue = trim($this->GetRed());
2548
			if (!empty($tmpvalue)) {
2549
				$comma = 1;
2550
				$pfq_rule .= " red ";
2551
			}
2552
			$tmpvalue = trim($this->GetRio());
2553
			if (!empty($tmpvalue)) {
2554
				if ($comma) 
2555
					$pfq_rule .= " ,";
2556
				$comma = 1;
2557
				$pfq_rule .= " rio ";
2558
			}
2559
			$tmpvalue = trim($this->GetEcn());
2560
			if (!empty($tmpvalue)) {
2561
				if ($comma) 
2562
					$pfq_rule .= " ,";
2563
				$comma = 1;
2564
				$pfq_rule .= " ecn ";
2565
			}
2566
			$tmpvalue = trim($this->GetDefault());
2567
			if (!empty($tmpvalue)) {
2568
				if ($comma)
2569
					$pfq_rule .= " ,";
2570
				$comma = 1;
2571
				$pfq_rule .= " default ";
2572
				$default = true;
2573
			}
2574
			$tmpvalue = trim($this->GetBuckets());
2575
			if (!empty($tmpvalue)) {
2576
				if ($comma)
2577
					$pfq_rule .= ", ";
2578
				$pfq_rule .= " buckets " . $this->GetBuckets() . " ";
2579
			}
2580
			$tmpvalue = trim($this->GetHogs());
2581
			if (!empty($tmpvalue)) {
2582
				if ($comma)
2583
					$pfq_rule .= ", ";
2584
				$pfq_rule .= " hogs " . $this->GetHogs() . " ";
2585
			}
2586
				$pfq_rule .= " ) ";
2587
		} 
2588

    
2589
		$pfq_rule .= " \n";
2590
		return $pfq_rule;
2591
	}
2592

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

    
2641
	function update_altq_queue_data(&$data) { 
2642
		$this->ReadConfig($data);
2643
	}
2644

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

    
2686

    
2687
/*
2688
 * dummynet(4) wrappers.
2689
 */
2690

    
2691

    
2692
/*
2693
 * List of respective objects!
2694
 */
2695
$dummynet_pipe_list = array();
2696

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

    
2707
        var $buckets;
2708
        /* mask parameters */
2709
        var $mask;
2710
        var $noerror;
2711

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

    
2786
	function build_javascript() { return; } /* Do not remove */
2787

    
2788
	function validate_input($data, &$input_errors) {
2789
		$reqdfields[] = "bandwidth";
2790
		$reqdfieldsn[] = gettext("Bandwidth");
2791
		$reqdfields[] = "bandwidthtype";
2792
		$reqdfieldsn[] = gettext("Bandwidthtype");
2793
		$reqdfields[] = "newname";
2794
		$reqdfieldsn[] = gettext("Name");
2795
	
2796
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2797

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

    
2813
class dnpipe_class extends dummynet_class {
2814
        var $delay;
2815
	var $qbandwidth = array();
2816
	var $qbandwidthtype;
2817

    
2818
		/* This is here to help on form building and building rules/lists */
2819
        var $subqueues = array();
2820

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

    
2844
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
2845

    
2846
		if (!is_array($this->subqueues))
2847
			$this->subqueues = array();
2848
			
2849
		$q =& new dnqueue_class();
2850
		$q->SetLink($path);
2851
		$q->SetEnabled("on");
2852
		$q->SetPipe($this->GetQname());
2853
		$q->SetParent(&$this);
2854
		$q->ReadConfig($queue);
2855
		$q->validate_input($queue, $input_errors);
2856
		if (count($input_errors)) {
2857
			log_error("SHAPER: could not create queue " . $q->GetQname() . " on interface {$interface} because: " . print_r($input_errors, true));
2858
			return $q;
2859
		}
2860
		$number = dnqueue_find_nextnumber();
2861
		$q->SetNumber($number);
2862
		$this->subqueues[$q->GetQname()] = &$q;
2863
            
2864
		return $q;
2865
	}
2866

    
2867
	function &get_queue_list($q = null) {
2868
		$qlist = array();
2869

    
2870
		$qlist[$this->GetQname()] = $this->GetNumber();
2871
		if (is_array($this->subqueues)) {
2872
			foreach ($this->subqueues as $queue)
2873
				$queue->get_queue_list(&$qlist);
2874
		}
2875
		return $qlist;
2876
	}
2877
		
2878
        /*
2879
         * Should search even its children
2880
         */
2881
        function &find_queue($pipe, $qname) {
2882
                if ($qname == $this->GetQname()) 
2883
                        return $this;
2884
               	foreach ($this->subqueues as $q) {
2885
                       	$result =& $q->find_queue("", $qname);
2886
						if ($result)
2887
                       	        return $result;
2888
               	}
2889
        }
2890

    
2891
	function &find_parentqueue($pipe, $qname) {
2892
		return NULL;
2893
       	}
2894

    
2895
	function validate_input($data, &$input_errors) {
2896
		parent::validate_input($data, $input_errors);
2897

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

    
2925
	function ReadConfig(&$q) {
2926
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
2927
			$this->SetQname($q['newname']);
2928
		} else if (!empty($q['newname'])) {
2929
			$this->SetQname($q['newname']);
2930
		} else {
2931
			$this->SetQname($q['name']);
2932
		}
2933
		$this->SetNumber($q['number']);
2934

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

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

    
2979
        }
2980

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

    
2996
        function build_rules() {
2997
		global $config, $time_based_rules;
2998

    
2999
		if ($this->GetEnabled() == "")
3000
			return;
3001

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

    
3035
		if ($this->GetQlimit())
3036
                    	$pfq_rule .= " queue " . $this->GetQlimit();
3037
		if ($this->GetPlr())
3038
			$pfq_rule .= " plr " . $this->GetPlr();
3039
		if ($this->GetBuckets())
3040
			$pfq_rule .= " buckets " . $this->GetBuckets();
3041
		if ($this->GetDelay())
3042
			$pfq_rule .= " delay " . $this->GetDelay();
3043

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

    
3060
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3061
			foreach ($this->subqueues as $q)
3062
			$pfq_rule .= $q->build_rules();
3063
		}
3064
		$pfq_rule .= " \n";
3065

    
3066
		return $pfq_rule;
3067
        }
3068

    
3069
	function update_dn_data(&$data) { 
3070
		$this->ReadConfig($data);
3071
	}
3072

    
3073
	function build_javascript() {
3074
		global $g, $config;
3075

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

    
3088
		$javasr = <<<EOD
3089
<script text='type/javascript'>
3090
var addBwRowTo = (function() {
3091
	return (function (tableId) {
3092
	var d, tbody, tr, td;
3093
	d = document;
3094
	tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0);
3095
	tr = d.createElement("tr");
3096
	td = d.createElement("td");
3097
	td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='bandwidth_row-" + totalrows + "'></input><input size='10' type='text' class='formfld unknown' name='bandwidth" + totalrows + "' id='bandwidth" + totalrows + "'></input> ";
3098
	tr.appendChild(td);
3099
	td = d.createElement("td");
3100
	td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='bwtype_row-" + totalrows + "'></input><select class='formselect' name='bwtype" + totalrows + "'>{$bwopt}</select>";
3101
	tr.appendChild(td);
3102
	td = d.createElement("td");
3103
	td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='bwsched_row-" + totalrows + "'></input><select class='formselect' name='bwsched" + totalrows + "'>{$schedules}</select>";
3104
	tr.appendChild(td);
3105
	td = d.createElement("td");
3106
	td.rowSpan = "1";
3107
	td.innerHTML = '<a onclick="removeBwRow(this); return false;" href="#"><img border="0" src="/themes/{$g['theme']}/images/icons/icon_x.gif" /></a>';
3108
	tr.appendChild(td);
3109
	tbody.appendChild(tr);
3110
	totalrows++;
3111
	});
3112
})();
3113

    
3114
function removeBwRow(el) {
3115
	var cel;
3116
	while (el && el.nodeName.toLowerCase() != "tr")
3117
	    el = el.parentNode;
3118
		if (el && el.parentNode) {
3119
			cel = el.getElementsByTagName("td").item(0);
3120
			el.parentNode.removeChild(el);
3121
		}
3122
}
3123
</script>
3124

    
3125
EOD;
3126

    
3127
	       return $javasr;
3128
	}
3129

    
3130
        function build_form() { 
3131
		global $g, $config;
3132

    
3133
		//build list of schedules
3134
		$schedules = array();
3135
		$schedules[] = "none";//leave none to leave rule enabled all the time
3136
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3137
			foreach ($config['schedules']['schedule'] as $schedule) {
3138
				if ($schedule['name'] <> "")
3139
					$schedules[] = $schedule['name'];
3140
			}
3141
		}
3142

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

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

    
3279
		return $form;
3280
			
3281
		}
3282

    
3283
	function wconfig() {
3284
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3285
            	if (!is_array($cflink))
3286
            		$cflink = array();
3287
		$cflink['name'] = $this->GetQname();
3288
		$cflink['number'] = $this->GetNumber();
3289
            	$cflink['qlimit'] = $this->GetQlimit();
3290
            	$cflink['plr'] = $this->GetPlr();
3291
            	$cflink['description'] = $this->GetDescription();
3292
               
3293
		$bandwidth = $this->GetBandwidth();
3294
		if (is_array($bandwidth)) {
3295
			$cflink['bandwidth'] = array();
3296
			$cflink['bandwidth']['item'] = array();
3297
			foreach ($bandwidth as $bwidx => $bw)
3298
				$cflink['bandwidth']['item'][] = $bw;
3299
		}
3300

    
3301
		$cflink['enabled'] = $this->GetEnabled();
3302
		$cflink['buckets'] = $this->GetBuckets();
3303
		$cflink['mask'] = $this->GetMask();
3304
		$cflink['delay'] = $this->GetDelay();
3305
	}
3306

    
3307
}
3308

    
3309
class dnqueue_class extends dummynet_class {
3310
        var $pipeparent;
3311
        var $weight;
3312

    
3313
        function GetWeight() {
3314
                return $this->weight;
3315
        }
3316
        function SetWeight($weight) {
3317
                $this->weight = $weight;
3318
        }
3319
	function GetPipe() {
3320
		return $this->pipeparent;
3321
	}
3322
	function SetPipe($pipe) {
3323
		$this->pipeparent = $pipe;
3324
	}
3325

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

    
3329
	function delete_queue() {
3330
		cleanup_dnqueue_from_rules($this->GetQname());
3331
		unset_dn_object_by_reference($this->GetLink());
3332
		mwexec("/sbin/ipfw queue delete " . $this->GetNumber());
3333
        }
3334

    
3335
	function validate_input($data, &$input_errors) {
3336
		parent::validate_input($data, $input_errors);
3337

    
3338
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3339
			($data['weight'] < 1 && $data['weight'] > 100))) 
3340
				$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
3341
	}
3342

    
3343
        /*
3344
         * Should search even its children
3345
         */
3346
        function &find_queue($pipe, $qname) {
3347
                if ($qname == $this->GetQname()) 
3348
                	return $this;
3349
		else
3350
			return NULL;
3351
        }
3352

    
3353
	function &find_parentqueue($pipe, $qname) {
3354
		return $this->qparent;
3355
        }
3356

    
3357
        function &get_queue_list(&$qlist) {
3358
		if ($this->GetEnabled() == "")
3359
			return;
3360
        	$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3361
        }		
3362

    
3363
	function ReadConfig(&$q) {
3364
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3365
			$this->SetQname($q['newname']);
3366
		} else if (!empty($q['newname'])) {
3367
			$this->SetQname($q['newname']);
3368
		} else {
3369
			$this->SetQname($q['name']);
3370
		}
3371
		$this->SetNumber($q['number']);
3372
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
3373
       		       	$this->SetQlimit($q['qlimit']);
3374
		else
3375
       		       	$this->SetQlimit("");
3376
		if (isset($q['mask']) && $q['mask'] <> "")
3377
              		$this->SetMask($q['mask']);
3378
		else
3379
              		$this->SetMask("");
3380
       		if (isset($q['weight']) && $q['weight'] <> "")
3381
            		$this->SetWeight($q['weight']);
3382
		else
3383
            		$this->SetWeight("");
3384
            	if (isset($q['description']) && $q['description'] <> "")
3385
			$this->SetDescription($q['description']);
3386
		else
3387
			$this->SetDescription("");
3388
		$this->SetEnabled($q['enabled']);
3389
        }
3390

    
3391
	function build_tree() {
3392
		$parent =& $this->GetParent();
3393
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&queue=" . $this->GetQname() ."&action=show\">"; 
3394
		$tree .= $this->GetQname() . "</a>";
3395
		$tree .= "</li>";
3396
		
3397
		return $tree;
3398
	}
3399

    
3400
        function build_rules() {
3401
		if ($this->GetEnabled() == "")
3402
			return; 
3403

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

    
3428
		return $pfq_rule;
3429
	}
3430

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

    
3526
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3527
		$form .= " value=\"" . $this->GetPipe() . "\">";
3528

    
3529
		return $form;
3530
			
3531
	}
3532

    
3533
        function update_dn_data(&$data) { 
3534
		$this->ReadConfig($data);
3535
	}
3536

    
3537
	function wconfig() {
3538
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3539
            	if (!is_array($cflink))
3540
            		$cflink = array();
3541
		$cflink['name'] = $this->GetQname();
3542
		$cflink['number'] = $this->GetNumber();
3543
            	$cflink['qlimit'] = $this->GetQlimit();
3544
            	$cflink['description'] = $this->GetDescription();
3545
		$cflink['weight'] = $this->GetWeight();
3546
		$cflink['enabled'] = $this->GetEnabled();
3547
		$cflink['buckets'] = $this->GetBuckets();
3548
		$cflink['mask'] = $this->GetMask();
3549
	}
3550
}
3551

    
3552
// List of layer7 objects
3553
$layer7_rules_list = array();
3554

    
3555
class layer7 {
3556
    
3557
    var $rname; //alias
3558
    var $rdescription; //alias description
3559
    var $rport; //divert port
3560
    var $renabled; //rule enabled
3561
    var $rsets = array(); //array of l7 associations
3562
    
3563
    // Auxiliary functions
3564
    
3565
    function GetRName() {
3566
        return $this->rname;
3567
    }
3568
    function SetRName($rname) {
3569
        $this->rname = $rname;
3570
    }
3571
    function GetRDescription() {
3572
        return $this->rdescription;
3573
    }
3574
    function SetRDescription($rdescription) {
3575
        $this->rdescription = $rdescription;
3576
    }
3577
    function GetRPort() {
3578
        return $this->rport;
3579
    }
3580
    function SetRPort($rport) {
3581
        $this->rport = $rport;
3582
    }
3583
    function GetREnabled() {
3584
        return $this->renabled;
3585
    }
3586
    function SetREnabled($value) {
3587
        $this->renabled = $value;
3588
    }
3589
    function GetRl7() {
3590
        return $this->rsets;
3591
    }
3592
    function SetRl7($rsets) {
3593
        $this->rsets = $rsets;
3594
    }
3595
    
3596
    //Add a tuple (rule,sctructure,element) to the $rsets
3597
    
3598
    function add_rule($l7set) {
3599
       	$this->rsets[] = $l7set;
3600
    }
3601
    
3602
    // Build the layer7 rules
3603
    function build_l7_rules() {
3604
        if($this->GetREnabled() == "") {
3605
            return;
3606
        }
3607
        //$l7rules = "#" . $this->rdescription . "\n";
3608
        foreach ($this->rsets as $rl7) {
3609
            $l7rules .= $rl7->build_rules();
3610
        }
3611
        return $l7rules;
3612
    }
3613
    
3614
    // Read the config from array
3615
    function ReadConfig(&$qname, &$q) {
3616
        $this->SetRName($qname);
3617
        $this->SetREnabled($q['enabled']);
3618
        $this->SetRPort($q['divert_port']);
3619
        if(isset($q['description']) && $q['description'] <> "")
3620
            $this->SetRDescription($q['description']);
3621
        $rsets = $q['l7rules'];
3622
        //Put individual rules in the array
3623
	if(is_array($rsets)) {
3624
	    $this->rsets = array(); // XXX: ugly hack
3625
	    foreach($rsets as $l7r) {
3626
	        $l7obj = new l7rule();
3627
	        $l7obj->SetRProtocol($l7r['protocol']);
3628
	        $l7obj->SetRStructure($l7r['structure']);
3629
	        $l7obj->SetRBehaviour($l7r['behaviour']);
3630
	        $this->add_rule($l7obj);
3631
	    }
3632
	}
3633
    }
3634
    
3635
    //Generate a random port for the divert socket
3636
    function gen_divert_port() {
3637
        $dports = get_divert_ports(); //array of used ports
3638
	$divert_port = 1; // Initialize
3639
	while (($divert_port % 2) != 0 || in_array($divert_port, $dports)) {
3640
		$divert_port = rand(40000, 60000);
3641
	}
3642
        return $divert_port;
3643
    }
3644
    
3645
    //Helps building the left tree
3646
    function build_tree() {
3647
        $tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&action=show\">"; 
3648
        $tree .= $this->GetRName() . "</a>";
3649
	$tree .= "</li>";
3650
		
3651
	return $tree;
3652
    }
3653
    
3654
    function build_form() {
3655
        $form = "<tr><td valign=\"center\" class=\"vncellreq\"><br>";
3656
	$form .= gettext("Enable/Disable");
3657
	$form .= "</td><td class=\"vncellreq\">";
3658
	$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\" value=\"on\" ";
3659
	if ($this->GetREnabled() == "on") {
3660
       	    $form .=  "checked = \"CHECKED\"";
3661
	}
3662
	$form .= " ><span class=\"vexpl\"> " . gettext("Enable/Disable layer7 Container") . "</span>";
3663
	$form .= "</td></tr>";
3664
        $form .= "<tr><td valign=\"center\" class=\"vncellreq\"><br><span class=\"vexpl\">" . gettext("Name") . "</span></td>";
3665
	$form .= "<td class=\"vncellreq\">";
3666
	$form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
3667
	$form .= $this->GetRName()."\">";
3668
	$form .= "</td></tr>";
3669
	$form .= "<tr><td valign=\"center\" class=\"vncellreq\">" . gettext("Description") . "</td>";
3670
	$form .= "<td class=\"vncellreq\">";
3671
	$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"50%\" id=\"description\" name=\"description\" value=\"";
3672
	$form .= $this->GetRDescription();
3673
	$form .= "\">";
3674
	$form .= "<br> <span class=\"vexpl\">";
3675
	$form .= gettext("You may enter a description here for your reference (not parsed).") . "</span>";
3676
	$form .= "</td></tr>";
3677
	
3678
	return $form;
3679
    }
3680
    
3681
    //Write the setting to the $config array
3682
    function wconfig() {
3683
	global $config;
3684
	
3685
	if(!is_array($config['l7shaper']['container'])) {
3686
		$config['l7shaper']['container'] = array();
3687
	}
3688
        //
3689
        $cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
3690
	// Test if this rule does exists already
3691
	if(!$cflink) {
3692
		$cflink =& $config['l7shaper']['container'][];
3693
	}
3694
	$cflink['name'] = $this->GetRName();
3695
        $cflink['enabled'] = $this->GetREnabled();
3696
        $cflink['description'] = $this->GetRDescription();
3697
        $cflink['divert_port'] = $this->GetRPort();
3698
        
3699
	//Destroy previously existent rules
3700
	if(is_array($cflink['rules'])) {
3701
		unset($cflink['l7rules']);
3702
	}
3703
	
3704
        $cflink['l7rules'] = array();
3705
	
3706
        $i = 0;
3707
        foreach($this->rsets as $rulel7) {
3708
            $cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
3709
            $cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
3710
            $cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
3711
            $i++;
3712
        }
3713
    }
3714
    
3715
    //This function is necessary to help producing the overload options for keep state
3716
    function get_unique_structures() {
3717
        
3718
        $unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
3719
        foreach($this->rsets as $l7rule) {
3720
		if($l7rule->GetRStructure() == "action")
3721
			$unique_structures['action'] = true;
3722
		else if($l7rule->GetRStructure() == "limiter")
3723
			$unique_structures['dummynet'] = true;
3724
		else
3725
			$unique_structures['altq'] = true;
3726
        }
3727
	//Delete non used structures so we don't have to check this in filter.inc
3728
	foreach($unique_structures as $key => $value)
3729
		if(!$value)
3730
			unset($unique_structures[$key]);
3731
        return $unique_structures;
3732
    }
3733
    
3734
    function validate_input($data, &$input_errors) {
3735
	$reqdfields[] = "container";
3736
	$reqdfieldsn[] = gettext("Name");
3737
		
3738
	shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3739
        
3740
        if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container']))
3741
            $input_errors[] = gettext("Queue names must be alphanumeric and _ or - only.");
3742
    }
3743
    
3744
    function delete_l7c() {
3745
	mwexec("/bin/pkill -f 'ipfw-classifyd .* -p ". $this->GetRPort() . "'", true);
3746
	unset_l7_object_by_reference($this->GetRName());
3747
	cleanup_l7_from_rules($this->GetRName());
3748
    }
3749
}
3750

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

    
3808
/*
3809
 * This function allows to return an array with all the used divert socket ports
3810
 */
3811
function get_divert_ports() {
3812
    global $layer7_rules_list;
3813
    $dports = array();
3814
    
3815
    foreach($layer7_rules_list as $l7r)
3816
        $dports[] = $l7r->GetRPort();
3817
    
3818
    return $dports;
3819
}
3820

    
3821
function &get_l7c_reference_to_me_in_config(&$name) {
3822
	global $config;
3823
	
3824
	$ptr = NULL;
3825
	
3826
	if(is_array($config['l7shaper']['container'])) {
3827
		foreach($config['l7shaper']['container'] as $key => $value) {
3828
			if($value['name'] == $name)
3829
				$ptr =& $config['l7shaper']['container'][$key];
3830
		}
3831
	}	
3832
	return $ptr;
3833
// $ptr can be null. has to be checked later
3834
}
3835

    
3836
function unset_l7_object_by_reference(&$name) {
3837
	global $config;
3838
        
3839
	if(is_array($config['l7shaper']['container'])) {
3840
		foreach($config['l7shaper']['container'] as $key => $value) {
3841
			if($value['name'] == $name) {
3842
				unset($config['l7shaper']['container'][$key]['l7rules']);
3843
				unset($config['l7shaper']['container'][$key]);
3844
				break;
3845
			}
3846
		}
3847
	}
3848
}
3849

    
3850
function read_layer7_config() {
3851
    global $layer7_rules_list, $config;
3852
    
3853
    $l7cs = &$config['l7shaper']['container'];
3854
    
3855
    $layer7_rules_list = array();
3856
    
3857
    if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container']))
3858
	return;
3859
    
3860
    foreach ($l7cs as $conf) {
3861
	if (empty($conf['name']))
3862
		continue; /* XXX: grrrrrr at php */ 
3863
        $root =& new layer7();
3864
        $root->ReadConfig($conf['name'],$conf);
3865
        $layer7_rules_list[$root->GetRName()] = &$root;
3866
    }
3867
}
3868

    
3869
function generate_layer7_files() {
3870
    global $layer7_rules_list, $g;
3871
    
3872
    read_layer7_config();
3873
    
3874
    if (!empty($layer7_rules_list)) {
3875
	if (!is_module_loaded("ipdivert.ko"))
3876
		mwexec("/sbin/kldload ipdivert.ko");
3877

    
3878
	mwexec("rm -f {$g['tmp_path']}/*.l7");
3879
    }
3880
    
3881
    foreach($layer7_rules_list as $l7rules) {
3882
        if($l7rules->GetREnabled()) {
3883
            $filename = $l7rules->GetRName() . ".l7";
3884
            $path = "{$g['tmp_path']}/" . $filename;
3885
        
3886
            $rules = $l7rules->build_l7_rules();
3887
        
3888
            $fp = fopen($path,'w');
3889
            fwrite($fp,$rules);
3890
            fclose($fp);
3891
        }
3892
    }
3893
}
3894

    
3895
function layer7_start_l7daemon() {
3896
    global $layer7_rules_list, $g;
3897

    
3898
    /*
3899
     * XXX: ermal - Needed ?!
3900
     * read_layer7_config();
3901
     */
3902

    
3903
    foreach($layer7_rules_list as $l7rules) {
3904
        if($l7rules->GetREnabled()) {
3905
            $filename = $l7rules->GetRName() . ".l7";
3906
            $path = "{$g['tmp_path']}/" . $filename;
3907

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

    
3923
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
3924
function generate_protocols_array() {
3925
	$protocols = return_dir_as_array("/usr/local/share/protocols");
3926
	$protocols_new = array();
3927
	if(is_array($protocols)) {
3928
		foreach($protocols as $key => $proto) {
3929
			if (strstr($proto, ".pat"))
3930
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
3931
		}
3932
		sort($protocols_new);
3933
	}		
3934
	return $protocols_new;
3935
}
3936

    
3937
function get_l7_unique_list() {
3938
	global $layer7_rules_list;
3939
	
3940
	$l7list = array();
3941
	if(is_array($layer7_rules_list)) 
3942
		foreach($layer7_rules_list as $l7c)
3943
			if($l7c->GetREnabled())
3944
				$l7list[] = $l7c->GetRName();
3945
	
3946
	return $l7list;
3947
}
3948

    
3949
// Disable a removed l7 container from the filter
3950
function cleanup_l7_from_rules(&$name) {
3951
	global $config;
3952

    
3953
	if(is_array($config['filter']['rule']))
3954
		foreach ($config['filter']['rule'] as $key => $rule) {
3955
			if ($rule['l7container'] == $name)
3956
				unset($config['filter']['rule'][$key]['l7container']);
3957
		}
3958
}
3959

    
3960
function get_dummynet_name_list() {
3961
	
3962
	$dn_name_list =& get_unique_dnqueue_list();
3963
	$dn_name = array();
3964
	if(is_array($dn_name_list))
3965
		foreach($dn_name_list as $key => $value)
3966
			$dn_name[] = $key;
3967
	
3968
	return $dn_name;
3969
	
3970
}
3971

    
3972
function get_altq_name_list() {
3973
	$altq_name_list =& get_unique_queue_list();
3974
	$altq_name = array();
3975
	if(is_array($altq_name_list))
3976
		foreach($altq_name_list as $key => $aqobj)
3977
			$altq_name[] = $key;
3978
		
3979
	return $altq_name;
3980
}
3981

    
3982
/*
3983
 * XXX: TODO Make a class shaper to hide all these function
3984
 * from the global namespace.
3985
 */
3986

    
3987
/* 
3988
 * This is a layer violation but for now there is no way 
3989
 * i can find to properly do this with PHP.
3990
 */
3991
function altq_get_default_queue($interface) {
3992
	global $altq_list_queues;
3993

    
3994
	$altq_tmp = $altq_list_queues[$interface];
3995
	if ($altq_tmp)
3996
		return $altq_tmp->GetDefaultQueuePresent(); 
3997
	else
3998
		return false;
3999
}
4000

    
4001
function altq_check_default_queues() {
4002
	global $altq_list_queues;
4003

    
4004
	$count = 0;
4005
	if (is_array($altq_list_queues)) {
4006
		foreach($altq_list_queues as $altq) {
4007
			if ($altq->GetDefaultQueuePresent())
4008
				$count++;
4009
		}
4010
	}
4011
	else  $count++;;
4012
	
4013
	return 0;
4014
}
4015

    
4016
function &get_unique_queue_list() {
4017
	global $altq_list_queues;
4018
	
4019
	$qlist = array();
4020
	if (is_array($altq_list_queues)) {
4021
		foreach ($altq_list_queues as $altq) {
4022
			if ($altq->GetEnabled() == "")
4023
				continue;
4024
			$tmplist =& $altq->get_queue_list();
4025
			foreach ($tmplist as $qname => $link) {
4026
				if ($link->GetEnabled() <> "")
4027
					$qlist[$qname] = $link;	
4028
			}
4029
		}
4030
	}
4031
	return $qlist;
4032
}
4033

    
4034
function &get_unique_dnqueue_list() {
4035
	global $dummynet_pipe_list;
4036
	
4037
	$qlist = array();
4038
	if (is_array($dummynet_pipe_list)) {
4039
		foreach ($dummynet_pipe_list as $dn) {
4040
			if ($dn->GetEnabled() == "")
4041
				continue;
4042
			$tmplist =& $dn->get_queue_list();
4043
			foreach ($tmplist as $qname => $link) {
4044
				$qlist[$qname] = $link;	
4045
			}
4046
		}
4047
	}
4048
	return $qlist;
4049
}
4050

    
4051
function ref_on_altq_queue_list($parent, $qname) {
4052
	if (isset($GLOBALS['queue_list'][$qname]))
4053
		$GLOBALS['queue_list'][$qname]++;
4054
	else
4055
		$GLOBALS['queue_list'][$qname] = 1;
4056

    
4057
	unref_on_altq_queue_list($parent);
4058
}
4059

    
4060
function unref_on_altq_queue_list($qname) {
4061
	$GLOBALS['queue_list'][$qname]--;
4062
	if ($GLOBALS['queue_list'][$qname] <= 1)
4063
		unset($GLOBALS['queue_list'][$qname]);	
4064
}
4065

    
4066
function read_altq_config() {
4067
	global $altq_list_queues, $config;
4068
	$path = array();
4069
	
4070
	if (!is_array($config['shaper']))
4071
		$config['shaper'] = array();
4072
	if (!is_array($config['shaper']['queue']))
4073
		$config['shaper']['queue'] = array();
4074
	$a_int = &$config['shaper']['queue'];
4075

    
4076
	$altq_list_queues = array();
4077
	
4078
	if (!is_array($config['shaper']['queue']))
4079
		return;
4080

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

    
4104
function read_dummynet_config() {
4105
	global $dummynet_pipe_list, $config;
4106
	$path = array();
4107

    
4108
	if (!is_array($config['dnshaper']))
4109
		$config['dnshaper'] = array();
4110
	if (!is_array($config['dnshaper']['queue']))
4111
		$config['dnshaper']['queue'] = array();
4112
	$a_int = &$config['dnshaper']['queue'];
4113

    
4114
	$dummynet_pipe_list = array();
4115
	
4116
	if (!is_array($config['dnshaper']['queue'])
4117
		|| !count($config['dnshaper']['queue']))
4118
		return;
4119

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

    
4143
function get_interface_list_to_show() {
4144
	global $altq_list_queues, $config;
4145
	global $shaperIFlist;
4146

    
4147
	$tree = "";
4148
	foreach ($shaperIFlist as $shif => $shDescr) {
4149
		if ($altq_list_queues[$shif]) {
4150
			continue;
4151
		} else  {
4152
			if (!is_altq_capable(get_real_interface($shif)))
4153
				continue;
4154
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&action=add\">".$shDescr."</a></li>";
4155
		}
4156
	}
4157
	
4158
	return $tree;
4159
}
4160

    
4161
function filter_generate_altq_queues() {
4162
	global $altq_list_queues;
4163
	
4164
	read_altq_config();
4165

    
4166
	$altq_rules = "";
4167
	foreach ($altq_list_queues as $altq) 
4168
		$altq_rules .= $altq->build_rules();
4169

    
4170
	return $altq_rules;
4171
}
4172

    
4173
function dnqueue_find_nextnumber() {
4174
	global $dummynet_pipe_list;
4175

    
4176
	$dnused = array();
4177
	if (is_array($dummynet_pipe_list)) {
4178
		foreach ($dummynet_pipe_list as $dn) {
4179
			$tmplist =& $dn->get_queue_list();
4180
			foreach ($tmplist as $qname => $link) {
4181
				if ($link[0] == "?")
4182
					$dnused[$qname] = substr($link, 1);
4183
			}
4184
		}
4185
	}
4186

    
4187
	sort($dnused, SORT_NUMERIC);
4188
	$dnnumber = 0;
4189
	$found = false;
4190
	foreach ($dnused as $dnnum) {
4191
		if (($dnnum - $dnnumber) > 1) {
4192
			$dnnumber = $dnnum + 1;
4193
			$found = true;
4194
			break;
4195
		} else
4196
			$dnnumber = $dnnum;
4197
	}
4198

    
4199
	if ($found == false)
4200
		$dnnumber++;
4201

    
4202
	unset($dnused, $dnnum, $found);
4203
	return $dnnumber;
4204
}
4205

    
4206
function dnpipe_find_nextnumber() {
4207
	global $dummynet_pipe_list;
4208

    
4209
	$dnused = array();
4210
	foreach ($dummynet_pipe_list as $dn)
4211
		$dnused[] = $dn->GetNumber();
4212

    
4213
	sort($dnused, SORT_NUMERIC);
4214
	$dnnumber = 0;
4215
	$found = false;
4216
	foreach ($dnused as $dnnum) {
4217
		if (($dnnum - $dnnumber) > 1) {
4218
			$dnnumber = $dnnum + 1;
4219
			$found = true;
4220
			break;
4221
		} else
4222
			$dnnumber = $dnnum;
4223
	}
4224

    
4225
	if ($found == false)
4226
		$dnnumber++;
4227

    
4228
	unset($dnused, $dnnum, $found);
4229
	return $dnnumber;
4230
}
4231

    
4232
function filter_generate_dummynet_rules() {
4233
	global $g, $dummynet_pipe_list;
4234
	
4235
	read_dummynet_config();
4236
	
4237
	if (!empty($dummynet_pipe_list)) {
4238
		if (!is_module_loaded("dummynet.ko")) {
4239
			mwexec("/sbin/kldload dummynet");
4240
			mwexec("/sbin/sysctl net.inet.ip.dummynet.io_fast=1 net.inet.ip.dummynet.hash_size=256");
4241
		}
4242
	}
4243

    
4244
	$dn_rules = "";
4245
	foreach ($dummynet_pipe_list as $dn) 
4246
		$dn_rules .= $dn->build_rules();
4247

    
4248
	if (!empty($dn_rules)) {
4249
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4250
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4251
	}
4252
}
4253

    
4254
function build_iface_without_this_queue($iface, $qname) {
4255
	global $g, $altq_list_queues;
4256
	global $shaperIFlist;
4257

    
4258
	$altq =& $altq_list_queues[$iface];
4259
	if ($altq)
4260
		$scheduler = ": " . $altq->GetScheduler();
4261
	$form = "<tr><td width=\"20%\" >";
4262
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&queue=" . $iface."&action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4263
	$form .= "</td></tr>";
4264
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4265
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4266
	$form .= $iface . "&queue=". $qname . "&action=add\">";
4267
	$form .= "<img src=\"";
4268
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4269
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\">";
4270
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4271

    
4272
	return $form;
4273

    
4274
}
4275

    
4276

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

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

    
4291
?>
(50-50/66)