Project

General

Profile

Download (137 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_BUILDER_BINARIES:	/usr/local/sbin/dhclient
41
	pfSense_MODULE:	interfaces
42

    
43
*/
44

    
45
/* include all configuration functions */
46
require_once("globals.inc");
47
require_once("cmd_chain.inc");
48
require_once("util.inc");
49
require_once("gwlb.inc");
50

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

    
60
/*
61
 * Return the interface array
62
 */
63
function get_interface_arr($flush = false) {
64
        global $interface_arr_cache;
65

    
66
        /* If the cache doesn't exist, build it */
67
        if (!isset($interface_arr_cache) or $flush)
68
                $interface_arr_cache = pfSense_interface_listget();
69

    
70
        return $interface_arr_cache;
71
}
72

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

    
83
	$ints = get_interface_arr(true);
84
	if (in_array($interface, $ints))
85
		return true;
86
	else
87
		return false;
88
}
89

    
90
/*
91
 * does_vip_exist($vip): return true or false if a vip is
92
 * configured.
93
 */
94
function does_vip_exist($vip) {
95
	global $config;
96
	
97
	if(!$vip)
98
		return false;
99

    
100

    
101
	switch ($vip['mode']) {
102
	case "carp":
103
		$realif = "{$vip['interface']}_vip{$vip['vhid']}";
104
		if (!does_interface_exist($realif)) {
105
			return false;
106
		}
107
		break;
108
	case "ipalias":
109
		$realif = get_real_interface($vip['interface']);
110
		if (!does_interface_exist($realif)) {
111
			return false;
112
		}
113
		break;
114
	case "proxyarp":
115
		/* XXX: Implement this */
116
	default:
117
		return false;
118
	}
119

    
120
	$ifacedata = pfSense_getall_interface_addresses($realif);
121
	foreach ($ifacedata as $vipips) {
122
		if ($vipips == "{$vip['subnet']}/{$vip['subnet_bits']}")
123
			return true;
124
	}
125

    
126
	return false;
127
}
128

    
129
function interface_netgraph_needed($interface = "wan") {
130
	global $config;
131

    
132
	$found = false;
133
	if (!empty($config['pptpd']) &&
134
		$config['pptpd']['mode'] == "server")
135
		$found = true;
136
	if ($found == false && !empty($config['l2tp']) &&
137
		$config['l2tp']['mode'] == "server")
138
		$found = true;
139
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
140
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
141
			if ($pppoe['mode'] != "server")
142
				continue;
143
			if ($pppoe['interface'] == $interface)
144
				$found = true;
145
				break;
146
		}
147
	}
148
	if ($found == false) {
149
		if (!empty($config['interfaces'][$interface])) {
150
			switch ($config['interfaces'][$interface]['ipaddr']) {
151
			case "ppp":
152
			case "pppoe":
153
			case "l2tp":
154
			case "pptp":
155
				$found = true;
156
				break;
157
			default:
158
				$found = false;
159
				break;
160
			}
161
		}
162
	}
163
	if ($found == false) {
164
		$realif = get_real_interface($interface);
165
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
166
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
167

    
168
/* This if block doesn't do anything. It can be deleted.
169
PPP interfaces are found above in the previous if ($found == false) block.
170
This block of code is only entered for OPTx interfaces that are configured for PPPoE modem access, so $realif != $ppp['if']
171

    
172
				if ($realif == $ppp['if']) {
173
					$found = true;
174
					break;
175
				}
176
*/			
177
				$ports = explode(',',$ppp['ports']);
178
				foreach($ports as $pid => $port){
179
					$port = get_real_interface($port);
180
					if ($realif == $port) {
181
						$found = true;
182
						break;
183
					}
184
					/* Find the parent interfaces of the vlans in the MLPPP configs 
185
					* there should be only one element in the array here 
186
					* -- this could be better . . . */
187
					$parent_if = get_parent_interface($port);
188
					if ($realif == $parent_if[0]) {
189
						$found = true;
190
						break;
191
					}
192
				}
193
			}
194
		}
195
	}
196
	
197
	if ($found == false) {
198
		$realif = get_real_interface($interface);
199
		pfSense_ngctl_detach("{$realif}:", $realif);
200
	}
201
	/* NOTE: We make sure for this on interface_ppps_configure()
202
	 *	no need to do it here agan.
203
	 *	else
204
	 *		pfSense_ngctl_attach(".", $realif);
205
	 */
206
}
207

    
208
function interfaces_loopback_configure() {
209
	global $g;
210

    
211
	if ($g['platform'] == 'jail')
212
		return;
213
	if($g['booting'])
214
		echo gettext("Configuring loopback interface...");
215
	pfSense_interface_setaddress("lo0", "127.0.0.1");
216
	interfaces_bring_up("lo0");
217
	if($g['booting'])
218
		echo gettext("done.") . "\n";
219
	return 0;
220
}
221

    
222
function interfaces_vlan_configure() {
223
	global $config, $g;
224
	if($g['booting'])
225
		echo gettext("Configuring VLAN interfaces...");
226
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
227
		foreach ($config['vlans']['vlan'] as $vlan) {
228
			if(empty($vlan['vlanif']))
229
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
230
			/* XXX: Maybe we should report any errors?! */
231
			interface_vlan_configure($vlan);
232
		}
233
	}
234
	if($g['booting'])
235
		echo gettext("done.") . "\n";
236
}
237

    
238
function interface_vlan_configure(&$vlan) {
239
        global $config, $g;
240

    
241
	if (!is_array($vlan)) {
242
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
243
		return;
244
	}
245
	$if = $vlan['if'];
246
	$vlanif  = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
247
	$tag = $vlan['tag'];
248

    
249
	if (empty($if)) {
250
		log_error(gettext("interface_vlan_configure called with if undefined."));
251
		return;
252
	}
253

    
254
	/* make sure the parent interface is up */
255
	interfaces_bring_up($if);
256
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
257
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
258

    
259
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
260
		interface_bring_down($vlanif, true);
261
	} else {
262
		$tmpvlanif = pfSense_interface_create("vlan");
263
		pfSense_interface_rename($tmpvlanif, $vlanif);
264
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
265
	}
266

    
267
	pfSense_vlan_create($vlanif, $if, $tag);
268

    
269
	interfaces_bring_up($vlanif);
270

    
271
	/* invalidate interface cache */
272
	get_interface_arr(true);
273

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

    
277
	return $vlanif;
278
}
279

    
280
function interface_qinq_configure(&$vlan, $fd = NULL) {
281
        global $config, $g;
282

    
283
        if (!is_array($vlan)) {
284
                log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
285
                return;
286
        }
287

    
288
        $qinqif = $vlan['if'];
289
        $tag = $vlan['tag'];
290
        if(empty($qinqif)) {
291
                log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
292
                return;
293
        }
294
	$vlanif = interface_vlan_configure($vlan);
295

    
296
        if ($fd == NULL) {
297
                $exec = true;
298
                $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
299
        } else
300
                $exec = false;
301
        /* make sure the parent is converted to ng_vlan(4) and is up */
302
        interfaces_bring_up($qinqif);
303

    
304
	pfSense_ngctl_attach(".", $qinqif);
305
        if (!empty($vlanif) && does_interface_exist($vlanif)) {
306
                fwrite($fd, "shutdown {$qinqif}qinq:\n");
307
                exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
308
                if (empty($result)) {
309
                        fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
310
                        fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
311
                        fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
312
                }
313
        } else {
314
                fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
315
                fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
316
                fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
317
        }
318

    
319
        /* invalidate interface cache */
320
        get_interface_arr(true);
321

    
322
        if (!stristr($qinqif, "vlan"))
323
                mwexec("/sbin/ifconfig {$qinqif} promisc\n");
324

    
325
        $macaddr = get_interface_mac($qinqif);
326
        if (!empty($vlan['members'])) {
327
                $members = explode(" ", $vlan['members']);
328
                foreach ($members as $qtag) {
329
                        $qinq = array();
330
                        $qinq['tag'] = $qtag;
331
                        $qinq['if'] = $vlanif;
332
                        interface_qinq2_configure($qinq, $fd, $macaddr);
333
                }
334
        }
335
        if ($exec == true) {
336
                fclose($fd);
337
                mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
338
        }
339

    
340
        interfaces_bring_up($qinqif);
341
        if (!empty($vlan['members'])) {
342
                $members = explode(" ", $vlan['members']);
343
                foreach ($members as $qif)
344
                        interfaces_bring_up("{$vlanif}_{$qif}");
345
        }
346

    
347
        return $vlanif;
348
}
349

    
350
function interfaces_qinq_configure() {
351
	global $config, $g;
352
	if($g['booting'])
353
		echo gettext("Configuring QinQ interfaces...");
354
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
355
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
356
			/* XXX: Maybe we should report any errors?! */
357
			interface_qinq_configure($qinq);
358
		}
359
	}
360
	if($g['booting'])
361
		echo gettext( "done.") . "\n";
362
}
363

    
364
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
365
        global $config, $g;
366

    
367
        if (!is_array($qinq)) {
368
                log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
369
                return;
370
        }
371

    
372
        $if = $qinq['if'];
373
        $tag = $qinq['tag'];
374
        $vlanif = "{$if}_{$tag}";
375
        if(empty($if)) {
376
                log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
377
                return;
378
        }
379

    
380
        fwrite($fd, "shutdown {$if}h{$tag}:\n");
381
        fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n");
382
        fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n");
383
        fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n");
384
        fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n");
385
        fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n");
386

    
387
        /* invalidate interface cache */
388
        get_interface_arr(true);
389

    
390
        return $vlanif;
391
}
392

    
393
function interfaces_create_wireless_clones() {
394
	global $config;
395

    
396
	if($g['booting'])
397
		echo gettext("Creating other wireless clone interfaces...");
398
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
399
		foreach ($config['wireless']['clone'] as $clone) {
400
			if(empty($clone['cloneif']))
401
				continue;
402
			if(does_interface_exist($clone['cloneif']))
403
				continue;
404
			/* XXX: Maybe we should report any errors?! */
405
			if(interface_wireless_clone($clone['cloneif'], $clone))
406
				if($g['booting'])
407
					echo " " . $clone['cloneif'];
408
		}
409
	}
410
	if($g['booting'])
411
		echo " " . gettext("done.") . "\n";
412

    
413
}
414

    
415
function interfaces_bridge_configure($checkmember = 0) {
416
        global $config;
417

    
418
        $i = 0;
419
        if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
420
                foreach ($config['bridges']['bridged'] as $bridge) {
421
                        if(empty($bridge['bridgeif']))
422
                                $bridge['bridgeif'] = "bridge{$i}";
423
                        /* XXX: Maybe we should report any errors?! */
424
                        interface_bridge_configure($bridge, $checkmember);
425
                        $i++;
426
                }
427
        }
428
}
429

    
430
function interface_bridge_configure(&$bridge, $checkmember = 0) {
431
	global $config, $g;
432

    
433
	if (!is_array($bridge))
434
	        return -1;
435

    
436
	if (empty($bridge['members'])) {
437
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
438
		return -1;
439
	}
440

    
441
	$members = explode(',', $bridge['members']);
442
	if (!count($members))
443
		return -1;
444

    
445
	/* Calculate smaller mtu and enforce it */
446
	$smallermtu = 0;
447
	$commonrx = true;
448
	$commontx = true;
449
	$foundgif = false;
450
	foreach ($members as $member) {
451
		$realif = get_real_interface($member);
452
		$opts = pfSense_get_interface_addresses($realif);
453
		$mtu = $opts['mtu'];
454
		if (substr($realif, 0, 3) == "gif") {
455
			$foundgif = true;
456
			if ($checkmember == 1)
457
				return;
458
			if ($mtu <= 1500)
459
				continue;
460
		}
461
		if (!isset($opts['encaps']['txcsum']))
462
			$commontx = false;
463
		if (!isset($opts['encaps']['rxcsum']))
464
			$commonrx = false;
465
		if (!isset($opts['encaps']['tso4']))
466
			$commontso4 = false;
467
		if (!isset($opts['encaps']['tso6']))
468
			$commontso6 = false;
469
		if (!isset($opts['encaps']['lro']))
470
			$commonlro = false;
471
		if ($smallermtu == 0 && !empty($mtu))
472
			$smallermtu = $mtu;
473
		else if (!empty($mtu) && $mtu < $smallermtu)
474
			$smallermtu = $mtu;
475
	}
476
	if ($foundgif == false && $checkmember == 2)
477
		return;
478

    
479
	/* Just in case anything is not working well */
480
	if ($smallermtu == 0)
481
		$smallermtu = 1500; 
482

    
483
	$flags = 0;
484
	if ($commonrx === false)
485
		$flags |= IFCAP_RXCSUM;
486
	if ($commontx === false)
487
		$flags |= IFCAP_TXCSUM;
488
	if ($commontso4 === false)
489
		$flags |= IFCAP_TSO4;
490
	if ($commontso6 === false)
491
		$flags |= IFCAP_TSO6;
492
	if ($commonlro === false)
493
		$flags |= IFCAP_LRO;
494

    
495
	if ($g['booting'] || !empty($bridge['bridgeif'])) {
496
		pfSense_interface_destroy($bridge['bridgeif']);
497
		pfSense_interface_create($bridge['bridgeif']);
498
		$bridgeif = $bridge['bridgeif'];
499
	} else
500
		$bridgeif = pfSense_interface_create("bridge");
501

    
502
	$checklist = get_configured_interface_list();
503

    
504
	/* Add interfaces to bridge */
505
	foreach ($members as $member) {
506
		if (!array_key_exists($member, $checklist))
507
			continue;
508
		$realif1 = get_real_interface($member);
509
		$realif =  escapeshellarg($realif1);
510
		if (!$realif) {
511
			log_error(gettext("realif not defined in interfaces bridge - up"));
512
			continue;
513
		}
514
		/* make sure the parent interface is up */
515
		pfSense_interface_mtu($realif1, $smallermtu);
516
		pfSense_interface_capabilities($realif1, -$flags);
517
		interfaces_bring_up($realif1);
518
		pfSense_bridge_add_member($bridgeif, $realif1);
519
	}
520

    
521
	if (isset($bridge['enablestp'])) {
522
		/* Choose spanning tree proto */
523
		mwexec("/sbin/ifconfig {$bridgeif} proto {$bridge['proto']}");	
524
		
525
		if (!empty($bridge['stp'])) {
526
			$stpifs = explode(',', $bridge['stp']);
527
			foreach ($stpifs as $stpif) {
528
				$realif = get_real_interface($stpif);
529
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
530
			}
531
		}
532
		if (!empty($bridge['maxage']))
533
			mwexec("/sbin/ifconfig {$bridgeif} maxage {$bridge['maxage']}");
534
		if (!empty($bridge['fwdelay']))
535
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay {$bridge['fwdelay']}");
536
		if (!empty($bridge['hellotime']))
537
                        mwexec("/sbin/ifconfig {$bridgeif} hellotime {$bridge['hellotime']}");
538
		if (!empty($bridge['priority']))
539
                        mwexec("/sbin/ifconfig {$bridgeif} priority {$bridge['priority']}");
540
		if (!empty($bridge['holdcount']))
541
                        mwexec("/sbin/ifconfig {$bridgeif} holdcnt {$bridge['holdcnt']}");
542
		if (!empty($bridge['ifpriority'])) {
543
			$pconfig = explode(",", $bridge['ifpriority']);
544
			$ifpriority = array();
545
			foreach ($pconfig as $cfg) {
546
				$embcfg = explode_assoc(":", $cfg);
547
				foreach ($embcfg as $key => $value)
548
					$ifpriority[$key] = $value;
549
			}
550
			foreach ($ifpriority as $key => $value) {
551
				$realif = get_real_interface($key);
552
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} {$value}"); 
553
			}
554
		}
555
		if (!empty($bridge['ifpathcost'])) {
556
			$pconfig = explode(",", $bridge['ifpathcost']);
557
			$ifpathcost = array();
558
			foreach ($pconfig as $cfg) {
559
				$embcfg = explode_assoc(":", $cfg);
560
				foreach ($embcfg as $key => $value)
561
					$ifpathcost[$key] = $value;
562
			}
563
			foreach ($ifpathcost as $key => $value) {
564
                        	$realif = get_real_interface($key);
565
                        	mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} {$value}");
566
                	}
567
		}
568
	}
569

    
570
	if ($bridge['maxaddr'] <> "")
571
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr {$bridge['maxaddr']}");
572
        if ($bridge['timeout'] <> "")
573
                mwexec("/sbin/ifconfig {$bridgeif} timeout {$bridge['timeout']}");
574
        if ($bridge['span'] <> "") {
575
		$realif = get_real_interface($bridge['span']);
576
                mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
577
	}
578
	if (!empty($bridge['edge'])) {
579
        	$edgeifs = explode(',', $bridge['edge']);
580
        	foreach ($edgeifs as $edgeif) {
581
			$realif = get_real_interface($edgeif);
582
                	mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
583
        	}
584
	}
585
	if (!empty($bridge['autoedge'])) {
586
        	$edgeifs = explode(',', $bridge['autoedge']);
587
        	foreach ($edgeifs as $edgeif) {
588
                	$realif = get_real_interface($edgeif);
589
                	mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
590
        	}
591
	}
592
	if (!empty($bridge['ptp'])) {
593
        	$ptpifs = explode(',', $bridge['ptp']);
594
        	foreach ($ptpifs as $ptpif) {
595
                	$realif = get_real_interface($ptpif);
596
                	mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
597
        	}
598
	}
599
	if (!empty($bridge['autoptp'])) {
600
        	$ptpifs = explode(',', $bridge['autoptp']);
601
        	foreach ($ptpifs as $ptpif) {
602
                	$realif = get_real_interface($ptpif);
603
                	mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
604
        	}
605
	}
606
	if (!empty($bridge['static'])) {
607
        	$stickyifs = explode(',', $bridge['static']);
608
        	foreach ($stickyifs as $stickyif) {
609
                	$realif = get_real_interface($stickyif);
610
                	mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
611
        	}
612
	}
613
	if (!empty($bridge['private'])) {
614
        	$privateifs = explode(',', $bridge['private']);
615
        	foreach ($privateifs as $privateif) {
616
                	$realif = get_real_interface($privateif);
617
               	 	mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
618
        	}
619
	}
620

    
621
	if($bridgeif)
622
		interfaces_bring_up($bridgeif);	
623
	else 
624
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
625

    
626
	return $bridgeif;
627
}
628

    
629
function interface_bridge_add_member($bridgeif, $interface) {
630

    
631
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface))
632
		return;
633

    
634
	$mtu = get_interface_mtu($bridgeif);
635
	$mtum = get_interface_mtu($interface);
636
	
637
	if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500))
638
		pfSense_interface_mtu($interface, $mtu);
639

    
640
	$options = pfSense_get_interface_addresses($bridgeif);
641
	$flags = 0;
642
	if (!isset($options['encaps']['txcsum']))
643
		$flags |= IFCAP_TXCSUM;
644

    
645
	if (!isset($options['encaps']['rxcsum']))
646
		$flags |= IFCAP_RXCSUM;
647

    
648
	pfSense_interface_capabilities($interface, -$flags);
649

    
650
	interfaces_bring_up($interface);
651
	pfSense_bridge_add_member($bridgeif, $interface);
652
}
653

    
654
function interfaces_lagg_configure() 
655
{
656
        global $config, $g;
657
		if($g['booting']) 
658
			echo gettext("Configuring LAGG interfaces...");
659
        $i = 0;
660
		if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
661
			foreach ($config['laggs']['lagg'] as $lagg) {
662
				if(empty($lagg['laggif']))
663
					$lagg['laggif'] = "lagg{$i}";
664
				/* XXX: Maybe we should report any errors?! */
665
				interface_lagg_configure($lagg);
666
				$i++;
667
			}
668
		}
669
		if($g['booting']) 
670
			echo gettext("done.") . "\n";
671
}
672

    
673
function interface_lagg_configure(&$lagg) {
674
        global $config, $g;
675

    
676
        if (!is_array($lagg))
677
		return -1;
678

    
679
	$members = explode(',', $lagg['members']);
680
	if (!count($members))
681
		return -1;
682
	
683
	if ($g['booting'] || !(empty($lagg['laggif']))) {
684
		pfSense_interface_destroy($lagg['laggif']);
685
		pfSense_interface_create($lagg['laggif']);
686
                $laggif = $lagg['laggif'];
687
        } else
688
		$laggif = pfSense_interface_create("lagg");
689

    
690
	/* Calculate smaller mtu and enforce it */
691
        $smallermtu = 0;
692
        foreach ($members as $member) {
693
		$opts = pfSense_get_interface_addresses($member);
694
                $mtu = $opts['mtu'];
695
		if (!isset($opts['encaps']['txcsum']))
696
                        $commontx = false;
697
                if (!isset($opts['encaps']['rxcsum']))
698
                        $commonrx = false;
699
		if (!isset($opts['encaps']['tso4']))
700
			$commontso4 = false;
701
		if (!isset($opts['encaps']['tso6']))
702
			$commontso6 = false;
703
		if (!isset($opts['encaps']['lro']))
704
			$commonlro = false;
705
		if ($smallermtu == 0 && !empty($mtu))
706
			$smallermtu = $mtu;
707
                else if (!empty($mtu) && $mtu < $smallermtu)
708
                        $smallermtu = $mtu;
709
        }
710

    
711
	/* Just in case anything is not working well */
712
        if ($smallermtu == 0)
713
                $smallermtu = 1500;
714

    
715
	$flags = 0;
716
        if ($commonrx === false)
717
                $flags |= IFCAP_RXCSUM;
718
        if ($commontx === false)
719
                $flags |= IFCAP_TXCSUM;
720
	if ($commontso4 === false)
721
                $flags |= IFCAP_TSO4;
722
        if ($commontso6 === false)
723
                $flags |= IFCAP_TSO6;
724
        if ($commonlro === false)
725
                $flags |= IFCAP_LRO;
726

    
727
	$checklist = get_interface_list();
728

    
729
	foreach ($members as $member) {
730
		if (!array_key_exists($member, $checklist))
731
			continue;
732
		/* make sure the parent interface is up */
733
		pfSense_interface_mtu($member, $smallermtu);
734
		pfSense_interface_capabilities($member, -$flags);
735
		interfaces_bring_up($member);
736
		mwexec("/sbin/ifconfig {$laggif} laggport {$member}");
737
	}
738
	
739
	mwexec("/sbin/ifconfig {$laggif} laggproto {$lagg['proto']}");
740

    
741
	interfaces_bring_up($laggif);
742

    
743
	return $laggif;
744
}
745

    
746
function interfaces_gre_configure($checkparent = 0) {
747
        global $config;
748

    
749
        if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
750
                foreach ($config['gres']['gre'] as $i => $gre) {
751
                        if(empty($gre['greif']))
752
                                $gre['greif'] = "gre{$i}";
753
			if ($checkparent == 1 && strstr($gre['if'], "_vip"))
754
				continue;
755
			if ($checkparent == 2 && !strstr($gre['if'], "_vip"))
756
				continue;
757
                        /* XXX: Maybe we should report any errors?! */
758
                        interface_gre_configure($gre);
759
                }
760
        }
761
}
762

    
763
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
764
function interface_gre_configure(&$gre, $grekey = "") {
765
        global $config, $g;
766

    
767
	if (!is_array($gre))
768
		return -1;
769

    
770
	$realif = get_real_interface($gre['if']);
771
	$realifip = get_interface_ip($gre['if']);
772

    
773
	/* make sure the parent interface is up */
774
	interfaces_bring_up($realif);
775

    
776
	if ($g['booting'] || !(empty($gre['greif']))) {
777
		pfSense_interface_destroy($gre['greif']);
778
		pfSense_interface_create($gre['greif']);
779
		$greif = $gre['greif'];
780
	} else
781
		$greif = pfSense_interface_create("gre");
782

    
783
	/* Do not change the order here for more see gre(4) NOTES section. */
784
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} {$gre['remote-addr']}");
785
	if((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
786
		mwexec("/sbin/ifconfig {$greif} inet6 {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} prefixlen /{$gre['tunnel-remote-net']} ");
787
	} else {
788
		mwexec("/sbin/ifconfig {$greif} {$gre['tunnel-local-addr']} {$gre['tunnel-remote-addr']} netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
789
	}
790
	if (isset($gre['link0']) && $gre['link0'])
791
		pfSense_interface_flags($greif, IFF_LINK0);
792
	if (isset($gre['link1']) && $gre['link1'])
793
		pfSense_interface_flags($greif, IFF_LINK1);
794
	if (isset($gre['link2']) && $gre['link2'])
795
		pfSense_interface_flags($greif, IFF_LINK2);
796

    
797
	if($greif)
798
		interfaces_bring_up($greif);
799
	else 
800
		log_error(gettext("Could not bring greif up -- variable not defined."));
801

    
802
	if (isset($gre['link1']) && $gre['link1'])
803
		mwexec("/sbin/route add {$gre['tunnel-remote-addr']}/{$gre['tunnel-remote-net']} {$gre['tunnel-local-addr']}");
804
	if(is_ipaddrv4($gre['tunnel-remote-addr']))
805
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
806
	if(is_ipaddrv6($gre['tunnel-remote-addr']))
807
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
808

    
809
	return $greif;
810
}
811

    
812
function interfaces_gif_configure($checkparent = 0) {
813
	global $config;
814

    
815
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
816
		foreach ($config['gifs']['gif'] as $i => $gif) {
817
			if(empty($gif['gifif']))
818
				$gre['gifif'] = "gif{$i}";
819
			if ($checkparent == 1 && strstr($gif['if'], "_vip"))
820
				continue;
821
			if ($checkparent == 2 && !strstr($gif['if'], "_vip"))
822
				continue;
823
			/* XXX: Maybe we should report any errors?! */
824
			interface_gif_configure($gif);
825
		}
826
	}
827
}
828

    
829
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
830
function interface_gif_configure(&$gif, $gifkey = "") {
831
	global $config, $g;
832

    
833
	if (!is_array($gif))
834
		return -1;
835

    
836
	$realif = get_real_interface($gif['if']);
837
	$ipaddr = $gif['ipaddr'];
838

    
839
	if (is_ipaddrv4($gif['remote-addr'])) {
840
		if (is_ipaddrv4($ipaddr))
841
			$realifip = $ipaddr;
842
		else
843
			$realifip = get_interface_ip($gif['if']);
844
		$realifgw = get_interface_gateway($gif['if']);
845
	} else if (is_ipaddrv6($gif['remote-addr'])) {
846
		if (is_ipaddrv6($ipaddr))
847
			$realifip = $ipaddr;
848
		else
849
			$realifip = get_interface_ipv6($gif['if']);
850
		$realifgw = get_interface_gatewayv6($gif['if']);
851
	}
852
	/* make sure the parent interface is up */
853
	if($realif)
854
		interfaces_bring_up($realif);
855
	else 
856
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
857

    
858
	if ($g['booting'] || !(empty($gif['gifif']))) {
859
		pfSense_interface_destroy($gif['gifif']);
860
		pfSense_interface_create($gif['gifif']);
861
		$gifif = $gif['gifif'];
862
	} else
863
		$gifif = pfSense_interface_create("gif");
864

    
865
	/* Do not change the order here for more see gif(4) NOTES section. */
866
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} {$gif['remote-addr']}");
867
	if((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
868
		mwexec("/sbin/ifconfig {$gifif} inet6 {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} prefixlen /{$gif['tunnel-remote-net']} ");
869
	} else {
870
		mwexec("/sbin/ifconfig {$gifif} {$gif['tunnel-local-addr']} {$gif['tunnel-remote-addr']} netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
871
	}
872
	if (isset($gif['link0']) && $gif['link0'])
873
		pfSense_interface_flags($gifif, IFF_LINK0);
874
	if (isset($gif['link1']) && $gif['link1'])
875
		pfSense_interface_flags($gifif, IFF_LINK1);
876
	if($gifif)
877
		interfaces_bring_up($gifif);
878
	else
879
		log_error(gettext("could not bring gifif up -- variable not defined"));
880

    
881
	$iflist = get_configured_interface_list();
882
	foreach($iflist as $ifname) {
883
		if($config['interfaces'][$ifname]['if'] == $gifif) {
884
			if(get_interface_gateway($ifname)) {
885
				system_routing_configure($ifname);
886
				break;
887
			}
888
			if(get_interface_gateway_v6($ifname)) {
889
				system_routing_configure($ifname);
890
				break;
891
			}
892
		}
893
	}
894

    
895

    
896
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
897
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
898
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
899
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
900

    
901
        if (is_ipaddrv4($realifgw)) {
902
                mwexec("route change -host {$gif['remote-addr']} {$realifgw}");
903
        }
904
        if (is_ipaddrv6($realifgw)) {
905
                mwexec("route change -host -inet6 {$gif['remote-addr']} {$realifgw}");
906
        }
907

    
908
	return $gifif;
909
}
910

    
911
function interfaces_configure() {
912
	global $config, $g;
913

    
914
	if ($g['platform'] == 'jail')
915
		return;
916

    
917
	/* Set up our loopback interface */
918
	interfaces_loopback_configure();
919

    
920
	/* set up LAGG virtual interfaces */
921
	interfaces_lagg_configure();
922

    
923
	/* set up VLAN virtual interfaces */
924
	interfaces_vlan_configure();
925

    
926
	interfaces_qinq_configure();
927

    
928
	$iflist = get_configured_interface_with_descr();
929
	$delayed_list = array();
930
	$bridge_list = array();
931
	
932
	/* This is needed to speedup interfaces on bootup. */
933
	$reload = false;
934
	if (!$g['booting'])
935
		$reload = true;
936

    
937
	foreach($iflist as $if => $ifname) {
938
		$realif = $config['interfaces'][$if]['if'];
939
		if (strstr($realif, "bridge")) 
940
			$bridge_list[$if] = $ifname;
941
		else if (strstr($realif, "gre"))
942
			$delayed_list[$if] = $ifname;
943
		else if (strstr($realif, "gif"))
944
			$delayed_list[$if] = $ifname;
945
		else if (strstr($realif, "ovpn")) {
946
			//echo "Delaying OpenVPN interface configuration...done.\n";
947
			continue;
948
		} else {
949
			if ($g['booting'])
950
				printf(gettext("Configuring %s interface..."), $ifname);
951

    
952
			if($g['debug'])
953
				log_error(sprintf(gettext("Configuring %s"), $ifname));
954
			interface_configure($if, $reload);
955
			if ($g['booting']) 
956
				echo gettext( "done.") . "\n";
957
		}
958
	}
959

    
960
	/* create the unconfigured wireless clones */
961
	interfaces_create_wireless_clones();
962

    
963
	/*
964
	 * NOTE: The following function parameter consists of
965
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
966
	 *	2 - Do load gre/gif/bridge with parent/member as vip
967
	 */
968

    
969
	/* set up GRE virtual interfaces */
970
	interfaces_gre_configure(1);
971

    
972
	/* set up GIF virtual interfaces */
973
	interfaces_gif_configure(1);
974

    
975
	/* set up BRIDGe virtual interfaces */
976
	interfaces_bridge_configure(1);
977

    
978
	/* bring up vip interfaces */
979
	interfaces_vips_configure();
980

    
981
	/* set up GRE virtual interfaces */
982
	interfaces_gre_configure(2);
983

    
984
	/* set up GIF virtual interfaces */
985
	interfaces_gif_configure(2);
986

    
987
	foreach ($delayed_list as $if => $ifname) {
988
		if ($g['booting'])
989
			printf(gettext("Configuring %s interface..."), $ifname);
990
        	if ($g['debug'])
991
        		log_error(sprintf(gettext("Configuring %s"), $ifname));
992

    
993
		interface_configure($if, $reload);
994

    
995
		if ($g['booting'])
996
			echo gettext("done.") . "\n";
997
	}
998

    
999
	/* set up BRIDGe virtual interfaces */
1000
	interfaces_bridge_configure(2);
1001

    
1002
	foreach ($bridge_list as $if => $ifname) {
1003
		if ($g['booting'])
1004
			printf(gettext("Configuring %s interface..."), $ifname);
1005
		if($g['debug'])
1006
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1007

    
1008
		interface_configure($if, $reload);
1009

    
1010
		if ($g['booting'])
1011
			echo gettext("done.") . "\n";
1012
	}
1013

    
1014
	/* configure interface groups */
1015
	interfaces_group_setup();
1016

    
1017
	if (!$g['booting']) {
1018
		/* reconfigure static routes (kernel may have deleted them) */
1019
		system_routing_configure();
1020

    
1021
		/* reload IPsec tunnels */
1022
		vpn_ipsec_configure();
1023

    
1024
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1025
		services_dhcpd_configure();
1026

    
1027
		/* restart dnsmasq */
1028
		services_dnsmasq_configure();
1029

    
1030
		/* reload captive portal */
1031
		if (function_exists('captiveportal_init_rules'))
1032
			captiveportal_init_rules();
1033
	}
1034

    
1035
	return 0;
1036
}
1037

    
1038
function interface_reconfigure($interface = "wan", $reloadall = false) {
1039
	interface_bring_down($interface);
1040
	interface_configure($interface, $reloadall);
1041
}
1042

    
1043
function interface_vip_bring_down($vip) {
1044
	global $g;
1045

    
1046
	switch ($vip['mode']) {
1047
	case "proxyarp":
1048
		$vipif = get_real_interface($vip['interface']);
1049
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1050
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1051
		break;
1052
	case "ipalias":
1053
		$vipif = get_real_interface($vip['interface']);
1054
		if(does_interface_exist($vipif))
1055
			pfSense_interface_deladdress($vipif, $vip['subnet']);
1056
		break;
1057
	case "carp":
1058
		$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
1059
		if (does_interface_exist($vipif)) 
1060
			pfSense_interface_destroy($vipif);
1061
		break;
1062
	}
1063
}
1064

    
1065
function interface_bring_down($interface = "wan", $destroy = false) {
1066
	global $config, $g;
1067

    
1068
	if (!isset($config['interfaces'][$interface]))
1069
		return; 
1070
	log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1071

    
1072
	$ifcfg = $config['interfaces'][$interface];
1073

    
1074
	$realif = get_real_interface($interface);
1075

    
1076
	switch ($ifcfg['ipaddr']) {
1077
	case "ppp":
1078
	case "pppoe":
1079
	case "pptp":
1080
	case "l2tp":
1081
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1082
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1083
				if ($realif == $ppp['if']) {
1084
					if (isset($ppp['ondemand']) && !$destroy){
1085
						send_event("interface reconfigure {$interface}");
1086
						break;
1087
					}
1088
					if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1089
						killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1090
						sleep(2);
1091
					}
1092
					unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1093
					break;
1094
				}
1095
			}
1096
		}
1097
		break;
1098
	case "dhcp":
1099
		$pid = find_dhclient_process($realif);
1100
		if($pid)
1101
			mwexec("/bin/kill {$pid}");
1102
		sleep(1);
1103
		unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1104
		if(does_interface_exist("$realif")) {
1105
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1106
			if ($destroy == true)
1107
				pfSense_interface_flags($realif, -IFF_UP);
1108
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1109
		}
1110
		break;
1111
	default:
1112
		if(does_interface_exist("$realif")) {
1113
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1114
			if ($destroy == true)
1115
				pfSense_interface_flags($realif, -IFF_UP);
1116
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1117
		}
1118
		break;
1119
	}
1120

    
1121
	switch ($ifcfg['ipaddrv6']) {
1122
	case "slaac":
1123
	case "dhcp6":
1124
		$pidv6 = find_dhcp6c_process($realif);
1125
		if($pidv6)
1126
			mwexec("/bin/kill {$pidv6}");
1127
		sleep(3);
1128
		unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1129
		if(does_interface_exist("$realif")) {
1130
			$ip6 = get_interface_ipv6($interface);
1131
			if (is_ipaddrv6($ip6))
1132
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1133
			if ($destroy == true)
1134
				pfSense_interface_flags($realif, -IFF_UP);
1135
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1136
		}
1137
		break;
1138
	case "6rd":
1139
	case "6to4":
1140
		$realif = "stf0";
1141
		if(does_interface_exist("$realif")) {
1142
			$ip6 = get_interface_ipv6($interface);
1143
			if (is_ipaddrv6($ip6))
1144
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1145
			if ($destroy == true)
1146
				pfSense_interface_flags($realif, -IFF_UP);
1147
		}		
1148
		break;
1149
	default:
1150
		if(does_interface_exist("$realif")) {
1151
			$ip6 = get_interface_ipv6($interface);
1152
			if (is_ipaddrv6($ip6))
1153
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1154
			if ($destroy == true)
1155
				pfSense_interface_flags($realif, -IFF_UP);
1156
			mwexec("/usr/sbin/arp -d -i {$realif} -a");
1157
		}
1158
		break;
1159
	}
1160

    
1161
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1162
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1163
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1164
	if (!empty($old_router)) {
1165
		log_error("Clearing states to old gateway {$old_router}.");
1166
		mwexec("/sbin/pfctl -b 0.0.0.0/32 -b {$old_router}/32");
1167
	}
1168

    
1169
	/* remove interface up file if it exists */
1170
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1171
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1172
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1173
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1174
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1175
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1176
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1177
	
1178
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1179
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1180
	if (is_array($ifcfg['wireless'])) {
1181
		mwexec(kill_hostapd($realif));
1182
		mwexec(kill_wpasupplicant($realif));
1183
	}
1184

    
1185
	if ($destroy == true) {
1186
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|^stf/i", $realif))
1187
			pfSense_interface_destroy($realif);
1188
	}	
1189

    
1190
	return;
1191
}
1192

    
1193
function interfaces_ptpid_used($ptpid) {
1194
	global $config;
1195

    
1196
	if (is_array($config['ppps']['ppp']))
1197
		foreach ($config['ppps']['ppp'] as & $settings)
1198
			if ($ptpid == $settings['ptpid'])
1199
				return true;
1200

    
1201
	return false;
1202
}
1203

    
1204
function interfaces_ptpid_next() {
1205

    
1206
	$ptpid = 0;
1207
	while(interfaces_ptpid_used($ptpid))
1208
		$ptpid++;
1209

    
1210
	return $ptpid;
1211
}
1212

    
1213
function getMPDCRONSettings($pppif) {
1214
	global $config;
1215

    
1216
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1217
	if (is_array($config['cron']['item'])) {
1218
		foreach ($config['cron']['item'] as $i => $item) {
1219
			if (stripos($item['command'], $cron_cmd_file) !== false)
1220
				return array("ID" => $i, "ITEM" => $item);
1221
		}
1222
	}
1223

    
1224
	return NULL;
1225
}
1226

    
1227
function handle_pppoe_reset($post_array) {
1228
	global $config, $g;
1229

    
1230
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1231
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1232

    
1233
	if (!is_array($config['cron']['item'])) 
1234
		$config['cron']['item'] = array(); 
1235

    
1236
	$itemhash = getMPDCRONSettings($pppif);
1237
	
1238
	// reset cron items if necessary and return
1239
	if (empty($post_array['pppoe-reset-type'])) {
1240
		if (isset($itemhash))
1241
			unset($config['cron']['item'][$itemhash['ID']]);
1242
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1243
		return;
1244
	}
1245

    
1246
	if (empty($itemhash)) 
1247
		$itemhash = array();
1248
	$item = array();
1249
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1250
		$item['minute'] = $post_array['pppoe_resetminute'];
1251
		$item['hour'] = $post_array['pppoe_resethour'];
1252
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1253
			$date = explode("/", $post_array['pppoe_resetdate']);
1254
			$item['mday'] = $date[1];
1255
			$item['month'] = $date[0];
1256
		} else {
1257
			$item['mday'] = "*";
1258
			$item['month'] = "*";
1259
		}
1260
		$item['wday'] = "*";
1261
		$item['who'] = "root";
1262
		$item['command'] = $cron_cmd_file;
1263
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1264
		switch ($post_array['pppoe_pr_preset_val']) {
1265
		case "monthly":
1266
			$item['minute'] = "0";
1267
			$item['hour'] = "0";
1268
			$item['mday'] = "1";
1269
			$item['month'] = "*";
1270
			$item['wday'] = "*";
1271
			break;
1272
	        case "weekly":
1273
			$item['minute'] = "0";
1274
			$item['hour'] = "0";
1275
			$item['mday'] = "*";
1276
			$item['month'] = "*";
1277
			$item['wday'] = "0";
1278
			break;
1279
		case "daily":
1280
			$item['minute'] = "0";
1281
			$item['hour'] = "0";
1282
			$item['mday'] = "*";
1283
			$item['month'] = "*";
1284
			$item['wday'] = "*";
1285
			break;
1286
		case "hourly":
1287
			$item['minute'] = "0";
1288
			$item['hour'] = "*";
1289
			$item['mday'] = "*";
1290
			$item['month'] = "*";
1291
			$item['wday'] = "*";
1292
			break;
1293
		} // end switch
1294
		$item['who'] = "root";
1295
		$item['command'] = $cron_cmd_file;
1296
	}
1297
	if (empty($item))
1298
		return;
1299
	if (isset($item['ID'])) 
1300
		$config['cron']['item'][$item['ID']] = $item;
1301
	else 
1302
		$config['cron']['item'][] = $item;
1303
}
1304

    
1305
/*
1306
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1307
 * It writes the mpd config file to /var/etc every time the link is opened.
1308
 */
1309
function interface_ppps_configure($interface) {
1310
	global $config, $g;
1311

    
1312
	/* Return for unassigned interfaces. This is a minimum requirement. */
1313
	if (empty($config['interfaces'][$interface]))
1314
		return 0;
1315
	$ifcfg = $config['interfaces'][$interface];
1316
	if (!isset($ifcfg['enable']))
1317
		return 0;
1318

    
1319
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1320
	if(!is_dir("/var/spool/lock")) {
1321
		exec("/bin/mkdir -p /var/spool/lock");
1322
		exec("/bin/chmod a+rw /var/spool/lock/.");
1323
	}
1324
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1325
	if (!file_exists("{$g['varetc_path']}/mpd.script"))
1326
		mwexec("/bin/ln -s /usr/local/sbin/mpd.script {$g['varetc_path']}/.");
1327

    
1328
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1329
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1330
			if ($ifcfg['if'] == $ppp['if'])
1331
				break;
1332
		}
1333
	}
1334
	if (!$ppp || $ifcfg['if'] != $ppp['if']){
1335
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1336
		return 0;
1337
	}
1338
	$pppif = $ifcfg['if'];
1339
	if ($ppp['type'] == "ppp")
1340
		$type = "modem";
1341
	else
1342
		$type = $ppp['type'];
1343
	$upper_type = strtoupper($ppp['type']);	
1344

    
1345
	if($g['booting']) {
1346
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1347
		echo "starting {$pppif} link...";
1348
		// Do not re-configure the interface if we are booting and it's already been started
1349
		if(file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1350
			return 0;
1351
	}
1352

    
1353
	$ports = explode(',',$ppp['ports']);
1354
	if ($type != "modem") {
1355
		foreach ($ports as $pid => $port)
1356
			$ports[$pid] = get_real_interface($port);
1357
	}
1358
	$localips = explode(',',$ppp['localip']);
1359
	$gateways = explode(',',$ppp['gateway']);
1360
	$subnets = explode(',',$ppp['subnet']);
1361

    
1362
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1363
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1364
	 */
1365
	foreach($ports as $pid => $port){
1366
		switch ($ppp['type']) {
1367
			case "pppoe": 
1368
				/* Bring the parent interface up */
1369
				interfaces_bring_up($port);
1370
				pfSense_ngctl_attach(".", $port);
1371
				break;
1372
			case "pptp":
1373
			case "l2tp":
1374
				/* configure interface */
1375
				if(is_ipaddr($localips[$pid])){
1376
					// Manually configure interface IP/subnet
1377
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1378
					interfaces_bring_up($port);
1379
				} else if (empty($localips[$pid]))
1380
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1381
				
1382
				if(!is_ipaddr($localips[$pid])){
1383
					log_error("Could not get a Local IP address for PPTP/L2TP link on {$port} in interfaces_ppps_configure. Using 0.0.0.0 ip!");
1384
					$localips[$pid] = "0.0.0.0";
1385
				}
1386
				/* XXX: This needs to go away soon! [It's commented out!] */
1387
				/* Configure the gateway (remote IP ) */
1388
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
1389
					/* XXX: Fix later 
1390
					$gateways[$pid] = gethostbyname($gateways[$pid]);
1391
					if(!is_ipaddr($gateways[$pid])) {
1392
						log_error("Could not get a valid Gateway IP from {$port} via DNS in interfaces_ppps_configure.");
1393
						return 0;
1394
					}
1395
					*/
1396
				}
1397
				if(!is_ipaddr($gateways[$pid])){
1398
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
1399
					return 0;
1400
				}
1401
				pfSense_ngctl_attach(".", $port);
1402
				break;
1403
			case "ppp":
1404
				if (!file_exists("{$port}")) {
1405
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1406
					return 0;
1407
				}
1408
				break;
1409
			default:
1410
				log_error(sprintf(gettext("Unkown %s configured as ppp interface."), $type));
1411
				break;
1412
		}
1413
	}
1414
	
1415
	if (is_array($ports) && count($ports) > 1)
1416
		$multilink = "enable";
1417
	else
1418
		$multilink = "disable";
1419
	
1420
	if ($type == "modem"){
1421
		if (is_ipaddr($ppp['localip']))
1422
			$localip = $ppp['localip'];
1423
		else
1424
			$localip = '0.0.0.0';
1425

    
1426
		if (is_ipaddr($ppp['gateway']))
1427
			$gateway = $ppp['gateway'];
1428
		else
1429
			$gateway = "10.64.64.{$pppid}";
1430
		$ranges = "{$localip}/0 {$gateway}/0";
1431
		
1432
		if (empty($ppp['apnum']))	
1433
			$ppp['apnum'] = 1;
1434
	} else
1435
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1436

    
1437
	if (isset($ppp['ondemand'])) 
1438
		$ondemand = "enable";
1439
	else
1440
		$ondemand = "disable";
1441
	if (!isset($ppp['idletimeout']))
1442
		$ppp['idletimeout'] = 0;
1443

    
1444
	if (empty($ppp['username']) && $type == "modem"){
1445
		$ppp['username'] = "user";
1446
		$ppp['password'] = "none";
1447
	}
1448
	if (empty($ppp['password']) && $type == "modem")
1449
		$passwd = "none";
1450
	else
1451
		$passwd = base64_decode($ppp['password']);
1452

    
1453
	$bandwidths = explode(',',$ppp['bandwidth']);
1454
	$defaultmtu = "1492";
1455
	if (!empty($ifcfg['mtu']))
1456
		$defaultmtu = intval($ifcfg['mtu']);
1457
	$mtus = explode(',',$ppp['mtu']);
1458
	$mrus = explode(',',$ppp['mru']);
1459

    
1460
	if (isset($ppp['mrru']))
1461
		$mrrus = explode(',',$ppp['mrru']);
1462

    
1463
	// Construct the mpd.conf file
1464
	$mpdconf = <<<EOD
1465
startup:
1466
	# configure the console
1467
	set console close
1468
	# configure the web server
1469
	set web close
1470

    
1471
default:
1472
{$ppp['type']}client:
1473
	create bundle static {$interface}
1474
	set bundle enable ipv6cp
1475
	set iface name {$pppif}
1476

    
1477
EOD;
1478
	$setdefaultgw = false;
1479
	$founddefaultgw = false;
1480
	if (is_array($config['gateways']['gateway_item'])) {
1481
		foreach($config['gateways']['gateway_item'] as $gateway) {
1482
			if($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1483
				$setdefaultgw = true;
1484
				break;
1485
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1486
				$founddefaultgw = true;
1487
				break;
1488
			}
1489
		}
1490
	}
1491
	
1492
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true){
1493
		$setdefaultgw = true;
1494
		$mpdconf .= <<<EOD
1495
	set iface route default
1496

    
1497
EOD;
1498
	}
1499
	$mpdconf .= <<<EOD
1500
	set iface {$ondemand} on-demand
1501
	set iface idle {$ppp['idletimeout']}
1502

    
1503
EOD;
1504

    
1505
	if (isset($ppp['ondemand']))
1506
		$mpdconf .= <<<EOD
1507
	set iface addrs 10.10.1.1 10.10.1.2
1508

    
1509
EOD;
1510
	
1511
	if (isset($ppp['tcpmssfix']))
1512
		$tcpmss = "disable";
1513
	else
1514
		$tcpmss = "enable";
1515
		$mpdconf .= <<<EOD
1516
	set iface {$tcpmss} tcpmssfix
1517

    
1518
EOD;
1519

    
1520
	$mpdconf .= <<<EOD
1521
	set iface up-script /usr/local/sbin/ppp-linkup
1522
	set iface down-script /usr/local/sbin/ppp-linkdown
1523
	set ipcp ranges {$ranges}
1524

    
1525
EOD;
1526
	if (isset($ppp['vjcomp']))
1527
		$mpdconf .= <<<EOD
1528
	set ipcp no vjcomp
1529

    
1530
EOD;
1531

    
1532
	if (isset($config['system']['dnsallowoverride']))
1533
		$mpdconf .= <<<EOD
1534
	set ipcp enable req-pri-dns
1535
	set ipcp enable req-sec-dns
1536

    
1537
EOD;
1538
	if (!isset($ppp['verbose_log']))
1539
		$mpdconf .= <<<EOD
1540
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1541

    
1542
EOD;
1543
	foreach($ports as $pid => $port){
1544
		$port = get_real_interface($port);
1545
		$mpdconf .= <<<EOD
1546

    
1547
	create link static {$interface}_link{$pid} {$type}
1548
	set link action bundle {$interface}
1549
	set link {$multilink} multilink
1550
	set link keep-alive 10 60
1551
	set link max-redial 0
1552

    
1553
EOD;
1554
		if (isset($ppp['shortseq']))
1555
			$mpdconf .= <<<EOD
1556
	set link no shortseq
1557

    
1558
EOD;
1559

    
1560
		if (isset($ppp['acfcomp']))
1561
			$mpdconf .= <<<EOD
1562
	set link no acfcomp
1563

    
1564
EOD;
1565

    
1566
		if (isset($ppp['protocomp']))
1567
			$mpdconf .= <<<EOD
1568
	set link no protocomp
1569

    
1570
EOD;
1571

    
1572
		$mpdconf .= <<<EOD
1573
	set link disable chap pap
1574
	set link accept chap pap eap
1575
	set link disable incoming
1576

    
1577
EOD;
1578

    
1579

    
1580
		if (!empty($bandwidths[$pid]))
1581
			$mpdconf .= <<<EOD
1582
	set link bandwidth {$bandwidths[$pid]}
1583

    
1584
EOD;
1585

    
1586
		if (empty($mtus[$pid]))
1587
			$mtus[$pid] = $defaultmtu;
1588
			$mpdconf .= <<<EOD
1589
	set link mtu {$mtus[$pid]}
1590

    
1591
EOD;
1592

    
1593
		if (!empty($mrus[$pid]))
1594
			$mpdconf .= <<<EOD
1595
	set link mru {$mrus[$pid]}
1596

    
1597
EOD;
1598

    
1599
		if (!empty($mrrus[$pid]))
1600
			$mpdconf .= <<<EOD
1601
	set link mrru {$mrrus[$pid]}
1602

    
1603
EOD;
1604

    
1605
		$mpdconf .= <<<EOD
1606
	set auth authname "{$ppp['username']}"
1607
	set auth password {$passwd}
1608

    
1609
EOD;
1610
		if ($type == "modem") {
1611
			$mpdconf .= <<<EOD
1612
	set modem device {$ppp['ports']}
1613
	set modem script DialPeer
1614
	set modem idle-script Ringback
1615
	set modem watch -cd
1616
	set modem var \$DialPrefix "DT"
1617
	set modem var \$Telephone "{$ppp['phone']}"
1618

    
1619
EOD;
1620
		}
1621
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1622
			$mpdconf .= <<<EOD
1623
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1624

    
1625
EOD;
1626
		}
1627
		if (isset($ppp['initstr']) && $type == "modem") {
1628
			$initstr = base64_decode($ppp['initstr']);
1629
			$mpdconf .= <<<EOD
1630
	set modem var \$InitString "{$initstr}"
1631

    
1632
EOD;
1633
		}
1634
		if (isset($ppp['simpin']) && $type == "modem") {
1635
			if($ppp['pin-wait'] == "")
1636
				$ppp['pin-wait'] = 0;
1637
			$mpdconf .= <<<EOD
1638
	set modem var \$SimPin "{$ppp['simpin']}"
1639
	set modem var \$PinWait "{$ppp['pin-wait']}"
1640

    
1641
EOD;
1642
		}
1643
		if (isset($ppp['apn']) && $type == "modem") {
1644
			$mpdconf .= <<<EOD
1645
	set modem var \$APN "{$ppp['apn']}"
1646
	set modem var \$APNum "{$ppp['apnum']}"
1647

    
1648
EOD;
1649
		}
1650
		if ($type == "pppoe") {
1651
			// Send a null service name if none is set.
1652
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1653
			$mpdconf .= <<<EOD
1654
	set pppoe service "{$provider}"
1655

    
1656
EOD;
1657
		}
1658
		if ($type == "pppoe")
1659
			$mpdconf .= <<<EOD
1660
	set pppoe iface {$port}
1661

    
1662
EOD;
1663

    
1664
		if ($type == "pptp" || $type == "l2tp") {
1665
			$mpdconf .= <<<EOD
1666
	set {$type} self {$localips[$pid]}
1667
	set {$type} peer {$gateways[$pid]}
1668

    
1669
EOD;
1670
		}
1671
		
1672
		$mpdconf .= "\topen\n";
1673
	} //end foreach($port)
1674

    
1675

    
1676
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1677
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf"))
1678
		mwexec("/bin/ln -s {$g['conf_path']}/mpd_{$interface}.conf {$g['varetc_path']}/.");
1679
	else {
1680
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1681
		if (!$fd) {
1682
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1683
			return 0;
1684
		}
1685
		// Write out mpd_ppp.conf
1686
		fwrite($fd, $mpdconf);
1687
		fclose($fd);
1688
		unset($mpdconf);
1689
	}
1690

    
1691
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1692
	if (isset($ppp['uptime'])) {
1693
		if (!file_exists("/conf/{$pppif}.log")) {
1694
			conf_mount_rw();
1695
			mwexec("echo /dev/null > /conf/{$pppif}.log");
1696
			conf_mount_ro();
1697
		}
1698
	} else {
1699
		if (file_exists("/conf/{$pppif}.log")) {
1700
			conf_mount_rw();
1701
			mwexec("rm -f /conf/{$pppif}.log");
1702
			conf_mount_ro();
1703
		}
1704
	}
1705

    
1706
	/* clean up old lock files */
1707
	foreach($ports as $port) {
1708
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1709
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1710
	}
1711

    
1712
	/* fire up mpd */
1713
	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");
1714

    
1715
	// Check for PPPoE periodic reset request 
1716
	if ($type == "pppoe") {
1717
		if (!empty($ppp['pppoe-reset-type']))
1718
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1719
		else
1720
			interface_setup_pppoe_reset_file($ppp['if']);
1721
	}
1722
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1723
	$i = 0;
1724
	while($i < 10) {
1725
		exec("/sbin/ifconfig {$ppp['if']} 2>&1", $out, $ret);
1726
		if($ret == 0)
1727
			break;
1728
		sleep(1);
1729
		$i++;
1730
	}
1731

    
1732
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
1733
	/* We should be able to launch the right version for each modem */
1734
	/* We can also guess the mondev from the manufacturer */
1735
	exec("usbconfig | egrep -ie '(huawei)'", $usbmodemoutput);
1736
	mwexec("/bin/ps auxww|grep \"{$interface}\" |grep \"[3]gstats\" | awk '{print $2}' |xargs kill");
1737
	foreach($ports as $port) {
1738
		if(preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1739
			$mondev  = substr(basename($port), 0, -1);
1740
			$devlist = glob("/dev/{$mondev}?");
1741
			$mondev = basename(end($devlist));
1742
		}
1743
		if(preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1744
			$mondev  = substr(basename($port), 0, -1) . "1";
1745
		}
1746
		log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
1747
		mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
1748
	}
1749

    
1750
	return 1;
1751
}
1752

    
1753
function interfaces_carp_setup() {
1754
	global $g, $config;
1755

    
1756
	$balanacing = "";
1757
	$pfsyncinterface = "";
1758
	$pfsyncenabled = "";
1759
	if(isset($config['system']['developerspew'])) {
1760
		$mt = microtime();
1761
		echo "interfaces_carp_setup() being called $mt\n";
1762
	}
1763

    
1764
	// Prepare CmdCHAIN that will be used to execute commands.
1765
	$cmdchain = new CmdCHAIN();	
1766

    
1767
	if ($g['booting']) {
1768
		echo gettext("Configuring CARP settings...");
1769
		mute_kernel_msgs();
1770
	}
1771

    
1772
	/* suck in configuration items */
1773
	if($config['hasync']) {
1774
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1775
		$balanacing = $config['hasync']['balancing'];
1776
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1777
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1778
	} else {
1779
		unset($pfsyncinterface);
1780
		unset($balanacing);
1781
		unset($pfsyncenabled);
1782
	}
1783

    
1784
	if($balanacing) {
1785
		$cmdchain->add(gettext("Enable CARP ARP-balancing"), "/sbin/sysctl net.inet.carp.arpbalance=1", true);
1786
		$cmdchain->add(gettext("Disallow CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=0", true);
1787
	} else
1788
		$cmdchain->add(gettext("Enable CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=1", true);		
1789

    
1790
	$cmdchain->add(gettext("Enable CARP logging"), "/sbin/sysctl net.inet.carp.log=1", true);
1791
	if (!empty($pfsyncinterface))
1792
		$carp_sync_int = get_real_interface($pfsyncinterface);
1793

    
1794
	if($g['booting']) {
1795
		/*    install rules to alllow pfsync to sync up during boot
1796
		 *    carp interfaces will remain down until the bootup sequence finishes
1797
		 */
1798
		$fd = fopen("{$g['tmp_path']}/rules.boot", "w");
1799
		if ($fd) {
1800
			fwrite($fd, "block quick proto carp \n");
1801
			fwrite($fd, "block quick proto pfsync \n");
1802
			fwrite($fd, "pass out quick from any to any keep state\n");
1803
			fclose($fd);
1804
			mwexec("/sbin/pfctl -f {$g['tmp_path']}/rules.boot");
1805
		} else
1806
			log_error(gettext("Could not create rules.boot file!"));
1807
	}
1808

    
1809
	/* setup pfsync interface */
1810
	if($carp_sync_int and $pfsyncenabled) {
1811
		if (is_ipaddr($pfsyncpeerip))
1812
			$cmdchain->add(gettext("Bring up pfsync0 syncpeer"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} syncpeer {$pfsyncpeerip} up", false);						
1813
		else
1814
			$cmdchain->add(gettext("Bring up pfsync0 syncdev"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} up", false);			
1815
	} else
1816
		$cmdchain->add(gettext("Bring up pfsync0"), "/sbin/ifconfig pfsync0 syncdev lo0 up", false);						
1817

    
1818
	sleep(1);
1819

    
1820
	/* XXX: Handle an issue with pfsync(4) and carp(4). In a cluster carp will come up before pfsync(4) has updated and so will cause issues
1821
	 * for existing sessions.
1822
	 */
1823
	if ($config['hasync']['pfsyncenabled'] === "on"){
1824
		log_error("waiting for pfsync...");
1825
		$i = 0;
1826
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1827
			$i++;
1828
			sleep(1);
1829
		}
1830
		log_error("pfsync done in $i seconds.");
1831
		log_error("Configuring CARP settings finalize...");
1832
	}
1833

    
1834
	if($config['virtualip']['vip'])
1835
		$cmdchain->add(gettext("Allow CARP."), "/sbin/sysctl net.inet.carp.allow=1", true);				
1836
	else
1837
		$cmdchain->add(gettext("Disallow CARP."), "/sbin/sysctl net.inet.carp.allow=0", true);		
1838
	
1839
	if($g['debug'])
1840
		$cmdchain->setdebug(); // optional for verbose logging
1841

    
1842
	$cmdchain->execute();
1843
	$cmdchain->clear();
1844

    
1845
	if ($g['booting']) {
1846
		unmute_kernel_msgs();
1847
		echo gettext("done.") . "\n";
1848
	}
1849
}
1850

    
1851
function interface_proxyarp_configure($interface = "") {
1852
	global $config, $g;
1853
	if(isset($config['system']['developerspew'])) {
1854
		$mt = microtime();
1855
		echo "interface_proxyarp_configure() being called $mt\n";
1856
	}
1857

    
1858
	/* kill any running choparp */
1859
	if (empty($interface))
1860
		killbyname("choparp");
1861
	else {
1862
		$vipif = get_real_interface($interface);
1863
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1864
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1865
	}
1866

    
1867
	$paa = array();
1868
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1869

    
1870
		/* group by interface */
1871
		foreach ($config['virtualip']['vip'] as $vipent) {
1872
			if ($vipent['mode'] === "proxyarp") {
1873
				if ($vipent['interface'])
1874
					$proxyif = $vipent['interface'];
1875
				else
1876
					$proxyif = "wan";
1877
				
1878
				if (!empty($interface) && $interface != $proxyif)
1879
					continue;
1880

    
1881
				if (!is_array($paa[$proxyif]))
1882
					$paa[$proxyif] = array();
1883

    
1884
				$paa[$proxyif][] = $vipent;
1885
			}
1886
		}
1887
	}
1888

    
1889
	if (!empty($interface)) {
1890
		if (is_array($paa[$interface])) {
1891
			$paaifip = get_interface_ip($interface);
1892
                        if (!is_ipaddr($paaifip))
1893
                                return;
1894
                        $args = get_real_interface($interface) . " auto";
1895
                        foreach ($paa[$interface] as $paent) {
1896
                                if (isset($paent['subnet']))
1897
                                        $args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1898
                                else if (isset($paent['range']))
1899
                                        $args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1900
                        }
1901
                        mwexec_bg("/usr/local/sbin/choparp " . $args);	
1902
		}
1903
	} else if (count($paa) > 0) {
1904
		foreach ($paa as $paif => $paents)  {
1905
			$paaifip = get_interface_ip($paif);
1906
			if (!is_ipaddr($paaifip))
1907
				continue;
1908
			$args = get_real_interface($paif) . " auto";
1909
			foreach ($paents as $paent) {
1910
				if (isset($paent['subnet']))
1911
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
1912
				else if (isset($paent['range']))
1913
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
1914
			}
1915
			mwexec_bg("/usr/local/sbin/choparp " . $args);
1916
		}
1917
	}
1918
}
1919

    
1920
function interfaces_vips_configure($interface = "") {
1921
	global $g, $config;
1922
	if(isset($config['system']['developerspew'])) {
1923
		$mt = microtime();
1924
		echo "interfaces_vips_configure() being called $mt\n";
1925
	}
1926
	$paa = array();
1927
	if(is_array($config['virtualip']['vip'])) {
1928
		$carp_setuped = false;
1929
		$anyproxyarp = false;
1930
		foreach ($config['virtualip']['vip'] as $vip) {
1931
			switch ($vip['mode']) {
1932
			case "proxyarp":
1933
				/* nothing it is handled on interface_proxyarp_configure() */
1934
				if ($interface <> "" && $vip['interface'] <> $interface)
1935
					continue;
1936
				$anyproxyarp = true;
1937
				break;
1938
			case "ipalias":
1939
				if ($interface <> "" && $vip['interface'] <> $interface)
1940
					continue;
1941
				interface_ipalias_configure(&$vip);
1942
				break;
1943
			case "carp":
1944
				if ($interface <> "" && $vip['interface'] <> $interface)
1945
					continue;
1946
				if ($carp_setuped == false)
1947
					$carp_setuped = true;
1948
				interface_carp_configure($vip);
1949
				break;
1950
			}
1951
		}
1952
		if ($carp_setuped == true)
1953
			interfaces_carp_setup();
1954
		if ($anyproxyarp == true)
1955
			interface_proxyarp_configure();
1956
	}
1957
}
1958

    
1959
function interface_ipalias_configure(&$vip) {
1960
	if ($vip['mode'] == "ipalias") {
1961
		$if = get_real_interface($vip['interface']);
1962
		$af = "inet";
1963
		if(is_ipaddrv6($vip['subnet']))
1964
			$af = "inet6";
1965
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
1966
	}
1967
}
1968

    
1969
function interface_reload_carps($cif) {
1970
	global $config;
1971

    
1972
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
1973
	if (empty($carpifs))
1974
		return;
1975

    
1976
	$carps = explode(" ", $carpifs);
1977
	if(is_array($config['virtualip']['vip'])) {
1978
		$viparr = &$config['virtualip']['vip'];
1979
		foreach ($viparr as $vip) {
1980
			if (in_array($vip['carpif'], $carps)) {
1981
				switch ($vip['mode']) {
1982
				case "carp":
1983
					interface_vip_bring_down($vip);
1984
					sleep(1);
1985
					interface_carp_configure($vip);
1986
					break;
1987
				case "ipalias":
1988
					interface_vip_bring_down($vip);
1989
					sleep(1);
1990
					interface_ipalias_configure($vip);
1991
					break;
1992
				}
1993
			}
1994
		}
1995
	}
1996
}
1997

    
1998
function interface_carp_configure(&$vip) {
1999
	global $config, $g;
2000
	if(isset($config['system']['developerspew'])) {
2001
		$mt = microtime();
2002
		echo "interface_carp_configure() being called $mt\n";
2003
	}
2004

    
2005
	if ($vip['mode'] != "carp")
2006
		return;
2007

    
2008
	/*
2009
	 * ensure the interface containing the VIP really exists
2010
 	 * prevents a panic if the interface is missing or invalid
2011
	 */
2012
	$realif = get_real_interface($vip['interface']);
2013
	if (!does_interface_exist($realif)) {
2014
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2015
		return;
2016
	}
2017

    
2018
	if(is_ipaddrv4($vip['subnet'])) {
2019
		/* Ensure CARP IP really exists prior to loading up. */
2020
		$ww_subnet_ip = find_interface_ip($realif);
2021
		$ww_subnet_bits = find_interface_subnet($realif);
2022
		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'])) {
2023
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IP address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2024
			return;
2025
		}
2026
	}
2027
	if(is_ipaddrv6($vip['subnet'])) {
2028
		/* Ensure CARP IP really exists prior to loading up. */
2029
		$ww_subnet_ip = find_interface_ipv6($realif);
2030
		$ww_subnet_bits = find_interface_subnetv6($realif);
2031
		if (!ip_in_subnet($vip['subnet'], gen_subnetv6($ww_subnet_ip, $ww_subnet_bits) . "/" . $ww_subnet_bits) && !ip_in_interface_alias_subnet($vip['interface'], $vip['subnet'])) {
2032
			file_notice("CARP", sprintf(gettext("Sorry but we could not find a matching real interface subnet for the virtual IPv6 address %s."), $vip['subnet']), "Firewall: Virtual IP", "");
2033
			return;
2034
		}
2035
	}
2036

    
2037
	// set the vip interface to the vhid
2038
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2039

    
2040
	/* create the carp interface and setup */
2041
	if (does_interface_exist($vipif)) {
2042
		pfSense_interface_flags($vipif, -IFF_UP);
2043
	} else {
2044
		$carpif = pfSense_interface_create("carp");
2045
		pfSense_interface_rename($carpif, $vipif);
2046
		pfSense_ngctl_name("{$carpif}:", $vipif);
2047
	}
2048

    
2049
	/* invalidate interface cache */
2050
	get_interface_arr(true);
2051

    
2052
	$vip_password = $vip['password'];
2053
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2054
	if ($vip['password'] != "")
2055
		$password = " pass {$vip_password}";
2056

    
2057
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2058
	$advbase = "";
2059
	if (!empty($vip['advbase']))
2060
		$advbase = "advbase {$vip['advbase']}";
2061

    
2062
	if(is_ipaddrv4($vip['subnet'])) {
2063
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2064
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2065
	}
2066
	if(is_ipaddrv6($vip['subnet'])) {
2067
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2068
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2069
	}
2070

    
2071
	interfaces_bring_up($vipif);
2072

    
2073
	return $vipif;
2074
}
2075

    
2076
function interface_wireless_clone($realif, $wlcfg) {
2077
	global $config, $g;
2078
	/*   Check to see if interface has been cloned as of yet.  
2079
	 *   If it has not been cloned then go ahead and clone it.
2080
	 */
2081
	$needs_clone = false;
2082
	if(is_array($wlcfg['wireless']))
2083
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2084
	else
2085
		$wlcfg_mode = $wlcfg['mode'];
2086
	switch($wlcfg_mode) {
2087
		 case "hostap":
2088
			$mode = "wlanmode hostap";
2089
			break;
2090
		 case "adhoc":
2091
			$mode = "wlanmode adhoc";
2092
			break;
2093
		 default:
2094
			$mode = "";
2095
			break;
2096
	}
2097
	$baseif = interface_get_wireless_base($wlcfg['if']);
2098
	if(does_interface_exist($realif)) {
2099
		exec("/sbin/ifconfig {$realif}", $output, $ret);
2100
		$ifconfig_str = implode($output);
2101
		if(($wlcfg_mode == "hostap") && (! preg_match("/hostap/si", $ifconfig_str))) {
2102
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2103
			$needs_clone = true;
2104
		}
2105
		if(($wlcfg_mode == "adhoc") && (! preg_match("/adhoc/si", $ifconfig_str))) {
2106
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2107
			$needs_clone = true;
2108
		}
2109
		if(($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2110
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2111
			$needs_clone = true;
2112
		}
2113
	} else {
2114
		$needs_clone = true;
2115
	}
2116

    
2117
	if($needs_clone == true) {
2118
		/* remove previous instance if it exists */
2119
		if(does_interface_exist($realif))
2120
			pfSense_interface_destroy($realif);
2121

    
2122
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2123
		// Create the new wlan interface. FreeBSD returns the new interface name.
2124
		// example:  wlan2
2125
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2126
		if($ret <> 0) {
2127
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2128
			return false;
2129
		}
2130
		$newif = trim($out[0]);
2131
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2132
		pfSense_interface_rename($newif, $realif);
2133
		// FIXME: not sure what ngctl is for. Doesn't work.
2134
		// mwexec("/usr/sbin/ngctl name {$newif}: {$realif}", false);
2135
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2136
	}
2137
	return true;
2138
}
2139

    
2140
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2141
	global $config, $g;
2142

    
2143
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2144
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
2145
	                         'regdomain', 'regcountry', 'reglocation');
2146

    
2147
	if(!is_interface_wireless($ifcfg['if']))
2148
		return;
2149

    
2150
	$baseif = interface_get_wireless_base($ifcfg['if']);
2151

    
2152
	// Sync shared settings for assigned clones
2153
	$iflist = get_configured_interface_list(false, true);
2154
	foreach ($iflist as $if) {
2155
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2156
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2157
				foreach ($shared_settings as $setting) {
2158
					if ($sync_changes) {
2159
						if (isset($ifcfg['wireless'][$setting]))
2160
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2161
						else if (isset($config['interfaces'][$if]['wireless'][$setting]))
2162
							unset($config['interfaces'][$if]['wireless'][$setting]);
2163
					} else {
2164
						if (isset($config['interfaces'][$if]['wireless'][$setting]))
2165
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2166
						else if (isset($ifcfg['wireless'][$setting]))
2167
							unset($ifcfg['wireless'][$setting]);
2168
					}
2169
				}
2170
				if (!$sync_changes)
2171
					break;
2172
			}
2173
		}
2174
	}
2175

    
2176
	// Read or write settings at shared area
2177
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2178
		foreach ($shared_settings as $setting) {
2179
			if ($sync_changes) {
2180
				if (isset($ifcfg['wireless'][$setting]))
2181
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2182
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2183
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2184
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2185
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2186
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2187
				else if (isset($ifcfg['wireless'][$setting]))
2188
					unset($ifcfg['wireless'][$setting]);
2189
			}
2190
		}
2191
	}
2192

    
2193
	// Sync the mode on the clone creation page with the configured mode on the interface
2194
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2195
		foreach ($config['wireless']['clone'] as &$clone) {
2196
			if ($clone['cloneif'] == $ifcfg['if']) {
2197
				if ($sync_changes) {
2198
					$clone['mode'] = $ifcfg['wireless']['mode'];
2199
				} else {
2200
					$ifcfg['wireless']['mode'] = $clone['mode'];
2201
				}
2202
				break;
2203
			}
2204
		}
2205
		unset($clone);
2206
	}
2207
}
2208

    
2209
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2210
	global $config, $g;
2211

    
2212
	/*    open up a shell script that will be used to output the commands.
2213
	 *    since wireless is changing a lot, these series of commands are fragile
2214
	 *    and will sometimes need to be verified by a operator by executing the command
2215
	 *    and returning the output of the command to the developers for inspection.  please
2216
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2217
	 */
2218

    
2219
	// Remove script file
2220
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2221

    
2222
	// Clone wireless nic if needed.
2223
	interface_wireless_clone($if, $wl);
2224

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

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

    
2232
	/* set values for /path/program */
2233
	$hostapd = "/usr/sbin/hostapd";
2234
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2235
	$ifconfig = "/sbin/ifconfig";
2236
	$sysctl = "/sbin/sysctl";
2237
	$killall = "/usr/bin/killall";
2238

    
2239
	/* Set all wireless ifconfig variables (split up to get rid of needed checking) */
2240

    
2241
	$wlcmd = array();
2242
	$wl_sysctl = array();
2243
	/* Make sure it's up */
2244
	$wlcmd[] = "up";
2245
	/* Set a/b/g standard */
2246
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2247
	$wlcmd[] = "mode " . escapeshellarg($standard);
2248

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

    
2254
	/* Set ssid */
2255
	if($wlcfg['ssid'])
2256
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2257

    
2258
	/* Set 802.11g protection mode */
2259
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2260

    
2261
	/* set wireless channel value */
2262
	if(isset($wlcfg['channel'])) {
2263
		if($wlcfg['channel'] == "0") {
2264
			$wlcmd[] = "channel any";
2265
		} else {
2266
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2267
		}
2268
	}
2269

    
2270
	/* Set antenna diversity value */
2271
	if(isset($wlcfg['diversity']))
2272
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2273

    
2274
	/* Set txantenna value */
2275
	if(isset($wlcfg['txantenna']))
2276
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2277

    
2278
	/* Set rxantenna value */
2279
	if(isset($wlcfg['rxantenna']))
2280
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2281

    
2282
	/* set Distance value */
2283
	if($wlcfg['distance'])
2284
		$distance = escapeshellarg($wlcfg['distance']);
2285

    
2286
	/* Set wireless hostap mode */
2287
	if ($wlcfg['mode'] == "hostap") {
2288
		$wlcmd[] = "mediaopt hostap";
2289
	} else {
2290
		$wlcmd[] = "-mediaopt hostap";
2291
	}
2292

    
2293
	/* Set wireless adhoc mode */
2294
	if ($wlcfg['mode'] == "adhoc") {
2295
		$wlcmd[] = "mediaopt adhoc";
2296
	} else {
2297
		$wlcmd[] = "-mediaopt adhoc";
2298
	}
2299

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

    
2302
	/* handle hide ssid option */
2303
	if(isset($wlcfg['hidessid']['enable'])) {
2304
		$wlcmd[] = "hidessid";
2305
	} else {
2306
		$wlcmd[] = "-hidessid";
2307
	}
2308

    
2309
	/* handle pureg (802.11g) only option */
2310
	if(isset($wlcfg['pureg']['enable'])) {
2311
		$wlcmd[] = "mode 11g pureg";
2312
	} else {
2313
		$wlcmd[] = "-pureg";
2314
	}
2315

    
2316
	/* handle puren (802.11n) only option */
2317
	if(isset($wlcfg['puren']['enable'])) {
2318
		$wlcmd[] = "puren";
2319
	} else {
2320
		$wlcmd[] = "-puren";
2321
	}
2322

    
2323
	/* enable apbridge option */
2324
	if(isset($wlcfg['apbridge']['enable'])) {
2325
		$wlcmd[] = "apbridge";
2326
	} else {
2327
		$wlcmd[] = "-apbridge";
2328
	}
2329

    
2330
	/* handle turbo option */
2331
	if(isset($wlcfg['turbo']['enable'])) {
2332
		$wlcmd[] = "mediaopt turbo";
2333
	} else {
2334
		$wlcmd[] = "-mediaopt turbo";
2335
	}
2336

    
2337
	/* handle txpower setting */
2338
	/* if($wlcfg['txpower'] <> "")
2339
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2340
	*/
2341
	/* handle wme option */
2342
	if(isset($wlcfg['wme']['enable'])) {
2343
		$wlcmd[] = "wme";
2344
	} else {
2345
		$wlcmd[] = "-wme";
2346
	}
2347

    
2348
	/* set up wep if enabled */
2349
	$wepset = "";
2350
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2351
		switch($wlcfg['wpa']['auth_algs']) {
2352
			case "1":
2353
				$wepset .= "authmode open wepmode on ";
2354
				break;
2355
			case "2":
2356
				$wepset .= "authmode shared wepmode on ";
2357
				break;
2358
			case "3":
2359
				$wepset .= "authmode mixed wepmode on ";
2360
		}
2361
		$i = 1;
2362
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2363
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2364
			if (isset($wepkey['txkey'])) {
2365
				$wlcmd[] = "weptxkey {$i} ";
2366
			}
2367
			$i++;
2368
		}
2369
		$wlcmd[] = $wepset;
2370
	} else {
2371
		$wlcmd[] = "authmode open wepmode off ";
2372
	}
2373

    
2374
	mwexec(kill_hostapd("{$if}"));
2375
	mwexec(kill_wpasupplicant("{$if}"));
2376

    
2377
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2378
	conf_mount_rw();
2379

    
2380
	switch ($wlcfg['mode']) {
2381
		case 'bss':
2382
			if (isset($wlcfg['wpa']['enable'])) {
2383
				$wpa .= <<<EOD
2384
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2385
ctrl_interface_group=0
2386
ap_scan=1
2387
#fast_reauth=1
2388
network={
2389
ssid="{$wlcfg['ssid']}"
2390
scan_ssid=1
2391
priority=5
2392
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2393
psk="{$wlcfg['wpa']['passphrase']}"
2394
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2395
group={$wlcfg['wpa']['wpa_pairwise']}
2396
}
2397
EOD;
2398

    
2399
				$fd = fopen("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", "w");
2400
				fwrite($fd, "{$wpa}");
2401
				fclose($fd);
2402
			}
2403
			break;
2404
		case 'hostap':
2405
			if($wlcfg['wpa']['passphrase']) 
2406
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2407
			else 
2408
				$wpa_passphrase = "";
2409
			if (isset($wlcfg['wpa']['enable'])) {
2410
				$wpa .= <<<EOD
2411
interface={$if}
2412
driver=bsd
2413
logger_syslog=-1
2414
logger_syslog_level=0
2415
logger_stdout=-1
2416
logger_stdout_level=0
2417
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2418
ctrl_interface={$g['varrun_path']}/hostapd
2419
ctrl_interface_group=wheel
2420
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2421
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2422
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2423
ssid={$wlcfg['ssid']}
2424
debug={$wlcfg['wpa']['debug_mode']}
2425
auth_algs={$wlcfg['wpa']['auth_algs']}
2426
wpa={$wlcfg['wpa']['wpa_mode']}
2427
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2428
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2429
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2430
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2431
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2432
{$wpa_passphrase}
2433

    
2434
EOD;
2435

    
2436
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2437
	$wpa .= <<<EOD
2438
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2439
rsn_preauth=1
2440
rsn_preauth_interfaces={$if}
2441

    
2442
EOD;
2443

    
2444
}
2445
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2446
					$auth_server_port = "1812";
2447
					if($wlcfg['auth_server_port']) 
2448
						$auth_server_port = $wlcfg['auth_server_port'];
2449
					$auth_server_port2 = "1812";
2450
					if($wlcfg['auth_server_port2']) 
2451
						$auth_server_port2 = $wlcfg['auth_server_port2'];
2452
					$wpa .= <<<EOD
2453

    
2454
ieee8021x=1
2455
auth_server_addr={$wlcfg['auth_server_addr']}
2456
auth_server_port={$auth_server_port}
2457
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2458
auth_server_addr={$wlcfg['auth_server_addr2']}
2459
auth_server_port={$auth_server_port2}
2460
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2461

    
2462
EOD;
2463
				} else {
2464
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2465
				}
2466

    
2467
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2468
				fwrite($fd, "{$wpa}");
2469
				fclose($fd);
2470

    
2471
			}
2472
			break;
2473
	}
2474

    
2475
	/*
2476
	 *    all variables are set, lets start up everything
2477
	 */
2478

    
2479
	$baseif = interface_get_wireless_base($if);
2480
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2481
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2482

    
2483
	/* set sysctls for the wireless interface */
2484
	if (!empty($wl_sysctl)) {
2485
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2486
		foreach ($wl_sysctl as $wl_sysctl_line) {
2487
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2488
		}
2489
	}
2490

    
2491
	/* set ack timers according to users preference (if he/she has any) */
2492
	if($distance) {
2493
		fwrite($fd_set, "# Enable ATH distance settings\n");
2494
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2495
	}
2496

    
2497
	if (isset($wlcfg['wpa']['enable'])) {
2498
		if ($wlcfg['mode'] == "bss") {
2499
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2500
		}
2501
		if ($wlcfg['mode'] == "hostap") {
2502
			/* add line to script to restore old mac to make hostapd happy */
2503
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2504
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2505
				if (is_macaddr($if_oldmac))
2506
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2507
						" link " . escapeshellarg($if_oldmac) . "\n");
2508
			}
2509

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

    
2512
			/* add line to script to restore spoofed mac after running hostapd */
2513
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2514
				if ($wl['spoofmac'])
2515
					$if_curmac = $wl['spoofmac'];
2516
				else
2517
					$if_curmac = get_interface_mac($if);
2518
				if (is_macaddr($if_curmac))
2519
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2520
						" link " . escapeshellarg($if_curmac) . "\n");
2521
			}
2522
		}
2523
	}
2524

    
2525
	fclose($fd_set);
2526
	conf_mount_ro();
2527

    
2528
	/* Making sure regulatory settings have actually changed
2529
	 * before applying, because changing them requires bringing
2530
	 * down all wireless networks on the interface. */
2531
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2532
	$ifconfig_str = implode($output);
2533
	unset($output);
2534
	$reg_changing = false;
2535

    
2536
	/* special case for the debug country code */
2537
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str))
2538
		$reg_changing = true;
2539
	else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str))
2540
		$reg_changing = true;
2541
	else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str))
2542
		$reg_changing = true;
2543
	else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str))
2544
		$reg_changing = true;
2545
	else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str))
2546
		$reg_changing = true;
2547

    
2548
	if ($reg_changing) {
2549
		/* set regulatory domain */
2550
		if($wlcfg['regdomain'])
2551
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2552

    
2553
		/* set country */
2554
		if($wlcfg['regcountry'])
2555
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2556

    
2557
		/* set location */
2558
		if($wlcfg['reglocation'])
2559
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2560

    
2561
		$wlregcmd_args = implode(" ", $wlregcmd);
2562

    
2563
		/* build a complete list of the wireless clones for this interface */
2564
		$clone_list = array();
2565
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2566
			$clone_list[] = interface_get_wireless_clone($baseif);
2567
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2568
			foreach ($config['wireless']['clone'] as $clone) {
2569
				if ($clone['if'] == $baseif)
2570
					$clone_list[] = $clone['cloneif'];
2571
			}
2572
		}
2573

    
2574
		/* find which clones are up and bring them down */
2575
		$clones_up = array();
2576
		foreach ($clone_list as $clone_if) {
2577
			$clone_status = pfSense_get_interface_addresses($clone_if);
2578
			if ($clone_status['status'] == 'up') {
2579
				$clones_up[] = $clone_if;
2580
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2581
			}
2582
		}
2583

    
2584
		/* apply the regulatory settings */
2585
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2586

    
2587
		/* bring the clones back up that were previously up */
2588
		foreach ($clones_up as $clone_if) {
2589
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2590

    
2591
			/*
2592
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2593
			 * is in infrastructure mode, and WPA is enabled.
2594
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2595
			 */
2596
			if ($clone_if != $if) {
2597
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2598
				if ( !empty($friendly_if)
2599
				    && $config['interfaces'][$friendly_if]['wireless']['mode'] == "bss"
2600
				    && isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']) ) {
2601
					mwexec("/bin/sh {$g['tmp_path']}/{$clone_if}_setup.sh");
2602
				}
2603
			}
2604
		}
2605
	}
2606

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

    
2611
	/* configure wireless */
2612
	$wlcmd_args = implode(" ", $wlcmd);
2613
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2614

    
2615
	
2616
	sleep(1);
2617
	/* execute hostapd and wpa_supplicant if required in shell */
2618
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2619

    
2620
	return 0;
2621

    
2622
}
2623

    
2624
function kill_hostapd($interface) {
2625
	return "/bin/pkill -f \"hostapd .*{$interface}\"\n";
2626
}
2627

    
2628
function kill_wpasupplicant($interface) {
2629
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\"\n";
2630
}
2631

    
2632
function find_dhclient_process($interface) {
2633
	if ($interface)
2634
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2635
	else
2636
		$pid = 0;
2637

    
2638
	return intval($pid);
2639
}
2640

    
2641
function find_dhcp6c_process($interface) {
2642
	if ($interface)
2643
		$pid = `/bin/ps auxww|grep "[d]hclient[ ]-6" |grep "{$interface}"|awk '{print $2}'`;
2644
	else
2645
		return(false);
2646

    
2647
	return intval($pid);
2648
}
2649

    
2650
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2651
	global $config, $g;
2652
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2653
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2654

    
2655
	$wancfg = $config['interfaces'][$interface];
2656

    
2657
	$realif = get_real_interface($interface);
2658
	$realhwif_array = get_parent_interface($interface);
2659
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2660
	$realhwif = $realhwif_array[0];
2661

    
2662
	/* Disable Accepting router advertisements unless specifically requested */
2663
	log_error("Deny router advertisements for interface {$interface}");
2664
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv");
2665
			
2666
	if (!$g['booting'] && !(substr($realif, 0, 4) == "ovpn")) {
2667
		/* remove all IPv4 and IPv6 addresses */
2668
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " -alias", true) == 0);
2669
		while (mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -alias", true) == 0);
2670

    
2671
		/* only bring down the interface when both v4 and v6 are set to NONE */
2672
		if(($wancfg['ipaddr'] <> "none") && ($wancfg['ipaddrv6'] <> "none")) {
2673
			interface_bring_down($interface);
2674
		}
2675
	}
2676

    
2677
	/* wireless configuration? */
2678
	if (is_array($wancfg['wireless']))
2679
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2680

    
2681
	$mac = get_interface_mac($realhwif);
2682
	/*	Don't try to reapply the spoofed MAC if it's already applied.
2683
		When ifconfig link is used, it cycles the interface down/up, which triggers 
2684
		the interface config again, which attempts to spoof the MAC again, 
2685
		which cycles the link again... */
2686
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
2687
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2688
			" link " . escapeshellarg($wancfg['spoofmac']));
2689

    
2690
                /*
2691
                 * All vlans need to spoof their parent mac address, too.  see
2692
                 * ticket #1514: http://cvstrac.pfsense.com/tktview?tn=1514,33
2693
                 */
2694
                if (is_array($config['vlans']['vlan'])) {
2695
                        foreach ($config['vlans']['vlan'] as $vlan) {
2696
                                if ($vlan['if'] == $realhwif)
2697
                                        mwexec("/sbin/ifconfig " . escapeshellarg($vlan['vlanif']) .
2698
                                                " link " . escapeshellarg($wancfg['spoofmac']));
2699
                        }
2700
                }
2701
	}  else {
2702

    
2703
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2704
			/*   this is not a valid mac address.  generate a
2705
			 *   temporary mac address so the machine can get online.
2706
			 */
2707
			echo gettext("Generating new MAC address.");
2708
			$random_mac = generate_random_mac_address();
2709
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2710
				" link " . escapeshellarg($random_mac));
2711
			$wancfg['spoofmac'] = $random_mac;
2712
			write_config();
2713
			file_notice("MAC Address altered", sprintf(gettext('The INVALID MAC address (ff:ff:ff:ff:ff:ff) on interface %1$s has been automatically replaced with %2$s'), $realif, $random_mac), "Interfaces");
2714
		}
2715
	}
2716

    
2717
	/* media */
2718
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2719
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2720
		if ($wancfg['media'])
2721
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2722
		if ($wancfg['mediaopt'])
2723
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2724
		mwexec($cmd);
2725
	}
2726
	if (!empty($wancfg['mtu']))
2727
		pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2728
	else {
2729
		$mtu = get_interface_default_mtu(remove_numbers($realhwif));
2730
		if ($mtu != get_interface_mtu($realhwif))
2731
			pfSense_interface_mtu($realhwif, $mtu);
2732
	}
2733

    
2734
	$options = pfSense_get_interface_addresses($realhwif);
2735
	if (is_array($options) && isset($options['caps']['polling'])) {
2736
		if (isset($config['system']['polling']))
2737
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2738
		else
2739
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2740
	}
2741

    
2742
	/* skip vlans for checksumming and polling */
2743
        if (!stristr($realhwif, "vlan") && is_array($options)) {
2744
		$flags = 0;
2745
		if(isset($config['system']['disablechecksumoffloading'])) {
2746
			if (isset($options['encaps']['txcsum']))
2747
				$flags |= IFCAP_TXCSUM;
2748
			if (isset($options['encaps']['rxcsum']))
2749
				$flags |= IFCAP_RXCSUM;
2750
        	} else {
2751
 			if (!isset($options['caps']['txcsum']))
2752
				$flags |= IFCAP_TXCSUM;
2753
			if (!isset($options['caps']['rxcsum']))
2754
				$flags |= IFCAP_RXCSUM;
2755
        	}
2756

    
2757
        	if(isset($config['system']['disablesegmentationoffloading'])) {
2758
                	if (isset($options['encaps']['tso4']))
2759
				$flags |= IFCAP_TSO;
2760
                	if (isset($options['encaps']['tso6']))
2761
				$flags |= IFCAP_TSO;
2762
        	} else {
2763
                	if (!isset($options['caps']['tso4']))
2764
				$flags |= IFCAP_TSO;
2765
                	if (!isset($options['caps']['tso6']))
2766
				$flags |= IFCAP_TSO;
2767
        	}
2768

    
2769
        	if(isset($config['system']['disablelargereceiveoffloading'])) {
2770
                	if (isset($options['encaps']['lro']))
2771
				$flags |= IFCAP_LRO;
2772
        	} else {
2773
                	if (!isset($options['caps']['lro']))
2774
				$flags |= IFCAP_LRO;
2775
        	}
2776

    
2777
        	/* if the NIC supports polling *AND* it is enabled in the GUI */
2778
        	if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2779
			$flags |= IFCAP_POLLING;
2780
		}
2781
               	pfSense_interface_capabilities($realhwif, -$flags);
2782
	}
2783

    
2784
	/* invalidate interface/ip/sn cache */
2785
	get_interface_arr(true);
2786
	unset($interface_ip_arr_cache[$realif]);
2787
	unset($interface_sn_arr_cache[$realif]);
2788
	unset($interface_ipv6_arr_cache[$realif]);
2789
	unset($interface_snv6_arr_cache[$realif]);
2790

    
2791
	switch ($wancfg['ipaddr']) {
2792
		case 'dhcp':
2793
			interface_dhcp_configure($interface);
2794
			break;
2795
		case 'pppoe':
2796
		case 'l2tp':
2797
		case 'pptp':
2798
		case 'ppp':
2799
			interface_ppps_configure($interface);
2800
			break;
2801
		default:
2802
			if (is_ipaddr($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
2803
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
2804
			} else if (substr($realif, 0, 3) == "gre") {
2805
				if (is_array($config['gres']['gre'])) {
2806
					foreach ($config['gres']['gre'] as $gre)
2807
						if ($gre['greif'] == $realif)
2808
							interface_gre_configure($gre);
2809
				}
2810
			} else if (substr($realif, 0, 3) == "gif") {
2811
				 if (is_array($config['gifs']['gif'])) {
2812
					foreach ($config['gifs']['gif'] as $gif)
2813
						if($gif['gifif'] == $realif)
2814
							interface_gif_configure($gif);
2815
				}
2816
			} else if (substr($realif, 0, 4) == "ovpn") {
2817
				/* XXX: Should be done anything?! */
2818
			}
2819
			break;
2820
	}
2821

    
2822
	switch ($wancfg['ipaddrv6']) {
2823
		case 'slaac':
2824
		case 'dhcp6':
2825
			interface_dhcpv6_configure($interface);
2826
			break;
2827
		case '6rd':
2828
			interface_6rd_configure($interface);
2829
			break;
2830
		case '6to4':
2831
			interface_6to4_configure($interface);
2832
			break;
2833
		case 'track6':
2834
			interface_track6_configure($interface);
2835
			break;
2836
		default:
2837
			if (is_ipaddr($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
2838
				pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
2839
				// FIXME: Add IPv6 Support to the pfSense module
2840
				mwexec("/sbin/ifconfig {$realif} inet6 {$wancfg['ipaddrv6']} prefixlen {$wancfg['subnetv6']} ");
2841
			}
2842
			break;
2843
	}
2844

    
2845
	if(does_interface_exist($wancfg['if']))
2846
		interfaces_bring_up($wancfg['if']);
2847

    
2848
	interface_netgraph_needed($interface);
2849
 	
2850
	if (!$g['booting']) {
2851
		link_interface_to_vips($interface, "update");
2852

    
2853
		unset($gre);
2854
		$gre = link_interface_to_gre($interface);
2855
		if (!empty($gre))
2856
			array_walk($gre, 'interface_gre_configure');
2857

    
2858
		unset($gif);
2859
		$gif = link_interface_to_gif($interface);
2860
		if (!empty($gif))
2861
			array_walk($gif, 'interface_gif_configure');
2862

    
2863
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
2864
			unset($bridgetmp);
2865
			$bridgetmp = link_interface_to_bridge($interface);
2866
			if (!empty($bridgetmp))
2867
				interface_bridge_add_member($bridgetmp, $realif);
2868
		}
2869

    
2870
		$grouptmp = link_interface_to_group($interface);
2871
		if (!empty($grouptmp))
2872
			array_walk($grouptmp, 'interface_group_add_member');
2873

    
2874
		if ($interface == "lan")
2875
			/* make new hosts file */
2876
			system_hosts_generate();
2877

    
2878
		if ($reloadall == true) {
2879

    
2880
			/* reconfigure static routes (kernel may have deleted them) */
2881
			system_routing_configure($interface);
2882

    
2883
			/* reload ipsec tunnels */
2884
			vpn_ipsec_configure();
2885

    
2886
			/* restart dnsmasq */
2887
			services_dnsmasq_configure();
2888

    
2889
			/* update dyndns */
2890
			send_event("service reload dyndns {$interface}");
2891

    
2892
			/* reload captive portal */
2893
			captiveportal_init_rules();
2894
		}
2895
	}
2896

    
2897
	return 0;
2898
}
2899

    
2900
function interface_track6_configure($interface = "lan") {
2901
	global $config, $g;
2902
	$iflist = get_configured_interface_with_descr(false, true);
2903

    
2904
	$wancfg = $config['interfaces'][$interface];
2905
	$wanif = $wancfg['if'];
2906
	if (empty($wancfg))
2907
		$wancfg = array();
2908

    
2909
	$wanif = get_real_interface($interface);
2910
	
2911
	/* If the interface is not configured via another, exit */
2912
	if(!$wancfg['track6-interface'] <> "") {
2913
		return(false);
2914
	}
2915

    
2916
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
2917
	$realif = get_real_interface($interface);
2918
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
2919

    
2920
	$type = $config['interfaces'][$wancfg['track6-interface']]['ipaddrv6'];
2921
	switch($type) {
2922
		case "6to4":
2923
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2924
			interface_track6_6to4_configure($interface);
2925
			break;
2926
		case "6rd":
2927
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2928
			interface_track6_6rd_configure($interface);
2929
			break;
2930
		case "dhcp6":
2931
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
2932
			interface_track6_dhcp6_configure($interface);
2933
			break;
2934
		default:
2935
			log_error("Interface {$interface} configured via {$wancfg['track6-interface']} but unknown type {$type}");
2936
			break;
2937
	}
2938
	return 0;
2939
}
2940

    
2941

    
2942
function interface_track6_6rd_configure($interface = "lan") {
2943
	global $config, $g;
2944
	$iflist = get_configured_interface_with_descr(false, true);
2945

    
2946
	$lancfg = $config['interfaces'][$interface];
2947
	$lanif = $lancfg['if'];
2948
	if (empty($lancfg))
2949
		$lancfg = array();
2950

    
2951
	$lanif = get_real_interface($interface);
2952
	
2953
	/* If the interface is not configured via another, exit */
2954
	if(!$lancfg['track6-interface'] <> "") {
2955
		return(false);
2956
	}
2957
	if(!is_numeric($lancfg['track6-prefix-id']))
2958
		$lancfg['track6-prefix-id'] = 0;
2959
	
2960
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
2961
	$wanif = $wancfg['if'];
2962
	if (empty($wancfg))
2963
		$wancfg = array();
2964
	
2965
	$ip4address = find_interface_ip($wanif);
2966
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
2967
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
2968
		return false;
2969
	}
2970
	$hexwanv4 = return_hex_ipv4($ip4address);
2971
	
2972
	/* create the long prefix notation for math, save the prefix length */
2973
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
2974
	$rd6prefixlen = $rd6prefix[1];
2975
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
2976

    
2977
	/* binary presentation of the prefix for all 128 bits. */
2978
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
2979
	
2980
	/* just save the left prefix length bits */
2981
	$rd6lanbin = substr($rd6lanbin, 0, $rd6prefixlen);
2982
	/* add the v4 address, offset n bits from the left */
2983
	$rd6lanbin .= substr(sprintf("%032b", hexdec($hexwanv4)), (0 + $wancfg['prefix-6rd-v4plen']), 32);
2984

    
2985
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
2986
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
2987
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
2988
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
2989
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
2990
	/* fill the rest out with zeros */
2991
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);;
2992

    
2993
	/* convert the 128 bits for the lan address back into a valid IPv6 address */ 
2994
	$rd6lan = convert_128bit_to_ipv6($rd6lanbin) ."1";
2995
	
2996
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
2997
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
2998
	return 0;
2999
}
3000

    
3001
function interface_track6_6to4_configure($interface = "lan") {
3002
	global $config, $g;
3003
	$iflist = get_configured_interface_with_descr(false, true);
3004

    
3005
	$lancfg = $config['interfaces'][$interface];
3006
	$lanif = $lancfg['if'];
3007
	if (empty($lancfg))
3008
		$lancfg = array();
3009

    
3010
	$lanif = get_real_interface($interface);
3011
	
3012
	/* If the interface is not configured via another, exit */
3013
	if(!$lancfg['track6-interface'] <> "") {
3014
		return(false);
3015
	}
3016
	if(!is_numeric($lancfg['track6-prefix-id']))
3017
		$lancfg['track6-prefix-id'] = 0;
3018
	
3019
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3020
	$wanif = $wancfg['if'];
3021
	if (empty($wancfg))
3022
		$wancfg = array();
3023
	
3024
	$ip4address = find_interface_ip($wanif);
3025
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3026
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3027
		return false;
3028
	}
3029
	$hexwanv4 = return_hex_ipv4($ip4address);
3030
	
3031
	/* create the long prefix notation for math, save the prefix length */
3032
	$sixto4prefix = "2002::";
3033
	$sixto4prefixlen = 16;
3034
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3035

    
3036
	/* binary presentation of the prefix for all 128 bits. */
3037
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3038
	
3039
	/* just save the left prefix length bits */
3040
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3041
	/* add the v4 address */
3042
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3043
	/* add the custom prefix id */
3044
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3045
	/* fill the rest out with zeros */
3046
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);;
3047
	
3048
	/* convert the 128 bits for the lan address back into a valid IPv6 address */ 
3049
	$sixto4lan = convert_128bit_to_ipv6($sixto4lanbin) ."1";
3050
	
3051
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3052
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3053
	return 0;
3054
}
3055

    
3056
function interface_track6_dhcp6_configure($interface = "lan") {
3057
	global $config, $g;
3058
	$iflist = get_configured_interface_with_descr(false, true);
3059

    
3060
	$lancfg = $config['interfaces'][$interface];
3061
	$lanif = $lancfg['if'];
3062
	if (empty($lancfg))
3063
		$lancfg = array();
3064

    
3065
	$lanif = get_real_interface($interface);
3066
	
3067
	/* If the interface is not configured via another, exit */
3068
	if(!$lancfg['track6-interface'] <> "") {
3069
		return(false);
3070
	}
3071
	if(!is_numeric($lancfg['track6-prefix-id']))
3072
		$lancfg['track6-prefix-id'] = 0;
3073
	
3074
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3075
	$wanif = $wancfg['if'];
3076
	if (empty($wancfg))
3077
		$wancfg = array();
3078
	
3079
	$realwanif = get_real_interface($wanif);
3080
	if(is_readable("{$g['vardb_path']}/{$realwanif}_pd_ipv6")) {
3081
		$ifcfgipv6pfx = file_get_contents("{$g['vardb_path']}/{$realwanif}_pd_ipv6");
3082
	} else {
3083
		log_error("No DHCP-PD delegated prefix found, exiting");
3084
		return false;
3085
	}		
3086

    
3087
	log_error("Delegated IPv6 prefix is {$ifcfgipv6pfx}");
3088
	$ifcfgipv6pfxarr = explode("/", $ifcfgipv6pfx);
3089
	$ifcfgipv6 = $ifcfgipv6pfxarr[0];
3090
	
3091
	if(is_ipaddrv6($ifcfgipv6)) {
3092
		$dhcp6lanarr = explode(":", Net_IPv6::uncompress($ifcfgipv6));
3093
		/* we need to fold the $lancfg['track6-prefix-id'] into this address */
3094
		$dhcp6lanarr[4] = 0;
3095
		$dhcp6lanarr[5] = 0;
3096
		$dhcp6lanarr[6] = 0;
3097
		$dhcp6lanarr[7] = 1;
3098
		$dhcp6lan =  Net_IPv6::compress(implode(":", $dhcp6lanarr));
3099
		log_error("dhcp6 {$interface} with ipv6 address {$dhcp6lan} based on {$lancfg['track6-interface']}");
3100
		mwexec("/sbin/ifconfig {$lanif} inet6 {$dhcp6lan} prefixlen 64");
3101
	} else {
3102
		log_error("The DHCP-PD interface {$interface} address {$ifcfgipv6} is not a valid IPv6 address");
3103
	}
3104
	return 0;
3105
}
3106

    
3107
function interface_6rd_configure($interface = "wan") {
3108
	global $config, $g;
3109
	$iflist = get_configured_interface_with_descr(false, true);
3110

    
3111
	/* because this is a tunnel interface we can only function 
3112
	 *	with a public IPv4 address on the interface */
3113

    
3114
	$wancfg = $config['interfaces'][$interface];
3115
	$wanif = $wancfg['if'];
3116
	if (empty($wancfg))
3117
		$wancfg = array();
3118

    
3119
	$wanif = get_real_interface($interface);
3120
	
3121
	$ip4address = find_interface_ip($wanif);
3122
	$ip4gateway = get_interface_gateway($wanif);
3123
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3124
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3125
		return false;
3126
	}
3127
	$hexwanv4 = return_hex_ipv4($ip4address);
3128
	
3129
	if(!is_numeric($wancfg['prefix-6rd-v4plen']))
3130
		$wancfg['prefix-6rd-v4plen'] = 0;
3131

    
3132
	/* create the long prefix notation for math, save the prefix length */
3133
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3134
	$rd6prefixlen = $rd6prefix[1];
3135
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3136

    
3137
	/* we need the hex form of the broker IPv4 address */
3138
	$hexbrv4 = return_hex_ipv4($wancfg['gateway-6rd']);
3139
	
3140
	/* binary presentation of the prefix for all 128 bits. */
3141
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3142
		
3143
	/* just save the left prefix length bits */
3144
	$rd6brprefixbin = substr($rd6prefixbin, 0, $rd6prefixlen);
3145
	/* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
3146
	$rd6brprefixbin .= substr(sprintf("%032b", hexdec($hexbrv4)), $wancfg['prefix-6rd-v4plen'], 32);
3147
	/* fill out the rest with 0's */
3148
	$rd6brprefixbin = str_pad($rd6brprefixbin, 128, "0", STR_PAD_RIGHT);;
3149

    
3150
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3151
	$rd6brgw = convert_128bit_to_ipv6($rd6brprefixbin);
3152

    
3153
	/* just save the left prefix length bits */
3154
	$rd6prefixbin = substr($rd6prefixbin, 0, $rd6prefixlen);
3155
	/* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
3156
	$rd6prefixbin .= substr(sprintf("%032b", hexdec($hexwanv4)), $wancfg['prefix-6rd-v4plen'], 32);
3157
	/* fill out the rest with 0's */
3158
	$rd6prefixbin = str_pad($rd6prefixbin, 128, "0", STR_PAD_RIGHT);;
3159

    
3160
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3161
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3162

    
3163
	/* stf approach only works when embedding the entire 32 bits of the v4 */
3164
	mwexec("/sbin/ifconfig stf0 create");
3165
	pfSense_interface_flags("stf0", IFF_LINK2);
3166
	mwexec("/sbin/ifconfig stf0 inet6 {$rd6prefix}/{$rd6prefixlen}");
3167
	log_error("Created 6rd interface stf0 {$rd6prefix}/{$rd6prefixlen}");
3168

    
3169
	/* write out a default router file */
3170
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3171
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3172

    
3173
	if (is_ipaddrv4($ip4gateway))
3174
		mwexec("route change -host " . $wancfg['gateway-6rd'] . " {$ip4gateway}");
3175

    
3176
	/* configure dependent interfaces */
3177
	foreach($iflist as $if => $ifname) {
3178
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3179
			interface_track6_configure($if);
3180
	}
3181

    
3182
	return 0;
3183
}
3184

    
3185
function interface_6to4_configure($interface = "wan"){
3186
	global $config, $g;
3187
	$iflist = get_configured_interface_with_descr(false, true);
3188

    
3189
	/* because this is a tunnel interface we can only function 
3190
	 *	with a public IPv4 address on the interface */
3191

    
3192
	$wancfg = $config['interfaces'][$interface];
3193
	$wanif = $wancfg['if'];
3194
	if (empty($wancfg))
3195
		$wancfg = array();
3196

    
3197
	$wanif = get_real_interface($interface);
3198
	
3199
	$ip4address = find_interface_ip($wanif);
3200
	$ip4gateway = get_interface_gateway($wanif);
3201
	if((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3202
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3203
		return false;
3204
	}
3205
	
3206
	/* create the long prefix notation for math, save the prefix length */
3207
	$stfprefixlen = 16;
3208
	$stfprefix = Net_IPv6::uncompress("2002::");
3209
	$stfarr = explode(":", $stfprefix);
3210
	$v4prefixlen = "0";
3211
	
3212
	/* we need the hex form of the interface IPv4 address */
3213
	$ip4arr = explode(".", $ip4address);
3214
	$hexwanv4 = "";
3215
	foreach($ip4arr as $octet)
3216
		$hexwanv4 .= sprintf("%02x", $octet);
3217

    
3218
	/* we need the hex form of the broker IPv4 address */
3219
	$ip4arr = explode(".", "192.88.99.1");
3220
	$hexbrv4 = "";
3221
	foreach($ip4arr as $octet)
3222
		$hexbrv4 .= sprintf("%02x", $octet);
3223
	
3224
	/* binary presentation of the prefix for all 128 bits. */
3225
	$stfprefixbin = "";
3226
	foreach($stfarr as $element) {
3227
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3228
	}
3229
	/* just save the left prefix length bits */
3230
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3231

    
3232
	/* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
3233
	$stfbrokerbin = substr(sprintf("%032b", hexdec($hexbrv4)), $v4prefixlen, 32);
3234
	$stfbrokerbin = str_pad($stfprefixstartbin . $stfbrokerbin, 128, "0", STR_PAD_RIGHT);;
3235

    
3236
	/* for the local subnet too. */
3237
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3238
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3239

    
3240
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3241
	$stfbrarr = array();
3242
	$stfbrbinarr = array();
3243
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3244
	foreach($stfbrbinarr as $bin)
3245
		$stfbrarr[] = dechex(bindec($bin));
3246
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3247

    
3248
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3249
	$stflanarr = array();
3250
	$stflanbinarr = array();
3251
	$stflanbinarr = str_split($stflanbin, 16);
3252
	foreach($stflanbinarr as $bin)
3253
		$stflanarr[] = dechex(bindec($bin));
3254
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3255
	$stflanarr[7] = 1;
3256
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3257

    
3258
	/* setup the stf interface */
3259
	mwexec("/sbin/ifconfig stf0 destroy");
3260
	mwexec("/sbin/ifconfig stf0 create");
3261
	pfSense_interface_flags("stf0", IFF_LINK2);
3262
	mwexec("/sbin/ifconfig stf0 inet6 {$stflanpr} prefixlen 16");
3263

    
3264
	log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for stf0, route {$stfbrgw}");
3265
	
3266
	/* write out a default router file */
3267
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3268
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3269

    
3270
	if (is_ipaddrv4($ip4gateway)) {
3271
		mwexec("route change -host 192.88.99.1 {$ip4gateway}");
3272
	}
3273

    
3274
	/* configure dependent interfaces */
3275
	foreach($iflist as $if => $ifname) {
3276
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3277
			interface_track6_configure($if);
3278
	}
3279
	
3280
	return 0;
3281
}
3282

    
3283
function interface_dhcpv6_configure($interface = "wan") {
3284
	global $config, $g;
3285
	$iflist = get_configured_interface_with_descr(false, true);
3286

    
3287
	$wancfg = $config['interfaces'][$interface];
3288
	$wanif = $wancfg['if'];
3289
	if (empty($wancfg))
3290
		$wancfg = array();
3291

    
3292
	$wanif = get_real_interface($interface);
3293

    
3294
	/* Add ISC IPv6 dhclient here */
3295
	$fd = fopen("{$g['varetc_path']}/dhcp6c_{$interface}.conf", "w");
3296
	if (!$fd) {
3297
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3298
		return 1;
3299
	}
3300

    
3301
	$dhcp6cconf = "interface \"{$wanif}\" {\n";
3302
	$dhcp6cconf .= "script \"/sbin/dhclient6-script\";\n";
3303
	$dhcp6cconf .= "}\n";
3304

    
3305
	fwrite($fd, $dhcp6cconf);
3306
	fclose($fd);
3307

    
3308
	/* accept router advertisements for this interface */
3309
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3310
	log_error("Accept router advertisements on interface {$wanif} ");
3311
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3312

    
3313
	/* run a filter configure so that the filter rules allow traffic before we launch the client */
3314
	filter_configure_sync();
3315
	sleep(3);
3316

    
3317
	/* dhclient -6
3318
	 * -T temprorary address
3319
	 * -S information only
3320
	 * -P Prefix
3321
	 * -N request address with temporary or prefix
3322
	*/
3323

    
3324
	$dhcp6c_options = "";
3325
	if($wancfg['ipaddrv6'] == "slaac") {
3326
		$dhcp6c_options .= "-S ";
3327
	}
3328
	if($wancfg['ipaddrv6'] == "dhcp6") {
3329
		$dhcp6c_options .= "-N ";
3330
	}
3331
	if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3332
		$dhcp6c_options .= "-P ";		
3333
	}
3334
	/* fire up dhcp6c for IPv6 first, this backgrounds immediately */
3335
	mwexec_bg("/usr/local/sbin/dhclient -6 {$dhcp6c_options} -cf {$g['varetc_path']}/dhcp6c_{$interface}.conf -lf {$g['varetc_path']}/dhcp6c_{$interface}.leases -pf {$g['varrun_path']}/dhcp6c_{$interface}.pid {$wanif}");
3336
	sleep(5);
3337
	return 0;
3338
}
3339

    
3340
function interface_dhcp_configure($interface = "wan") {
3341
	global $config, $g;
3342

    
3343
	$wancfg = $config['interfaces'][$interface];
3344
	$wanif = $wancfg['if'];
3345
	if (empty($wancfg))
3346
		$wancfg = array();
3347

    
3348
	/* generate dhclient_wan.conf */
3349
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3350
	if (!$fd) {
3351
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3352
		return 1;
3353
	}
3354

    
3355
	if ($wancfg['dhcphostname']) {
3356
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3357
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3358
	} else {
3359
		$dhclientconf_hostname = "";
3360
	}
3361

    
3362
	$wanif = get_real_interface($interface);
3363
	if (empty($wanif)) {
3364
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3365
		return 0;
3366
	}
3367
 	$dhclientconf = "";
3368
	
3369
	$dhclientconf .= <<<EOD
3370
interface "{$wanif}" {
3371
timeout 60;
3372
retry 15;
3373
select-timeout 0;
3374
initial-interval 1;
3375
	{$dhclientconf_hostname}
3376
	script "/sbin/dhclient-script";
3377
}
3378

    
3379
EOD;
3380

    
3381
if(is_ipaddr($wancfg['alias-address'])) {
3382
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3383
	$dhclientconf .= <<<EOD
3384
alias {
3385
	interface  "{$wanif}";
3386
	fixed-address {$wancfg['alias-address']};
3387
	option subnet-mask {$subnetmask};
3388
}
3389

    
3390
EOD;
3391
}
3392
	fwrite($fd, $dhclientconf);
3393
	fclose($fd);
3394

    
3395
	/* bring wan interface up before starting dhclient */
3396
	if($wanif)
3397
		interfaces_bring_up($wanif);
3398
	else 
3399
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3400

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

    
3404
	return 0;
3405
}
3406

    
3407
function interfaces_group_setup() {
3408
	global $config;
3409

    
3410
	if (!is_array($config['ifgroups']['ifgroupentry']))
3411
		return;
3412

    
3413
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3414
		interface_group_setup($groupar);
3415

    
3416
	return;
3417
}
3418

    
3419
function interface_group_setup(&$groupname /* The parameter is an array */) {
3420
	global $config;
3421

    
3422
	if (!is_array($groupname))
3423
		return;
3424
	$members = explode(" ", $groupname['members']);
3425
	foreach($members as $ifs) {
3426
		$realif = get_real_interface($ifs);
3427
		if ($realif)
3428
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3429
	}
3430

    
3431
	return;
3432
}
3433

    
3434
function interface_group_add_member($interface, $groupname) {
3435
	$interface = get_real_interface($interface);
3436
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
3437
}
3438
 
3439
/* COMPAT Function */
3440
function convert_friendly_interface_to_real_interface_name($interface) {
3441
	return get_real_interface($interface);
3442
}
3443

    
3444
/* COMPAT Function */
3445
function get_real_wan_interface($interface = "wan") {
3446
	return get_real_interface($interface);
3447
}
3448

    
3449
/* COMPAT Function */
3450
function get_current_wan_address($interface = "wan") {
3451
	return get_interface_ip($interface);
3452
}
3453

    
3454
/*
3455
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3456
 */
3457
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3458
        global $config;
3459

    
3460
	if (stristr($interface, "_vip")) {
3461
                foreach ($config['virtualip']['vip'] as $counter => $vip) {
3462
                        if ($vip['mode'] == "carp")  {
3463
                                if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3464
                                        return $vip['interface'];
3465
                        }
3466
                }
3467
        }
3468

    
3469
        /* XXX: For speed reasons reference directly the interface array */
3470
	$ifdescrs = &$config['interfaces'];
3471
        //$ifdescrs = get_configured_interface_list(false, true);
3472

    
3473
        foreach ($ifdescrs as $if => $ifname) {
3474
                if ($config['interfaces'][$if]['if'] == $interface)
3475
                        return $if;
3476

    
3477
                if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
3478
                        return $if;
3479

    
3480
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
3481
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
3482
		/*
3483
                $int = get_parent_interface($if);
3484
                if ($int[0] == $interface)
3485
                        return $ifname;
3486
		*/
3487
        }
3488
        return NULL;
3489
}
3490

    
3491
/* attempt to resolve interface to friendly descr */
3492
function convert_friendly_interface_to_friendly_descr($interface) {
3493
        global $config;
3494

    
3495
        switch ($interface) {
3496
        case "l2tp":
3497
        	$ifdesc = "L2TP";
3498
                break;
3499
	case "pptp":
3500
		$ifdesc = "PPTP";
3501
		break;
3502
	case "pppoe":
3503
		$ifdesc = "PPPoE";
3504
		break;
3505
	case "openvpn":
3506
		$ifdesc = "OpenVPN";
3507
		break;
3508
	case "enc0":
3509
	case "ipsec":
3510
		$ifdesc = "IPsec";
3511
		break;
3512
        default:
3513
                if (isset($config['interfaces'][$interface])) {
3514
                        if (empty($config['interfaces'][$interface]['descr']))
3515
                                $ifdesc = strtoupper($interface);
3516
                        else
3517
                                $ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
3518
			break;
3519
		} else if (stristr($interface, "_vip")) {
3520
			if (is_array($config['virtualip']['vip'])) {
3521
				foreach ($config['virtualip']['vip'] as $counter => $vip) {
3522
					if ($vip['mode'] == "carp")  {
3523
						if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3524
							return "{$vip['subnet']} - {$vip['descr']}";
3525
					}
3526
				}
3527
                        }
3528
                } else {
3529
			/* if list */
3530
			$ifdescrs = get_configured_interface_with_descr(false, true);
3531
			foreach ($ifdescrs as $if => $ifname) {
3532
				if ($if == $interface || $ifname == $interface)
3533
					return $ifname;
3534
			}
3535
		}
3536
                break;
3537
        }
3538

    
3539
        return $ifdesc;
3540
}
3541

    
3542
function convert_real_interface_to_friendly_descr($interface) {
3543
        global $config;
3544

    
3545
        $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3546

    
3547
        if ($ifdesc) {
3548
                $iflist = get_configured_interface_with_descr(false, true);
3549
                return $iflist[$ifdesc];
3550
        }
3551

    
3552
        return $interface;
3553
}
3554

    
3555
/*
3556
 *  get_parent_interface($interface):
3557
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3558
 *				or virtual interface (i.e. vlan)
3559
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3560
 *			-- returns $interface passed in if $interface parent is not found
3561
 *			-- returns empty array if an invalid interface is passed
3562
 *	(Only handles ppps and vlans now.)
3563
 */
3564
function get_parent_interface($interface) {
3565
	global $config;
3566

    
3567
	$parents = array();
3568
	//Check that we got a valid interface passed
3569
	$realif = get_real_interface($interface);
3570
	if ($realif == NULL)
3571
		return $parents;
3572

    
3573
	// If we got a real interface, find it's friendly assigned name
3574
	$interface = convert_real_interface_to_friendly_interface_name($interface);
3575
		
3576
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
3577
		$ifcfg = $config['interfaces'][$interface];
3578
		switch ($ifcfg['ipaddr']) {
3579
			case "ppp":
3580
			case "pppoe":
3581
			case "pptp":
3582
			case "l2tp":
3583
				if (empty($parents))
3584
					if (is_array($config['ppps']['ppp']))
3585
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
3586
							if ($ppp_if == $ppp['if']) {
3587
								$ports = explode(',', $ppp['ports']);
3588
								foreach ($ports as $pid => $parent_if) 
3589
									$parents[$pid] = get_real_interface($parent_if);
3590
								break;
3591
							}
3592
						}
3593
				break;
3594
			case "dhcp":
3595
			case "static":
3596
			default:
3597
				// Handle _vlans
3598
				if (strstr($realif,"_vlan"))
3599
					if (is_array($config['vlans']['vlan'])) 
3600
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan)
3601
							if ($ifcfg['if'] == $vlan['vlanif']){
3602
								$parents[0] = $vlan['if'];
3603
								break;
3604
							}
3605
				break;
3606
		}
3607
	}
3608
	
3609
	if (empty($parents))
3610
		$parents[0] = $realif;
3611
	
3612
	return $parents;
3613
}
3614

    
3615
function interface_is_wireless_clone($wlif) {
3616
	if(!stristr($wlif, "_wlan")) {
3617
		return false;
3618
	} else {
3619
		return true;
3620
	}
3621
}
3622

    
3623
function interface_get_wireless_base($wlif) {
3624
	if(!stristr($wlif, "_wlan")) {
3625
		return $wlif;
3626
	} else {
3627
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3628
	}
3629
}
3630

    
3631
function interface_get_wireless_clone($wlif) {
3632
	if(!stristr($wlif, "_wlan")) {
3633
		return $wlif . "_wlan0";
3634
	} else {
3635
		return $wlif;
3636
	}
3637
}
3638

    
3639
function get_real_interface($interface = "wan") {
3640
    global $config;
3641

    
3642
	$wanif = NULL;
3643

    
3644
	switch ($interface) {
3645
	case "l2tp":
3646
		$wanif = "l2tp";
3647
		break;
3648
	case "pptp":
3649
		$wanif = "pptp";
3650
		break;
3651
	case "pppoe":
3652
		$wanif = "pppoe";
3653
		break;
3654
	case "openvpn":
3655
		$wanif = "openvpn";
3656
		break;
3657
	case "ipsec":
3658
	case "enc0":
3659
		$wanif = "enc0";
3660
		break;
3661
	case "ppp":
3662
		$wanif = "ppp";
3663
		break;
3664
	default:
3665
		// If a real interface was alread passed simply
3666
		// pass the real interface back.  This encourages
3667
		// the usage of this function in more cases so that
3668
		// we can combine logic for more flexibility.
3669
		if(does_interface_exist($interface)) {
3670
			$wanif = $interface;
3671
			break;
3672
		}
3673

    
3674
		if (empty($config['interfaces'][$interface]))
3675
			break;
3676

    
3677
		$cfg = &$config['interfaces'][$interface];
3678

    
3679
		// Wireless cloned NIC support (FreeBSD 8+)
3680
		// interface name format: $parentnic_wlanparentnic#
3681
		// example: ath0_wlan0
3682
		if (is_interface_wireless($cfg['if'])) {
3683
			$wanif = interface_get_wireless_clone($cfg['if']);
3684
			break;
3685
		}
3686
		/*
3687
		if (empty($cfg['if'])) {
3688
			$wancfg = $cfg['if'];
3689
			break;
3690
		}
3691
		*/
3692

    
3693
		switch ($cfg['ipaddr']) {
3694
			case "pppoe": 
3695
			case "pptp": 
3696
			case "l2tp": 
3697
			case "ppp":
3698
				$wanif = $cfg['if'];
3699
				break;
3700
			default:
3701
				$wanif = $cfg['if'];
3702
				break;
3703
		}
3704
		break;
3705
	}
3706

    
3707
    return $wanif;
3708
}
3709

    
3710
/* Guess the physical interface by providing a IP address */
3711
function guess_interface_from_ip($ipaddress) {
3712
	if(! is_ipaddr($ipaddress)) {
3713
		return false;
3714
	}
3715
	if(is_ipaddrv4($ipaddress)) {
3716
		/* create a route table we can search */
3717
		exec("netstat -rnWf inet", $output, $ret);
3718
		foreach($output as $line) {
3719
			if(preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\/[0-9]+[ ]+link[#]/", $line)) {
3720
				$fields = preg_split("/[ ]+/", $line);
3721
				if(ip_in_subnet($ipaddress, $fields[0])) {
3722
					return $fields[6];
3723
				}
3724
			}
3725
		}
3726
	}
3727
	/* FIXME: This works from cursory testing, regexp might need fine tuning */
3728
	if(is_ipaddrv6($ipaddress)) {
3729
		/* create a route table we can search */
3730
		exec("netstat -rnWf inet6", $output, $ret);
3731
		foreach($output as $line) {
3732
			if(preg_match("/[0-9a-f]+[:]+[0-9a-f]+[:]+[\/][0-9]+/", $line)) {
3733
				$fields = preg_split("/[ ]+/", $line);
3734
				if(ip_in_subnet($ipaddress, $fields[0])) {
3735
					return $fields[6];
3736
				}
3737
			}
3738
		}
3739
	}
3740
	$ret = exec_command("/sbin/route -n get {$ipaddress} | /usr/bin/awk '/interface/ { print \$2; };'");
3741
	if(empty($ret)) {
3742
        	return false;
3743
	}
3744
	return $ret;
3745
}
3746

    
3747
/*
3748
 * find_ip_interface($ip): return the interface where an ip is defined
3749
 *   (or if $bits is specified, where an IP within the subnet is defined)
3750
 */
3751
function find_ip_interface($ip, $bits = null)
3752
{
3753
	/* if list */
3754
	$ifdescrs = get_configured_interface_list();
3755
		
3756
	foreach ($ifdescrs as $ifdescr => $ifname) {
3757
		if ($bits === null) {
3758
			if ($ip == get_interface_ip($ifname)) {
3759
				$int = get_real_interface($ifname);
3760
				return $int;
3761
			}
3762
		}
3763
		else {
3764
			if (ip_in_subnet(get_interface_ip($ifname), $ip . "/" . $bits)) {
3765
				$int = get_real_interface($ifname);
3766
				return $int;
3767
			}
3768
		}
3769
	}
3770
	return false;
3771
}
3772

    
3773
/*
3774
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
3775
 *   (or if $bits is specified, where an IP within the subnet is found)
3776
 */
3777
function find_virtual_ip_alias($ip, $bits = null) {
3778
	global $config;
3779
	if (!is_array($config['virtualip']['vip'])) {
3780
		return false;
3781
	}
3782
	foreach ($config['virtualip']['vip'] as $vip) {
3783
		if ($vip['mode'] === "ipalias") {
3784
			if ($bits === null) {
3785
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
3786
					return $vip;
3787
				}
3788
			}
3789
			else {
3790
				if (check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) {
3791
					return $vip;
3792
				}
3793
			}
3794
		}
3795
	}
3796
	return false;
3797
}
3798

    
3799
/*
3800
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
3801
 */
3802
function find_number_of_created_carp_interfaces() {
3803
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
3804
}
3805

    
3806
function get_all_carp_interfaces() {
3807
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
3808
	$ints = explode(" ", $ints);
3809
	return $ints;
3810
}
3811

    
3812
/*
3813
 * find_carp_interface($ip): return the carp interface where an ip is defined
3814
 */
3815
function find_carp_interface($ip) {
3816
	global $config;
3817
	if (is_array($config['virtualip']['vip'])) {
3818
		foreach ($config['virtualip']['vip'] as $vip) {
3819
			if ($vip['mode'] == "carp") {
3820
				if(is_ipaddrv4($ip)) {
3821
					$carp_ip = get_interface_ip($vip['interface']);
3822
				}
3823
				if(is_ipaddrv6($ip)) {
3824
					$carp_ip = get_interface_ipv6($vip['interface']);
3825
				}
3826
				exec("/sbin/ifconfig", $output, $return);
3827
				foreach($output as $line) {
3828
					$elements = preg_split("/[ ]+/i", $line);
3829
					if(strstr($elements[0], "vip"))
3830
						$curif = str_replace(":", "", $elements[0]);
3831
					if(stristr($line, $ip)) {
3832
						$if = $curif;
3833
						continue;
3834
					}
3835
				}
3836

    
3837
				if ($if)
3838
					return $if;
3839
			}
3840
		}
3841
	}
3842
}
3843

    
3844
function link_carp_interface_to_parent($interface) {
3845
	global $config;
3846

    
3847
	if ($interface == "")
3848
		return;
3849

    
3850
	$carp_ip = get_interface_ip($interface);
3851
	$carp_ipv6 = get_interface_ipv6($interface);
3852

    
3853
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
3854
		return;
3855

    
3856
	/* if list */
3857
	$ifdescrs = get_configured_interface_list();
3858
	foreach ($ifdescrs as $ifdescr => $ifname) {
3859
		/* check IPv4 */
3860
		if(is_ipaddrv4($carp_ip)) {
3861
			$interfaceip = get_interface_ip($ifname);
3862
			$subnet_bits = get_interface_subnet($ifname);
3863
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3864
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3865
				return $ifname;
3866
		}
3867
		/* Check IPv6 */
3868
		if(is_ipaddrv6($carp_ipv6)) {
3869
			$interfaceipv6 = get_interface_ipv6($ifname);
3870
			$prefixlen = get_interface_subnetv6($ifname);
3871
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
3872
				return $ifname;
3873
		}
3874
	}
3875
	return "";
3876
}
3877

    
3878

    
3879
/****f* interfaces/link_ip_to_carp_interface
3880
 * NAME
3881
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3882
 * INPUTS
3883
 *   $ip
3884
 * RESULT
3885
 *   $carp_ints
3886
 ******/
3887
function link_ip_to_carp_interface($ip) {
3888
        global $config;
3889

    
3890
        if (!is_ipaddr($ip))
3891
                return;
3892

    
3893
        $carp_ints = "";
3894
        if (is_array($config['virtualip']['vip'])) {
3895
		$first = 0;
3896
		$carp_int = array();
3897
                foreach ($config['virtualip']['vip'] as $vip) {
3898
                        if ($vip['mode'] == "carp") {
3899
                                $carp_ip = $vip['subnet'];
3900
                                $carp_sn = $vip['subnet_bits'];
3901
                                $carp_nw = gen_subnet($carp_ip, $carp_sn);
3902
                                if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
3903
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
3904
				}
3905
                        }
3906
                }
3907
		if (!empty($carp_int))
3908
			$carp_ints = implode(" ", array_unique($carp_int));
3909
        }
3910

    
3911
        return $carp_ints;
3912
}
3913

    
3914
function link_interface_to_vlans($int, $action = "") {
3915
	global $config;
3916

    
3917
	if (empty($int))
3918
		return;
3919

    
3920
	if (is_array($config['vlans']['vlan'])) {
3921
                foreach ($config['vlans']['vlan'] as $vlan) {
3922
			if ($int == $vlan['if']) {
3923
				if ($action == "update") {
3924
					interfaces_bring_up($int);
3925
				} else if ($action == "")
3926
					return $vlan;
3927
			}
3928
		}
3929
	}
3930
}
3931

    
3932
function link_interface_to_vips($int, $action = "") {
3933
        global $config;
3934

    
3935
        if (is_array($config['virtualip']['vip'])) {
3936
		foreach ($config['virtualip']['vip'] as $vip) {
3937
			if ($int == $vip['interface']) {
3938
				if ($action == "update")
3939
					interfaces_vips_configure($int);
3940
				else
3941
					return $vip;
3942
			}
3943
		}
3944
	}
3945
}
3946

    
3947
/****f* interfaces/link_interface_to_bridge
3948
 * NAME
3949
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3950
 * INPUTS
3951
 *   $ip
3952
 * RESULT
3953
 *   bridge[0-99]
3954
 ******/
3955
function link_interface_to_bridge($int) {
3956
        global $config;
3957

    
3958
        if (is_array($config['bridges']['bridged'])) {
3959
                foreach ($config['bridges']['bridged'] as $bridge) {
3960
			if (in_array($int, explode(',', $bridge['members'])))
3961
                                return "{$bridge['bridgeif']}";
3962
		}
3963
	}
3964
}
3965

    
3966
function link_interface_to_group($int) {
3967
        global $config;
3968

    
3969
	$result = array();
3970

    
3971
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3972
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3973
			if (in_array($int, explode(" ", $group['members'])))
3974
				$result[$group['ifname']] = $int;
3975
		}
3976
	}
3977

    
3978
	return $result;
3979
}
3980

    
3981
function link_interface_to_gre($interface) {
3982
        global $config;
3983

    
3984
	$result = array();
3985

    
3986
        if (is_array($config['gres']['gre'])) {
3987
                foreach ($config['gres']['gre'] as $gre)
3988
                        if($gre['if'] == $interface)
3989
				$result[] = $gre;
3990
	}
3991

    
3992
	return $result;
3993
}
3994

    
3995
function link_interface_to_gif($interface) {
3996
        global $config;
3997

    
3998
	$result = array();
3999

    
4000
        if (is_array($config['gifs']['gif'])) {
4001
                foreach ($config['gifs']['gif'] as $gif)
4002
                        if($gif['if'] == $interface)
4003
                                $result[] = $gif;
4004
	}
4005

    
4006
	return $result;
4007
}
4008

    
4009
/*
4010
 * find_interface_ip($interface): return the interface ip (first found)
4011
 */
4012
function find_interface_ip($interface, $flush = false)
4013
{
4014
	global $interface_ip_arr_cache;
4015
	global $interface_sn_arr_cache;
4016

    
4017
	$interface = str_replace("\n", "", $interface);
4018
	
4019
	if (!does_interface_exist($interface))
4020
		return;
4021

    
4022
	/* Setup IP cache */
4023
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4024
		$ifinfo = pfSense_get_interface_addresses($interface);
4025
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4026
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4027
	}
4028

    
4029
	return $interface_ip_arr_cache[$interface];
4030
}
4031

    
4032
/*
4033
 * find_interface_ipv6($interface): return the interface ip (first found)
4034
 */
4035
function find_interface_ipv6($interface, $flush = false)
4036
{
4037
	global $interface_ipv6_arr_cache;
4038
	global $interface_snv6_arr_cache;
4039
	global $config;
4040
	
4041
	$interface = trim($interface);
4042
	$interface = get_real_interface($interface);
4043
	
4044
	if (!does_interface_exist($interface))
4045
		return;
4046

    
4047
	/* Setup IP cache */
4048
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
4049
		$ifinfo = pfSense_get_interface_addresses($interface);
4050
		// FIXME: Add IPv6 support to the pfSense module
4051
		exec("/sbin/ifconfig {$interface} inet6", $output);
4052
		foreach($output as $line) {
4053
			if(preg_match("/inet6/", $line)) {
4054
				$parts = explode(" ", $line);
4055
				if(! preg_match("/fe80::/", $parts[1])) {
4056
					$ifinfo['ipaddrv6'] = $parts[1];
4057
					if($parts[2] == "-->") {
4058
						$parts[5] = "126";
4059
						$ifinfo['subnetbitsv6'] = $parts[5];
4060
					} else {
4061
						$ifinfo['subnetbitsv6'] = $parts[3];
4062
					}
4063
				}
4064
			}
4065
		}
4066
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4067
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4068
	}
4069

    
4070
	return $interface_ipv6_arr_cache[$interface];
4071
}
4072

    
4073
/*
4074
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4075
 */
4076
function find_interface_ipv6_ll($interface, $flush = false)
4077
{
4078
	global $interface_llv6_arr_cache;
4079
	global $config;
4080
	
4081
	$interface = str_replace("\n", "", $interface);
4082
	
4083
	if (!does_interface_exist($interface))
4084
		return;
4085

    
4086
	/* Setup IP cache */
4087
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
4088
		$ifinfo = pfSense_get_interface_addresses($interface);
4089
		// FIXME: Add IPv6 support to the pfSense module
4090
		exec("/sbin/ifconfig {$interface} inet6", $output);
4091
		foreach($output as $line) {
4092
			if(preg_match("/inet6/", $line)) {
4093
				$parts = explode(" ", $line);
4094
				if(preg_match("/fe80::/", $parts[1])) {
4095
					$partsaddress = explode("%", $parts[1]);
4096
					$ifinfo['linklocal'] = $partsaddress[0];
4097
				}
4098
			}
4099
		}
4100
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
4101
	}
4102
	return $interface_llv6_arr_cache[$interface];
4103
}
4104

    
4105
function find_interface_subnet($interface, $flush = false)
4106
{
4107
	global $interface_sn_arr_cache;
4108
	global $interface_ip_arr_cache;
4109

    
4110
	$interface = str_replace("\n", "", $interface);
4111
	if (does_interface_exist($interface) == false)
4112
		return;
4113

    
4114
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4115
		$ifinfo = pfSense_get_interface_addresses($interface);
4116
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4117
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4118
        }
4119

    
4120
	return $interface_sn_arr_cache[$interface];
4121
}
4122

    
4123
function find_interface_subnetv6($interface, $flush = false)
4124
{
4125
	global $interface_snv6_arr_cache;
4126
	global $interface_ipv6_arr_cache;
4127

    
4128
	$interface = str_replace("\n", "", $interface);
4129
	if (does_interface_exist($interface) == false)
4130
		return;
4131

    
4132
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
4133
		$ifinfo = pfSense_get_interface_addresses($interface);
4134
		// FIXME: Add IPv6 support to the pfSense module
4135
		exec("/sbin/ifconfig {$interface} inet6", $output);
4136
		foreach($output as $line) {
4137
			if(preg_match("/inet6/", $line)) {
4138
				$parts = explode(" ", $line);
4139
				if(! preg_match("/fe80::/", $parts[1])) {
4140
					$ifinfo['ipaddrv6'] = $parts[1];
4141
					if($parts[2] == "-->") {
4142
						$parts[5] = "126";
4143
						$ifinfo['subnetbitsv6'] = $parts[5];
4144
					} else {
4145
						$ifinfo['subnetbitsv6'] = $parts[3];
4146
					}
4147
				}
4148
			}
4149
		}
4150
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddrv6'];
4151
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbitsv6'];
4152
        }
4153

    
4154
	return $interface_snv6_arr_cache[$interface];
4155
}
4156

    
4157
function ip_in_interface_alias_subnet($interface, $ipalias) {
4158
	global $config;
4159

    
4160
	if (empty($interface) || !is_ipaddr($ipalias))
4161
		return false;
4162
	if (is_array($config['virtualip']['vip'])) {
4163
                foreach ($config['virtualip']['vip'] as $vip) {
4164
                        switch ($vip['mode']) {
4165
                        case "ipalias":
4166
                                if ($vip['interface'] <> $interface)
4167
                                        break;
4168
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
4169
					return true;
4170
                                break;
4171
                        }
4172
                }
4173
	}
4174

    
4175
	return false;
4176
}
4177

    
4178
function get_interface_ip($interface = "wan")
4179
{
4180
	$realif = get_failover_interface($interface);
4181
	if (!$realif) {
4182
		if (preg_match("/^carp/i", $interface))
4183
			$realif = $interface;
4184
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4185
			$realif = $interface;
4186
		else
4187
			return null;
4188
	}
4189

    
4190
	$curip = find_interface_ip($realif);
4191
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4192
		return $curip;
4193
	else
4194
		return null;
4195
}
4196

    
4197
function get_interface_ipv6($interface = "wan")
4198
{
4199
	global $config;
4200
	$realif = get_failover_interface($interface);
4201
	switch($config['interfaces'][$interface]['ipaddrv6']) {
4202
		case "6rd":
4203
		case "6to4":
4204
			$realif = "stf0";
4205
			break;
4206
	}
4207
	if (!$realif) {
4208
		if (preg_match("/^carp/i", $interface))
4209
			$realif = $interface;
4210
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4211
			$realif = $interface;
4212
		else
4213
			return null;
4214
	}
4215

    
4216
	$curip = find_interface_ipv6($realif);
4217
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4218
		return $curip;
4219
	else
4220
		return null;
4221
}
4222

    
4223
function get_interface_linklocal($interface = "wan")
4224
{
4225
	$realif = get_failover_interface($interface);
4226
	if (!$realif) {
4227
		if (preg_match("/^carp/i", $interface))
4228
			$realif = $interface;
4229
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4230
			$realif = $interface;
4231
		else
4232
			return null;
4233
	}
4234

    
4235
	$curip = find_interface_ipv6_ll($realif);
4236
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4237
		return $curip;
4238
	else
4239
		return null;
4240
}
4241

    
4242
function get_interface_subnet($interface = "wan")
4243
{
4244
	$realif = get_real_interface($interface);
4245
	if (!$realif) {
4246
                if (preg_match("/^carp/i", $interface))
4247
                        $realif = $interface;
4248
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4249
                        $realif = $interface;
4250
                else
4251
                        return null;
4252
        }
4253

    
4254
	$cursn = find_interface_subnet($realif);
4255
	if (!empty($cursn))
4256
		return $cursn;
4257

    
4258
	return null;
4259
}
4260

    
4261
function get_interface_subnetv6($interface = "wan")
4262
{
4263
	$realif = get_real_interface($interface);
4264
	if (!$realif) {
4265
                if (preg_match("/^carp/i", $interface))
4266
                        $realif = $interface;
4267
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4268
                        $realif = $interface;
4269
                else
4270
                        return null;
4271
        }
4272

    
4273
	$cursn = find_interface_subnetv6($realif);
4274
	if (!empty($cursn))
4275
		return $cursn;
4276

    
4277
	return null;
4278
}
4279

    
4280
/* return outside interfaces with a gateway */
4281
function get_interfaces_with_gateway() {
4282
	global $config;
4283

    
4284
	$ints = array();
4285

    
4286
	/* loop interfaces, check config for outbound */
4287
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4288
		switch ($ifname['ipaddr']) {
4289
			case "dhcp":
4290
			case "ppp";
4291
			case "pppoe":
4292
			case "pptp":
4293
			case "l2tp":
4294
			case "ppp";
4295
				$ints[$ifdescr] = $ifdescr;
4296
			break;
4297
			default:
4298
				if (substr($ifname['if'], 0, 4) ==  "ovpn" ||
4299
				    !empty($ifname['gateway']))
4300
					$ints[$ifdescr] = $ifdescr;
4301
			break;
4302
		}
4303
	}
4304
	return $ints;
4305
}
4306

    
4307
/* return true if interface has a gateway */
4308
function interface_has_gateway($friendly) {
4309
	global $config;
4310

    
4311
	if (!empty($config['interfaces'][$friendly])) {
4312
		$ifname = &$config['interfaces'][$friendly];
4313
		switch ($ifname['ipaddr']) {
4314
			case "dhcp":
4315
			case "pppoe":
4316
			case "pptp":
4317
			case "l2tp":
4318
			case "ppp";
4319
				return true;
4320
			break;
4321
			default:
4322
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4323
					return true;
4324
				if (!empty($ifname['gateway']))
4325
					return true;
4326
			break;
4327
		}
4328
	}
4329

    
4330
	return false;
4331
}
4332

    
4333
/* return true if interface has a gateway */
4334
function interface_has_gatewayv6($friendly) {
4335
	global $config;
4336

    
4337
	if (!empty($config['interfaces'][$friendly])) {
4338
		$ifname = &$config['interfaces'][$friendly];
4339
		switch ($ifname['ipaddrv6']) {
4340
			case "slaac":
4341
			case "dhcp6":
4342
				return true;
4343
				break;
4344
			case "6to4":
4345
				return true;
4346
				break;
4347
			case "6rd":
4348
				return true;
4349
				break;
4350
			default:
4351
				if (substr($ifname['if'], 0, 4) ==  "ovpn")
4352
					return true;
4353
				if (!empty($ifname['gatewayv6']))
4354
					return true;
4355
				break;
4356
		}
4357
	}
4358

    
4359
	return false;
4360
}
4361

    
4362
/****f* interfaces/is_altq_capable
4363
 * NAME
4364
 *   is_altq_capable - Test if interface is capable of using ALTQ
4365
 * INPUTS
4366
 *   $int            - string containing interface name
4367
 * RESULT
4368
 *   boolean         - true or false
4369
 ******/
4370

    
4371
function is_altq_capable($int) {
4372
        /* Per:
4373
         * http://www.freebsd.org/cgi/man.cgi?query=altq&manpath=FreeBSD+7.2-current&format=html
4374
         * Only the following drivers have ALTQ support
4375
         */
4376
	$capable = array("age", "alc", "ale", "an", "ath", "aue", "awi", "bce",
4377
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "fxp", "gem",
4378
			"hme", "igb", "ipw", "iwi", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
4379
			"npe", "nve", "ral", "re", "rl", "rum", "run", "bwn", "sf", "sis", "sk",
4380
			"ste", "stge", "txp", "udav", "ural", "vge", "vr", "wi", "xl",
4381
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
4382
			"l2tp", "ppp", "vtnet");
4383

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

    
4386
        if (in_array($int_family[0], $capable))
4387
                return true;
4388
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4389
		return true;
4390
	else if (stristr($int, "vlan")) /* VLANs are name $parent_$vlan now */
4391
		return true;
4392
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4393
		return true;
4394
        else
4395
                return false;
4396
}
4397

    
4398
/****f* interfaces/is_interface_wireless
4399
 * NAME
4400
 *   is_interface_wireless - Returns if an interface is wireless
4401
 * RESULT
4402
 *   $tmp       - Returns if an interface is wireless
4403
 ******/
4404
function is_interface_wireless($interface) {
4405
        global $config, $g;
4406

    
4407
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
4408
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
4409
                if (preg_match($g['wireless_regex'], $interface)) {
4410
                        if (isset($config['interfaces'][$friendly]))
4411
                                $config['interfaces'][$friendly]['wireless'] = array();
4412
                        return true;
4413
                }
4414
                return false;
4415
        } else
4416
                return true;
4417
}
4418

    
4419
function get_wireless_modes($interface) {
4420
	/* return wireless modes and channels */
4421
	$wireless_modes = array();
4422

    
4423
	$cloned_interface = get_real_interface($interface);
4424

    
4425
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4426
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4427
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4428
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4429

    
4430
		$interface_channels = "";
4431
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4432
		$interface_channel_count = count($interface_channels);
4433

    
4434
		$c = 0;
4435
		while ($c < $interface_channel_count)
4436
		{
4437
			$channel_line = explode(",", $interface_channels["$c"]);
4438
			$wireless_mode = trim($channel_line[0]);
4439
			$wireless_channel = trim($channel_line[1]);
4440
			if(trim($wireless_mode) != "") {
4441
				/* if we only have 11g also set 11b channels */
4442
				if($wireless_mode == "11g") {
4443
					if(!isset($wireless_modes["11b"]))
4444
						$wireless_modes["11b"] = array();
4445
				} else if($wireless_mode == "11g ht") {
4446
					if(!isset($wireless_modes["11b"]))
4447
						$wireless_modes["11b"] = array();
4448
					if(!isset($wireless_modes["11g"]))
4449
						$wireless_modes["11g"] = array();
4450
					$wireless_mode = "11ng";
4451
				} else if($wireless_mode == "11a ht") {
4452
					if(!isset($wireless_modes["11a"]))
4453
						$wireless_modes["11a"] = array();
4454
					$wireless_mode = "11na";
4455
				}
4456
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
4457
			}
4458
			$c++;
4459
		}
4460
	}
4461
	return($wireless_modes);
4462
}
4463

    
4464
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4465
function get_wireless_channel_info($interface) {
4466
	$wireless_channels = array();
4467

    
4468
	$cloned_interface = get_real_interface($interface);
4469

    
4470
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4471
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4472
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4473
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4474

    
4475
		$interface_channels = "";
4476
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4477

    
4478
		foreach ($interface_channels as $channel_line) {
4479
			$channel_line = explode(",", $channel_line);
4480
			if(!isset($wireless_channels[$channel_line[0]]))
4481
				$wireless_channels[$channel_line[0]] = $channel_line;
4482
		}
4483
	}
4484
	return($wireless_channels);
4485
}
4486

    
4487
/****f* interfaces/get_interface_mtu
4488
 * NAME
4489
 *   get_interface_mtu - Return the mtu of an interface
4490
 * RESULT
4491
 *   $tmp       - Returns the mtu of an interface
4492
 ******/
4493
function get_interface_mtu($interface) {
4494
        $mtu = pfSense_get_interface_addresses($interface);
4495
        return $mtu['mtu'];
4496
}
4497

    
4498
function get_interface_mac($interface) {
4499

    
4500
	$macinfo = pfSense_get_interface_addresses($interface);
4501
	return $macinfo["macaddr"];
4502
}
4503

    
4504
/****f* pfsense-utils/generate_random_mac_address
4505
 * NAME
4506
 *   generate_random_mac - generates a random mac address
4507
 * INPUTS
4508
 *   none
4509
 * RESULT
4510
 *   $mac - a random mac address
4511
 ******/
4512
function generate_random_mac_address() {
4513
        $mac = "02";
4514
        for($x=0; $x<5; $x++)
4515
                $mac .= ":" . dechex(rand(16, 255));
4516
        return $mac;
4517
}
4518

    
4519
/****f* interfaces/is_jumbo_capable
4520
 * NAME
4521
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4522
 * INPUTS
4523
 *   $int             - string containing interface name
4524
 * RESULT
4525
 *   boolean          - true or false
4526
 ******/
4527
function is_jumbo_capable($iface) {
4528

    
4529

    
4530
	$iface = trim($iface);
4531
	$capable = pfSense_get_interface_addresses($iface);
4532
	if (isset($capable['caps']['vlanmtu']))
4533
                return true;
4534

    
4535

    
4536

    
4537

    
4538

    
4539
	return false;
4540
}
4541

    
4542
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4543
	global $g;
4544

    
4545
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4546

    
4547
	if(!empty($iface) && !empty($pppif)){
4548
		$cron_cmd = <<<EOD
4549
#!/bin/sh
4550
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4551
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4552

    
4553
EOD;
4554

    
4555
		@file_put_contents($cron_file, $cron_cmd);
4556
		chmod($cron_file, 0755);
4557
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4558
	} else
4559
		unlink_if_exists($cron_file);
4560
}
4561

    
4562
function get_interface_default_mtu($type = "ethernet") {
4563
	switch ($type) {
4564
	case "gre":
4565
		return 1476;
4566
		break;
4567
	case "gif":
4568
		return 1280;
4569
		break;
4570
	case "tun":
4571
	case "vlan":
4572
	case "tap":
4573
	case "ethernet":
4574
	default:
4575
		return 1500;
4576
		break;
4577
	}
4578

    
4579
	/* Never reached */
4580
	return 1500;
4581
}
4582

    
4583
function get_vip_descr($ipaddress) {
4584
	global $config;
4585

    
4586
	foreach ($config['virtualip']['vip'] as $vip) {
4587
		if ($vip['subnet'] == $ipaddress) {
4588
			return ($vip['descr']);
4589
		}
4590
	}
4591
	return "";
4592
}
4593

    
4594
function interfaces_staticarp_configure($if) {
4595
	global $config, $g;
4596
	if(isset($config['system']['developerspew'])) {
4597
		$mt = microtime();
4598
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4599
	}
4600

    
4601
	$ifcfg = $config['interfaces'][$if];
4602

    
4603
	if (empty($if) || empty($ifcfg['if']))
4604
		return 0;
4605

    
4606
	/* Enable staticarp, if enabled */
4607
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4608
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4609
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4610
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4611

    
4612
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4613
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4614

    
4615
			}
4616

    
4617
		}
4618
	} else {
4619
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4620
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4621
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4622
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4623
				if (isset($arpent['arp_table_static_entry'])) {
4624
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4625
				}
4626
			}
4627
		}
4628
	}
4629

    
4630
	return 0;
4631
}
4632

    
4633
function get_failover_interface($interface) {
4634
	global $config;
4635
	/* shortcut to get_real_interface if we find it in the config */
4636
	if(is_array($config['interfaces'][$interface])) {
4637
		$wanif = get_real_interface($interface);
4638
		return $wanif;
4639
	}
4640

    
4641
	/* compare against gateway groups */
4642
	$a_groups = return_gateway_groups_array();
4643
	if(is_array($a_groups[$interface])) {
4644
		/* we found a gateway group, fetch the interface or vip */
4645
		if($a_groups[$interface][0]['vip'] <> "")
4646
			$wanif = $a_groups[$interface][0]['vip'];
4647
		else
4648
			$wanif = $a_groups[$interface][0]['int'];
4649
		
4650
		return $wanif;
4651
	}
4652
	/* fall through to get_real_interface */
4653
	$wanif = get_real_interface($interface);
4654
	return $wanif;
4655
}
4656

    
4657
?>
(26-26/68)