Project

General

Profile

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

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

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

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

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

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

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

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

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

    
50
	return $ptr;
51
}
52

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

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

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

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

    
73
	return $ptr;
74
}
75

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
453
		return $q;
454
	}
455

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

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

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

    
485
		$tree = " <li><a href=\"firewall_shaper.php?interface=".$this->GetInterface()."&queue=". $this->GetInterface()."&action=show"; 
486
		$tree .= "\">" . $shaperIFlist[$this->GetInterface()] . "</a>";
487
		if (is_array($this->queues)) {
488
			$tree .= "<ul>";
489
			foreach ($this->queues as $q)  {
490
				$tree .= $q->build_tree();
491
			}
492
		$tree .= "</ul>";
493
		}
494
		$tree .= "</li>";
495
		return $tree;
496
	}
497
	
498
	function delete_queue() { 
499
		foreach ($this->queues as $q) {
500
		$this->SetAvailableBandwidth($this->GetAvailableBandwidth() + $q->GetAvailableBandwidth());
501
			$q->delete_queue();			
502
		}
503
		unset_object_by_reference($this->GetLink());
504
	 }
505

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

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

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

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

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

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

    
606
		return $form;
607

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

    
695

    
696
		return $form;
697
	}
698

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

    
727
}
728

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

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

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

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

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

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

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

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

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

    
920
	 }
921

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

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

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

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

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

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

    
1038
	}
1039

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

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

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

    
1107
		$pfq_rule .= " \n";
1108

    
1109
		return $pfq_rule;
1110
	}
1111

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

    
1189
		return $form;
1190
	}
1191

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

    
1229
	}
1230

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1846
		return $javascript;
1847
	}
1848

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

    
1950
		return $form;
1951
	}
1952

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

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

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

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

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

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

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

    
2110
		return $q;
2111
	}
2112

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

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

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

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

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

    
2203

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

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

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

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

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

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

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

    
2364
		return $form;
2365
	}
2366

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

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

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

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

    
2429

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

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

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

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

    
2478

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

    
2482

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

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

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

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

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

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

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

    
2685

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

    
2690

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2978
        }
2979

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

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

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

    
3001
		$pfq_rule = "\npipe ". $this->GetNumber() . " config ";
3002
		$bandwidth = $this->GetBandwidth();
3003
		if (is_array($bandwidth)) {
3004
			foreach ($bandwidth as $bw) {
3005
				if ($bw['bwsched'] != "none") {
3006
					$time_based_rules = true;
3007
					if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3008
						foreach ($config['schedules']['schedule'] as $schedule) {
3009
							if ($bw['bwsched'] == $schedule['name']) {
3010
								if (filter_get_time_based_rule_status($schedule)) {
3011
									$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3012
									break;
3013
								}
3014
							}
3015
						}
3016
					} else
3017
						return "";
3018
				} else
3019
					$pfq_rule .= " bw ".trim($bw['bw']).$bw['bwscale'];
3020
			}
3021
		}
3022

    
3023
		if ($this->GetQlimit())
3024
                    	$pfq_rule .= " queue " . $this->GetQlimit();
3025
		if ($this->GetPlr())
3026
			$pfq_rule .= " plr " . $this->GetPlr();
3027
		if ($this->GetBuckets())
3028
			$pfq_rule .= " buckets " . $this->GetBuckets();
3029
		if ($this->GetDelay())
3030
			$pfq_rule .= " delay " . $this->GetDelay();
3031

    
3032
		$mask = $this->GetMask();
3033
		if (!empty($mask)) {
3034
			/* XXX TODO extend this to support more complicated masks */
3035
			switch ($mask) {
3036
			case 'srcaddress':
3037
				$pfq_rule .= " mask src-ip 0xffffffff ";
3038
				break;
3039
			case 'dstaddress':
3040
				$pfq_rule .= " mask dst-ip 0xffffffff ";
3041
				break;
3042
			default:
3043
				break;
3044
			}
3045
    		}            
3046
		$pfq_rule .= "\n";
3047

    
3048
		if (!empty($this->subqueues) && count($this->subqueues) > 0) {
3049
			foreach ($this->subqueues as $q)
3050
			$pfq_rule .= $q->build_rules();
3051
		}
3052
		$pfq_rule .= " \n";
3053

    
3054
		return $pfq_rule;
3055
        }
3056

    
3057
	function update_dn_data(&$data) { 
3058
		$this->ReadConfig($data);
3059
	}
3060

    
3061
	function build_javascript() {
3062
		global $g, $config;
3063

    
3064
		//build list of schedules
3065
		$schedules = "<option value='none'>none</option>";
3066
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3067
			foreach ($config['schedules']['schedule'] as $schedule) {
3068
				if ($schedule['name'] <> "")
3069
					$schedules .= "<option value='{$schedule['name']}'>{$schedule['name']}</option>";
3070
			}
3071
		}
3072
		$bwopt = "";
3073
		foreach (array("Kb" => "Kbit/s", "Mb" => "Mbit/s", "Gb" => "Gbit/s", "b" => "Bit/s") as $bwidx => $bw)
3074
			$bwopt .= "<option value='{$bwidx}'>{$bw}</option>";
3075

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

    
3102
function removeBwRow(el) {
3103
	var cel;
3104
	while (el && el.nodeName.toLowerCase() != "tr")
3105
	    el = el.parentNode;
3106
		if (el && el.parentNode) {
3107
			cel = el.getElementsByTagName("td").item(0);
3108
			el.parentNode.removeChild(el);
3109
		}
3110
}
3111
</script>
3112

    
3113
EOD;
3114

    
3115
	       return $javasr;
3116
	}
3117

    
3118
        function build_form() { 
3119
		global $g, $config;
3120

    
3121
		//build list of schedules
3122
		$schedules = array();
3123
		$schedules[] = "none";//leave none to leave rule enabled all the time
3124
		if (is_array($config['schedules']) && is_array($config['schedules']['schedule'])) {
3125
			foreach ($config['schedules']['schedule'] as $schedule) {
3126
				if ($schedule['name'] <> "")
3127
					$schedules[] = $schedule['name'];
3128
			}
3129
		}
3130

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

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

    
3267
		return $form;
3268
			
3269
		}
3270

    
3271
	function wconfig() {
3272
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3273
            	if (!is_array($cflink))
3274
            		$cflink = array();
3275
		$cflink['name'] = $this->GetQname();
3276
		$cflink['number'] = $this->GetNumber();
3277
            	$cflink['qlimit'] = $this->GetQlimit();
3278
            	$cflink['plr'] = $this->GetPlr();
3279
            	$cflink['description'] = $this->GetDescription();
3280
               
3281
		$bandwidth = $this->GetBandwidth();
3282
		if (is_array($bandwidth)) {
3283
			$cflink['bandwidth'] = array();
3284
			$cflink['bandwidth']['item'] = array();
3285
			foreach ($bandwidth as $bwidx => $bw)
3286
				$cflink['bandwidth']['item'][] = $bw;
3287
		}
3288

    
3289
		$cflink['enabled'] = $this->GetEnabled();
3290
		$cflink['buckets'] = $this->GetBuckets();
3291
		$cflink['mask'] = $this->GetMask();
3292
		$cflink['delay'] = $this->GetDelay();
3293
	}
3294

    
3295
}
3296

    
3297
class dnqueue_class extends dummynet_class {
3298
        var $pipeparent;
3299
        var $weight;
3300

    
3301
        function GetWeight() {
3302
                return $this->weight;
3303
        }
3304
        function SetWeight($weight) {
3305
                $this->weight = $weight;
3306
        }
3307
	function GetPipe() {
3308
		return $this->pipeparent;
3309
	}
3310
	function SetPipe($pipe) {
3311
		$this->pipeparent = $pipe;
3312
	}
3313

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

    
3317
	function delete_queue() {
3318
		cleanup_dnqueue_from_rules($this->GetQname());
3319
		unset_dn_object_by_reference($this->GetLink());
3320
		mwexec("/sbin/ipfw queue delete " . $this->GetNumber());
3321
        }
3322

    
3323
	function validate_input($data, &$input_errors) {
3324
		parent::validate_input($data, $input_errors);
3325

    
3326
		if ($data['weight'] && ((!is_numeric($data['weight'])) ||
3327
			($data['weight'] < 1 && $data['weight'] > 100))) 
3328
				$input_errors[] = gettext("Weight must be an integer between 1 and 100.");
3329
	}
3330

    
3331
        /*
3332
         * Should search even its children
3333
         */
3334
        function &find_queue($pipe, $qname) {
3335
                if ($qname == $this->GetQname()) 
3336
                	return $this;
3337
		else
3338
			return NULL;
3339
        }
3340

    
3341
	function &find_parentqueue($pipe, $qname) {
3342
		return $this->qparent;
3343
        }
3344

    
3345
        function &get_queue_list(&$qlist) {
3346
		if ($this->GetEnabled() == "")
3347
			return;
3348
        	$qlist[$this->GetQname()] = "?" .$this->GetNumber();
3349
        }		
3350

    
3351
	function ReadConfig(&$q) {
3352
		if (!empty($q['name']) && !empty($q['newname']) && $q['name'] != $q['newname']) {
3353
			$this->SetQname($q['newname']);
3354
		} else if (!empty($q['newname'])) {
3355
			$this->SetQname($q['newname']);
3356
		} else {
3357
			$this->SetQname($q['name']);
3358
		}
3359
		$this->SetNumber($q['number']);
3360
		if (isset($q['qlimit']) && $q['qlimit'] <> "")
3361
       		       	$this->SetQlimit($q['qlimit']);
3362
		else
3363
       		       	$this->SetQlimit("");
3364
		if (isset($q['mask']) && $q['mask'] <> "")
3365
              		$this->SetMask($q['mask']);
3366
		else
3367
              		$this->SetMask("");
3368
       		if (isset($q['weight']) && $q['weight'] <> "")
3369
            		$this->SetWeight($q['weight']);
3370
		else
3371
            		$this->SetWeight("");
3372
            	if (isset($q['description']) && $q['description'] <> "")
3373
			$this->SetDescription($q['description']);
3374
		else
3375
			$this->SetDescription("");
3376
		$this->SetEnabled($q['enabled']);
3377
        }
3378

    
3379
	function build_tree() {
3380
		$parent =& $this->GetParent();
3381
		$tree = " <li><a href=\"firewall_shaper_vinterface.php?pipe=" . $parent->GetQname() ."&queue=" . $this->GetQname() ."&action=show\">"; 
3382
		$tree .= $this->GetQname() . "</a>";
3383
		$tree .= "</li>";
3384
		
3385
		return $tree;
3386
	}
3387

    
3388
        function build_rules() {
3389
		if ($this->GetEnabled() == "")
3390
			return; 
3391

    
3392
		$parent =& $this->GetParent();
3393
            	$pfq_rule = "queue ". $this->GetNumber() . " config pipe " . $parent->GetNumber();
3394
		if ($this->GetQlimit())
3395
                    	$pfq_rule .= " queue " . $this->GetQlimit();
3396
		if ($this->GetWeight())
3397
			$pfq_rule .= " weight " . $this->GetWeight();
3398
		if ($this->GetBuckets())
3399
			$pfq_rule .= " buckets " . $this->GetBuckets();
3400
		$mask = $this->GetMask();
3401
		if (!empty($mask)) {
3402
			/* XXX TODO extend this to support more complicated masks */
3403
			switch ($mask) {
3404
			case 'srcaddress':
3405
				$pfq_rule .= " mask src-ip 0xffffffff ";
3406
				break;
3407
			case 'dstaddress':
3408
				$pfq_rule .= " mask dst-ip 0xffffffff ";
3409
				break;
3410
			default:
3411
				break;
3412
			}
3413
			$pfq_rule .= "\n";
3414
		}
3415

    
3416
		return $pfq_rule;
3417
	}
3418

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

    
3514
		$form .= "<input type=\"hidden\" id=\"pipe\" name=\"pipe\"";
3515
		$form .= " value=\"" . $this->GetPipe() . "\">";
3516

    
3517
		return $form;
3518
			
3519
	}
3520

    
3521
        function update_dn_data(&$data) { 
3522
		$this->ReadConfig($data);
3523
	}
3524

    
3525
	function wconfig() {
3526
		$cflink =& get_dn_reference_to_me_in_config($this->GetLink());
3527
            	if (!is_array($cflink))
3528
            		$cflink = array();
3529
		$cflink['name'] = $this->GetQname();
3530
		$cflink['number'] = $this->GetNumber();
3531
            	$cflink['qlimit'] = $this->GetQlimit();
3532
            	$cflink['description'] = $this->GetDescription();
3533
		$cflink['weight'] = $this->GetWeight();
3534
		$cflink['enabled'] = $this->GetEnabled();
3535
		$cflink['buckets'] = $this->GetBuckets();
3536
		$cflink['mask'] = $this->GetMask();
3537
	}
3538
}
3539

    
3540
// List of layer7 objects
3541
$layer7_rules_list = array();
3542

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

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

    
3796
/*
3797
 * This function allows to return an array with all the used divert socket ports
3798
 */
3799
function get_divert_ports() {
3800
    global $layer7_rules_list;
3801
    $dports = array();
3802
    
3803
    foreach($layer7_rules_list as $l7r)
3804
        $dports[] = $l7r->GetRPort();
3805
    
3806
    return $dports;
3807
}
3808

    
3809
function &get_l7c_reference_to_me_in_config(&$name) {
3810
	global $config;
3811
	
3812
	$ptr = NULL;
3813
	
3814
	if(is_array($config['l7shaper']['container'])) {
3815
		foreach($config['l7shaper']['container'] as $key => $value) {
3816
			if($value['name'] == $name)
3817
				$ptr =& $config['l7shaper']['container'][$key];
3818
		}
3819
	}	
3820
	return $ptr;
3821
// $ptr can be null. has to be checked later
3822
}
3823

    
3824
function unset_l7_object_by_reference(&$name) {
3825
	global $config;
3826
        
3827
	if(is_array($config['l7shaper']['container'])) {
3828
		foreach($config['l7shaper']['container'] as $key => $value) {
3829
			if($value['name'] == $name) {
3830
				unset($config['l7shaper']['container'][$key]['l7rules']);
3831
				unset($config['l7shaper']['container'][$key]);
3832
				break;
3833
			}
3834
		}
3835
	}
3836
}
3837

    
3838
function read_layer7_config() {
3839
    global $layer7_rules_list, $config;
3840
    
3841
    $l7cs = &$config['l7shaper']['container'];
3842
    
3843
    $layer7_rules_list = array();
3844
    
3845
    if (!is_array($config['l7shaper']['container']) || !count($config['l7shaper']['container']))
3846
	return;
3847
    
3848
    foreach ($l7cs as $conf) {
3849
	if (empty($conf['name']))
3850
		continue; /* XXX: grrrrrr at php */ 
3851
        $root =& new layer7();
3852
        $root->ReadConfig($conf['name'],$conf);
3853
        $layer7_rules_list[$root->GetRName()] = &$root;
3854
    }
3855
}
3856

    
3857
function generate_layer7_files() {
3858
    global $layer7_rules_list, $g;
3859
    
3860
    read_layer7_config();
3861
    
3862
    if (!empty($layer7_rules_list)) {
3863
	if (!is_module_loaded("ipdivert.ko"))
3864
		mwexec("/sbin/kldload ipdivert.ko");
3865

    
3866
	mwexec("rm -f {$g['tmp_path']}/*.l7");
3867
    }
3868
    
3869
    foreach($layer7_rules_list as $l7rules) {
3870
        if($l7rules->GetREnabled()) {
3871
            $filename = $l7rules->GetRName() . ".l7";
3872
            $path = "{$g['tmp_path']}/" . $filename;
3873
        
3874
            $rules = $l7rules->build_l7_rules();
3875
        
3876
            $fp = fopen($path,'w');
3877
            fwrite($fp,$rules);
3878
            fclose($fp);
3879
        }
3880
    }
3881
}
3882

    
3883
function layer7_start_l7daemon() {
3884
    global $layer7_rules_list, $g;
3885

    
3886
    /*
3887
     * XXX: ermal - Needed ?!
3888
     * read_layer7_config();
3889
     */
3890

    
3891
    foreach($layer7_rules_list as $l7rules) {
3892
        if($l7rules->GetREnabled()) {
3893
            $filename = $l7rules->GetRName() . ".l7";
3894
            $path = "{$g['tmp_path']}/" . $filename;
3895

    
3896
	    unset($l7pid);
3897
	    /* Only reread the configuration rather than restart to avoid loosing information. */
3898
	    exec("/bin/pgrep -f 'ipfw-classifyd .* -p ". $l7rules->GetRPort() . "'", $l7pid);
3899
	    if (count($l7pid) > 0) {
3900
		log_error(sprintf(gettext("Sending HUP signal to %s"), $l7pid[0]));
3901
		mwexec("/bin/kill -HUP {$l7pid[0]}");
3902
	    } else {
3903
		// XXX: Hardcoded number of packets to garbage collect and queue length..
3904
		$ipfw_classifyd_init = "/usr/local/sbin/ipfw-classifyd -n 8 -q 700 -c {$path} -p " . $l7rules->GetRPort() . " -P /usr/local/share/protocols";
3905
		mwexec_bg($ipfw_classifyd_init);
3906
	    }
3907
        }
3908
    }
3909
}
3910

    
3911
// This function uses /usr/local/share/protocols as a default directory for searching .pat files
3912
function generate_protocols_array() {
3913
	$protocols = return_dir_as_array("/usr/local/share/protocols");
3914
	$protocols_new = array();
3915
	if(is_array($protocols)) {
3916
		foreach($protocols as $key => $proto) {
3917
			if (strstr($proto, ".pat"))
3918
				$protocols_new[$key] =& str_replace(".pat", "", $proto);
3919
		}
3920
		sort($protocols_new);
3921
	}		
3922
	return $protocols_new;
3923
}
3924

    
3925
function get_l7_unique_list() {
3926
	global $layer7_rules_list;
3927
	
3928
	$l7list = array();
3929
	if(is_array($layer7_rules_list)) 
3930
		foreach($layer7_rules_list as $l7c)
3931
			if($l7c->GetREnabled())
3932
				$l7list[] = $l7c->GetRName();
3933
	
3934
	return $l7list;
3935
}
3936

    
3937
// Disable a removed l7 container from the filter
3938
function cleanup_l7_from_rules(&$name) {
3939
	global $config;
3940

    
3941
	if(is_array($config['filter']['rule']))
3942
		foreach ($config['filter']['rule'] as $key => $rule) {
3943
			if ($rule['l7container'] == $name)
3944
				unset($config['filter']['rule'][$key]['l7container']);
3945
		}
3946
}
3947

    
3948
function get_dummynet_name_list() {
3949
	
3950
	$dn_name_list =& get_unique_dnqueue_list();
3951
	$dn_name = array();
3952
	if(is_array($dn_name_list))
3953
		foreach($dn_name_list as $key => $value)
3954
			$dn_name[] = $key;
3955
	
3956
	return $dn_name;
3957
	
3958
}
3959

    
3960
function get_altq_name_list() {
3961
	$altq_name_list =& get_unique_queue_list();
3962
	$altq_name = array();
3963
	if(is_array($altq_name_list))
3964
		foreach($altq_name_list as $key => $aqobj)
3965
			$altq_name[] = $key;
3966
		
3967
	return $altq_name;
3968
}
3969

    
3970
/*
3971
 * XXX: TODO Make a class shaper to hide all these function
3972
 * from the global namespace.
3973
 */
3974

    
3975
/* 
3976
 * This is a layer violation but for now there is no way 
3977
 * i can find to properly do this with PHP.
3978
 */
3979
function altq_get_default_queue($interface) {
3980
	global $altq_list_queues;
3981

    
3982
	$altq_tmp = $altq_list_queues[$interface];
3983
	if ($altq_tmp)
3984
		return $altq_tmp->GetDefaultQueuePresent(); 
3985
	else
3986
		return false;
3987
}
3988

    
3989
function altq_check_default_queues() {
3990
	global $altq_list_queues;
3991

    
3992
	$count = 0;
3993
	if (is_array($altq_list_queues)) {
3994
		foreach($altq_list_queues as $altq) {
3995
			if ($altq->GetDefaultQueuePresent())
3996
				$count++;
3997
		}
3998
	}
3999
	else  $count++;;
4000
	
4001
	return 0;
4002
}
4003

    
4004
function &get_unique_queue_list() {
4005
	global $altq_list_queues;
4006
	
4007
	$qlist = array();
4008
	if (is_array($altq_list_queues)) {
4009
		foreach ($altq_list_queues as $altq) {
4010
			if ($altq->GetEnabled() == "")
4011
				continue;
4012
			$tmplist =& $altq->get_queue_list();
4013
			foreach ($tmplist as $qname => $link) {
4014
				if ($link->GetEnabled() <> "")
4015
					$qlist[$qname] = $link;	
4016
			}
4017
		}
4018
	}
4019
	return $qlist;
4020
}
4021

    
4022
function &get_unique_dnqueue_list() {
4023
	global $dummynet_pipe_list;
4024
	
4025
	$qlist = array();
4026
	if (is_array($dummynet_pipe_list)) {
4027
		foreach ($dummynet_pipe_list as $dn) {
4028
			if ($dn->GetEnabled() == "")
4029
				continue;
4030
			$tmplist =& $dn->get_queue_list();
4031
			foreach ($tmplist as $qname => $link) {
4032
				$qlist[$qname] = $link;	
4033
			}
4034
		}
4035
	}
4036
	return $qlist;
4037
}
4038

    
4039
function ref_on_altq_queue_list($parent, $qname) {
4040
	if (isset($GLOBALS['queue_list'][$qname]))
4041
		$GLOBALS['queue_list'][$qname]++;
4042
	else
4043
		$GLOBALS['queue_list'][$qname] = 1;
4044

    
4045
	unref_on_altq_queue_list($parent);
4046
}
4047

    
4048
function unref_on_altq_queue_list($qname) {
4049
	$GLOBALS['queue_list'][$qname]--;
4050
	if ($GLOBALS['queue_list'][$qname] <= 1)
4051
		unset($GLOBALS['queue_list'][$qname]);	
4052
}
4053

    
4054
function read_altq_config() {
4055
	global $altq_list_queues, $config;
4056
	$path = array();
4057
	
4058
	if (!is_array($config['shaper']))
4059
		$config['shaper'] = array();
4060
	if (!is_array($config['shaper']['queue']))
4061
		$config['shaper']['queue'] = array();
4062
	$a_int = &$config['shaper']['queue'];
4063

    
4064
	$altq_list_queues = array();
4065
	
4066
	if (!is_array($config['shaper']['queue']))
4067
		return;
4068

    
4069
	foreach ($a_int as $key => $conf) {
4070
		$int = $conf['interface'];
4071
		$root =& new altq_root_queue();
4072
		$root->SetInterface($int);
4073
		$altq_list_queues[$root->GetInterface()] = &$root;
4074
		$root->ReadConfig($conf);
4075
		array_push($path, $key);
4076
		$root->SetLink($path);
4077
		if (is_array($conf['queue'])) {
4078
			foreach ($conf['queue'] as $key1 => $q) {
4079
				array_push($path, $key1);
4080
				/* 
4081
				 * XXX: we compeletely ignore errors here but anyway we must have 
4082
				 *	checked them before so no harm should be come from this.
4083
				 */
4084
				$root->add_queue($root->GetInterface(), $q, &$path, $input_errors);
4085
				array_pop($path);
4086
			} 	
4087
		}
4088
		array_pop($path);
4089
	}
4090
}
4091

    
4092
function read_dummynet_config() {
4093
	global $dummynet_pipe_list, $config;
4094
	$path = array();
4095

    
4096
	if (!is_array($config['dnshaper']))
4097
		$config['dnshaper'] = array();
4098
	if (!is_array($config['dnshaper']['queue']))
4099
		$config['dnshaper']['queue'] = array();
4100
	$a_int = &$config['dnshaper']['queue'];
4101

    
4102
	$dummynet_pipe_list = array();
4103
	
4104
	if (!is_array($config['dnshaper']['queue'])
4105
		|| !count($config['dnshaper']['queue']))
4106
		return;
4107

    
4108
	foreach ($a_int as $key => $conf) {
4109
		if (empty($conf['name']))
4110
			continue; /* XXX: grrrrrr at php */ 
4111
		$root =& new dnpipe_class();
4112
		$root->ReadConfig($conf);
4113
		$dummynet_pipe_list[$root->GetQname()] = &$root;
4114
		array_push($path, $key);
4115
		$root->SetLink($path);
4116
		if (is_array($conf['queue'])) {
4117
			foreach ($conf['queue'] as $key1 => $q) {
4118
				array_push($path, $key1);
4119
				/* 
4120
				 * XXX: we compeletely ignore errors here but anyway we must have 
4121
				 *	checked them before so no harm should be come from this.
4122
				 */	
4123
				$root->add_queue($root->GetQname(), $q, &$path, $input_errors);
4124
				array_pop($path);
4125
			} 	
4126
		}
4127
		array_pop($path);
4128
	}
4129
}
4130

    
4131
function get_interface_list_to_show() {
4132
	global $altq_list_queues, $config;
4133
	global $shaperIFlist;
4134

    
4135
	$tree = "";
4136
	foreach ($shaperIFlist as $shif => $shDescr) {
4137
		if ($altq_list_queues[$shif]) {
4138
			continue;
4139
		} else  {
4140
			if (!is_altq_capable(get_real_interface($shif)))
4141
				continue;
4142
			$tree .= " <li><a href=\"firewall_shaper.php?interface=".$shif."&action=add\">".$shDescr."</a></li>";
4143
		}
4144
	}
4145
	
4146
	return $tree;
4147
}
4148

    
4149
function filter_generate_altq_queues() {
4150
	global $altq_list_queues;
4151
	
4152
	read_altq_config();
4153

    
4154
	$altq_rules = "";
4155
	foreach ($altq_list_queues as $altq) 
4156
		$altq_rules .= $altq->build_rules();
4157

    
4158
	return $altq_rules;
4159
}
4160

    
4161
function dnqueue_find_nextnumber() {
4162
	global $dummynet_pipe_list;
4163

    
4164
	$dnused = array();
4165
	if (is_array($dummynet_pipe_list)) {
4166
		foreach ($dummynet_pipe_list as $dn) {
4167
			$tmplist =& $dn->get_queue_list();
4168
			foreach ($tmplist as $qname => $link) {
4169
				if ($link[0] == "?")
4170
					$dnused[$qname] = substr($link, 1);
4171
			}
4172
		}
4173
	}
4174

    
4175
	sort($dnused, SORT_NUMERIC);
4176
	$dnnumber = 0;
4177
	$found = false;
4178
	foreach ($dnused as $dnnum) {
4179
		if (($dnnum - $dnnumber) > 1) {
4180
			$dnnumber = $dnnum + 1;
4181
			$found = true;
4182
			break;
4183
		} else
4184
			$dnnumber = $dnnum;
4185
	}
4186

    
4187
	if ($found == false)
4188
		$dnnumber++;
4189

    
4190
	unset($dnused, $dnnum, $found);
4191
	return $dnnumber;
4192
}
4193

    
4194
function dnpipe_find_nextnumber() {
4195
	global $dummynet_pipe_list;
4196

    
4197
	$dnused = array();
4198
	foreach ($dummynet_pipe_list as $dn)
4199
		$dnused[] = $dn->GetNumber();
4200

    
4201
	sort($dnused, SORT_NUMERIC);
4202
	$dnnumber = 0;
4203
	$found = false;
4204
	foreach ($dnused as $dnnum) {
4205
		if (($dnnum - $dnnumber) > 1) {
4206
			$dnnumber = $dnnum + 1;
4207
			$found = true;
4208
			break;
4209
		} else
4210
			$dnnumber = $dnnum;
4211
	}
4212

    
4213
	if ($found == false)
4214
		$dnnumber++;
4215

    
4216
	unset($dnused, $dnnum, $found);
4217
	return $dnnumber;
4218
}
4219

    
4220
function filter_generate_dummynet_rules() {
4221
	global $g, $dummynet_pipe_list;
4222
	
4223
	read_dummynet_config();
4224
	
4225
	if (!empty($dummynet_pipe_list)) {
4226
		if (!is_module_loaded("dummynet.ko"))
4227
			mwexec("/sbin/kldload dummynet");
4228
	}
4229

    
4230
	$dn_rules = "";
4231
	foreach ($dummynet_pipe_list as $dn) 
4232
		$dn_rules .= $dn->build_rules();
4233

    
4234
	if (!empty($dn_rules)) {
4235
		file_put_contents("{$g['tmp_path']}/rules.limiter", $dn_rules);
4236
		mwexec("/sbin/ipfw {$g['tmp_path']}/rules.limiter");
4237
	}
4238
}
4239

    
4240
function build_iface_without_this_queue($iface, $qname) {
4241
	global $g, $altq_list_queues;
4242
	global $shaperIFlist;
4243

    
4244
	$altq =& $altq_list_queues[$iface];
4245
	if ($altq)
4246
		$scheduler = ": " . $altq->GetScheduler();
4247
	$form = "<tr><td width=\"20%\" >";
4248
	$form .= "<a href=\"firewall_shaper.php?interface=" . $iface . "&queue=" . $iface."&action=show\">". $shaperIFlist[$iface] . $scheduler."</a>";
4249
	$form .= "</td></tr>";
4250
	$form .= "<tr><td width=\"100%\" class=\"vncellreq\">";
4251
	$form .= "<a href=\"firewall_shaper_queues.php?interface=";
4252
	$form .= $iface . "&queue=". $qname . "&action=add\">";
4253
	$form .= "<img src=\"";
4254
	$form .= "./themes/".$g['theme']."/images/icons/icon_plus.gif\"";
4255
	$form .= " width=\"17\" height=\"17\" border=\"0\" title=\"Clone shaper/queue on this interface\">";
4256
	$form .= gettext(" Clone shaper/queue on this interface") . "</a></td></tr>";
4257

    
4258
	return $form;
4259

    
4260
}
4261

    
4262

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

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

    
4277
?>
(49-49/66)