Project

General

Profile

Download (123 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("functions.inc");
34

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

    
42
	 $ptr =& $config['shaper'];
43
	foreach ($mypath as $indeks) {
44
		$ptr =& $ptr['queue'][$indeks];
45
	}
46

    
47
	return $ptr;
48
}
49

    
50
function unset_object_by_reference(&$mypath) 
51
{
52
	global $config;
53

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

    
61
function &get_dn_reference_to_me_in_config(&$mypath) 
62
{
63
	global $config;
64

    
65
	$ptr =& $config['dnshaper'];
66
	foreach ($mypath as $indeks) {
67
		$ptr =& $ptr['queue'][$indeks];
68
	}
69

    
70
	return $ptr;
71
}
72

    
73
function unset_dn_object_by_reference(&$mypath) 
74
{
75
	global $config;
76

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

    
84
function clean_child_queues($type, $mypath) 
85
{
86
	$ref = &get_reference_to_me_in_config($mypath);
87

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

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

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

    
163
function get_interface_bandwidth($object) 
164
{
165
	global $altq_list_queues;
166

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

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

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

    
191
        for ($i = 0; $i < count($reqdfields); $i++) {
192
                if ($postdata[$reqdfields[$i]] == "") {
193
                        $input_errors[] = "The field '" . $reqdfieldsn[$i] . "' is required.";
194
                }
195
        }
196
}
197

    
198
function cleanup_queue_from_rules($queue) 
199
{
200
	global $config;
201

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

    
210
function cleanup_dnqueue_from_rules($queue) 
211
{
212
	global $config;
213

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

    
222
class altq_root_queue {
223
	var $interface;
224
	var $tbrconfig ;
225
	var $bandwidth;
226
	var $bandwidthtype; /* b, Kb, Mb */
227
	var $scheduler;
228
	var $qlimit;
229
	var $queues = array();
230
	var $qenabled = false;
231
	var $link;
232
	var $default_present; /* if we have a default queue set */
233
	var $available_bw; /* in b/s */
234

    
235
	/* Accesor functions */
236
	function GetAvailableBandwidth() {
237
		return $this->available_bw;
238
	}
239
	function SetAvailableBandwidth($bw) {
240
		$this->available_bw = $bw;
241
	}
242
	function SetDefaultQueuePresent($value) {
243
		$this->default_present = $value;
244
	}
245
	function GetDefaultQueuePresent() {
246
		return trim($this->default_present);
247
	}
248
	function SetLink($link) {
249
		$this->link = $link;
250
	}
251
	function GetLink() {
252
		return $this->link;
253
	}	
254
	function GetEnabled() {
255
		return $this->qenabled;
256
	}
257
	function SetEnabled($value) {
258
		$this->qenabled = $value;
259
	}
260
	function CanHaveChildren() {
261
		return true;
262
	}
263
	function CanBeDeleted() {
264
		return false;
265
	}
266
	function GetQname() {
267
		return $this->interface;
268
	}
269
	function SetQname($name) {
270
		$this->interface = trim($name);
271
	}
272
	function GetInterface() {
273
		return $this->interface;
274
	}
275
	function SetInterface($name) {
276
		$this->interface = trim($name);
277
	}
278
	function GetTbrConfig() {
279
		return $this->tbrconfig;
280
	}
281
	function SetTbrConfig($tbrconfig) {
282
		$this->tbrconfig = $tbrconfig;
283
	}
284
	function GetBandwidth() {
285
		return $this->bandwidth;
286
	}
287
	function SetBandwidth($bw) {
288
		$this->bandwidth = $bw;
289
	}
290
	function GetBwscale() {
291
		return $this->bandwidthtype;
292
	}
293
	function SetBwscale($bwscale) {
294
		$this->bandwidthtype = $bwscale;
295
	}
296
	function GetScheduler() {
297
		return $this->scheduler;
298
	}
299
	function SetScheduler($scheduler) {
300
		$this->scheduler = trim($scheduler);
301
	}
302
	function GetQlimit() {
303
		return $this->qlimit;
304
	}
305
	function SetQlimit($limit) {
306
		$this->qlimit = $limit;
307
	}
308

    
309
	function validate_input($data, &$input_errors) {
310
		
311
		$reqdfields[] = "bandwidth";
312
		$reqdfieldsn[] = "Bandwidth";
313
		$reqdfields[] = "bandwidthtype";
314
		$reqdfieldsn[] = "Bandwidthtype";
315
		
316
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
317
		
318
                if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
319
			$input_errors[] = "Bandwidth must be an integer.";
320
                if ($data['bandwidth'] < 0)
321
			$input_errors[] = "Bandwidth cannot be negative.";
322
                if ($data['qlimit'] && (!is_numeric($data['qlimit'])))
323
			$input_errors[] = "Qlimit must be an integer.";
324
	 	if ($data['qlimit'] < 0)
325
			$input_errors[] = "Qlimit must be an positive.";
326
                if ($data['tbrconfig'] && (!is_numeric($data['tbrconfig'])))
327
			$input_errors[] = "Tbrsize must be an integer.";
328
                if ($data['tbrconfig'] < 0)
329
			$input_errors[] = "Tbrsize must be an positive.";
330
	}
331

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

    
358
	function copy_queue($interface, &$cflink) {
359
                $cflink['interface'] = $interface;
360
                $cflink['name'] = $interface;
361
                $cflink['scheduler'] = $this->GetScheduler();
362
                $cflink['bandwidth'] = $this->GetBandwidth();
363
                $cflink['bandwidthtype'] = $this->GetBwscale();
364
                $cflink['qlimit'] = $this->GetQlimit();
365
                $cflink['tbrconfig'] = $this->GetTbrConfig();
366
                $cflink['enabled'] = $this->GetEnabled();
367
		if (is_array($this->queues)) {
368
			$cflink['queue'] = array();
369
			foreach ($this->queues as $q) {
370
				$cflink['queue'][$q->GetQname()] = array();
371
				$q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
372
			}
373
		}
374
	}
375

    
376
	function &get_queue_list($q = null) {
377
		$qlist = array();
378

    
379
		$qlist[$this->GetQname()] = & $this;
380
		if (is_array($this->queues)) {
381
			foreach ($this->queues as $queue)
382
				$queue->get_queue_list(&$qlist);
383
		}
384
		return $qlist;
385
	}
386

    
387
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
388

    
389
		if (!is_array($this->queues))
390
			$this->queues = array();
391

    
392
		switch ($this->GetScheduler()) {
393
		case "PRIQ":
394
			$q =& new priq_queue();
395
			break;
396
		case "HFSC":
397
			$q =& new hfsc_queue();
398
			break;
399
		case "CBQ":
400
			$q =& new cbq_queue();
401
			break;
402
		case "FAIRQ":
403
			$q =& new fairq_queue();
404
			break;
405
		default:
406
			/* XXX: but should not happen anyway */ 
407
			return;
408
			break;
409
		}
410
		$q->SetLink($path);
411
		$q->SetInterface($this->GetInterface());
412
		$q->SetEnabled("on");
413
		$q->SetParent(&$this);
414
		$q->ReadConfig($queue);
415
		$q->validate_input($queue, $input_errors);
416
		if (count($input_errors)) {
417
			return $q;
418
		}
419

    
420
		if (isset($queue['bandwidth'])) {
421
			switch ($queue['bandwidthtype']) {
422
			case "%":
423
				$myBw = $this->GetAvailableBandwidth() * $queue['bandwidth'] / 100;
424
				break;
425
			default:
426
				$myBw = $queue['bandwidth'] * get_bandwidthtype_scale($queue['bandwdithtype']);
427
				break;
428
			}
429
		}
430
		$q->SetAvailableBandwidth($myBw);
431
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
432
		$this->queues[$q->GetQname()] = &$q; 
433
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
434
		if (is_array($queue['queue'])) {
435
			foreach ($queue['queue'] as $key1 => $que) {
436
				array_push($path, $key1);
437
				$q->add_queue($q->GetInterface(), &$que, &$path, $input_errors);
438
				array_pop($path);
439
			}
440
		}
441

    
442
		return $q;
443
	}
444

    
445
	/* interface here might be optional */
446
	function &find_queue($interface, $qname) {
447
		if ($qname == $this->GetQname()) {
448
			return $this;
449
		} 
450
		foreach ($this->queues as $q) {
451
			$result =& $q->find_queue("", $qname);
452
			if ($result)
453
				return $result;
454
		}
455
	}
456

    
457
	function &find_parentqueue($interface, $qname) {
458
		if ($qname == $interface) {
459
			$result =  NULL;
460
		} else if ($this->queues[$qname])	 {
461
			$result = $this;
462
		} else if ($this->GetScheduler() <> "PRIQ") {
463
			foreach ($this->queues as $q) {
464
				$result = $q->find_parentqueue("", $qname);
465
				if ($result)
466
					return $result;
467
			}
468
		}
469
	}
470

    
471
	function build_tree() {
472
		global $shaperIFlist;
473

    
474
		$tree = " <li><a href=\"firewall_shaper.php?interface=".$this->GetInterface()."&queue=". $this->GetInterface()."&action=show"; 
475
		$tree .= "\">" . $shaperIFlist[$this->GetInterface()] . "</a>";
476
		if (is_array($this->queues)) {
477
			$tree .= "<ul>";
478
			foreach ($this->queues as $q)  {
479
				$tree .= $q->build_tree();
480
			}
481
		$tree .= "</ul>";
482
		}
483
		$tree .= "</li>";
484
		return $tree;
485
	}
486
	
487
	function delete_queue() { 
488
		foreach ($this->queues as $q) {
489
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
490
			$q->delete_queue();			
491
		}
492
		unset_object_by_reference($this->GetLink());
493
	 }
494

    
495
	function delete_all() {
496
                if (count($this->queues)) {
497
                        foreach ($this->queues as $q) {
498
                        	$q->delete_all();
499
                        	unset_object_by_reference($q->GetLink());
500
                                unset($q);
501
               		}
502
        	        unset($this->queues);
503
                }
504
        }
505

    
506
	/*
507
	 * First it spits:
508
	 * altq on $interface ..............
509
	 *      then it goes like
510
	 *      foreach ($queues as $qkey => $queue)
511
	 *              this->queues[$qkey]->build_rule();
512
	 */
513
	function build_rules() {
514
		if (count($this->queues) > 0 && $this->GetEnabled()) {
515
			$rules = " altq on  " . get_real_interface($this->GetInterface());
516
			if ($this->GetScheduler())
517
				$rules .= " ".strtolower($this->GetScheduler());
518
			if ($this->GetBandwidth())
519
				$rules .= " bandwidth ".trim($this->GetBandwidth());
520
			if ($this->GetBwscale())
521
				$rules .= $this->GetBwscale();
522
			if ($this->GetTbrConfig())
523
				$rules .= " tbrsize ".$this->GetTbrConfig();
524
			if (count($this->queues)) {
525
				$i = count($this->queues);
526
				$rules .= " queue { ";
527
				foreach ($this->queues as $qkey => $qnone) {
528
					if ($i > 1) {
529
						$i--;
530
						$rules .= " {$qkey}, ";
531
					} else
532
						$rules .= " {$qkey} ";
533
				}
534
				$rules .= " } \n";
535
				foreach ($this->queues as $q) {
536
					$rules .= $q->build_rules();
537
				}
538
			}
539
		}
540
		$rules .= " \n";
541
		return $rules;
542
	}
543

    
544
	function build_javascript() {
545
		$javascript = "<script type=\"text/javascript\">";
546
		$javascript .= "function mySuspend() {";
547
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null);";
548
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';";
549
		$javascript .= "else if (document.all)";
550
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';";
551
		$javascript .= "}";
552

    
553
		$javascript .= "function myResume() {";
554
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)";
555
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';";
556
		$javascript .= "else if (document.all)";
557
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';";
558
		$javascript .= "}";
559
		$javascript .= "</script>";
560

    
561
		return $javascript;
562
	}
563
	
564
	function build_shortform() {
565
		global $g;
566

    
567
		$altq =& $this;
568
		if ($altq)
569
			$scheduler = ": " . $altq->GetScheduler();
570
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
571
		$form .= "<a href=\"firewall_shaper.php?interface" . $this->GetInterface() . "&queue=". $this->GetInterface()."&action=show\">".$this->GetInterface().": ".$scheduler."</a>";
572
		$form .= "</td></tr>";
573
		$form .= "<tr>";
574
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
575
		$form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale();
576
		$form .= "</td><td width=\"50%\"></td></tr>";
577
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
578
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
579
		$form .= $this->GetInterface() . "&queue=";
580
		$form .= $this->GetQname() . "&action=delete\">";
581
		$form .= "<img src=\"";
582
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
583
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Disable shaper on interface\">";
584
		$form .= "<span>Disable shaper on interface</span></a></td></tr>";
585

    
586
		return $form;
587

    
588
	}
589
	/*
590
	 * For requesting the parameters of the root queue
591
	 * to the user like the traffic wizard does.
592
	 */
593
	function build_form() { 
594
		$form = "<tr><td valign=\"top\" class=\"vncellreq\"><br><span class=\"vexpl\">Name</span></td>";
595
		$form .= "<td class=\"vncellreq\">";
596
		$form .= "<strong>".$this->GetQname()."</strong>";
597
		$form .= "</td></tr>";
598
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Scheduler Type ";
599
		$form .= "</td>";
600
		$form .= "<td class=\"vncellreq\">";
601
		$form .= "<select id=\"scheduler\" name=\"scheduler\" class=\"formselect\">";
602
		$form .= "<option value=\"HFSC\"";
603
		if ($this->GetScheduler() == "HFSC")
604
			$form .= " selected=\"yes\"";
605
		$form .= ">HFSC</option>";
606
		$form .= "<option value=\"CBQ\"";
607
		if ($this->GetScheduler() == "CBQ")
608
			$form .= " selected=\"yes\"";
609
		$form .= ">CBQ</option>";
610
		$form .= "<option value=\"FAIRQ\"";
611
                if ($this->GetScheduler() == "FAIRQ")
612
                	$form .= " selected=\"yes\"";
613
                $form .= ">FAIRQ</option>";
614
		$form .= "<option value=\"PRIQ\"";
615
		if ($this->GetScheduler() == "PRIQ")
616
			$form .= " selected=\"yes\"";
617
		$form .= ">PRIQ</option>";
618
		$form .= "</select>";
619
		$form .= "<br> <span class=\"vexpl\">";
620
		$form .= "NOTE: changing this changes all child queues!";
621
		$form .= " Beware you can lose information.";
622
		$form .= "</span>";
623
		$form .= "</td></tr>";
624
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Bandwidth";
625
		$form .= "</td><td class=\"vncellreq\">";
626
		$form .= "<input type=\"text\" id=\"bandwidth\" name=\"bandwidth\" value=\"";
627
		$form .= $this->GetBandwidth() . "\">"; 
628
		$form .= "<select id=\"bandwidthtype\" name=\"bandwidthtype\" class=\"formselect\">";
629
		$form .= "<option value=\"Kb\"";
630
		if ($this->GetBwscale() == "Kb")
631
			$form .= " selected=\"yes\"";
632
		$form .= ">Kbit/s</option>";
633
		$form .= "<option value=\"Mb\"";
634
		if ($this->GetBwscale() == "Mb")
635
			$form .= " selected=\"yes\"";
636
		$form .= ">Mbit/s</option>";
637
		$form .= "<option value=\"Gb\"";
638
		if ($this->GetBwscale() == "Gb")
639
			$form .= " selected=\"yes\"";
640
		$form .= ">Gbit/s</option>";		
641
		$form .= "<option value=\"\"";
642
		if ($this->GetBwscale() == "b")
643
			$form .= " selected=\"yes\"";
644
		$form .= ">Bit/s</option>";
645
		$form .= "</select>";
646
		$form .= "</td></tr>";
647
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Queue Limit</td>";
648
		$form .= "<td class=\"vncellreq\">";
649
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
650
		$form .= $this->GetQlimit();
651
		$form .= "\">";
652
		$form .= "</td></tr>";
653
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Tbr Size</td>";
654
		$form .= "<td class=\"vncellreq\">";
655
		$form .= "<input type=\"text\" id=\"tbrconfig\" name=\"tbrconfig\" value=\"";
656
		$form .= $this->GetTbrConfig();
657
		$form .= "\">";
658
		$form .= "<br> <span class=\"vexpl\">";
659
		$form .= "Adjusts the size, in bytes, of the token bucket regulator.";
660
		$form .= "If not specified, heuristics based on the interface ";
661
		$form .= "bandwidth are used to determine the size.";
662
		$form .= "</span></td></tr>";
663
		$form .= "<input type=\"hidden\" id=\"interface\" name=\"interface\"";
664
		$form .= " value=\"" . $this->GetInterface() . "\">";
665
		$form .= "<input type=\"hidden\" id=\"name\" name=\"name\" value=\"".$this->GetQname()."\" >";
666

    
667

    
668
		return $form;
669
	}
670

    
671
	function update_altq_queue_data(&$data) { 
672
		$this->ReadConfig($data);
673
	}
674
	
675
	/*
676
	 * Should call on each of it queues and subqueues
677
	 * the same function much like build_rules();
678
	 */
679
	function wconfig() { 
680
		$cflink = &get_reference_to_me_in_config($this->GetLink());
681
		if (!is_array($cflink))
682
			$cflink = array();
683
		$cflink['interface'] = $this->GetInterface();	
684
		$cflink['name'] = $this->GetQname();
685
		$cflink['scheduler'] = $this->GetScheduler();
686
		$cflink['bandwidth'] = $this->GetBandwidth();
687
		$cflink['bandwidthtype'] = $this->GetBwscale();
688
		$cflink['qlimit'] = trim($this->GetQlimit());
689
		if (empty($cflink['qlimit']))
690
			unset($cflink['qlimit']);
691
		$cflink['tbrconfig'] = trim($this->GetTbrConfig());
692
		if (empty($cflink['tbrconfig']))
693
			unset($cflink['tbrconfig']);
694
		$cflink['enabled'] = $this->GetEnabled();
695
		if (empty($cflink['enabled']))
696
			unset($cflink['enabled']);
697
	}
698

    
699
}
700

    
701
class priq_queue {
702
	var $qname;
703
	var $qinterface; 
704
	var $qlimit;
705
	var $qpriority;
706
	var $description;
707
	var $isparent;
708
	var $qbandwidth;
709
	var $qbandwidthtype;
710
	var $qdefault = "";
711
	var $qrio = "";
712
	var $qred = "";
713
	var $qecn = "";
714
	var $qack;
715
	var $qenabled = "";
716
	var $qparent;
717
	var $link;
718
	var $available_bw; /* in b/s */
719

    
720
	/* This is here to help with form building and building rules/lists */
721
		var $subqueues = array();
722

    
723
	/* Accesor functions */
724
	function GetAvailableBandwidth() {
725
		return $this->available_bw;
726
	}
727
	function SetAvailableBandwidth($bw) {
728
		$this->available_bw = $bw;
729
	}
730
	function SetLink($link) {
731
		$this->link = $link;
732
	}
733
	function GetLink() {
734
		return $this->link;
735
	}
736
	function &GetParent() {
737
		return $this->qparent;
738
	}
739
	function SetParent(&$parent) {
740
		$this->qparent = &$parent;
741
	}
742
	function GetEnabled() {
743
		return $this->qenabled;
744
	}
745
	function SetEnabled($value) {
746
		$this->qenabled = $value;
747
	}
748
	function CanHaveChildren() {
749
		return false;
750
	}
751
	function CanBeDeleted() {
752
		return true;
753
	}
754
	function GetQname() {
755
		return $this->qname;
756
	}
757
	function SetQname($name) {
758
		$this->qname = trim($name);
759
	}
760
	function GetBandwidth() {
761
		return $this->qbandwidth;
762
	}
763
	function SetBandwidth($bandwidth) {
764
		$this->qbandwidth = $bandwidth;
765
	}
766
	function GetInterface() {
767
		return $this->qinterface;
768
	}
769
	function SetInterface($name) {
770
		$this->qinterface = trim($name);
771
	}
772
	function GetQlimit() {
773
		return $this->qlimit;
774
	}
775
	function SetQlimit($limit) {
776
		$this->qlimit = $limit;
777
	}
778
	function GetQpriority() {
779
		return $this->qpriority;
780
	}
781
	function SetQpriority($priority) {
782
		$this->qpriority = $priority;
783
	}
784
	function GetDescription() {
785
		return $this->description;
786
	}
787
	function SetDescription($str) {
788
		$this->description = trim($str);
789
	}
790
	function GetFirstime() {
791
		return $this->firsttime;
792
	}
793
	function SetFirsttime($number) {
794
		$this->firsttime = $number;
795
	}
796
	function GetBwscale() {
797
		return $this->qbandwidthtype;
798
	}
799
	function SetBwscale($scale) {
800
		$this->qbandwidthtype = $scale;
801
	}
802
	function GetDefault() {
803
		return $this->qdefault;
804
	}
805
	function SetDefault($value = false) {
806
		$this->qdefault = $value;
807
		altq_set_default_queue($this->GetInterface(), "true");
808
	}
809
	function GetRed() {
810
		return $this->qred;
811
	}
812
	function SetRed($red = false) {
813
		$this->qred = $red;
814
	}
815
	function GetRio() {
816
		return $this->qrio;
817
	}
818
	function SetRio($rio = false) {
819
		$this->qrio = $rio;
820
	}
821
	function GetEcn() {
822
		return $this->qecn;
823
	}
824
	function SetEcn($ecn = false) {
825
		$this->qecn = $ecn;
826
	}
827
	function GetAck() {
828
		return $this->qack;
829
	}
830
	function SetAck($ack = false) {
831
		$this->qack = $ack;
832
	}
833

    
834
	function build_javascript() {
835
		$javascript = "<script type=\"text/javascript\">";
836
		$javascript .= "function mySuspend() { \n";
837
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null);\n";
838
		$javascript .= "document.layers['shaperarea'].visibility = 'hidden';\n";
839
		$javascript .= "else if (document.all)\n";
840
		$javascript .= "document.all['shaperarea'].style.visibility = 'hidden';\n";
841
		$javascript .= "}\n";
842

    
843
		$javascript .= "function myResume() {\n";
844
		$javascript .= "if (document.layers && document.layers['shaperarea'] != null)\n";
845
		$javascript .= "document.layers['shaperarea'].visibility = 'visible';\n";
846
		$javascript .= "else if (document.all)\n";
847
		$javascript .= "document.all['shaperarea'].style.visibility = 'visible';\n";
848
		$javascript .= "}\n";
849
		$javascript .= "</script>";
850
		
851
		return $javascript;
852
	}
853
	
854
	function &add_queue($interface, &$qname, &$path, &$input_errors) { return; }
855

    
856
	/* 
857
	 * Currently this will not be called unless we decide to clone a whole 
858
	 * queue tree on the 'By Queues' view or support drag&drop on the tree/list
859
	 */
860
	 function copy_queue($interface, &$cflink) {
861

    
862
 		$cflink['name'] = $this->GetQname();
863
                $cflink['interface'] = $interface;
864
                $cflink['qlimit'] = $this->GetQlimit();
865
                $cflink['priority'] = $this->GetQpriority();
866
                $cflink['description'] = $this->GetDescription();
867
                $cflink['enabled'] = $this->GetEnabled();
868
                $cflink['default'] = $this->GetDefault();
869
                $cflink['red'] = $this->GetRed();
870
                $cflink['rio'] = $this->GetRio();
871
                $cflink['ecn'] = $this->GetEcn();
872

    
873
                if (is_array($this->subqueues)) {
874
                        $cflinkp['queue'] = array();
875
                        foreach ($this->subqueues as $q) {
876
				 $cflink['queue'][$q->GetQname()] = array();
877
                                $q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
878
			}
879
                }
880

    
881
	 }
882

    
883
	function clean_queue($sched) {
884
		clean_child_queues($sched, $this->GetLink());
885
		if (is_array($this->subqueues)) {
886
			foreach ($this->subqueues as $q)
887
				$q->clean_queue($sched);
888
		}
889
	}
890

    
891
        function &get_queue_list(&$qlist) {
892
		$qlist[$this->GetQname()] = & $this;
893
		if (is_array($this->subqueues)) {
894
			foreach ($this->subqueues as $queue)
895
				$queue->get_queue_list($qlist);
896
		}
897
	}
898

    
899
	function delete_queue() {
900
		unref_on_altq_queue_list($this->GetQname());
901
		if ($this->GetDefault())
902
				altq_set_default_queue($this->GetInterface(), "false");
903
		cleanup_queue_from_rules($this->GetQname());
904
		unset_object_by_reference($this->GetLink());
905
	}
906
	
907
	function delete_all() {
908
                if (count($this->subqueues)) {
909
                        foreach ($this->subqueues as $q) {
910
                                $q->delete_all();
911
                                unset_object_by_reference($q->GetLink());
912
                                unset($q);
913
                        }
914
                        unset($this->subqueues);
915
                }
916
        }
917

    
918
	 function &find_queue($interface, $qname) { 
919
		if ($qname == $this->GetQname())
920
			return $this; 
921
	}
922
	
923
	function find_parentqueue($interface, $qname) { return; }
924
		
925
	function validate_input($data, &$input_errors) {
926
	
927
		$reqdfields[] = "name";
928
		$reqdfieldsn[] = "Name";
929
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
930

    
931
		if ($data['priority'] && (!is_numeric($data['priority'])
932
						|| ($data['priority'] < 1) || ($data['priority'] > 15))) {
933
					$input_errors[] = "The priority must be an integer between 1 and 15.";
934
		}
935
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) 
936
				$input_errors[] = "Queue limit must be an integer";
937
		if ($data['qlimit'] < 0)
938
				$input_errors[] = "Queue limit must be positive";
939
		if (!preg_match("/^[a-zA-Z0-9_-]*$/", $data['name']))
940
			 $input_errors[] = "Queue names must be alphanumeric and _ or - only.";
941
		
942
	}
943

    
944
	function ReadConfig(&$q) {
945
		if (isset($q['name']))
946
				$this->SetQname($q['name']);
947
		if (isset($q['interface']))
948
				$this->SetInterface($q['interface']);
949
		if ($q['bandwidth'] <> "") {
950
			$this->SetBandwidth($q['bandwidth']);
951
			if ($q['bandwidthtype'] <> "")
952
				$this->SetBwscale($q['bandwidthtype']);
953
		}
954
		if (!empty($q['qlimit']))
955
			$this->SetQlimit($q['qlimit']);
956
		if (!empty($q['priority']))
957
			$this->SetQPriority($q['priority']);
958
		if (!empty($q['description']))
959
			$this->SetDescription($q['description']);
960
		if (!empty($q['red']))
961
			$this->SetRed($q['red']);
962
		if (!empty($q['rio']))
963
			$this->SetRio($q['rio']);
964
		if (!empty($q['ecn']))
965
			$this->SetEcn($q['ecn']);
966
		if (!empty($q['default']))
967
			$this->SetDefault($q['default']);
968
		if (!empty($q['enabled']))
969
			$this->SetEnabled($q['enabled']);
970

    
971
	}
972

    
973
	function build_tree() {
974
		$tree = " <li><a href=\"firewall_shaper.php?interface=". $this->GetInterface()."&queue=". $this->GetQname()."&action=show"; 
975
		$tree .= "\" ";
976
		$tmpvalue = $this->GetDefault();
977
		if (!empty($tmpvalue))
978
			$tree .= " class=\"navlnk\"";
979
		$tree .= " >" . $this->GetQname() . "</a>";
980
		/* 
981
		 * Not needed here!
982
		 * if (is_array($queues) {
983
		 *	  $tree .= "<ul>";
984
		 *	  foreach ($q as $queues) 
985
		 *		  $tree .= $queues['$q->GetName()']->build_tree();
986
		 *	  endforeach	
987
		 *	  $tree .= "</ul>";
988
		 * }
989
		 */
990

    
991
		$tree .= "</li>"; 
992

    
993
		return $tree;
994
	}
995
		
996
	/* Should return something like:
997
	 * queue $qname on $qinterface bandwidth ....
998
	 */
999
	function build_rules() {
1000
		$pfq_rule = " queue ". $this->qname;
1001
		if ($this->GetInterface())
1002
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1003
		$tmpvalue = $this->GetQpriority();
1004
		if (!empty($tmpvalue))
1005
			$pfq_rule .= " priority ".$this->GetQpriority();
1006
		$tmpvalue = $this->GetQlimit();
1007
		if (!empty($tmpvalue))
1008
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1009
		if ($this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetDefault()) {
1010
			$pfq_rule .= " priq ( ";
1011
			$tmpvalue = $this->GetRed();
1012
			if (!empty($tmpvalue)) {
1013
				$comma = 1;
1014
				$pfq_rule .= " red ";
1015
			}
1016
			$tmpvalue = $this->GetRio();
1017
			if (!empty($tmpvalue)) {
1018
				if ($comma) 
1019
					$pfq_rule .= " ,";
1020
				$comma = 1;
1021
				$pfq_rule .= " rio ";
1022
			}
1023
			$tmpvalue = $this->GetEcn();
1024
			if (!empty($tmpvalue)) {
1025
				if ($comma) 
1026
					$pfq_rule .= " ,";
1027
				$comma = 1;
1028
				$pfq_rule .= " ecn ";
1029
			}
1030
			$tmpvalue = $this->GetDefault();
1031
			if (!empty($tmpvalue)) {
1032
				if ($comma)
1033
					$pfq_rule .= " ,";
1034
				$pfq_rule .= " default ";
1035
			}
1036
			$pfq_rule .= " ) ";
1037
		}
1038

    
1039
		$pfq_rule .= " \n";
1040

    
1041
		return $pfq_rule;
1042
	}
1043

    
1044
	/*
1045
	 * To return the html form to show to user
1046
	 * for getting the parameters.
1047
	 * Should do even for first time when the
1048
	 * object is created and later when we may
1049
	 * need to update it.
1050
	 */
1051
	function build_form() {
1052
		$form .= "<tr>";
1053
		$form .= "<td width=\"22%\" valign=\"top\" class=\"vncellreq\">";
1054
		$form .= "Queue Name</td><td width=\"78%\" class=\"vtable\">";
1055
		$form .= "<input name=\"name\" type=\"text\" id=\"name\" class=\"formfld unknown\" size=\"15\" maxlength=\"15\" value=\"";
1056
		$form .= htmlspecialchars($this->GetQname());
1057
		$form .= "\">";
1058
		$form .= "<br> <span class=\"vexpl\">Enter the name of the queue here.  Do not use spaces and limit the size to 15 characters.";
1059
		$form .= "</span></td>";
1060
		$form .= "</tr><tr>";
1061
		$form .= "<td width=\"22%\" valign=\"top\" class=\"vncellreq\">Priority</td>";
1062
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"priority\" type=\"text\" id=\"priority\" size=\"5\" value=\"";
1063
		$form .= htmlspecialchars($this->GetQpriority());
1064
		$form .= "\">";
1065
		$form .= "<br> <span class=\"vexpl\">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>";
1066
		$form .= "</tr>";
1067
		$form .= "</tr>";
1068
		$form .= "<td width=\"22%\" valign=\"top\" class=\"vncellreq\">Queue limit</td>";
1069
		$form .= "<td width=\"78%\" class=\"vtable\"> <input name=\"qlimit\" type=\"text\" id=\"qlimit\" size=\"5\" value=\"";
1070
		$form .= htmlspecialchars($this->GetQlimit());
1071
		$form .= "\">";
1072
		$form .= "<br> <span class=\"vexpl\">Queue limit in packets per second."; 
1073
		$form .= "</span></td>";
1074
		$form .= "<tr>";
1075
		$form .= "<td width=\"22%\" valign=\"top\" class=\"vncell\">Scheduler options</td>";
1076
		$form .= "<td width=\"78%\" class=\"vtable\">";
1077
		$tmpvalue = $this->GetDefault();	
1078
		if (!empty($tmpvalue)) { 
1079
			$form .= "<input type=\"checkbox\" id=\"default\" CHECKED name=\"default\" value=\"default\"";
1080
			$form .= "> Default queue<br>";
1081
		} else {
1082
			$form .= "<input type=\"checkbox\" id=\"default\" name=\"default\" value=\"default\"";
1083
			$form .= "> Default queue<br>";
1084
		}
1085
		$form .= "<input type=\"checkbox\" id=\"red\" name=\"red\" value=\"red\" ";
1086
		$tmpvalue = $this->GetRed();
1087
		if(!empty($tmpvalue)) 
1088
			$form .=  " CHECKED";
1089
		$form .= "> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#red\">Random Early Detection</a><br>";
1090
		$form .= "<input type=\"checkbox\" id=\"rio\" name=\"rio\" value=\"rio\"";
1091
		$tmpvalue = $this->GetRio();
1092
		if(!empty($tmpvalue)) 
1093
			$form .=  " CHECKED";
1094
		$form .= "> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#rio\">Random Early Detection In and Out</a><br>";
1095
		$form .= "<input type=\"checkbox\" id=\"ecn\" name=\"ecn\" value=\"ecn\"";
1096
		$tmpvalue = $this->GetEcn();
1097
		if(!empty($tmpvalue)) 
1098
			$form .=  " CHECKED";
1099
		$form .= "> <a target=\"_new\" href=\"http://www.openbsd.org/faq/pf/queueing.html#ecn\">Explicit Congestion Notification</a><br>";
1100
		$form .= "<span class=\"vexpl\"><br>Select options for this queue";
1101
		$form .= "</tr><tr>";
1102
		$form .= "<td width=\"22%\" class=\"vncellreq\">Description</td>";
1103
		$form .= "<td width=\"78%\" class=\"vtable\">";
1104
		$form .= "<input type=\"text\" name=\"description\" size=\"50%\" class=\"formfld unknown\" value=\"" . $this->GetDescription() . "\"  >";
1105
		$form .= "</td></tr>";
1106
		$form .= "<input type=\"hidden\" name=\"interface\" id=\"interface\"";
1107
		$form .= " value=\"".$this->GetInterface()."\">";
1108

    
1109
		return $form;
1110
	}
1111

    
1112
	function build_shortform() {
1113
		/* XXX: Hacks in site. Mostly layer violations!  */
1114
		global $g, $altq_list_queues;
1115

    
1116
		$altq =& $altq_list_queues[$this->GetInterface()];
1117
		if ($altq)
1118
			$scheduler = ": " . $altq->GetScheduler();
1119
		$form = "<tr><td width=\"20%\" class=\"vtable\">";
1120
		$form .= "<a href=\"firewall_shaper.php?interface" . $this->GetInterface() . "&queue=" . $this->GetInterface()."&action=show\">".$this->GetInterface().": ".$scheduler."</a>";
1121
		$form .= "</td></tr>";
1122
		/* 
1123
		 * XXX: Hack in sight maybe fix with a class that wraps all
1124
		 * of this layer violations
1125
		 */
1126
		$form .= "<tr>";
1127
		$form .= "<td width=\"50%\" class=\"vncellreq\">";
1128
		$form .= "Bandwidth: " . $this->GetBandwidth().$this->GetBwscale();
1129
		$form .= "</td><td width=\"50%\"></td></tr>";
1130
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
1131
		$tmpvalue = $this->GetQpriority();
1132
		if (!empty($tmpvalue))
1133
			$form .= "Priority: on </td></tr>";
1134
		$tmpvalue = $this->GetDefault();
1135
		if (!empty($tmpvalue))
1136
			$form .= "<tr><td class=\"vncellreq\">Default: on </td></tr>";
1137
		$form .= "<tr><td width=\"20%\" class=\"vncellreq\">";
1138
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
1139
		$form .= $this->GetInterface() . "&queue=";
1140
		$form .= $this->GetQname() . "&action=delete\">";
1141
		$form .= "<img src=\"";
1142
		$form .= "./themes/".$g['theme']."/images/icons/icon_x.gif\"";
1143
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Delete queue from interface\">";
1144
		$form .= "<span>Delete queue from interface</span></a></td></tr>";
1145
		
1146
		return $form;
1147

    
1148
	}
1149

    
1150
		function update_altq_queue_data(&$q) { 
1151
		$this->ReadConfig($q);
1152
	}
1153

    
1154
	function wconfig() {
1155
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1156
		if (!is_array($cflink))
1157
			$cflink = array();
1158
		$cflink['name'] = $this->GetQname();
1159
		$cflink['interface'] = $this->GetInterface();
1160
		$cflink['qlimit'] = trim($this->GetQlimit());
1161
		if (empty($cflink['qlimit']))
1162
			unset($cflink['qlimit']);
1163
		$cflink['priority'] = trim($this->GetQpriority());
1164
		if (empty($cflink['priority']))
1165
			unset($cflink['priority']);
1166
		$cflink['description'] = trim($this->GetDescription());
1167
		if (empty($cflink['description']))
1168
			unset($cflink['description']);
1169
		$cflink['enabled'] = trim($this->GetEnabled());
1170
		if (empty($cflink['enabled']))
1171
			unset($cflink['enabled']);
1172
		$cflink['default'] = trim($this->GetDefault());
1173
		if (empty($cflink['default']))
1174
			unset($cflink['default']);
1175
		$cflink['red'] = trim($this->GetRed());
1176
		if (empty($cflink['red']))
1177
			unset($cflink['red']);
1178
		$cflink['rio'] = trim($this->GetRio());
1179
		if (empty($cflink['rio']))
1180
			unset($cflink['rio']);
1181
		$cflink['ecn'] = trim($this->GetEcn());
1182
		if (empty($cflink['ecn']))
1183
			unset($cflink['ecn']);
1184
	}
1185
}
1186

    
1187
class hfsc_queue extends priq_queue {
1188
	/* realtime */
1189
	var $realtime;
1190
	var $r_m1;
1191
	var $r_d;
1192
	var $r_m2;
1193
	/* linkshare */
1194
	var $linkshare;
1195
	var $l_m1;
1196
	var $l_d;
1197
	var $l_m2;
1198
	/* upperlimit */
1199
	var $upperlimit;
1200
	var $u_m1;
1201
	var $u_d;
1202
	var $u_m2;
1203

    
1204
	/*
1205
	 * HFSC can have nested queues.
1206
	 */
1207

    
1208
	function CanHaveChildren() {
1209
		return true;
1210
	}
1211
	function GetRealtime() {
1212
           return $this->realtime;
1213
	}
1214
	function GetR_m1() {
1215
		return $this->r_m1;
1216
	}
1217
	function GetR_d() {
1218
		return $this->r_d;
1219
	}
1220
	function GetR_m2() {
1221
		return $this->r_m2;
1222
	}
1223
	function SetRealtime() {
1224
		$this->realtime = "on";
1225
	}
1226
	function DisableRealtime() {
1227
		$this->realtime = "";
1228
	}
1229
	function SetR_m1($value) {
1230
		$this->r_m1 = $value;
1231
	}
1232
	function SetR_d($value) {
1233
		$this->r_d = $value;
1234
	}
1235
	function SetR_m2($value) {
1236
		$this->r_m2 = $value;
1237
	}
1238
	function GetLinkshare() {
1239
		return $this->linkshare;
1240
	}
1241
	function DisableLinkshare() {
1242
		$this->linkshare = "";
1243
	}
1244
	function GetL_m1() {
1245
		return $this->l_m1;
1246
	}
1247
	function GetL_d() {
1248
		return $this->l_d;
1249
	}
1250
	function GetL_m2() {
1251
		return $this->l_m2;
1252
	}
1253
	function SetLinkshare() {
1254
		$this->linkshare = "on";
1255
	}
1256
	function SetL_m1($value) {
1257
		$this->l_m1 = $value;
1258
	}
1259
	function SetL_d($value) {
1260
		$this->l_d = $value;
1261
	}
1262
	function SetL_m2($value) {
1263
		$this->l_m2 = $value;
1264
	}
1265
	function GetUpperlimit() {
1266
		return $this->upperlimit;
1267
	}
1268
	function GetU_m1() {
1269
		return $this->u_m1;
1270
	}
1271
	function GetU_d() {
1272
		return $this->u_d;
1273
	}
1274
	function GetU_m2() {
1275
		return $this->u_m2;
1276
	}
1277
	function SetUpperlimit() {
1278
		$this->upperlimit = "on";
1279
	}
1280
	function DisableUpperlimit() {
1281
		$this->upperlimit = "";
1282
	}
1283
	function SetU_m1($value) {
1284
		$this->u_m1 = $value;
1285
	}
1286
	function SetU_d($value) {
1287
		$this->u_d = $value;
1288
	}
1289
	function SetU_m2($value) {
1290
		$this->u_m2 = $value;
1291
	}
1292

    
1293
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1294

    
1295
		if (!is_array($this->subqueues))
1296
			$this->subqueues = array();
1297
		$q =& new hfsc_queue();
1298
		$q->SetInterface($this->GetInterface());
1299
		$q->SetParent(&$this);
1300
		$q->ReadConfig($qname);
1301
		$q->validate_input($qname, $input_errors);
1302
		if (count($input_errors)) {
1303
			return $q;
1304
		}
1305

    
1306
		$q->SetEnabled("on");
1307
		$q->SetLink($path);
1308
		switch ($q->GetBwscale()) {
1309
		case "%":
1310
			$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
1311
			break;
1312
		default:
1313
			$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
1314
			break;
1315
		}
1316
		$q->SetAvailableBandwidth($myBw);
1317
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
1318

    
1319
		$this->subqueues[$q->GetQname()] =& $q; //new hfsc_queue()
1320
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
1321
		if (is_array($qname['queue'])) {
1322
			foreach ($qname['queue'] as $key1 => $que) {
1323
				array_push($path, $key1);
1324
				$q->add_queue($q->GetInterface(), &$que, &$path, $input_errors);
1325
				array_pop($path);
1326
			}
1327
		}
1328
	
1329
		return $q;
1330
	}
1331

    
1332
        function copy_queue($interface, &$cflink) {
1333

    
1334
		$cflink['name'] = $this->GetQname();
1335
		$cflink['interface'] = $interface;
1336
		$cflink['qlimit'] = trim($this->GetQlimit());
1337
		if (empty($cflink['qlimit']))
1338
			unset($cflink['qlimit']);
1339
		$cflink['priority'] = trim($this->GetQpriority());
1340
		if (empty($cflink['priority']))
1341
			unset($cflink['priority']);
1342
		$cflink['description'] = trim($this->GetDescription());
1343
		if (empty($cflink['description']))
1344
			unset($cflink['description']);
1345
		$cflink['bandwidth'] = $this->GetBandwidth();
1346
		$cflink['bandwidthtype'] = $this->GetBwscale();
1347
		$cflink['enabled'] = trim($this->GetEnabled());
1348
		if (empty($cflink['enabled']))
1349
			unset($cflink['enabled']);
1350
		$cflink['default'] = trim($this->GetDefault());
1351
		if (empty($cflink['default']))
1352
			unset($cflink['default']);
1353
		$cflink['red'] = trim($this->GetRed());
1354
		if (empty($cflink['red']))
1355
			unset($cflink['red']);
1356
		$cflink['rio'] = trim($this->GetRio());
1357
		if (empty($cflink['rio']))
1358
			unset($cflink['rio']);
1359
		$cflink['ecn'] = trim($this->GetEcn());
1360
		if (empty($cflink['ecn']))
1361
			unset($cflink['ecn']);
1362
		if ($this->GetLinkshare() <> "") {
1363
			if ($this->GetL_m1() <> "") {
1364
				$cflink['linkshare1'] = $this->GetL_m1();
1365
				$cflink['linkshare2'] = $this->GetL_d();
1366
				$cflink['linkshare'] = "on";
1367
			} else {
1368
				unset($cflink['linkshare1']);
1369
				unset($cflink['linkshare2']);
1370
				unset($cflink['linkshare']);
1371
			}
1372
			if ($this->GetL_m2() <> "") {
1373
				$cflink['linkshare3'] = $this->GetL_m2();
1374
				$cflink['linkshare'] = "on";
1375
			} else {
1376
				unset($cflink['linkshare3']);
1377
				unset($cflink['linkshare']);
1378
			}
1379
		}
1380
		if ($this->GetRealtime() <> "") {
1381
			if ($this->GetR_m1() <> "") {
1382
				$cflink['realtime1'] = $this->GetR_m1();
1383
				$cflink['realtime2'] = $this->GetR_d();
1384
				$cflink['realtime'] = "on";
1385
			} else {
1386
				unset($cflink['realtime1']);
1387
                                unset($cflink['realtime2']);
1388
                                unset($cflink['realtime']);
1389
			}
1390
			if ($this->GetR_m2() <> "") {
1391
				$cflink['realtime3'] = $this->GetR_m2();
1392
				$cflink['realtime'] = "on";
1393
			} else {
1394
				unset($cflink['realtime3']);
1395
				unset($cflink['realtime']);
1396
			}
1397
		}
1398
		if ($this->GetUpperlimit() <> "") {
1399
			if ($this->GetU_m1() <> "") {
1400
				$cflink['upperlimit1'] = $this->GetU_m1();
1401
				$cflink['upperlimit2'] = $this->GetU_d();
1402
				$cflink['upperlimit'] = "on";
1403
			} else {
1404
				unset($cflink['upperlimit']);
1405
				unset($cflink['upperlimit1']);
1406
				unset($cflink['upperlimit2']);
1407
			}
1408
			if ($this->GetU_m2() <> "") {
1409
				$cflink['upperlimit3'] = $this->GetU_m2();
1410
				$cflink['upperlimit'] = "on";
1411
			} else {
1412
				unset($cflink['upperlimit3']);
1413
				unset($cflink['upperlimit']);
1414
			}
1415
		}
1416

    
1417
		if (is_array($this->subqueues)) {
1418
			$cflinkp['queue'] = array();
1419
			foreach ($this->subqueues as $q) {
1420
				$cflink['queue'][$q->GetQname()] = array();
1421
				$q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
1422
			}
1423
		}
1424
	}
1425

    
1426
	function delete_queue() { 
1427
		unref_on_altq_queue_list($this->GetQname());
1428
		$tmpvalue = $this->GetDefault();
1429
		if (!empty($tmpvalue)) 
1430
			altq_set_default_queue($this->GetInterface(), "false");
1431
		cleanup_queue_from_rules($this->GetQname());
1432
		$parent =& $this->GetParent();
1433
		foreach ($this->subqueues as $q)  {
1434
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
1435
			$q->delete_queue();
1436
		}
1437
		unset_object_by_reference($this->GetLink());
1438
	}
1439

    
1440
	/*
1441
	 * Should search even its children
1442
	 */
1443
	function &find_queue($interface, $qname) {
1444
		if ($qname == $this->GetQname()) 
1445
			return $this;
1446

    
1447
		foreach ($this->subqueues as $q) {
1448
			$result =& $q->find_queue("", $qname);
1449
			if ($result)
1450
				return $result;
1451
		}
1452
	}
1453

    
1454
	function &find_parentqueue($interface, $qname) {
1455
		if ($this->subqueues[$qname]) 
1456
			return $this;
1457
		foreach ($this->subqueues as $q) {
1458
			$result = $q->find_parentqueue("", $qname);
1459
			if ($result)
1460
				return $result;
1461
		}
1462
	}
1463
	
1464
	function validate_input($data, &$input_errors) {
1465
		parent::validate_input($data, $input_errors);
1466
		
1467
		$reqdfields[] = "bandwidth";
1468
		$reqdfieldsn[] = "Bandwidth";
1469
		$reqdfields[] = "bandwidthtype";
1470
		$reqdfieldsn[] = "Bandwidthtype";
1471

    
1472
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
1473
		
1474
		if (isset($data['linkshare3']) && $data['linkshare3'] <> "") {
1475
			if ($data['bandwidth'] && (!is_numeric($data['bandwidth'])))
1476
                        	$input_errors[] = "Bandwidth must be an integer.";
1477

    
1478
                	if ($data['bandwidth'] < 0)
1479
                        	$input_errors[] = "Bandwidth cannot be negative.";
1480

    
1481
			if ($data['bandwidthtype'] == "%") {
1482
				if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
1483
					$input_errors[] = "Bandwidth in percentage should be between 1 and 100 bounds.";
1484
			}
1485
		/*
1486
			$parent =& $this->GetParent();
1487
			switch ($data['bandwidthtype']) {
1488
			case "%":
1489
				$myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
1490
			default:
1491
				$mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
1492
				break;
1493
			}
1494
			if ($parent->GetAvailableBandwidth() < $myBw)
1495
				$input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
1496
		*/
1497
		}
1498

    
1499
		if ($data['upperlimit1'] <> "" &&  $data['upperlimit2'] == "")
1500
			$input_errors[] = ("upperlimit service curve defined but missing (d) value");
1501
		if ($data['upperlimit2'] <> "" &&  $data['upperlimit1'] == "")
1502
			$input_errors[] = ("upperlimit service curve defined but missing initial bandwidth (m1) value");
1503
		if ($data['upperlimit1'] <> "" && !is_valid_shaperbw($data['upperlimit1']))
1504
			$input_errors[] = ("upperlimit m1 value needs to be Kb, Mb, Gb, or %");
1505
		if ($data['upperlimit2'] <> "" && !is_numeric($data['upperlimit2']))
1506
			$input_errors[] = ("upperlimit d value needs to be numeric");
1507
		if ($data['upperlimit3'] <> "" && !is_valid_shaperbw($data['upperlimit3']))
1508
			$input_errors[] = ("upperlimit m2 value needs to be Kb, Mb, Gb, or %");
1509

    
1510
		/*
1511
		if (isset($data['upperlimit']) && $data['upperlimit3'] <> "" && $data['upperlimit1'] <> "") {
1512
			$bw_1 = get_hfsc_bandwidth($this, $data['upperlimit1']);
1513
			$bw_2 = get_hfsc_bandwidth($this, $data['upperlimit3']);
1514
			if (floatval($bw_1) < floatval($bw_2)) 
1515
				$input_errors[] = ("upperlimit m1 cannot be smaller than m2");
1516

    
1517
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1518
				$input_errors[] = ("upperlimit specification excedd 80% of allowable allocation.");
1519
		}
1520
		*/
1521
		if ($data['linkshare1'] <> "" &&  $data['linkshare2'] == "")
1522
			$input_errors[] = ("linkshare service curve defined but missing (d) value");
1523
		if ($data['linkshare2'] <> "" &&  $data['linkshare1'] == "")
1524
			$input_errors[] = ("linkshare service curve defined but missing initial bandwidth (m1) value");
1525
		if ($data['linkshare1'] <> "" && !is_valid_shaperbw($data['linkshare1']))
1526
			$input_errors[] = ("linkshare m1 value needs to be Kb, Mb, Gb, or %");
1527
		if ($data['linkshare2'] <> "" && !is_numeric($data['linkshare2']))
1528
			$input_errors[] = ("linkshare d value needs to be numeric");
1529
		if ($data['linkshare3'] <> "" && !is_valid_shaperbw($data['linkshare3']))
1530
			$input_errors[] = ("linkshare m2 value needs to be Kb, Mb, Gb, or %");
1531
		if ($data['realtime1'] <> "" &&  $data['realtime2'] == "")
1532
			$input_errors[] = ("realtime service curve defined but missing (d) value");
1533
		if ($data['realtime2'] <> "" &&  $data['realtime1'] == "")
1534
			$input_errors[] = ("realtime service curve defined but missing initial bandwidth (m1) value");
1535

    
1536
		/*
1537
		if (isset($data['linkshare']) && $data['linkshare3'] <> "" && $data['linkshare1'] <> "" && 0) {
1538
			$bw_1 = get_hfsc_bandwidth($this, $data['linkshare1']);
1539
                	$bw_2 = get_hfsc_bandwidth($this, $data['linkshare3']);
1540
                	if (floatval($bw_1) < floatval($bw_2))
1541
                        	$input_errors[] = ("linkshare m1 cannot be smaller than m2");
1542

    
1543
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1544
                        	$input_errors[] = ("linkshare specification excedd 80% of allowable allocation.");
1545
		}
1546
		*/
1547

    
1548
		if ($data['realtime1'] <> "" && !is_valid_shaperbw($data['realtime1']))
1549
			$input_errors[] = ("realtime m1 value needs to be Kb, Mb, Gb, or %");
1550
		if ($data['realtime2'] <> "" && !is_numeric($data['realtime2']))
1551
			$input_errors[] = ("realtime d value needs to be numeric");
1552
		if ($data['realtime3'] <> "" && !is_valid_shaperbw($data['realtime3']))
1553
			$input_errors[] = ("realtime m2 value needs to be Kb, Mb, Gb, or %");
1554

    
1555
		/*
1556
		if (isset($data['realtime']) && $data['realtime3'] <> "" && $data['realtime1'] <> "" && 0) {
1557
			$bw_1 = get_hfsc_bandwidth($this, $data['realtime1']);
1558
                	$bw_2 = get_hfsc_bandwidth($this, $data['realtime3']);
1559
                	if (floatval($bw_1) < floatval($bw_2))
1560
                        	$input_errors[] = ("realtime m1 cannot be smaller than m2");
1561

    
1562
			if (get_interface_bandwidth($this) < (0.8 * (floatval($bw_1) + floatval($bw_2))))
1563
				$input_errors[] = ("realtime specification excedd 80% of allowable allocation.");
1564
		}
1565
		*/
1566

    
1567
	}
1568

    
1569
	function ReadConfig(&$cflink) {
1570
		if (!empty($cflink['linkshare'])) {
1571
			if (!empty($cflink['linkshare1'])) {
1572
				$this->SetL_m1($cflink['linkshare1']);
1573
                                $this->SetL_d($cflink['linkshare2']);
1574
				$this->SetLinkshare();
1575
			}
1576
			if (!empty($cflink['linkshare3'])) {
1577
                                $this->SetL_m2($cflink['linkshare3']);
1578
				$this->SetLinkshare();
1579
			}
1580
		} else
1581
			$this->DisableLinkshare();
1582
		if (!empty($cflink['realtime'])) {
1583
                        if (!empty($cflink['realtime1'])) {
1584
                                $this->SetR_m1($cflink['realtime1']);
1585
                                $this->SetR_d($cflink['realtime2']);
1586
				$this->SetRealtime();
1587
			}
1588
                        if (!empty($cflink['realtime3'])) {
1589
                                $this->SetR_m2($cflink['realtime3']);
1590
				$this->SetRealtime();
1591
			}
1592
		} else
1593
			$this->DisableRealtime(); 
1594
		if (!empty($cflink['upperlimit'])) {
1595
                        if (!empty($cflink['upperlimit1'])) {
1596
                                $this->SetU_m1($cflink['upperlimit1']);
1597
                                $this->SetU_d($cflink['upperlimit2']);
1598
				$this->SetUpperlimit();
1599
			}
1600
                        if (!empty($cflink['upperlimit3'])) {
1601
                                $this->SetU_m2($cflink['upperlimit3']);
1602
				$this->SetUpperlimit();
1603
			}
1604
		} else
1605
			$this->DisableUpperlimit();
1606
		parent::ReadConfig($cflink);
1607
	}
1608

    
1609
	function build_tree() {
1610
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface() ."&queue=" . $this->GetQname()."&action=show"; 
1611
		$tree .= "\" ";
1612
		$tmpvalue = $this->GetDefault();
1613
		if (!empty($tmpvalue))
1614
			$tree .= " class=\"navlnk\"";
1615
		$tree .= " >" . $this->GetQname() . "</a>";
1616
		if (is_array($this->subqueues)) {
1617
			$tree .= "<ul>";
1618
			foreach ($this->subqueues as $q)  {
1619
				$tree .= $q->build_tree();
1620
			}	
1621
			$tree .= "</ul>";
1622
		}
1623
		$tree .= "</li>";
1624
		return $tree;
1625
	}
1626

    
1627
	/* Even this should take children into consideration */
1628
	function build_rules() {
1629

    
1630
		$pfq_rule = " queue ". $this->qname;
1631
		if ($this->GetInterface())
1632
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
1633
		if ($this->GetBandwidth() && $this->GetBwscale())
1634
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
1635
				
1636
		$tmpvalue = $this->GetQlimit();
1637
		if (!empty($tmpvalue))
1638
			$pfq_rule .= " qlimit " . $this->GetQlimit();
1639
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetRealtime() <> "" || $this->GetLinkshare() <> "" || $this->GetUpperlimit() <> "") {
1640
			$pfq_rule .= " hfsc ( ";
1641
			$tmpvalue = $this->GetRed();
1642
			if (!empty($tmpvalue)) {
1643
				$comma = 1;
1644
				$pfq_rule .= " red ";
1645
			}
1646
			
1647
			$tmpvalue = $this->GetRio();
1648
			if (!empty($tmpvalue)) {
1649
				if ($comma) 
1650
					$pfq_rule .= " ,";
1651
				$comma = 1;
1652
				$pfq_rule .= " rio ";
1653
			}
1654
			$tmpvalue = $this->GetEcn();
1655
			if (!empty($tmpvalue)) {
1656
				if ($comma) 
1657
					$pfq_rule .= " ,";
1658
				$comma = 1;
1659
				$pfq_rule .= " ecn ";
1660
			}
1661
			$tmpvalue = $this->GetDefault();
1662
			if (!empty($tmpvalue)) {
1663
				if ($comma)
1664
					$pfq_rule .= " ,";
1665
				$comma = 1;
1666
				$pfq_rule .= " default ";
1667
			}
1668

    
1669
			if ($this->GetRealtime() <> "")  {
1670
				if ($comma) 
1671
					$pfq_rule .= " , ";
1672
				if ($this->GetR_m1()  <> "" && $this->GetR_d() <> "" && $this->GetR_m2() <> "")
1673
					$pfq_rule .= " realtime (".$this->GetR_m1() . ", " . $this->GetR_d().", ". $this->GetR_m2() .") ";
1674
				else  if ($this->GetR_m2() <> "")
1675
					$pfq_rule .= " realtime " . $this->GetR_m2();
1676
				$comma = 1;
1677
			}
1678
			if ($this->GetLinkshare() <> "") {
1679
				if ($comma)
1680
					$pfq_rule .= " ,";
1681
				if ($this->GetL_m1() <> "" && $this->GetL_d() <> "" && $this->GetL_m2() <> "")
1682
					$pfq_rule .= " linkshare (".$this->GetL_m1(). ", ". $this->GetL_d(). ", ". $this->GetL_m2(). ") ";
1683
				else if ($this->GetL_m2() <> "")
1684
					$pfq_rule .= " linkshare " . $this->GetL_m2() . " ";
1685
				$comma = 1;
1686
			}
1687
			if ($this->GetUpperlimit() <> "") {
1688
				if ($comma)
1689
					$pfq_rule .= " ,";
1690
				if ($this->GetU_m1() <> "" && $this->GetU_d() <> "" && $this->GetU_m2() <> "")
1691
							$pfq_rule .= " upperlimit (".$this->GetU_m1().", ". $this->GetU_d().", ". $this->GetU_m2(). ") ";
1692
				else if ($this->GetU_m2() <> "")
1693
					$pfq_rule .= " upperlimit " . $this->GetU_m2() . " ";
1694
			}
1695
			$pfq_rule .= " ) ";
1696
		}
1697
		if (count($this->subqueues)) {
1698
			$i = count($this->subqueues);
1699
			$pfq_rule .= " { ";
1700
			foreach ($this->subqueues as $qkey => $qnone) {
1701
				if ($i > 1) {
1702
					$i--;
1703
					$pfq_rule .= " {$qkey}, ";
1704
				} else
1705
					$pfq_rule .= " {$qkey} ";
1706
			}
1707
			$pfq_rule .= " } \n";
1708
			foreach ($this->subqueues as $q)
1709
				$pfq_rule .= $q->build_rules();
1710
		}
1711

    
1712
		 $pfq_rule .= " \n";
1713
			
1714
		return $pfq_rule;
1715
	}
1716

    
1717
	function build_javascript() {
1718
		$javascript = parent::build_javascript();
1719
		$javascript .= "<script type=\"text/javascript\">";
1720
		$javascript .= "function enable_realtime(enable_over) { \n";
1721
		$javascript .= "if (document.iform.realtime.checked || enable_over) { \n";
1722
		$javascript .= "document.iform.realtime1.disabled = 0;\n";
1723
		$javascript .= "document.iform.realtime2.disabled = 0;\n";
1724
		$javascript .= "document.iform.realtime3.disabled = 0;\n";
1725
		$javascript .= " } else { \n";
1726
		$javascript .= "document.iform.realtime1.disabled = 1;\n";
1727
		$javascript .= "document.iform.realtime2.disabled = 1;\n";
1728
		$javascript .= "document.iform.realtime3.disabled = 1;\n";
1729
		$javascript .= " } \n";
1730
		$javascript .= " } \n";
1731
		$javascript .= "function enable_linkshare(enable_over) { \n";
1732
		$javascript .= "if (document.iform.linkshare.checked || enable_over) { \n";
1733
		$javascript .= "document.iform.linkshare1.disabled = 0;\n";
1734
		$javascript .= "document.iform.linkshare2.disabled = 0;\n";
1735
		$javascript .= "document.iform.linkshare3.disabled = 0;\n";
1736
		$javascript .= " } else { \n";
1737
		$javascript .= "document.iform.linkshare1.disabled = 1;\n";
1738
		$javascript .= "document.iform.linkshare2.disabled = 1;\n";
1739
		$javascript .= "document.iform.linkshare3.disabled = 1;\n";
1740
		$javascript .= " } \n";
1741
		$javascript .= " } \n";
1742
		$javascript .= "function enable_upperlimit(enable_over) { \n";
1743
		$javascript .= "if (document.iform.upperlimit.checked || enable_over) { \n";
1744
		$javascript .= "document.iform.upperlimit1.disabled = 0;\n";
1745
		$javascript .= "document.iform.upperlimit2.disabled = 0;\n";
1746
		$javascript .= "document.iform.upperlimit3.disabled = 0;\n";
1747
		$javascript .= " } else { \n";
1748
		$javascript .= "document.iform.upperlimit1.disabled = 1;\n";
1749
		$javascript .= "document.iform.upperlimit2.disabled = 1;\n";
1750
		$javascript .= "document.iform.upperlimit3.disabled = 1;\n";
1751
		$javascript .= " } \n";
1752
			
1753
		$javascript .= "} \n";
1754
		$javascript .= "</script>";
1755

    
1756
		return $javascript;
1757
	}
1758

    
1759
	function build_form() {
1760
		$form = "<tr>";
1761
		$form .= "<td valign=\"top\" class=\"vncellreq\">Bandwidth</td>";
1762
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
1763
		$form .= htmlspecialchars($this->GetBandwidth());
1764
		$form .= "\">";
1765
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
1766
		$form .= "<option value=\"Gb\"";
1767
		if ($this->GetBwscale() == "Gb")
1768
			$form .= " selected=\"yes\"";
1769
		$form .= ">Gbit/s</option>";
1770
		$form .= "<option value=\"Mb\"";
1771
		if ($this->GetBwscale() == "Mb")
1772
			$form .= " selected=\"yes\"";
1773
		$form .= ">Mbit/s</option>";
1774
		$form .= "<option value=\"Kb\"";
1775
		if ($this->GetBwscale() == "Kb")
1776
			$form .= " selected=\"yes\"";
1777
		$form .= ">Kbit/s</option>";
1778
		$form .= "<option value=\"\"";
1779
		if ($this->GetBwscale() == "b")
1780
			$form .= " selected=\"yes\"";
1781
		$form .= ">Bit/s</option>";
1782
		$form .= "<option value=\"%\"";
1783
		if ($this->GetBwscale() == "%")
1784
			$form .= " selected=\"yes\"";
1785
		$form .= ">%</option>";
1786
		$form .= "</select> <br>";
1787
		$form .= "<span class=\"vexpl\">Choose the amount of bandwidth for this queue";
1788
		$form .= "</span></td>";
1789
		$form .= parent::build_form();
1790
		$form .= "<tr>";
1791
		$form .= "<td width=\"22%\" valign=\"top\" class=\"vncellreq\">Service Curve (sc)</td>";
1792
		$form .= "<td width=\"78%\" class=\"vtable\">";
1793
		$form .= "<table>";
1794
		$form .= "<tr><td>&nbsp;</td><td><center>m1</center></td><td><center>d</center></td><td><center><b>m2</b></center></td></tr>";
1795
		$form .= "<tr><td><input type=\"checkbox\" id=\"upperlimit\" name=\"upperlimit\"";
1796
		if($this->GetUpperlimit()<> "") 
1797
			$form .=  " CHECKED ";
1798
		$form .= "onChange=\"enable_upperlimit()\"> Upperlimit:</td><td><input size=\"6\" value=\"";
1799
		$form .= htmlspecialchars($this->GetU_m1());
1800
		$form .= "\" id=\"upperlimit1\" name=\"upperlimit1\" ";
1801
		if ($this->GetUpperlimit() == "")
1802
			$form .= " disabled";
1803
		$form .= "></td><td><input size=\"6\" value=\"";
1804
		$form .= htmlspecialchars($this->GetU_d());
1805
		$form .= "\" id=\"upperlimi2\" name=\"upperlimit2\" ";
1806
		if ($this->GetUpperlimit() == "")
1807
			$form .= " disabled";
1808
		$form .= "></td><td><input size=\"6\" value=\"";
1809
		$form .= htmlspecialchars($this->GetU_m2());
1810
		$form .= "\" id=\"upperlimit3\" name=\"upperlimit3\" ";
1811
		if ($this->GetUpperlimit() == "")
1812
			$form .= " disabled";
1813
		$form .= "></td><td>The maximum allowed bandwidth for the queue.</td></tr>";
1814
		$form .= "<tr><td><input type=\"checkbox\" id=\"realtime\" name=\"realtime\"";
1815
		if($this->GetRealtime() <> "") 
1816
			$form .=  " CHECKED ";
1817
		$form .= "onChange=\"enable_realtime()\"> Real time:</td><td><input size=\"6\" value=\"";
1818
		$form .= htmlspecialchars($this->GetR_m1());
1819
		$form .= "\" id=\"realtime1\" name=\"realtime1\" ";
1820
		if ($this->GetRealtime() == "")
1821
			$form .= " disabled";
1822
		$form .= "></td><td><input size=\"6\" value=\"";
1823
		$form .= htmlspecialchars($this->GetR_d());
1824
		$form .= "\" id=\"realtime2\" name=\"realtime2\" ";
1825
		if ($this->GetRealtime() == "")
1826
			$form .= " disabled";
1827
		$form .= "></td><td><input size=\"6\" value=\"";
1828
		$form .= htmlspecialchars($this->GetR_m2());
1829
		$form .= "\" id=\"realtime3\" name=\"realtime3\" ";
1830
		if ($this->GetRealtime() == "")
1831
			$form .= " disabled";
1832
		$form .= "></td><td>The minimum required bandwidth for the queue.</td></tr>";
1833
		$form .= "<tr><td><input type=\"checkbox\" id=\"linkshare\" id=\"linkshare\" name=\"linkshare\"";
1834
		if($this->GetLinkshare() <> "") 
1835
			$form .=  " CHECKED ";
1836
		$form .= "onChange=\"enable_linkshare()\"> Link share:</td><td><input size=\"6\" value=\"";
1837
		$form .= htmlspecialchars($this->GetL_m1());
1838
		$form .= "\" id=\"linkshare1\" name=\"linkshare1\" ";
1839
		if ($this->GetLinkshare() == "")
1840
			$form .= " disabled";
1841
		$form .= "></td><td><input size=\"6\" value=\"";
1842
		$form .= htmlspecialchars($this->GetL_d());
1843
		$form .= "\" id=\"linkshare2\" name=\"linkshare2\" ";
1844
		if ($this->GetLinkshare() == "")
1845
			$form .= " disabled";
1846
		$form .= "></td><td><input size=\"6\" value=\"";
1847
		$form .= htmlspecialchars($this->GetL_m2());
1848
		$form .= "\" id=\"linkshare3\" name=\"linkshare3\" ";
1849
		if ($this->GetLinkshare() == "")
1850
			$form .= " disabled";
1851
		$form .= "></td><td>The bandwidth share of a backlogged queue - this overrides priority.</td></tr>";
1852
		$form .= "</table><br>";
1853
		$form .= "The format for service curve specifications is (m1, d, m2).  m2 controls";
1854
		$form .= "the bandwidth assigned to the queue.  m1 and d are optional and can be";
1855
		$form .= "used to control the initial bandwidth assignment.  For the first d milliseconds the queue gets the bandwidth given as m1, afterwards the value";
1856
		$form .= "given in m2.";
1857
		$form .= "</span></td>";
1858
		$form .= "</tr>";
1859

    
1860
		return $form;
1861
	}
1862

    
1863
	function update_altq_queue_data(&$data) { 
1864
		$this->ReadConfig($data);
1865
	}
1866

    
1867
	function wconfig() {
1868
		$cflink =& get_reference_to_me_in_config($this->GetLink());
1869
		if (!is_array($cflink))
1870
			$cflink = array();
1871
		$cflink['name'] = $this->GetQname();
1872
		$cflink['interface'] = $this->GetInterface();
1873
		$cflink['qlimit'] = trim($this->GetQlimit());
1874
		if (empty($cflink['qlimit']))
1875
			unset($cflink['qlimit']);
1876
		$cflink['priority'] = $this->GetQpriority();
1877
		if (empty($cflink['priority']))
1878
			unset($cflink['priority']);
1879
		$cflink['description'] = $this->GetDescription();
1880
		if (empty($cflink['description']))
1881
			unset($cflink['description']);
1882
		$cflink['bandwidth'] = $this->GetBandwidth();
1883
		$cflink['bandwidthtype'] = $this->GetBwscale();
1884
		$cflink['enabled'] = $this->GetEnabled();
1885
		if (empty($cflink['enabled']))
1886
			unset($cflink['enabled']);
1887
		$cflink['default'] = $this->GetDefault();
1888
		if (empty($cflink['default']))
1889
			unset($cflink['default']);
1890
		$cflink['red'] = trim($this->GetRed());
1891
		if (empty($cflink['red']))
1892
			unset($cflink['red']);
1893
		$cflink['rio'] = $this->GetRio();
1894
		if (empty($cflink['rio']))
1895
			unset($cflink['rio']);
1896
		$cflink['ecn'] = trim($this->GetEcn());
1897
		if (empty($cflink['ecn']))
1898
			unset($cflink['ecn']);
1899
		if ($this->GetLinkshare() <> "") {
1900
			if ($this->GetL_m1() <> "") {
1901
				$cflink['linkshare1'] = $this->GetL_m1();
1902
				$cflink['linkshare2'] = $this->GetL_d();
1903
				$cflink['linkshare'] = "on";
1904
			} else {
1905
				unset($cflink['linkshare']);
1906
				unset($cflink['linkshare1']);
1907
				unset($cflink['linkshare2']);
1908
			}
1909
			if ($this->GetL_m2() <> "") {
1910
				$cflink['linkshare3'] = $this->GetL_m2();
1911
				$cflink['linkshare'] = "on";
1912
			} else {
1913
				unset($cflink['linkshare']);
1914
				unset($cflink['linkshare3']);
1915
			}
1916
		} else {
1917
			unset($cflink['linkshare']);
1918
			unset($cflink['linkshare1']);
1919
			unset($cflink['linkshare2']);
1920
			unset($cflink['linkshare3']);
1921
		}
1922
		if ($this->GetRealtime() <> "") {
1923
			if ($this->GetR_m1() <> "") {
1924
				$cflink['realtime1'] = $this->GetR_m1();
1925
				$cflink['realtime2'] = $this->GetR_d();
1926
				$cflink['realtime'] = "on";
1927
			} else {
1928
				unset($cflink['realtime']);
1929
				unset($cflink['realtime1']);
1930
				unset($cflink['realtime2']);
1931
			}
1932
			if ($this->GetR_m2() <> "") {
1933
				$cflink['realtime3'] = $this->GetR_m2();
1934
				$cflink['realtime'] = "on";
1935
			} else {
1936
				unset($cflink['realtime']);
1937
				unset($cflink['realtime3']);
1938
			}
1939
		} else {
1940
			unset($cflink['realtime']);
1941
			unset($cflink['realtime1']);
1942
			unset($cflink['realtime2']);
1943
			unset($cflink['realtime3']);
1944
		}
1945
		if ($this->GetUpperlimit() <> "") {
1946
			if ($this->GetU_m1() <> "") {
1947
				$cflink['upperlimit1'] = $this->GetU_m1();
1948
				$cflink['upperlimit2'] = $this->GetU_d();
1949
				$cflink['upperlimit'] = "on";
1950
			} else {
1951
				unset($cflink['upperlimit']);
1952
				unset($cflink['upperlimit1']);
1953
				unset($cflink['upperlimit2']);
1954
			}
1955
			if ($this->GetU_m2() <> "") {
1956
				$cflink['upperlimit3'] = $this->GetU_m2();
1957
				$cflink['upperlimit'] = "on";
1958
			} else {
1959
				unset($cflink['upperlimit']);
1960
				unset($cflink['upperlimit3']);
1961
			}
1962
		} else {
1963
			unset($cflink['upperlimit']);
1964
			unset($cflink['upperlimit1']);
1965
			unset($cflink['upperlimit2']);
1966
			unset($cflink['upperlimit3']);
1967
		}
1968
	}
1969
}
1970

    
1971
class cbq_queue extends priq_queue {
1972
	var $qborrow = "";
1973

    
1974
	function GetBorrow() {
1975
		return $this->qborrow;
1976
	}
1977
	function SetBorrow($borrow) {
1978
		$this->qborrow = $borrow;
1979
	}
1980
	function CanHaveChildren() {
1981
		return true;
1982
	}
1983

    
1984
	function &add_queue($interface, &$qname, &$path, &$input_errors) {
1985

    
1986
		if (!is_array($this->subqueues))
1987
			$this->subqueues = array();
1988
		$q =& new cbq_queue();
1989
		$q->SetInterface($this->GetInterface());
1990
		$q->SetParent(&$this);
1991
		$q->ReadConfig($qname);
1992
                $q->validate_input($qname, $input_errors);
1993
                if (count($input_errors)) {
1994
                        return $q;
1995
                }
1996
                switch ($q->GetBwscale()) {
1997
                case "%":
1998
                	$myBw = $this->GetAvailableBandwidth() * $qname['bandwidth'] / 100;
1999
                        break;
2000
                default:
2001
                	$myBw = $qname['bandwidth'] * get_bandwidthtype_scale($q->GetBwscale());
2002
                        break;
2003
                }
2004
                $q->SetAvailableBandwidth($myBw);
2005
                $this->SetAvailableBandwidth($this->GetAvailableBandwidth() - $myBw);
2006

    
2007
		$q->SetEnabled("on");
2008
		$q->SetLink($path);
2009
		$this->subqueues[$q->GetQName()] = &$q;
2010
		ref_on_altq_queue_list($this->GetQname(), $q->GetQname());
2011
		if (is_array($qname['queue'])) {
2012
			foreach ($qname['queue'] as $key1 => $que) {
2013
				array_push($path, $key1);
2014
				$q->add_queue($q->GetInterface(), &$que, &$path, $input_errors);
2015
				array_pop($path);
2016
			}
2017
		}
2018

    
2019
		return $q;
2020
	}
2021

    
2022
	function copy_queue($interface, &$cflink) {
2023

    
2024
		$cflink['interface'] = $interface;
2025
		$cflink['qlimit'] = trim($this->GetQlimit());
2026
		if (empty($clink['qlimit']))
2027
			unset($cflink['qlimit']);
2028
		$cflink['priority'] = trim($this->GetQpriority());
2029
		if (empty($cflink['priority']))
2030
			unset($cflink['priority']);
2031
		$cflink['name'] = $this->GetQname();
2032
		$cflink['description'] = trim($this->GetDescription());
2033
		if (empty($cflink['description']))
2034
			unset($cflink['description']);
2035
		$cflink['bandwidth'] = $this->GetBandwidth();
2036
		$cflink['bandwidthtype'] = $this->GetBwscale();
2037
		$cflink['enabled'] = trim($this->GetEnabled());
2038
		if (empty($cflink['enabled']))
2039
			unset($cflink['enabled']);
2040
		$cflink['default'] = trim($this->GetDefault());
2041
		if (empty($cflink['default']))
2042
			unset($cflink['default']);
2043
		$cflink['red'] = trim($this->GetRed());
2044
		if (empty($cflink['red']))
2045
			unset($cflink['red']);
2046
		$cflink['rio'] = trim($this->GetRio());
2047
		if (empty($cflink['rio']))
2048
			unset($cflink['rio']);
2049
		$cflink['ecn'] = trim($this->GetEcn());
2050
		if (empty($cflink['ecn']))
2051
			unset($cflink['ecn']);
2052
		$cflink['borrow'] = trim($this->GetBorrow());
2053
		if (empty($cflink['borrow']))
2054
			unset($cflink['borrow']);
2055
		if (is_array($this->queues)) {
2056
			$cflinkp['queue'] = array();
2057
			foreach ($this->subqueues as $q) {
2058
				$cflink['queue'][$q->GetQname()] = array();
2059
				$q->copy_queue($interface, &$cflink['queue'][$q->GetQname()]);
2060
			}
2061
		}
2062
	}
2063
	
2064
	/*
2065
	 * Should search even its children
2066
	 */
2067
	function &find_queue($interface, $qname) {
2068
		if ($qname == $this->GetQname())
2069
			return $this;
2070
		foreach ($this->subqueues as $q) {
2071
			$result =& $q->find_queue("", $qname);
2072
			if ($result)
2073
				return $result;
2074
		}
2075
	}
2076

    
2077
	function &find_parentqueue($interface, $qname) {
2078
		if ($this->subqueues[$qname])
2079
			return $this;
2080
		foreach ($this->subqueues as $q) {
2081
			$result = $q->find_parentqueue("", $qname);
2082
			if ($result)
2083
				return $result;
2084
		}
2085
	}
2086

    
2087
	function delete_queue() {
2088
		unref_on_altq_queue_list($this->GetQname());
2089
		if ($this->GetDefault())
2090
			altq_set_default_queue($this->GetInterface(), "false");
2091
		cleanup_queue_from_rules($this->GetQname());
2092
		foreach ($this->subqueues as $q) {
2093
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
2094
			$q->delete_queue();
2095
		}
2096
		unset_object_by_reference($this->GetLink());
2097
	}
2098
	
2099
	function validate_input($data, &$input_errors) {
2100
		parent::validate_input($data, $input_errors);
2101
		
2102
		if ($data['priority'] > 7)
2103
				$input_errors[] = "Priority must be an integer between 1 and 7.";
2104
		$reqdfields[] = "bandwidth";
2105
		$reqdfieldsn[] = "Bandwidth";
2106
		$reqdfields[] = "bandwidthtype";
2107
		$reqdfieldsn[] = "Bandwidthtype";
2108

    
2109
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2110
		
2111
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2112
			$input_errors[] = "Bandwidth must be an integer.";
2113

    
2114

    
2115
		if ($data['bandwidth'] < 0)
2116
                       $input_errors[] = "Bandwidth cannot be negative.";
2117

    
2118
		if ($data['bandwidthtype'] == "%") {
2119
			if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2120
				$input_errors[] = "Bandwidth in percentage should be between 1 and 100 bounds.";
2121
		}
2122

    
2123
/*
2124
           $parent =& $this->GetParent();
2125
           switch ($data['bandwidthtype']) {
2126
                       case "%":
2127
                             $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2128
                       default:
2129
                             $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2130
                             break;
2131
           }
2132
                if ($parent->GetAvailableBandwidth() < floatval($myBw))
2133
                        $input_errors[] = "The sum of the children bandwidth exceeds that of the parent.";
2134
*/
2135
	}
2136

    
2137
	function ReadConfig(&$q) {
2138
		parent::ReadConfig($q);
2139
		if (!empty($q['borrow']))
2140
			$this->SetBorrow("on");
2141
	}
2142
		
2143
	function build_javascript() {
2144
		return parent::build_javascript();
2145
	}
2146

    
2147
	function build_tree() {
2148
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . $this->GetInterface()."&queue=" . $this->GetQname()."&action=show"; 
2149
		$tree .= "\" ";
2150
		$tmpvalue = trim($this->GetDefault());
2151
		if (!empty($tmpvalue))
2152
			$tree .= " class=\"navlnk\"";
2153
		$tree .= " >" . $this->GetQname() . "</a>";
2154
		if (is_array($this->subqueues)) {
2155
			$tree .= "<ul>";
2156
			foreach ($this->subqueues as $q)  {
2157
				$tree .= $q->build_tree();
2158
			}	
2159
			$tree .= "</ul>";
2160
		}
2161
		$tree .= "</li>";
2162
		return $tree;
2163
	}
2164
		
2165
	/* Even this should take children into consideration */
2166
	function build_rules() {
2167
		$pfq_rule = "queue ". $this->qname;
2168
		if ($this->GetInterface())
2169
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2170
		if ($this->GetBandwidth() && $this->GetBwscale())
2171
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2172
		$tmpvalue = $this->GetQpriority();
2173
		if (!empty($tmpvalue))
2174
			$pfq_rule .= " priority " . $this->GetQpriority();
2175
		$tmpvalue = trim($this->GetQlimit());
2176
		if (!empty($tmpvalue))
2177
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2178
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() || $this->GetEcn() || $this->GetBorrow()) {
2179
			$pfq_rule .= " cbq ( ";
2180
			$tmpvalue = trim($this->GetRed());
2181
			if (!empty($tmpvalue)) {
2182
				$comma = 1;
2183
				$pfq_rule .= " red ";
2184
			}
2185
			$tmpvalue = trim($this->GetRio());
2186
			if (!empty($tmpvalue)) {
2187
				if ($comma) 
2188
					$pfq_rule .= " ,";
2189
				$comma = 1;
2190
				$pfq_rule .= " rio ";
2191
			}
2192
			$tmpvalue = trim($this->GetEcn());
2193
			if (!empty($tmpvalue)) {
2194
				if ($comma) 
2195
					$pfq_rule .= " ,";
2196
				$comma = 1;
2197
				$pfq_rule .= " ecn ";
2198
			}
2199
			$tmpvalue = trim($this->GetDefault());
2200
			if (!empty($tmpvalue)) {
2201
				if ($comma)
2202
					$pfq_rule .= " ,";
2203
				$comma = 1;
2204
				$pfq_rule .= " default ";
2205
			}
2206
			$tmpvalue = trim($this->GetBorrow());
2207
			if (!empty($tmpvalue)) {
2208
				if ($comma)
2209
					$pfq_rule .= ", ";
2210
				$pfq_rule .= " borrow ";
2211
			}
2212
			$pfq_rule .= " ) ";
2213
		} 
2214
		if (count($this->subqueues)) {
2215
			$i = count($this->subqueues);
2216
			$pfq_rule .= " { ";
2217
			foreach ($this->subqueues as $qkey => $qnone) {
2218
				if ($i > 1) {
2219
					$i--;
2220
					$pfq_rule .= " {$qkey}, ";
2221
				} else
2222
					$pfq_rule .= " {$qkey} ";
2223
			}
2224
			$pfq_rule .= " } \n";
2225
			foreach ($this->subqueues as $q)
2226
				$pfq_rule .= $q->build_rules();
2227
		}
2228

    
2229
		$pfq_rule .= " \n";
2230
		return $pfq_rule;
2231
	}
2232

    
2233
	function build_form() {
2234
		$form = "<tr>";
2235
		$form .= "<td valign=\"top\" class=\"vncellreq\">Bandwidth</td>";
2236
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2237
		if ($this->GetBandwidth() > 0)
2238
			$form .= htmlspecialchars($this->GetBandwidth());
2239
		$form .= "\">";
2240
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2241
		$form .= "<option value=\"Gb\"";
2242
		if ($this->GetBwscale() == "Gb")
2243
			$form .= " selected=\"yes\"";
2244
		$form .= ">Gbit/s</option>";
2245
		$form .= "<option value=\"Mb\"";
2246
		if ($this->GetBwscale() == "Mb")
2247
			$form .= " selected=\"yes\"";
2248
		$form .= ">Mbit/s</option>";
2249
		$form .= "<option value=\"Kb\"";
2250
		if ($this->GetBwscale() == "Kb")
2251
			$form .= " selected=\"yes\"";
2252
		$form .= ">Kbit/s</option>";
2253
		$form .= "<option value=\"\"";
2254
		if ($this->GetBwscale() == "b")
2255
			$form .= " selected=\"yes\"";
2256
		$form .= ">Bit/s</option>";
2257
		$form .= "<option value=\"%\"";
2258
		if ($this->GetBwscale() == "%")
2259
			$form .= " selected=\"yes\"";
2260
		$form .= ">%</option>";
2261
		$form .= "</select> <br>";
2262
		$form .= "<span class=\"vexpl\">Choose the amount of bandwidth for this queue";
2263
		$form .= "</span></td></tr>";
2264
		$form .= parent::build_form();
2265
		$form .= "<tr><td class=\"vncellreq\">Scheduler specific options</td>";
2266
		$form .= "<td class=\"vtable\"><input type=\"checkbox\" id=\"borrow\" name=\"borrow\"";
2267
		if($this->GetBorrow() == "on") 
2268
			$form .=  " CHECKED ";
2269
		$form .= "> Borrow from other queues when available<br></td></tr>";
2270

    
2271
		return $form;
2272
	}
2273

    
2274
	function update_altq_queue_data(&$data) { 
2275
		$this->ReadConfig($data);
2276
	}
2277

    
2278
	function wconfig() {
2279
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2280
		if (!is_array($cflink))
2281
			$cflink = array();
2282
		$cflink['interface'] = $this->GetInterface();
2283
		$cflink['qlimit'] = trim($this->GetQlimit());
2284
		if (empty($cflink['qlimit']))
2285
			unset($cflink['qlimit']);
2286
		$cflink['priority'] = $this->GetQpriority();
2287
		if (empty($cflink['priority']))
2288
			unset($cflink['priority']);
2289
		$cflink['name'] = $this->GetQname();
2290
		$cflink['description'] = $this->GetDescription();
2291
		if (empty($cflink['description']))
2292
			unset($cflink['description']);
2293
		$cflink['bandwidth'] = $this->GetBandwidth();
2294
		$cflink['bandwidthtype'] = $this->GetBwscale();
2295
		$cflink['enabled'] = trim($this->GetEnabled());
2296
		if (empty($cflink['enabled']))
2297
			unset($cflink['enabled']);
2298
		$cflink['default'] = trim($this->GetDefault());
2299
		if (empty($cflink['default']))
2300
			unset($cflink['default']);
2301
		$cflink['red'] = trim($this->GetRed());
2302
		if (empty($cflink['red']))
2303
			unset($cflink['red']);
2304
		$cflink['rio'] = trim($this->GetRio());
2305
		if (empty($cflink['rio']))
2306
			unset($cflink['rio']);
2307
		$cflink['ecn'] = trim($this->GetEcn());
2308
		if (empty($cflink['ecn']))
2309
			unset($cflink['ecn']);
2310
		$cflink['borrow'] = trim($this->GetBorrow());
2311
		if (empty($cflink['borrow']))
2312
			unset($cflink['borrow']);
2313
	}
2314
}
2315

    
2316
class fairq_queue extends priq_queue {
2317
	var $hogs;
2318
	var $buckets;
2319

    
2320
	function GetBuckets() {
2321
		return $this->buckets;
2322
	}
2323
	function SetBuckets($buckets) {
2324
		$this->buckets = $buckets;
2325
	}
2326
	function GetHogs() {
2327
		return $this->hogs;
2328
	}
2329
	function SetHogs($hogs) {
2330
		$this->hogs = $hogs;
2331
	}
2332
	function CanHaveChildren() {
2333
		return false;
2334
	}
2335

    
2336

    
2337
	function copy_queue($interface, &$cflink) {
2338
                $cflink['interface'] = $interface;
2339
                $cflink['qlimit'] = $this->GetQlimit();
2340
                $cflink['priority'] = $this->GetQpriority();
2341
                $cflink['name'] = $this->GetQname();
2342
                $cflink['description'] = $this->GetDescription();
2343
                $cflink['bandwidth'] = $this->GetBandwidth();
2344
                $cflink['bandwidthtype'] = $this->GetBwscale();
2345
                $cflink['enabled'] = $this->GetEnabled();
2346
                $cflink['default'] = $this->GetDefault();
2347
                $cflink['red'] = $this->GetRed();
2348
                $cflink['rio'] = $this->GetRio();
2349
                $cflink['ecn'] = $this->GetEcn();
2350
                $cflink['buckets'] = $this->GetBuckets();
2351
		$cflink['hogs'] = $this->GetHogs();
2352
	}
2353
	
2354
	/*
2355
	 * Should search even its children
2356
	 */
2357
	function &find_queue($interface, $qname) {
2358
		if ($qname == $this->GetQname())
2359
			return $this;
2360
	}
2361

    
2362
	function find_parentqueue($interface, $qname) { return; }
2363

    
2364
	function delete_queue() {
2365
		unref_on_altq_queue_list($this->GetQname());
2366
		if ($this->GetDefault())
2367
			altq_set_default_queue($this->GetInterface(), "false");
2368
		cleanup_queue_from_rules($this->GetQname());
2369
		unset_object_by_reference($this->GetLink());
2370
	}
2371
	
2372
	function validate_input($data, &$input_errors) {
2373
		parent::validate_input($data, $input_errors);
2374
		
2375
		if ($data['priority'] > 255)
2376
				$input_errors[] = "Priority must be an integer between 1 and 255.";
2377
		$reqdfields[] = "bandwidth";
2378
		$reqdfieldsn[] = "Bandwidth";
2379
		$reqdfields[] = "bandwidthtype";
2380
		$reqdfieldsn[] = "Bandwidthtype";
2381

    
2382
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2383
		
2384
		if ($data['bandwidth'] && !is_numeric($data['bandwidth']))
2385
	                 $input_errors[] = "Bandwidth must be an integer.";
2386

    
2387

    
2388
	        if ($data['bandwidth'] < 0)
2389
                       $input_errors[] = "Bandwidth cannot be negative.";
2390

    
2391

    
2392
        	if ($data['bandwidthtype'] == "%") {
2393
                	if ($data['bandwidth'] > 100 || $data['bandwidth'] < 0)
2394
                       		$input_errors[] = "Bandwidth in percentage should be between 1 and 100 bounds.";
2395
           	}
2396

    
2397
/*
2398
           	$parent =& $this->GetParent();
2399
           	switch ($data['bandwidthtype']) {
2400
                       case "%":
2401
                             $myBw = $parent->GetAvailableBandwidth() * floatval($data['bandwidth']) / 100;
2402
                       default:
2403
                             $mybw = floatval($data['bandwidth']) * get_bandwidthtype_scale($data['bandwidthtype']);
2404
                             break;
2405
           	}
2406
                if ($parent->GetAvailableBandwidth() < floatval($myBw))
2407
                        $input_errors[] = "The sum of children bandwidth exceeds that of the parent.";
2408
*/
2409
	}
2410
	
2411
	function ReadConfig(&$q) {
2412
		parent::ReadConfig($q);
2413
		if (!empty($q['buckets']))
2414
			$this->SetBuckets($q['buckets']);
2415
		if (!empty($q['hogs']) && is_valid_shaperbw($q['hogs']))
2416
			$this->SetHogs($q['hogs']);
2417
	}
2418
		
2419
	function build_javascript() {
2420
		return parent::build_javascript();
2421
	}
2422

    
2423
	function build_tree() {
2424
		$tree = " <li><a href=\"firewall_shaper.php?interface=" . 
2425
		$this->GetInterface()."&queue=" . $this->GetQname()."&action=show"; 
2426
		$tree .= "\" ";
2427
		$tmpvalue = trim($this->GetDefault());
2428
		if (!empty($tmpvalue))
2429
			$tree .= " class=\"navlnk\"";
2430
		$tree .= " >" . $this->GetQname() . "</a>";
2431
		$tree .= "</li>";
2432
		return $tree;
2433
	}
2434
		
2435
	/* Even this should take children into consideration */
2436
	function build_rules() {
2437
		$pfq_rule = "queue ". $this->qname;
2438
		if ($this->GetInterface())
2439
			$pfq_rule .= " on ".get_real_interface($this->GetInterface());
2440
		if ($this->GetBandwidth() && $this->GetBwscale())
2441
			$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2442
		$tmpvalue = trim($this->GetQpriority());
2443
		if (!empty($tmpvalue))
2444
			$pfq_rule .= " priority " . $this->GetQpriority();
2445
		$tmpvalue = trim($this->GetQlimit());
2446
		if (!empty($tmpvalue))
2447
			$pfq_rule .= " qlimit " . $this->GetQlimit();
2448
		if ($this->GetDefault() || $this->GetRed() || $this->GetRio() 
2449
			|| $this->GetEcn() || $this->GetBuckets() || $this->GetHogs()) {
2450
			$pfq_rule .= " fairq ( ";
2451
			$tmpvalue = trim($this->GetRed());
2452
			if (!empty($tmpvalue)) {
2453
				$comma = 1;
2454
				$pfq_rule .= " red ";
2455
			}
2456
			$tmpvalue = trim($this->GetRio());
2457
			if (!empty($tmpvalue)) {
2458
				if ($comma) 
2459
					$pfq_rule .= " ,";
2460
				$comma = 1;
2461
				$pfq_rule .= " rio ";
2462
			}
2463
			$tmpvalue = trim($this->GetEcn());
2464
			if (!empty($tmpvalue)) {
2465
				if ($comma) 
2466
					$pfq_rule .= " ,";
2467
				$comma = 1;
2468
				$pfq_rule .= " ecn ";
2469
			}
2470
			$tmpvalue = trim($this->GetDefault());
2471
			if (!empty($tmpvalue)) {
2472
				if ($comma)
2473
					$pfq_rule .= " ,";
2474
				$comma = 1;
2475
				$pfq_rule .= " default ";
2476
			}
2477
			$tmpvalue = trim($this->GetBuckets());
2478
			if (!empty($tmpvalue)) {
2479
				if ($comma)
2480
					$pfq_rule .= ", ";
2481
				$pfq_rule .= " buckets " . $this->GetBuckets() . " ";
2482
			}
2483
			$tmpvalue = trim($this->GetHogs());
2484
			if (!empty($tmpvalue)) {
2485
				if ($comma)
2486
					$pfq_rule .= ", ";
2487
				$pfq_rule .= " hogs " . $this->GetHogs() . " ";
2488
			}
2489
				$pfq_rule .= " ) ";
2490
		} 
2491

    
2492
		$pfq_rule .= " \n";
2493
		return $pfq_rule;
2494
	}
2495

    
2496
	function build_form() {
2497
		$form = "<tr>";
2498
		$form .= "<td valign=\"top\" class=\"vncellreq\">Bandwidth</td>";
2499
		$form .= "<td class=\"vtable\"> <input name=\"bandwidth\" id=\"bandwidth\" class=\"formfld unknown\" value=\"";
2500
		if ($this->GetBandwidth() > 0)
2501
			$form .= htmlspecialchars($this->GetBandwidth());
2502
		$form .= "\">";
2503
		$form .= "<select name=\"bandwidthtype\" id=\"bandwidthtype\" class=\"formselect\">";
2504
		$form .= "<option value=\"Gb\"";
2505
		if ($this->GetBwscale() == "Gb")
2506
			$form .= " selected=\"yes\"";
2507
		$form .= ">Gbit/s</option>";
2508
		$form .= "<option value=\"Mb\"";
2509
		if ($this->GetBwscale() == "Mb")
2510
			$form .= " selected=\"yes\"";
2511
		$form .= ">Mbit/s</option>";
2512
		$form .= "<option value=\"Kb\"";
2513
		if ($this->GetBwscale() == "Kb")
2514
			$form .= " selected=\"yes\"";
2515
		$form .= ">Kbit/s</option>";
2516
		$form .= "<option value=\"\"";
2517
		if ($this->GetBwscale() == "b")
2518
			$form .= " selected=\"yes\"";
2519
		$form .= ">Bit/s</option>";
2520
		$form .= "<option value=\"%\"";
2521
		if ($this->GetBwscale() == "%")
2522
			$form .= " selected=\"yes\"";
2523
		$form .= ">%</option>";
2524
		$form .= "</select> <br>";
2525
		$form .= "<span class=\"vexpl\">Choose the amount of bandwidth for this queue";
2526
		$form .= "</span></td></tr>";
2527
		$form .= parent::build_form();
2528
		$form .= "<tr><td class=\"vncellreq\">Scheduler specific options</td>";
2529
		$form .= "<td class=\"vtable\"><table><tr><td>";
2530
		$form .= "<input id=\"buckets\" name=\"buckets\" value=\"";
2531
		$tmpvalue = trim($this->GetBuckets());
2532
		if(!empty($tmpvalue)) 
2533
			$form .=  $this->GetBuckets();
2534
		$form .= "\"> Number of buckets available.<br></td></tr>";
2535
		$form .= "<tr><td class=\"vtable\"><input id=\"hogs\" name=\"hogs\" value=\"";
2536
		$tmpvalue = trim($this->GetHogs());
2537
		if(!empty($tmpvalue)) 
2538
			$form .=  $this->GetHogs();
2539
		$form .= "\"> Bandwidth limit for hosts to not saturate link.<br></td></tr>";
2540
		$form .= "</table></td></tr>";
2541
		return $form;
2542
	}
2543

    
2544
	function update_altq_queue_data(&$data) { 
2545
		$this->ReadConfig($data);
2546
	}
2547

    
2548
	function wconfig() {
2549
		$cflink =& get_reference_to_me_in_config($this->GetLink());
2550
		if (!is_array($cflink))
2551
			$cflink = array();
2552
		$cflink['interface'] = $this->GetInterface();
2553
		$cflink['qlimit'] = trim($this->GetQlimit());
2554
		if (empty($cflink['qlimit']))
2555
			unset($cflink['qlimit']);
2556
		$cflink['priority'] = trim($this->GetQpriority());
2557
		if (empty($cflink['priority']))
2558
			unset($cflink['priority']);
2559
		$cflink['name'] = $this->GetQname();
2560
		$cflink['description'] = trim($this->GetDescription());
2561
		if (empty($cflink['description']))
2562
			unset($cflink['description']);
2563
		$cflink['bandwidth'] = $this->GetBandwidth();
2564
		$cflink['bandwidthtype'] = $this->GetBwscale();
2565
		$cflink['enabled'] = $this->GetEnabled();
2566
		if (empty($cflink['enabled']))
2567
			unset($cflink['enabled']);
2568
		$cflink['default'] = trim($this->GetDefault());
2569
		if (empty($cflink['default']))
2570
			unset($cflink['default']);
2571
		$cflink['red'] = trim($this->GetRed());
2572
		if (empty($cflink['red']))
2573
			unset($cflink['red']);
2574
		$cflink['rio'] = trim($this->GetRio());
2575
		if (empty($cflink['rio']))
2576
			unset($cflink['rio']);
2577
		$cflink['ecn'] = trim($this->GetEcn());
2578
		if (empty($cflink['ecn']))
2579
			unset($cflink['ecn']);
2580
		$cflink['buckets'] = trim($this->GetBuckets());
2581
		if (empty($cflink['buckets']))
2582
			unset($cflink['buckets']);
2583
		$cflink['hogs'] = trim($this->GetHogs());
2584
		if (empty($cflink['hogs']))
2585
			unset($cflink['hogs']);
2586
	}
2587
}
2588

    
2589

    
2590
/*
2591
 * XXX: TODO Link dummynet(4) in the system. 
2592
 */
2593

    
2594

    
2595
/*
2596
 * List of respective objects!
2597
 */
2598
$dummynet_pipe_list = array();
2599

    
2600
class dummynet_class {
2601
        var $qname;
2602
	var $qnumber; /* dummynet(4) uses numbers instead of names; maybe integrate with pf the same as altq does?! */
2603
        var $qlimit;
2604
        var $description;
2605
	var $qenabled;
2606
	var $link;
2607
	var $qparent; /* link to upper class so we do things easily on WF2Q+ rule creation */
2608
        var $plr;
2609

    
2610
        var $buckets;
2611
        /* mask parameters */
2612
        var $mask;
2613
        var $noerror;
2614

    
2615
        /* Accessor functions */
2616
        function SetLink($link) {
2617
                $this->link = $link;
2618
        }
2619
        function GetLink() {
2620
                return $this->link;
2621
        }
2622
	function Getmask() {
2623
		return $this->mask;
2624
	}
2625
	function SetMask($mask) {
2626
		$this->mask = $mask;
2627
	}
2628
	function &GetParent() {
2629
		return $this->qparent;
2630
	}
2631
	function SetParent(&$parent) {
2632
		$this->qparent = &$parent;
2633
	}
2634
        function GetEnabled() {
2635
                return $this->qenabled;
2636
        }
2637
        function SetEnabled($value) {
2638
                $this->qenabled = $value;
2639
        }
2640
	function CanHaveChildren() {
2641
		return false;
2642
        }
2643
	function CanBeDeleted() {
2644
                return true;
2645
        }
2646
        function GetQname() {
2647
                return $this->qname;
2648
        }
2649
        function SetQname($name) {
2650
                $this->qname = trim($name);
2651
        }
2652
        function GetQlimit() {
2653
                return $this->qlimit;
2654
        }
2655
        function SetQlimit($limit) {
2656
               	$this->qlimit = $limit;
2657
        }
2658
        function GetDescription() {
2659
                return $this->description;
2660
        }
2661
        function SetDescription($str) {
2662
                $this->descritpion = trim($str);
2663
        }
2664
        function GetFirstime() {
2665
                return $this->firsttime;
2666
        }
2667
        function SetFirsttime($number) {
2668
                $this->firsttime = $number;
2669
        }
2670
        function GetBuckets() {
2671
                return $this->buckets;
2672
        }
2673
        function SetBuckets($buckets) {
2674
                $this->buckets = $buckets;
2675
        }
2676
	function SetNumber($number) {
2677
		$this->qnumber = $number;
2678
	}
2679
	function GetNumber() {
2680
		return $this->qnumber;
2681
	}
2682
        function GetPlr() {
2683
                return $this->plr;
2684
        }
2685
        function SetPlr($plr) {
2686
                $this->plr = $plr;
2687
        }
2688

    
2689
	function build_javascript() { return; } /* Do not remove */
2690

    
2691
	function validate_input($data, &$input_errors) {
2692
		$reqdfields[] = "bandwidth";
2693
		$reqdfieldsn[] = "Bandwidth";
2694
		$reqdfields[] = "bandwidthtype";
2695
		$reqdfieldsn[] = "Bandwidthtype";
2696
		$reqdfields[] = "name";
2697
		$reqdfieldsn[] = "Name";
2698
	
2699
		shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
2700

    
2701
		if ($data['plr'] && ((!is_numeric($data['plr'])) ||
2702
			($data['plr'] <= 0 && $data['plr'] > 1))) 
2703
            		$input_errors[] = "Plr must be an integer between 1 and 100.";
2704
		if (($data['buckets'] && (!is_numeric($data['buckets']))) ||
2705
			($data['buckets'] < 1 && $data['buckets'] > 100)) 
2706
            		$input_errors[] = "Buckets must be an integer between 16 and 65535.";
2707
		if ($data['qlimit'] && (!is_numeric($data['qlimit']))) 
2708
            		$input_errors[] = "Queue limit must be an integer";
2709
        	if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['name']))
2710
			$input_errors[] = "Queue names must be alphanumeric and _ or - only.";
2711
	}
2712
}
2713

    
2714
class dnpipe_class extends dummynet_class {
2715
        var $pipe_nr;
2716
        var $delay;
2717
	var $qbandwidth;
2718
	var $qbandwidthtype;
2719

    
2720
		/* This is here to help on form building and building rules/lists */
2721
        var $subqueues = array();
2722

    
2723
	function CanHaveChildren() {
2724
	        return true;
2725
        }
2726
	function SetDelay($delay) {
2727
		$this->delay = $delay;
2728
	}
2729
	function GetDelay() {
2730
		return $this->delay;
2731
	}
2732
	function GetBwscale() {
2733
                return $this->qbandwidthtype;
2734
        }
2735
        function SetBwscale($scale) {
2736
               	$this->qbandwidthtype = $scale;
2737
        }		
2738
	function delete_queue() {
2739
		cleanup_dnqueue_from_rules($this->GetQname());
2740
		foreach ($this->subqueues as $q)
2741
			$q->delete_queue();
2742
		unset_dn_object_by_reference($this->GetLink());
2743
        }
2744
        function GetBandwidth() {
2745
                return $this->qbandwidth;
2746
        }
2747
        function SetBandwidth($bandwidth) {
2748
                $this->qbandwidth = $bandwidth;
2749
        }
2750

    
2751
	function &add_queue($interface, &$queue, &$path, &$input_errors) {
2752

    
2753
		if (!is_array($this->subqueues))
2754
			$this->subqueues = array();
2755
			
2756
		$q =& new dnqueue_class();
2757
		$q->SetLink($path);
2758
		$q->SetEnabled("on");
2759
		$q->SetPipe($this->GetQname());
2760
		$q->SetParent(&$this);
2761
		$q->ReadConfig($queue);
2762
		$q->validate_input($queue, $input_errors);
2763
		if (count($input_errors))
2764
			return $q;
2765
		$this->subqueues[$q->GetQname()] = &$q;
2766
            
2767
		return $q;
2768
	}
2769

    
2770
	function &get_queue_list($q = null) {
2771
		$qlist = array();
2772

    
2773
		$qlist[$this->GetQname()] = $this->GetNumber();
2774
		if (is_array($this->subqueues)) {
2775
			foreach ($this->subqueues as $queue)
2776
				$queue->get_queue_list(&$qlist);
2777
		}
2778
		return $qlist;
2779
	}
2780
		
2781
        /*
2782
         * Should search even its children
2783
         */
2784
        function &find_queue($pipe, $qname) {
2785
                if ($qname == $this->GetQname()) 
2786
                        return $this;
2787
               	foreach ($this->subqueues as $q) {
2788
                       	$result =& $q->find_queue("", $qname);
2789
						if ($result)
2790
                       	        return $result;
2791
               	}
2792
        }
2793

    
2794
	function &find_parentqueue($pipe, $qname) {
2795
		return NULL;
2796
       	}
2797

    
2798
	function validate_input($data, &$input_errors) {
2799
		parent::validate_input($data, $input_errors);
2800

    
2801
		if ($data['bandwidth'] && (!is_numeric($data['bandwidth']))) 
2802
       		     	$input_errors[] = "Bandwidth must be an integer.";
2803
		if ($data['delay'] && (!is_numeric($data['delay'])))
2804
            		$input_errors[] = "Delay must be an integer.";
2805
		}
2806

    
2807
	function ReadConfig(&$q) {
2808
           	$this->SetQname($q['name']);
2809
		$this->SetNumber($q['number']);
2810
		if (isset($q['bandwidth']) && $q['bandwidth'] <> "") { 
2811
			$this->SetBandwidth($q['bandwidth']);
2812
			if (isset($q['bandwidthtype']) && $q['bandwidthtype'])
2813
				$this->SetBwscale($q['bandwidthtype']);
2814
		}
2815
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
2816
              		$this->SetQlimit($q['qlimit']);
2817
		if (isset($q['mask']) && $q['mask'] <> "")
2818
              		$this->SetMask($q['mask']);
2819
		if (isset($q['buckets']) && $q['buckets'] <> "")
2820
              		$this->SetBuckets($q['buckets']);
2821
            	if (isset($q['plr']) && $q['plr'] <> "")
2822
            		$this->SetPlr($q['plr']);
2823
		if (isset($q['delay']) && $q['delay'] <> "")
2824
            		$this->SetDelay($q['delay']);
2825
            	if (isset($q['description']) && $q['description'] <> "")
2826
			$this->SetDescription($q['description']);
2827
		$this->SetEnabled($q['enabled']);
2828

    
2829
        }
2830

    
2831
	function build_tree() {
2832
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $this->GetQname() ."&queue=".$this->GetQname() ."&action=show\">"; 
2833
		$tree .= $this->GetQname() . "</a>";
2834
		if (is_array($this->subqueues)) {
2835
			$tree .= "<ul>";
2836
			foreach ($this->subqueues as $q)  {
2837
				$tree .= $q->build_tree();
2838
			}	
2839
			$tree .= "</ul>";
2840
		}
2841
		$tree .= "</li>";
2842
		
2843
		return $tree;
2844
	}
2845

    
2846
        function build_rules() {
2847
		if ($this->GetEnabled() == "")
2848
			return;
2849

    
2850
       		$pfq_rule = "\ndnpipe ". $this->GetNumber();
2851
		if ($this->GetBandwidth() && $this->GetBwscale())
2852
                    	$pfq_rule .= " bandwidth ".trim($this->GetBandwidth()).$this->GetBwscale();
2853
		if ($this->GetQlimit())
2854
                    	$pfq_rule .= " queue " . $this->GetQlimit();
2855
		if ($this->GetPlr())
2856
			$pfq_rule .= " plr " . $this->GetPlr();
2857
		if ($this->GetBuckets())
2858
			$pfq_rule .= " buckets " . $this->GetBuckets();
2859
		if ($this->GetDelay())
2860
			$pfq_rule .= " delay " . $this->GetDelay();
2861

    
2862
		$mask = $this->GetMask();
2863
		if (!empty($mask)) {
2864
			/* XXX TODO extend this to support more complicated masks */
2865
			switch ($mask) {
2866
			case 'srcaddress':
2867
				$pfq_rule .= " mask src-ip 0xffffffff ";
2868
				break;
2869
			case 'dstaddress':
2870
				$pfq_rule .= " mask dst-ip 0xffffffff ";
2871
				break;
2872
			default:
2873
				break;
2874
			}
2875
			$pfq_rule .= "\n";
2876

    
2877
			if (!empty($this->subqueues) && count($this->subqueues) > 0) {
2878
       			        foreach ($this->subqueues as $q)
2879
				$pfq_rule .= $q->build_rules();
2880
               		}
2881
    		}            
2882
		$pfq_rule .= " \n";
2883

    
2884
		return $pfq_rule;
2885
        }
2886

    
2887
	function update_dn_data(&$data) { 
2888
		$this->ReadConfig($data);
2889
	}
2890

    
2891
        function build_form() { 
2892
		$form = "<tr><td valign=\"top\" class=\"vncellreq\"><br><span class=\"vexpl\">Name</span></td>";
2893
		$form .= "<td class=\"vncellreq\">";
2894
		$form .= "<input type=\"text\" id=\"name\" name=\"name\" value=\"";
2895
		$form .= $this->GetQname()."\">";
2896
		$form .= "</td></tr>";
2897
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Bandwidth";
2898
		$form .= "</td><td class=\"vncellreq\">";
2899
		$form .= "<input type=\"text\" id=\"bandwidth\" name=\"bandwidth\" value=\"";
2900
		$form .= $this->GetBandwidth() . "\">"; 
2901
		$form .= "<select id=\"bandwidthtype\" name=\"bandwidthtype\" class=\"formselect\">";
2902
		$form .= "<option value=\"Kb\"";
2903
		if ($this->GetBwscale() == "Kb")
2904
			$form .= " selected=\"yes\"";
2905
		$form .= ">Kbit/s</option>";
2906
		$form .= "<option value=\"Mb\"";
2907
		if ($this->GetBwscale() == "Mb")
2908
			$form .= " selected=\"yes\"";
2909
		$form .= ">Mbit/s</option>";
2910
		$form .= "<option value=\"Gb\"";
2911
		if ($this->GetBwscale() == "Gb")
2912
			$form .= " selected=\"yes\"";
2913
		$form .= ">Gbit/s</option>";		
2914
		$form .= "<option value=\"\"";
2915
		if ($this->GetBwscale() == "b")
2916
			$form .= " selected=\"yes\"";
2917
		$form .= ">Bit/s</option>";
2918
		$form .= "</select>";
2919
		$form .= "</td></tr>";
2920
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Mask</td>";
2921
		$form .= "<td class=\"vncellreq\">";
2922
		$form .= "<select name=\"mask\" class=\"formselect\">";
2923
		$form .= "<option value=\"none\"";
2924
		if ($this->GetMask() == "none")
2925
			$form .= " selected=\"yes\"";
2926
		$form .= ">none</option>";
2927
		$form .= "<option value=\"srcaddress\"";
2928
		if ($this->GetMask() == "srcaddress")
2929
			$form .= " selected=\"yes\"";
2930
		$form .= ">Source addresses</option>";
2931
		$form .= "<option value=\"dstaddress\"";
2932
		if ($this->GetMask() == "dstaddress")
2933
			$form .= " selected=\"yes\"";
2934
		$form .= ">Destination addresses</option>";
2935
		$form .= "</select>";
2936
		$form .= "&nbsp;<br>";
2937
		$form .= "<span class=\"vexpl\">If 'source' or 'destination' is chosen, \n";
2938
		$form .= "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n";
2939
		$form .= "be created for each source/destination IP address encountered, \n";
2940
		$form .= "respectively. This makes it possible to easily specify bandwidth \n";
2941
		$form .= "limits per host.</span>";
2942
		$form .= "</td></tr>";
2943
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Description</td>";
2944
		$form .= "<td class=\"vncellreq\">";
2945
		$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"50%\" id=\"description\" name=\"description\" value=\"";
2946
		$form .= $this->GetDescription();
2947
		$form .= "\">";
2948
		$form .= "<br> <span class=\"vexpl\">";
2949
		$form .= "You may enter a description here ";
2950
		$form .= "for your reference (not parsed).</span>";
2951
		$form .= "</td></tr>";
2952
      		$form .= "<tr id=\"sprtable4\" name=\"sprtable4\">";
2953
		$form .= "<td></td>";
2954
                $form .= "<td><div id=\"showadvancedboxspr\">";
2955
                $form .= "<p><input type=\"button\" onClick=\"show_source_port_range()\"";
2956
		$form .= " value=\"Show advanced options\"></input></a>";
2957
                $form .= "</div></td></tr>";
2958
                $form .= "<tr style=\"display:none\" id=\"sprtable\" name=\"sprtable\">";
2959

    
2960
		$form .= "<td valign=\"top\" class=\"vncellreq\">Delay</td>";
2961
		$form .= "<td valign=\"top\" class=\"vncellreq\">";
2962
		$form .= "<input name=\"delay\" type=\"text\" id=\"delay\" size=\"5\" value=\"";
2963
		$form .= $this->GetDelay() . "\">";
2964
		$form .= "&nbsp;ms<br> <span class=\"vexpl\">Hint: in most cases, you "; 
2965
		$form .= "should specify 0 here (or leave the field empty)</span>";
2966
		$form .= "</td></tr><br/>";
2967
      		$form .= "<tr style=\"display:none\" id=\"sprtable1\" name=\"sprtable1\">";
2968
		$form .= "<td valign=\"top\" class=\"vncellreq\">Packet loss rate</td>";
2969
		$form .= "<td valign=\"top\" class=\"vncellreq\">";
2970
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
2971
		$form .= $this->GetPlr() . "\">";
2972
		$form .= "&nbsp;<br> <span class=\"vexpl\">Hint: in most cases, you "; 
2973
        	$form .= "should specify 0 here (or leave the field empty).";
2974
		$form .= "A value of 0.001 means one packet in 1000 gets dropped</span>";
2975
		$form .= "</td></tr>";
2976
		$form .= "<tr style=\"display:none\" id=\"sprtable2\" name=\"sprtable2\">";
2977
		$form .= "<td valign=\"top\" class=\"vncellreq\">Queue Size</td>";
2978
		$form .= "<td class=\"vncellreq\">";
2979
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
2980
		$form .= $this->GetQlimit() . "\">";
2981
		$form .= "&nbsp;slots<br>";
2982
		$form .= "<span class=\"vexpl\">Hint: in most cases, you ";
2983
		$form .= "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first,";
2984
	        $form .= "then they are delayed by value specified in the Delay field, and then they ";
2985
		$form .= "are delivered to their destination.</span>";
2986
		$form .= "</td></tr>";
2987
		$form .= "<tr style=\"display:none\" id=\"sprtable5\" name=\"sprtable5\">";
2988
                $form .= "<td valign=\"top\" class=\"vncellreq\">Bucket Size</td>";
2989
                $form .= "<td class=\"vncellreq\">";
2990
                $form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
2991
                $form .= $this->GetBuckets() . "\">";
2992
                $form .= "&nbsp;slots<br>";
2993
                $form .= "<span class=\"vexpl\">Hint: in most cases, you ";
2994
                $form .= "should leave the field empty. It increases the hash size set.";
2995
                $form .= "</td></tr>";
2996

    
2997
		return $form;
2998
			
2999
		}
3000

    
3001
	function wconfig() {
3002
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3003
            	if (!is_array($cflink))
3004
            		$cflink = array();
3005
		$cflink['name'] = $this->GetQname();
3006
		$cflink['number'] = $this->GetNumber();
3007
            	$cflink['qlimit'] = $this->GetQlimit();
3008
            	$cflink['plr'] = $this->GetPlr();
3009
            	$cflink['description'] = $this->GetDescription();
3010
		$cflink['bandwidth'] = $this->GetBandwidth();
3011
            	$cflink['bandwidthtype'] = $this->GetBwscale();
3012
		$cflink['enabled'] = $this->GetEnabled();
3013
		$cflink['buckets'] = $this->GetBuckets();
3014
		$cflink['mask'] = $this->GetMask();
3015
		$cflink['delay'] = $this->GetDelay();
3016
	}
3017

    
3018
}
3019

    
3020
class dnqueue_class extends dummynet_class {
3021
        var $pipeparent;
3022
        var $weight;
3023

    
3024
        function GetWeight() {
3025
                return $this->weight;
3026
        }
3027
        function SetWeight($weight) {
3028
                $this->weight = $weight;
3029
        }
3030
	function GetPipe() {
3031
		return $this->pipeparent;
3032
	}
3033
	function SetPipe($pipe) {
3034
		$this->pipeparent = $pipe;
3035
	}
3036

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

    
3040
	function delete_queue() {
3041
		cleanup_dnqueue_from_rules($this->GetQname());
3042
		unset_dn_object_by_reference($this->GetLink());
3043
        }
3044

    
3045
	function validate_input($data, &$input_errors) {
3046
		parent::validate_input($data, $input_errors);
3047

    
3048
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3049
			($data['weight'] < 1 && $data['weight'] > 100))) 
3050
       		     	$input_errors[] = "Weight must be an integer between 1 and 100.";
3051
	}
3052

    
3053
        /*
3054
         * Should search even its children
3055
         */
3056
        function &find_queue($pipe, $qname) {
3057
                if ($qname == $this->GetQname()) 
3058
                	return $this;
3059
		else
3060
			return NULL;
3061
        }
3062

    
3063
	function &find_parentqueue($pipe, $qname) {
3064
		return $this->qparent;
3065
        }
3066

    
3067
        function &get_queue_list(&$qlist) {
3068
        	$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3069
        }		
3070

    
3071
	function ReadConfig(&$q) {
3072
          	$this->SetQname($q['name']);
3073
		$this->SetNumber($q['number']);
3074
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
3075
       		       	$this->SetQlimit($q['qlimit']);
3076
		if (isset($q['mask']) && $q['mask'] <> "")
3077
              		$this->SetMask($q['mask']);
3078
       		if (isset($q['weight']) && $q['weight'] <> "")
3079
            		$this->SetWeight($q['weight']);
3080
            	if (isset($q['descritption']) && $q['description'] <> "")
3081
			$this->SetDescription($q['description']);
3082
		$this->SetEnabled($q['enabled']);
3083
        }
3084

    
3085
	function build_tree() {
3086
		$parent =& $this->GetParent();
3087
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&queue=" . $this->GetQname() ."&action=show\">"; 
3088
		$tree .= $this->GetQname() . "</a>";
3089
		$tree .= "</li>";
3090
		
3091
		return $tree;
3092
	}
3093

    
3094
        function build_rules() {
3095
		if ($this->GetEnabled() == "")
3096
			return; 
3097

    
3098
		$parent =& $this->GetParent();
3099
            	$pfq_rule = "dnqueue ". $this->GetNumber() . " dnpipe " . $parent->GetNumber();
3100
		if ($this->GetQlimit())
3101
                    	$pfq_rule .= " queue " . $this->GetQimit();
3102
		if ($this->GetWeight())
3103
			$pfq_rule .= " weight " . $this->GetWeight();
3104
		if ($this->GetBuckets())
3105
			$pfq_rule .= " buckets " . $this->GetBuckets();
3106
		$mask = $this->GetMask();
3107
		if (!empty($mask)) {
3108
			/* XXX TODO extend this to support more complicated masks */
3109
			switch ($mask) {
3110
			case 'srcaddress':
3111
				$pfq_rule .= " mask src-ip 0xffffffff ";
3112
				break;
3113
			case 'dstaddress':
3114
				$pfq_rule .= " mask dst-ip 0xffffffff ";
3115
				break;
3116
			default:
3117
				break;
3118
			}
3119
			$pfq_rule .= "\n";
3120
		}
3121

    
3122
		return $pfq_rule;
3123
	}
3124

    
3125
        function build_form() { 
3126
		$form = "<tr><td valign=\"top\" class=\"vncellreq\"><br><span class=\"vexpl\">Name</span></td>";
3127
		$form .= "<td class=\"vncellreq\">";
3128
		$form .= "<input type=\"text\" id=\"name\" name=\"name\" value=\"";
3129
		$form .= $this->GetQname()."\">";
3130
		$form .= "</td></tr>";
3131
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Mask</td>";
3132
		$form .= "<td class=\"vncellreq\">";
3133
		$form .= "<select name=\"mask\" class=\"formselect\">";
3134
		$form .= "<option value=\"none\"";
3135
		if ($this->GetMask() == "none")
3136
			$form .= " selected=\"yes\"";
3137
		$form .= ">none</option>";
3138
		$form .= "<option value=\"srcaddress\"";
3139
		if ($this->GetMask() == "srcaddress")
3140
			$form .= " selected=\"yes\"";
3141
		$form .= ">Source addresses</option>";
3142
		$form .= "<option value=\"dstaddress\"";
3143
		if ($this->GetMask() == "dstaddress")
3144
			$form .= " selected=\"yes\"";
3145
		$form .= ">Destination addresses</option>";
3146
		$form .= "</select>";
3147
		$form .= "&nbsp;slots<br>";
3148
		$form .= "<span class=\"vexpl\">If 'source' or 'destination' is chosen, \n";
3149
		$form .= "a dynamic pipe with the bandwidth, delay, packet loss and queue size given above will \n";
3150
		$form .= "be created for each source/destination IP address encountered, \n";
3151
		$form .= "respectively. This makes it possible to easily specify bandwidth \n";
3152
		$form .= "limits per host.</span>";
3153
		$form .= "</td></tr>";
3154
		$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Description</td>";
3155
		$form .= "<td class=\"vncellreq\">";
3156
		$form .= "<input type=\"text\" id=\"description\" class=\"formfld unknown\" size=\"50%\" name=\"description\" value=\"";
3157
		$form .= $this->GetDescription();
3158
		$form .= "\">";
3159
		$form .= "<br> <span class=\"vexpl\">";
3160
		$form .= "You may enter a description here ";
3161
		$form .= "for your reference (not parsed).</span>";
3162
		$form .= "</td></tr>";
3163
		$form .= "<tr id=\"sprtable4\" name=\"sprtable4\">";
3164
		$form .= "<td></td>";
3165
                $form .= "<td><div id=\"showadvancedboxspr\">";
3166
                $form .= "<p><input type=\"button\" onClick=\"show_source_port_range()\"";
3167
		$form .= " value=\"Show advanced options\"></input></a>";
3168
                $form .= "</div></td></tr>";
3169
		$form .= "<tr style=\"display:none\" id=\"sprtable\" name=\"sprtable\">";
3170
		$form .= "<td valign=\"top\" class=\"vncellreq\">Weight</td>";
3171
		$form .= "<td valign=\"top\" class=\"vncellreq\">";
3172
		$form .= "<input name=\"weight\" type=\"text\" id=\"weight\" size=\"5\" value=\"";
3173
		$form .= $this->GetWeight() . "\">";
3174
		$form .= "&nbsp;ms<br> <span class=\"vexpl\">Hint: For queues under the same parent "; 
3175
		$form .= "this specifies the share that a queue gets(values range from 1 to 100, you can leave it blank otherwise)</span>";
3176
		$form .= "</td></tr>";
3177
		$form .= "<tr style=\"display:none\" id=\"sprtable1\" name=\"sprtable1\">";
3178
		$form .= "<td valign=\"top\" class=\"vncellreq\">Packet loss rate</td>";
3179
		$form .= "<td valign=\"top\" class=\"vncellreq\">";
3180
		$form .= "<input name=\"plr\" type=\"text\" id=\"plr\" size=\"5\" value=\"";
3181
		$form .= $this->GetPlr() . "\">";
3182
		$form .= "&nbsp;<br> <span class=\"vexpl\">Hint: in most cases, you "; 
3183
        	$form .= "should specify 0 here (or leave the field empty).";
3184
		$form .= "A value of 0.001 means one packet in 1000 gets dropped</span>";
3185
		$form .= "</td></tr>";
3186
		$form .= "<tr style=\"display:none\" id=\"sprtable2\" name=\"sprtable2\">";
3187
		$form .= "<td valign=\"top\" class=\"vncellreq\">Queue Size</td>";
3188
		$form .= "<td class=\"vncellreq\">";
3189
		$form .= "<input type=\"text\" id=\"qlimit\" name=\"qlimit\" value=\"";
3190
		$form .= $this->GetQlimit() . "\">";
3191
		$form .= "&nbsp;slots<br>";
3192
		$form .= "<span class=\"vexpl\">Hint: in most cases, you ";
3193
		$form .= "should leave the field empty. All packets in this pipe are placed into a fixed-size queue first, ";
3194
        	$form .= "then they are delayed by value specified in the Delay field, and then they ";
3195
		$form .= "are delivered to their destination.</span>";
3196
		$form .= "</td></tr>";
3197
		$form .= "<tr style=\"display:none\" id=\"sprtable5\" name=\"sprtable5\">";
3198
                $form .= "<td valign=\"top\" class=\"vncellreq\">Bucket Size</td>";
3199
                $form .= "<td class=\"vncellreq\">";
3200
                $form .= "<input type=\"text\" id=\"buckets\" name=\"buckets\" value=\"";
3201
                $form .= $this->GetBuckets() . "\">";
3202
                $form .= "&nbsp;slots<br>";
3203
                $form .= "<span class=\"vexpl\">Hint: in most cases, you ";
3204
                $form .= "should leave the field empty. It increases the hash size set.";
3205
                $form .= "</td></tr>";
3206

    
3207
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3208
		$form .= " value=\"" . $this->GetPipe() . "\">";
3209

    
3210
		return $form;
3211
			
3212
	}
3213

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

    
3218
	function wconfig() {
3219
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3220
            	if (!is_array($cflink))
3221
            		$cflink = array();
3222
		$cflink['name'] = $this->GetQname();
3223
		$cflink['number'] = $this->GetNumber();
3224
            	$cflink['qlimit'] = $this->GetQlimit();
3225
            	$cflink['description'] = $this->GetDescription();
3226
		$cflink['weight'] = $this->GetWeight();
3227
		$cflink['enabled'] = $this->GetEnabled();
3228
		$cflink['buckets'] = $this->GetBuckets();
3229
		$cflink['mask'] = $this->GetMask();
3230
	}
3231
}
3232

    
3233
// List of layer7 objects
3234
$layer7_rules_list = array();
3235

    
3236
class layer7 {
3237
    
3238
    var $rname; //alias
3239
    var $rdescription; //alias description
3240
    var $rport; //divert port
3241
    var $renabled; //rule enabled
3242
    var $rsets = array(); //array of l7 associations
3243
    
3244
    // Auxiliary functions
3245
    
3246
    function GetRName() {
3247
        return $this->rname;
3248
    }
3249
    function SetRName($rname) {
3250
        $this->rname = $rname;
3251
    }
3252
    function GetRDescription() {
3253
        return $this->rdescription;
3254
    }
3255
    function SetRDescription($rdescription) {
3256
        $this->rdescription = $rdescription;
3257
    }
3258
    function GetRPort() {
3259
        return $this->rport;
3260
    }
3261
    function SetRPort($rport) {
3262
        $this->rport = $rport;
3263
    }
3264
    function GetREnabled() {
3265
        return $this->renabled;
3266
    }
3267
    function SetREnabled($value) {
3268
        $this->renabled = $value;
3269
    }
3270
    function GetRl7() {
3271
        return $this->rsets;
3272
    }
3273
    function SetRl7($rsets) {
3274
        $this->rsets = $rsets;
3275
    }
3276
    
3277
    //Add a tuple (rule,sctructure,element) to the $rsets
3278
    
3279
    function add_rule($l7set) {
3280
        $this->rsets[] = $l7set;
3281
    }
3282
    
3283
    // Build the layer7 rules
3284
    function build_l7_rules() {
3285
        if($this->GetREnabled() == "") {
3286
            return;
3287
        }
3288
        //$l7rules = "#" . $this->rdescription . "\n";
3289
        foreach ($this->rsets as $rl7) {
3290
            $l7rules .= $rl7->build_rules();
3291
        }
3292
        return $l7rules;
3293
    }
3294
    
3295
    // Read the config from array
3296
    function ReadConfig(&$qname, &$q) {
3297
        $this->SetRName($qname);
3298
        $this->SetREnabled($q['enabled']);
3299
        $this->SetRPort($q['divert_port']);
3300
        if(isset($q['description']) && $q['description'] <> "")
3301
            $this->SetRDescription($q['description']);
3302
        $rsets = $q['l7rules'];
3303
        //Put individual rules in the array
3304
	if(is_array($rsets)) {
3305
	    foreach($rsets as $l7r) {
3306
	        $l7obj = new l7rule();
3307
	        $l7obj->SetRProtocol($l7r['protocol']);
3308
	        $l7obj->SetRStructure($l7r['structure']);
3309
	        $l7obj->SetRBehaviour($l7r['behaviour']);
3310
	        $this->add_rule($l7obj);
3311
	    }
3312
	}
3313
    }
3314
    
3315
    //Generate a random port for the divert socket
3316
    function gen_divert_port() {
3317
        $dports = get_divert_ports(); //array of used ports
3318
        $divert_port = rand(40000, 60000);
3319
        while(true) {
3320
            foreach($dports as $dport) {
3321
                $dupe = false;
3322
                if($dport == $divert_port) {
3323
                    $divert_port = rand(40000, 60000);
3324
                    $dupe = true;
3325
                    break;
3326
                }
3327
            }
3328
            if(!$dupe) {
3329
                break;
3330
            }
3331
        }
3332
        return $divert_port;
3333
    }
3334
    
3335
    //Helps building the left tree
3336
    function build_tree() {
3337
        $tree = " <li><a href=\"firewall_shaper_layer7.php?container=" . $this->GetRName() ."&action=show\">"; 
3338
        $tree .= $this->GetRName() . "</a>";
3339
	$tree .= "</li>";
3340
		
3341
	return $tree;
3342
    }
3343
    
3344
    function build_form() {
3345
        $form = "<tr><td valign=\"top\" class=\"vncellreq\"><br>";
3346
	$form .= "Enable/Disable";
3347
	$form .= "</td><td class=\"vncellreq\">";
3348
	$form .= " <input type=\"checkbox\" id=\"enabled\" name=\"enabled\"";
3349
	if ($this->GetREnabled()) {
3350
       	    $form .=  "checked = \"CHECKED\"";
3351
	}
3352
	$form .= " ><span class=\"vexpl\"> Enable/Disable layer7 Container</span>";
3353
	$form .= "</td></tr>";
3354
        $form .= "<tr><td valign=\"top\" class=\"vncellreq\"><br><span class=\"vexpl\">Name</span></td>";
3355
	$form .= "<td class=\"vncellreq\">";
3356
	$form .= "<input type=\"text\" id=\"container\" name=\"container\" value=\"";
3357
	$form .= $this->GetRName()."\">";
3358
	$form .= "</td></tr>";
3359
	$form .= "<tr><td valign=\"top\" class=\"vncellreq\">Description</td>";
3360
	$form .= "<td class=\"vncellreq\">";
3361
	$form .= "<input type=\"text\" class=\"formfld unknown\" size=\"50%\" id=\"description\" name=\"description\" value=\"";
3362
	$form .= $this->GetRDescription();
3363
	$form .= "\">";
3364
	$form .= "<br> <span class=\"vexpl\">";
3365
	$form .= "You may enter a description here ";
3366
	$form .= "for your reference (not parsed).</span>";
3367
	$form .= "</td></tr>";
3368
	
3369
	return $form;
3370
    }
3371
    
3372
    //Write the setting to the $config array
3373
    function wconfig() {
3374
	global $config;
3375
	
3376
	if(!is_array($config['l7shaper']['container'])) {
3377
		$config['l7shaper']['container'] = array();
3378
	}
3379
        //
3380
        $cflink =& get_l7c_reference_to_me_in_config($this->GetRName());
3381
	// Test if this rule does exists already
3382
	if(!$cflink) {
3383
		$cflink =& $config['l7shaper']['container'][];
3384
	}
3385
	$cflink['name'] = $this->GetRName();
3386
        $cflink['enabled'] = $this->GetREnabled();
3387
        $cflink['description'] = $this->GetRDescription();
3388
        $cflink['divert_port'] = $this->GetRPort();
3389
        
3390
	//Destroy previously existent rules
3391
	if(is_array($cflink['rules'])) {
3392
		unset($cflink['l7rules']);
3393
	}
3394
	
3395
        $cflink['l7rules'] = array();
3396
	
3397
        $i = 0;
3398
        foreach($this->rsets as $rulel7) {
3399
            $cflink['l7rules'][$i]['protocol'] = $rulel7->GetRProtocol();
3400
            $cflink['l7rules'][$i]['structure'] = $rulel7->GetRStructure();
3401
            $cflink['l7rules'][$i]['behaviour'] = $rulel7->GetRBehaviour();
3402
            $i++;
3403
        }
3404
    }
3405
    
3406
    //This function is necessary to help producing the overload options for keep state
3407
    function get_unique_structures() {
3408
        
3409
        $unique_structures = array("action" => false, "dummynet" => false, "altq" => false);
3410
        foreach($this->rsets as $l7rule) {
3411
		if($l7rule->GetRStructure() == "action")
3412
			$unique_structures['action'] = true;
3413
		else if($l7rule->GetRStructure() == "limiter")
3414
			$unique_structures['dummynet'] = true;
3415
		else
3416
			$unique_structures['altq'] = true;
3417
        }
3418
	//Delete non used structures so we don't have to check this in filter.inc
3419
	foreach($unique_structures as $key => $value)
3420
		if(!$value)
3421
			unset($unique_structures[$key]);
3422
        return $unique_structures;
3423
    }
3424
    
3425
    function validate_input($data, &$input_errors) {
3426
	$reqdfields[] = "container";
3427
	$reqdfieldsn[] = "Name";
3428
		
3429
	shaper_do_input_validation($data, $reqdfields, $reqdfieldsn, $input_errors);
3430
        
3431
        if (!preg_match("/^[a-zA-Z0-9_-]+$/", $data['container']))
3432
            $input_errors[] = "Queue names must be alphanumeric and _ or - only.";
3433
    }
3434
    
3435
    function delete_l7c() {
3436
	$l7pid = `/bin/ps -ax | /usr/bin/grep ipfw-classifyd | /usr/bin/grep ". $l7rules->GetRPort() . " | /usr/bin/grep -v grep | /usr/bin/awk '{ print $1 }'`;
3437
	mwexec("/bin/kill {$l7pid}");
3438
	unset_l7_object_by_reference($this->GetRName());
3439
	cleanup_l7_from_rules($this->GetRName());
3440
    }
3441
}
3442

    
3443
class l7rule {
3444
    
3445
    var $rprotocol; //protocol
3446
    var $rstructure; //action, limiter, queue
3447
    var $rbehaviour; //allow, block, queue_name, pipe_number ...
3448
    
3449
    //Auxiliary Functions
3450
    
3451
    function GetRProtocol() {
3452
        return $this->rprotocol;
3453
    }
3454
    function SetRProtocol($rprotocol) {
3455
        $this->rprotocol = $rprotocol;
3456
    }
3457
    function GetRStructure() {
3458
        return $this->rstructure;
3459
    }
3460
    function SetRStructure($rstructure) {
3461
        $this->rstructure = $rstructure;
3462
    }
3463
    function GetRBehaviour() {
3464
        return $this->rbehaviour;
3465
    }
3466
    function SetRBehaviour($rbehaviour) {
3467
        $this->rbehaviour = $rbehaviour;
3468
    }
3469
    
3470
    //XXX Do we need to test any particularity for AltQ queues?
3471
    function build_rules() {
3472
	global $dummynet_pipe_list;
3473
	switch ($this->GetRStructure()) {
3474
		case "limiter":
3475
			read_dummynet_config();
3476
			$dn_list =& get_unique_dnqueue_list();
3477
			$found = false;
3478
			if(is_array($dn_list)) {
3479
				foreach($dn_list as $key => $value) {
3480
					if($key == $this->GetRBehaviour()) {
3481
						if($value[0] == "?")
3482
							$l7rule = $this->GetRProtocol() . " = dnqueue " . substr($value, 1) . "\n";
3483
						else
3484
							$l7rule = $this->GetRProtocol() . " = dnpipe " . $value . "\n";
3485
						$found = true;
3486
					}
3487
					if($found)
3488
						break;
3489
				}
3490
			}
3491
			break;
3492
		default: //This is for action and for altq
3493
			$l7rule = $this->GetRProtocol() . " = " . $this->GetRStructure() . " " . $this->GetRBehaviour() . "\n";
3494
			break;
3495
	}
3496
        return $l7rule;
3497
    }
3498
}
3499

    
3500
/*
3501
 * This function allows to return an array with all the used divert socket ports
3502
 */
3503
function get_divert_ports() {
3504
    global $layer7_rules_list;
3505
    $dports = array();
3506
    
3507
    foreach($layer7_rules_list as $l7r)
3508
        $dports[] = $l7r->GetRPort();
3509
    
3510
    return $dports;
3511
}
3512

    
3513
function &get_l7c_reference_to_me_in_config(&$name) {
3514
	global $config;
3515
	
3516
	$ptr = NULL;
3517
	
3518
	if(is_array($config['l7shaper']['container'])) {
3519
		foreach($config['l7shaper']['container'] as $key => $value) {
3520
			if($value['name'] == $name)
3521
				$ptr =& $config['l7shaper']['container'][$key];
3522
		}
3523
	}	
3524
	return $ptr;
3525
// $ptr can be null. has to be checked later
3526
}
3527

    
3528
function unset_l7_object_by_reference(&$name) {
3529
	global $config;
3530
        
3531
	if(is_array($config['l7shaper']['container'])) {
3532
		foreach($config['l7shaper']['container'] as $key => $value) {
3533
			if($value['name'] == $name) {
3534
				unset($config['l7shaper']['container'][$key]['l7rules']);
3535
				unset($config['l7shaper']['container'][$key]);
3536
				break;
3537
			}
3538
		}
3539
	}
3540
}
3541

    
3542
function read_layer7_config() {
3543
    global $layer7_rules_list, $config;
3544
    
3545
    $l7cs = &$config['l7shaper']['container'];
3546
    
3547
    $layer7_rules_list = array();
3548
    
3549
    if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container']))
3550
	return;
3551
    
3552
    foreach ($l7cs as $conf) {
3553
	if (empty($conf['name']))
3554
		continue; /* XXX: grrrrrr at php */ 
3555
        $root =& new layer7();
3556
        $root->ReadConfig($conf['name'],$conf);
3557
        $layer7_rules_list[$root->GetRName()] = &$root;
3558
    }
3559
}
3560

    
3561
function generate_layer7_files() {
3562
    global $layer7_rules_list;
3563
    
3564
    read_layer7_config();
3565
    
3566
    if (!empty($layer7_rules_list)) {
3567
	if (!is_module_loaded("ipdivert.ko"))
3568
		mwexec("/sbin/kldload ipdivert.ko");
3569

    
3570
	mwexec("rm -f /tmp/*.l7");
3571
    }
3572
    
3573
    foreach($layer7_rules_list as $l7rules) {
3574
        if($l7rules->GetREnabled()) {
3575
            $filename = $l7rules->GetRName() . ".l7";
3576
            $path = "/tmp/" . $filename;
3577
        
3578
            $rules = $l7rules->build_l7_rules();
3579
        
3580
            $fp = fopen($path,'w');
3581
            fwrite($fp,$rules);
3582
            fclose($fp);
3583
        }
3584
    }
3585
}
3586

    
3587
function layer7_start_l7daemon() {
3588
    global $layer7_rules_list;
3589

    
3590
    /*
3591
     * XXX: ermal - Needed ?!
3592
     * read_layer7_config();
3593
     */
3594

    
3595
    foreach($layer7_rules_list as $l7rules) {
3596
        if($l7rules->GetREnabled()) {
3597
            $filename = $l7rules->GetRName() . ".l7";
3598
            $path = "/tmp/" . $filename;
3599

    
3600
	    unset($l7pid);
3601
	    /* Only reread the configuration rather than restart to avoid loosing information. */
3602
	    exec("/bin/ps -ax | /usr/bin/grep ipfw-classifyd | /usr/bin/grep ". $l7rules->GetRPort() . " | /usr/bin/grep -v grep | /usr/bin/awk '{ print $1}'", $l7pid);
3603
	    if (count($l7pid) > 0) {
3604
		log_error("Sending HUP signal to {$l7pid[0]}");
3605
		mwexec("/bin/kill -HUP {$l7pid[0]}");
3606
	    } else {
3607
		// XXX: Hardcoded number of packets to garbage collect and queue length..
3608
		$ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 5 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
3609
		mwexec_bg($ipfw_classifyd_init);
3610
	    }
3611
        }
3612
    }
3613
}
3614

    
3615
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
3616
function generate_protocols_array() {
3617
	$protocols = return_dir_as_array("/usr/local/share/protocols");
3618
	if(is_array($protocols)) {
3619
		foreach($protocols as $key => $proto)
3620
			$protocols[$key] =& str_replace(".pat", "", $proto);
3621
		sort($protocols);
3622
	}		
3623
	return $protocols;
3624
}
3625

    
3626
function get_l7_unique_list() {
3627
	global $layer7_rules_list;
3628
	
3629
	$l7list = array();
3630
	if(is_array($layer7_rules_list)) 
3631
		foreach($layer7_rules_list as $l7c)
3632
			if($l7c->GetREnabled())
3633
				$l7list[] = $l7c->GetRName();
3634
	
3635
	return $l7list;
3636
}
3637

    
3638
// Disable a removed l7 container from the filter
3639
function cleanup_l7_from_rules(&$name) {
3640
	global $config;
3641

    
3642
	if(is_array($config['filter']['rule']))
3643
		foreach ($config['filter']['rule'] as $key => $rule) {
3644
			if ($rule['l7container'] == $name)
3645
				unset($config['filter']['rule'][$key]['l7container']);
3646
		}
3647
}
3648

    
3649
function get_dummynet_name_list() {
3650
	
3651
	$dn_name_list =& get_unique_dnqueue_list();
3652
	$dn_name = array();
3653
	if(is_array($dn_name_list))
3654
		foreach($dn_name_list as $key => $value)
3655
			$dn_name[] = $key;
3656
	
3657
	return $dn_name;
3658
	
3659
}
3660

    
3661
function get_altq_name_list() {
3662
	$altq_name_list =& get_unique_queue_list();
3663
	$altq_name = array();
3664
	if(is_array($altq_name_list))
3665
		foreach($altq_name_list as $key => $aqobj)
3666
			$altq_name[] = $key;
3667
		
3668
	return $altq_name;
3669
}
3670

    
3671
/*
3672
 * XXX: TODO Make a class shaper to hide all these function
3673
 * from the global namespace.
3674
 */
3675

    
3676
/* 
3677
 * This is a layer violation but for now there is no way 
3678
 * i can find to properly do this with PHP.
3679
 */
3680
function altq_set_default_queue($interface, $value) {
3681
	global $altq_list_queues;
3682
		
3683
	$altq_tmp =& $altq_list_queues[$interface];
3684
	if ($altq_tmp) {
3685
		if ($value) {
3686
			$altq_tmp->SetDefaultQueuePresent("true");
3687
		}
3688
		else {
3689
			$altq_tmp->SetDefaultQueuePresent("false");
3690
		}
3691
	}
3692
}
3693

    
3694
function altq_get_default_queue($interface) {
3695
	global $altq_list_queues;
3696

    
3697
	$altq_tmp = $altq_list_queues[$interface];
3698
	if ($altq_tmp)  
3699
		return $altq_tmp->GetDefaultQueuePresent(); 
3700
}
3701

    
3702
function altq_check_default_queues() {
3703
	global $altq_list_queues;
3704

    
3705
	$count = 0;
3706
	if (is_array($altq_list_queues)) {
3707
		foreach($altq_list_queues as $altq) {
3708
			if ($altq->GetDefaultQueuePresent())
3709
				$count++;
3710
		}
3711
	}
3712
	else  $count++;;
3713
	
3714
	return 0;
3715
}
3716

    
3717
function &get_unique_queue_list() {
3718
	global $altq_list_queues;
3719
	
3720
	$qlist = array();
3721
	if (is_array($altq_list_queues)) {
3722
		foreach ($altq_list_queues as $altq) {
3723
			$tmplist =& $altq->get_queue_list();
3724
			foreach ($tmplist as $qname => $link)
3725
				$qlist[$qname] = $link;	
3726
		}
3727
	}
3728
	return $qlist;
3729
}
3730

    
3731
function &get_unique_dnqueue_list() {
3732
	global $dummynet_pipe_list;
3733
	
3734
	$qlist = array();
3735
	if (is_array($dummynet_pipe_list)) {
3736
		foreach ($dummynet_pipe_list as $dn) {
3737
			$tmplist =& $dn->get_queue_list();
3738
			foreach ($tmplist as $qname => $link)
3739
				$qlist[$qname] = $link;	
3740
		}
3741
	}
3742
	return $qlist;
3743
}
3744

    
3745
function ref_on_altq_queue_list($parent, $qname) {
3746
	if (isset($GLOBALS['queue_list'][$qname]))
3747
		$GLOBALS['queue_list'][$qname]++;
3748
	else
3749
		$GLOBALS['queue_list'][$qname] = 1;
3750

    
3751
	unref_on_altq_queue_list($parent);
3752
}
3753

    
3754
function unref_on_altq_queue_list($qname) {
3755
	$GLOBALS['queue_list'][$qname]--;
3756
	if ($GLOBALS['queue_list'][$qname] <= 1)
3757
		unset($GLOBALS['queue_list'][$qname]);	
3758
}
3759

    
3760
function read_altq_config() {
3761
	global $altq_list_queues, $config;
3762
	$path = array();
3763
	
3764
	if (!is_array($config['shaper']))
3765
		$config['shaper'] = array();
3766
	if (!is_array($config['shaper']['queue']))
3767
		$config['shaper']['queue'] = array();
3768
	$a_int = &$config['shaper']['queue'];
3769

    
3770
	$altq_list_queues = array();
3771
	
3772
	if (!is_array($config['shaper']['queue']))
3773
		return;
3774

    
3775
	foreach ($a_int as $key => $conf) {
3776
				$int = $conf['interface'];
3777
				$root =& new altq_root_queue();
3778
				$root->SetInterface($int);
3779
				$altq_list_queues[$root->GetInterface()] = &$root;
3780
				$root->ReadConfig($conf);
3781
		array_push($path, $key);
3782
		$root->SetLink($path);
3783
		if (is_array($conf['queue'])) {
3784
			foreach ($conf['queue'] as $key1 => $q) {
3785
				array_push($path, $key1);
3786
				/* 
3787
				 * XXX: we compeletely ignore errors here but anyway we must have 
3788
				 *	checked them before so no harm should be come from this.
3789
				 */
3790
				$root->add_queue($root->GetInterface(), $q, &$path, $input_errors);
3791
				array_pop($path);
3792
			} 	
3793
				}
3794
		array_pop($path);
3795
	}
3796
}
3797

    
3798
function read_dummynet_config() {
3799
	global $dummynet_pipe_list, $config;
3800
	$path = array();
3801
	$dnqueuenumber = 1;
3802
	$dnpipenumber = 1;
3803

    
3804
	if (!is_array($config['dnshaper']))
3805
		$config['dnshaper'] = array();
3806
	if (!is_array($config['dnshaper']['queue']))
3807
		$config['dnshaper']['queue'] = array();
3808
	$a_int = &$config['dnshaper']['queue'];
3809

    
3810
	$dummynet_pipe_list = array();
3811
	
3812
	if (!is_array($config['dnshaper']['queue'])
3813
		|| !count($config['dnshaper']['queue']))
3814
		return;
3815

    
3816
	foreach ($a_int as $key => $conf) {
3817
		if (empty($conf['name']))
3818
			continue; /* XXX: grrrrrr at php */ 
3819
		$root =& new dnpipe_class();
3820
		$root->ReadConfig($conf);
3821
		$root->SetNumber($dnpipenumber);	
3822
		$dummynet_pipe_list[$root->GetQname()] = &$root;
3823
		array_push($path, $key);
3824
		$root->SetLink($path);
3825
		if (is_array($conf['queue'])) {
3826
			foreach ($conf['queue'] as $key1 => $q) {
3827
				array_push($path, $key1);
3828
				/* XXX: We cheat a little here till a better way is found. */
3829
				$q['number'] = $dnqueuenumber;
3830
				/* 
3831
				 * XXX: we compeletely ignore errors here but anyway we must have 
3832
				 *	checked them before so no harm should be come from this.
3833
				 */	
3834
				$root->add_queue($root->GetQname(), $q, &$path, $input_errors);
3835
				array_pop($path);
3836

    
3837
				$dnqueuenumber++;
3838
			} 	
3839
		}
3840
		array_pop($path);
3841
			
3842
		$dnpipenumber++;
3843
	}
3844
}
3845

    
3846
function get_interface_list_to_show() {
3847
	global $altq_list_queues, $config;
3848
	global $shaperIFlist;
3849

    
3850
	$tree = "";
3851
	foreach ($shaperIFlist as $shif => $shDescr) {
3852
		if ($altq_list_queues[$shif]) {
3853
			continue;
3854
		} else  {
3855
			if (!is_altq_capable(get_real_interface($shif)))
3856
				continue;
3857
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&action=add\">".$shDescr."</a></li>";
3858
		}
3859
	}
3860
	
3861
	return $tree;
3862
}
3863

    
3864
function filter_generate_altq_queues() {
3865
	global $altq_list_queues;
3866
	
3867
	read_altq_config();
3868

    
3869
	$altq_rules = "";
3870
	foreach ($altq_list_queues as $altq) 
3871
		$altq_rules .= $altq->build_rules();
3872

    
3873
	return $altq_rules;
3874
}
3875

    
3876
function filter_generate_dummynet_rules() {
3877
	global $dummynet_pipe_list;
3878
	
3879
	read_dummynet_config();
3880
	
3881
	if (!empty($dummynet_pipe_list)) {
3882
		if (!is_module_loaded("dummynet.ko"))
3883
			mwexec("/sbin/kldload dummynet");
3884
		/* XXX: Needs to be added code elsewhere to clear pipes/queues from kernel when not needed! */
3885
		//mwexec("pfctl -F dummynet");
3886
	}
3887

    
3888
	$dn_rules = "";
3889
	foreach ($dummynet_pipe_list as $dn) 
3890
		$dn_rules .= $dn->build_rules();
3891

    
3892
	return $dn_rules;
3893
}
3894

    
3895
function build_iface_without_this_queue($iface, $qname) {
3896
	global $g, $altq_list_queues;
3897

    
3898
	$altq =& $altq_list_queues[$iface];
3899
				if ($altq)
3900
						$scheduler = ": " . $altq->GetScheduler();
3901
	$form = "<tr><td width=\"20%\" >";
3902
	$form .= "<a href=\"firewall_shaper.php?interface" . $iface . "&queue=" . $iface."&action=show\">".$iface.": ".$scheduler."</a>";
3903
		$form .= "</td></tr>";
3904
		$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
3905
		$form .= "<a href=\"firewall_shaper_queues.php?interface=";
3906
		$form .= $iface . "&queue=". $qname . "&action=add\">";
3907
		$form .= "<img src=\"";
3908
		$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
3909
		$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\">";
3910
		$form .= " Clone shaper/queue on this interface</a></td></tr>";
3911

    
3912
		return $form;
3913

    
3914
}
3915

    
3916

    
3917
$default_shaper_msg =	"<tr><td align=\"center\" width=\"80%\" >";
3918
$default_shaper_msg .= "<span class=\"vexpl\"><strong><p><b>Welcome to the pfSense Traffic Shaper.</b><br />";
3919
$default_shaper_msg .= "The tree on the left helps you navigate through the queues <br />";
3920
$default_shaper_msg .= "buttons at the bottom represent queue actions and are activated accordingly.";
3921
$default_shaper_msg .= " </p></strong></span>";
3922
$default_shaper_msg .= "</td></tr>";
3923

    
3924
$dn_default_shaper_msg =	"<tr><td align=\"center\" width=\"80%\" >";
3925
$dn_default_shaper_msg .= "<span class=\"vexpl\"><strong><p><b>Welcome to the pfSense Traffic Shaper.</b><br />";
3926
$dn_default_shaper_msg .= "The tree on the left helps you navigate through the queues <br />";
3927
$dn_default_shaper_msg .= "buttons at the bottom represent queue actions and are activated accordingly.";
3928
$dn_default_shaper_msg .= " </p></strong></span>";
3929
$dn_default_shaper_msg .= "</td></tr>";
3930

    
3931

    
3932

    
3933
?>
(35-35/47)