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

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

    
852
	if ($g['booting'] || !(empty($gif['gifif']))) {
853
		pfSense_interface_destroy($gif['gifif']);
854
		pfSense_interface_create($gif['gifif']);
855
		$gifif = $gif['gifif'];
856
	} else
857
		$gifif = pfSense_interface_create("gif");
858

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

    
875
	$iflist = get_configured_interface_list();
876
	foreach($iflist as $ifname) {
877
		if($config['interfaces'][$ifname]['if'] == $gifif) {
878
			if(get_interface_gateway($ifname)) {
879
				system_routing_configure($ifname);
880
				break;
881
			}
882
			if(get_interface_gateway_v6($ifname)) {
883
				system_routing_configure($ifname);
884
				break;
885
			}
886
		}
887
	}
888

    
889

    
890
	if(is_ipaddrv4($gif['tunnel-remote-addr']))
891
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
892
	if(is_ipaddrv6($gif['tunnel-remote-addr']))
893
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
894

    
895
        if (is_ipaddrv4($realifgw)) {
896
                mwexec("route change -host {$gif['remote-addr']} {$realifgw}");
897
        }
898
        if (is_ipaddrv6($realifgw)) {
899
                mwexec("route change -host -inet6 {$gif['remote-addr']} {$realifgw}");
900
        }
901

    
902
	return $gifif;
903
}
904

    
905
function interfaces_configure() {
906
	global $config, $g;
907

    
908
	if ($g['platform'] == 'jail')
909
		return;
910

    
911
	/* Set up our loopback interface */
912
	interfaces_loopback_configure();
913

    
914
	/* set up LAGG virtual interfaces */
915
	interfaces_lagg_configure();
916

    
917
	/* set up VLAN virtual interfaces */
918
	interfaces_vlan_configure();
919

    
920
	interfaces_qinq_configure();
921

    
922
	$iflist = get_configured_interface_with_descr();
923
	$delayed_list = array();
924
	$bridge_list = array();
925
	
926
	/* This is needed to speedup interfaces on bootup. */
927
	$reload = false;
928
	if (!$g['booting'])
929
		$reload = true;
930

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

    
946
			if($g['debug'])
947
				log_error(sprintf(gettext("Configuring %s"), $ifname));
948
			interface_configure($if, $reload);
949
			if ($g['booting']) 
950
				echo gettext( "done.") . "\n";
951
		}
952
	}
953

    
954
	/* create the unconfigured wireless clones */
955
	interfaces_create_wireless_clones();
956

    
957
	/*
958
	 * NOTE: The following function parameter consists of
959
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
960
	 *	2 - Do load gre/gif/bridge with parent/member as vip
961
	 */
962

    
963
	/* set up GRE virtual interfaces */
964
	interfaces_gre_configure(1);
965

    
966
	/* set up GIF virtual interfaces */
967
	interfaces_gif_configure(1);
968

    
969
	/* set up BRIDGe virtual interfaces */
970
	interfaces_bridge_configure(1);
971

    
972
	/* bring up vip interfaces */
973
	interfaces_vips_configure();
974

    
975
	/* set up GRE virtual interfaces */
976
	interfaces_gre_configure(2);
977

    
978
	/* set up GIF virtual interfaces */
979
	interfaces_gif_configure(2);
980

    
981
	foreach ($delayed_list as $if => $ifname) {
982
		if ($g['booting'])
983
			printf(gettext("Configuring %s interface..."), $ifname);
984
        	if ($g['debug'])
985
        		log_error(sprintf(gettext("Configuring %s"), $ifname));
986

    
987
		interface_configure($if, $reload);
988

    
989
		if ($g['booting'])
990
			echo gettext("done.") . "\n";
991
	}
992

    
993
	/* set up BRIDGe virtual interfaces */
994
	interfaces_bridge_configure(2);
995

    
996
	foreach ($bridge_list as $if => $ifname) {
997
		if ($g['booting'])
998
			printf(gettext("Configuring %s interface..."), $ifname);
999
		if($g['debug'])
1000
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1001

    
1002
		interface_configure($if, $reload);
1003

    
1004
		if ($g['booting'])
1005
			echo gettext("done.") . "\n";
1006
	}
1007

    
1008
	/* configure interface groups */
1009
	interfaces_group_setup();
1010

    
1011
	if (!$g['booting']) {
1012
		/* reconfigure static routes (kernel may have deleted them) */
1013
		system_routing_configure();
1014

    
1015
		/* reload IPsec tunnels */
1016
		vpn_ipsec_configure();
1017

    
1018
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1019
		services_dhcpd_configure();
1020

    
1021
		/* restart dnsmasq */
1022
		services_dnsmasq_configure();
1023

    
1024
		/* reload captive portal */
1025
		if (function_exists('captiveportal_init_rules'))
1026
			captiveportal_init_rules();
1027
	}
1028

    
1029
	return 0;
1030
}
1031

    
1032
function interface_reconfigure($interface = "wan", $reloadall = false) {
1033
	interface_bring_down($interface);
1034
	interface_configure($interface, $reloadall);
1035
}
1036

    
1037
function interface_vip_bring_down($vip) {
1038
	global $g;
1039

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

    
1059
function interface_bring_down($interface = "wan", $destroy = false) {
1060
	global $config, $g;
1061

    
1062
	if (!isset($config['interfaces'][$interface]))
1063
		return; 
1064
	log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1065

    
1066
	$ifcfg = $config['interfaces'][$interface];
1067

    
1068
	$realif = get_real_interface($interface);
1069

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

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

    
1155
	if (file_exists("{$g['tmp_path']}/{$realif}_router"))
1156
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1157
//	log_error("Checking for old router states: {$g['tmp_path']}/{$realif}_router = {$old_router}");
1158
	if (!empty($old_router)) {
1159
		log_error("Clearing states to old gateway {$old_router}.");
1160
		mwexec("/sbin/pfctl -b 0.0.0.0/32 -b {$old_router}/32");
1161
	}
1162

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

    
1179
	if ($destroy == true) {
1180
		if (preg_match("/^[a-z0-9]+_vip|^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|^stf/i", $realif))
1181
			pfSense_interface_destroy($realif);
1182
	}	
1183

    
1184
	return;
1185
}
1186

    
1187
function interfaces_ptpid_used($ptpid) {
1188
	global $config;
1189

    
1190
	if (is_array($config['ppps']['ppp']))
1191
		foreach ($config['ppps']['ppp'] as & $settings)
1192
			if ($ptpid == $settings['ptpid'])
1193
				return true;
1194

    
1195
	return false;
1196
}
1197

    
1198
function interfaces_ptpid_next() {
1199

    
1200
	$ptpid = 0;
1201
	while(interfaces_ptpid_used($ptpid))
1202
		$ptpid++;
1203

    
1204
	return $ptpid;
1205
}
1206

    
1207
function getMPDCRONSettings($pppif) {
1208
	global $config;
1209

    
1210
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1211
	if (is_array($config['cron']['item'])) {
1212
		foreach ($config['cron']['item'] as $i => $item) {
1213
			if (stripos($item['command'], $cron_cmd_file) !== false)
1214
				return array("ID" => $i, "ITEM" => $item);
1215
		}
1216
	}
1217

    
1218
	return NULL;
1219
}
1220

    
1221
function handle_pppoe_reset($post_array) {
1222
	global $config, $g;
1223

    
1224
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1225
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1226

    
1227
	if (!is_array($config['cron']['item'])) 
1228
		$config['cron']['item'] = array(); 
1229

    
1230
	$itemhash = getMPDCRONSettings($pppif);
1231
	
1232
	// reset cron items if necessary and return
1233
	if (empty($post_array['pppoe-reset-type'])) {
1234
		if (isset($itemhash))
1235
			unset($config['cron']['item'][$itemhash['ID']]);
1236
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1237
		return;
1238
	}
1239

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

    
1299
/*
1300
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1301
 * It writes the mpd config file to /var/etc every time the link is opened.
1302
 */
1303
function interface_ppps_configure($interface) {
1304
	global $config, $g;
1305

    
1306
	/* Return for unassigned interfaces. This is a minimum requirement. */
1307
	if (empty($config['interfaces'][$interface]))
1308
		return 0;
1309
	$ifcfg = $config['interfaces'][$interface];
1310
	if (!isset($ifcfg['enable']))
1311
		return 0;
1312

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

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

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

    
1347
	$ports = explode(',',$ppp['ports']);
1348
	if ($type != "modem") {
1349
		foreach ($ports as $pid => $port)
1350
			$ports[$pid] = get_real_interface($port);
1351
	}
1352
	$localips = explode(',',$ppp['localip']);
1353
	$gateways = explode(',',$ppp['gateway']);
1354
	$subnets = explode(',',$ppp['subnet']);
1355

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

    
1420
		if (is_ipaddr($ppp['gateway']))
1421
			$gateway = $ppp['gateway'];
1422
		else
1423
			$gateway = "10.64.64.{$pppid}";
1424
		$ranges = "{$localip}/0 {$gateway}/0";
1425
		
1426
		if (empty($ppp['apnum']))	
1427
			$ppp['apnum'] = 1;
1428
	} else
1429
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1430

    
1431
	if (isset($ppp['ondemand'])) 
1432
		$ondemand = "enable";
1433
	else
1434
		$ondemand = "disable";
1435
	if (!isset($ppp['idletimeout']))
1436
		$ppp['idletimeout'] = 0;
1437

    
1438
	if (empty($ppp['username']) && $type == "modem"){
1439
		$ppp['username'] = "user";
1440
		$ppp['password'] = "none";
1441
	}
1442
	if (empty($ppp['password']) && $type == "modem")
1443
		$passwd = "none";
1444
	else
1445
		$passwd = base64_decode($ppp['password']);
1446

    
1447
	$bandwidths = explode(',',$ppp['bandwidth']);
1448
	$defaultmtu = "1492";
1449
	if (!empty($ifcfg['mtu']))
1450
		$defaultmtu = intval($ifcfg['mtu']);
1451
	$mtus = explode(',',$ppp['mtu']);
1452
	$mrus = explode(',',$ppp['mru']);
1453

    
1454
	if (isset($ppp['mrru']))
1455
		$mrrus = explode(',',$ppp['mrru']);
1456

    
1457
	// Construct the mpd.conf file
1458
	$mpdconf = <<<EOD
1459
startup:
1460
	# configure the console
1461
	set console close
1462
	# configure the web server
1463
	set web close
1464

    
1465
default:
1466
{$ppp['type']}client:
1467
	create bundle static {$interface}
1468
	set bundle enable ipv6cp
1469
	set iface name {$pppif}
1470

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

    
1491
EOD;
1492
	}
1493
	$mpdconf .= <<<EOD
1494
	set iface {$ondemand} on-demand
1495
	set iface idle {$ppp['idletimeout']}
1496

    
1497
EOD;
1498

    
1499
	if (isset($ppp['ondemand']))
1500
		$mpdconf .= <<<EOD
1501
	set iface addrs 10.10.1.1 10.10.1.2
1502

    
1503
EOD;
1504
	
1505
	if (isset($ppp['tcpmssfix']))
1506
		$tcpmss = "disable";
1507
	else
1508
		$tcpmss = "enable";
1509
		$mpdconf .= <<<EOD
1510
	set iface {$tcpmss} tcpmssfix
1511

    
1512
EOD;
1513

    
1514
	$mpdconf .= <<<EOD
1515
	set iface up-script /usr/local/sbin/ppp-linkup
1516
	set iface down-script /usr/local/sbin/ppp-linkdown
1517
	set ipcp ranges {$ranges}
1518

    
1519
EOD;
1520
	if (isset($ppp['vjcomp']))
1521
		$mpdconf .= <<<EOD
1522
	set ipcp no vjcomp
1523

    
1524
EOD;
1525

    
1526
	if (isset($config['system']['dnsallowoverride']))
1527
		$mpdconf .= <<<EOD
1528
	set ipcp enable req-pri-dns
1529
	set ipcp enable req-sec-dns
1530

    
1531
EOD;
1532
	if (!isset($ppp['verbose_log']))
1533
		$mpdconf .= <<<EOD
1534
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1535

    
1536
EOD;
1537
	foreach($ports as $pid => $port){
1538
		$port = get_real_interface($port);
1539
		$mpdconf .= <<<EOD
1540

    
1541
	create link static {$interface}_link{$pid} {$type}
1542
	set link action bundle {$interface}
1543
	set link {$multilink} multilink
1544
	set link keep-alive 10 60
1545
	set link max-redial 0
1546

    
1547
EOD;
1548
		if (isset($ppp['shortseq']))
1549
			$mpdconf .= <<<EOD
1550
	set link no shortseq
1551

    
1552
EOD;
1553

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

    
1558
EOD;
1559

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

    
1564
EOD;
1565

    
1566
		$mpdconf .= <<<EOD
1567
	set link disable chap pap
1568
	set link accept chap pap eap
1569
	set link disable incoming
1570

    
1571
EOD;
1572

    
1573

    
1574
		if (!empty($bandwidths[$pid]))
1575
			$mpdconf .= <<<EOD
1576
	set link bandwidth {$bandwidths[$pid]}
1577

    
1578
EOD;
1579

    
1580
		if (empty($mtus[$pid]))
1581
			$mtus[$pid] = $defaultmtu;
1582
			$mpdconf .= <<<EOD
1583
	set link mtu {$mtus[$pid]}
1584

    
1585
EOD;
1586

    
1587
		if (!empty($mrus[$pid]))
1588
			$mpdconf .= <<<EOD
1589
	set link mru {$mrus[$pid]}
1590

    
1591
EOD;
1592

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

    
1597
EOD;
1598

    
1599
		$mpdconf .= <<<EOD
1600
	set auth authname "{$ppp['username']}"
1601
	set auth password {$passwd}
1602

    
1603
EOD;
1604
		if ($type == "modem") {
1605
			$mpdconf .= <<<EOD
1606
	set modem device {$ppp['ports']}
1607
	set modem script DialPeer
1608
	set modem idle-script Ringback
1609
	set modem watch -cd
1610
	set modem var \$DialPrefix "DT"
1611
	set modem var \$Telephone "{$ppp['phone']}"
1612

    
1613
EOD;
1614
		}
1615
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1616
			$mpdconf .= <<<EOD
1617
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1618

    
1619
EOD;
1620
		}
1621
		if (isset($ppp['initstr']) && $type == "modem") {
1622
			$initstr = base64_decode($ppp['initstr']);
1623
			$mpdconf .= <<<EOD
1624
	set modem var \$InitString "{$initstr}"
1625

    
1626
EOD;
1627
		}
1628
		if (isset($ppp['simpin']) && $type == "modem") {
1629
			if($ppp['pin-wait'] == "")
1630
				$ppp['pin-wait'] = 0;
1631
			$mpdconf .= <<<EOD
1632
	set modem var \$SimPin "{$ppp['simpin']}"
1633
	set modem var \$PinWait "{$ppp['pin-wait']}"
1634

    
1635
EOD;
1636
		}
1637
		if (isset($ppp['apn']) && $type == "modem") {
1638
			$mpdconf .= <<<EOD
1639
	set modem var \$APN "{$ppp['apn']}"
1640
	set modem var \$APNum "{$ppp['apnum']}"
1641

    
1642
EOD;
1643
		}
1644
		if ($type == "pppoe") {
1645
			// Send a null service name if none is set.
1646
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1647
			$mpdconf .= <<<EOD
1648
	set pppoe service "{$provider}"
1649

    
1650
EOD;
1651
		}
1652
		if ($type == "pppoe")
1653
			$mpdconf .= <<<EOD
1654
	set pppoe iface {$port}
1655

    
1656
EOD;
1657

    
1658
		if ($type == "pptp" || $type == "l2tp") {
1659
			$mpdconf .= <<<EOD
1660
	set {$type} self {$localips[$pid]}
1661
	set {$type} peer {$gateways[$pid]}
1662

    
1663
EOD;
1664
		}
1665
		
1666
		$mpdconf .= "\topen\n";
1667
	} //end foreach($port)
1668

    
1669

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

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

    
1700
	/* clean up old lock files */
1701
	foreach($ports as $port) {
1702
		if(file_exists("{$g['var_path']}/spool/lock/LCK..{$port}"))
1703
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1704
	}
1705

    
1706
	/* fire up mpd */
1707
	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");
1708

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

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

    
1744
	return 1;
1745
}
1746

    
1747
function interfaces_carp_setup() {
1748
	global $g, $config;
1749

    
1750
	$balanacing = "";
1751
	$pfsyncinterface = "";
1752
	$pfsyncenabled = "";
1753
	if(isset($config['system']['developerspew'])) {
1754
		$mt = microtime();
1755
		echo "interfaces_carp_setup() being called $mt\n";
1756
	}
1757

    
1758
	// Prepare CmdCHAIN that will be used to execute commands.
1759
	$cmdchain = new CmdCHAIN();	
1760

    
1761
	if ($g['booting']) {
1762
		echo gettext("Configuring CARP settings...");
1763
		mute_kernel_msgs();
1764
	}
1765

    
1766
	/* suck in configuration items */
1767
	if($config['hasync']) {
1768
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
1769
		$balanacing = $config['hasync']['balancing'];
1770
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
1771
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
1772
	} else {
1773
		unset($pfsyncinterface);
1774
		unset($balanacing);
1775
		unset($pfsyncenabled);
1776
	}
1777

    
1778
	if($balanacing) {
1779
		$cmdchain->add(gettext("Enable CARP ARP-balancing"), "/sbin/sysctl net.inet.carp.arpbalance=1", true);
1780
		$cmdchain->add(gettext("Disallow CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=0", true);
1781
	} else
1782
		$cmdchain->add(gettext("Enable CARP preemption"), "/sbin/sysctl net.inet.carp.preempt=1", true);		
1783

    
1784
	$cmdchain->add(gettext("Enable CARP logging"), "/sbin/sysctl net.inet.carp.log=1", true);
1785
	if (!empty($pfsyncinterface))
1786
		$carp_sync_int = get_real_interface($pfsyncinterface);
1787

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

    
1803
	/* setup pfsync interface */
1804
	if($carp_sync_int and $pfsyncenabled) {
1805
		if (is_ipaddr($pfsyncpeerip))
1806
			$cmdchain->add(gettext("Bring up pfsync0 syncpeer"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} syncpeer {$pfsyncpeerip} up", false);						
1807
		else
1808
			$cmdchain->add(gettext("Bring up pfsync0 syncdev"), "/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} up", false);			
1809
	} else
1810
		$cmdchain->add(gettext("Bring up pfsync0"), "/sbin/ifconfig pfsync0 syncdev lo0 up", false);						
1811

    
1812
	sleep(1);
1813

    
1814
	/* 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
1815
	 * for existing sessions.
1816
	 */
1817
	if ($config['hasync']['pfsyncenabled'] === "on"){
1818
		log_error("waiting for pfsync...");
1819
		$i = 0;
1820
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
1821
			$i++;
1822
			sleep(1);
1823
		}
1824
		log_error("pfsync done in $i seconds.");
1825
		log_error("Configuring CARP settings finalize...");
1826
	}
1827

    
1828
	if($config['virtualip']['vip'])
1829
		$cmdchain->add(gettext("Allow CARP."), "/sbin/sysctl net.inet.carp.allow=1", true);				
1830
	else
1831
		$cmdchain->add(gettext("Disallow CARP."), "/sbin/sysctl net.inet.carp.allow=0", true);		
1832
	
1833
	if($g['debug'])
1834
		$cmdchain->setdebug(); // optional for verbose logging
1835

    
1836
	$cmdchain->execute();
1837
	$cmdchain->clear();
1838

    
1839
	if ($g['booting']) {
1840
		unmute_kernel_msgs();
1841
		echo gettext("done.") . "\n";
1842
	}
1843
}
1844

    
1845
function interface_proxyarp_configure($interface = "") {
1846
	global $config, $g;
1847
	if(isset($config['system']['developerspew'])) {
1848
		$mt = microtime();
1849
		echo "interface_proxyarp_configure() being called $mt\n";
1850
	}
1851

    
1852
	/* kill any running choparp */
1853
	if (empty($interface))
1854
		killbyname("choparp");
1855
	else {
1856
		$vipif = get_real_interface($interface);
1857
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid"))
1858
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1859
	}
1860

    
1861
	$paa = array();
1862
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
1863

    
1864
		/* group by interface */
1865
		foreach ($config['virtualip']['vip'] as $vipent) {
1866
			if ($vipent['mode'] === "proxyarp") {
1867
				if ($vipent['interface'])
1868
					$proxyif = $vipent['interface'];
1869
				else
1870
					$proxyif = "wan";
1871
				
1872
				if (!empty($interface) && $interface != $proxyif)
1873
					continue;
1874

    
1875
				if (!is_array($paa[$proxyif]))
1876
					$paa[$proxyif] = array();
1877

    
1878
				$paa[$proxyif][] = $vipent;
1879
			}
1880
		}
1881
	}
1882

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

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

    
1953
function interface_ipalias_configure(&$vip) {
1954
	if ($vip['mode'] == "ipalias") {
1955
		$if = get_real_interface($vip['interface']);
1956
		$af = "inet";
1957
		if(is_ipaddrv6($vip['subnet']))
1958
			$af = "inet6";
1959
		mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias");
1960
	}
1961
}
1962

    
1963
function interface_reload_carps($cif) {
1964
	global $config;
1965

    
1966
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
1967
	if (empty($carpifs))
1968
		return;
1969

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

    
1992
function interface_carp_configure(&$vip) {
1993
	global $config, $g;
1994
	if(isset($config['system']['developerspew'])) {
1995
		$mt = microtime();
1996
		echo "interface_carp_configure() being called $mt\n";
1997
	}
1998

    
1999
	if ($vip['mode'] != "carp")
2000
		return;
2001

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

    
2012
	if(is_ipaddrv4($vip['subnet'])) {
2013
		/* Ensure CARP IP really exists prior to loading up. */
2014
		$ww_subnet_ip = find_interface_ip($realif);
2015
		$ww_subnet_bits = find_interface_subnet($realif);
2016
		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'])) {
2017
			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", "");
2018
			return;
2019
		}
2020
	}
2021
	if(is_ipaddrv6($vip['subnet'])) {
2022
		/* Ensure CARP IP really exists prior to loading up. */
2023
		$ww_subnet_ip = find_interface_ipv6($realif);
2024
		$ww_subnet_bits = find_interface_subnetv6($realif);
2025
		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'])) {
2026
			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", "");
2027
			return;
2028
		}
2029
	}
2030

    
2031
	// set the vip interface to the vhid
2032
	$vipif = "{$vip['interface']}_vip{$vip['vhid']}";
2033

    
2034
	/* create the carp interface and setup */
2035
	if (does_interface_exist($vipif)) {
2036
		pfSense_interface_flags($vipif, -IFF_UP);
2037
	} else {
2038
		$carpif = pfSense_interface_create("carp");
2039
		pfSense_interface_rename($carpif, $vipif);
2040
		pfSense_ngctl_name("{$carpif}:", $vipif);
2041
	}
2042

    
2043
	/* invalidate interface cache */
2044
	get_interface_arr(true);
2045

    
2046
	$vip_password = $vip['password'];
2047
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2048
	if ($vip['password'] != "")
2049
		$password = " pass {$vip_password}";
2050

    
2051
	$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2052
	$advbase = "";
2053
	if (!empty($vip['advbase']))
2054
		$advbase = "advbase {$vip['advbase']}";
2055

    
2056
	if(is_ipaddrv4($vip['subnet'])) {
2057
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2058
		mwexec("/sbin/ifconfig {$vipif} {$vip['subnet']}/{$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2059
	}
2060
	if(is_ipaddrv6($vip['subnet'])) {
2061
		$broadcast_address = gen_subnet_max($vip['subnet'], $vip['subnet_bits']);
2062
		mwexec("/sbin/ifconfig {$vipif} inet6 {$vip['subnet']} prefixlen {$vip['subnet_bits']} vhid {$vip['vhid']} advskew {$vip['advskew']} {$advbase} {$password}");
2063
	}
2064

    
2065
	interfaces_bring_up($vipif);
2066

    
2067
	return $vipif;
2068
}
2069

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

    
2111
	if($needs_clone == true) {
2112
		/* remove previous instance if it exists */
2113
		if(does_interface_exist($realif))
2114
			pfSense_interface_destroy($realif);
2115

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

    
2134
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2135
	global $config, $g;
2136

    
2137
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2138
	                         'diversity', 'txantenna', 'rxantenna', 'distance',
2139
	                         'regdomain', 'regcountry', 'reglocation');
2140

    
2141
	if(!is_interface_wireless($ifcfg['if']))
2142
		return;
2143

    
2144
	$baseif = interface_get_wireless_base($ifcfg['if']);
2145

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

    
2170
	// Read or write settings at shared area
2171
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2172
		foreach ($shared_settings as $setting) {
2173
			if ($sync_changes) {
2174
				if (isset($ifcfg['wireless'][$setting]))
2175
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2176
				else if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2177
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2178
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2179
				if (isset($config['wireless']['interfaces'][$baseif][$setting]))
2180
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2181
				else if (isset($ifcfg['wireless'][$setting]))
2182
					unset($ifcfg['wireless'][$setting]);
2183
			}
2184
		}
2185
	}
2186

    
2187
	// Sync the mode on the clone creation page with the configured mode on the interface
2188
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2189
		foreach ($config['wireless']['clone'] as &$clone) {
2190
			if ($clone['cloneif'] == $ifcfg['if']) {
2191
				if ($sync_changes) {
2192
					$clone['mode'] = $ifcfg['wireless']['mode'];
2193
				} else {
2194
					$ifcfg['wireless']['mode'] = $clone['mode'];
2195
				}
2196
				break;
2197
			}
2198
		}
2199
		unset($clone);
2200
	}
2201
}
2202

    
2203
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2204
	global $config, $g;
2205

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

    
2213
	// Remove script file
2214
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2215

    
2216
	// Clone wireless nic if needed.
2217
	interface_wireless_clone($if, $wl);
2218

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

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

    
2226
	/* set values for /path/program */
2227
	$hostapd = "/usr/sbin/hostapd";
2228
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2229
	$ifconfig = "/sbin/ifconfig";
2230
	$sysctl = "/sbin/sysctl";
2231
	$killall = "/usr/bin/killall";
2232

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

    
2235
	$wlcmd = array();
2236
	$wl_sysctl = array();
2237
	/* Make sure it's up */
2238
	$wlcmd[] = "up";
2239
	/* Set a/b/g standard */
2240
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2241
	$wlcmd[] = "mode " . escapeshellarg($standard);
2242

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

    
2248
	/* Set ssid */
2249
	if($wlcfg['ssid'])
2250
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2251

    
2252
	/* Set 802.11g protection mode */
2253
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2254

    
2255
	/* set wireless channel value */
2256
	if(isset($wlcfg['channel'])) {
2257
		if($wlcfg['channel'] == "0") {
2258
			$wlcmd[] = "channel any";
2259
		} else {
2260
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2261
		}
2262
	}
2263

    
2264
	/* Set antenna diversity value */
2265
	if(isset($wlcfg['diversity']))
2266
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2267

    
2268
	/* Set txantenna value */
2269
	if(isset($wlcfg['txantenna']))
2270
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2271

    
2272
	/* Set rxantenna value */
2273
	if(isset($wlcfg['rxantenna']))
2274
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2275

    
2276
	/* set Distance value */
2277
	if($wlcfg['distance'])
2278
		$distance = escapeshellarg($wlcfg['distance']);
2279

    
2280
	/* Set wireless hostap mode */
2281
	if ($wlcfg['mode'] == "hostap") {
2282
		$wlcmd[] = "mediaopt hostap";
2283
	} else {
2284
		$wlcmd[] = "-mediaopt hostap";
2285
	}
2286

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

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

    
2296
	/* handle hide ssid option */
2297
	if(isset($wlcfg['hidessid']['enable'])) {
2298
		$wlcmd[] = "hidessid";
2299
	} else {
2300
		$wlcmd[] = "-hidessid";
2301
	}
2302

    
2303
	/* handle pureg (802.11g) only option */
2304
	if(isset($wlcfg['pureg']['enable'])) {
2305
		$wlcmd[] = "mode 11g pureg";
2306
	} else {
2307
		$wlcmd[] = "-pureg";
2308
	}
2309

    
2310
	/* handle puren (802.11n) only option */
2311
	if(isset($wlcfg['puren']['enable'])) {
2312
		$wlcmd[] = "puren";
2313
	} else {
2314
		$wlcmd[] = "-puren";
2315
	}
2316

    
2317
	/* enable apbridge option */
2318
	if(isset($wlcfg['apbridge']['enable'])) {
2319
		$wlcmd[] = "apbridge";
2320
	} else {
2321
		$wlcmd[] = "-apbridge";
2322
	}
2323

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

    
2331
	/* handle txpower setting */
2332
	/* if($wlcfg['txpower'] <> "")
2333
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2334
	*/
2335
	/* handle wme option */
2336
	if(isset($wlcfg['wme']['enable'])) {
2337
		$wlcmd[] = "wme";
2338
	} else {
2339
		$wlcmd[] = "-wme";
2340
	}
2341

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

    
2368
	mwexec(kill_hostapd("{$if}"));
2369
	mwexec(kill_wpasupplicant("{$if}"));
2370

    
2371
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2372
	conf_mount_rw();
2373

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

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

    
2428
EOD;
2429

    
2430
if (isset($wlcfg['wpa']['rsn_preauth'])) {
2431
	$wpa .= <<<EOD
2432
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2433
rsn_preauth=1
2434
rsn_preauth_interfaces={$if}
2435

    
2436
EOD;
2437

    
2438
}
2439
				if($wlcfg['auth_server_addr'] && $wlcfg['auth_server_shared_secret']) {
2440
					$auth_server_port = "1812";
2441
					if($wlcfg['auth_server_port']) 
2442
						$auth_server_port = $wlcfg['auth_server_port'];
2443
					$auth_server_port2 = "1812";
2444
					if($wlcfg['auth_server_port2']) 
2445
						$auth_server_port2 = $wlcfg['auth_server_port2'];
2446
					$wpa .= <<<EOD
2447

    
2448
ieee8021x=1
2449
auth_server_addr={$wlcfg['auth_server_addr']}
2450
auth_server_port={$auth_server_port}
2451
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2452
auth_server_addr={$wlcfg['auth_server_addr2']}
2453
auth_server_port={$auth_server_port2}
2454
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2455

    
2456
EOD;
2457
				} else {
2458
					$wpa .= "ieee8021x={$wlcfg['wpa']['ieee8021x']}\n";
2459
				}
2460

    
2461
				$fd = fopen("{$g['varetc_path']}/hostapd_{$if}.conf", "w");
2462
				fwrite($fd, "{$wpa}");
2463
				fclose($fd);
2464

    
2465
			}
2466
			break;
2467
	}
2468

    
2469
	/*
2470
	 *    all variables are set, lets start up everything
2471
	 */
2472

    
2473
	$baseif = interface_get_wireless_base($if);
2474
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2475
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2476

    
2477
	/* set sysctls for the wireless interface */
2478
	if (!empty($wl_sysctl)) {
2479
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2480
		foreach ($wl_sysctl as $wl_sysctl_line) {
2481
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2482
		}
2483
	}
2484

    
2485
	/* set ack timers according to users preference (if he/she has any) */
2486
	if($distance) {
2487
		fwrite($fd_set, "# Enable ATH distance settings\n");
2488
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2489
	}
2490

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

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

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

    
2519
	fclose($fd_set);
2520
	conf_mount_ro();
2521

    
2522
	/* Making sure regulatory settings have actually changed
2523
	 * before applying, because changing them requires bringing
2524
	 * down all wireless networks on the interface. */
2525
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2526
	$ifconfig_str = implode($output);
2527
	unset($output);
2528
	$reg_changing = false;
2529

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

    
2542
	if ($reg_changing) {
2543
		/* set regulatory domain */
2544
		if($wlcfg['regdomain'])
2545
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2546

    
2547
		/* set country */
2548
		if($wlcfg['regcountry'])
2549
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2550

    
2551
		/* set location */
2552
		if($wlcfg['reglocation'])
2553
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2554

    
2555
		$wlregcmd_args = implode(" ", $wlregcmd);
2556

    
2557
		/* build a complete list of the wireless clones for this interface */
2558
		$clone_list = array();
2559
		if (does_interface_exist(interface_get_wireless_clone($baseif)))
2560
			$clone_list[] = interface_get_wireless_clone($baseif);
2561
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2562
			foreach ($config['wireless']['clone'] as $clone) {
2563
				if ($clone['if'] == $baseif)
2564
					$clone_list[] = $clone['cloneif'];
2565
			}
2566
		}
2567

    
2568
		/* find which clones are up and bring them down */
2569
		$clones_up = array();
2570
		foreach ($clone_list as $clone_if) {
2571
			$clone_status = pfSense_get_interface_addresses($clone_if);
2572
			if ($clone_status['status'] == 'up') {
2573
				$clones_up[] = $clone_if;
2574
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2575
			}
2576
		}
2577

    
2578
		/* apply the regulatory settings */
2579
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2580

    
2581
		/* bring the clones back up that were previously up */
2582
		foreach ($clones_up as $clone_if) {
2583
			mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " up");
2584

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

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

    
2605
	/* configure wireless */
2606
	$wlcmd_args = implode(" ", $wlcmd);
2607
	mwexec("/sbin/ifconfig {$if} $wlcmd_args", false);
2608

    
2609
	
2610
	sleep(1);
2611
	/* execute hostapd and wpa_supplicant if required in shell */
2612
	mwexec("/bin/sh {$g['tmp_path']}/{$if}_setup.sh");
2613

    
2614
	return 0;
2615

    
2616
}
2617

    
2618
function kill_hostapd($interface) {
2619
	return "/bin/pkill -f \"hostapd .*{$interface}\"\n";
2620
}
2621

    
2622
function kill_wpasupplicant($interface) {
2623
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\"\n";
2624
}
2625

    
2626
function find_dhclient_process($interface) {
2627
	if ($interface)
2628
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2629
	else
2630
		$pid = 0;
2631

    
2632
	return intval($pid);
2633
}
2634

    
2635
function find_dhcp6c_process($interface) {
2636
	if ($interface)
2637
		$pid = `/bin/ps auxww|grep "[d]hclient[ ]-6" |grep "{$interface}"|awk '{print $2}'`;
2638
	else
2639
		return(false);
2640

    
2641
	return intval($pid);
2642
}
2643

    
2644
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
2645
	global $config, $g;
2646
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
2647
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
2648

    
2649
	$wancfg = $config['interfaces'][$interface];
2650

    
2651
	$realif = get_real_interface($interface);
2652
	$realhwif_array = get_parent_interface($interface);
2653
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
2654
	$realhwif = $realhwif_array[0];
2655

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

    
2665
		/* only bring down the interface when both v4 and v6 are set to NONE */
2666
		if(($wancfg['ipaddr'] <> "none") && ($wancfg['ipaddrv6'] <> "none")) {
2667
			interface_bring_down($interface);
2668
		}
2669
	}
2670

    
2671
	/* wireless configuration? */
2672
	if (is_array($wancfg['wireless']))
2673
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
2674

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

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

    
2697
		if ($mac == "ff:ff:ff:ff:ff:ff") {
2698
			/*   this is not a valid mac address.  generate a
2699
			 *   temporary mac address so the machine can get online.
2700
			 */
2701
			echo gettext("Generating new MAC address.");
2702
			$random_mac = generate_random_mac_address();
2703
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
2704
				" link " . escapeshellarg($random_mac));
2705
			$wancfg['spoofmac'] = $random_mac;
2706
			write_config();
2707
			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");
2708
		}
2709
	}
2710

    
2711
	/* media */
2712
	if ($wancfg['media'] || $wancfg['mediaopt']) {
2713
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
2714
		if ($wancfg['media'])
2715
			$cmd .= " media " . escapeshellarg($wancfg['media']);
2716
		if ($wancfg['mediaopt'])
2717
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
2718
		mwexec($cmd);
2719
	}
2720
	if (!empty($wancfg['mtu']))
2721
		pfSense_interface_mtu($realhwif, $wancfg['mtu']);
2722
	else {
2723
		$mtu = get_interface_default_mtu(remove_numbers($realhwif));
2724
		if ($mtu != get_interface_mtu($realhwif))
2725
			pfSense_interface_mtu($realhwif, $mtu);
2726
	}
2727

    
2728
	$options = pfSense_get_interface_addresses($realhwif);
2729
	if (is_array($options) && isset($options['caps']['polling'])) {
2730
		if (isset($config['system']['polling']))
2731
			pfSense_interface_capabilities($realif, IFCAP_POLLING);
2732
		else
2733
			pfSense_interface_capabilities($realif, -IFCAP_POLLING);
2734
	}
2735

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

    
2751
        	if(isset($config['system']['disablesegmentationoffloading'])) {
2752
                	if (isset($options['encaps']['tso4']))
2753
				$flags |= IFCAP_TSO;
2754
                	if (isset($options['encaps']['tso6']))
2755
				$flags |= IFCAP_TSO;
2756
        	} else {
2757
                	if (!isset($options['caps']['tso4']))
2758
				$flags |= IFCAP_TSO;
2759
                	if (!isset($options['caps']['tso6']))
2760
				$flags |= IFCAP_TSO;
2761
        	}
2762

    
2763
        	if(isset($config['system']['disablelargereceiveoffloading'])) {
2764
                	if (isset($options['encaps']['lro']))
2765
				$flags |= IFCAP_LRO;
2766
        	} else {
2767
                	if (!isset($options['caps']['lro']))
2768
				$flags |= IFCAP_LRO;
2769
        	}
2770

    
2771
        	/* if the NIC supports polling *AND* it is enabled in the GUI */
2772
        	if (!isset($config['system']['polling']) || !isset($options['caps']['polling'])) {
2773
			$flags |= IFCAP_POLLING;
2774
		}
2775
               	pfSense_interface_capabilities($realhwif, -$flags);
2776
	}
2777

    
2778
	/* invalidate interface/ip/sn cache */
2779
	get_interface_arr(true);
2780
	unset($interface_ip_arr_cache[$realif]);
2781
	unset($interface_sn_arr_cache[$realif]);
2782
	unset($interface_ipv6_arr_cache[$realif]);
2783
	unset($interface_snv6_arr_cache[$realif]);
2784

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

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

    
2839
	if(does_interface_exist($wancfg['if']))
2840
		interfaces_bring_up($wancfg['if']);
2841

    
2842
	interface_netgraph_needed($interface);
2843
 	
2844
	if (!$g['booting']) {
2845
		link_interface_to_vips($interface, "update");
2846

    
2847
		unset($gre);
2848
		$gre = link_interface_to_gre($interface);
2849
		if (!empty($gre))
2850
			array_walk($gre, 'interface_gre_configure');
2851

    
2852
		unset($gif);
2853
		$gif = link_interface_to_gif($interface);
2854
		if (!empty($gif))
2855
			array_walk($gif, 'interface_gif_configure');
2856

    
2857
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
2858
			unset($bridgetmp);
2859
			$bridgetmp = link_interface_to_bridge($interface);
2860
			if (!empty($bridgetmp))
2861
				interface_bridge_add_member($bridgetmp, $realif);
2862
		}
2863

    
2864
		$grouptmp = link_interface_to_group($interface);
2865
		if (!empty($grouptmp))
2866
			array_walk($grouptmp, 'interface_group_add_member');
2867

    
2868
		if ($interface == "lan")
2869
			/* make new hosts file */
2870
			system_hosts_generate();
2871

    
2872
		if ($reloadall == true) {
2873

    
2874
			/* reconfigure static routes (kernel may have deleted them) */
2875
			system_routing_configure($interface);
2876

    
2877
			/* reload ipsec tunnels */
2878
			vpn_ipsec_configure();
2879

    
2880
			/* restart dnsmasq */
2881
			services_dnsmasq_configure();
2882

    
2883
			/* update dyndns */
2884
			send_event("service reload dyndns {$interface}");
2885

    
2886
			/* reload captive portal */
2887
			captiveportal_init_rules();
2888
		}
2889
	}
2890

    
2891
	return 0;
2892
}
2893

    
2894
function interface_track6_configure($interface = "lan") {
2895
	global $config, $g;
2896
	$iflist = get_configured_interface_with_descr(false, true);
2897

    
2898
	$wancfg = $config['interfaces'][$interface];
2899
	$wanif = $wancfg['if'];
2900
	if (empty($wancfg))
2901
		$wancfg = array();
2902

    
2903
	$wanif = get_real_interface($interface);
2904
	
2905
	/* If the interface is not configured via another, exit */
2906
	if(!$wancfg['track6-interface'] <> "") {
2907
		return(false);
2908
	}
2909

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

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

    
2935

    
2936
function interface_track6_6rd_configure($interface = "lan") {
2937
	global $config, $g;
2938
	$iflist = get_configured_interface_with_descr(false, true);
2939

    
2940
	$lancfg = $config['interfaces'][$interface];
2941
	$lanif = $lancfg['if'];
2942
	if (empty($lancfg))
2943
		$lancfg = array();
2944

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

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

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

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

    
2995
function interface_track6_6to4_configure($interface = "lan") {
2996
	global $config, $g;
2997
	$iflist = get_configured_interface_with_descr(false, true);
2998

    
2999
	$lancfg = $config['interfaces'][$interface];
3000
	$lanif = $lancfg['if'];
3001
	if (empty($lancfg))
3002
		$lancfg = array();
3003

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

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

    
3050
function interface_track6_dhcp6_configure($interface = "lan") {
3051
	global $config, $g;
3052
	$iflist = get_configured_interface_with_descr(false, true);
3053

    
3054
	$lancfg = $config['interfaces'][$interface];
3055
	$lanif = $lancfg['if'];
3056
	if (empty($lancfg))
3057
		$lancfg = array();
3058

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

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

    
3101
function interface_6rd_configure($interface = "wan") {
3102
	global $config, $g;
3103
	$iflist = get_configured_interface_with_descr(false, true);
3104

    
3105
	/* because this is a tunnel interface we can only function 
3106
	 *	with a public IPv4 address on the interface */
3107

    
3108
	$wancfg = $config['interfaces'][$interface];
3109
	$wanif = $wancfg['if'];
3110
	if (empty($wancfg))
3111
		$wancfg = array();
3112

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

    
3126
	/* create the long prefix notation for math, save the prefix length */
3127
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3128
	$rd6prefixlen = $rd6prefix[1];
3129
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3130

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

    
3144
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3145
	$rd6brgw = convert_128bit_to_ipv6($rd6brprefixbin);
3146

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

    
3154
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3155
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3156

    
3157
	/* stf approach only works when embedding the entire 32 bits of the v4 */
3158
	mwexec("/sbin/ifconfig stf0 create");
3159
	mwexec("/sbin/ifconfig stf0 inet6 {$rd6prefix}/{$rd6prefixlen}");
3160
	log_error("Created 6rd interface stf0 {$rd6prefix}/{$rd6prefixlen}");
3161

    
3162
	/* write out a default router file */
3163
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3164
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3165

    
3166
	if (is_ipaddrv4($ip4gateway))
3167
		mwexec("route change -host " . $wancfg['gateway-6rd'] . " {$ip4gateway}");
3168

    
3169
	/* configure dependent interfaces */
3170
	foreach($iflist as $if => $ifname) {
3171
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3172
			interface_track6_configure($if);
3173
	}
3174

    
3175
	return 0;
3176
}
3177

    
3178
function interface_6to4_configure($interface = "wan"){
3179
	global $config, $g;
3180
	$iflist = get_configured_interface_with_descr(false, true);
3181

    
3182
	/* because this is a tunnel interface we can only function 
3183
	 *	with a public IPv4 address on the interface */
3184

    
3185
	$wancfg = $config['interfaces'][$interface];
3186
	$wanif = $wancfg['if'];
3187
	if (empty($wancfg))
3188
		$wancfg = array();
3189

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

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

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

    
3229
	/* for the local subnet too. */
3230
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3231
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);;
3232

    
3233
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3234
	$stfbrarr = array();
3235
	$stfbrbinarr = array();
3236
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3237
	foreach($stfbrbinarr as $bin)
3238
		$stfbrarr[] = dechex(bindec($bin));
3239
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3240

    
3241
	/* convert the 128 bits for the broker address back into a valid IPv6 address */ 
3242
	$stflanarr = array();
3243
	$stflanbinarr = array();
3244
	$stflanbinarr = str_split($stflanbin, 16);
3245
	foreach($stflanbinarr as $bin)
3246
		$stflanarr[] = dechex(bindec($bin));
3247
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3248
	$stflanarr[7] = 1;
3249
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3250

    
3251
	/* setup the stf interface */
3252
	mwexec("/sbin/ifconfig stf0 destroy");
3253
	mwexec("/sbin/ifconfig stf0 create");
3254
	mwexec("/sbin/ifconfig stf0 inet6 {$stflanpr} prefixlen 16");
3255

    
3256
	log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for stf0, route {$stfbrgw}");
3257
	
3258
	/* write out a default router file */
3259
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3260
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3261

    
3262
	if (is_ipaddrv4($ip4gateway)) {
3263
		mwexec("route change -host 192.88.99.1 {$ip4gateway}");
3264
	}
3265

    
3266
	/* configure dependent interfaces */
3267
	foreach($iflist as $if => $ifname) {
3268
		if($config['interfaces'][$if]['track6-interface'] == $interface)
3269
			interface_track6_configure($if);
3270
	}
3271
	
3272
	return 0;
3273
}
3274

    
3275
function interface_dhcpv6_configure($interface = "wan") {
3276
	global $config, $g;
3277
	$iflist = get_configured_interface_with_descr(false, true);
3278

    
3279
	$wancfg = $config['interfaces'][$interface];
3280
	$wanif = $wancfg['if'];
3281
	if (empty($wancfg))
3282
		$wancfg = array();
3283

    
3284
	$wanif = get_real_interface($interface);
3285

    
3286
	/* Add ISC IPv6 dhclient here */
3287
	$fd = fopen("{$g['varetc_path']}/dhcp6c_{$interface}.conf", "w");
3288
	if (!$fd) {
3289
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3290
		return 1;
3291
	}
3292

    
3293
	$dhcp6cconf = "interface \"{$wanif}\" {\n";
3294
	$dhcp6cconf .= "script \"/sbin/dhclient6-script\";\n";
3295
	$dhcp6cconf .= "}\n";
3296

    
3297
	fwrite($fd, $dhcp6cconf);
3298
	fclose($fd);
3299

    
3300
	/* accept router advertisements for this interface */
3301
	mwexec("/sbin/sysctl -w net.inet6.ip6.accept_rtadv=1");
3302
	log_error("Accept router advertisements on interface {$wanif} ");
3303
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3304

    
3305
	/* run a filter configure so that the filter rules allow traffic before we launch the client */
3306
	filter_configure_sync();
3307
	sleep(3);
3308

    
3309
	/* dhclient -6
3310
	 * -T temprorary address
3311
	 * -S information only
3312
	 * -P Prefix
3313
	 * -N request address with temporary or prefix
3314
	*/
3315

    
3316
	$dhcp6c_options = "";
3317
	if($wancfg['ipaddrv6'] == "slaac") {
3318
		$dhcp6c_options .= "-S ";
3319
	}
3320
	if($wancfg['ipaddrv6'] == "dhcp6") {
3321
		$dhcp6c_options .= "-N ";
3322
	}
3323
	if(is_numeric($wancfg['dhcp6-ia-pd-len'])) {
3324
		$dhcp6c_options .= "-P ";		
3325
	}
3326
	/* fire up dhcp6c for IPv6 first, this backgrounds immediately */
3327
	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}");
3328
	sleep(5);
3329
	return 0;
3330
}
3331

    
3332
function interface_dhcp_configure($interface = "wan") {
3333
	global $config, $g;
3334

    
3335
	$wancfg = $config['interfaces'][$interface];
3336
	$wanif = $wancfg['if'];
3337
	if (empty($wancfg))
3338
		$wancfg = array();
3339

    
3340
	/* generate dhclient_wan.conf */
3341
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
3342
	if (!$fd) {
3343
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
3344
		return 1;
3345
	}
3346

    
3347
	if ($wancfg['dhcphostname']) {
3348
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
3349
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
3350
	} else {
3351
		$dhclientconf_hostname = "";
3352
	}
3353

    
3354
	$wanif = get_real_interface($interface);
3355
	if (empty($wanif)) {
3356
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
3357
		return 0;
3358
	}
3359
 	$dhclientconf = "";
3360
	
3361
	$dhclientconf .= <<<EOD
3362
interface "{$wanif}" {
3363
timeout 60;
3364
retry 15;
3365
select-timeout 0;
3366
initial-interval 1;
3367
	{$dhclientconf_hostname}
3368
	script "/sbin/dhclient-script";
3369
}
3370

    
3371
EOD;
3372

    
3373
if(is_ipaddr($wancfg['alias-address'])) {
3374
	$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
3375
	$dhclientconf .= <<<EOD
3376
alias {
3377
	interface  "{$wanif}";
3378
	fixed-address {$wancfg['alias-address']};
3379
	option subnet-mask {$subnetmask};
3380
}
3381

    
3382
EOD;
3383
}
3384
	fwrite($fd, $dhclientconf);
3385
	fclose($fd);
3386

    
3387
	/* bring wan interface up before starting dhclient */
3388
	if($wanif)
3389
		interfaces_bring_up($wanif);
3390
	else 
3391
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
3392

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

    
3396
	return 0;
3397
}
3398

    
3399
function interfaces_group_setup() {
3400
	global $config;
3401

    
3402
	if (!is_array($config['ifgroups']['ifgroupentry']))
3403
		return;
3404

    
3405
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar)
3406
		interface_group_setup($groupar);
3407

    
3408
	return;
3409
}
3410

    
3411
function interface_group_setup(&$groupname /* The parameter is an array */) {
3412
	global $config;
3413

    
3414
	if (!is_array($groupname))
3415
		return;
3416
	$members = explode(" ", $groupname['members']);
3417
	foreach($members as $ifs) {
3418
		$realif = get_real_interface($ifs);
3419
		if ($realif)
3420
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
3421
	}
3422

    
3423
	return;
3424
}
3425

    
3426
function interface_group_add_member($interface, $groupname) {
3427
	$interface = get_real_interface($interface);
3428
	mwexec("/sbin/ifconfig {$interface} group {$groupname}", true);
3429
}
3430
 
3431
/* COMPAT Function */
3432
function convert_friendly_interface_to_real_interface_name($interface) {
3433
	return get_real_interface($interface);
3434
}
3435

    
3436
/* COMPAT Function */
3437
function get_real_wan_interface($interface = "wan") {
3438
	return get_real_interface($interface);
3439
}
3440

    
3441
/* COMPAT Function */
3442
function get_current_wan_address($interface = "wan") {
3443
	return get_interface_ip($interface);
3444
}
3445

    
3446
/*
3447
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
3448
 */
3449
function convert_real_interface_to_friendly_interface_name($interface = "wan") {
3450
        global $config;
3451

    
3452
	if (stristr($interface, "_vip")) {
3453
                foreach ($config['virtualip']['vip'] as $counter => $vip) {
3454
                        if ($vip['mode'] == "carp")  {
3455
                                if ($interface == "{$vip['interface']}_vip{$vip['vhid']}")
3456
                                        return $vip['interface'];
3457
                        }
3458
                }
3459
        }
3460

    
3461
        /* XXX: For speed reasons reference directly the interface array */
3462
	$ifdescrs = &$config['interfaces'];
3463
        //$ifdescrs = get_configured_interface_list(false, true);
3464

    
3465
        foreach ($ifdescrs as $if => $ifname) {
3466
                if ($config['interfaces'][$if]['if'] == $interface)
3467
                        return $if;
3468

    
3469
                if (stristr($interface, "_wlan0") && $config['interfaces'][$if]['if'] == interface_get_wireless_base($interface))
3470
                        return $if;
3471

    
3472
		// XXX: This case doesn't work anymore (segfaults - recursion?) - should be replaced with something else or just removed.
3473
		//      Not to be replaced with get_real_interface - causes slow interface listings here because of recursion!
3474
		/*
3475
                $int = get_parent_interface($if);
3476
                if ($int[0] == $interface)
3477
                        return $ifname;
3478
		*/
3479
        }
3480
        return NULL;
3481
}
3482

    
3483
/* attempt to resolve interface to friendly descr */
3484
function convert_friendly_interface_to_friendly_descr($interface) {
3485
        global $config;
3486

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

    
3531
        return $ifdesc;
3532
}
3533

    
3534
function convert_real_interface_to_friendly_descr($interface) {
3535
        global $config;
3536

    
3537
        $ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
3538

    
3539
        if ($ifdesc) {
3540
                $iflist = get_configured_interface_with_descr(false, true);
3541
                return $iflist[$ifdesc];
3542
        }
3543

    
3544
        return $interface;
3545
}
3546

    
3547
/*
3548
 *  get_parent_interface($interface):
3549
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
3550
 *				or virtual interface (i.e. vlan)
3551
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
3552
 *			-- returns $interface passed in if $interface parent is not found
3553
 *			-- returns empty array if an invalid interface is passed
3554
 *	(Only handles ppps and vlans now.)
3555
 */
3556
function get_parent_interface($interface) {
3557
	global $config;
3558

    
3559
	$parents = array();
3560
	//Check that we got a valid interface passed
3561
	$realif = get_real_interface($interface);
3562
	if ($realif == NULL)
3563
		return $parents;
3564

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

    
3607
function interface_is_wireless_clone($wlif) {
3608
	if(!stristr($wlif, "_wlan")) {
3609
		return false;
3610
	} else {
3611
		return true;
3612
	}
3613
}
3614

    
3615
function interface_get_wireless_base($wlif) {
3616
	if(!stristr($wlif, "_wlan")) {
3617
		return $wlif;
3618
	} else {
3619
		return substr($wlif, 0, stripos($wlif, "_wlan"));
3620
	}
3621
}
3622

    
3623
function interface_get_wireless_clone($wlif) {
3624
	if(!stristr($wlif, "_wlan")) {
3625
		return $wlif . "_wlan0";
3626
	} else {
3627
		return $wlif;
3628
	}
3629
}
3630

    
3631
function get_real_interface($interface = "wan") {
3632
    global $config;
3633

    
3634
	$wanif = NULL;
3635

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

    
3666
		if (empty($config['interfaces'][$interface]))
3667
			break;
3668

    
3669
		$cfg = &$config['interfaces'][$interface];
3670

    
3671
		// Wireless cloned NIC support (FreeBSD 8+)
3672
		// interface name format: $parentnic_wlanparentnic#
3673
		// example: ath0_wlan0
3674
		if (is_interface_wireless($cfg['if'])) {
3675
			$wanif = interface_get_wireless_clone($cfg['if']);
3676
			break;
3677
		}
3678
		/*
3679
		if (empty($cfg['if'])) {
3680
			$wancfg = $cfg['if'];
3681
			break;
3682
		}
3683
		*/
3684

    
3685
		switch ($cfg['ipaddr']) {
3686
			case "pppoe": 
3687
			case "pptp": 
3688
			case "l2tp": 
3689
			case "ppp":
3690
				$wanif = $cfg['if'];
3691
				break;
3692
			default:
3693
				$wanif = $cfg['if'];
3694
				break;
3695
		}
3696
		break;
3697
	}
3698

    
3699
    return $wanif;
3700
}
3701

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

    
3739
/*
3740
 * find_ip_interface($ip): return the interface where an ip is defined
3741
 *   (or if $bits is specified, where an IP within the subnet is defined)
3742
 */
3743
function find_ip_interface($ip, $bits = null)
3744
{
3745
	/* if list */
3746
	$ifdescrs = get_configured_interface_list();
3747
		
3748
	foreach ($ifdescrs as $ifdescr => $ifname) {
3749
		if ($bits === null) {
3750
			if ($ip == get_interface_ip($ifname)) {
3751
				$int = get_real_interface($ifname);
3752
				return $int;
3753
			}
3754
		}
3755
		else {
3756
			if (ip_in_subnet(get_interface_ip($ifname), $ip . "/" . $bits)) {
3757
				$int = get_real_interface($ifname);
3758
				return $int;
3759
			}
3760
		}
3761
	}
3762
	return false;
3763
}
3764

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

    
3791
/*
3792
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
3793
 */
3794
function find_number_of_created_carp_interfaces() {
3795
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
3796
}
3797

    
3798
function get_all_carp_interfaces() {
3799
	$ints = str_replace("\n", " ", `ifconfig | grep "carp:" -B2 | grep ": flag" | cut -d: -f1`);
3800
	$ints = explode(" ", $ints);
3801
	return $ints;
3802
}
3803

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

    
3829
				if ($if)
3830
					return $if;
3831
			}
3832
		}
3833
	}
3834
}
3835

    
3836
function link_carp_interface_to_parent($interface) {
3837
	global $config;
3838

    
3839
	if ($interface == "")
3840
		return;
3841

    
3842
	$carp_ip = get_interface_ip($interface);
3843
	$carp_ipv6 = get_interface_ipv6($interface);
3844

    
3845
	if((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6)))
3846
		return;
3847

    
3848
	/* if list */
3849
	$ifdescrs = get_configured_interface_list();
3850
	foreach ($ifdescrs as $ifdescr => $ifname) {
3851
		/* check IPv4 */
3852
		if(is_ipaddrv4($carp_ip)) {
3853
			$interfaceip = get_interface_ip($ifname);
3854
			$subnet_bits = get_interface_subnet($ifname);
3855
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
3856
			if(ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}"))
3857
				return $ifname;
3858
		}
3859
		/* Check IPv6 */
3860
		if(is_ipaddrv6($carp_ipv6)) {
3861
			$interfaceipv6 = get_interface_ipv6($ifname);
3862
			$prefixlen = get_interface_subnetv6($ifname);
3863
			if(ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}"))
3864
				return $ifname;
3865
		}
3866
	}
3867
	return "";
3868
}
3869

    
3870

    
3871
/****f* interfaces/link_ip_to_carp_interface
3872
 * NAME
3873
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
3874
 * INPUTS
3875
 *   $ip
3876
 * RESULT
3877
 *   $carp_ints
3878
 ******/
3879
function link_ip_to_carp_interface($ip) {
3880
        global $config;
3881

    
3882
        if (!is_ipaddr($ip))
3883
                return;
3884

    
3885
        $carp_ints = "";
3886
        if (is_array($config['virtualip']['vip'])) {
3887
		$first = 0;
3888
		$carp_int = array();
3889
                foreach ($config['virtualip']['vip'] as $vip) {
3890
                        if ($vip['mode'] == "carp") {
3891
                                $carp_ip = $vip['subnet'];
3892
                                $carp_sn = $vip['subnet_bits'];
3893
                                $carp_nw = gen_subnet($carp_ip, $carp_sn);
3894
                                if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
3895
					$carp_int[] = "{$vip['interface']}_vip{$vip['vhid']}";
3896
				}
3897
                        }
3898
                }
3899
		if (!empty($carp_int))
3900
			$carp_ints = implode(" ", array_unique($carp_int));
3901
        }
3902

    
3903
        return $carp_ints;
3904
}
3905

    
3906
function link_interface_to_vlans($int, $action = "") {
3907
	global $config;
3908

    
3909
	if (empty($int))
3910
		return;
3911

    
3912
	if (is_array($config['vlans']['vlan'])) {
3913
                foreach ($config['vlans']['vlan'] as $vlan) {
3914
			if ($int == $vlan['if']) {
3915
				if ($action == "update") {
3916
					interfaces_bring_up($int);
3917
				} else if ($action == "")
3918
					return $vlan;
3919
			}
3920
		}
3921
	}
3922
}
3923

    
3924
function link_interface_to_vips($int, $action = "") {
3925
        global $config;
3926

    
3927
        if (is_array($config['virtualip']['vip'])) {
3928
		foreach ($config['virtualip']['vip'] as $vip) {
3929
			if ($int == $vip['interface']) {
3930
				if ($action == "update")
3931
					interfaces_vips_configure($int);
3932
				else
3933
					return $vip;
3934
			}
3935
		}
3936
	}
3937
}
3938

    
3939
/****f* interfaces/link_interface_to_bridge
3940
 * NAME
3941
 *   link_interface_to_bridge - Finds out a bridge group for an interface
3942
 * INPUTS
3943
 *   $ip
3944
 * RESULT
3945
 *   bridge[0-99]
3946
 ******/
3947
function link_interface_to_bridge($int) {
3948
        global $config;
3949

    
3950
        if (is_array($config['bridges']['bridged'])) {
3951
                foreach ($config['bridges']['bridged'] as $bridge) {
3952
			if (in_array($int, explode(',', $bridge['members'])))
3953
                                return "{$bridge['bridgeif']}";
3954
		}
3955
	}
3956
}
3957

    
3958
function link_interface_to_group($int) {
3959
        global $config;
3960

    
3961
	$result = array();
3962

    
3963
        if (is_array($config['ifgroups']['ifgroupentry'])) {
3964
                foreach ($config['ifgroups']['ifgroupentry'] as $group) {
3965
			if (in_array($int, explode(" ", $group['members'])))
3966
				$result[$group['ifname']] = $int;
3967
		}
3968
	}
3969

    
3970
	return $result;
3971
}
3972

    
3973
function link_interface_to_gre($interface) {
3974
        global $config;
3975

    
3976
	$result = array();
3977

    
3978
        if (is_array($config['gres']['gre'])) {
3979
                foreach ($config['gres']['gre'] as $gre)
3980
                        if($gre['if'] == $interface)
3981
				$result[] = $gre;
3982
	}
3983

    
3984
	return $result;
3985
}
3986

    
3987
function link_interface_to_gif($interface) {
3988
        global $config;
3989

    
3990
	$result = array();
3991

    
3992
        if (is_array($config['gifs']['gif'])) {
3993
                foreach ($config['gifs']['gif'] as $gif)
3994
                        if($gif['if'] == $interface)
3995
                                $result[] = $gif;
3996
	}
3997

    
3998
	return $result;
3999
}
4000

    
4001
/*
4002
 * find_interface_ip($interface): return the interface ip (first found)
4003
 */
4004
function find_interface_ip($interface, $flush = false)
4005
{
4006
	global $interface_ip_arr_cache;
4007
	global $interface_sn_arr_cache;
4008

    
4009
	$interface = str_replace("\n", "", $interface);
4010
	
4011
	if (!does_interface_exist($interface))
4012
		return;
4013

    
4014
	/* Setup IP cache */
4015
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
4016
		$ifinfo = pfSense_get_interface_addresses($interface);
4017
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4018
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4019
	}
4020

    
4021
	return $interface_ip_arr_cache[$interface];
4022
}
4023

    
4024
/*
4025
 * find_interface_ipv6($interface): return the interface ip (first found)
4026
 */
4027
function find_interface_ipv6($interface, $flush = false)
4028
{
4029
	global $interface_ipv6_arr_cache;
4030
	global $interface_snv6_arr_cache;
4031
	global $config;
4032
	
4033
	$interface = trim($interface);
4034
	$interface = get_real_interface($interface);
4035
	
4036
	if (!does_interface_exist($interface))
4037
		return;
4038

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

    
4062
	return $interface_ipv6_arr_cache[$interface];
4063
}
4064

    
4065
/*
4066
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
4067
 */
4068
function find_interface_ipv6_ll($interface, $flush = false)
4069
{
4070
	global $interface_llv6_arr_cache;
4071
	global $config;
4072
	
4073
	$interface = str_replace("\n", "", $interface);
4074
	
4075
	if (!does_interface_exist($interface))
4076
		return;
4077

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

    
4097
function find_interface_subnet($interface, $flush = false)
4098
{
4099
	global $interface_sn_arr_cache;
4100
	global $interface_ip_arr_cache;
4101

    
4102
	$interface = str_replace("\n", "", $interface);
4103
	if (does_interface_exist($interface) == false)
4104
		return;
4105

    
4106
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
4107
		$ifinfo = pfSense_get_interface_addresses($interface);
4108
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
4109
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
4110
        }
4111

    
4112
	return $interface_sn_arr_cache[$interface];
4113
}
4114

    
4115
function find_interface_subnetv6($interface, $flush = false)
4116
{
4117
	global $interface_snv6_arr_cache;
4118
	global $interface_ipv6_arr_cache;
4119

    
4120
	$interface = str_replace("\n", "", $interface);
4121
	if (does_interface_exist($interface) == false)
4122
		return;
4123

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

    
4146
	return $interface_snv6_arr_cache[$interface];
4147
}
4148

    
4149
function ip_in_interface_alias_subnet($interface, $ipalias) {
4150
	global $config;
4151

    
4152
	if (empty($interface) || !is_ipaddr($ipalias))
4153
		return false;
4154
	if (is_array($config['virtualip']['vip'])) {
4155
                foreach ($config['virtualip']['vip'] as $vip) {
4156
                        switch ($vip['mode']) {
4157
                        case "ipalias":
4158
                                if ($vip['interface'] <> $interface)
4159
                                        break;
4160
				if (ip_in_subnet($ipalias, gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits']))
4161
					return true;
4162
                                break;
4163
                        }
4164
                }
4165
	}
4166

    
4167
	return false;
4168
}
4169

    
4170
function get_interface_ip($interface = "wan")
4171
{
4172
	$realif = get_failover_interface($interface);
4173
	if (!$realif) {
4174
		if (preg_match("/^carp/i", $interface))
4175
			$realif = $interface;
4176
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4177
			$realif = $interface;
4178
		else
4179
			return null;
4180
	}
4181

    
4182
	$curip = find_interface_ip($realif);
4183
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0"))
4184
		return $curip;
4185
	else
4186
		return null;
4187
}
4188

    
4189
function get_interface_ipv6($interface = "wan")
4190
{
4191
	global $config;
4192
	$realif = get_failover_interface($interface);
4193
	switch($config['interfaces'][$interface]['ipaddrv6']) {
4194
		case "6rd":
4195
		case "6to4":
4196
			$realif = "stf0";
4197
			break;
4198
	}
4199
	if (!$realif) {
4200
		if (preg_match("/^carp/i", $interface))
4201
			$realif = $interface;
4202
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4203
			$realif = $interface;
4204
		else
4205
			return null;
4206
	}
4207

    
4208
	$curip = find_interface_ipv6($realif);
4209
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4210
		return $curip;
4211
	else
4212
		return null;
4213
}
4214

    
4215
function get_interface_linklocal($interface = "wan")
4216
{
4217
	$realif = get_failover_interface($interface);
4218
	if (!$realif) {
4219
		if (preg_match("/^carp/i", $interface))
4220
			$realif = $interface;
4221
		else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4222
			$realif = $interface;
4223
		else
4224
			return null;
4225
	}
4226

    
4227
	$curip = find_interface_ipv6_ll($realif);
4228
	if ($curip && is_ipaddrv6($curip) && ($curip != "::"))
4229
		return $curip;
4230
	else
4231
		return null;
4232
}
4233

    
4234
function get_interface_subnet($interface = "wan")
4235
{
4236
	$realif = get_real_interface($interface);
4237
	if (!$realif) {
4238
                if (preg_match("/^carp/i", $interface))
4239
                        $realif = $interface;
4240
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4241
                        $realif = $interface;
4242
                else
4243
                        return null;
4244
        }
4245

    
4246
	$cursn = find_interface_subnet($realif);
4247
	if (!empty($cursn))
4248
		return $cursn;
4249

    
4250
	return null;
4251
}
4252

    
4253
function get_interface_subnetv6($interface = "wan")
4254
{
4255
	$realif = get_real_interface($interface);
4256
	if (!$realif) {
4257
                if (preg_match("/^carp/i", $interface))
4258
                        $realif = $interface;
4259
                else if (preg_match("/^[a-z0-9]+_vip/i", $interface))
4260
                        $realif = $interface;
4261
                else
4262
                        return null;
4263
        }
4264

    
4265
	$cursn = find_interface_subnetv6($realif);
4266
	if (!empty($cursn))
4267
		return $cursn;
4268

    
4269
	return null;
4270
}
4271

    
4272
/* return outside interfaces with a gateway */
4273
function get_interfaces_with_gateway() {
4274
	global $config;
4275

    
4276
	$ints = array();
4277

    
4278
	/* loop interfaces, check config for outbound */
4279
	foreach($config['interfaces'] as $ifdescr => $ifname) {
4280
		switch ($ifname['ipaddr']) {
4281
			case "dhcp":
4282
			case "ppp";
4283
			case "pppoe":
4284
			case "pptp":
4285
			case "l2tp":
4286
			case "ppp";
4287
				$ints[$ifdescr] = $ifdescr;
4288
			break;
4289
			default:
4290
				if (substr($ifname['if'], 0, 5) ==  "ovpnc" ||
4291
				    !empty($ifname['gateway']))
4292
					$ints[$ifdescr] = $ifdescr;
4293
			break;
4294
		}
4295
	}
4296
	return $ints;
4297
}
4298

    
4299
/* return true if interface has a gateway */
4300
function interface_has_gateway($friendly) {
4301
	global $config;
4302

    
4303
	if (!empty($config['interfaces'][$friendly])) {
4304
		$ifname = &$config['interfaces'][$friendly];
4305
		switch ($ifname['ipaddr']) {
4306
			case "dhcp":
4307
			case "pppoe":
4308
			case "pptp":
4309
			case "l2tp":
4310
			case "ppp";
4311
				return true;
4312
			break;
4313
			default:
4314
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
4315
					return true;
4316
				if (!empty($ifname['gateway']))
4317
					return true;
4318
			break;
4319
		}
4320
	}
4321

    
4322
	return false;
4323
}
4324

    
4325
/* return true if interface has a gateway */
4326
function interface_has_gatewayv6($friendly) {
4327
	global $config;
4328

    
4329
	if (!empty($config['interfaces'][$friendly])) {
4330
		$ifname = &$config['interfaces'][$friendly];
4331
		switch ($ifname['ipaddrv6']) {
4332
			case "slaac":
4333
			case "dhcp6":
4334
				return true;
4335
				break;
4336
			case "6to4":
4337
				return true;
4338
				break;
4339
			case "6rd":
4340
				return true;
4341
				break;
4342
			default:
4343
				if (substr($ifname['if'], 0, 5) ==  "ovpnc")
4344
					return true;
4345
				if (!empty($ifname['gatewayv6']))
4346
					return true;
4347
				break;
4348
		}
4349
	}
4350

    
4351
	return false;
4352
}
4353

    
4354
/****f* interfaces/is_altq_capable
4355
 * NAME
4356
 *   is_altq_capable - Test if interface is capable of using ALTQ
4357
 * INPUTS
4358
 *   $int            - string containing interface name
4359
 * RESULT
4360
 *   boolean         - true or false
4361
 ******/
4362

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

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

    
4378
        if (in_array($int_family[0], $capable))
4379
                return true;
4380
	else if (stristr($int, "l2tp")) /* VLANs are name $parent_$vlan now */
4381
		return true;
4382
	else if (stristr($int, "vlan")) /* VLANs are name $parent_$vlan now */
4383
		return true;
4384
	else if (stristr($int, "_wlan")) /* WLANs are name $parent_$wlan now */
4385
		return true;
4386
        else
4387
                return false;
4388
}
4389

    
4390
/****f* interfaces/is_interface_wireless
4391
 * NAME
4392
 *   is_interface_wireless - Returns if an interface is wireless
4393
 * RESULT
4394
 *   $tmp       - Returns if an interface is wireless
4395
 ******/
4396
function is_interface_wireless($interface) {
4397
        global $config, $g;
4398

    
4399
        $friendly = convert_real_interface_to_friendly_interface_name($interface);
4400
        if(!isset($config['interfaces'][$friendly]['wireless'])) {
4401
                if (preg_match($g['wireless_regex'], $interface)) {
4402
                        if (isset($config['interfaces'][$friendly]))
4403
                                $config['interfaces'][$friendly]['wireless'] = array();
4404
                        return true;
4405
                }
4406
                return false;
4407
        } else
4408
                return true;
4409
}
4410

    
4411
function get_wireless_modes($interface) {
4412
	/* return wireless modes and channels */
4413
	$wireless_modes = array();
4414

    
4415
	$cloned_interface = get_real_interface($interface);
4416

    
4417
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4418
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
4419
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4420
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
4421

    
4422
		$interface_channels = "";
4423
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4424
		$interface_channel_count = count($interface_channels);
4425

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

    
4456
/* return channel numbers, frequency, max txpower, and max regulation txpower */
4457
function get_wireless_channel_info($interface) {
4458
	$wireless_channels = array();
4459

    
4460
	$cloned_interface = get_real_interface($interface);
4461

    
4462
	if($cloned_interface && is_interface_wireless($cloned_interface)) {
4463
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
4464
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
4465
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
4466

    
4467
		$interface_channels = "";
4468
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
4469

    
4470
		foreach ($interface_channels as $channel_line) {
4471
			$channel_line = explode(",", $channel_line);
4472
			if(!isset($wireless_channels[$channel_line[0]]))
4473
				$wireless_channels[$channel_line[0]] = $channel_line;
4474
		}
4475
	}
4476
	return($wireless_channels);
4477
}
4478

    
4479
/****f* interfaces/get_interface_mtu
4480
 * NAME
4481
 *   get_interface_mtu - Return the mtu of an interface
4482
 * RESULT
4483
 *   $tmp       - Returns the mtu of an interface
4484
 ******/
4485
function get_interface_mtu($interface) {
4486
        $mtu = pfSense_get_interface_addresses($interface);
4487
        return $mtu['mtu'];
4488
}
4489

    
4490
function get_interface_mac($interface) {
4491

    
4492
	$macinfo = pfSense_get_interface_addresses($interface);
4493
	return $macinfo["macaddr"];
4494
}
4495

    
4496
/****f* pfsense-utils/generate_random_mac_address
4497
 * NAME
4498
 *   generate_random_mac - generates a random mac address
4499
 * INPUTS
4500
 *   none
4501
 * RESULT
4502
 *   $mac - a random mac address
4503
 ******/
4504
function generate_random_mac_address() {
4505
        $mac = "02";
4506
        for($x=0; $x<5; $x++)
4507
                $mac .= ":" . dechex(rand(16, 255));
4508
        return $mac;
4509
}
4510

    
4511
/****f* interfaces/is_jumbo_capable
4512
 * NAME
4513
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
4514
 * INPUTS
4515
 *   $int             - string containing interface name
4516
 * RESULT
4517
 *   boolean          - true or false
4518
 ******/
4519
function is_jumbo_capable($iface) {
4520

    
4521

    
4522
	$iface = trim($iface);
4523
	$capable = pfSense_get_interface_addresses($iface);
4524
	if (isset($capable['caps']['vlanmtu']))
4525
                return true;
4526

    
4527

    
4528

    
4529

    
4530

    
4531
	return false;
4532
}
4533

    
4534
function interface_setup_pppoe_reset_file($pppif, $iface="") {
4535
	global $g;
4536

    
4537
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
4538

    
4539
	if(!empty($iface) && !empty($pppif)){
4540
		$cron_cmd = <<<EOD
4541
#!/bin/sh
4542
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
4543
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
4544

    
4545
EOD;
4546

    
4547
		@file_put_contents($cron_file, $cron_cmd);
4548
		chmod($cron_file, 0755);
4549
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
4550
	} else
4551
		unlink_if_exists($cron_file);
4552
}
4553

    
4554
function get_interface_default_mtu($type = "ethernet") {
4555
	switch ($type) {
4556
	case "gre":
4557
		return 1476;
4558
		break;
4559
	case "gif":
4560
		return 1280;
4561
		break;
4562
	case "tun":
4563
	case "vlan":
4564
	case "tap":
4565
	case "ethernet":
4566
	default:
4567
		return 1500;
4568
		break;
4569
	}
4570

    
4571
	/* Never reached */
4572
	return 1500;
4573
}
4574

    
4575
function get_vip_descr($ipaddress) {
4576
	global $config;
4577

    
4578
	foreach ($config['virtualip']['vip'] as $vip) {
4579
		if ($vip['subnet'] == $ipaddress) {
4580
			return ($vip['descr']);
4581
		}
4582
	}
4583
	return "";
4584
}
4585

    
4586
function interfaces_staticarp_configure($if) {
4587
	global $config, $g;
4588
	if(isset($config['system']['developerspew'])) {
4589
		$mt = microtime();
4590
		echo "interfaces_staticarp_configure($if) being called $mt\n";
4591
	}
4592

    
4593
	$ifcfg = $config['interfaces'][$if];
4594

    
4595
	if (empty($if) || empty($ifcfg['if']))
4596
		return 0;
4597

    
4598
	/* Enable staticarp, if enabled */
4599
	if(isset($config['dhcpd'][$if]['staticarp'])) {
4600
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp " );
4601
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4602
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4603

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

    
4607
			}
4608

    
4609
		}
4610
	} else {
4611
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp " );
4612
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
4613
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
4614
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
4615
				if (isset($arpent['arp_table_static_entry'])) {
4616
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
4617
				}
4618
			}
4619
		}
4620
	}
4621

    
4622
	return 0;
4623
}
4624

    
4625
function get_failover_interface($interface) {
4626
	global $config;
4627
	/* shortcut to get_real_interface if we find it in the config */
4628
	if(is_array($config['interfaces'][$interface])) {
4629
		$wanif = get_real_interface($interface);
4630
		return $wanif;
4631
	}
4632

    
4633
	/* compare against gateway groups */
4634
	$a_groups = return_gateway_groups_array();
4635
	if(is_array($a_groups[$interface])) {
4636
		/* we found a gateway group, fetch the interface or vip */
4637
		if($a_groups[$interface][0]['vip'] <> "")
4638
			$wanif = $a_groups[$interface][0]['vip'];
4639
		else
4640
			$wanif = $a_groups[$interface][0]['int'];
4641
		
4642
		return $wanif;
4643
	}
4644
	/* fall through to get_real_interface */
4645
	$wanif = get_real_interface($interface);
4646
	return $wanif;
4647
}
4648

    
4649
?>
(26-26/68)