Project

General

Profile

Download (103 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	interfaces.inc
5
	Copyright (C) 2004-2008 Scott Ullrich
6
	Copyright (C) 2008-2009 Ermal Lu?i
7
	All rights reserved.
8

    
9
	function interfaces_wireless_configure is
10
	Copyright (C) 2005 Espen Johansen
11
	All rights reserved.
12

    
13
	originally part of m0n0wall (http://m0n0.ch/wall)
14
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
15
	All rights reserved.
16

    
17
	Redistribution and use in source and binary forms, with or without
18
	modification, are permitted provided that the following conditions are met:
19

    
20
	1. Redistributions of source code must retain the above copyright notices,
21
	   this list of conditions and the following disclaimer.
22

    
23
	2. Redistributions in binary form must reproduce the above copyright
24
	   notices, this list of conditions and the following disclaimer in the
25
	   documentation and/or other materials provided with the distribution.
26

    
27
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
28
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
	POSSIBILITY OF SUCH DAMAGE.
37

    
38
	pfSense_BUILDER_BINARIES:	/sbin/dhclient	/bin/sh	/usr/bin/grep	/usr/bin/xargs	/usr/bin/awk	/usr/local/sbin/choparp
39
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig	/sbin/route	/usr/sbin/ngctl	/usr/sbin/arp	/bin/kill	/usr/local/sbin/mpd5
40
	pfSense_MODULE:	interfaces
41

    
42
*/
43

    
44
/* include all configuration functions */
45
require_once("globals.inc");
46
require_once("cmd_chain.inc");
47

    
48
function interfaces_bring_up($interface) {
49
	if(!$interface) {
50
		log_error("interfaces_bring_up() was called but no variable defined.");
51
		log_error( "Backtrace: " . debug_backtrace() );
52
		return;
53
	}
54
	pfSense_interface_flags($interface, IFF_UP);
55
}
56

    
57
/*
58
 * Return the interface array
59
 */
60
function get_interface_arr($flush = false) {
61
        global $interface_arr_cache;
62

    
63
        /* If the cache doesn't exist, build it */
64
        if (!isset($interface_arr_cache) or $flush)
65
                $interface_arr_cache = explode(" ", trim(`/sbin/ifconfig -l`));
66

    
67
        return $interface_arr_cache;
68
}
69

    
70
/*
71
 * does_interface_exist($interface): return true or false if a interface is
72
 * detected.
73
 */
74
function does_interface_exist($interface) {
75
	global $config;
76
	
77
	if(!$interface)
78
		return false;
79

    
80
	$ints = get_interface_arr(true);
81
	if (in_array($interface, $ints))
82
		return true;
83
	else
84
		return false;
85
}
86

    
87
function interface_netgraph_needed($interface = "wan") {
88
	global $config;
89

    
90
	$found = false;
91
	if (!empty($config['pptpd']) &&
92
		$config['pptpd']['mode'] == "server")
93
		$found = true;
94
	if ($found == false && !empty($config['l2tp']) &&
95
		$config['l2tp']['mode'] == "server")
96
		$found = true;
97
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
98
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
99
			if ($pppoe['mode'] != "server")
100
				continue;
101
			if ($pppoe['interface'] == $interface)
102
				$found = true;
103
				break;
104
		}
105
	}
106
	if ($found == false) {
107
		if (!empty($config['interfaces'][$interface])) {
108
			switch ($config['interfaces'][$interface]['ipaddr']) {
109
			case "ppp":
110
			case "pppoe":
111
			case "l2tp":
112
			case "pptp":
113
				$found = true;
114
				break;
115
			default:
116
				$found = false;
117
				break;
118
			}
119
		}
120
	}
121
	if ($found == false) {
122
		$realif = get_real_interface($interface);
123
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
124
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
125
				if ($realif == $ppp['if']) {
126
					$found = true;
127
					break;
128
				}
129
				$ports = explode(',',$ppp['ports']);
130
				foreach($ports as $pid => $port){
131
					if ($realif == $port) {
132
						$found = true;
133
						break;
134
					}
135
				}
136
			}
137
		}
138
	}
139

    
140
	if ($found == false) {
141
		$realif = get_real_interface($interface);
142
		pfSense_ngctl_detach("{$realif}:", $realif);
143
	}
144
	/* NOTE: We make sure for this on interface_ppps_configure()
145
	 *	no need to do it here agan.
146
	 *	else
147
	 *		pfSense_ngctl_attach(".", $realif);
148
	 */
149
}
150

    
151
function interfaces_loopback_configure() {
152
	if($g['booting'])
153
		echo "Configuring loopback interface...";
154
	pfSense_interface_setaddress("lo0", "127.0.0.1");
155
	interfaces_bring_up("lo0");
156
	if($g['booting'])
157
		echo "done.\n";
158
	return 0;
159
}
160

    
161
function interfaces_vlan_configure() {
162
	global $config, $g;
163
	if($g['booting'])
164
		echo "Configuring VLAN interfaces...";
165
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
166
		foreach ($config['vlans']['vlan'] as $vlan) {
167
			if(empty($vlan['vlanif']))
168
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
169
			/* XXX: Maybe we should report any errors?! */
170
			interface_vlan_configure($vlan);
171
		}
172
	}
173
	if($g['booting'])
174
		echo "done.\n";
175
}
176

    
177
function interface_vlan_configure(&$vlan) {
178
        global $config, $g;
179

    
180
	if (!is_array($vlan)) {
181
		log_error("VLAN: called with wrong options. Problems with config!");
182
		return;
183
	}
184
	$if = $vlan['if'];
185
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
186
	$tag = $vlan['tag'];
187

    
188
	if (empty($if)) {
189
		log_error("interface_vlan_confgure called with if undefined.");
190
		return;
191
	}
192

    
193
	/* make sure the parent interface is up */
194
	interfaces_bring_up($if);
195
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
196
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
197

    
198
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
199
		interface_bring_down($vlanif, true);
200
	} else {
201
		$tmpvlanif = pfSense_interface_create("vlan");
202
		pfSense_interface_rename($tmpvlanif, $vlanif);
203
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
204
	}
205

    
206
	pfSense_vlan_create($vlanif, $if, $tag);
207

    
208
	interfaces_bring_up($vlanif);
209

    
210
	/* invalidate interface cache */
211
	get_interface_arr(true);
212

    
213
	/* XXX: ermal -- for now leave it here at the moment it does not hurt. */
214
	interfaces_bring_up($if);
215

    
216
	return $vlanif;
217
}
218

    
219
function interface_qinq_configure(&$vlan, $fd = NULL) {
220
        global $config, $g;
221

    
222
        if (!is_array($vlan)) {
223
                log_error("QinQ compat VLAN: called with wrong options. Problems with config!\n");
224
                return;
225
        }
226

    
227
        $qinqif = $vlan['if'];
228
        $tag = $vlan['tag'];
229
        if(empty($qinqif)) {
230
                log_error("interface_qinq_confgure called with if undefined.\n");
231
                return;
232
        }
233
	$vlanif = interface_vlan_configure($vlan);
234

    
235
        if ($fd == NULL) {
236
                $exec = true;
237
                $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
238
        } else
239
                $exec = false;
240
        /* make sure the parent is converted to ng_vlan(4) and is up */
241
        interfaces_bring_up($qinqif);
242

    
243
        if (!empty($vlanif) && does_interface_exist($vlanif)) {
244
                fwrite($fd, "shutdown {$qinqif}qinq:\n");
245
                exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
246
                if (empty($result)) {
247
                        fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
248
                        fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
249
                        fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
250
                }
251
        } else {
252
                fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
253
                fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
254
                fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
255
        }
256

    
257
        /* invalidate interface cache */
258
        get_interface_arr(true);
259

    
260
        if (!stristr($qinqif, "vlan"))
261
                mwexec("/sbin/ifconfig {$qinqif} promisc\n");
262

    
263
        $macaddr = get_interface_mac($qinqif);
264
        if (!empty($vlan['members'])) {
265
                $members = explode(" ", $vlan['members']);
266
                foreach ($members as $qtag) {
267
                        $qinq = array();
268
                        $qinq['tag'] = $qtag;
269
                        $qinq['if'] = $vlanif;
270
                        interface_qinq2_configure($qinq, $fd, $macaddr);
271
                }
272
        }
273
        if ($exec == true) {
274
                fclose($fd);
275
                mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
276
        }
277

    
278
        interfaces_bring_up($qinqif);
279
        if (!empty($vlan['members'])) {
280
                $members = explode(" ", $vlan['members']);
281
                foreach ($members as $qif)
282
                        interfaces_bring_up("{$vlanif}_{$qif}");
283
        }
284

    
285
        return $vlanif;
286
}
287

    
288
function interfaces_qinq_configure() {
289
	global $config, $g;
290
	if($g['booting'])
291
		echo "Configuring QinQ interfaces...";
292
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
293
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
294
			/* XXX: Maybe we should report any errors?! */
295
			interface_qinq_configure($qinq);
296
		}
297
	}
298
	if($g['booting'])
299
		echo "done.\n";
300
}
301

    
302
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
303
        global $config, $g;
304

    
305
        if (!is_array($qinq)) {
306
                log_error("QinQ compat VLAN: called with wrong options. Problems with config!\n");
307
                return;
308
        }
309

    
310
        $if = $qinq['if'];
311
        $tag = $qinq['tag'];
312
        $vlanif = "{$if}_{$tag}";
313
        if(empty($if)) {
314
                log_error("interface_qinq_confgure called with if undefined.\n");
315
                return;
316
        }
317

    
318
        fwrite($fd, "shutdown {$if}h{$tag}:\n");
319
        fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
320
        fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
321
        fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
322
        fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
323
        fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
324

    
325
        /* invalidate interface cache */
326
        get_interface_arr(true);
327

    
328
        return $vlanif;
329
}
330

    
331
function interfaces_create_wireless_clones() {
332
	global $config;
333

    
334
	if($g['booting'])
335
		echo "Creating other wireless clone interfaces...";
336
	if (is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
337
		foreach ($config['wireless']['clone'] as $clone) {
338
			if(empty($clone['cloneif']))
339
				continue;
340
			if(does_interface_exist($clone['cloneif']))
341
				continue;
342
			/* XXX: Maybe we should report any errors?! */
343
			if(interface_wireless_clone($clone['cloneif'], $clone))
344
				if($g['booting'])
345
					echo " " . $clone['cloneif'];
346
		}
347
	}
348
	if($g['booting'])
349
		echo " done.\n";
350
}
351

    
352
function interfaces_bridge_configure() {
353
        global $config;
354

    
355
        $i = 0;
356
        if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
357
                foreach ($config['bridges']['bridged'] as $bridge) {
358
                        if(empty($bridge['bridgeif']))
359
                                $bridge['bridgeif'] = "bridge{$i}";
360
                        /* XXX: Maybe we should report any errors?! */
361
                        interface_bridge_configure($bridge);
362
                        $i++;
363
                }
364
        }
365
}
366

    
367
function interface_bridge_configure(&$bridge) {
368
	global $config, $g;
369

    
370
	if (!is_array($bridge))
371
	        return -1;
372

    
373
	if (empty($bridge['members'])) {
374
		log_error("No members found on {$bridge['bridgeif']}");
375
		return -1;
376
	}
377

    
378
	$members = explode(',', $bridge['members']);
379
	if (!count($members))
380
		return -1;
381

    
382
	$checklist = get_configured_interface_list();
383

    
384
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
385
		pfSense_interface_destroy($bridge['bridgeif']);
386
		pfSense_interface_create($bridge['bridgeif']);
387
		$bridgeif = $bridge['bridgeif'];
388
	} else
389
		$bridgeif = pfSense_interface_create("bridge");
390

    
391
	/* Calculate smaller mtu and enforce it */
392
	$smallermtu = 0;
393
	$commonrx = true;
394
	$commontx = true;
395
	foreach ($members as $member) {
396
		$realif = get_real_interface($member);
397
		$opts = pfSense_get_interface_addresses($realif);
398
		$mtu = $opts['mtu'];
399
		if (!isset($opts['encaps']['txcsum']))
400
			$commontx = false;
401
		if (!isset($opts['encaps']['rxcsum']))
402
			$commonrx = false;
403
		if (!isset($opts['encaps']['tso4']))
404
			$commontso4 = false;
405
		if (!isset($opts['encaps']['tso6']))
406
			$commontso6 = false;
407
		if (!isset($opts['encaps']['lro']))
408
			$commonlro = false;
409
		if ($smallermtu == 0 && !empty($mtu))
410
			$smallermtu = $mtu;
411
		else if (!empty($mtu) && $mtu < $smallermtu)
412
			$smallermtu = $mtu;
413
	}
414
	 
415
	/* Just in case anything is not working well */
416
	if ($smallermtu == 0)
417
		$smallermtu = 1500; 
418

    
419
	$flags = 0;
420
	if ($commonrx === false)
421
		$flags |= IFCAP_RXCSUM;
422
	if ($commontx === false)
423
		$flags |= IFCAP_TXCSUM;
424
	if ($commontso4 === false)
425
		$flags |= IFCAP_TSO4;
426
	if ($commontso6 === false)
427
		$flags |= IFCAP_TSO6;
428
	if ($commonlro === false)
429
		$flags |= IFCAP_LRO;
430
		
431
	/* Add interfaces to bridge */
432
	foreach ($members as $member) {
433
		if (!array_key_exists($member, $checklist))
434
			continue;
435
		$realif1 = get_real_interface($member);
436
		$realif =  escapeshellarg($realif1);
437
		if (!$realif) {
438
			log_error("realif not defined in interfaces bridge - up");
439
			continue;
440
		}
441
		/* make sure the parent interface is up */
442
		pfSense_interface_mtu($realif1, $smallermtu);
443
		pfSense_interface_capabilities($realif1, -$flags);
444
		interfaces_bring_up($realif1);
445
		mwexec("/sbin/ifconfig {$bridgeif} addm {$realif}");	
446
	}
447

    
448
	if (isset($bridge['enablestp'])) {
449
		/* Choose spanning tree proto */
450
		mwexec("/sbin/ifconfig {$bridgeif} proto {$bridge['proto']}");	
451
		
452
		if (!empty($bridge['stp'])) {
453
			$stpifs = explode(',', $bridge['stp']);
454
			foreach ($stpifs as $stpif) {
455
				$realif = get_real_interface($stpif);
456
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
457
			}
458
		}
459
		if (!empty($bridge['maxage']))
460
			mwexec("/sbin/ifconfig {$bridgeif} maxage {$bridge['maxage']}");
461
		if (!empty($brige['fwdelay']))
462
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay {$bridge['fwdelay']}");
463
		if (!empty($brige['hellotime']))
464
                        mwexec("/sbin/ifconfig {$bridgeif} hellotime {$bridge['hellotime']}");
465
		if (!empty($brige['priority']))
466
                        mwexec("/sbin/ifconfig {$bridgeif} priority {$bridge['priority']}");
467
		if (!empty($brige['holdcount']))
468
                        mwexec("/sbin/ifconfig {$bridgeif} holdcnt {$bridge['holdcnt']}");
469
		if (!empty($bridge['ifpriority'])) {
470
			$pconfig = explode(",", $bridge['ifpriority']);
471
			$ifpriority = array();
472
			foreach ($pconfig as $cfg) {
473
				$embcfg = explode(":", $cfg);
474
				foreach ($embcfg as $key => $value)
475
					$ifpriority[$key] = $value;
476
			}
477
			foreach ($ifpriority as $key => $value) {
478
				$realif = get_real_interface($key);
479
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} {$value}"); 
480
			}
481
		}
482
		if (!empty($bridge['ifpathcost'])) {
483
			$pconfig = explode(",", $bridges['ifpathcost']);
484
			$ifpathcost = array();
485
			foreach ($pconfig as $cfg) {
486
				$embcfg = explode(":", $cfg);
487
				foreach ($embcfg as $key => $value)
488
					$ifpathcost[$key] = $value;
489
			}
490
			foreach ($ifpathcost as $key => $value) {
491
                        	$realif = get_real_interface($key);
492
                        	mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} {$value}");
493
                	}
494
		}
495
	}
496

    
497
	if ($bridge['maxaddr'] <> "")
498
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr {$bridge['maxaddr']}");
499
        if ($bridge['timeout'] <> "")
500
                mwexec("/sbin/ifconfig {$bridgeif} timeout {$bridge['timeout']}");
501
        if ($bridge['span'] <> "") {
502
		$realif = get_real_interface($bridge['span']);
503
                mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
504
	}
505
	if (!empty($bridge['edge'])) {
506
        	$edgeifs = explode(',', $bridge['edge']);
507
        	foreach ($edgeifs as $edgeif) {
508
			$realif = get_real_interface($edgeif);
509
                	mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
510
        	}
511
	}
512
	if (!empty($bridge['autoedge'])) {
513
        	$edgeifs = explode(',', $bridge['autoedge']);
514
        	foreach ($edgeifs as $edgeif) {
515
                	$realif = get_real_interface($edgeif);
516
                	mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
517
        	}
518
	}
519
	if (!empty($bridge['ptp'])) {
520
        	$ptpifs = explode(',', $bridge['ptp']);
521
        	foreach ($ptpifs as $ptpif) {
522
                	$realif = get_real_interface($ptpif);
523
                	mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
524
        	}
525
	}
526
	if (!empty($bridge['autoptp'])) {
527
        	$ptpifs = explode(',', $bridge['autoptp']);
528
        	foreach ($ptpifs as $ptpif) {
529
                	$realif = get_real_interface($ptpif);
530
                	mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
531
        	}
532
	}
533
	if (!empty($bridge['static'])) {
534
        	$stickyifs = explode(',', $bridge['static']);
535
        	foreach ($stickyifs as $stickyif) {
536
                	$realif = get_real_interface($stickyif);
537
                	mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
538
        	}
539
	}
540
	if (!empty($bridge['private'])) {
541
        	$privateifs = explode(',', $bridge['private']);
542
        	foreach ($privateifs as $privateif) {
543
                	$realif = get_real_interface($privateif);
544
               	 	mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
545
        	}
546
	}
547

    
548
	if($bridgeif)
549
		interfaces_bring_up($bridgeif);	
550
	else 
551
		log_error("bridgeif not defined -- could not bring interface up");
552

    
553
	return $bridgeif;
554
}
555

    
556
function interface_bridge_add_member($bridgeif, $interface) {
557

    
558
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
559
		return;
560

    
561
	$mtu = get_interface_mtu($brigeif);
562
	$mtum = get_interface_mtu($interface);
563
	
564
	if ($mtu != $mtum)
565
		pfSense_interface_mtu($interface, $mtu);
566

    
567
	$options = pfSense_get_interface_addresses($bridgeif);
568
	$flags = 0;
569
	if (!isset($options['encaps']['txcsum']))
570
		$flags |= IFCAP_TXCSUM;
571

    
572
	if (!isset($options['encaps']['rxcsum']))
573
		$flags |= IFCAP_RXCSUM;
574

    
575
	pfSense_interface_capabilities($interface, -$flags);
576

    
577
	interfaces_bring_up($interface);
578
	mwexec("/sbin/ifconfig {$bridgeif} addm {$interface}");
579
}
580

    
581
function interfaces_lagg_configure() 
582
{
583
        global $config, $g;
584
		if($g['booting']) 
585
			echo "Configuring LAGG interfaces...";
586
        $i = 0;
587
		if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
588
			foreach ($config['laggs']['lagg'] as $lagg) {
589
				if(empty($lagg['laggif']))
590
					$lagg['laggif'] = "lagg{$i}";
591
				/* XXX: Maybe we should report any errors?! */
592
				interface_lagg_configure($lagg);
593
				$i++;
594
			}
595
		}
596
		if($g['booting']) 
597
			echo "done.\n";
598
}
599

    
600
function interface_lagg_configure(&$lagg) {
601
        global $config, $g;
602

    
603
        if (!is_array($lagg))
604
		return -1;
605

    
606
	$members = explode(',', $lagg['members']);
607
	if (!count($members))
608
		return -1;
609
	
610
	$checklist = get_interface_list();
611

    
612
	if ($g['booting'] || !(empty($lagg['laggif']))) {
613
		pfSense_interface_destroy($lagg['laggif']);
614
		pfSense_interface_create($lagg['laggif']);
615
                $laggif = $lagg['laggif'];
616
        } else
617
		$laggif = pfSense_interface_create("lagg");
618

    
619
	/* Calculate smaller mtu and enforce it */
620
        $smallermtu = 0;
621
        foreach ($members as $member) {
622
		$opts = pfSense_get_interface_addresses($member);
623
                $mtu = $opts['mtu'];
624
		if (!isset($opts['encaps']['txcsum']))
625
                        $commontx = false;
626
                if (!isset($opts['encaps']['rxcsum']))
627
                        $commonrx = false;
628
		if (!isset($opts['encaps']['tso4']))
629
			$commontso4 = false;
630
		if (!isset($opts['encaps']['tso6']))
631
			$commontso6 = false;
632
		if (!isset($opts['encaps']['lro']))
633
			$commonlro = false;
634
		if ($smallermtu == 0 && !empty($mtu))
635
			$smallermtu = $mtu;
636
                else if (!empty($mtu) && $mtu < $smallermtu)
637
                        $smallermtu = $mtu;
638
        }
639

    
640
	/* Just in case anything is not working well */
641
        if ($smallermtu == 0)
642
                $smallermtu = 1500;
643

    
644
	$flags = 0;
645
        if ($commonrx === false)
646
                $flags |= IFCAP_RXCSUM;
647
        if ($commontx === false)
648
                $flags |= IFCAP_TXCSUM;
649
	if ($commontso4 === false)
650
                $flags |= IFCAP_TSO4;
651
        if ($commontso6 === false)
652
                $flags |= IFCAP_TSO6;
653
        if ($commonlro === false)
654
                $flags |= IFCAP_LRO;
655

    
656
	foreach ($members as $member) {
657
		if (!array_key_exists($member, $checklist))
658
			continue;
659
		/* make sure the parent interface is up */
660
		pfSense_interface_mtu($member, $smallermtu);
661
		pfSense_interface_capabilities($member, -$flags);
662
		interfaces_bring_up($member);
663
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
664
	}
665
	
666
	mwexec("/sbin/ifconfig {$laggif} laggproto {$lagg['proto']}");
667

    
668
	interfaces_bring_up($laggif);
669

    
670
	return $laggif;
671
}
672

    
673
function interfaces_gre_configure() {
674
        global $config;
675

    
676
        if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
677
                foreach ($config['gres']['gre'] as $i => $gre) {
678
                        if(empty($gre['greif']))
679
                                $gre['greif'] = "gre{$i}";
680
                        /* XXX: Maybe we should report any errors?! */
681
                        interface_gre_configure($gre);
682
                }
683
        }
684
}
685

    
686
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
687
function interface_gre_configure(&$gre, $grekey = "") {
688
        global $config, $g;
689

    
690
	if (!is_array($gre))
691
		return -1;
692

    
693
	$realif = get_real_interface($gre['if']);
694
	$realifip = get_interface_ip($gre['if']);
695

    
696
	/* make sure the parent interface is up */
697
	interfaces_bring_up($realif);
698

    
699
	if ($g['booting'] || !(empty($gre['greif']))) {
700
		pfSense_interface_destroy($gre['greif']);
701
		pfSense_interface_create($gre['greif']);
702
		$greif = $gre['greif'];
703
	} else
704
		$greif = pfSense_interface_create("gre");
705

    
706
	/* Do not change the order here for more see gre(4) NOTES section. */
707
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} {$gre['remote-addr']}");
708
	mwexec("/sbin/ifconfig {$greif} {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
709
	if (isset($gre['link0']) && $gre['link0'])
710
		pfSense_interface_flags($greif, IFF_LINK0);
711
	if (isset($gre['link1']) && $gre['link1'])
712
		pfSense_interface_flags($greif, IFF_LINK1);
713
	if (isset($gre['link2']) && $gre['link2'])
714
		pfSense_interface_flags($greif, IFF_LINK2);
715

    
716
	if($greif)
717
		interfaces_bring_up($greif);
718
	else 
719
		log_error("Could not bring greif up -- variable not defined.");
720

    
721
	if (isset($gre['link1']) && $gre['link1'])
722
		mwexec("/sbin/route add {$gre['tunnel-remote-addr']}/{$gre['tunnel-remote-net']} {$gre['tunnel-local-addr']}");
723
	file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
724

    
725
	return $greif;
726
}
727

    
728
function interfaces_gif_configure() {
729
	global $config;
730

    
731
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
732
		foreach ($config['gifs']['gif'] as $i => $gif) {
733
			if(empty($gif['gifif']))
734
				$gre['gifif'] = "gif{$i}";
735
			/* XXX: Maybe we should report any errors?! */
736
			interface_gif_configure($gif);
737
		}
738
	}
739
}
740

    
741
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
742
function interface_gif_configure(&$gif, $gifkey = "") {
743
	global $config, $g;
744

    
745
	if (!is_array($gif))
746
		return -1;
747

    
748
	$realif = get_real_interface($gif['if']);
749
	$realifip = get_interface_ip($gif['if']);
750

    
751
	/* make sure the parent interface is up */
752
	if($realif)
753
		interfaces_bring_up($realif);
754
	else 
755
		log_error("could not bring realif up -- variable not defined -- interface_gif_configure()");
756

    
757
	if ($g['booting'] || !(empty($gif['gifif']))) {
758
		pfSense_interface_destroy($gif['gifif']);
759
		pfSense_interface_create($gif['gifif']);
760
		$gifif = $gif['gifif'];
761
	} else
762
		$gifif = pfSense_interface_create("gif");
763

    
764
	/* Do not change the order here for more see gif(4) NOTES section. */
765
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} {$gif['remote-addr']}");
766
	mwexec("/sbin/ifconfig {$gifif} {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
767
	if (isset($gif['link0']) && $gif['link0'])
768
		pfSense_interface_flags($gifif, IFF_LINK0);
769
	if (isset($gif['link1']) && $gif['link1'])
770
		pfSense_interface_flags($gifif, IFF_LINK1);
771
	if($gifif)
772
		interfaces_bring_up($gifif);
773
	else
774
		log_error("could not bring gifif up -- variable not defined");
775

    
776
	/* XXX: Needed?! */
777
	//mwexec("/sbin/route add {$gif['tunnel-remote-addr']}/{$gif['tunnel-remote-net']} -iface {$gifif}");
778
	file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
779

    
780
	return $gifif;
781
}
782

    
783
function interfaces_configure() {
784
	global $config, $g;
785

    
786
	/* Set up our loopback interface */
787
	interfaces_loopback_configure();
788

    
789
	/* set up LAGG virtual interfaces */
790
	interfaces_lagg_configure();
791

    
792
	/* set up VLAN virtual interfaces */
793
	interfaces_vlan_configure();
794

    
795
	interfaces_qinq_configure();
796

    
797
	$iflist = get_configured_interface_with_descr();
798
	$delayed_list = array();
799
	$bridge_list = array();
800
	
801
	/* This is needed to speedup interfaces on bootup. */
802
	$reload = false;
803
	if ($g['booting'])
804
		$reload = true;
805

    
806
	foreach($iflist as $if => $ifname) {
807
		$realif = $config['interfaces'][$if]['if'];
808
		if (strstr($realif, "bridge")) 
809
			$bridge_list[$if] = $ifname;
810
		else if (strstr($realif, "gre"))
811
			$delayed_list[$if] = $ifname;
812
		else if (strstr($realif, "gif"))
813
			$delayed_list[$if] = $ifname;
814
		else if (strstr($realif, "ovpn")) {
815
			//echo "Delaying OpenVPN interface configuration...done.\n";
816
			continue;
817
		} else {
818
			if ($g['booting'])
819
				echo "Configuring {$ifname} interface...";
820
			if($g['debug'])
821
				log_error("Configuring {$ifname}");
822
			interface_configure($if, $reload);
823
			if ($g['booting']) 
824
				echo "done.\n";
825
		}
826
	}
827

    
828
	/* create the unconfigured wireless clones */
829
	interfaces_create_wireless_clones();
830

    
831
	/* set up GRE virtual interfaces */
832
	interfaces_gre_configure();
833

    
834
	/* set up GIF virtual interfaces */
835
	interfaces_gif_configure();
836
	
837
	foreach ($delayed_list as $if => $ifname) {
838
		if ($g['booting'])
839
			echo "Configuring {$ifname} interface...";
840
        	if ($g['debug'])
841
        		log_error("Configuring {$ifname}");
842

    
843
		interface_configure($if, $reload);
844

    
845
		if ($g['booting'])
846
			echo "done.\n";
847
	}
848

    
849
	/* set up BRIDGe virtual interfaces */
850
	interfaces_bridge_configure();
851

    
852
	foreach ($bridge_list as $if => $ifname) {
853
		if ($g['booting'])
854
			echo "Configuring {$ifname} interface...";
855
		if($g['debug'])
856
			log_error("Configuring {$ifname}");
857

    
858
		interface_configure($if, $reload);
859

    
860
		if ($g['booting'])
861
			echo "done.\n";
862
	}
863

    
864
	/* bring up vip interfaces */
865
	interfaces_vips_configure();
866

    
867
	/* configure interface groups */
868
	interfaces_group_setup();
869

    
870
	if (!$g['booting']) {
871
		/* reconfigure static routes (kernel may have deleted them) */
872
		system_routing_configure();
873

    
874
		/* reload IPsec tunnels */
875
		vpn_ipsec_configure();
876

    
877
		/* reload dhcpd (interface enabled/disabled status may have changed) */
878
		services_dhcpd_configure();
879

    
880
		/* restart dnsmasq */
881
		services_dnsmasq_configure();
882

    
883
		/* reload captive portal */
884
		captiveportal_init_rules();
885
	}
886

    
887
	return 0;
888
}
889

    
890
function interface_reconfigure($interface = "wan") {
891
	interface_bring_down($interface);
892
	interface_configure($interface, true);
893
}
894

    
895
function interface_vip_bring_down($vip) {
896
	global $g;
897

    
898
	switch ($vip['mode']) {
899
	case "proxyarp":
900
		$vipif = get_real_interface($vip['interface']);
901
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
902
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
903
		break;
904
	case "ipalias":
905
		$vipif = get_real_interface($vip['interface']);
906
		if(does_interface_exist($vipif))
907
			pfSense_interface_deladdress($vipif, $vip['subnet']);
908
		break;
909
	case "carp":
910
		$vipif = "vip" . $vip['vhid'];
911
		if(does_interface_exist($vipif)) 
912
			pfSense_interface_destroy($vipif);
913
		break;
914
	case "carpdev-dhcp":
915
		$vipif = "vip" . $vip['vhid'];
916
		if(does_interface_exist($vipif)) 
917
			pfSense_interface_destroy($vipif);
918
		break;
919
	}
920
}
921

    
922
function interface_bring_down($interface = "wan", $destroy = false) {
923
	global $config, $g;
924

    
925
	if (!isset($config['interfaces'][$interface]))
926
		return; 
927

    
928
	$ifcfg = $config['interfaces'][$interface];
929

    
930
	$realif = get_real_interface($interface);
931

    
932
	switch ($ifcfg['ipaddr']) {
933
	case "ppp":
934
	case "pppoe":
935
	case "pptp":
936
	case "l2tp":
937
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
938
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
939
				if ($realif == $ppp['if']) {
940
					if (isset($ppp['ondemand']) && !$destroy){
941
						send_event("interface reconfigure {$interface}");
942
						break;
943
					}
944
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
945
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
946
						sleep(2);
947
					}
948
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
949
					break;
950
				}
951
			}
952
		}
953
		break;
954
	case "carpdev-dhcp":
955
		/* 
956
		 * NB: When carpdev gets enabled it would be better to be handled as all
957
		 *	   other interfaces! 
958
		 */
959
	case "dhcp":
960
		$pid = find_dhclient_process($realif);
961
		if($pid)
962
			mwexec("/bin/kill {$pid}");
963
		sleep(1);
964
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
965
		if(does_interface_exist("$realif")) {
966
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
967
			if ($destroy == true)
968
				pfSense_interface_flags($realif, -IFF_UP);
969
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
970
		}
971
		break;
972
	default:
973
		if(does_interface_exist("$realif")) {
974
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
975
			if ($destroy == true)
976
				pfSense_interface_flags($realif, -IFF_UP);
977
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
978
		}
979
		break;
980
	}
981

    
982
	/* remove interface up file if it exists */
983
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
984
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
985
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
986
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
987
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
988
	
989
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
990
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
991
	if (is_array($ifcfg['wireless'])) {
992
		mwexec(kill_hostapd($realif));
993
		mwexec(kill_wpasupplicant($realif));
994
	}
995

    
996
	if ($destroy == true) {
997
		if (preg_match("/^vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan/i", $realif))
998
			pfSense_interface_destroy($realif);
999
	}	
1000

    
1001
	return;
1002
}
1003

    
1004
function interfaces_ptpid_used($ptpid) {
1005
	global $config;
1006

    
1007
	if (is_array($config['ppps']['ppp']))
1008
		foreach ($config['ppps']['ppp'] as & $settings)
1009
			if ($ptpid == $settings['ptpid'])
1010
				return true;
1011

    
1012
	return false;
1013
}
1014

    
1015
function interfaces_ptpid_next() {
1016

    
1017
	$ptpid = 0;
1018
	while(interfaces_ptpid_used($ptpid))
1019
		$ptpid++;
1020

    
1021
	return $ptpid;
1022
}
1023

    
1024
function getMPDCRONSettings($pppif_) {
1025
	global $config;
1026
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
1027
	if (is_array($config['cron']['item'])) {
1028
		for ($i = 0; $i < count($config['cron']['item']); $i++) {
1029
			$item = $config['cron']['item'][$i];
1030
			if (strpos($item['command'], $cron_cmd_file.$pppif_) !== false) {
1031
				return array("ID" => $i, "ITEM" => $item);
1032
			}
1033
		}
1034
	}
1035
	return NULL;
1036
}
1037

    
1038
function handle_pppoe_reset($post_array) {
1039
	global $config, $g;
1040

    
1041
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_";
1042

    
1043
	$pppif = $post_array['type'].$post_array['ptpid'];
1044
	if (!is_array($config['cron']['item'])) 
1045
		$config['cron']['item'] = array(); 
1046
	$itemhash = getMPDCRONSettings($pppif);
1047
	$item = $itemhash['ITEM'];
1048
	
1049
	// reset cron items if necessary and return
1050
	if (empty($post_array['pppoe-reset-type'])) {
1051
		if (isset($item))
1052
			unset($config['cron']['item'][$itemhash['ID']]);
1053
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1054
		return;
1055
	}
1056

    
1057
	if (empty($item)) 
1058
		$item = array();
1059
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1060
		$item['minute'] = $post_array['pppoe_resetminute'];
1061
		$item['hour'] = $post_array['pppoe_resethour'];
1062
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1063
			$date = explode("/", $post_array['pppoe_resetdate']);
1064
			$item['mday'] = $date[1];
1065
			$item['month'] = $date[0];
1066
		} else {
1067
			$item['mday'] = "*";
1068
			$item['month'] = "*";
1069
		}
1070
		$item['wday'] = "*";
1071
		$item['who'] = "root";
1072
		$item['command'] = $cron_cmd_file.$pppif;
1073
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1074
		switch ($post_array['pppoe_pr_preset_val']) {
1075
			case "monthly":
1076
				$item['minute'] = "0";
1077
				$item['hour'] = "0";
1078
				$item['mday'] = "1";
1079
				$item['month'] = "*";
1080
				$item['wday'] = "*";
1081
				$item['who'] = "root";
1082
				$item['command'] = $cron_cmd_file.$pppif;
1083
				break;
1084
	        case "weekly":
1085
				$item['minute'] = "0";
1086
				$item['hour'] = "0";
1087
				$item['mday'] = "*";
1088
				$item['month'] = "*";
1089
				$item['wday'] = "0";
1090
				$item['who'] = "root";
1091
				$item['command'] = $cron_cmd_file.$pppif;
1092
				break;
1093
			case "daily":
1094
				$item['minute'] = "0";
1095
				$item['hour'] = "0";
1096
				$item['mday'] = "*";
1097
				$item['month'] = "*";
1098
				$item['wday'] = "*";
1099
				$item['who'] = "root";
1100
				$item['command'] = $cron_cmd_file.$pppif;
1101
				break;
1102
			case "hourly":
1103
				$item['minute'] = "0";
1104
				$item['hour'] = "*";
1105
				$item['mday'] = "*";
1106
				$item['month'] = "*";
1107
				$item['wday'] = "*";
1108
				$item['who'] = "root";
1109
				$item['command'] = $cron_cmd_file.$pppif;
1110
				break;
1111
		} // end switch
1112
	} else {
1113
		/* test whether a cron item exists and unset() it if necessary */
1114
		$itemhash = getMPDCRONSettings($pppif);
1115
		$item = $itemhash['ITEM'];
1116
		if (isset($item))
1117
			unset($config['cron']['item'][$itemhash['ID']]); 
1118
	}// end if
1119
	if (isset($itemhash['ID'])) 
1120
		$config['cron']['item'][$itemhash['ID']] = $item;
1121
	else 
1122
		$config['cron']['item'][] = $item;
1123
}
1124

    
1125
/*	This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1126
*	It writes the mpd config file to /var/etc every time the link is opened.
1127
*/
1128

    
1129
function interface_ppps_configure($interface) {
1130
	global $config, $g;
1131
	
1132
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1133
	if(!is_dir("/var/spool/lock")) {
1134
		exec("/bin/mkdir -p /var/spool/lock");
1135
		exec("/bin/chmod a+rw /var/spool/lock/.");
1136
	}
1137
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files	
1138
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1139
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1140
		
1141
	$ifcfg = $config['interfaces'][$interface];
1142
	if (!isset($ifcfg['enable']))
1143
		return 0;
1144
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1145
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1146
			if ($ifcfg['if'] == $ppp['if'])
1147
				break;
1148
		}
1149
	}
1150
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1151
		log_error("Can't find PPP config for {$ifcfg['if']} in interface_ppps_configure().");
1152
		return 0;
1153
	}
1154
	$pppif = $ifcfg['if'];
1155
	if ($ppp['type'] == "ppp")
1156
		$type = "modem";
1157
	else
1158
		$type = $ppp['type'];
1159
	$upper_type = strtoupper($ppp['type']);	
1160
	
1161
	if($g['booting']) {
1162
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1163
		echo "starting {$pppif} link...";
1164
		// Do not re-configure the interface if we are booting and it's already been started
1165
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1166
			return 0;
1167
	}
1168
	
1169
	$ports = explode(',',$ppp['ports']);
1170
	if ($type != "modem") {
1171
		foreach ($ports as $pid => $port)
1172
			$ports[$pid] = get_real_interface($port);
1173
	}
1174
	$localips = explode(',',$ppp['localip']);
1175
	$gateways = explode(',',$ppp['gateway']);
1176
	$subnets = explode(',',$ppp['subnet']);
1177
	
1178
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1179
	to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1180
	*/
1181
	foreach($ports as $pid => $port){
1182
		switch ($ppp['type']) {
1183
			case "pppoe": 
1184
				/* Bring the parent interface up */
1185
				interfaces_bring_up($port);
1186
				pfSense_ngctl_attach(".", $port);
1187
				break;
1188
			case "pptp":
1189
			case "l2tp":
1190
				/* configure interface */
1191
				if(is_ipaddr($localips[$pid])){
1192
					// Manually configure interface IP/subnet
1193
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1194
					interfaces_bring_up($port);
1195
				} else if (empty($localips[$pid]))
1196
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1197
				
1198
				if(!is_ipaddr($localips[$pid])){
1199
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure.");
1200
					return 0;
1201
				}
1202
				/* XXX: This needs to go away soon! [It's commented out!] */
1203
				/* Configure the gateway (remote IP ) */
1204
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1205
					/* XXX: Fix later 
1206
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1207
					if(!is_ipaddr($gateways[$pid])) {
1208
						log_error("Could not get a valid Gateway IP from {$port} via DNS in interfaces_ppps_configure.");
1209
						return 0;
1210
					}
1211
					*/
1212
				}
1213
				if(!is_ipaddr($gateways[$pid])){
1214
					log_error("Could not get a PPTP/L2TP Remote IP address from {$dhcp_gateway} for {$gway} in interfaces_ppps_configure.");
1215
					return 0;
1216
				}
1217
				pfSense_ngctl_attach(".", $port);
1218
				break;
1219
			case "ppp":
1220
				if (!file_exists("{$port}")) {
1221
					log_error("Device {$port} does not exist. PPP link cannot start without the modem device.");
1222
					return 0;
1223
				}
1224
				break;
1225
			default:
1226
				log_error("Unkown {$type} configured as ppp interface.");
1227
				break;
1228
		}
1229
	}
1230
	
1231
	if (is_array($ports) && count($ports) > 1)
1232
		$multilink = "enable";
1233
	else
1234
		$multilink = "disable";
1235
	
1236
	if ($type == "modem"){
1237
		if (is_ipaddr($ppp['localip']))
1238
			$localip = $ppp['localip'];
1239
		else
1240
			$localip = '0.0.0.0';
1241

    
1242
		if (is_ipaddr($ppp['gateway']))
1243
			$gateway = $ppp['gateway'];
1244
		else
1245
			$gateway = "10.64.64.{$pppid}";
1246
		$ranges = "{$localip}/0 {$gateway}/0";
1247
		
1248
		if (empty($ppp['apnum']))	
1249
			$ppp['apnum'] = 1;
1250
	} else
1251
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1252

    
1253
	if (isset($ppp['ondemand'])) 
1254
		$ondemand = "enable";
1255
	else
1256
		$ondemand = "disable";
1257
	if (!isset($ppp['idletimeout']))
1258
		$ppp['idletimeout'] = 0;
1259

    
1260
	if (empty($ppp['username']) && $type == "modem"){
1261
		$ppp['username'] = "user";
1262
		$ppp['password'] = "none";
1263
	}
1264
	if (empty($ppp['password']) && $type == "modem")
1265
		$passwd = "none";
1266
	else
1267
		$passwd = base64_decode($ppp['password']);
1268

    
1269
	$bandwidths = explode(',',$ppp['bandwidth']);
1270
	$mtus = explode(',',$ppp['mtu']);
1271
	$mrus = explode(',',$ppp['mru']);
1272

    
1273
	if (isset($ppp['mrru']))
1274
		$mrrus = explode(',',$ppp['mrru']);
1275

    
1276
	// Construct the mpd.conf file
1277
	$mpdconf = <<<EOD
1278
startup:
1279
	# configure the console
1280
	set console close
1281
	# configure the web server
1282
	set web close
1283

    
1284
default:
1285
{$ppp['type']}client:
1286
	create bundle static {$interface}
1287
	set iface name {$pppif}
1288

    
1289
EOD;
1290
	$setdefaultgw = false;
1291
	$founddefaultgw = false;
1292
	if (is_array($config['gateways']['gateway_item'])) {
1293
		foreach($config['gateways']['gateway_item'] as $gateway) {
1294
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1295
				$setdefaultgw = true;
1296
				break;
1297
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1298
				$founddefaultgw = true;
1299
				break;
1300
			}
1301
		}
1302
	}
1303
	
1304
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1305
		$setdefaultgw = true;
1306
		$mpdconf .= <<<EOD
1307
	set iface route default
1308

    
1309
EOD;
1310
	}
1311
	$mpdconf .= <<<EOD
1312
	set iface {$ondemand} on-demand
1313
	set iface idle {$ppp['idletimeout']}
1314

    
1315
EOD;
1316

    
1317
	if (isset($ppp['ondemand']))
1318
		$mpdconf .= <<<EOD
1319
	set iface addrs 10.10.1.1 10.10.1.2
1320

    
1321
EOD;
1322
	
1323
	if (isset($ppp['tcpmssfix']))
1324
		$tcpmss = "disable";
1325
	else
1326
		$tcpmss = "enable";
1327
		$mpdconf .= <<<EOD
1328
	set iface {$tcpmss} tcpmssfix
1329

    
1330
EOD;
1331

    
1332
	$mpdconf .= <<<EOD
1333
	set iface up-script /usr/local/sbin/ppp-linkup
1334
	set iface down-script /usr/local/sbin/ppp-linkdown
1335
	set ipcp ranges {$ranges}
1336

    
1337
EOD;
1338
	if (isset($ppp['vjcomp']))
1339
		$mpdconf .= <<<EOD
1340
	set ipcp no vjcomp
1341

    
1342
EOD;
1343

    
1344
	if (isset($config['system']['dnsallowoverride']))
1345
		$mpdconf .= <<<EOD
1346
	set ipcp enable req-pri-dns
1347
	set ipcp enable req-sec-dns
1348

    
1349
EOD;
1350
	if (!isset($ppp['verbose_log']))
1351
		$mpdconf .= <<<EOD
1352
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1353

    
1354
EOD;
1355
	foreach($ports as $pid => $port){
1356
		$port = get_real_interface($port);
1357
		$mpdconf .= <<<EOD
1358

    
1359
	create link static {$interface}_link{$pid} {$type}
1360
	set link action bundle {$interface}
1361
	set link {$multilink} multilink
1362
	set link keep-alive 10 60
1363
	set link max-redial 0
1364

    
1365
EOD;
1366
		if (isset($ppp['shortseq']))
1367
			$mpdconf .= <<<EOD
1368
	set link no shortseq
1369

    
1370
EOD;
1371

    
1372
		if (isset($ppp['acfcomp']))
1373
			$mpdconf .= <<<EOD
1374
	set link no acfcomp
1375

    
1376
EOD;
1377

    
1378
		if (isset($ppp['protocomp']))
1379
			$mpdconf .= <<<EOD
1380
	set link no protocomp
1381

    
1382
EOD;
1383

    
1384
		$mpdconf .= <<<EOD
1385
	set link disable chap pap
1386
	set link accept chap pap eap
1387
	set link disable incoming
1388

    
1389
EOD;
1390

    
1391

    
1392
		if (!empty($bandwidths[$pid]))
1393
			$mpdconf .= <<<EOD
1394
	set link bandwidth {$bandwidths[$pid]}
1395

    
1396
EOD;
1397

    
1398
		if (empty($mtus[$pid]))
1399
			$mtus[$pid] = "1492";
1400
			$mpdconf .= <<<EOD
1401
	set link mtu {$mtus[$pid]}
1402

    
1403
EOD;
1404

    
1405
		if (!empty($mrus[$pid]))
1406
			$mpdconf .= <<<EOD
1407
	set link mru {$mrus[$pid]}
1408

    
1409
EOD;
1410

    
1411
		if (!empty($mrrus[$pid]))
1412
			$mpdconf .= <<<EOD
1413
	set link mrru {$mrrus[$pid]}
1414

    
1415
EOD;
1416

    
1417
		$mpdconf .= <<<EOD
1418
	set auth authname "{$ppp['username']}"
1419
	set auth password {$passwd}
1420

    
1421
EOD;
1422
		if ($type == "modem") {
1423
			$mpdconf .= <<<EOD
1424
	set modem device {$ppp['ports']}
1425
	set modem script DialPeer
1426
	set modem idle-script Ringback
1427
	set modem watch -cd
1428
	set modem var \$DialPrefix "DT"
1429
	set modem var \$Telephone "{$ppp['phone']}"
1430

    
1431
EOD;
1432
		}
1433
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1434
			$mpdconf .= <<<EOD
1435
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1436

    
1437
EOD;
1438
		}
1439
		if (isset($ppp['initstr']) && $type == "modem") {
1440
			$initstr = base64_decode($ppp['initstr']);
1441
			$mpdconf .= <<<EOD
1442
	set modem var \$InitString "{$initstr}"
1443

    
1444
EOD;
1445
		}
1446
		if (isset($ppp['simpin']) && $type == "modem") {
1447
			$mpdconf .= <<<EOD
1448
	set modem var \$SimPin "{$ppp['simpin']}"
1449
	set modem var \$PinWait "{$ppp['pin-wait']}"
1450

    
1451
EOD;
1452
		}
1453
		if (isset($ppp['apn']) && $type == "modem") {
1454
			$mpdconf .= <<<EOD
1455
	set modem var \$APN "{$ppp['apn']}"
1456
	set modem var \$APNum "{$ppp['apnum']}"
1457

    
1458
EOD;
1459
		}
1460
		if (isset($ppp['provider']) && $type == "pppoe") {
1461
			$mpdconf .= <<<EOD
1462
	set pppoe service "{$ppp['provider']}"
1463

    
1464
EOD;
1465
		}
1466
		if ($type == "pppoe")
1467
			$mpdconf .= <<<EOD
1468
	set pppoe iface {$port}
1469

    
1470
EOD;
1471

    
1472
		if ($type == "pptp" || $type == "l2tp") {
1473
			$mpdconf .= <<<EOD
1474
	set {$type} self {$localips[$pid]}
1475
	set {$type} peer {$gateways[$pid]}
1476
	set {$type} disable windowing
1477

    
1478
EOD;
1479
		}
1480
		
1481
		$mpdconf .= "\topen\r\n";
1482
	} //end foreach($port)
1483

    
1484

    
1485
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1486
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1487
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1488
	else {
1489
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1490
		if (!$fd) {
1491
			log_error("Error: cannot open mpd_{$interface}.conf in interface_ppps_configure().\n");
1492
			return 0;
1493
		}
1494
		// Write out mpd_ppp.conf
1495
		fwrite($fd, $mpdconf);
1496
		fclose($fd);
1497
	}
1498

    
1499
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1500
	if (isset($ppp['uptime'])) {
1501
		if (!file_exists("/conf/{$pppif}.log")) {
1502
			conf_mount_rw();
1503
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1504
			conf_mount_ro();
1505
		}
1506
	} else {
1507
		if (file_exists("/conf/{$pppif}.log")) {
1508
			conf_mount_rw();
1509
			mwexec("rm -f /conf/{$pppif}.log");
1510
			conf_mount_ro();
1511
		}
1512
	}
1513

    
1514
	/* fire up mpd */
1515
	mwexec("/usr/local/sbin/mpd5 -b -k -d {$g['varetc_path']} -f mpd_{$interface}.conf -p {$g['varrun_path']}/{$ppp['type']}_{$interface}.pid -s ppp {$ppp['type']}client");
1516

    
1517
	// Check for PPPoE periodic reset request 
1518
	if ($type == "pppoe") {
1519
		if (isset($ppp['pppoe-reset-type']))
1520
			setup_pppoe_reset_file($ppp['if'], $interface);
1521
		else
1522
			setup_pppoe_reset_file($ppp['if']);
1523
	}
1524

    
1525
	return 1;
1526
}
1527

    
1528
function interfaces_carp_setup() {
1529
	global $g, $config;
1530

    
1531
	$balanacing = "";
1532
	$pfsyncinterface = "";
1533
	$pfsyncenabled = "";
1534
	if(isset($config['system']['developerspew'])) {
1535
		$mt = microtime();
1536
		echo "interfaces_carp_setup() being called $mt\n";
1537
	}
1538

    
1539
	// Prepare CmdCHAIN that will be used to execute commands.
1540
	$cmdchain = new CmdCHAIN();	
1541

    
1542
	if ($g['booting']) {
1543
		echo "Configuring CARP settings...";
1544
		mute_kernel_msgs();
1545
	}
1546

    
1547
	/* suck in configuration items */
1548
	if($config['installedpackages']['carpsettings']) {
1549
		if($config['installedpackages']['carpsettings']['config']) {
1550
			foreach($config['installedpackages']['carpsettings']['config'] as $carp) {
1551
				$pfsyncenabled = $carp['pfsyncenabled'];
1552
				$balanacing = $carp['balancing'];
1553
				$pfsyncinterface = $carp['pfsyncinterface'];
1554
				$pfsyncpeerip = $carp['pfsyncpeerip'];
1555
			}
1556
		}
1557
	} else {
1558
		unset($pfsyncinterface);
1559
		unset($balanacing);
1560
		unset($pfsyncenabled);
1561
	}
1562

    
1563
	$cmdchain->add("Allow CARP", "/sbin/sysctl net.inet.carp.allow=1", true);			
1564
	if($balanacing) {
1565
		$cmdchain->add("Enable CARP ARP-balancing", "/sbin/sysctl net.inet.carp.arpbalance=1", true);
1566
		$cmdchain->add("Disallow CARP preemption", "/sbin/sysctl net.inet.carp.preempt=0", true);
1567
	} else
1568
		$cmdchain->add("Enable CARP preemption", "/sbin/sysctl net.inet.carp.preempt=1", true);		
1569

    
1570
	$cmdchain->add("Enable CARP logging", "/sbin/sysctl net.inet.carp.log=1", true);
1571
	if (!empty($pfsyncinterface))
1572
		$carp_sync_int = get_real_interface($pfsyncinterface);
1573

    
1574
	if($g['booting']) {
1575
		/*    install rules to alllow pfsync to sync up during boot
1576
		 *    carp interfaces will remain down until the bootup sequence finishes
1577
		 */
1578
		$fd = fopen("{$g['tmp_path']}/rules.boot", "w");
1579
		if ($fd) {
1580
			fwrite($fd, "pass quick proto carp all keep state\n");
1581
			fwrite($fd, "pass quick proto pfsync all\n");
1582
			fwrite($fd, "pass out quick from any to any keep state\n");
1583
			fclose($fd);
1584
			mwexec("/sbin/pfctl -f {$g['tmp_path']}/rules.boot");
1585
		} else
1586
			log_error("Could not create rules.boot file!");
1587
	}
1588

    
1589
	/* setup pfsync interface */
1590
	if($carp_sync_int and $pfsyncenabled) {
1591
		if (is_ipaddr($pfsyncpeerip))
1592
			$cmdchain->add("Bring up pfsync0 syncpeer", "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} syncpeer {$pfsyncpeerip} up", false);						
1593
		else
1594
			$cmdchain->add("Bring up pfsync0 syncdev", "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} up", false);			
1595
	} else
1596
		$cmdchain->add("Bring up pfsync0", "/sbin/ifconfig pfsync0 syncdev lo0 up", false);						
1597

    
1598
	if($config['virtualip']['vip'])
1599
		$cmdchain->add("Allow CARP.", "/sbin/sysctl net.inet.carp.allow=1", true);				
1600
	else
1601
		$cmdchain->add("Disallow CARP.", "/sbin/sysctl net.inet.carp.allow=0", true);		
1602
	
1603
	if($g['debug'])
1604
		$cmdchain->setdebug(); // optional for verbose logging
1605

    
1606
	$cmdchain->execute();
1607
	$cmdchain->clear();
1608

    
1609
	if ($g['booting']) {
1610
		unmute_kernel_msgs();
1611
		echo "done.\n";
1612
	}
1613
}
1614

    
1615
function interface_proxyarp_configure($interface = "") {
1616
	global $config, $g;
1617
	if(isset($config['system']['developerspew'])) {
1618
		$mt = microtime();
1619
		echo "interface_proxyarp_configure() being called $mt\n";
1620
	}
1621

    
1622
	/* kill any running choparp */
1623
	if (empty($interface))
1624
		killbyname("choparp");
1625
	else {
1626
		$vipif = get_real_interface($interface);
1627
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1628
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1629
	}
1630

    
1631
	$paa = array();
1632
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1633

    
1634
		/* group by interface */
1635
		foreach ($config['virtualip']['vip'] as $vipent) {
1636
			if ($vipent['mode'] === "proxyarp") {
1637
				if ($vipent['interface'])
1638
					$proxyif = $vipent['interface'];
1639
				else
1640
					$proxyif = "wan";
1641
				
1642
				if (!empty($interface) && $interface != $proxyif)
1643
					continue;
1644

    
1645
				if (!is_array($paa[$proxyif]))
1646
					$paa[$proxyif] = array();
1647

    
1648
				$paa[$proxyif][] = $vipent;
1649
			}
1650
		}
1651
	}
1652

    
1653
	if (!empty($interface)) {
1654
		if (is_array($paa[$interface])) {
1655
			$paaifip = get_interface_ip($interface);
1656
                        if (!is_ipaddr($paaifip))
1657
                                return;
1658
                        $args = get_real_interface($interface) . " auto";
1659
                        foreach ($paa[$interface] as $paent) {
1660
                                if (isset($paent['subnet']))
1661
                                        $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1662
                                else if (isset($paent['range']))
1663
                                        $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1664
                        }
1665
                        mwexec_bg("/usr/local/sbin/choparp " . $args);	
1666
		}
1667
	} else if (count($paa) > 0) {
1668
		foreach ($paa as $paif => $paents)  {
1669
			$paaifip = get_interface_ip($paif);
1670
			if (!is_ipaddr($paaifip))
1671
				continue;
1672
			$args = get_real_interface($paif) . " auto";
1673
			foreach ($paents as $paent) {
1674
				if (isset($paent['subnet']))
1675
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1676
				else if (isset($paent['range']))
1677
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1678
			}
1679
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1680
		}
1681
	}
1682
}
1683

    
1684
function interfaces_vips_configure($interface = "") {
1685
	global $g, $config;
1686
	if(isset($config['system']['developerspew'])) {
1687
		$mt = microtime();
1688
		echo "interfaces_vips_configure() being called $mt\n";
1689
	}
1690
	$paa = array();
1691
	if(is_array($config['virtualip']['vip'])) {
1692
		$carp_setuped = false;
1693
		$anyproxyarp = false;
1694
		foreach ($config['virtualip']['vip'] as $vip) {
1695
			switch ($vip['mode']) {
1696
			case "proxyarp":
1697
				/* nothing it is handled on interface_proxyarp_configure() */
1698
				if ($interface <> "" && $vip['interface'] <> $interface)
1699
					continue;
1700
				$anyproxyarp = true;
1701
				break;
1702
			case "ipalias":
1703
				if ($interface <> "" && $vip['interface'] <> $interface)
1704
					continue;
1705
				interface_ipalias_configure(&$vip);
1706
				break;
1707
			case "carp":
1708
				if ($interface <> "" && $vip['interface'] <> $interface)
1709
					continue;
1710
				if ($carp_setuped == false) {
1711
					interfaces_carp_setup();
1712
					$carp_setuped = true;
1713
				}
1714
				interface_carp_configure($vip);
1715
				break;
1716
			case "carpdev-dhcp":
1717
				if ($interface <> "" && $vip['interface'] <> $interface)
1718
					continue;
1719
				interface_carpdev_configure($vip);
1720
				break;
1721
			}
1722
		}
1723
		
1724
		if ($anyproxyarp == true)
1725
			interface_proxyarp_configure();
1726
	}
1727
}
1728

    
1729
function interface_ipalias_configure(&$vip) {
1730

    
1731
	if ($vip['mode'] == "ipalias") {
1732
		$if = get_real_interface($vip['interface']);
1733
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $vip['subnet'] . "/" . escapeshellarg($vip['subnet_bits']) . " alias");
1734
	}
1735
}
1736

    
1737
function interface_reload_carps($cif) {
1738
	global $config;
1739

    
1740
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
1741
	if (empty($carpifs))
1742
		return;
1743

    
1744
	$carps = explode(" ", $carpifs);
1745
	if(is_array($config['virtualip']['vip'])) {
1746
		$viparr = &$config['virtualip']['vip'];
1747
		foreach ($viparr as $vip) {
1748
			if (in_array($vip['carpif'], $carps)) {
1749
				switch ($vip['mode']) {
1750
				case "carp":
1751
					interface_vip_bring_down($vip);
1752
					sleep(1);
1753
					interface_carp_configure($vip);
1754
					break;
1755
				case "carpdev-dhcp":
1756
					interface_vip_bring_down($vip);
1757
					sleep(1);
1758
					interface_carpdev_configure($vip);
1759
					break;
1760
				case "ipalias":
1761
					interface_vip_bring_down($vip);
1762
					sleep(1);
1763
					interface_ipalias_configure($vip);
1764
					break;
1765
				}
1766
			}
1767
		}
1768
	}
1769
}
1770

    
1771
function interface_carp_configure(&$vip) {
1772
	global $config, $g;
1773
	if(isset($config['system']['developerspew'])) {
1774
		$mt = microtime();
1775
		echo "interface_carp_configure() being called $mt\n";
1776
	}
1777

    
1778
	if ($vip['mode'] != "carp")
1779
		return;
1780

    
1781
	$vip_password = $vip['password'];
1782
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
1783
	if ($vip['password'] != "")
1784
		$password = " pass {$vip_password}";
1785

    
1786
	// set the vip interface to the vhid
1787
	$vipif = "vip{$vip['vhid']}";
1788

    
1789
	/*
1790
	 * ensure the interface containing the VIP really exists
1791
 	 * prevents a panic if the interface is missing or invalid
1792
	 */
1793
	$realif = get_real_interface($vip['interface']);
1794
	if (!does_interface_exist($realif)) {
1795
		file_notice("CARP", "Interface specified for the virtual IP address {$vip['subnet']} does not exist. Skipping this VIP.", "Firewall: Virtual IP", "");
1796
		return;
1797
	}
1798

    
1799
	/* Ensure CARP IP really exists prior to loading up. */
1800
	$ww_subnet_ip = find_interface_ip($realif);
1801
	$ww_subnet_bits = find_interface_subnet($realif);
1802
	if (!ip_in_subnet($vip['subnet'], gen_subnet($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
1803
		file_notice("CARP", "Sorry but we could not find a matching real interface subnet for the virtual IP address {$vip['subnet']}.", "Firewall: Virtual IP", "");
1804
		return;
1805
	}
1806

    
1807
	/* create the carp interface and setup */
1808
	if (does_interface_exist($vipif)) {
1809
		pfSense_interface_flags($vipif, -IFF_UP);
1810
	} else {
1811
		$carpif = pfSense_interface_create("carp");
1812
		pfSense_interface_rename($carpif, $vipif);
1813
		pfSense_ngctl_name("{$carpif}:", $vipif);
1814
	}
1815

    
1816
	/* invalidate interface cache */
1817
	get_interface_arr(true);
1818

    
1819
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
1820
	$advbase = "";
1821
	if (!empty($vip['advbase']))
1822
		$advbase = "advbase {$vip['advbase']}";
1823
	mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
1824

    
1825
	interfaces_bring_up($vipif);
1826
	
1827
	return $vipif;
1828
}
1829

    
1830
function interface_carpdev_configure(&$vip) {
1831
	global $g;
1832

    
1833
	if ($vip['mode'] != "carpdev-dhcp")
1834
		return;
1835

    
1836
	$vip_password = $vip['password'];
1837
	$vip_password = str_replace(" ", "", $vip_password);
1838
	if($vip['password'] != "")
1839
		$password = " pass \"" . $vip_password . "\"";
1840

    
1841
	if (empty($vip['interface']))
1842
		return;
1843

    
1844
	$vipif = "vip" . $vip['vhid'];
1845
	$realif = get_real_interface($vip['interface']);
1846
	interfaces_bring_up($realif);
1847
	/*
1848
	 * ensure the interface containing the VIP really exists
1849
	 * prevents a panic if the interface is missing or invalid
1850
	 */
1851
	if (!does_interface_exist($realif)) {
1852
		file_notice("CARP", "Interface specified for the virtual IP address {$vip['subnet']} does not exist. Skipping this VIP.", "Firewall: Virtual IP", "");
1853
		return;
1854
	}
1855

    
1856
	if (does_interface_exist($vipif)) {
1857
		interface_bring_down($vipif);
1858
	} else {
1859
		$carpdevif = exec("/sbin/ifconfig carp create");
1860
		mwexec("/sbin/ifconfig {$carpdevif} name {$vipif}");
1861
		pfSense_ngctl_name("{$carpdevif}:", $vipif);
1862
	}
1863

    
1864
	mwexec("/sbin/ifconfig {$vipif} carpdev {$realif} vhid {$vip['vhid']} advskew {$vip['advskew']} advbase {$vip['advbase']} {$password}");
1865
	interfaces_bring_up($vipif);
1866

    
1867
	/*
1868
	 * XXX: BIG HACK but carpdev needs ip services active
1869
	 *      before even starting something as dhclient.
1870
	 *      I do not know if this is a feature or a bug
1871
	 *      but better than track it make it work ;) .
1872
	 */
1873
	//$fakeiptouse = "10.254.254." . ($carp_instances_counter+1);
1874
	//$cmdchain->add("CarpDEV hack", "/sbin/ifconfig {$carpint} inet {$fakeiptouse}", false);
1875

    
1876
	/* generate dhclient_wan.conf */
1877
	$fd = fopen("{$g['varetc_path']}/dhclient_{$vipif}.conf", "w");
1878
	if ($fd) {
1879
		$dhclientconf = "";
1880

    
1881
		$dhclientconf .= <<<EOD
1882
interface "{$vipif}" {
1883
timeout 60;
1884
retry 1;
1885
select-timeout 0;
1886
initial-interval 1;
1887
script "/sbin/dhclient-script";
1888
}
1889

    
1890
EOD;
1891

    
1892
		fwrite($fd, $dhclientconf);
1893
		fclose($fd);
1894

    
1895
		/* fire up dhclient */
1896
		mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$vipif}.conf {$vipif} >{$g['tmp_path']}/{$vipif}_output 2>{$g['tmp_path']}/{$vipif}_error_output", false);
1897
	} else {
1898
		log_error("Error: cannot open dhclient_{$vipif}.conf in interfaces_carpdev_configure() for writing.\n");
1899
		mwexec("/sbin/dhclient -b {$vipif}");
1900
	}
1901

    
1902
	return $vipif;
1903
}
1904

    
1905
function interface_wireless_clone($realif, $wlcfg) {
1906
	global $config, $g;
1907
	/*   Check to see if interface has been cloned as of yet.  
1908
	 *   If it has not been cloned then go ahead and clone it.
1909
	 */
1910
	$needs_clone = false;
1911
	if(is_array($wlcfg['wireless']))
1912
		$wlcfg_mode = $wlcfg['wireless']['mode'];
1913
	else
1914
		$wlcfg_mode = $wlcfg['mode'];
1915
	switch($wlcfg_mode) {
1916
		 case "hostap":
1917
			$mode = "wlanmode hostap";
1918
			break;
1919
		 case "adhoc":
1920
			$mode = "wlanmode adhoc";
1921
			break;
1922
		 default:
1923
			$mode = "";
1924
			break;
1925
	}
1926
	$baseif = interface_get_wireless_base($wlcfg['if']);
1927
	if(does_interface_exist($realif)) {
1928
		exec("/sbin/ifconfig {$realif}", $output, $ret);
1929
		$ifconfig_str = implode($output);
1930
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
1931
			log_error("Interface {$realif} changed to hostap mode");
1932
			$needs_clone = true;
1933
		}
1934
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
1935
			log_error("Interface {$realif} changed to adhoc mode");
1936
			$needs_clone = true;
1937
		}
1938
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
1939
			log_error("Interface {$realif} changed to infrastructure mode");
1940
			$needs_clone = true;
1941
		}
1942
	} else {
1943
		$needs_clone = true;
1944
	}
1945

    
1946
	if($needs_clone == true) {
1947
		/* remove previous instance if it exists */
1948
		if(does_interface_exist($realif))
1949
			pfSense_interface_destroy($realif);
1950

    
1951
		log_error("Cloning new wireless interface {$realif}");
1952
		// Create the new wlan interface. FreeBSD returns the new interface name.
1953
		// example:  wlan2
1954
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
1955
		if($ret <> 0) {
1956
			log_error("Failed to clone interface {$baseif} with error code {$ret}, output {$out[0]}");
1957
			return false;
1958
		}
1959
		$newif = trim($out[0]);
1960
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
1961
		pfSense_interface_rename($newif, $realif);
1962
		// FIXME: not sure what ngctl is for. Doesn't work.
1963
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
1964
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
1965
	}
1966
	return true;
1967
}
1968

    
1969
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
1970
	global $config, $g;
1971

    
1972
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
1973
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
1974
	                         'regdomain', 'regcountry', 'reglocation');
1975

    
1976
	if(!is_interface_wireless($ifcfg['if']))
1977
		return;
1978

    
1979
	$baseif = interface_get_wireless_base($ifcfg['if']);
1980

    
1981
	// Sync shared settings for assigned clones
1982
	$iflist = get_configured_interface_list(false, true);
1983
	foreach ($iflist as $if) {
1984
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
1985
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
1986
				foreach ($shared_settings as $setting) {
1987
					if ($sync_changes) {
1988
						if (isset($ifcfg['wireless'][$setting]))
1989
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
1990
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
1991
							unset($config['interfaces'][$if]['wireless'][$setting]);
1992
					} else {
1993
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
1994
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
1995
						else if (isset($ifcfg['wireless'][$setting]))
1996
							unset($ifcfg['wireless'][$setting]);
1997
					}
1998
				}
1999
				if (!$sync_changes)
2000
					break;
2001
			}
2002
		}
2003
	}
2004

    
2005
	// Read or write settings at shared area
2006
	if (isset($config['wireless']['interfaces'][$baseif])) {
2007
		foreach ($shared_settings as $setting) {
2008
			if ($sync_changes) {
2009
				if (isset($ifcfg['wireless'][$setting]))
2010
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2011
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2012
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2013
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2014
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2015
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2016
				else if (isset($ifcfg['wireless'][$setting]))
2017
					unset($ifcfg['wireless'][$setting]);
2018
			}
2019
		}
2020
	}
2021

    
2022
	// Sync the mode on the clone creation page with the configured mode on the interface
2023
	if (interface_is_wireless_clone($ifcfg['if'])) {
2024
		foreach ($config['wireless']['clone'] as &$clone) {
2025
			if ($clone['cloneif'] == $ifcfg['if']) {
2026
				if ($sync_changes) {
2027
					$clone['mode'] = $ifcfg['wireless']['mode'];
2028
				} else {
2029
					$ifcfg['wireless']['mode'] = $clone['mode'];
2030
				}
2031
				break;
2032
			}
2033
		}
2034
		unset($clone);
2035
	}
2036
}
2037

    
2038
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2039
	global $config, $g;
2040

    
2041
	/*    open up a shell script that will be used to output the commands.
2042
	 *    since wireless is changing a lot, these series of commands are fragile
2043
     *    and will sometimes need to be verified by a operator by executing the command
2044
     *    and returning the output of the command to the developers for inspection.  please
2045
     *    do not change this routine from a shell script to individul exec commands.  -sullrich
2046
	 */
2047

    
2048
	// Remove script file
2049
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2050

    
2051
	// Clone wireless nic if needed.
2052
	interface_wireless_clone($if, $wl);
2053

    
2054
	// Reject inadvertent changes to shared settings in case the interface hasn't been configured.
2055
	interface_sync_wireless_clones($wl, false);
2056

    
2057
	$fd_set = fopen("{$g['tmp_path']}/{$if}_setup.sh","w");
2058
	fwrite($fd_set, "#!/bin/sh\n");
2059
	fwrite($fd_set, "# {$g['product_name']} wireless configuration script.\n\n");
2060

    
2061
	/* set values for /path/program */
2062
	$hostapd = "/usr/sbin/hostapd";
2063
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2064
	$ifconfig = "/sbin/ifconfig";
2065
	$sysctl = "/sbin/sysctl";
2066
	$killall = "/usr/bin/killall";
2067

    
2068
	/* Set all wireless ifconfig variables (splitt up to get rid of needed checking) */
2069

    
2070
	$wlcmd = array();
2071
	$wl_sysctl = array();
2072
	/* Make sure it's up */
2073
	$wlcmd[] = "up";
2074
	/* Set a/b/g standard */
2075
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2076
	$wlcmd[] = "mode " . escapeshellarg($standard);
2077

    
2078
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2079
	 * to prevent massive packet loss under certain conditions. */
2080
	if(preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na"))
2081
		$wlcmd[] = "-ampdu";
2082

    
2083
	/* Set ssid */
2084
	if($wlcfg['ssid'])
2085
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2086

    
2087
	/* Set 802.11g protection mode */
2088
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2089

    
2090
	/* set wireless channel value */
2091
	if(isset($wlcfg['channel'])) {
2092
		if($wlcfg['channel'] == "0") {
2093
			$wlcmd[] = "channel any";
2094
		} else {
2095
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2096
		}
2097
	}
2098

    
2099
	/* Set antenna diversity value */
2100
	if(isset($wlcfg['diversity']))
2101
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2102

    
2103
	/* Set txantenna value */
2104
	if(isset($wlcfg['txantenna']))
2105
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2106

    
2107
	/* Set rxantenna value */
2108
	if(isset($wlcfg['rxantenna']))
2109
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2110

    
2111
	/* set Distance value */
2112
	if($wlcfg['distance'])
2113
		$distance = escapeshellarg($wlcfg['distance']);
2114

    
2115
	/* Set wireless hostap mode */
2116
	if ($wlcfg['mode'] == "hostap") {
2117
		$wlcmd[] = "mediaopt hostap";
2118
	} else {
2119
		$wlcmd[] = "-mediaopt hostap";
2120
	}
2121

    
2122
	/* Set wireless adhoc mode */
2123
	if ($wlcfg['mode'] == "adhoc") {
2124
		$wlcmd[] = "mediaopt adhoc";
2125
	} else {
2126
		$wlcmd[] = "-mediaopt adhoc";
2127
	}
2128

    
2129
	/* Not neccesary to set BSS mode as this is default if adhoc and/or hostap is NOT set */
2130

    
2131
	/* handle hide ssid option */
2132
	if(isset($wlcfg['hidessid']['enable'])) {
2133
		$wlcmd[] = "hidessid";
2134
	} else {
2135
		$wlcmd[] = "-hidessid";
2136
	}
2137

    
2138
	/* handle pureg (802.11g) only option */
2139
	if(isset($wlcfg['pureg']['enable'])) {
2140
		$wlcmd[] = "mode 11g pureg";
2141
	} else {
2142
		$wlcmd[] = "-pureg";
2143
	}
2144

    
2145
	/* handle puren (802.11n) only option */
2146
	if(isset($wlcfg['puren']['enable'])) {
2147
		$wlcmd[] = "puren";
2148
	} else {
2149
		$wlcmd[] = "-puren";
2150
	}
2151

    
2152
	/* enable apbridge option */
2153
	if(isset($wlcfg['apbridge']['enable'])) {
2154
		$wlcmd[] = "apbridge";
2155
	} else {
2156
		$wlcmd[] = "-apbridge";
2157
	}
2158

    
2159
	/* handle turbo option */
2160
	if(isset($wlcfg['turbo']['enable'])) {
2161
		$wlcmd[] = "mediaopt turbo";
2162
	} else {
2163
		$wlcmd[] = "-mediaopt turbo";
2164
	}
2165

    
2166
	/* handle txpower setting */
2167
	/* if($wlcfg['txpower'] <> "")
2168
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2169
	*/
2170
	/* handle wme option */
2171
	if(isset($wlcfg['wme']['enable'])) {
2172
		$wlcmd[] = "wme";
2173
	} else {
2174
		$wlcmd[] = "-wme";
2175
	}
2176

    
2177
	/* set up wep if enabled */
2178
	$wepset = "";
2179
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2180
		switch($wlcfg['wpa']['auth_algs']) {
2181
			case "1":
2182
				$wepset .= "authmode open wepmode on ";
2183
				break;
2184
			case "2":
2185
				$wepset .= "authmode shared wepmode on ";
2186
				break;
2187
			case "3":
2188
				$wepset .= "authmode mixed wepmode on ";
2189
		}
2190
		$i = 1;
2191
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2192
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2193
			if (isset($wepkey['txkey'])) {
2194
				$wlcmd[] = "weptxkey {$i} ";
2195
			}
2196
			$i++;
2197
		}
2198
		$wlcmd[] = $wepset;
2199
	} else {
2200
		$wlcmd[] = "authmode open wepmode off ";
2201
	}
2202

    
2203
	mwexec(kill_hostapd("{$if}"));
2204
	mwexec(kill_wpasupplicant("{$if}"));
2205

    
2206
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2207
	conf_mount_rw();
2208

    
2209
	switch ($wlcfg['mode']) {
2210
		case 'bss':
2211
			if (isset($wlcfg['wpa']['enable'])) {
2212
				$wpa .= <<<EOD
2213
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2214
ctrl_interface_group=0
2215
ap_scan=1
2216
#fast_reauth=1
2217
network={
2218
ssid="{$wlcfg['ssid']}"
2219
scan_ssid=1
2220
priority=5
2221
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2222
psk="{$wlcfg['wpa']['passphrase']}"
2223
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2224
group={$wlcfg['wpa']['wpa_pairwise']}
2225
}
2226
EOD;
2227

    
2228
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2229
				fwrite($fd, "{$wpa}");
2230
				fclose($fd);
2231
			}
2232
			break;
2233
		case 'hostap':
2234
			if($wlcfg['wpa']['passphrase']) 
2235
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2236
			else 
2237
				$wpa_passphrase = "";
2238
			if (isset($wlcfg['wpa']['enable'])) {
2239
				$wpa .= <<<EOD
2240
interface={$if}
2241
driver=bsd
2242
logger_syslog=-1
2243
logger_syslog_level=0
2244
logger_stdout=-1
2245
logger_stdout_level=0
2246
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2247
ctrl_interface={$g['varrun_path']}/hostapd
2248
ctrl_interface_group=wheel
2249
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2250
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2251
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2252
ssid={$wlcfg['ssid']}
2253
debug={$wlcfg['wpa']['debug_mode']}
2254
auth_algs={$wlcfg['wpa']['auth_algs']}
2255
wpa={$wlcfg['wpa']['wpa_mode']}
2256
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2257
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2258
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2259
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2260
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2261
{$wpa_passphrase}
2262

    
2263
EOD;
2264

    
2265
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2266
	$wpa .= <<<EOD
2267
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2268
rsn_preauth=1
2269
rsn_preauth_interfaces={$if}
2270

    
2271
EOD;
2272

    
2273
}
2274
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2275
					$auth_server_port = "1812";
2276
					if($wlcfg['auth_server_port']) 
2277
						$auth_server_port = $wlcfg['auth_server_port'];
2278
					$wpa .= <<<EOD
2279

    
2280
ieee8021x=1
2281
auth_server_addr={$wlcfg['auth_server_addr']}
2282
auth_server_port={$auth_server_port}
2283
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2284

    
2285
EOD;
2286
				} else {
2287
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2288
				}
2289

    
2290
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2291
				fwrite($fd, "{$wpa}");
2292
				fclose($fd);
2293

    
2294
			}
2295
			break;
2296
	}
2297

    
2298
	/*
2299
	 *    all variables are set, lets start up everything
2300
	 */
2301

    
2302
	$baseif = interface_get_wireless_base($if);
2303
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2304
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2305

    
2306
	/* set sysctls for the wireless interface */
2307
	if (!empty($wl_sysctl)) {
2308
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2309
		foreach ($wl_sysctl as $wl_sysctl_line) {
2310
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2311
		}
2312
	}
2313

    
2314
	/* set ack timers according to users preference (if he/she has any) */
2315
	if($distance) {
2316
		fwrite($fd_set, "# Enable ATH distance settings\n");
2317
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2318
	}
2319

    
2320
	if (isset($wlcfg['wpa']['enable'])) {
2321
		if ($wlcfg['mode'] == "bss") {
2322
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2323
		}
2324
		if ($wlcfg['mode'] == "hostap") {
2325
			/* add line to script to restore old mac to make hostapd happy */
2326
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2327
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2328
				if (is_macaddr($if_oldmac))
2329
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2330
						" link " . escapeshellarg($if_oldmac) . "\n");
2331
			}
2332

    
2333
			fwrite($fd_set, "{$hostapd} -B {$g['varetc_path']}/hostapd_{$if}.conf\n");
2334

    
2335
			/* add line to script to restore spoofed mac after running hostapd */
2336
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2337
				if ($wl['spoofmac'])
2338
					$if_curmac = $wl['spoofmac'];
2339
				else
2340
					$if_curmac = get_interface_mac($if);
2341
				if (is_macaddr($if_curmac))
2342
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2343
						" link " . escapeshellarg($if_curmac) . "\n");
2344
			}
2345
		}
2346
	}
2347

    
2348
	fclose($fd_set);
2349
	conf_mount_ro();
2350

    
2351
	/* Making sure regulatory settings have actually changed
2352
	 * before applying, because changing them requires bringing
2353
	 * down all wireless networks on the interface. */
2354
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2355
	$ifconfig_str = implode($output);
2356
	unset($output);
2357
	$reg_changing = false;
2358

    
2359
	/* special case for the debug country code */
2360
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2361
		$reg_changing = true;
2362
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2363
		$reg_changing = true;
2364
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2365
		$reg_changing = true;
2366
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2367
		$reg_changing = true;
2368
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2369
		$reg_changing = true;
2370

    
2371
	if ($reg_changing) {
2372
		/* set regulatory domain */
2373
		if($wlcfg['regdomain'])
2374
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2375

    
2376
		/* set country */
2377
		if($wlcfg['regcountry'])
2378
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2379

    
2380
		/* set location */
2381
		if($wlcfg['reglocation'])
2382
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2383

    
2384
		$wlregcmd_args = implode(" ", $wlregcmd);
2385

    
2386
		/* build a complete list of the wireless clones for this interface */
2387
		$clone_list = array();
2388
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2389
			$clone_list[] = interface_get_wireless_clone($baseif);
2390
		if (is_array($config['wireless']['clone'])) {
2391
			foreach ($config['wireless']['clone'] as $clone) {
2392
				if ($clone['if'] == $baseif)
2393
					$clone_list[] = $clone['cloneif'];
2394
			}
2395
		}
2396

    
2397
		/* find which clones are up and bring them down */
2398
		$clones_up = array();
2399
		foreach ($clone_list as $clone_if) {
2400
			$clone_status = pfSense_get_interface_addresses($clone_if);
2401
			if ($clone_status['status'] == 'up') {
2402
				$clones_up[] = $clone_if;
2403
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2404
			}
2405
		}
2406

    
2407
		/* apply the regulatory settings */
2408
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2409

    
2410
		/* bring the clones back up that were previously up */
2411
		foreach ($clones_up as $clone_if) {
2412
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2413

    
2414
			/*
2415
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2416
			 * is in infrastructure mode, and WPA is enabled.
2417
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2418
			 */
2419
			if ($clone_if != $if) {
2420
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2421
				if ( !empty($friendly_if)
2422
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2423
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2424
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2425
				}
2426
			}
2427
		}
2428
	}
2429

    
2430
	/* The mode must be specified in a separate command before ifconfig
2431
	 * will allow the mode and channel at the same time in the next. */
2432
	mwexec("/sbin/ifconfig {$if} mode " . escapeshellarg($standard));
2433

    
2434
	/* configure wireless */
2435
	$wlcmd_args = implode(" ", $wlcmd);
2436
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2437

    
2438
	
2439
	sleep(1);
2440
	/* execute hostapd and wpa_supplicant if required in shell */
2441
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2442

    
2443
	return 0;
2444

    
2445
}
2446

    
2447
function kill_hostapd($interface) {
2448
	return "/bin/pkill -f \"hostapd .*{$interface}\"\n";
2449
}
2450

    
2451
function kill_wpasupplicant($interface) {
2452
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\"\n";
2453
}
2454

    
2455
function find_dhclient_process($interface) {
2456
	if ($interface)
2457
		$pid = `/bin/pgrep -xf "dhclient: {$interface}"`;
2458
	else
2459
		$pid = 0;
2460

    
2461
	return intval($pid);
2462
}
2463

    
2464
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2465
	global $config, $g;
2466
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2467

    
2468
	$wancfg = $config['interfaces'][$interface];
2469

    
2470
	$realif = get_real_interface($interface);
2471
	$realhwif = get_parent_interface($interface);
2472

    
2473
	if (!$g['booting']) {
2474
		/* remove all IPv4 addresses */
2475
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0);
2476

    
2477
		switch ($wancfg['ipaddr']) {
2478
			case 'pppoe':
2479
			case 'l2tp':
2480
			case 'pptp':
2481
			case 'ppp':
2482
				break;
2483
			default:
2484
				interface_bring_down($interface);
2485
				break;
2486
		}
2487
	}
2488

    
2489
	/* wireless configuration? */
2490
	if (is_array($wancfg['wireless']))
2491
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2492

    
2493
	if ($wancfg['spoofmac']) {
2494
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2495
			" link " . escapeshellarg($wancfg['spoofmac']));
2496

    
2497
                /*
2498
                 * All vlans need to spoof their parent mac address, too.  see
2499
                 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2500
                 */
2501
                if (is_array($config['vlans']['vlan'])) {
2502
                        foreach ($config['vlans']['vlan'] as $vlan) {
2503
                                if ($vlan['if'] == $realhwif)
2504
                                        mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2505
                                                " link " . escapeshellarg($wancfg['spoofmac']));
2506
                        }
2507
                }
2508
	}  else {
2509
		$mac = get_interface_mac($realhwif);
2510
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2511
			/*   this is not a valid mac address.  generate a
2512
			 *   temporary mac address so the machine can get online.
2513
			 */
2514
			echo "Generating new MAC address.";
2515
			$random_mac = generate_random_mac_address();
2516
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2517
				" link " . escapeshellarg($random_mac));
2518
			$wancfg['spoofmac'] = $random_mac;
2519
			write_config();
2520
			file_notice("MAC Address altered", "The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface {$realif} has been automatically replaced with {$random_mac}", "Interfaces");
2521
		}
2522
	}
2523

    
2524
	/* media */
2525
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2526
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2527
		if ($wancfg['media'])
2528
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2529
		if ($wancfg['mediaopt'])
2530
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2531
		mwexec($cmd);
2532
	}
2533
	if (!empty($wancfg['mtu']))
2534
		pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2535

    
2536
	$options = pfSense_get_interface_addresses($realhwif);
2537
	if (is_array($options) && isset($options['caps']['polling'])) {
2538
		if (isset($config['system']['polling']))
2539
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2540
		else
2541
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2542
	}
2543

    
2544
	/* skip vlans for checksumming and polling */
2545
        if (!stristr($realhwif, "vlan") && is_array($options)) {
2546
		$flags = 0;
2547
		if(isset($config['system']['disablechecksumoffloading'])) {
2548
			if (isset($options['encaps']['txcsum']))
2549
				$flags |= IFCAP_TXCSUM;
2550
			if (isset($options['encaps']['rxcsum']))
2551
				$flags |= IFCAP_RXCSUM;
2552
        	} else {
2553
 			if (!isset($options['caps']['txcsum']))
2554
				$flags |= IFCAP_TXCSUM;
2555
			if (!isset($options['caps']['rxcsum']))
2556
				$flags |= IFCAP_RXCSUM;
2557
        	}
2558

    
2559
        	if(isset($config['system']['disablesegmentationoffloading'])) {
2560
                	if (isset($options['encaps']['tso4']))
2561
				$flags |= IFCAP_TSO;
2562
                	if (isset($options['encaps']['tso6']))
2563
				$flags |= IFCAP_TSO;
2564
        	} else {
2565
                	if (!isset($options['caps']['tso4']))
2566
				$flags |= IFCAP_TSO;
2567
                	if (!isset($options['caps']['tso6']))
2568
				$flags |= IFCAP_TSO;
2569
        	}
2570

    
2571
        	if(isset($config['system']['disablelargereceiveoffloading'])) {
2572
                	if (isset($options['encaps']['lro']))
2573
				$flags |= IFCAP_LRO;
2574
        	} else {
2575
                	if (!isset($options['caps']['lro']))
2576
				$flags |= IFCAP_LRO;
2577
        	}
2578

    
2579
        	/* if the NIC supports polling *AND* it is enabled in the GUI */
2580
        	if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2581
			$flags |= IFCAP_POLLING;
2582
		}
2583
               	pfSense_interface_capabilities($realhwif, -$flags);
2584
	}
2585

    
2586
	/* invalidate interface/ip/sn cache */
2587
	get_interface_arr(true);
2588
	unset($interface_ip_arr_cache[$realif]);
2589
	unset($interface_sn_arr_cache[$realif]);
2590

    
2591
	switch ($wancfg['ipaddr']) {
2592
		case 'carpdev-dhcp':
2593
			interface_carpdev_dhcp_configure($interface);
2594
			break;
2595
		case 'dhcp':
2596
			interface_dhcp_configure($interface);
2597
			break;
2598
		case 'pppoe':
2599
		case 'l2tp':
2600
		case 'pptp':
2601
		case 'ppp':
2602
			interface_ppps_configure($interface);
2603
			break;
2604
		default:
2605
			if ($wancfg['ipaddr'] <> "" && $wancfg['subnet'] <> "") {
2606
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2607
			} else if (substr($realif, 0, 3) == "gre") {
2608
				if (is_array($config['gres']['gre'])) {
2609
					foreach ($config['gres']['gre'] as $gre)
2610
						if ($gre['greif'] == $realif)
2611
							interface_gre_configure($gre);
2612
				}
2613
			} else if (substr($realif, 0, 3) == "gif") {
2614
				 if (is_array($config['gifs']['gif'])) {
2615
					foreach ($config['gifs']['gif'] as $gif)
2616
						if($gif['gifif'] == $interface)
2617
							interface_gif_configure($gif);
2618
				}
2619
			} else if (substr($realif, 0, 4) == "ovpn") {
2620
				/* XXX: Should be done anything?! */
2621
			}
2622
			break;
2623
	}
2624

    
2625
	if(does_interface_exist($wancfg['if']))
2626
		interfaces_bring_up($wancfg['if']);
2627

    
2628
	interface_netgraph_needed($interface);
2629
 	
2630
	if (!$g['booting']) {
2631
		link_interface_to_vips($interface, "update");
2632

    
2633
		unset($gre);
2634
		$gre = link_interface_to_gre($interface);
2635
		if (!empty($gre))
2636
			array_walk($gre, 'interface_gre_configure');
2637

    
2638
		unset($gif);
2639
		$gif = link_interface_to_gif($interface);
2640
		if (!empty($gif))
2641
                       	array_walk($gif, 'interface_gif_configure');
2642

    
2643
		if ($linkupevent == false) {
2644
			unset($bridgetmp);
2645
			$bridgetmp = link_interface_to_bridge($interface);
2646
			if (!empty($bridgetmp))
2647
				interface_bridge_add_member($bridgetmp, $realif);
2648
		}
2649

    
2650
		$grouptmp = link_interface_to_group($interface);
2651
		if (!empty($grouptmp))
2652
			array_walk($grouptmp, 'interface_group_add_member');
2653

    
2654
		if ($interface == "lan")
2655
			/* make new hosts file */
2656
			system_hosts_generate();
2657

    
2658
		if ($reloadall == true) {
2659

    
2660
			/* reconfigure static routes (kernel may have deleted them) */
2661
			system_routing_configure($interface);
2662

    
2663
			/* reload ipsec tunnels */
2664
			vpn_ipsec_configure();
2665

    
2666
			/* restart dnsmasq */
2667
			services_dnsmasq_configure();
2668

    
2669
			/* update dyndns */
2670
			send_event("service reload dyndns {$interface}");
2671

    
2672
			/* reload captive portal */
2673
			captiveportal_init_rules();
2674
		}
2675
	}
2676

    
2677
	return 0;
2678
}
2679

    
2680
function interface_carpdev_dhcp_configure($interface = "wan") {
2681
	global $config, $g;
2682

    
2683
	$wancfg = $config['interfaces'][$interface];
2684
	$wanif = $wancfg['if'];
2685
	/* bring wan interface up before starting dhclient */
2686
	if($wanif)
2687
		interfaces_bring_up($wanif);
2688
	else 
2689
		log_error("Could not bring wanif up in terface_carpdev_dhcp_configure()");
2690

    
2691
	return 0;
2692
}
2693

    
2694
function interface_dhcp_configure($interface = "wan") {
2695
	global $config, $g;
2696

    
2697
	$wancfg = $config['interfaces'][$interface];
2698
	if (empty($wancfg))
2699
		$wancfg = array();
2700

    
2701
	/* generate dhclient_wan.conf */
2702
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
2703
	if (!$fd) {
2704
		printf("Error: cannot open dhclient_{$interface}.conf in interfaces_wan_dhcp_configure() for writing.\n");
2705
		return 1;
2706
	}
2707

    
2708
	if ($wancfg['dhcphostname']) {
2709
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
2710
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
2711
	} else {
2712
		$dhclientconf_hostname = "";
2713
	}
2714

    
2715
	$wanif = get_real_interface($interface);
2716
	if (empty($wanif)) {
2717
		log_error("Invalid interface \"{$interface}\" in interface_dhcp_configure()");
2718
		return 0;
2719
	}
2720
 	$dhclientconf = "";
2721
	
2722
	$dhclientconf .= <<<EOD
2723
interface "{$wanif}" {
2724
timeout 60;
2725
retry 1;
2726
select-timeout 0;
2727
initial-interval 1;
2728
	{$dhclientconf_hostname}
2729
	script "/sbin/dhclient-script";
2730
}
2731

    
2732
EOD;
2733

    
2734
if(is_ipaddr($wancfg['alias-address'])) {
2735
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
2736
	$dhclientconf .= <<<EOD
2737
alias {
2738
	interface  "{$wanif}";
2739
	fixed-address {$wancfg['alias-address']};
2740
	option subnet-mask {$subnetmask};
2741
}
2742

    
2743
EOD;
2744
}
2745
	fwrite($fd, $dhclientconf);
2746
	fclose($fd);
2747

    
2748
	/* bring wan interface up before starting dhclient */
2749
	if($wanif)
2750
		interfaces_bring_up($wanif);
2751
	else 
2752
		log_error("Could not bring up {$wanif} interface in interface_dhcp_configure()");
2753

    
2754
	/* fire up dhclient */
2755
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$wanif} > {$g['tmp_path']}/{$wanif}_output > {$g['tmp_path']}/{$wanif}_error_output");
2756

    
2757
	return 0;
2758
}
2759

    
2760
function interfaces_group_setup() {
2761
	global $config;
2762

    
2763
	if (!is_array($config['ifgroups']['ifgroupentry']))
2764
		return;
2765

    
2766
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
2767
		interface_group_setup($groupar);
2768

    
2769
	return;
2770
}
2771

    
2772
function interface_group_setup(&$groupname /* The parameter is an array */) {
2773
	global $config;
2774

    
2775
	if (!is_array($groupname))
2776
		return;
2777
	$members = explode(" ", $groupname['members']);
2778
	foreach($members as $ifs) {
2779
		$realif = get_real_interface($ifs);
2780
		if ($realif)
2781
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
2782
	}
2783

    
2784
	return;
2785
}
2786

    
2787
function interface_group_add_member($interface, $groupname) {
2788
	$interface = get_real_interface($interface);
2789
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
2790
}
2791
 
2792
/* COMPAT Function */
2793
function convert_friendly_interface_to_real_interface_name($interface) {
2794
	return get_real_interface($interface);
2795
}
2796

    
2797
/* COMPAT Function */
2798
function get_real_wan_interface($interface = "wan") {
2799
	return get_real_interface($interface);
2800
}
2801

    
2802
/* COMPAT Function */
2803
function get_current_wan_address($interface = "wan") {
2804
	return get_interface_ip($interface);
2805
}
2806

    
2807
/*
2808
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
2809
 */
2810
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
2811
        global $config;
2812

    
2813
	if (stristr($interface, "vip")) {
2814
                $index = intval(substr($interface, 3));
2815
                foreach ($config['virtualip']['vip'] as $counter => $vip) {
2816
                        if ($vip['mode'] == "carpdev-dhcp" || $vip['mode'] == "carp")  {
2817
                                if ($index == $vip['vhid'])
2818
                                        return $vip['interface'];
2819
                        }
2820
                }
2821
        }
2822

    
2823
        /* XXX: For speed reasons reference directly the interface array */
2824
	$ifdescrs = &$config['interfaces'];
2825
        //$ifdescrs = get_configured_interface_list(false, true);
2826

    
2827
        foreach ($ifdescrs as $if => $ifname) {
2828
                if ($config['interfaces'][$if]['if'] == $interface)
2829
                        return $if;
2830

    
2831
                if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
2832
                        return $if;
2833

    
2834
                $int = get_parent_interface($if);
2835
                if ($int == $interface)
2836
                        return $ifname;
2837
        }
2838
        return NULL;
2839
}
2840

    
2841
/* attempt to resolve interface to friendly descr */
2842
function convert_friendly_interface_to_friendly_descr($interface) {
2843
        global $config;
2844

    
2845
        switch ($interface) {
2846
        case "l2tp":
2847
        	$ifdesc = "L2TP";
2848
                break;
2849
	case "pptp":
2850
		$ifdesc = "PPTP";
2851
		break;
2852
	case "pppoe":
2853
		$ifdesc = "PPPoE";
2854
		break;
2855
	case "openvpn":
2856
		$ifdesc = "OpenVPN";
2857
		break;
2858
	case "enc0":
2859
	case "ipsec":
2860
		$ifdesc = "IPsec";
2861
		break;
2862
        default:
2863
                if (isset($config['interfaces'][$interface])) {
2864
                        if (empty($config['interfaces'][$interface]['descr']))
2865
                                $ifdesc = strtoupper($interface);
2866
                        else
2867
                                $ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
2868
			break;
2869
		} else if (substr($interface, 0, 3) == "vip") {
2870
			if (is_array($config['virtualip']['vip'])) {
2871
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
2872
					if ($vip['mode'] == "carpdev-dhcp" || $vip['mode'] == "carp")  {
2873
						if ($interface == "vip{$vip['vhid']}")
2874
							return "{$vip['subnet']} - {$vip['descr']}";
2875
					}
2876
				}
2877
                        }
2878
                } else {
2879
			/* if list */
2880
			$ifdescrs = get_configured_interface_with_descr(false, true);
2881
			foreach ($ifdescrs as $if => $ifname) {
2882
					if ($if == $interface || $ifname == $interface)
2883
						return $ifname;
2884
			}
2885
		}
2886
                break;
2887
        }
2888

    
2889
        return $ifdesc;
2890
}
2891

    
2892
function convert_real_interface_to_friendly_descr($interface) {
2893
        global $config;
2894

    
2895
        $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
2896

    
2897
        if ($ifdesc) {
2898
                $iflist = get_configured_interface_with_descr(false, true);
2899
                return $iflist[$ifdesc];
2900
        }
2901

    
2902
        return $interface;
2903
}
2904

    
2905
/*
2906
 *  get_parent_interface($interface):
2907
 *			returns the real parent interface for a given interface description (i.e. wan)
2908
 *			or a virtual interface (i.e. vlan1 or pppoe0 etc.)
2909
 */
2910
function get_parent_interface($interface) {
2911
	global $config;
2912

    
2913
	if (empty($config['interfaces'][$interface]))
2914
		return $interface;
2915

    
2916
	$tmpif = $config['interfaces'][$interface];
2917
	switch ($tmpif['ipaddr']) {
2918
	case "ppp":
2919
	case "pppoe":
2920
	case "pptp":
2921
	case "l2tp":
2922
		if (is_array($config['ppps']['ppp'])) {
2923
			foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
2924
				if ($tmpif['if'] == $ppp['if']) {
2925
					$interface = $ppp['ports'];
2926
					break;
2927
				}
2928
			}
2929
		}
2930
		break;
2931
	case "dhcp":
2932
	case "static":
2933
	default:
2934
		$interface = $tmpif['if'];
2935
		break;
2936
	}
2937

    
2938
	return $interface;
2939
}
2940

    
2941
function interface_is_wireless_clone($wlif) {
2942
	if(!stristr($wlif, "_wlan")) {
2943
		return false;
2944
	} else {
2945
		return true;
2946
	}
2947
}
2948

    
2949
function interface_get_wireless_base($wlif) {
2950
	if(!stristr($wlif, "_wlan")) {
2951
		return $wlif;
2952
	} else {
2953
		return substr($wlif, 0, stripos($wlif, "_wlan"));
2954
	}
2955
}
2956

    
2957
function interface_get_wireless_clone($wlif) {
2958
	if(!stristr($wlif, "_wlan")) {
2959
		return $wlif . "_wlan0";
2960
	} else {
2961
		return $wlif;
2962
	}
2963
}
2964

    
2965
function get_real_interface($interface = "wan") {
2966
    global $config;
2967

    
2968
	$wanif = NULL;
2969

    
2970
	switch ($interface) {
2971
	case "l2tp":
2972
		$wanif = "l2tp";
2973
		break;
2974
	case "pptp":
2975
		$wanif = "pptp";
2976
		break;
2977
	case "pppoe":
2978
		$wanif = "pppoe";
2979
		break;
2980
	case "openvpn":
2981
		$wanif = "openvpn";
2982
		break;
2983
	case "ipsec":
2984
	case "enc0":
2985
		$wanif = "enc0";
2986
		break;
2987
	case "ppp":
2988
		$wanif = "ppp";
2989
		break;
2990
	default:
2991
		// If a real interface was alread passed simply
2992
		// pass the real interface back.  This encourages
2993
		// the usage of this function in more cases so that
2994
		// we can combine logic for more flexibility.
2995
		if(does_interface_exist($interface)) {
2996
			$wanif = $interface;
2997
			break;
2998
		}
2999
		if (empty($config['interfaces'][$interface]))
3000
			break;
3001

    
3002
		$cfg = &$config['interfaces'][$interface];
3003

    
3004
		// Wireless cloned NIC support (FreeBSD 8+)
3005
		// interface name format: $parentnic_wlanparentnic#
3006
		// example: ath0_wlan0
3007
		if (is_interface_wireless($cfg['if'])) {
3008
			$wanif = interface_get_wireless_clone($cfg['if']);
3009
			break;
3010
		}
3011
		/*
3012
		if (empty($cfg['if'])) {
3013
			$wancfg = $cfg['if'];
3014
			break;
3015
		}
3016
		*/
3017

    
3018
		switch ($cfg['ipaddr']) {
3019
			case "carpdev-dhcp":
3020
				$viparr = &$config['virtualip']['vip'];
3021
				if(is_array($viparr))
3022
				foreach ($viparr as $counter => $vip) {
3023
					if ($vip['mode'] == "carpdev-dhcp") {
3024
						if($vip['interface'] == $interface) {
3025
							$wanif = "carp{$counter}";
3026
							break;
3027
						}
3028
					}
3029
				}
3030
				break;
3031
			case "pppoe": 
3032
			case "pptp": 
3033
			case "l2tp": 
3034
			case "ppp":
3035
				$wanif = $cfg['if'];
3036
				break;
3037
			default:
3038
				$wanif = $cfg['if'];
3039
				break;
3040
		}
3041
		break;
3042
	}
3043

    
3044
    return $wanif;
3045
}
3046

    
3047
/* Guess the physical interface by providing a IP address */
3048
function guess_interface_from_ip($ipaddress) {
3049
	if(! is_ipaddr($ipaddress)) {
3050
		return false;
3051
	}
3052
	/* create a route table we can search */
3053
	exec("netstat -rnWf inet", $output, $ret);
3054
	foreach($output as $line) {
3055
		if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
3056
			$fields = preg_split("/[ ]+/", $line);
3057
			if(ip_in_subnet($ipaddress, $fields[0])) {
3058
				return $fields[6];
3059
			}
3060
		}
3061
	}
3062
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
3063
	if(empty($ret)) {
3064
        	return false;
3065
	}
3066
	return $ret;
3067
}
3068

    
3069
/*
3070
 * find_ip_interface($ip): return the interface where an ip is defined
3071
 */
3072
function find_ip_interface($ip)
3073
{
3074
        /* if list */
3075
        $ifdescrs = get_configured_interface_list();
3076

    
3077
        foreach ($ifdescrs as $ifdescr => $ifname) {
3078
		if ($ip == get_interface_ip($ifname)) {
3079
                	$int = get_real_interface($ifname);
3080
			return $int;
3081
		}
3082
        }
3083
        return false;
3084
}
3085

    
3086
/*
3087
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
3088
 */
3089
function find_number_of_created_carp_interfaces() {
3090
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
3091
}
3092

    
3093
function get_all_carp_interfaces() {
3094
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
3095
	$ints = explode(" ", $ints);
3096
	return $ints;
3097
}
3098

    
3099
/*
3100
 * find_carp_interface($ip): return the carp interface where an ip is defined
3101
 */
3102
function find_carp_interface($ip) {
3103
	global $config;
3104
	if (is_array($config['virtualip']['vip'])) {
3105
		foreach ($config['virtualip']['vip'] as $vip) {
3106
			if ($vip['mode'] == "carp" || $vip['mode'] == "carpdev") {
3107
				$carp_ip = get_interface_ip($vip['interface']);
3108
				$if = `ifconfig | grep '$ip ' -B1 | head -n1 | cut -d: -f1`;
3109
				if ($if)
3110
					return $if;
3111
			}
3112
		}
3113
	}
3114
}
3115

    
3116
function link_carp_interface_to_parent($interface) {
3117
        global $config;
3118

    
3119
        if ($interface == "")
3120
                return;
3121

    
3122
        $carp_ip = get_interface_ip($interface);
3123
        if (!is_ipaddr($carp_ip))
3124
                return;
3125

    
3126
        /* if list */
3127
        $ifdescrs = get_configured_interface_list();
3128
        foreach ($ifdescrs as $ifdescr => $ifname) {
3129
                $interfaceip = get_interface_ip($ifname);
3130
                $subnet_bits = get_interface_subnet($ifname);
3131
                $subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3132
                if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3133
                        return $ifname;
3134
        }
3135

    
3136
        return "";
3137
}
3138

    
3139
/****f* interfaces/link_ip_to_carp_interface
3140
 * NAME
3141
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3142
 * INPUTS
3143
 *   $ip
3144
 * RESULT
3145
 *   $carp_ints
3146
 ******/
3147
function link_ip_to_carp_interface($ip) {
3148
        global $config;
3149

    
3150
        if (!is_ipaddr($ip))
3151
                return;
3152

    
3153
        $carp_ints = "";
3154
        if (is_array($config['virtualip']['vip'])) {
3155
		$first = 0;
3156
		$carp_int = array();
3157
                foreach ($config['virtualip']['vip'] as $vip) {
3158
                        if ($vip['mode'] == "carp" || $vip['mode'] == "carpdev") {
3159
                                $carp_ip = $vip['subnet'];
3160
                                $carp_sn = $vip['subnet_bits'];
3161
                                $carp_nw = gen_subnet($carp_ip, $carp_sn);
3162
                                if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}"))
3163
					$carp_int[] = "vip{$vip['vhid']}";
3164
                        }
3165
                }
3166
		if (!empty($carp_int))
3167
			$carp_ints = implode(" ", array_unique($carp_int));
3168
        }
3169

    
3170
        return $carp_ints;
3171
}
3172

    
3173
function link_interface_to_vlans($int, $action = "") {
3174
	global $config;
3175

    
3176
	if (empty($int))
3177
		return;
3178

    
3179
	if (is_array($config['vlans']['vlan'])) {
3180
                foreach ($config['vlans']['vlan'] as $vlan) {
3181
			if ($int == $vlan['if']) {
3182
				if ($action == "update") {
3183
					interfaces_bring_up($int);
3184
				} else if ($action == "")
3185
					return $vlan;
3186
			}
3187
		}
3188
	}
3189
}
3190

    
3191
function link_interface_to_vips($int, $action = "") {
3192
        global $config;
3193

    
3194
        if (is_array($config['virtualip']['vip'])) {
3195
		foreach ($config['virtualip']['vip'] as $vip) {
3196
			if ($int == $vip['interface']) {
3197
				if ($action == "update") {
3198
					interface_vip_bring_down($vip);
3199
					interfaces_vips_configure($int);
3200
				} else
3201
					return $vip;
3202
			}
3203
		}
3204
	}
3205
}
3206

    
3207
/****f* interfaces/link_interface_to_bridge
3208
 * NAME
3209
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3210
 * INPUTS
3211
 *   $ip
3212
 * RESULT
3213
 *   bridge[0-99]
3214
 ******/
3215
function link_interface_to_bridge($int) {
3216
        global $config;
3217

    
3218
        if (is_array($config['bridges']['bridged'])) {
3219
                foreach ($config['bridges']['bridged'] as $bridge) {
3220
			if (in_array($int, explode(',', $bridge['members'])))
3221
                                return "{$bridge['bridgeif']}";
3222
		}
3223
	}
3224
}
3225

    
3226
function link_interface_to_group($int) {
3227
        global $config;
3228

    
3229
	$result = array();
3230

    
3231
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3232
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3233
			if (in_array($int, explode(" ", $group['members'])))
3234
				$result[$group['ifname']] = $int;
3235
		}
3236
	}
3237

    
3238
	return $result;
3239
}
3240

    
3241
function link_interface_to_gre($interface) {
3242
        global $config;
3243

    
3244
	$result = array();
3245

    
3246
        if (is_array($config['gres']['gre'])) {
3247
                foreach ($config['gres']['gre'] as $gre)
3248
                        if($gre['if'] == $interface)
3249
				$result[] = $gre;
3250
	}
3251

    
3252
	return $result;
3253
}
3254

    
3255
function link_interface_to_gif($interface) {
3256
        global $config;
3257

    
3258
	$result = array();
3259

    
3260
        if (is_array($config['gifs']['gif'])) {
3261
                foreach ($config['gifs']['gif'] as $gif)
3262
                        if($gif['if'] == $interface)
3263
                                $result[] = $gif;
3264
	}
3265

    
3266
	return $result;
3267
}
3268

    
3269
/*
3270
 * find_interface_ip($interface): return the interface ip (first found)
3271
 */
3272
function find_interface_ip($interface, $flush = false)
3273
{
3274
	global $interface_ip_arr_cache;
3275
	global $interface_sn_arr_cache;
3276

    
3277
	$interface = str_replace("\n", "", $interface);
3278
	
3279
	if (!does_interface_exist($interface))
3280
		return;
3281

    
3282
	/* Setup IP cache */
3283
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
3284
		$ifinfo = pfSense_get_interface_addresses($interface);
3285
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
3286
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
3287
	}
3288

    
3289
	return $interface_ip_arr_cache[$interface];
3290
}
3291

    
3292
function find_interface_subnet($interface, $flush = false)
3293
{
3294
	global $interface_sn_arr_cache;
3295
	global $interface_ip_arr_cache;
3296

    
3297
	$interface = str_replace("\n", "", $interface);
3298
	if (does_interface_exist($interface) == false)
3299
		return;
3300

    
3301
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
3302
		$ifinfo = pfSense_get_interface_addresses($interface);
3303
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
3304
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
3305
        }
3306

    
3307
	return $interface_sn_arr_cache[$interface];
3308
}
3309

    
3310
function ip_in_interface_alias_subnet($interface, $ipalias) {
3311
	global $config;
3312

    
3313
	if (empty($interface) || !is_ipaddr($ipalias))
3314
		return false;
3315
	if (is_array($config['virtualip']['vip'])) {
3316
                foreach ($config['virtualip']['vip'] as $vip) {
3317
                        switch ($vip['mode']) {
3318
                        case "ipalias":
3319
                                if ($vip['interface'] <> $interface)
3320
                                        break;
3321
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
3322
					return true;
3323
                                break;
3324
                        }
3325
                }
3326
	}
3327

    
3328
	return false;
3329
}
3330

    
3331
function get_interface_ip($interface = "wan")
3332
{
3333
	$realif = get_real_interface($interface);
3334
	if (!$realif) {
3335
		if (preg_match("/^carp/i", $interface))
3336
			$realif = $interface;
3337
		else if (preg_match("/^vip/i", $interface))
3338
			$realif = $interface;
3339
		else
3340
			return null;
3341
	}
3342

    
3343
	$curip = find_interface_ip($realif);
3344
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
3345
		return $curip;
3346
	else
3347
		return null;
3348
}
3349

    
3350
function get_interface_subnet($interface = "wan")
3351
{
3352
	$realif = get_real_interface($interface);
3353
	if (!$realif) {
3354
                if (preg_match("/^carp/i", $interface))
3355
                        $realif = $interface;
3356
                else if (preg_match("/^vip/i", $interface))
3357
                        $realif = $interface;
3358
                else
3359
                        return null;
3360
        }
3361

    
3362
	$cursn = find_interface_subnet($realif);
3363
	if (!empty($cursn))
3364
		return $cursn;
3365

    
3366
	return null;
3367
}
3368

    
3369
/* return outside interfaces with a gateway */
3370
function get_interfaces_with_gateway() {
3371
	global $config;
3372

    
3373
	$ints = array();
3374

    
3375
	/* loop interfaces, check config for outbound */
3376
	foreach($config['interfaces'] as $ifdescr => $ifname) {
3377
		switch ($ifname['ipaddr']) {
3378
			case "dhcp":
3379
			case "carpdev-dhcp":
3380
			case "ppp";
3381
			case "pppoe":
3382
			case "pptp":
3383
			case "l2tp":
3384
			case "ppp";
3385
				$ints[$ifdescr] = $ifdescr;
3386
			break;
3387
			default:
3388
				if (substr($ifname['if'], 0, 5) ==  "ovpnc" ||
3389
				    !empty($ifname['gateway']))
3390
					$ints[$ifdescr] = $ifdescr;
3391
			break;
3392
		}
3393
	}
3394
	return $ints;
3395
}
3396

    
3397
/* return true if interface has a gateway */
3398
function interface_has_gateway($friendly) {
3399
	global $config;
3400

    
3401
	if (!empty($config['interfaces'][$friendly])) {
3402
		$ifname = &$config['interfaces'][$friendly];
3403
		switch ($ifname['ipaddr']) {
3404
			case "dhcp":
3405
			case "carpdev-dhcp":
3406
			case "pppoe":
3407
			case "pptp":
3408
			case "l2tp":
3409
			case "ppp";
3410
				return true;
3411
			break;
3412
			default:
3413
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
3414
					return true;
3415
				if (!empty($ifname['gateway']))
3416
					return true;
3417
			break;
3418
		}
3419
	}
3420

    
3421
	return false;
3422
}
3423

    
3424
/****f* interfaces/is_altq_capable
3425
 * NAME
3426
 *   is_altq_capable - Test if interface is capable of using ALTQ
3427
 * INPUTS
3428
 *   $int            - string containing interface name
3429
 * RESULT
3430
 *   boolean         - true or false
3431
 ******/
3432

    
3433
function is_altq_capable($int) {
3434
        /* Per:
3435
         * http://www.freebsd.org/cgi/man.cgi?query=altq&manpath=FreeBSD+7.2-current&format=html
3436
         * Only the following drivers have ALTQ support
3437
         */
3438
	$capable = array("age", "ale", "an", "ath", "aue", "awi", "bce",
3439
			"bfe", "bge", "dc", "de", "ed", "em", "ep", "fxp", "gem",
3440
			"hme", "igb", "ipw", "iwi", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
3441
			"npe", "nve", "ral", "re", "rl", "rum", "run", "bwn", "sf", "sis", "sk",
3442
			"ste", "stge", "txp", "udav", "ural", "vge", "vr", "wi", "xl",
3443
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
3444
			"l2tp", "ppp");
3445

    
3446
        $int_family = preg_split("/[0-9]+/", $int);
3447

    
3448
        if (in_array($int_family[0], $capable))
3449
                return true;
3450
	else if (stristr($int, "vlan")) /* VLANs are name $parent_$vlan now */
3451
		return true;
3452
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
3453
		return true;
3454
        else
3455
                return false;
3456
}
3457

    
3458
/****f* interfaces/is_interface_wireless
3459
 * NAME
3460
 *   is_interface_wireless - Returns if an interface is wireless
3461
 * RESULT
3462
 *   $tmp       - Returns if an interface is wireless
3463
 ******/
3464
function is_interface_wireless($interface) {
3465
        global $config, $g;
3466

    
3467
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
3468
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
3469
                if (preg_match($g['wireless_regex'], $interface)) {
3470
                        if (isset($config['interfaces'][$friendly]))
3471
                                $config['interfaces'][$friendly]['wireless'] = array();
3472
                        return true;
3473
                }
3474
                return false;
3475
        } else
3476
                return true;
3477
}
3478

    
3479
function get_wireless_modes($interface) {
3480
	/* return wireless modes and channels */
3481
	$wireless_modes = array();
3482

    
3483
	$wlif = get_real_interface($interface);
3484

    
3485
	if(is_interface_wireless($wlif)) {
3486
		$cloned_interface = get_real_interface($interface);
3487
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
3488
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
3489
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
3490

    
3491
		$interface_channels = "";
3492
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
3493
		$interface_channel_count = count($interface_channels);
3494

    
3495
		$c = 0;
3496
		while ($c < $interface_channel_count)
3497
		{
3498
			$channel_line = explode(",", $interface_channels["$c"]);
3499
			$wireless_mode = trim($channel_line[0]);
3500
			$wireless_channel = trim($channel_line[1]);
3501
			if(trim($wireless_mode) != "") {
3502
				/* if we only have 11g also set 11b channels */
3503
				if($wireless_mode == "11g") {
3504
					if(!isset($wireless_modes["11b"]))
3505
						$wireless_modes["11b"] = array();
3506
				} else if($wireless_mode == "11g ht") {
3507
					if(!isset($wireless_modes["11b"]))
3508
						$wireless_modes["11b"] = array();
3509
					if(!isset($wireless_modes["11g"]))
3510
						$wireless_modes["11g"] = array();
3511
					$wireless_mode = "11ng";
3512
				} else if($wireless_mode == "11a ht") {
3513
					if(!isset($wireless_modes["11a"]))
3514
						$wireless_modes["11a"] = array();
3515
					$wireless_mode = "11na";
3516
				}
3517
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
3518
			}
3519
			$c++;
3520
		}
3521
	}
3522
	return($wireless_modes);
3523
}
3524

    
3525
/* return channel numbers, frequency, max txpower, and max regulation txpower */
3526
function get_wireless_channel_info($interface) {
3527
	$wireless_channels = array();
3528

    
3529
	$wlif = get_real_interface($interface);
3530

    
3531
	if(is_interface_wireless($wlif)) {
3532
		$cloned_interface = get_real_interface($interface);
3533
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
3534
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
3535
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
3536

    
3537
		$interface_channels = "";
3538
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
3539

    
3540
		foreach ($interface_channels as $channel_line) {
3541
			$channel_line = explode(",", $channel_line);
3542
			if(!isset($wireless_channels[$channel_line[0]]))
3543
				$wireless_channels[$channel_line[0]] = $channel_line;
3544
		}
3545
	}
3546
	return($wireless_channels);
3547
}
3548

    
3549
/****f* interfaces/get_interface_mtu
3550
 * NAME
3551
 *   get_interface_mtu - Return the mtu of an interface
3552
 * RESULT
3553
 *   $tmp       - Returns the mtu of an interface
3554
 ******/
3555
function get_interface_mtu($interface) {
3556
        $mtu = pfSense_get_interface_addresses($interface);
3557
        return $mtu['mtu'];
3558
}
3559

    
3560
function get_interface_mac($interface) {
3561

    
3562
	$macinfo = pfSense_get_interface_addresses($interface);
3563
	return $macinfo["macaddr"];
3564
}
3565

    
3566
/****f* pfsense-utils/generate_random_mac_address
3567
 * NAME
3568
 *   generate_random_mac - generates a random mac address
3569
 * INPUTS
3570
 *   none
3571
 * RESULT
3572
 *   $mac - a random mac address
3573
 ******/
3574
function generate_random_mac_address() {
3575
        $mac = "02";
3576
        for($x=0; $x<5; $x++)
3577
                $mac .= ":" . dechex(rand(16, 255));
3578
        return $mac;
3579
}
3580

    
3581
/****f* interfaces/is_jumbo_capable
3582
 * NAME
3583
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
3584
 * INPUTS
3585
 *   $int             - string containing interface name
3586
 * RESULT
3587
 *   boolean          - true or false
3588
 ******/
3589
function is_jumbo_capable($int) {
3590
        global $g;
3591

    
3592
        $int_family = preg_split("/[0-9]+/", $int);
3593

    
3594
        if (in_array($int_family[0], $g['vlan_long_frame']))
3595
                return true;
3596
        else
3597
                return false;
3598
}
3599

    
3600
function setup_pppoe_reset_file($pppif, $iface="") {
3601
	global $g;
3602
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
3603

    
3604
	if(!empty($iface) && !empty($pppif)){
3605
		$cron_cmd = <<<EOD
3606
#!/bin/sh
3607
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
3608
/usr/bin/logger -t pppoe{$iface} "PPPoE periodic reset executed on {$iface}"
3609

    
3610
EOD;
3611

    
3612
		file_put_contents($cron_file, $cron_cmd);
3613
		chmod($cron_file, 0700);
3614
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
3615
	} else
3616
		unlink_if_exists($cron_file);
3617
}
3618

    
3619
function get_vip_descr($ipaddress) {
3620
	global $config;
3621

    
3622
	foreach ($config['virtualip']['vip'] as $vip) {
3623
		if ($vip['subnet'] == $ipaddress) {
3624
			return ($vip['descr']);
3625
		}
3626
	}
3627
	return "";
3628
}
3629

    
3630
?>
(25-25/61)