Project

General

Profile

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

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

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

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

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

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

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

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

    
42
*/
43

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

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

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

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

    
69
	return $interface_arr_cache;
70
}
71

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

    
79
	if (!$interface) {
80
		return false;
81
	}
82

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

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

    
98
	if (!$vip) {
99
		return false;
100
	}
101

    
102

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

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

    
125
	return false;
126
}
127

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

    
131
	$found = false;
132
	if (!empty($config['l2tp']) &&
133
	    $config['l2tp']['mode'] == "server") {
134
		$found = true;
135
	}
136
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
137
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
138
			if ($pppoe['mode'] != "server") {
139
				continue;
140
			}
141
			if ($pppoe['interface'] == $interface) {
142
				$found = true;
143
				break;
144
			}
145
		}
146
	}
147
	if ($found == false) {
148
		$found = interface_isppp_type($interface);
149
	}
150

    
151
	if ($found == false) {
152
		$realif = get_real_interface($interface);
153
		if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
154
			foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
155
				$ports = explode(',', $ppp['ports']);
156
				foreach ($ports as $pid => $port) {
157
					$port = get_real_interface($port);
158
					if ($realif == $port) {
159
						$found = true;
160
						break;
161
					}
162
					/* Find the parent interfaces of the vlans in the MLPPP configs
163
					* there should be only one element in the array here
164
					* -- this could be better . . . */
165
					$parent_if = get_parent_interface($port);
166
					if ($realif == $parent_if[0]) {
167
						$found = true;
168
						break;
169
					}
170
				}
171
			}
172
		}
173
	}
174

    
175
	if ($found == false) {
176
		$realif = get_real_interface($interface);
177
		pfSense_ngctl_detach("{$realif}:", $realif);
178
	}
179
	/* NOTE: We make sure for this on interface_ppps_configure()
180
	 *	no need to do it here again.
181
	 *	else
182
	 *		pfSense_ngctl_attach(".", $realif);
183
	 */
184
}
185

    
186
function interfaces_loopback_configure() {
187
	global $g;
188

    
189
	if (platform_booting()) {
190
		echo gettext("Configuring loopback interface...");
191
	}
192
	pfSense_interface_setaddress("lo0", "127.0.0.1");
193
	interfaces_bring_up("lo0");
194
	if (platform_booting()) {
195
		echo gettext("done.") . "\n";
196
	}
197
	return 0;
198
}
199

    
200
function interfaces_vlan_configure($realif = "") {
201
	global $config, $g;
202
	if (platform_booting()) {
203
		echo gettext("Configuring VLAN interfaces...");
204
	}
205
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
206
		foreach ($config['vlans']['vlan'] as $vlan) {
207
			if (empty($vlan['vlanif'])) {
208
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
209
			}
210
			if (!empty($realif) && $realif != $vlan['vlanif']) {
211
				continue;
212
			}
213

    
214
			/* XXX: Maybe we should report any errors?! */
215
			interface_vlan_configure($vlan);
216
		}
217
	}
218
	if (platform_booting()) {
219
		echo gettext("done.") . "\n";
220
	}
221
}
222

    
223
function interface_vlan_configure(&$vlan) {
224
	global $config, $g;
225

    
226
	if (!is_array($vlan)) {
227
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
228
		return;
229
	}
230
	$if = $vlan['if'];
231
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
232
	$tag = $vlan['tag'];
233

    
234
	if (empty($if)) {
235
		log_error(gettext("interface_vlan_configure called with if undefined."));
236
		return;
237
	}
238

    
239
	/* make sure the parent interface is up */
240
	interfaces_bring_up($if);
241
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
242
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
243

    
244
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
245
		interface_bring_down($vlanif, true);
246
	} else {
247
		$tmpvlanif = pfSense_interface_create("vlan");
248
		pfSense_interface_rename($tmpvlanif, $vlanif);
249
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
250
	}
251

    
252
	pfSense_vlan_create($vlanif, $if, $tag);
253

    
254
	interfaces_bring_up($vlanif);
255

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

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

    
262
	return $vlanif;
263
}
264

    
265
function interface_qinq_configure(&$vlan, $fd = NULL) {
266
	global $config, $g;
267

    
268
	if (!is_array($vlan)) {
269
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
270
		return;
271
	}
272

    
273
	$qinqif = $vlan['if'];
274
	$tag = $vlan['tag'];
275
	if (empty($qinqif)) {
276
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
277
		return;
278
	}
279

    
280
	if (!does_interface_exist($qinqif)) {
281
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
282
		return;
283
	}
284

    
285
	$vlanif = interface_vlan_configure($vlan);
286

    
287
	if ($fd == NULL) {
288
		$exec = true;
289
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
290
	} else {
291
		$exec = false;
292
	}
293
	/* make sure the parent is converted to ng_vlan(4) and is up */
294
	interfaces_bring_up($qinqif);
295

    
296
	pfSense_ngctl_attach(".", $qinqif);
297
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
298
		fwrite($fd, "shutdown {$qinqif}qinq:\n");
299
		exec("/usr/sbin/ngctl msg {$qinqif}qinq: gettable", $result);
300
		if (empty($result)) {
301
			fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
302
			fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
303
			fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
304
		}
305
	} else {
306
		fwrite($fd, "mkpeer {$qinqif}: vlan lower downstream\n");
307
		fwrite($fd, "name {$qinqif}:lower {$vlanif}qinq\n");
308
		fwrite($fd, "connect {$qinqif}: {$vlanif}qinq: upper nomatch\n");
309
	}
310

    
311
	/* invalidate interface cache */
312
	get_interface_arr(true);
313

    
314
	if (!stristr($qinqif, "_vlan")) {
315
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
316
	}
317

    
318
	$macaddr = get_interface_mac($qinqif);
319
	if (!empty($vlan['members'])) {
320
		$members = explode(" ", $vlan['members']);
321
		foreach ($members as $qtag) {
322
			$qinq = array();
323
			$qinq['tag'] = $qtag;
324
			$qinq['if'] = $vlanif;
325
			interface_qinq2_configure($qinq, $fd, $macaddr);
326
		}
327
	}
328
	if ($exec == true) {
329
		fclose($fd);
330
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd");
331
	}
332

    
333
	interfaces_bring_up($qinqif);
334
	if (!empty($vlan['members'])) {
335
		$members = explode(" ", $vlan['members']);
336
		foreach ($members as $qif) {
337
			interfaces_bring_up("{$vlanif}_{$qif}");
338
		}
339
	}
340

    
341
	return $vlanif;
342
}
343

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

    
360
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
361
	global $config, $g;
362

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

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

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

    
383
	/* invalidate interface cache */
384
	get_interface_arr(true);
385

    
386
	return $vlanif;
387
}
388

    
389
function interfaces_create_wireless_clones() {
390
	global $config, $g;
391

    
392
	if (platform_booting()) {
393
		echo gettext("Creating wireless clone interfaces...");
394
	}
395

    
396
	$iflist = get_configured_interface_list();
397

    
398
	foreach ($iflist as $if) {
399
		$realif = $config['interfaces'][$if]['if'];
400
		if (is_interface_wireless($realif)) {
401
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
402
		}
403
	}
404

    
405
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
406
		foreach ($config['wireless']['clone'] as $clone) {
407
			if (empty($clone['cloneif'])) {
408
				continue;
409
			}
410
			if (does_interface_exist($clone['cloneif'])) {
411
				continue;
412
			}
413
			/* XXX: Maybe we should report any errors?! */
414
			interface_wireless_clone($clone['cloneif'], $clone);
415
		}
416
	}
417
	if (platform_booting()) {
418
		echo gettext("done.") . "\n";
419
	}
420

    
421
}
422

    
423
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
424
	global $config;
425

    
426
	$i = 0;
427
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
428
		foreach ($config['bridges']['bridged'] as $bridge) {
429
			if (empty($bridge['bridgeif'])) {
430
				$bridge['bridgeif'] = "bridge{$i}";
431
			}
432
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
433
				continue;
434
			}
435

    
436
			if ($checkmember == 1) {
437
				/* XXX: It should not be possible no? */
438
				if (strstr($bridge['if'], '_vip')) {
439
					continue;
440
				}
441
				$members = explode(',', $bridge['members']);
442
				foreach ($members as $member) {
443
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
444
						continue 2;
445
					}
446
				}
447
			}
448
			else if ($checkmember == 2) {
449
				$members = explode(',', $bridge['members']);
450
				foreach ($members as $member) {
451
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
452
						continue 2;
453
					}
454
				}
455
			}
456
			/* XXX: Maybe we should report any errors?! */
457
			interface_bridge_configure($bridge, $checkmember);
458
			$i++;
459
		}
460
	}
461
}
462

    
463
function interface_bridge_configure(&$bridge, $checkmember = 0) {
464
	global $config, $g;
465

    
466
	if (!is_array($bridge)) {
467
		return;
468
	}
469

    
470
	if (empty($bridge['members'])) {
471
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
472
		return;
473
	}
474

    
475
	$members = explode(',', $bridge['members']);
476
	if (!count($members)) {
477
		return;
478
	}
479

    
480
	/* Calculate smaller mtu and enforce it */
481
	$smallermtu = 0;
482
	$commonrx = true;
483
	$commontx = true;
484
	$foundgif = false;
485
	foreach ($members as $member) {
486
		$realif = get_real_interface($member);
487
		$mtu = get_interface_mtu($realif);
488
		if (substr($realif, 0, 3) == "gif") {
489
			$foundgif = true;
490
			if ($checkmember == 1) {
491
				return;
492
			}
493
			if ($mtu <= 1500) {
494
				continue;
495
			}
496
		}
497
		if ($smallermtu == 0 && !empty($mtu)) {
498
			$smallermtu = $mtu;
499
		} else if (!empty($mtu) && $mtu < $smallermtu) {
500
			$smallermtu = $mtu;
501
		}
502
	}
503
	if ($foundgif == false && $checkmember == 2) {
504
		return;
505
	}
506

    
507
	/* Just in case anything is not working well */
508
	if ($smallermtu == 0) {
509
		$smallermtu = 1500;
510
	}
511

    
512
	if (platform_booting() || !empty($bridge['bridgeif'])) {
513
		pfSense_interface_destroy($bridge['bridgeif']);
514
		pfSense_interface_create($bridge['bridgeif']);
515
		$bridgeif = escapeshellarg($bridge['bridgeif']);
516
	} else {
517
		$bridgeif = pfSense_interface_create("bridge");
518
		$bridge['bridgeif'] = $bridgeif;
519
	}
520

    
521
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
522
	if ($bridgemtu > $smallermtu) {
523
		$smallermtu = $bridgemtu;
524
	}
525

    
526
	$checklist = get_configured_interface_list();
527

    
528
	/* Add interfaces to bridge */
529
	foreach ($members as $member) {
530
		if (empty($checklist[$member])) {
531
			continue;
532
		}
533
		$realif = get_real_interface($member);
534
		if (!$realif) {
535
			log_error(gettext("realif not defined in interfaces bridge - up"));
536
			continue;
537
		}
538
		/* make sure the parent interface is up */
539
		pfSense_interface_mtu($realif, $smallermtu);
540
		interfaces_bring_up($realif);
541
		enable_hardware_offloading($member);
542
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
543
	}
544

    
545
	if (isset($bridge['enablestp'])) {
546
		/* Choose spanning tree proto */
547
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
548

    
549
		if (!empty($bridge['stp'])) {
550
			$stpifs = explode(',', $bridge['stp']);
551
			foreach ($stpifs as $stpif) {
552
				$realif = get_real_interface($stpif);
553
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
554
			}
555
		}
556
		if (!empty($bridge['maxage'])) {
557
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
558
		}
559
		if (!empty($bridge['fwdelay'])) {
560
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
561
		}
562
		if (!empty($bridge['hellotime'])) {
563
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
564
		}
565
		if (!empty($bridge['priority'])) {
566
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
567
		}
568
		if (!empty($bridge['holdcnt'])) {
569
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
570
		}
571
		if (!empty($bridge['ifpriority'])) {
572
			$pconfig = explode(",", $bridge['ifpriority']);
573
			$ifpriority = array();
574
			foreach ($pconfig as $cfg) {
575
				$embcfg = explode_assoc(":", $cfg);
576
				foreach ($embcfg as $key => $value) {
577
					$ifpriority[$key] = $value;
578
				}
579
			}
580
			foreach ($ifpriority as $key => $value) {
581
				$realif = get_real_interface($key);
582
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
583
			}
584
		}
585
		if (!empty($bridge['ifpathcost'])) {
586
			$pconfig = explode(",", $bridge['ifpathcost']);
587
			$ifpathcost = array();
588
			foreach ($pconfig as $cfg) {
589
				$embcfg = explode_assoc(":", $cfg);
590
				foreach ($embcfg as $key => $value) {
591
					$ifpathcost[$key] = $value;
592
				}
593
			}
594
			foreach ($ifpathcost as $key => $value) {
595
				$realif = get_real_interface($key);
596
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
597
			}
598
		}
599
	}
600

    
601
	if ($bridge['maxaddr'] <> "") {
602
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
603
	}
604
	if ($bridge['timeout'] <> "") {
605
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
606
	}
607
	if ($bridge['span'] <> "") {
608
		$realif = get_real_interface($bridge['span']);
609
		mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
610
	}
611
	if (!empty($bridge['edge'])) {
612
		$edgeifs = explode(',', $bridge['edge']);
613
		foreach ($edgeifs as $edgeif) {
614
			$realif = get_real_interface($edgeif);
615
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
616
		}
617
	}
618
	if (!empty($bridge['autoedge'])) {
619
		$edgeifs = explode(',', $bridge['autoedge']);
620
		foreach ($edgeifs as $edgeif) {
621
			$realif = get_real_interface($edgeif);
622
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
623
		}
624
	}
625
	if (!empty($bridge['ptp'])) {
626
		$ptpifs = explode(',', $bridge['ptp']);
627
		foreach ($ptpifs as $ptpif) {
628
			$realif = get_real_interface($ptpif);
629
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
630
		}
631
	}
632
	if (!empty($bridge['autoptp'])) {
633
		$ptpifs = explode(',', $bridge['autoptp']);
634
		foreach ($ptpifs as $ptpif) {
635
			$realif = get_real_interface($ptpif);
636
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
637
		}
638
	}
639
	if (!empty($bridge['static'])) {
640
		$stickyifs = explode(',', $bridge['static']);
641
		foreach ($stickyifs as $stickyif) {
642
			$realif = get_real_interface($stickyif);
643
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
644
		}
645
	}
646
	if (!empty($bridge['private'])) {
647
		$privateifs = explode(',', $bridge['private']);
648
		foreach ($privateifs as $privateif) {
649
			$realif = get_real_interface($privateif);
650
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
651
		}
652
	}
653

    
654
	if ($bridge['bridgeif']) {
655
		interfaces_bring_up($bridge['bridgeif']);
656
	} else {
657
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
658
	}
659
}
660

    
661
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
662

    
663
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
664
		return;
665
	}
666

    
667
	if ($flagsapplied == false) {
668
		$mtu = get_interface_mtu($bridgeif);
669
		$mtum = get_interface_mtu($interface);
670
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
671
			pfSense_interface_mtu($interface, $mtu);
672
		}
673

    
674
		hardware_offloading_applyflags($interface);
675
		interfaces_bring_up($interface);
676
	}
677

    
678
	pfSense_bridge_add_member($bridgeif, $interface);
679
}
680

    
681
function interfaces_lagg_configure($realif = "") {
682
	global $config, $g;
683
	if (platform_booting()) {
684
		echo gettext("Configuring LAGG interfaces...");
685
	}
686
	$i = 0;
687
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
688
		foreach ($config['laggs']['lagg'] as $lagg) {
689
			if (empty($lagg['laggif'])) {
690
				$lagg['laggif'] = "lagg{$i}";
691
			}
692
			if (!empty($realif) && $realif != $lagg['laggif']) {
693
				continue;
694
			}
695
			/* XXX: Maybe we should report any errors?! */
696
			interface_lagg_configure($lagg);
697
			$i++;
698
		}
699
	}
700
	if (platform_booting()) {
701
		echo gettext("done.") . "\n";
702
	}
703
}
704

    
705
function interface_lagg_configure($lagg) {
706
	global $config, $g;
707

    
708
	if (!is_array($lagg)) {
709
		return -1;
710
	}
711

    
712
	$members = explode(',', $lagg['members']);
713
	if (!count($members)) {
714
		return -1;
715
	}
716

    
717
	if (platform_booting() || !(empty($lagg['laggif']))) {
718
		pfSense_interface_destroy($lagg['laggif']);
719
		pfSense_interface_create($lagg['laggif']);
720
		$laggif = $lagg['laggif'];
721
	} else {
722
		$laggif = pfSense_interface_create("lagg");
723
	}
724

    
725
	/* Check if MTU was defined for this lagg interface */
726
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
727
	if ($lagg_mtu == 0) {
728
		/* Calculate smaller mtu and enforce it */
729
		$smallermtu = 0;
730
		foreach ($members as $member) {
731
			$mtu = get_interface_mtu($member);
732
			if ($smallermtu == 0 && !empty($mtu)) {
733
				$smallermtu = $mtu;
734
			} else if (!empty($mtu) && $mtu < $smallermtu) {
735
				$smallermtu = $mtu;
736
			}
737
		}
738
		$lagg_mtu = $smallermtu;
739
	}
740

    
741
	/* Just in case anything is not working well */
742
	if ($lagg_mtu == 0) {
743
		$lagg_mtu = 1500;
744
	}
745

    
746
	foreach ($members as $member) {
747
		if (!does_interface_exist($member)) {
748
			continue;
749
		}
750
		/* make sure the parent interface is up */
751
		pfSense_interface_mtu($member, $lagg_mtu);
752
		interfaces_bring_up($member);
753
		hardware_offloading_applyflags($member);
754
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
755
	}
756
	pfSense_interface_capabilities($laggif, -$flags_off);
757
	pfSense_interface_capabilities($laggif, $flags_on);
758

    
759
	mwexec("/sbin/ifconfig {$laggif} laggproto " . escapeshellarg($lagg['proto']));
760

    
761
	interfaces_bring_up($laggif);
762

    
763
	return $laggif;
764
}
765

    
766
function interfaces_gre_configure($checkparent = 0, $realif = "") {
767
	global $config;
768

    
769
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
770
		foreach ($config['gres']['gre'] as $i => $gre) {
771
			if (empty($gre['greif'])) {
772
				$gre['greif'] = "gre{$i}";
773
			}
774
			if (!empty($realif) && $realif != $gre['greif']) {
775
				continue;
776
			}
777

    
778
			if ($checkparent == 1) {
779
				if (substr($gre['if'], 0, 4) == '_vip') {
780
					continue;
781
				}
782
				if (substr($gre['if'], 0, 5) == '_lloc') {
783
					continue;
784
				}
785
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
786
					continue;
787
				}
788
			} else if ($checkparent == 2) {
789
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
790
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
791
					continue;
792
				}
793
			}
794
			/* XXX: Maybe we should report any errors?! */
795
			interface_gre_configure($gre);
796
		}
797
	}
798
}
799

    
800
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
801
function interface_gre_configure(&$gre, $grekey = "") {
802
	global $config, $g;
803

    
804
	if (!is_array($gre)) {
805
		return -1;
806
	}
807

    
808
	$realif = get_real_interface($gre['if']);
809
	$realifip = get_interface_ip($gre['if']);
810

    
811
	/* make sure the parent interface is up */
812
	interfaces_bring_up($realif);
813

    
814
	if (platform_booting() || !(empty($gre['greif']))) {
815
		pfSense_interface_destroy($gre['greif']);
816
		pfSense_interface_create($gre['greif']);
817
		$greif = $gre['greif'];
818
	} else {
819
		$greif = pfSense_interface_create("gre");
820
	}
821

    
822
	/* Do not change the order here for more see gre(4) NOTES section. */
823
	mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
824
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
825
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
826
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
827
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
828
	} else {
829
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
830
	}
831
	if (isset($gre['link0'])) {
832
		pfSense_interface_flags($greif, IFF_LINK0);
833
	}
834
	if (isset($gre['link1'])) {
835
		pfSense_interface_flags($greif, IFF_LINK1);
836
	}
837
	if (isset($gre['link2'])) {
838
		pfSense_interface_flags($greif, IFF_LINK2);
839
	}
840

    
841
	if ($greif) {
842
		interfaces_bring_up($greif);
843
	} else {
844
		log_error(gettext("Could not bring greif up -- variable not defined."));
845
	}
846

    
847
	if (isset($gre['link1']) && $gre['link1']) {
848
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
849
	}
850
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
851
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
852
	}
853
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
854
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
855
	}
856

    
857
	interfaces_bring_up($greif);
858

    
859
	return $greif;
860
}
861

    
862
function interfaces_gif_configure($checkparent = 0, $realif = "") {
863
	global $config;
864

    
865
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
866
		foreach ($config['gifs']['gif'] as $i => $gif) {
867
			if (empty($gif['gifif'])) {
868
				$gre['gifif'] = "gif{$i}";
869
			}
870
			if (!empty($realif) && $realif != $gif['gifif']) {
871
				continue;
872
			}
873

    
874
			if ($checkparent == 1) {
875
				if (substr($gif['if'], 0, 4) == '_vip') {
876
					continue;
877
				}
878
				if (substr($gif['if'], 0, 5) == '_lloc') {
879
					continue;
880
				}
881
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
882
					continue;
883
				}
884
			}
885
			else if ($checkparent == 2) {
886
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
887
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
888
					continue;
889
				}
890
			}
891
			/* XXX: Maybe we should report any errors?! */
892
			interface_gif_configure($gif);
893
		}
894
	}
895
}
896

    
897
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
898
function interface_gif_configure(&$gif, $gifkey = "") {
899
	global $config, $g;
900

    
901
	if (!is_array($gif)) {
902
		return -1;
903
	}
904

    
905
	$realif = get_real_interface($gif['if']);
906
	$ipaddr = get_interface_ip($gif['if']);
907

    
908
	if (is_ipaddrv4($gif['remote-addr'])) {
909
		if (is_ipaddrv4($ipaddr)) {
910
			$realifip = $ipaddr;
911
		} else {
912
			$realifip = get_interface_ip($gif['if']);
913
		}
914
		$realifgw = get_interface_gateway($gif['if']);
915
	} else if (is_ipaddrv6($gif['remote-addr'])) {
916
		if (is_ipaddrv6($ipaddr)) {
917
			$realifip = $ipaddr;
918
		} else {
919
			$realifip = get_interface_ipv6($gif['if']);
920
		}
921
		$realifgw = get_interface_gateway_v6($gif['if']);
922
	}
923
	/* make sure the parent interface is up */
924
	if ($realif) {
925
		interfaces_bring_up($realif);
926
	} else {
927
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
928
	}
929

    
930
	if (platform_booting() || !(empty($gif['gifif']))) {
931
		pfSense_interface_destroy($gif['gifif']);
932
		pfSense_interface_create($gif['gifif']);
933
		$gifif = $gif['gifif'];
934
	} else {
935
		$gifif = pfSense_interface_create("gif");
936
	}
937

    
938
	/* Do not change the order here for more see gif(4) NOTES section. */
939
	mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
940
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
941
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
942
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
943
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
944
	} else {
945
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
946
	}
947
	if (isset($gif['link0'])) {
948
		pfSense_interface_flags($gifif, IFF_LINK0);
949
	}
950
	if (isset($gif['link1'])) {
951
		pfSense_interface_flags($gifif, IFF_LINK1);
952
	}
953
	if ($gifif) {
954
		interfaces_bring_up($gifif);
955
	} else {
956
		log_error(gettext("could not bring gifif up -- variable not defined"));
957
	}
958

    
959
	if (!platform_booting()) {
960
		$iflist = get_configured_interface_list();
961
		foreach ($iflist as $ifname) {
962
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
963
				if (get_interface_gateway($ifname)) {
964
					system_routing_configure($ifname);
965
					break;
966
				}
967
				if (get_interface_gateway_v6($ifname)) {
968
					system_routing_configure($ifname);
969
					break;
970
				}
971
			}
972
		}
973
	}
974

    
975

    
976
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
977
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
978
	}
979
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
980
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
981
	}
982

    
983
	if (is_ipaddrv4($realifgw)) {
984
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
985
	}
986
	if (is_ipaddrv6($realifgw)) {
987
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
988
	}
989

    
990
	interfaces_bring_up($gifif);
991

    
992
	return $gifif;
993
}
994

    
995
function interfaces_configure() {
996
	global $config, $g;
997

    
998
	/* Set up our loopback interface */
999
	interfaces_loopback_configure();
1000

    
1001
	/* create the unconfigured wireless clones */
1002
	interfaces_create_wireless_clones();
1003

    
1004
	/* set up LAGG virtual interfaces */
1005
	interfaces_lagg_configure();
1006

    
1007
	/* set up VLAN virtual interfaces */
1008
	interfaces_vlan_configure();
1009

    
1010
	interfaces_qinq_configure();
1011

    
1012
	$iflist = get_configured_interface_with_descr();
1013
	$delayed_list = array();
1014
	$bridge_list = array();
1015
	$track6_list = array();
1016

    
1017
	/* This is needed to speedup interfaces on bootup. */
1018
	$reload = false;
1019
	if (!platform_booting()) {
1020
		$reload = true;
1021
	}
1022

    
1023
	foreach ($iflist as $if => $ifname) {
1024
		$realif = $config['interfaces'][$if]['if'];
1025
		if (strstr($realif, "bridge")) {
1026
			$bridge_list[$if] = $ifname;
1027
		} else if (strstr($realif, "gre")) {
1028
			$delayed_list[$if] = $ifname;
1029
		} else if (strstr($realif, "gif")) {
1030
			$delayed_list[$if] = $ifname;
1031
		} else if (strstr($realif, "ovpn")) {
1032
			//echo "Delaying OpenVPN interface configuration...done.\n";
1033
			continue;
1034
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1035
			$track6_list[$if] = $ifname;
1036
		} else {
1037
			if (platform_booting()) {
1038
				printf(gettext("Configuring %s interface..."), $ifname);
1039
			}
1040

    
1041
			if ($g['debug']) {
1042
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1043
			}
1044
			interface_configure($if, $reload);
1045
			if (platform_booting()) {
1046
				echo gettext("done.") . "\n";
1047
			}
1048
		}
1049
	}
1050

    
1051
	/*
1052
	 * NOTE: The following function parameter consists of
1053
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1054
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1055
	 */
1056

    
1057
	/* set up GRE virtual interfaces */
1058
	interfaces_gre_configure(1);
1059

    
1060
	/* set up GIF virtual interfaces */
1061
	interfaces_gif_configure(1);
1062

    
1063
	/* set up BRIDGe virtual interfaces */
1064
	interfaces_bridge_configure(1);
1065

    
1066
	foreach ($track6_list as $if => $ifname) {
1067
		if (platform_booting()) {
1068
			printf(gettext("Configuring %s interface..."), $ifname);
1069
		}
1070
		if ($g['debug']) {
1071
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1072
		}
1073

    
1074
		interface_configure($if, $reload);
1075

    
1076
		if (platform_booting()) {
1077
			echo gettext("done.") . "\n";
1078
		}
1079
	}
1080

    
1081
	/* bring up vip interfaces */
1082
	interfaces_vips_configure();
1083

    
1084
	/* set up GRE virtual interfaces */
1085
	interfaces_gre_configure(2);
1086

    
1087
	/* set up GIF virtual interfaces */
1088
	interfaces_gif_configure(2);
1089

    
1090
	foreach ($delayed_list as $if => $ifname) {
1091
		if (platform_booting()) {
1092
			printf(gettext("Configuring %s interface..."), $ifname);
1093
		}
1094
		if ($g['debug']) {
1095
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1096
		}
1097

    
1098
		interface_configure($if, $reload);
1099

    
1100
		if (platform_booting()) {
1101
			echo gettext("done.") . "\n";
1102
		}
1103
	}
1104

    
1105
	/* set up BRIDGe virtual interfaces */
1106
	interfaces_bridge_configure(2);
1107

    
1108
	foreach ($bridge_list as $if => $ifname) {
1109
		if (platform_booting()) {
1110
			printf(gettext("Configuring %s interface..."), $ifname);
1111
		}
1112
		if ($g['debug']) {
1113
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1114
		}
1115

    
1116
		interface_configure($if, $reload);
1117

    
1118
		if (platform_booting()) {
1119
			echo gettext("done.") . "\n";
1120
		}
1121
	}
1122

    
1123
	/* configure interface groups */
1124
	interfaces_group_setup();
1125

    
1126
	if (!platform_booting()) {
1127
		/* reconfigure static routes (kernel may have deleted them) */
1128
		system_routing_configure();
1129

    
1130
		/* reload IPsec tunnels */
1131
		vpn_ipsec_configure();
1132

    
1133
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1134
		services_dhcpd_configure();
1135

    
1136
		/* restart dnsmasq or unbound */
1137
		if (isset($config['dnsmasq']['enable'])) {
1138
			services_dnsmasq_configure();
1139
		} elseif (isset($config['unbound']['enable'])) {
1140
			services_unbound_configure();
1141
		}
1142
	}
1143

    
1144
	return 0;
1145
}
1146

    
1147
function interface_reconfigure($interface = "wan", $reloadall = false) {
1148
	interface_bring_down($interface);
1149
	interface_configure($interface, $reloadall);
1150
}
1151

    
1152
function interface_vip_bring_down($vip) {
1153
	global $g;
1154

    
1155
	if (strpos($vip['interface'], '_vip')) {
1156
		if (is_ipaddrv6($vip['subnet'])) {
1157
			$family = 'inet6';
1158
		} else {
1159
			$family = 'inet';
1160
		}
1161

    
1162
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1163
		$iface = $carpvip['interface'];
1164
	} else {
1165
		$iface = $vip['interface'];
1166
	}
1167

    
1168
	$vipif = get_real_interface($iface);
1169
	switch ($vip['mode']) {
1170
		case "proxyarp":
1171
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1172
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1173
			}
1174
			break;
1175
		case "ipalias":
1176
			if (does_interface_exist($vipif)) {
1177
				if (is_ipaddrv6($vip['subnet'])) {
1178
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1179
				} else {
1180
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1181
				}
1182
			}
1183
			break;
1184
		case "carp":
1185
			/* XXX: Is enough to delete ip address? */
1186
			if (does_interface_exist($vipif)) {
1187
				if (is_ipaddrv6($vip['subnet'])) {
1188
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1189
				} else {
1190
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1191
				}
1192
			}
1193
			break;
1194
	}
1195
}
1196

    
1197
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1198
	global $config, $g;
1199

    
1200
	if (!isset($config['interfaces'][$interface])) {
1201
		return;
1202
	}
1203

    
1204
	if ($g['debug']) {
1205
		log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1206
	}
1207

    
1208
	/*
1209
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1210
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1211
	 * Keep this in mind while doing changes here!
1212
	 */
1213
	if ($ifacecfg === false) {
1214
		$ifcfg = $config['interfaces'][$interface];
1215
		$ppps = $config['ppps']['ppp'];
1216
		$realif = get_real_interface($interface);
1217
		$realifv6 = get_real_interface($interface, "inet6", true);
1218
	} elseif (!is_array($ifacecfg)) {
1219
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1220
		$ifcfg = $config['interfaces'][$interface];
1221
		$ppps = $config['ppps']['ppp'];
1222
		$realif = get_real_interface($interface);
1223
		$realifv6 = get_real_interface($interface, "inet6", true);
1224
	} else {
1225
		$ifcfg = $ifacecfg['ifcfg'];
1226
		$ppps = $ifacecfg['ppps'];
1227
		if (isset($ifacecfg['ifcfg']['realif'])) {
1228
			$realif = $ifacecfg['ifcfg']['realif'];
1229
			/* XXX: Any better way? */
1230
			$realifv6 = $realif;
1231
		} else {
1232
			$realif = get_real_interface($interface);
1233
			$realifv6 = get_real_interface($interface, "inet6", true);
1234
		}
1235
	}
1236

    
1237
	switch ($ifcfg['ipaddr']) {
1238
		case "ppp":
1239
		case "pppoe":
1240
		case "pptp":
1241
		case "l2tp":
1242
			if (is_array($ppps) && count($ppps)) {
1243
				foreach ($ppps as $pppid => $ppp) {
1244
					if ($realif == $ppp['if']) {
1245
						if (isset($ppp['ondemand']) && !$destroy) {
1246
							send_event("interface reconfigure {$interface}");
1247
							break;
1248
						}
1249
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1250
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1251
							sleep(2);
1252
						}
1253
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1254
						break;
1255
					}
1256
				}
1257
			}
1258
			break;
1259
		case "dhcp":
1260
			kill_dhclient_process($realif);
1261
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1262
			if (does_interface_exist("$realif")) {
1263
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1264
				interface_ipalias_cleanup($interface);
1265
				if ($destroy == true) {
1266
					pfSense_interface_flags($realif, -IFF_UP);
1267
				}
1268
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1269
			}
1270
			break;
1271
		default:
1272
			if (does_interface_exist("$realif")) {
1273
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1274
				interface_ipalias_cleanup($interface);
1275
				if ($destroy == true) {
1276
					pfSense_interface_flags($realif, -IFF_UP);
1277
				}
1278
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1279
			}
1280
			break;
1281
	}
1282

    
1283
	$track6 = array();
1284
	switch ($ifcfg['ipaddrv6']) {
1285
		case "slaac":
1286
		case "dhcp6":
1287
			$pidv6 = find_dhcp6c_process($realif);
1288
			if ($pidv6) {
1289
				posix_kill($pidv6, SIGTERM);
1290
			}
1291
			sleep(3);
1292
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1293
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1294
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1295
			if (does_interface_exist($realifv6)) {
1296
				$ip6 = find_interface_ipv6($realifv6);
1297
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1298
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1299
				}
1300
				interface_ipalias_cleanup($interface, "inet6");
1301
				if ($destroy == true) {
1302
					pfSense_interface_flags($realif, -IFF_UP);
1303
				}
1304
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1305
			}
1306
			$track6 = link_interface_to_track6($interface);
1307
			break;
1308
		case "6rd":
1309
		case "6to4":
1310
			$realif = "{$interface}_stf";
1311
			if (does_interface_exist("$realif")) {
1312
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1313
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1314
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1315
					$destroy = true;
1316
				} else {
1317
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1318
					$ip6 = get_interface_ipv6($interface);
1319
					if (is_ipaddrv6($ip6)) {
1320
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1321
					}
1322
				}
1323
				interface_ipalias_cleanup($interface, "inet6");
1324
				if ($destroy == true) {
1325
					pfSense_interface_flags($realif, -IFF_UP);
1326
				}
1327
			}
1328
			$track6 = link_interface_to_track6($interface);
1329
			break;
1330
		default:
1331
			if (does_interface_exist("$realif")) {
1332
				$ip6 = get_interface_ipv6($interface);
1333
				if (is_ipaddrv6($ip6)) {
1334
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1335
				}
1336
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1337
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1338
				}
1339
				interface_ipalias_cleanup($interface, "inet6");
1340
				if ($destroy == true) {
1341
					pfSense_interface_flags($realif, -IFF_UP);
1342
				}
1343
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1344
			}
1345
			$track6 = link_interface_to_track6($interface);
1346
			break;
1347
	}
1348

    
1349
	if (!empty($track6) && is_array($track6)) {
1350
		if (!function_exists('services_dhcpd_configure')) {
1351
			require_once('services.inc');
1352
		}
1353
		/* Bring down radvd and dhcp6 on these interfaces */
1354
		services_dhcpd_configure('inet6', $track6);
1355
	}
1356

    
1357
	$old_router = '';
1358
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1359
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1360
	}
1361

    
1362
	/* remove interface up file if it exists */
1363
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1364
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1365
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1366
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1367
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1368
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1369
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1370

    
1371
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1372
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1373
	if (is_array($ifcfg['wireless'])) {
1374
		kill_hostapd($realif);
1375
		mwexec(kill_wpasupplicant($realif));
1376
	}
1377

    
1378
	if ($destroy == true) {
1379
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1380
			pfSense_interface_destroy($realif);
1381
		}
1382
	}
1383

    
1384
	return;
1385
}
1386

    
1387
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1388
	global $config;
1389
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1390
		unset($config["virtualip_carp_maintenancemode"]);
1391
		write_config("Leave CARP maintenance mode");
1392
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1393
		$config["virtualip_carp_maintenancemode"] = true;
1394
		write_config("Enter CARP maintenance mode");
1395
	}
1396

    
1397
	$viparr = &$config['virtualip']['vip'];
1398
	foreach ($viparr as $vip) {
1399
		if ($vip['mode'] == "carp") {
1400
			interface_carp_configure($vip);
1401
		}
1402
	}
1403
}
1404

    
1405
function interface_isppp_type($interface) {
1406
	global $config;
1407

    
1408
	if (!is_array($config['interfaces'][$interface])) {
1409
		return false;
1410
	}
1411

    
1412
	switch ($config['interfaces'][$interface]['ipaddr']) {
1413
		case 'pptp':
1414
		case 'l2tp':
1415
		case 'pppoe':
1416
		case 'ppp':
1417
			return true;
1418
			break;
1419
		default:
1420
			return false;
1421
			break;
1422
	}
1423
}
1424

    
1425
function interfaces_ptpid_used($ptpid) {
1426
	global $config;
1427

    
1428
	if (is_array($config['ppps']['ppp'])) {
1429
		foreach ($config['ppps']['ppp'] as & $settings) {
1430
			if ($ptpid == $settings['ptpid']) {
1431
				return true;
1432
			}
1433
		}
1434
	}
1435

    
1436
	return false;
1437
}
1438

    
1439
function interfaces_ptpid_next() {
1440

    
1441
	$ptpid = 0;
1442
	while (interfaces_ptpid_used($ptpid)) {
1443
		$ptpid++;
1444
	}
1445

    
1446
	return $ptpid;
1447
}
1448

    
1449
function getMPDCRONSettings($pppif) {
1450
	global $config;
1451

    
1452
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1453
	if (is_array($config['cron']['item'])) {
1454
		foreach ($config['cron']['item'] as $i => $item) {
1455
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1456
				return array("ID" => $i, "ITEM" => $item);
1457
			}
1458
		}
1459
	}
1460

    
1461
	return NULL;
1462
}
1463

    
1464
function handle_pppoe_reset($post_array) {
1465
	global $config, $g;
1466

    
1467
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1468
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1469

    
1470
	if (!is_array($config['cron']['item'])) {
1471
		$config['cron']['item'] = array();
1472
	}
1473

    
1474
	$itemhash = getMPDCRONSettings($pppif);
1475

    
1476
	// reset cron items if necessary and return
1477
	if (empty($post_array['pppoe-reset-type'])) {
1478
		if (isset($itemhash)) {
1479
			unset($config['cron']['item'][$itemhash['ID']]);
1480
		}
1481
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1482
		return;
1483
	}
1484

    
1485
	if (empty($itemhash)) {
1486
		$itemhash = array();
1487
	}
1488
	$item = array();
1489
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1490
		$item['minute'] = $post_array['pppoe_resetminute'];
1491
		$item['hour'] = $post_array['pppoe_resethour'];
1492
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1493
			$date = explode("/", $post_array['pppoe_resetdate']);
1494
			$item['mday'] = $date[1];
1495
			$item['month'] = $date[0];
1496
		} else {
1497
			$item['mday'] = "*";
1498
			$item['month'] = "*";
1499
		}
1500
		$item['wday'] = "*";
1501
		$item['who'] = "root";
1502
		$item['command'] = $cron_cmd_file;
1503
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1504
		switch ($post_array['pppoe_pr_preset_val']) {
1505
			case "monthly":
1506
				$item['minute'] = "0";
1507
				$item['hour'] = "0";
1508
				$item['mday'] = "1";
1509
				$item['month'] = "*";
1510
				$item['wday'] = "*";
1511
				break;
1512
			case "weekly":
1513
				$item['minute'] = "0";
1514
				$item['hour'] = "0";
1515
				$item['mday'] = "*";
1516
				$item['month'] = "*";
1517
				$item['wday'] = "0";
1518
				break;
1519
			case "daily":
1520
				$item['minute'] = "0";
1521
				$item['hour'] = "0";
1522
				$item['mday'] = "*";
1523
				$item['month'] = "*";
1524
				$item['wday'] = "*";
1525
				break;
1526
			case "hourly":
1527
				$item['minute'] = "0";
1528
				$item['hour'] = "*";
1529
				$item['mday'] = "*";
1530
				$item['month'] = "*";
1531
				$item['wday'] = "*";
1532
				break;
1533
		} // end switch
1534
		$item['who'] = "root";
1535
		$item['command'] = $cron_cmd_file;
1536
	}
1537
	if (empty($item)) {
1538
		return;
1539
	}
1540
	if (isset($itemhash['ID'])) {
1541
		$config['cron']['item'][$itemhash['ID']] = $item;
1542
	} else {
1543
		$config['cron']['item'][] = $item;
1544
	}
1545
}
1546

    
1547
/*
1548
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1549
 * It writes the mpd config file to /var/etc every time the link is opened.
1550
 */
1551
function interface_ppps_configure($interface) {
1552
	global $config, $g;
1553

    
1554
	/* Return for unassigned interfaces. This is a minimum requirement. */
1555
	if (empty($config['interfaces'][$interface])) {
1556
		return 0;
1557
	}
1558
	$ifcfg = $config['interfaces'][$interface];
1559
	if (!isset($ifcfg['enable'])) {
1560
		return 0;
1561
	}
1562

    
1563
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1564
	if (!is_dir("/var/spool/lock")) {
1565
		mkdir("/var/spool/lock", 0777, true);
1566
	}
1567
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1568
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1569
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1570
	}
1571

    
1572
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1573
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1574
			if ($ifcfg['if'] == $ppp['if']) {
1575
				break;
1576
			}
1577
		}
1578
	}
1579
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1580
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1581
		return 0;
1582
	}
1583
	$pppif = $ifcfg['if'];
1584
	if ($ppp['type'] == "ppp") {
1585
		$type = "modem";
1586
	} else {
1587
		$type = $ppp['type'];
1588
	}
1589
	$upper_type = strtoupper($ppp['type']);
1590

    
1591
	/* XXX: This does not make sense and may create trouble
1592
	 * comment it for now to be removed later on.
1593
	if (platform_booting()) {
1594
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1595
		echo "starting {$pppif} link...";
1596
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1597
			return 0;
1598
	}
1599
	*/
1600

    
1601
	$ports = explode(',', $ppp['ports']);
1602
	if ($type != "modem") {
1603
		foreach ($ports as $pid => $port) {
1604
			$ports[$pid] = get_real_interface($port);
1605
			if (empty($ports[$pid])) {
1606
				return 0;
1607
			}
1608
		}
1609
	}
1610
	$localips = explode(',', $ppp['localip']);
1611
	$gateways = explode(',', $ppp['gateway']);
1612
	$subnets = explode(',', $ppp['subnet']);
1613

    
1614
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
1615
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
1616
	 */
1617
	foreach ($ports as $pid => $port) {
1618
		switch ($ppp['type']) {
1619
			case "pppoe":
1620
				/* Bring the parent interface up */
1621
				interfaces_bring_up($port);
1622
				pfSense_ngctl_attach(".", $port);
1623
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
1624
				mwexec("/usr/sbin/ngctl msg {$port}: setautosrc 1");
1625
				break;
1626
			case "pptp":
1627
			case "l2tp":
1628
				/* configure interface */
1629
				if (is_ipaddr($localips[$pid])) {
1630
					// Manually configure interface IP/subnet
1631
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
1632
					interfaces_bring_up($port);
1633
				} else if (empty($localips[$pid])) {
1634
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
1635
				}
1636

    
1637
				if (!is_ipaddr($localips[$pid])) {
1638
					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!");
1639
					$localips[$pid] = "0.0.0.0";
1640
				}
1641
				if (!is_ipaddr($gateways[$pid])) {
1642
					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));
1643
					return 0;
1644
				}
1645
				pfSense_ngctl_attach(".", $port);
1646
				break;
1647
			case "ppp":
1648
				if (!file_exists("{$port}")) {
1649
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1650
					return 0;
1651
				}
1652
				break;
1653
			default:
1654
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1655
				break;
1656
		}
1657
	}
1658

    
1659
	if (is_array($ports) && count($ports) > 1) {
1660
		$multilink = "enable";
1661
	} else {
1662
		$multilink = "disable";
1663
	}
1664

    
1665
	if ($type == "modem") {
1666
		if (is_ipaddr($ppp['localip'])) {
1667
			$localip = $ppp['localip'];
1668
		} else {
1669
			$localip = '0.0.0.0';
1670
		}
1671

    
1672
		if (is_ipaddr($ppp['gateway'])) {
1673
			$gateway = $ppp['gateway'];
1674
		} else {
1675
			$gateway = "10.64.64.{$pppid}";
1676
		}
1677
		$ranges = "{$localip}/0 {$gateway}/0";
1678

    
1679
		if (empty($ppp['apnum'])) {
1680
			$ppp['apnum'] = 1;
1681
		}
1682
	} else {
1683
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1684
	}
1685

    
1686
	if (isset($ppp['ondemand'])) {
1687
		$ondemand = "enable";
1688
	} else {
1689
		$ondemand = "disable";
1690
	}
1691
	if (!isset($ppp['idletimeout'])) {
1692
		$ppp['idletimeout'] = 0;
1693
	}
1694

    
1695
	if (empty($ppp['username']) && $type == "modem") {
1696
		$ppp['username'] = "user";
1697
		$ppp['password'] = "none";
1698
	}
1699
	if (empty($ppp['password']) && $type == "modem") {
1700
		$passwd = "none";
1701
	} else {
1702
		$passwd = base64_decode($ppp['password']);
1703
	}
1704

    
1705
	$bandwidths = explode(',', $ppp['bandwidth']);
1706
	$defaultmtu = "1492";
1707
	if (!empty($ifcfg['mtu'])) {
1708
		$defaultmtu = intval($ifcfg['mtu']);
1709
	}
1710
	$mtus = explode(',', $ppp['mtu']);
1711
	$mrus = explode(',', $ppp['mru']);
1712

    
1713
	if (isset($ppp['mrru'])) {
1714
		$mrrus = explode(',', $ppp['mrru']);
1715
	}
1716

    
1717
	// Construct the mpd.conf file
1718
	$mpdconf = <<<EOD
1719
startup:
1720
	# configure the console
1721
	set console close
1722
	# configure the web server
1723
	set web close
1724

    
1725
default:
1726
{$ppp['type']}client:
1727
	create bundle static {$interface}
1728
	set bundle enable ipv6cp
1729
	set iface name {$pppif}
1730

    
1731
EOD;
1732
	$setdefaultgw = false;
1733
	$founddefaultgw = false;
1734
	if (is_array($config['gateways']['gateway_item'])) {
1735
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1736
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1737
				$setdefaultgw = true;
1738
				break;
1739
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1740
				$founddefaultgw = true;
1741
				break;
1742
			}
1743
		}
1744
	}
1745

    
1746
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1747
		$setdefaultgw = true;
1748
		$mpdconf .= <<<EOD
1749
	set iface route default
1750

    
1751
EOD;
1752
	}
1753
	$mpdconf .= <<<EOD
1754
	set iface {$ondemand} on-demand
1755
	set iface idle {$ppp['idletimeout']}
1756

    
1757
EOD;
1758

    
1759
	if (isset($ppp['ondemand'])) {
1760
		$mpdconf .= <<<EOD
1761
	set iface addrs 10.10.1.1 10.10.1.2
1762

    
1763
EOD;
1764
	}
1765

    
1766
	if (isset($ppp['tcpmssfix'])) {
1767
		$tcpmss = "disable";
1768
	} else {
1769
		$tcpmss = "enable";
1770
	}
1771
	$mpdconf .= <<<EOD
1772
	set iface {$tcpmss} tcpmssfix
1773

    
1774
EOD;
1775

    
1776
	$mpdconf .= <<<EOD
1777
	set iface up-script /usr/local/sbin/ppp-linkup
1778
	set iface down-script /usr/local/sbin/ppp-linkdown
1779
	set ipcp ranges {$ranges}
1780

    
1781
EOD;
1782
	if (isset($ppp['vjcomp'])) {
1783
		$mpdconf .= <<<EOD
1784
	set ipcp no vjcomp
1785

    
1786
EOD;
1787
	}
1788

    
1789
	if (isset($config['system']['dnsallowoverride'])) {
1790
		$mpdconf .= <<<EOD
1791
	set ipcp enable req-pri-dns
1792
	set ipcp enable req-sec-dns
1793

    
1794
EOD;
1795
	}
1796

    
1797
	if (!isset($ppp['verbose_log'])) {
1798
		$mpdconf .= <<<EOD
1799
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1800

    
1801
EOD;
1802
	}
1803

    
1804
	foreach ($ports as $pid => $port) {
1805
		$port = get_real_interface($port);
1806
		$mpdconf .= <<<EOD
1807

    
1808
	create link static {$interface}_link{$pid} {$type}
1809
	set link action bundle {$interface}
1810
	set link {$multilink} multilink
1811
	set link keep-alive 10 60
1812
	set link max-redial 0
1813

    
1814
EOD;
1815
		if (isset($ppp['shortseq'])) {
1816
			$mpdconf .= <<<EOD
1817
	set link no shortseq
1818

    
1819
EOD;
1820
		}
1821

    
1822
		if (isset($ppp['acfcomp'])) {
1823
			$mpdconf .= <<<EOD
1824
	set link no acfcomp
1825

    
1826
EOD;
1827
		}
1828

    
1829
		if (isset($ppp['protocomp'])) {
1830
			$mpdconf .= <<<EOD
1831
	set link no protocomp
1832

    
1833
EOD;
1834
		}
1835

    
1836
		$mpdconf .= <<<EOD
1837
	set link disable chap pap
1838
	set link accept chap pap eap
1839
	set link disable incoming
1840

    
1841
EOD;
1842

    
1843

    
1844
		if (!empty($bandwidths[$pid])) {
1845
			$mpdconf .= <<<EOD
1846
	set link bandwidth {$bandwidths[$pid]}
1847

    
1848
EOD;
1849
		}
1850

    
1851
		if (empty($mtus[$pid])) {
1852
			$mtus[$pid] = $defaultmtu;
1853
		}
1854
		$mpdconf .= <<<EOD
1855
	set link mtu {$mtus[$pid]}
1856

    
1857
EOD;
1858

    
1859
		if (!empty($mrus[$pid])) {
1860
			$mpdconf .= <<<EOD
1861
	set link mru {$mrus[$pid]}
1862

    
1863
EOD;
1864
		}
1865

    
1866
		if (!empty($mrrus[$pid])) {
1867
			$mpdconf .= <<<EOD
1868
	set link mrru {$mrrus[$pid]}
1869

    
1870
EOD;
1871
		}
1872

    
1873
		$mpdconf .= <<<EOD
1874
	set auth authname "{$ppp['username']}"
1875
	set auth password {$passwd}
1876

    
1877
EOD;
1878
		if ($type == "modem") {
1879
			$mpdconf .= <<<EOD
1880
	set modem device {$ppp['ports']}
1881
	set modem script DialPeer
1882
	set modem idle-script Ringback
1883
	set modem watch -cd
1884
	set modem var \$DialPrefix "DT"
1885
	set modem var \$Telephone "{$ppp['phone']}"
1886

    
1887
EOD;
1888
		}
1889
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1890
			$mpdconf .= <<<EOD
1891
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1892

    
1893
EOD;
1894
		}
1895
		if (isset($ppp['initstr']) && $type == "modem") {
1896
			$initstr = base64_decode($ppp['initstr']);
1897
			$mpdconf .= <<<EOD
1898
	set modem var \$InitString "{$initstr}"
1899

    
1900
EOD;
1901
		}
1902
		if (isset($ppp['simpin']) && $type == "modem") {
1903
			if ($ppp['pin-wait'] == "") {
1904
				$ppp['pin-wait'] = 0;
1905
			}
1906
			$mpdconf .= <<<EOD
1907
	set modem var \$SimPin "{$ppp['simpin']}"
1908
	set modem var \$PinWait "{$ppp['pin-wait']}"
1909

    
1910
EOD;
1911
		}
1912
		if (isset($ppp['apn']) && $type == "modem") {
1913
			$mpdconf .= <<<EOD
1914
	set modem var \$APN "{$ppp['apn']}"
1915
	set modem var \$APNum "{$ppp['apnum']}"
1916

    
1917
EOD;
1918
		}
1919
		if ($type == "pppoe") {
1920
			// Send a null service name if none is set.
1921
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1922
			$mpdconf .= <<<EOD
1923
	set pppoe service "{$provider}"
1924

    
1925
EOD;
1926
		}
1927
		if ($type == "pppoe") {
1928
			$mpdconf .= <<<EOD
1929
	set pppoe iface {$port}
1930

    
1931
EOD;
1932
		}
1933

    
1934
		if ($type == "pptp" || $type == "l2tp") {
1935
			$mpdconf .= <<<EOD
1936
	set {$type} self {$localips[$pid]}
1937
	set {$type} peer {$gateways[$pid]}
1938

    
1939
EOD;
1940
		}
1941

    
1942
		$mpdconf .= "\topen\n";
1943
	} //end foreach ($port)
1944

    
1945

    
1946
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1947
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
1948
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1949
	} else {
1950
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1951
		if (!$fd) {
1952
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1953
			return 0;
1954
		}
1955
		// Write out mpd_ppp.conf
1956
		fwrite($fd, $mpdconf);
1957
		fclose($fd);
1958
		unset($mpdconf);
1959
	}
1960

    
1961
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1962
	if (isset($ppp['uptime'])) {
1963
		if (!file_exists("/conf/{$pppif}.log")) {
1964
			conf_mount_rw();
1965
			file_put_contents("/conf/{$pppif}.log", '');
1966
			conf_mount_ro();
1967
		}
1968
	} else {
1969
		if (file_exists("/conf/{$pppif}.log")) {
1970
			conf_mount_rw();
1971
			@unlink("/conf/{$pppif}.log");
1972
			conf_mount_ro();
1973
		}
1974
	}
1975

    
1976
	/* clean up old lock files */
1977
	foreach ($ports as $port) {
1978
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
1979
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1980
		}
1981
	}
1982

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

    
1987
	// Check for PPPoE periodic reset request
1988
	if ($type == "pppoe") {
1989
		if (!empty($ppp['pppoe-reset-type'])) {
1990
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
1991
		} else {
1992
			interface_setup_pppoe_reset_file($ppp['if']);
1993
		}
1994
	}
1995
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
1996
	$i = 0;
1997
	while ($i < 3) {
1998
		sleep(10);
1999
		if (does_interface_exist($ppp['if'], true)) {
2000
			break;
2001
		}
2002
		$i++;
2003
	}
2004

    
2005
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2006
	/* We should be able to launch the right version for each modem */
2007
	/* We can also guess the mondev from the manufacturer */
2008
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2009
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2010
	foreach ($ports as $port) {
2011
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2012
			$mondev = substr(basename($port), 0, -1);
2013
			$devlist = glob("/dev/{$mondev}?");
2014
			$mondev = basename(end($devlist));
2015
		}
2016
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2017
			$mondev = substr(basename($port), 0, -1) . "1";
2018
		}
2019
		if ($mondev != '') {
2020
			log_error("Starting 3gstats.php on device '{$mondev}' for interface '{$interface}'");
2021
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2022
		}
2023
	}
2024

    
2025
	return 1;
2026
}
2027

    
2028
function interfaces_sync_setup() {
2029
	global $g, $config;
2030

    
2031
	if (isset($config['system']['developerspew'])) {
2032
		$mt = microtime();
2033
		echo "interfaces_sync_setup() being called $mt\n";
2034
	}
2035

    
2036
	if (platform_booting()) {
2037
		echo gettext("Configuring CARP settings...");
2038
		mute_kernel_msgs();
2039
	}
2040

    
2041
	/* suck in configuration items */
2042
	if ($config['hasync']) {
2043
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2044
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2045
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2046
	} else {
2047
		unset($pfsyncinterface);
2048
		unset($pfsyncenabled);
2049
	}
2050

    
2051
	set_sysctl(array(
2052
		"net.inet.carp.preempt" => "1",
2053
		"net.inet.carp.log" => "1")
2054
	);
2055

    
2056
	if (!empty($pfsyncinterface)) {
2057
		$carp_sync_int = get_real_interface($pfsyncinterface);
2058
	} else {
2059
		unset($carp_sync_int);
2060
	}
2061

    
2062
	/* setup pfsync interface */
2063
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2064
		if (is_ipaddr($pfsyncpeerip)) {
2065
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2066
		} else {
2067
			$syncpeer = "-syncpeer";
2068
		}
2069

    
2070
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2071
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2072

    
2073
		sleep(1);
2074

    
2075
		/* 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
2076
		 * for existing sessions.
2077
		 */
2078
		log_error("waiting for pfsync...");
2079
		$i = 0;
2080
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2081
			$i++;
2082
			sleep(1);
2083
		}
2084
		log_error("pfsync done in $i seconds.");
2085
		log_error("Configuring CARP settings finalize...");
2086
	} else {
2087
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2088
	}
2089

    
2090
	if ($config['virtualip']['vip']) {
2091
		set_single_sysctl("net.inet.carp.allow", "1");
2092
	} else {
2093
		set_single_sysctl("net.inet.carp.allow", "0");
2094
	}
2095

    
2096
	if (platform_booting()) {
2097
		unmute_kernel_msgs();
2098
		echo gettext("done.") . "\n";
2099
	}
2100
}
2101

    
2102
function interface_proxyarp_configure($interface = "") {
2103
	global $config, $g;
2104
	if (isset($config['system']['developerspew'])) {
2105
		$mt = microtime();
2106
		echo "interface_proxyarp_configure() being called $mt\n";
2107
	}
2108

    
2109
	/* kill any running choparp */
2110
	if (empty($interface)) {
2111
		killbyname("choparp");
2112
	} else {
2113
		$vipif = get_real_interface($interface);
2114
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2115
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2116
		}
2117
	}
2118

    
2119
	$paa = array();
2120
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2121

    
2122
		/* group by interface */
2123
		foreach ($config['virtualip']['vip'] as $vipent) {
2124
			if ($vipent['mode'] === "proxyarp") {
2125
				if ($vipent['interface']) {
2126
					$proxyif = $vipent['interface'];
2127
				} else {
2128
					$proxyif = "wan";
2129
				}
2130

    
2131
				if (!empty($interface) && $interface != $proxyif) {
2132
					continue;
2133
				}
2134

    
2135
				if (!is_array($paa[$proxyif])) {
2136
					$paa[$proxyif] = array();
2137
				}
2138

    
2139
				$paa[$proxyif][] = $vipent;
2140
			}
2141
		}
2142
	}
2143

    
2144
	if (!empty($interface)) {
2145
		if (is_array($paa[$interface])) {
2146
			$paaifip = get_interface_ip($interface);
2147
			if (!is_ipaddr($paaifip)) {
2148
				return;
2149
			}
2150
			$args = get_real_interface($interface) . " auto";
2151
			foreach ($paa[$interface] as $paent) {
2152
				if (isset($paent['subnet'])) {
2153
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2154
				} else if (isset($paent['range'])) {
2155
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2156
				}
2157
			}
2158
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2159
		}
2160
	} else if (count($paa) > 0) {
2161
		foreach ($paa as $paif => $paents) {
2162
			$paaifip = get_interface_ip($paif);
2163
			if (!is_ipaddr($paaifip)) {
2164
				continue;
2165
			}
2166
			$args = get_real_interface($paif) . " auto";
2167
			foreach ($paents as $paent) {
2168
				if (isset($paent['subnet'])) {
2169
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2170
				} else if (isset($paent['range'])) {
2171
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2172
				}
2173
			}
2174
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2175
		}
2176
	}
2177
}
2178

    
2179
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2180
	global $g, $config;
2181

    
2182
	if (is_array($config['virtualip']['vip'])) {
2183
		foreach ($config['virtualip']['vip'] as $vip) {
2184
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2185
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet'])) {
2186
					interface_vip_bring_down($vip);
2187
				} else if ($inet == "inet4" && is_ipaddrv4($vip['subnet'])) {
2188
					interface_vip_bring_down($vip);
2189
				}
2190
			}
2191
		}
2192
	}
2193
}
2194

    
2195
function interfaces_vips_configure($interface = "") {
2196
	global $g, $config;
2197
	if (isset($config['system']['developerspew'])) {
2198
		$mt = microtime();
2199
		echo "interfaces_vips_configure() being called $mt\n";
2200
	}
2201
	$paa = array();
2202
	if (is_array($config['virtualip']['vip'])) {
2203
		$carp_setuped = false;
2204
		$anyproxyarp = false;
2205
		foreach ($config['virtualip']['vip'] as $vip) {
2206
			switch ($vip['mode']) {
2207
				case "proxyarp":
2208
					/* nothing it is handled on interface_proxyarp_configure() */
2209
					if ($interface <> "" && $vip['interface'] <> $interface) {
2210
						continue;
2211
					}
2212
					$anyproxyarp = true;
2213
					break;
2214
				case "ipalias":
2215
					if ($interface <> "" && $vip['interface'] <> $interface) {
2216
						continue;
2217
					}
2218
					interface_ipalias_configure($vip);
2219
					break;
2220
				case "carp":
2221
					if ($interface <> "" && $vip['interface'] <> $interface) {
2222
						continue;
2223
					}
2224
					if ($carp_setuped == false) {
2225
						$carp_setuped = true;
2226
					}
2227
					interface_carp_configure($vip);
2228
					break;
2229
			}
2230
		}
2231
		if ($carp_setuped == true) {
2232
			interfaces_sync_setup();
2233
		}
2234
		if ($anyproxyarp == true) {
2235
			interface_proxyarp_configure();
2236
		}
2237
	}
2238
}
2239

    
2240
function interface_ipalias_configure(&$vip) {
2241
	global $config;
2242

    
2243
	if ($vip['mode'] != 'ipalias') {
2244
		return;
2245
	}
2246

    
2247
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2248
		if (!isset($config['interfaces'][$vip['interface']])) {
2249
			return;
2250
		}
2251

    
2252
		if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
2253
			return;
2254
		}
2255
	}
2256

    
2257
	$af = 'inet';
2258
	if (is_ipaddrv6($vip['subnet'])) {
2259
		$af = 'inet6';
2260
	}
2261
	$iface = $vip['interface'];
2262
	$vipadd = '';
2263
	if (strpos($vip['interface'], '_vip')) {
2264
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2265
		$iface = $carpvip['interface'];
2266
		$vipadd = "vhid {$carpvip['vhid']}";
2267
	}
2268
	$if = get_real_interface($iface);
2269
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2270
	unset($iface, $af, $if, $carpvip, $vipadd);
2271
}
2272

    
2273
function interface_reload_carps($cif) {
2274
	global $config;
2275

    
2276
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2277
	if (empty($carpifs)) {
2278
		return;
2279
	}
2280

    
2281
	$carps = explode(" ", $carpifs);
2282
	if (is_array($config['virtualip']['vip'])) {
2283
		$viparr = &$config['virtualip']['vip'];
2284
		foreach ($viparr as $vip) {
2285
			if (in_array($vip['carpif'], $carps)) {
2286
				switch ($vip['mode']) {
2287
					case "carp":
2288
						interface_vip_bring_down($vip);
2289
						sleep(1);
2290
						interface_carp_configure($vip);
2291
						break;
2292
					case "ipalias":
2293
						interface_vip_bring_down($vip);
2294
						sleep(1);
2295
						interface_ipalias_configure($vip);
2296
						break;
2297
				}
2298
			}
2299
		}
2300
	}
2301
}
2302

    
2303
function interface_carp_configure(&$vip) {
2304
	global $config, $g;
2305
	if (isset($config['system']['developerspew'])) {
2306
		$mt = microtime();
2307
		echo "interface_carp_configure() being called $mt\n";
2308
	}
2309

    
2310
	if ($vip['mode'] != "carp") {
2311
		return;
2312
	}
2313

    
2314
	/* NOTE: Maybe its useless nowadays */
2315
	$realif = get_real_interface($vip['interface']);
2316
	if (!does_interface_exist($realif)) {
2317
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2318
		return;
2319
	}
2320

    
2321
	$vip_password = $vip['password'];
2322
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2323
	if ($vip['password'] != "") {
2324
		$password = " pass {$vip_password}";
2325
	}
2326

    
2327
	$advbase = "";
2328
	if (!empty($vip['advbase'])) {
2329
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2330
	}
2331

    
2332
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2333
	if ($carp_maintenancemode) {
2334
		$advskew = "advskew 254";
2335
	} else {
2336
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2337
	}
2338

    
2339
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) . " {$advskew} {$advbase} {$password}");
2340

    
2341
	if (is_ipaddrv4($vip['subnet'])) {
2342
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2343
	} else if (is_ipaddrv6($vip['subnet'])) {
2344
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2345
	}
2346

    
2347
	return $realif;
2348
}
2349

    
2350
function interface_wireless_clone($realif, $wlcfg) {
2351
	global $config, $g;
2352
	/*   Check to see if interface has been cloned as of yet.
2353
	 *   If it has not been cloned then go ahead and clone it.
2354
	 */
2355
	$needs_clone = false;
2356
	if (is_array($wlcfg['wireless'])) {
2357
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2358
	} else {
2359
		$wlcfg_mode = $wlcfg['mode'];
2360
	}
2361
	switch ($wlcfg_mode) {
2362
		case "hostap":
2363
			$mode = "wlanmode hostap";
2364
			break;
2365
		case "adhoc":
2366
			$mode = "wlanmode adhoc";
2367
			break;
2368
		default:
2369
			$mode = "";
2370
			break;
2371
	}
2372
	$baseif = interface_get_wireless_base($wlcfg['if']);
2373
	if (does_interface_exist($realif)) {
2374
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2375
		$ifconfig_str = implode($output);
2376
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2377
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2378
			$needs_clone = true;
2379
		}
2380
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2381
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2382
			$needs_clone = true;
2383
		}
2384
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2385
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2386
			$needs_clone = true;
2387
		}
2388
	} else {
2389
		$needs_clone = true;
2390
	}
2391

    
2392
	if ($needs_clone == true) {
2393
		/* remove previous instance if it exists */
2394
		if (does_interface_exist($realif)) {
2395
			pfSense_interface_destroy($realif);
2396
		}
2397

    
2398
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2399
		// Create the new wlan interface. FreeBSD returns the new interface name.
2400
		// example:  wlan2
2401
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2402
		if ($ret <> 0) {
2403
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2404
			return false;
2405
		}
2406
		$newif = trim($out[0]);
2407
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2408
		pfSense_interface_rename($newif, $realif);
2409
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2410
	}
2411
	return true;
2412
}
2413

    
2414
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2415
	global $config, $g;
2416

    
2417
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2418
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2419
				 'regdomain', 'regcountry', 'reglocation');
2420

    
2421
	if (!is_interface_wireless($ifcfg['if'])) {
2422
		return;
2423
	}
2424

    
2425
	$baseif = interface_get_wireless_base($ifcfg['if']);
2426

    
2427
	// Sync shared settings for assigned clones
2428
	$iflist = get_configured_interface_list(false, true);
2429
	foreach ($iflist as $if) {
2430
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2431
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2432
				foreach ($shared_settings as $setting) {
2433
					if ($sync_changes) {
2434
						if (isset($ifcfg['wireless'][$setting])) {
2435
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2436
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2437
							unset($config['interfaces'][$if]['wireless'][$setting]);
2438
						}
2439
					} else {
2440
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2441
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2442
						} else if (isset($ifcfg['wireless'][$setting])) {
2443
							unset($ifcfg['wireless'][$setting]);
2444
						}
2445
					}
2446
				}
2447
				if (!$sync_changes) {
2448
					break;
2449
				}
2450
			}
2451
		}
2452
	}
2453

    
2454
	// Read or write settings at shared area
2455
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2456
		foreach ($shared_settings as $setting) {
2457
			if ($sync_changes) {
2458
				if (isset($ifcfg['wireless'][$setting])) {
2459
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2460
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2461
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2462
				}
2463
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2464
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2465
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2466
				} else if (isset($ifcfg['wireless'][$setting])) {
2467
					unset($ifcfg['wireless'][$setting]);
2468
				}
2469
			}
2470
		}
2471
	}
2472

    
2473
	// Sync the mode on the clone creation page with the configured mode on the interface
2474
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2475
		foreach ($config['wireless']['clone'] as &$clone) {
2476
			if ($clone['cloneif'] == $ifcfg['if']) {
2477
				if ($sync_changes) {
2478
					$clone['mode'] = $ifcfg['wireless']['mode'];
2479
				} else {
2480
					$ifcfg['wireless']['mode'] = $clone['mode'];
2481
				}
2482
				break;
2483
			}
2484
		}
2485
		unset($clone);
2486
	}
2487
}
2488

    
2489
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2490
	global $config, $g;
2491

    
2492
	/*    open up a shell script that will be used to output the commands.
2493
	 *    since wireless is changing a lot, these series of commands are fragile
2494
	 *    and will sometimes need to be verified by a operator by executing the command
2495
	 *    and returning the output of the command to the developers for inspection.  please
2496
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2497
	 */
2498

    
2499
	// Remove script file
2500
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2501

    
2502
	// Clone wireless nic if needed.
2503
	interface_wireless_clone($if, $wl);
2504

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

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

    
2512
	$wlan_setup_log = fopen("{$g['tmp_path']}/{$if}_setup.log", "w");
2513

    
2514
	/* set values for /path/program */
2515
	$hostapd = "/usr/sbin/hostapd";
2516
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2517
	$ifconfig = "/sbin/ifconfig";
2518
	$sysctl = "/sbin/sysctl";
2519
	$killall = "/usr/bin/killall";
2520

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

    
2523
	$wlcmd = array();
2524
	$wl_sysctl = array();
2525
	/* Make sure it's up */
2526
	$wlcmd[] = "up";
2527
	/* Set a/b/g standard */
2528
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2529
	/* skip mode entirely for "auto" */
2530
	if ($wlcfg['standard'] != "auto") {
2531
		$wlcmd[] = "mode " . escapeshellarg($standard);
2532
	}
2533

    
2534
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2535
	 * to prevent massive packet loss under certain conditions. */
2536
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2537
		$wlcmd[] = "-ampdu";
2538
	}
2539

    
2540
	/* Set ssid */
2541
	if ($wlcfg['ssid']) {
2542
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2543
	}
2544

    
2545
	/* Set 802.11g protection mode */
2546
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2547

    
2548
	/* set wireless channel value */
2549
	if (isset($wlcfg['channel'])) {
2550
		if ($wlcfg['channel'] == "0") {
2551
			$wlcmd[] = "channel any";
2552
		} else {
2553
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2554
		}
2555
	}
2556

    
2557
	/* Set antenna diversity value */
2558
	if (isset($wlcfg['diversity'])) {
2559
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
2560
	}
2561

    
2562
	/* Set txantenna value */
2563
	if (isset($wlcfg['txantenna'])) {
2564
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2565
	}
2566

    
2567
	/* Set rxantenna value */
2568
	if (isset($wlcfg['rxantenna'])) {
2569
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2570
	}
2571

    
2572
	/* set Distance value */
2573
	if ($wlcfg['distance']) {
2574
		$distance = escapeshellarg($wlcfg['distance']);
2575
	}
2576

    
2577
	/* Set wireless hostap mode */
2578
	if ($wlcfg['mode'] == "hostap") {
2579
		$wlcmd[] = "mediaopt hostap";
2580
	} else {
2581
		$wlcmd[] = "-mediaopt hostap";
2582
	}
2583

    
2584
	/* Set wireless adhoc mode */
2585
	if ($wlcfg['mode'] == "adhoc") {
2586
		$wlcmd[] = "mediaopt adhoc";
2587
	} else {
2588
		$wlcmd[] = "-mediaopt adhoc";
2589
	}
2590

    
2591
	/* Not necessary to set BSS mode as this is default if adhoc and/or hostap is NOT set */
2592

    
2593
	/* handle hide ssid option */
2594
	if (isset($wlcfg['hidessid']['enable'])) {
2595
		$wlcmd[] = "hidessid";
2596
	} else {
2597
		$wlcmd[] = "-hidessid";
2598
	}
2599

    
2600
	/* handle pureg (802.11g) only option */
2601
	if (isset($wlcfg['pureg']['enable'])) {
2602
		$wlcmd[] = "mode 11g pureg";
2603
	} else {
2604
		$wlcmd[] = "-pureg";
2605
	}
2606

    
2607
	/* handle puren (802.11n) only option */
2608
	if (isset($wlcfg['puren']['enable'])) {
2609
		$wlcmd[] = "puren";
2610
	} else {
2611
		$wlcmd[] = "-puren";
2612
	}
2613

    
2614
	/* enable apbridge option */
2615
	if (isset($wlcfg['apbridge']['enable'])) {
2616
		$wlcmd[] = "apbridge";
2617
	} else {
2618
		$wlcmd[] = "-apbridge";
2619
	}
2620

    
2621
	/* handle turbo option */
2622
	if (isset($wlcfg['turbo']['enable'])) {
2623
		$wlcmd[] = "mediaopt turbo";
2624
	} else {
2625
		$wlcmd[] = "-mediaopt turbo";
2626
	}
2627

    
2628
	/* handle txpower setting */
2629
	// or don't. this has issues at the moment.
2630
	/*
2631
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2632
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2633
	}*/
2634

    
2635
	/* handle wme option */
2636
	if (isset($wlcfg['wme']['enable'])) {
2637
		$wlcmd[] = "wme";
2638
	} else {
2639
		$wlcmd[] = "-wme";
2640
	}
2641

    
2642
	/* Enable wpa if it's configured. No WEP support anymore. */
2643
	if (isset($wlcfg['wpa']['enable'])) {
2644
		$wlcmd[] = "authmode wpa wepmode off ";
2645
	} else {
2646
		$wlcmd[] = "authmode open wepmode off ";
2647
	}
2648

    
2649
	kill_hostapd($if);
2650
	mwexec(kill_wpasupplicant("{$if}"));
2651

    
2652
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2653
	conf_mount_rw();
2654

    
2655
	switch ($wlcfg['mode']) {
2656
		case 'bss':
2657
			if (isset($wlcfg['wpa']['enable'])) {
2658
				$wpa .= <<<EOD
2659
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2660
ctrl_interface_group=0
2661
ap_scan=1
2662
#fast_reauth=1
2663
network={
2664
ssid="{$wlcfg['ssid']}"
2665
scan_ssid=1
2666
priority=5
2667
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2668
psk="{$wlcfg['wpa']['passphrase']}"
2669
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2670
group={$wlcfg['wpa']['wpa_pairwise']}
2671
}
2672
EOD;
2673

    
2674
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2675
				unset($wpa);
2676
			}
2677
			break;
2678
		case 'hostap':
2679
			if (!empty($wlcfg['wpa']['passphrase'])) {
2680
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2681
			} else {
2682
				$wpa_passphrase = "";
2683
			}
2684
			if (isset($wlcfg['wpa']['enable'])) {
2685
				$wpa .= <<<EOD
2686
interface={$if}
2687
driver=bsd
2688
logger_syslog=-1
2689
logger_syslog_level=0
2690
logger_stdout=-1
2691
logger_stdout_level=0
2692
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2693
ctrl_interface={$g['varrun_path']}/hostapd
2694
ctrl_interface_group=wheel
2695
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2696
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2697
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2698
ssid={$wlcfg['ssid']}
2699
debug={$wlcfg['wpa']['debug_mode']}
2700
wpa={$wlcfg['wpa']['wpa_mode']}
2701
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2702
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2703
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2704
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2705
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2706
{$wpa_passphrase}
2707

    
2708
EOD;
2709

    
2710
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2711
					$wpa .= <<<EOD
2712
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2713
rsn_preauth=1
2714
rsn_preauth_interfaces={$if}
2715

    
2716
EOD;
2717
				}
2718
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2719
					$wpa .= "ieee8021x=1\n";
2720

    
2721
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2722
						$auth_server_port = "1812";
2723
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2724
							$auth_server_port = intval($wlcfg['auth_server_port']);
2725
						}
2726
						$wpa .= <<<EOD
2727

    
2728
auth_server_addr={$wlcfg['auth_server_addr']}
2729
auth_server_port={$auth_server_port}
2730
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2731

    
2732
EOD;
2733
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2734
							$auth_server_port2 = "1812";
2735
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2736
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2737
							}
2738

    
2739
							$wpa .= <<<EOD
2740
auth_server_addr={$wlcfg['auth_server_addr2']}
2741
auth_server_port={$auth_server_port2}
2742
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2743

    
2744
EOD;
2745
						}
2746
					}
2747
				}
2748

    
2749
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2750
				unset($wpa);
2751
			}
2752
			break;
2753
	}
2754

    
2755
	/*
2756
	 *    all variables are set, lets start up everything
2757
	 */
2758

    
2759
	$baseif = interface_get_wireless_base($if);
2760
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2761
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2762

    
2763
	/* set sysctls for the wireless interface */
2764
	if (!empty($wl_sysctl)) {
2765
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2766
		foreach ($wl_sysctl as $wl_sysctl_line) {
2767
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2768
		}
2769
	}
2770

    
2771
	/* set ack timers according to users preference (if he/she has any) */
2772
	if ($distance) {
2773
		fwrite($fd_set, "# Enable ATH distance settings\n");
2774
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2775
	}
2776

    
2777
	if (isset($wlcfg['wpa']['enable'])) {
2778
		if ($wlcfg['mode'] == "bss") {
2779
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2780
		}
2781
		if ($wlcfg['mode'] == "hostap") {
2782
			/* add line to script to restore old mac to make hostapd happy */
2783
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2784
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2785
				if (is_macaddr($if_oldmac)) {
2786
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2787
						" link " . escapeshellarg($if_oldmac) . "\n");
2788
				}
2789
			}
2790

    
2791
			fwrite($fd_set, "{$hostapd} -B -P {$g['varrun_path']}/hostapd_{$if}.pid {$g['varetc_path']}/hostapd_{$if}.conf\n");
2792

    
2793
			/* add line to script to restore spoofed mac after running hostapd */
2794
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2795
				if ($wl['spoofmac']) {
2796
					$if_curmac = $wl['spoofmac'];
2797
				} else {
2798
					$if_curmac = get_interface_mac($if);
2799
				}
2800
				if (is_macaddr($if_curmac)) {
2801
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2802
						" link " . escapeshellarg($if_curmac) . "\n");
2803
				}
2804
			}
2805
		}
2806
	}
2807

    
2808
	fclose($fd_set);
2809
	conf_mount_ro();
2810

    
2811
	/* Making sure regulatory settings have actually changed
2812
	 * before applying, because changing them requires bringing
2813
	 * down all wireless networks on the interface. */
2814
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2815
	$ifconfig_str = implode($output);
2816
	unset($output);
2817
	$reg_changing = false;
2818

    
2819
	/* special case for the debug country code */
2820
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2821
		$reg_changing = true;
2822
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2823
		$reg_changing = true;
2824
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2825
		$reg_changing = true;
2826
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2827
		$reg_changing = true;
2828
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2829
		$reg_changing = true;
2830
	}
2831

    
2832
	if ($reg_changing) {
2833
		/* set regulatory domain */
2834
		if ($wlcfg['regdomain']) {
2835
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2836
		}
2837

    
2838
		/* set country */
2839
		if ($wlcfg['regcountry']) {
2840
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2841
		}
2842

    
2843
		/* set location */
2844
		if ($wlcfg['reglocation']) {
2845
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2846
		}
2847

    
2848
		$wlregcmd_args = implode(" ", $wlregcmd);
2849

    
2850
		/* build a complete list of the wireless clones for this interface */
2851
		$clone_list = array();
2852
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2853
			$clone_list[] = interface_get_wireless_clone($baseif);
2854
		}
2855
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2856
			foreach ($config['wireless']['clone'] as $clone) {
2857
				if ($clone['if'] == $baseif) {
2858
					$clone_list[] = $clone['cloneif'];
2859
				}
2860
			}
2861
		}
2862

    
2863
		/* find which clones are up and bring them down */
2864
		$clones_up = array();
2865
		foreach ($clone_list as $clone_if) {
2866
			$clone_status = pfSense_get_interface_addresses($clone_if);
2867
			if ($clone_status['status'] == 'up') {
2868
				$clones_up[] = $clone_if;
2869
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2870
			}
2871
		}
2872

    
2873
		/* apply the regulatory settings */
2874
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2875
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2876

    
2877
		/* bring the clones back up that were previously up */
2878
		foreach ($clones_up as $clone_if) {
2879
			interfaces_bring_up($clone_if);
2880

    
2881
			/*
2882
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2883
			 * is in infrastructure mode, and WPA is enabled.
2884
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2885
			 */
2886
			if ($clone_if != $if) {
2887
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2888
				if ((!empty($friendly_if)) &&
2889
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2890
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2891
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2892
				}
2893
			}
2894
		}
2895
	}
2896

    
2897
	/* 20150318 cmb - Note: the below no longer appears to be true on FreeBSD 10.x, so don't set
2898
	 * mode twice (for now at least). This can be removed entirely in the future if no problems are found
2899

    
2900
	 * The mode must be specified in a separate command before ifconfig
2901
	 * will allow the mode and channel at the same time in the next. */
2902
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2903
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2904

    
2905
	/* configure wireless */
2906
	$wlcmd_args = implode(" ", $wlcmd);
2907
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2908
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2909
	fclose($wlan_setup_log);
2910

    
2911
	unset($wlcmd_args, $wlcmd);
2912

    
2913

    
2914
	sleep(1);
2915
	/* execute hostapd and wpa_supplicant if required in shell */
2916
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2917

    
2918
	return 0;
2919

    
2920
}
2921

    
2922
function kill_hostapd($interface) {
2923
	global $g;
2924

    
2925
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2926
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2927
	}
2928
}
2929

    
2930
function kill_wpasupplicant($interface) {
2931
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2932
}
2933

    
2934
function find_dhclient_process($interface) {
2935
	if ($interface) {
2936
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2937
	} else {
2938
		$pid = 0;
2939
	}
2940

    
2941
	return intval($pid);
2942
}
2943

    
2944
function kill_dhclient_process($interface) {
2945
	if (empty($interface) || !does_interface_exist($interface)) {
2946
		return;
2947
	}
2948

    
2949
	$i = 0;
2950
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2951
		/* 3rd time make it die for sure */
2952
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2953
		posix_kill($pid, $sig);
2954
		sleep(1);
2955
		$i++;
2956
	}
2957
	unset($i);
2958
}
2959

    
2960
function find_dhcp6c_process($interface) {
2961
	global $g;
2962

    
2963
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
2964
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2965
	} else {
2966
		return(false);
2967
	}
2968

    
2969
	return intval($pid);
2970
}
2971

    
2972
function interface_virtual_create($interface) {
2973
	global $config;
2974

    
2975
	if (strstr($interface, "_vlan")) {
2976
		interfaces_vlan_configure($vlan);
2977
	} else if (substr($interface, 0, 3) == "gre") {
2978
		interfaces_gre_configure(0, $interface);
2979
	} else if (substr($interface, 0, 3) == "gif") {
2980
		interfaces_gif_configure(0, $interface);
2981
	} else if (substr($interface, 0, 5) == "ovpns") {
2982
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
2983
			foreach ($config['openvpn']['openvpn-server'] as $server) {
2984
				if ($interface == "ovpns{$server['vpnid']}") {
2985
					if (!function_exists('openvpn_resync')) {
2986
						require_once('openvpn.inc');
2987
					}
2988
					log_error("OpenVPN: Resync server {$server['description']}");
2989
					openvpn_resync('server', $server);
2990
				}
2991
			}
2992
			unset($server);
2993
		}
2994
	} else if (substr($interface, 0, 5) == "ovpnc") {
2995
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
2996
			foreach ($config['openvpn']['openvpn-client'] as $client) {
2997
				if ($interface == "ovpnc{$client['vpnid']}") {
2998
					if (!function_exists('openvpn_resync')) {
2999
						require_once('openvpn.inc');
3000
					}
3001
					log_error("OpenVPN: Resync server {$client['description']}");
3002
					openvpn_resync('client', $client);
3003
				}
3004
			}
3005
			unset($client);
3006
		}
3007
	} else if (substr($interface, 0, 4) == "lagg") {
3008
		interfaces_lagg_configure($interface);
3009
	} else if (substr($interface, 0, 6) == "bridge") {
3010
		interfaces_bridge_configure(0, $interface);
3011
	}
3012
}
3013

    
3014
function interface_vlan_mtu_configured($realhwif, $mtu) {
3015
	global $config;
3016

    
3017
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3018
		foreach ($config['vlans']['vlan'] as $vlan) {
3019
			if ($vlan['if'] != $realhwif) {
3020
				continue;
3021
			}
3022
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3023
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3024
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
3025
					$mtu = $config['interfaces'][$assignedport]['mtu'];
3026
				}
3027
			}
3028
		}
3029
	}
3030

    
3031
	return $mtu;
3032
}
3033

    
3034
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
3035
	global $config;
3036

    
3037
	if (!is_array($vlanifs)) {
3038
		return;
3039
	}
3040

    
3041
	/* All vlans need to use the same mtu value as their parent. */
3042
	foreach ($vlanifs as $vlan) {
3043
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3044
		if (!empty($assignedport)) {
3045
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
3046
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
3047
			} else {
3048
				if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3049
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3050
				}
3051
			}
3052
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3053
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
3054
		}
3055
	}
3056
}
3057

    
3058
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3059
	global $config, $g;
3060
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3061
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3062

    
3063
	$wancfg = $config['interfaces'][$interface];
3064

    
3065
	if (!isset($wancfg['enable'])) {
3066
		return;
3067
	}
3068

    
3069
	$realif = get_real_interface($interface);
3070
	$realhwif_array = get_parent_interface($interface);
3071
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3072
	$realhwif = $realhwif_array[0];
3073

    
3074
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3075
		/* remove all IPv4 and IPv6 addresses */
3076
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3077
		if (is_array($tmpifaces)) {
3078
			foreach ($tmpifaces as $tmpiface) {
3079
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3080
					if (!is_linklocal($tmpiface)) {
3081
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3082
					}
3083
				} else {
3084
					if (is_subnetv4($tmpiface)) {
3085
						$tmpip = explode('/', $tmpiface);
3086
						$tmpip = $tmpip[0];
3087
					} else {
3088
						$tmpip = $tmpiface;
3089
					}
3090
					pfSense_interface_deladdress($realif, $tmpip);
3091
				}
3092
			}
3093
		}
3094

    
3095
		/* only bring down the interface when both v4 and v6 are set to NONE */
3096
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3097
			interface_bring_down($interface);
3098
		}
3099
	}
3100

    
3101
	$interface_to_check = $realif;
3102
	if (interface_isppp_type($interface)) {
3103
		$interface_to_check = $realhwif;
3104
	}
3105

    
3106
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
3107
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) || !does_interface_exist($interface_to_check))) {
3108
		interface_virtual_create($interface_to_check);
3109
	}
3110

    
3111
	/* Disable Accepting router advertisements unless specifically requested */
3112
	if ($g['debug']) {
3113
		log_error("Deny router advertisements for interface {$interface}");
3114
	}
3115
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3116

    
3117
	/* wireless configuration? */
3118
	if (is_array($wancfg['wireless'])) {
3119
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3120
	}
3121

    
3122
	$mac = get_interface_mac($realhwif);
3123
	/*
3124
	 * Don't try to reapply the spoofed MAC if it's already applied.
3125
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3126
	 * the interface config again, which attempts to spoof the MAC again,
3127
	 * which cycles the link again...
3128
	 */
3129
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3130
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3131
			" link " . escapeshellarg($wancfg['spoofmac']));
3132
	} else {
3133

    
3134
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3135
			/*   this is not a valid mac address.  generate a
3136
			 *   temporary mac address so the machine can get online.
3137
			 */
3138
			echo gettext("Generating new MAC address.");
3139
			$random_mac = generate_random_mac_address();
3140
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3141
				" link " . escapeshellarg($random_mac));
3142
			$wancfg['spoofmac'] = $random_mac;
3143
			write_config();
3144
			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");
3145
		}
3146
	}
3147

    
3148
	/* media */
3149
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3150
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3151
		if ($wancfg['media']) {
3152
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3153
		}
3154
		if ($wancfg['mediaopt']) {
3155
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3156
		}
3157
		mwexec($cmd);
3158
	}
3159

    
3160
	/* Apply hw offloading policies as configured */
3161
	enable_hardware_offloading($interface);
3162

    
3163
	/* invalidate interface/ip/sn cache */
3164
	get_interface_arr(true);
3165
	unset($interface_ip_arr_cache[$realif]);
3166
	unset($interface_sn_arr_cache[$realif]);
3167
	unset($interface_ipv6_arr_cache[$realif]);
3168
	unset($interface_snv6_arr_cache[$realif]);
3169

    
3170
	$tunnelif = substr($realif, 0, 3);
3171

    
3172
	if (does_interface_exist($wancfg['if'])) {
3173
		interfaces_bring_up($wancfg['if']);
3174
	}
3175

    
3176
	if (!empty($wancfg['mtu'])) {
3177
		if (stristr($realif, "_vlan")) {
3178
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3179
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3180
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3181
				if ($wancfg['mtu'] > $parentmtu) {
3182
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
3183
				}
3184
			} else {
3185
				$parentmtu = 0;
3186
			}
3187

    
3188
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
3189

    
3190
			if (get_interface_mtu($realhwif) != $parentmtu) {
3191
				pfSense_interface_mtu($realhwif, $parentmtu);
3192
			}
3193

    
3194
			/* All vlans need to use the same mtu value as their parent. */
3195
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
3196
		} else if (substr($realif, 0, 4) == 'lagg') {
3197
			/* LAGG interface must be destroyed and re-created to change MTU */
3198
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3199
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3200
					foreach ($config['laggs']['lagg'] as $lagg) {
3201
						if ($lagg['laggif'] == $realif) {
3202
							interface_lagg_configure($lagg);
3203
							break;
3204
						}
3205
					}
3206
				}
3207
			}
3208
		} else {
3209
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3210
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3211
			}
3212

    
3213
			/* This case is needed when the parent of vlans is being configured */
3214
			$vlans = link_interface_to_vlans($realif);
3215
			if (is_array($vlans)) {
3216
				interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
3217
			}
3218
			unset($vlans);
3219
		}
3220
		/* XXX: What about gre/gif/.. ? */
3221
	}
3222

    
3223
	switch ($wancfg['ipaddr']) {
3224
		case 'dhcp':
3225
			interface_dhcp_configure($interface);
3226
			break;
3227
		case 'pppoe':
3228
		case 'l2tp':
3229
		case 'pptp':
3230
		case 'ppp':
3231
			interface_ppps_configure($interface);
3232
			break;
3233
		default:
3234
			/* XXX: Kludge for now related to #3280 */
3235
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3236
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3237
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3238
				}
3239
			}
3240
			break;
3241
	}
3242

    
3243
	switch ($wancfg['ipaddrv6']) {
3244
		case 'slaac':
3245
		case 'dhcp6':
3246
			interface_dhcpv6_configure($interface, $wancfg);
3247
			break;
3248
		case '6rd':
3249
			interface_6rd_configure($interface, $wancfg);
3250
			break;
3251
		case '6to4':
3252
			interface_6to4_configure($interface, $wancfg);
3253
			break;
3254
		case 'track6':
3255
			interface_track6_configure($interface, $wancfg, $linkupevent);
3256
			break;
3257
		default:
3258
			/* XXX: Kludge for now related to #3280 */
3259
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3260
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3261
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3262
					// FIXME: Add IPv6 Support to the pfSense module
3263
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3264
				}
3265
			}
3266
			break;
3267
	}
3268

    
3269
	interface_netgraph_needed($interface);
3270

    
3271
	if (!platform_booting()) {
3272
		link_interface_to_vips($interface, "update");
3273

    
3274
		if ($tunnelif != 'gre') {
3275
			unset($gre);
3276
			$gre = link_interface_to_gre($interface);
3277
			if (!empty($gre)) {
3278
				array_walk($gre, 'interface_gre_configure');
3279
			}
3280
		}
3281

    
3282
		if ($tunnelif != 'gif') {
3283
			unset($gif);
3284
			$gif = link_interface_to_gif ($interface);
3285
			if (!empty($gif)) {
3286
				array_walk($gif, 'interface_gif_configure');
3287
			}
3288
		}
3289

    
3290
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3291
			unset($bridgetmp);
3292
			$bridgetmp = link_interface_to_bridge($interface);
3293
			if (!empty($bridgetmp)) {
3294
				interface_bridge_add_member($bridgetmp, $realif);
3295
			}
3296
		}
3297

    
3298
		$grouptmp = link_interface_to_group($interface);
3299
		if (!empty($grouptmp)) {
3300
			array_walk($grouptmp, 'interface_group_add_member');
3301
		}
3302

    
3303
		if ($interface == "lan") {
3304
			/* make new hosts file */
3305
			system_hosts_generate();
3306
		}
3307

    
3308
		if ($reloadall == true) {
3309

    
3310
			/* reconfigure static routes (kernel may have deleted them) */
3311
			system_routing_configure($interface);
3312

    
3313
			/* reload ipsec tunnels */
3314
			send_event("service reload ipsecdns");
3315

    
3316
			/* restart dnsmasq or unbound */
3317
			if (isset($config['dnsmasq']['enable'])) {
3318
				services_dnsmasq_configure();
3319
			} elseif (isset($config['unbound']['enable'])) {
3320
				services_unbound_configure();
3321
			}
3322

    
3323
			/* update dyndns */
3324
			send_event("service reload dyndns {$interface}");
3325

    
3326
			/* reload captive portal */
3327
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3328
				require_once('captiveportal.inc');
3329
			}
3330
			captiveportal_init_rules_byinterface($interface);
3331
		}
3332
	}
3333

    
3334
	interfaces_staticarp_configure($interface);
3335
	return 0;
3336
}
3337

    
3338
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3339
	global $config, $g;
3340

    
3341
	if (!is_array($wancfg)) {
3342
		return;
3343
	}
3344

    
3345
	if (!isset($wancfg['enable'])) {
3346
		return;
3347
	}
3348

    
3349
	/* If the interface is not configured via another, exit */
3350
	if (empty($wancfg['track6-interface'])) {
3351
		return;
3352
	}
3353

    
3354
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3355
	$realif = get_real_interface($interface);
3356
	$linklocal = find_interface_ipv6_ll($realif);
3357
	if (!empty($linklocal)) {
3358
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3359
	}
3360
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3361
	/* XXX: Probably should remove? */
3362
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3363

    
3364
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3365
	if (!isset($trackcfg['enable'])) {
3366
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3367
		return;
3368
	}
3369

    
3370
	switch ($trackcfg['ipaddrv6']) {
3371
		case "6to4":
3372
			if ($g['debug']) {
3373
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3374
			}
3375
			interface_track6_6to4_configure($interface, $wancfg);
3376
			break;
3377
		case "6rd":
3378
			if ($g['debug']) {
3379
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3380
			}
3381
			interface_track6_6rd_configure($interface, $wancfg);
3382
			break;
3383
		case "dhcp6":
3384
			if ($linkupevent == true) {
3385
				/*
3386
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3387
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3388
				 *
3389
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3390
				 */
3391
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3392
				$pidv6 = find_dhcp6c_process($parentrealif);
3393
				if ($pidv6) {
3394
					posix_kill($pidv6, SIGHUP);
3395
				}
3396
			}
3397
			break;
3398
	}
3399

    
3400
	if ($linkupevent == false) {
3401
		if (!function_exists('services_dhcpd_configure')) {
3402
			require_once("services.inc");
3403
		}
3404

    
3405
		if (isset($config['unbound']['enable'])) {
3406
			services_unbound_configure();
3407
		}
3408

    
3409
		services_dhcpd_configure("inet6");
3410
	}
3411

    
3412
	return 0;
3413
}
3414

    
3415
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3416
	global $config, $g;
3417
	global $interface_ipv6_arr_cache;
3418
	global $interface_snv6_arr_cache;
3419

    
3420
	if (!is_array($lancfg)) {
3421
		return;
3422
	}
3423

    
3424
	/* If the interface is not configured via another, exit */
3425
	if (empty($lancfg['track6-interface'])) {
3426
		return;
3427
	}
3428

    
3429
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3430
	if (empty($wancfg)) {
3431
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3432
		return;
3433
	}
3434

    
3435
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3436
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3437
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3438
		return;
3439
	}
3440
	$hexwanv4 = return_hex_ipv4($ip4address);
3441

    
3442
	/* create the long prefix notation for math, save the prefix length */
3443
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3444
	$rd6prefixlen = $rd6prefix[1];
3445
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3446

    
3447
	/* binary presentation of the prefix for all 128 bits. */
3448
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3449

    
3450
	/* just save the left prefix length bits */
3451
	$rd6lanbin = substr($rd6lanbin, 0, $rd6prefixlen);
3452
	/* add the v4 address, offset n bits from the left */
3453
	$rd6lanbin .= substr(sprintf("%032b", hexdec($hexwanv4)), (0 + $wancfg['prefix-6rd-v4plen']), 32);
3454

    
3455
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3456
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3457
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3458
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3459
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3460
	/* fill the rest out with zeros */
3461
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3462

    
3463
	/* convert the 128 bits for the lan address back into a valid IPv6 address */
3464
	$rd6lan = convert_128bit_to_ipv6($rd6lanbin) ."1";
3465

    
3466
	$lanif = get_real_interface($interface);
3467
	$oip = find_interface_ipv6($lanif);
3468
	if (is_ipaddrv6($oip)) {
3469
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3470
	}
3471
	unset($interface_ipv6_arr_cache[$lanif]);
3472
	unset($interface_snv6_arr_cache[$lanif]);
3473
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3474
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3475

    
3476
	return 0;
3477
}
3478

    
3479
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3480
	global $config, $g;
3481
	global $interface_ipv6_arr_cache;
3482
	global $interface_snv6_arr_cache;
3483

    
3484
	if (!is_array($lancfg)) {
3485
		return;
3486
	}
3487

    
3488
	/* If the interface is not configured via another, exit */
3489
	if (empty($lancfg['track6-interface'])) {
3490
		return;
3491
	}
3492

    
3493
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3494
	if (empty($wancfg)) {
3495
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3496
		return;
3497
	}
3498

    
3499
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3500
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3501
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3502
		return;
3503
	}
3504
	$hexwanv4 = return_hex_ipv4($ip4address);
3505

    
3506
	/* create the long prefix notation for math, save the prefix length */
3507
	$sixto4prefix = "2002::";
3508
	$sixto4prefixlen = 16;
3509
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3510

    
3511
	/* binary presentation of the prefix for all 128 bits. */
3512
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3513

    
3514
	/* just save the left prefix length bits */
3515
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3516
	/* add the v4 address */
3517
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3518
	/* add the custom prefix id */
3519
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3520
	/* fill the rest out with zeros */
3521
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3522

    
3523
	/* convert the 128 bits for the lan address back into a valid IPv6 address */
3524
	$sixto4lan = convert_128bit_to_ipv6($sixto4lanbin) ."1";
3525

    
3526
	$lanif = get_real_interface($interface);
3527
	$oip = find_interface_ipv6($lanif);
3528
	if (is_ipaddrv6($oip)) {
3529
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3530
	}
3531
	unset($interface_ipv6_arr_cache[$lanif]);
3532
	unset($interface_snv6_arr_cache[$lanif]);
3533
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3534
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3535

    
3536
	return 0;
3537
}
3538

    
3539
function interface_6rd_configure($interface = "wan", $wancfg) {
3540
	global $config, $g;
3541

    
3542
	/* because this is a tunnel interface we can only function
3543
	 *	with a public IPv4 address on the interface */
3544

    
3545
	if (!is_array($wancfg)) {
3546
		return;
3547
	}
3548

    
3549
	if (!is_module_loaded('if_stf.ko')) {
3550
		mwexec('/sbin/kldload if_stf.ko');
3551
	}
3552

    
3553
	$wanif = get_real_interface($interface);
3554
	$ip4address = find_interface_ip($wanif);
3555
	if (!is_ipaddrv4($ip4address)) {
3556
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3557
		return false;
3558
	}
3559
	$hexwanv4 = return_hex_ipv4($ip4address);
3560

    
3561
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3562
		$wancfg['prefix-6rd-v4plen'] = 0;
3563
	}
3564

    
3565
	/* create the long prefix notation for math, save the prefix length */
3566
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3567
	$rd6prefixlen = $rd6prefix[1];
3568
	$brgw = explode('.', $wancfg['gateway-6rd']);
3569
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3570
	$rd6brgw .= str_pad(decbin($brgw[0]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[1]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[2]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[3]), 8, '0', STR_PAD_LEFT);
3571
	if (strlen($rd6brgw) < 128) {
3572
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3573
	}
3574
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3575
	unset($brgw);
3576
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3577

    
3578
	/* binary presentation of the prefix for all 128 bits. */
3579
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3580

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

    
3588
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3589
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3590

    
3591

    
3592
	/* XXX: need to extend to support variable prefix size for v4 */
3593
	if (!is_module_loaded("if_stf")) {
3594
		mwexec("/sbin/kldload if_stf.ko");
3595
	}
3596
	$stfiface = "{$interface}_stf";
3597
	if (does_interface_exist($stfiface)) {
3598
		pfSense_interface_destroy($stfiface);
3599
	}
3600
	$tmpstfiface = pfSense_interface_create("stf");
3601
	pfSense_interface_rename($tmpstfiface, $stfiface);
3602
	pfSense_interface_flags($stfiface, IFF_LINK2);
3603
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3604
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3605
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3606
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3607
	}
3608
	if ($g['debug']) {
3609
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3610
	}
3611

    
3612
	/* write out a default router file */
3613
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3614
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3615

    
3616
	$ip4gateway = get_interface_gateway($interface);
3617
	if (is_ipaddrv4($ip4gateway)) {
3618
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3619
	}
3620

    
3621
	/* configure dependent interfaces */
3622
	if (!platform_booting()) {
3623
		link_interface_to_track6($interface, "update");
3624
	}
3625

    
3626
	return 0;
3627
}
3628

    
3629
function interface_6to4_configure($interface = "wan", $wancfg) {
3630
	global $config, $g;
3631

    
3632
	/* because this is a tunnel interface we can only function
3633
	 *	with a public IPv4 address on the interface */
3634

    
3635
	if (!is_array($wancfg)) {
3636
		return;
3637
	}
3638

    
3639
	$wanif = get_real_interface($interface);
3640
	$ip4address = find_interface_ip($wanif);
3641
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3642
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3643
		return false;
3644
	}
3645

    
3646
	/* create the long prefix notation for math, save the prefix length */
3647
	$stfprefixlen = 16;
3648
	$stfprefix = Net_IPv6::uncompress("2002::");
3649
	$stfarr = explode(":", $stfprefix);
3650
	$v4prefixlen = "0";
3651

    
3652
	/* we need the hex form of the interface IPv4 address */
3653
	$ip4arr = explode(".", $ip4address);
3654
	$hexwanv4 = "";
3655
	foreach ($ip4arr as $octet) {
3656
		$hexwanv4 .= sprintf("%02x", $octet);
3657
	}
3658

    
3659
	/* we need the hex form of the broker IPv4 address */
3660
	$ip4arr = explode(".", "192.88.99.1");
3661
	$hexbrv4 = "";
3662
	foreach ($ip4arr as $octet) {
3663
		$hexbrv4 .= sprintf("%02x", $octet);
3664
	}
3665

    
3666
	/* binary presentation of the prefix for all 128 bits. */
3667
	$stfprefixbin = "";
3668
	foreach ($stfarr as $element) {
3669
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3670
	}
3671
	/* just save the left prefix length bits */
3672
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3673

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

    
3678
	/* for the local subnet too. */
3679
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3680
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3681

    
3682
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3683
	$stfbrarr = array();
3684
	$stfbrbinarr = array();
3685
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3686
	foreach ($stfbrbinarr as $bin) {
3687
		$stfbrarr[] = dechex(bindec($bin));
3688
	}
3689
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3690

    
3691
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3692
	$stflanarr = array();
3693
	$stflanbinarr = array();
3694
	$stflanbinarr = str_split($stflanbin, 16);
3695
	foreach ($stflanbinarr as $bin) {
3696
		$stflanarr[] = dechex(bindec($bin));
3697
	}
3698
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3699
	$stflanarr[7] = 1;
3700
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3701

    
3702
	/* setup the stf interface */
3703
	if (!is_module_loaded("if_stf")) {
3704
		mwexec("/sbin/kldload if_stf.ko");
3705
	}
3706
	$stfiface = "{$interface}_stf";
3707
	if (does_interface_exist($stfiface)) {
3708
		pfSense_interface_destroy($stfiface);
3709
	}
3710
	$tmpstfiface = pfSense_interface_create("stf");
3711
	pfSense_interface_rename($tmpstfiface, $stfiface);
3712
	pfSense_interface_flags($stfiface, IFF_LINK2);
3713
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3714

    
3715
	if ($g['debug']) {
3716
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3717
	}
3718

    
3719
	/* write out a default router file */
3720
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3721
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3722

    
3723
	$ip4gateway = get_interface_gateway($interface);
3724
	if (is_ipaddrv4($ip4gateway)) {
3725
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3726
	}
3727

    
3728
	if (!platform_booting()) {
3729
		link_interface_to_track6($interface, "update");
3730
	}
3731

    
3732
	return 0;
3733
}
3734

    
3735
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3736
	global $config, $g;
3737

    
3738
	if (!is_array($wancfg)) {
3739
		return;
3740
	}
3741

    
3742
	$wanif = get_real_interface($interface, "inet6");
3743
	$dhcp6cconf = "";
3744

    
3745
	if ($wancfg['adv_dhcp6_config_file_override']) {
3746
		// DHCP6 Config File Override
3747
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3748
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3749
		// DHCP6 Config File Advanced
3750
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3751
	} else {
3752
		// DHCP6 Config File Basic
3753
		$dhcp6cconf .= "interface {$wanif} {\n";
3754

    
3755
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3756
		if ($wancfg['ipaddrv6'] == "slaac") {
3757
			$dhcp6cconf .= "\tinformation-only;\n";
3758
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3759
			$dhcp6cconf .= "\trequest domain-name;\n";
3760
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3761
			$dhcp6cconf .= "};\n";
3762
		} else {
3763
			$trackiflist = array();
3764
			$iflist = link_interface_to_track6($interface);
3765
			foreach ($iflist as $ifname => $ifcfg) {
3766
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3767
					$trackiflist[$ifname] = $ifcfg;
3768
				}
3769
			}
3770

    
3771
			/* skip address request if this is set */
3772
			if (!isset($wancfg['dhcp6prefixonly'])) {
3773
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3774
			}
3775
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3776
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3777
			}
3778

    
3779
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3780
			$dhcp6cconf .= "\trequest domain-name;\n";
3781
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3782
			$dhcp6cconf .= "};\n";
3783

    
3784
			if (!isset($wancfg['dhcp6prefixonly'])) {
3785
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3786
			}
3787

    
3788
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3789
				/* Setup the prefix delegation */
3790
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3791
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3792
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3793
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3794
				}
3795
				foreach ($trackiflist as $friendly => $ifcfg) {
3796
					if ($g['debug']) {
3797
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3798
					}
3799
					$realif = get_real_interface($friendly);
3800
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3801
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3802
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3803
					$dhcp6cconf .= "\t};\n";
3804
				}
3805
				unset($preflen, $iflist, $ifcfg, $ifname);
3806
				$dhcp6cconf .= "};\n";
3807
			}
3808
			unset($trackiflist);
3809
		}
3810
	}
3811

    
3812
	/* wide-dhcp6c works for now. */
3813
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3814
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3815
		unset($dhcp6cconf);
3816
		return 1;
3817
	}
3818
	unset($dhcp6cconf);
3819

    
3820
	$dhcp6cscript = "#!/bin/sh\n";
3821
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3822
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3823
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3824
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3825
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3826
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3827
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3828
		unset($dhcp6cscript);
3829
		return 1;
3830
	}
3831
	unset($dhcp6cscript);
3832
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3833

    
3834
	$rtsoldscript = "#!/bin/sh\n";
3835
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3836
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3837
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3838
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3839
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3840
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3841
	$rtsoldscript .= "\t/bin/sleep 1\n";
3842
	$rtsoldscript .= "fi\n";
3843
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3844
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3845
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3846
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3847
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3848
		unset($rtsoldscript);
3849
		return 1;
3850
	}
3851
	unset($rtsoldscript);
3852
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3853

    
3854
	/* accept router advertisements for this interface */
3855
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3856
	log_error("Accept router advertisements on interface {$wanif} ");
3857
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3858

    
3859
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3860
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3861
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3862
		sleep(2);
3863
	}
3864
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3865

    
3866
	/* NOTE: will be called from rtsold invoked script
3867
	 * link_interface_to_track6($interface, "update");
3868
	 */
3869

    
3870
	return 0;
3871
}
3872

    
3873
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3874
	global $g;
3875

    
3876
	$send_options = "";
3877
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3878
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
3879
		foreach ($options as $option) {
3880
			$send_options .= "\tsend " . trim($option) . ";\n";
3881
		}
3882
	}
3883

    
3884
	$request_options = "";
3885
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3886
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
3887
		foreach ($options as $option) {
3888
			$request_options .= "\trequest " . trim($option) . ";\n";
3889
		}
3890
	}
3891

    
3892
	$information_only = "";
3893
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
3894
		$information_only = "\tinformation-only;\n";
3895
	}
3896

    
3897
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3898
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
3899
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3900
	}
3901

    
3902
	$interface_statement  = "interface";
3903
	$interface_statement .= " {$wanif}";
3904
	$interface_statement .= " {\n";
3905
	$interface_statement .= "$send_options";
3906
	$interface_statement .= "$request_options";
3907
	$interface_statement .= "$information_only";
3908
	$interface_statement .= "$script";
3909
	$interface_statement .= "};\n";
3910

    
3911
	$id_assoc_statement_address = "";
3912
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3913
		$id_assoc_statement_address .= "id-assoc";
3914
		$id_assoc_statement_address .= " na";
3915
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
3916
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3917
		}
3918
		$id_assoc_statement_address .= " { ";
3919

    
3920
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
3921
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
3922
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
3923
			$id_assoc_statement_address .= "\n\taddress";
3924
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3925
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3926
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
3927
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
3928
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3929
			}
3930
			$id_assoc_statement_address .= ";\n";
3931
		}
3932

    
3933
		$id_assoc_statement_address .= "};\n";
3934
	}
3935

    
3936
	$id_assoc_statement_prefix = "";
3937
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3938
		$id_assoc_statement_prefix .= "id-assoc";
3939
		$id_assoc_statement_prefix .= " pd";
3940
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
3941
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3942
		}
3943
		$id_assoc_statement_prefix .= " { ";
3944

    
3945
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
3946
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
3947
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
3948
			$id_assoc_statement_prefix .= "\n\tprefix";
3949
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3950
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3951
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
3952
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
3953
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3954
			}
3955
			$id_assoc_statement_prefix .= ";";
3956
		}
3957

    
3958
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3959
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3960
			$id_assoc_statement_prefix .= " {$wanif}";
3961
			$id_assoc_statement_prefix .= " {\n";
3962
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3963
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
3964
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
3965
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3966
			}
3967
			$id_assoc_statement_prefix .= "\t};";
3968
		}
3969

    
3970
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
3971
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
3972
			$id_assoc_statement_prefix .= "\n";
3973
		}
3974

    
3975
		$id_assoc_statement_prefix .= "};\n";
3976
	}
3977

    
3978
	$authentication_statement = "";
3979
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
3980
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
3981
		$authentication_statement .= "authentication";
3982
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
3983
		$authentication_statement .= " {\n";
3984
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
3985
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
3986
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
3987
		}
3988
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
3989
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
3990
		}
3991
		$authentication_statement .= "};\n";
3992
	}
3993

    
3994
	$key_info_statement = "";
3995
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
3996
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
3997
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
3998
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
3999
		$key_info_statement .= "keyinfo";
4000
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4001
		$key_info_statement .= " {\n";
4002
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4003
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4004
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4005
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
4006
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4007
		}
4008
		$key_info_statement .= "};\n";
4009
	}
4010

    
4011
	$dhcp6cconf  = $interface_statement;
4012
	$dhcp6cconf .= $id_assoc_statement_address;
4013
	$dhcp6cconf .= $id_assoc_statement_prefix;
4014
	$dhcp6cconf .= $authentication_statement;
4015
	$dhcp6cconf .= $key_info_statement;
4016

    
4017
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4018

    
4019
	return $dhcp6cconf;
4020
}
4021

    
4022

    
4023
function DHCP6_Config_File_Override($wancfg, $wanif) {
4024

    
4025
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4026

    
4027
	if ($dhcp6cconf === false) {
4028
		log_error("Error: cannot open {$wancfg['adv_dhcp6_config_file_override_path']} in DHCP6_Config_File_Override() for reading.\n");
4029
		return '';
4030
	} else {
4031
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4032
	}
4033
}
4034

    
4035

    
4036
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4037

    
4038
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4039

    
4040
	return $dhcp6cconf;
4041
}
4042

    
4043

    
4044
function interface_dhcp_configure($interface = "wan") {
4045
	global $config, $g;
4046

    
4047
	$wancfg = $config['interfaces'][$interface];
4048
	$wanif = $wancfg['if'];
4049
	if (empty($wancfg)) {
4050
		$wancfg = array();
4051
	}
4052

    
4053
	/* generate dhclient_wan.conf */
4054
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4055
	if (!$fd) {
4056
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
4057
		return 1;
4058
	}
4059

    
4060
	if ($wancfg['dhcphostname']) {
4061
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4062
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4063
	} else {
4064
		$dhclientconf_hostname = "";
4065
	}
4066

    
4067
	$wanif = get_real_interface($interface);
4068
	if (empty($wanif)) {
4069
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4070
		return 0;
4071
	}
4072
	$dhclientconf = "";
4073

    
4074
	$dhclientconf .= <<<EOD
4075
interface "{$wanif}" {
4076
timeout 60;
4077
retry 15;
4078
select-timeout 0;
4079
initial-interval 1;
4080
	{$dhclientconf_hostname}
4081
	script "/sbin/dhclient-script";
4082
EOD;
4083

    
4084
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4085
		$dhclientconf .= <<<EOD
4086

    
4087
	reject {$wancfg['dhcprejectfrom']};
4088
EOD;
4089
	}
4090
	$dhclientconf .= <<<EOD
4091

    
4092
}
4093

    
4094
EOD;
4095

    
4096
	// DHCP Config File Advanced
4097
	if ($wancfg['adv_dhcp_config_advanced']) {
4098
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4099
	}
4100

    
4101
	if (is_ipaddr($wancfg['alias-address'])) {
4102
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4103
		$dhclientconf .= <<<EOD
4104
alias {
4105
	interface "{$wanif}";
4106
	fixed-address {$wancfg['alias-address']};
4107
	option subnet-mask {$subnetmask};
4108
}
4109

    
4110
EOD;
4111
	}
4112

    
4113
	// DHCP Config File Override
4114
	if ($wancfg['adv_dhcp_config_file_override']) {
4115
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4116
	}
4117

    
4118
	fwrite($fd, $dhclientconf);
4119
	fclose($fd);
4120

    
4121
	/* bring wan interface up before starting dhclient */
4122
	if ($wanif) {
4123
		interfaces_bring_up($wanif);
4124
	} else {
4125
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4126
	}
4127

    
4128
	/* Make sure dhclient is not running */
4129
	kill_dhclient_process($wanif);
4130

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

    
4134
	return 0;
4135
}
4136

    
4137
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4138

    
4139
	$hostname = "";
4140
	if ($wancfg['dhcphostname'] != '') {
4141
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4142
	}
4143

    
4144
	/* DHCP Protocol Timings */
4145
	$protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
4146
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4147
		$pt_variable = "{$Protocol_Timing}";
4148
		${$pt_variable} = "";
4149
		if ($wancfg[$Protocol_Timing] != "") {
4150
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4151
		}
4152
	}
4153

    
4154
	$send_options = "";
4155
	if ($wancfg['adv_dhcp_send_options'] != '') {
4156
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4157
		foreach ($options as $option) {
4158
			$send_options .= "\tsend " . trim($option) . ";\n";
4159
		}
4160
	}
4161

    
4162
	$request_options = "";
4163
	if ($wancfg['adv_dhcp_request_options'] != '') {
4164
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4165
	}
4166

    
4167
	$required_options = "";
4168
	if ($wancfg['adv_dhcp_required_options'] != '') {
4169
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4170
	}
4171

    
4172
	$option_modifiers = "";
4173
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4174
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4175
		foreach ($modifiers as $modifier) {
4176
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4177
		}
4178
	}
4179

    
4180
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4181
	$dhclientconf .= "\n";
4182
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4183
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4184
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4185
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4186
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4187
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4188
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4189
	$dhclientconf .= "\n";
4190
	$dhclientconf .= "# DHCP Protocol Options\n";
4191
	$dhclientconf .= "{$hostname}";
4192
	$dhclientconf .= "{$send_options}";
4193
	$dhclientconf .= "{$request_options}";
4194
	$dhclientconf .= "{$required_options}";
4195
	$dhclientconf .= "{$option_modifiers}";
4196
	$dhclientconf .= "\n";
4197
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4198
	$dhclientconf .= "}\n";
4199

    
4200
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4201

    
4202
	return $dhclientconf;
4203
}
4204

    
4205

    
4206
function DHCP_Config_File_Override($wancfg, $wanif) {
4207

    
4208
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4209

    
4210
	if ($dhclientconf === false) {
4211
		log_error("Error: cannot open {$wancfg['adv_dhcp_config_file_override_path']} in DHCP_Config_File_Override() for reading.\n");
4212
		return '';
4213
	} else {
4214
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4215
	}
4216
}
4217

    
4218

    
4219
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4220

    
4221
	/* Apply Interface Substitutions */
4222
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4223

    
4224
	/* Apply Hostname Substitutions */
4225
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4226

    
4227
	/* Arrays of MAC Address Types, Cases, Delimiters */
4228
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4229
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4230
	$various_mac_cases      = array("U", "L");
4231
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4232

    
4233
	/* Apply MAC Address Substitutions */
4234
	foreach ($various_mac_types as $various_mac_type) {
4235
		foreach ($various_mac_cases as $various_mac_case) {
4236
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4237

    
4238
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4239
				if ($res !== false) {
4240

    
4241
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4242
					if ("$various_mac_case" == "U") {
4243
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4244
					}
4245
					if ("$various_mac_case" == "L") {
4246
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4247
					}
4248

    
4249
					if ("$various_mac_type" == "mac_addr_hex") {
4250
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4251
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4252
						$dhcpclientconf_mac_hex = "";
4253
						$delimiter = "";
4254
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4255
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4256
							$delimiter = ":";
4257
						}
4258
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4259
					}
4260

    
4261
					/* MAC Address Delimiter Substitutions */
4262
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4263

    
4264
					/* Apply MAC Address Substitutions */
4265
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4266
				}
4267
			}
4268
		}
4269
	}
4270

    
4271
	return $dhclientconf;
4272
}
4273

    
4274
function interfaces_group_setup() {
4275
	global $config;
4276

    
4277
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4278
		return;
4279
	}
4280

    
4281
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4282
		interface_group_setup($groupar);
4283
	}
4284

    
4285
	return;
4286
}
4287

    
4288
function interface_group_setup(&$groupname /* The parameter is an array */) {
4289
	global $config;
4290

    
4291
	if (!is_array($groupname)) {
4292
		return;
4293
	}
4294
	$members = explode(" ", $groupname['members']);
4295
	foreach ($members as $ifs) {
4296
		$realif = get_real_interface($ifs);
4297
		if ($realif && does_interface_exist($realif)) {
4298
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4299
		}
4300
	}
4301

    
4302
	return;
4303
}
4304

    
4305
function is_interface_group($if) {
4306
	global $config;
4307

    
4308
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4309
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4310
			if ($groupentry['ifname'] === $if) {
4311
				return true;
4312
			}
4313
		}
4314
	}
4315

    
4316
	return false;
4317
}
4318

    
4319
function interface_group_add_member($interface, $groupname) {
4320
	$interface = get_real_interface($interface);
4321
	if (does_interface_exist($interface)) {
4322
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4323
	}
4324
}
4325

    
4326
/* COMPAT Function */
4327
function convert_friendly_interface_to_real_interface_name($interface) {
4328
	return get_real_interface($interface);
4329
}
4330

    
4331
/* COMPAT Function */
4332
function get_real_wan_interface($interface = "wan") {
4333
	return get_real_interface($interface);
4334
}
4335

    
4336
/* COMPAT Function */
4337
function get_current_wan_address($interface = "wan") {
4338
	return get_interface_ip($interface);
4339
}
4340

    
4341
/*
4342
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4343
 */
4344
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4345
	global $config;
4346

    
4347
	if (stripos($interface, "_vip")) {
4348
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4349
			if ($vip['mode'] == "carp") {
4350
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4351
					return $vip['interface'];
4352
				}
4353
			}
4354
		}
4355
	}
4356

    
4357
	/* XXX: For speed reasons reference directly the interface array */
4358
	$ifdescrs = &$config['interfaces'];
4359
	//$ifdescrs = get_configured_interface_list(false, true);
4360

    
4361
	foreach ($ifdescrs as $if => $ifname) {
4362
		if ($if == $interface || $ifname['if'] == $interface) {
4363
			return $if;
4364
		}
4365

    
4366
		if (get_real_interface($if) == $interface) {
4367
			return $if;
4368
		}
4369

    
4370
		if ($checkparent == false) {
4371
			continue;
4372
		}
4373

    
4374
		$int = get_parent_interface($if, true);
4375
		if (is_array($int)) {
4376
			foreach ($int as $iface) {
4377
				if ($iface == $interface) {
4378
					return $if;
4379
				}
4380
			}
4381
		}
4382
	}
4383

    
4384
	if ($interface == "enc0") {
4385
		return 'IPsec';
4386
	}
4387
}
4388

    
4389
/* attempt to resolve interface to friendly descr */
4390
function convert_friendly_interface_to_friendly_descr($interface) {
4391
	global $config;
4392

    
4393
	switch ($interface) {
4394
		case "l2tp":
4395
			$ifdesc = "L2TP";
4396
			break;
4397
		case "pptp":
4398
			$ifdesc = "PPTP";
4399
			break;
4400
		case "pppoe":
4401
			$ifdesc = "PPPoE";
4402
			break;
4403
		case "openvpn":
4404
			$ifdesc = "OpenVPN";
4405
			break;
4406
		case "enc0":
4407
		case "ipsec":
4408
		case "IPsec":
4409
			$ifdesc = "IPsec";
4410
			break;
4411
		default:
4412
			if (isset($config['interfaces'][$interface])) {
4413
				if (empty($config['interfaces'][$interface]['descr'])) {
4414
					$ifdesc = strtoupper($interface);
4415
				} else {
4416
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4417
				}
4418
				break;
4419
			} else if (substr($interface, 0, 4) == '_vip') {
4420
				if (is_array($config['virtualip']['vip'])) {
4421
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4422
						if ($vip['mode'] == "carp") {
4423
							if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4424
								return "{$vip['subnet']} - {$vip['descr']}";
4425
							}
4426
						}
4427
					}
4428
				}
4429
			} else if (substr($interface, 0, 5) == '_lloc') {
4430
				return get_interface_linklocal($interface);
4431
			} else {
4432
				/* if list */
4433
				$ifdescrs = get_configured_interface_with_descr(false, true);
4434
				foreach ($ifdescrs as $if => $ifname) {
4435
					if ($if == $interface || $ifname == $interface) {
4436
						return $ifname;
4437
					}
4438
				}
4439
			}
4440
			break;
4441
	}
4442

    
4443
	return $ifdesc;
4444
}
4445

    
4446
function convert_real_interface_to_friendly_descr($interface) {
4447

    
4448
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4449

    
4450
	if (!empty($ifdesc)) {
4451
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4452
	}
4453

    
4454
	return $interface;
4455
}
4456

    
4457
/*
4458
 *  get_parent_interface($interface):
4459
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4460
 *				or virtual interface (i.e. vlan)
4461
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4462
 *			-- returns $interface passed in if $interface parent is not found
4463
 *			-- returns empty array if an invalid interface is passed
4464
 *	(Only handles ppps and vlans now.)
4465
 */
4466
function get_parent_interface($interface, $avoidrecurse = false) {
4467
	global $config;
4468

    
4469
	$parents = array();
4470
	//Check that we got a valid interface passed
4471
	$realif = get_real_interface($interface);
4472
	if ($realif == NULL) {
4473
		return $parents;
4474
	}
4475

    
4476
	// If we got a real interface, find it's friendly assigned name
4477
	if ($interface == $realif && $avoidrecurse == false) {
4478
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4479
	}
4480

    
4481
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4482
		$ifcfg = $config['interfaces'][$interface];
4483
		switch ($ifcfg['ipaddr']) {
4484
			case "ppp":
4485
			case "pppoe":
4486
			case "pptp":
4487
			case "l2tp":
4488
				if (empty($parents)) {
4489
					if (is_array($config['ppps']['ppp'])) {
4490
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4491
							if ($ifcfg['if'] == $ppp['if']) {
4492
								$ports = explode(',', $ppp['ports']);
4493
								foreach ($ports as $pid => $parent_if) {
4494
									$parents[$pid] = get_real_interface($parent_if);
4495
								}
4496
								break;
4497
							}
4498
						}
4499
					}
4500
				}
4501
				break;
4502
			case "dhcp":
4503
			case "static":
4504
			default:
4505
				// Handle _vlans
4506
				if (strpos($realif, '_vlan') !== FALSE) {
4507
					if (is_array($config['vlans']['vlan'])) {
4508
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4509
							if ($ifcfg['if'] == $vlan['vlanif']) {
4510
								$parents[0] = $vlan['if'];
4511
								break;
4512
							}
4513
						}
4514
					}
4515
				}
4516
				break;
4517
		}
4518
	}
4519

    
4520
	if (empty($parents)) {
4521
		$parents[0] = $realif;
4522
	}
4523

    
4524
	return $parents;
4525
}
4526

    
4527
function interface_is_wireless_clone($wlif) {
4528
	if (!stristr($wlif, "_wlan")) {
4529
		return false;
4530
	} else {
4531
		return true;
4532
	}
4533
}
4534

    
4535
function interface_get_wireless_base($wlif) {
4536
	if (!stristr($wlif, "_wlan")) {
4537
		return $wlif;
4538
	} else {
4539
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4540
	}
4541
}
4542

    
4543
function interface_get_wireless_clone($wlif) {
4544
	if (!stristr($wlif, "_wlan")) {
4545
		return $wlif . "_wlan0";
4546
	} else {
4547
		return $wlif;
4548
	}
4549
}
4550

    
4551
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4552
	global $config, $g;
4553

    
4554
	$wanif = NULL;
4555

    
4556
	switch ($interface) {
4557
		case "l2tp":
4558
			$wanif = "l2tp";
4559
			break;
4560
		case "pptp":
4561
			$wanif = "pptp";
4562
			break;
4563
		case "pppoe":
4564
			$wanif = "pppoe";
4565
			break;
4566
		case "openvpn":
4567
			$wanif = "openvpn";
4568
			break;
4569
		case "IPsec":
4570
		case "ipsec":
4571
		case "enc0":
4572
			$wanif = "enc0";
4573
			break;
4574
		case "ppp":
4575
			$wanif = "ppp";
4576
			break;
4577
		default:
4578
			if (substr($interface, 0, 4) == '_vip') {
4579
				$wanif = get_configured_carp_interface_list($interface, '', 'iface');
4580
				if (!empty($wanif)) {
4581
					$wanif = get_real_interface($wanif, $family);
4582
				}
4583
				break;
4584
			} else if (substr($interface, 0, 5) == '_lloc') {
4585
				$interface = substr($interface, 5);
4586
			} else if (does_interface_exist($interface, $flush)) {
4587
				/*
4588
				 * If a real interface was already passed simply
4589
				 * pass the real interface back.  This encourages
4590
				 * the usage of this function in more cases so that
4591
				 * we can combine logic for more flexibility.
4592
				 */
4593
				$wanif = $interface;
4594
				break;
4595
			}
4596

    
4597
			if (empty($config['interfaces'][$interface])) {
4598
				break;
4599
			}
4600

    
4601
			$cfg = &$config['interfaces'][$interface];
4602

    
4603
			if ($family == "inet6") {
4604
				switch ($cfg['ipaddrv6']) {
4605
					case "6rd":
4606
					case "6to4":
4607
						$wanif = "{$interface}_stf";
4608
						break;
4609
					case 'pppoe':
4610
					case 'ppp':
4611
					case 'l2tp':
4612
					case 'pptp':
4613
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4614
							$wanif = interface_get_wireless_clone($cfg['if']);
4615
						} else {
4616
							$wanif = $cfg['if'];
4617
						}
4618
						break;
4619
					default:
4620
						switch ($cfg['ipaddr']) {
4621
							case 'pppoe':
4622
							case 'ppp':
4623
							case 'l2tp':
4624
							case 'pptp':
4625
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4626
									$wanif = $cfg['if'];
4627
								} else {
4628
									$parents = get_parent_interface($interface);
4629
									if (!empty($parents[0])) {
4630
										$wanif = $parents[0];
4631
									} else {
4632
										$wanif = $cfg['if'];
4633
									}
4634
								}
4635
								break;
4636
							default:
4637
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4638
									$wanif = interface_get_wireless_clone($cfg['if']);
4639
								} else {
4640
									$wanif = $cfg['if'];
4641
								}
4642
								break;
4643
						}
4644
						break;
4645
				}
4646
			} else {
4647
				// Wireless cloned NIC support (FreeBSD 8+)
4648
				// interface name format: $parentnic_wlanparentnic#
4649
				// example: ath0_wlan0
4650
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4651
					$wanif = interface_get_wireless_clone($cfg['if']);
4652
				} else {
4653
					$wanif = $cfg['if'];
4654
				}
4655
			}
4656
			break;
4657
	}
4658

    
4659
	return $wanif;
4660
}
4661

    
4662
/* Guess the physical interface by providing a IP address */
4663
function guess_interface_from_ip($ipaddress) {
4664

    
4665
	$family = '';
4666
	if (is_ipaddrv4($ipaddress)) {
4667
		$family = 'inet';
4668
	}
4669
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4670
		$family = 'inet6';
4671
	}
4672

    
4673
	if (empty($family)) {
4674
		return false;
4675
	}
4676

    
4677
	/* create a route table we can search */
4678
	$output = '';
4679
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4680
	$output[0] = trim($output[0], " \n");
4681
	if (!empty($output[0])) {
4682
		return $output[0];
4683
	}
4684

    
4685
	return false;
4686
}
4687

    
4688
/*
4689
 * find_ip_interface($ip): return the interface where an ip is defined
4690
 *   (or if $bits is specified, where an IP within the subnet is defined)
4691
 */
4692
function find_ip_interface($ip, $bits = null) {
4693
	if (!is_ipaddr($ip)) {
4694
		return false;
4695
	}
4696

    
4697
	$isv6ip = is_ipaddrv6($ip);
4698

    
4699
	/* if list */
4700
	$ifdescrs = get_configured_interface_list();
4701

    
4702
	foreach ($ifdescrs as $ifdescr => $ifname) {
4703
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4704
		if (is_null($ifip)) {
4705
			continue;
4706
		}
4707
		if (is_null($bits)) {
4708
			if ($ip == $ifip) {
4709
				$int = get_real_interface($ifname);
4710
				return $int;
4711
			}
4712
		} else {
4713
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4714
				$int = get_real_interface($ifname);
4715
				return $int;
4716
			}
4717
		}
4718
	}
4719

    
4720
	return false;
4721
}
4722

    
4723
/*
4724
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4725
 *   (or if $bits is specified, where an IP within the subnet is found)
4726
 */
4727
function find_virtual_ip_alias($ip, $bits = null) {
4728
	global $config;
4729

    
4730
	if (!is_array($config['virtualip']['vip'])) {
4731
		return false;
4732
	}
4733
	if (!is_ipaddr($ip)) {
4734
		return false;
4735
	}
4736

    
4737
	$isv6ip = is_ipaddrv6($ip);
4738

    
4739
	foreach ($config['virtualip']['vip'] as $vip) {
4740
		if ($vip['mode'] === "ipalias") {
4741
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4742
				continue;
4743
			}
4744
			if (is_null($bits)) {
4745
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4746
					return $vip;
4747
				}
4748
			} else {
4749
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4750
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4751
					return $vip;
4752
				}
4753
			}
4754
		}
4755
	}
4756
	return false;
4757
}
4758

    
4759
/*
4760
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4761
 */
4762
function find_number_of_created_carp_interfaces() {
4763
	return `/sbin/ifconfig | /usr/bin/grep "carp:" | /usr/bin/wc -l`;
4764
}
4765

    
4766
/*
4767
 * find_carp_interface($ip): return the carp interface where an ip is defined
4768
 */
4769
function find_carp_interface($ip) {
4770
	global $config;
4771
	if (is_array($config['virtualip']['vip'])) {
4772
		foreach ($config['virtualip']['vip'] as $vip) {
4773
			if ($vip['mode'] == "carp") {
4774
				if (is_ipaddrv4($ip)) {
4775
					$carp_ip = get_interface_ip($vip['interface']);
4776
				}
4777
				if (is_ipaddrv6($ip)) {
4778
					$carp_ip = get_interface_ipv6($vip['interface']);
4779
				}
4780
				exec("/sbin/ifconfig", $output, $return);
4781
				foreach ($output as $line) {
4782
					$elements = preg_split("/[ ]+/i", $line);
4783
					if (strstr($elements[0], "vip")) {
4784
						$curif = str_replace(":", "", $elements[0]);
4785
					}
4786
					if (stristr($line, $ip)) {
4787
						$if = $curif;
4788
						continue;
4789
					}
4790
				}
4791

    
4792
				if ($if) {
4793
					return $if;
4794
				}
4795
			}
4796
		}
4797
	}
4798
}
4799

    
4800
function link_carp_interface_to_parent($interface) {
4801
	global $config;
4802

    
4803
	if (empty($interface)) {
4804
		return;
4805
	}
4806

    
4807
	$carp_ip = get_interface_ip($interface);
4808
	$carp_ipv6 = get_interface_ipv6($interface);
4809

    
4810
	if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
4811
		return;
4812
	}
4813

    
4814
	/* if list */
4815
	$ifdescrs = get_configured_interface_list();
4816
	foreach ($ifdescrs as $ifdescr => $ifname) {
4817
		/* check IPv4 */
4818
		if (is_ipaddrv4($carp_ip)) {
4819
			$interfaceip = get_interface_ip($ifname);
4820
			$subnet_bits = get_interface_subnet($ifname);
4821
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4822
			if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
4823
				return $ifname;
4824
			}
4825
		}
4826
		/* Check IPv6 */
4827
		if (is_ipaddrv6($carp_ipv6)) {
4828
			$interfaceipv6 = get_interface_ipv6($ifname);
4829
			$prefixlen = get_interface_subnetv6($ifname);
4830
			if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
4831
				return $ifname;
4832
			}
4833
		}
4834
	}
4835
	return "";
4836
}
4837

    
4838

    
4839
/****f* interfaces/link_ip_to_carp_interface
4840
 * NAME
4841
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4842
 * INPUTS
4843
 *   $ip
4844
 * RESULT
4845
 *   $carp_ints
4846
 ******/
4847
function link_ip_to_carp_interface($ip) {
4848
	global $config;
4849

    
4850
	if (!is_ipaddr($ip)) {
4851
		return;
4852
	}
4853

    
4854
	$carp_ints = "";
4855
	if (is_array($config['virtualip']['vip'])) {
4856
		$first = 0;
4857
		$carp_int = array();
4858
		foreach ($config['virtualip']['vip'] as $vip) {
4859
			if ($vip['mode'] == "carp") {
4860
				$carp_ip = $vip['subnet'];
4861
				$carp_sn = $vip['subnet_bits'];
4862
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4863
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4864
					$carp_int[] = get_real_interface($vip['interface']);
4865
				}
4866
			}
4867
		}
4868
		if (!empty($carp_int)) {
4869
			$carp_ints = implode(" ", array_unique($carp_int));
4870
		}
4871
	}
4872

    
4873
	return $carp_ints;
4874
}
4875

    
4876
function link_interface_to_track6($int, $action = "") {
4877
	global $config;
4878

    
4879
	if (empty($int)) {
4880
		return;
4881
	}
4882

    
4883
	if (is_array($config['interfaces'])) {
4884
		$list = array();
4885
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4886
			if (!isset($ifcfg['enable'])) {
4887
				continue;
4888
			}
4889
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4890
				if ($action == "update") {
4891
					interface_track6_configure($ifname, $ifcfg);
4892
				} else if ($action == "") {
4893
					$list[$ifname] = $ifcfg;
4894
				}
4895
			}
4896
		}
4897
		return $list;
4898
	}
4899
}
4900

    
4901
function interface_find_child_cfgmtu($realiface) {
4902
	global $config;
4903

    
4904
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4905
	$vlans = link_interface_to_vlans($realiface);
4906
	$bridge = link_interface_to_bridge($realiface);
4907
	if (!empty($interface)) {
4908
		$gifs = link_interface_to_gif($interface);
4909
		$gres = link_interface_to_gre($interface);
4910
	} else {
4911
		$gifs = array();
4912
		$gres = array();
4913
	}
4914

    
4915
	$mtu = 0;
4916
	if (is_array($vlans)) {
4917
		foreach ($vlans as $vlan) {
4918
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4919
			if (empty($ifass)) {
4920
				continue;
4921
			}
4922
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4923
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4924
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4925
				}
4926
			}
4927
		}
4928
	}
4929
	if (is_array($gifs)) {
4930
		foreach ($gifs as $vlan) {
4931
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4932
			if (empty($ifass)) {
4933
				continue;
4934
			}
4935
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4936
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4937
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4938
				}
4939
			}
4940
		}
4941
	}
4942
	if (is_array($gres)) {
4943
		foreach ($gres as $vlan) {
4944
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4945
			if (empty($ifass)) {
4946
				continue;
4947
			}
4948
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4949
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4950
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4951
				}
4952
			}
4953
		}
4954
	}
4955
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4956
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4957
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4958
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4959
		}
4960
	}
4961
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4962

    
4963
	return $mtu;
4964
}
4965

    
4966
function link_interface_to_vlans($int, $action = "") {
4967
	global $config;
4968

    
4969
	if (empty($int)) {
4970
		return;
4971
	}
4972

    
4973
	if (is_array($config['vlans']['vlan'])) {
4974
		$ifaces = array();
4975
		foreach ($config['vlans']['vlan'] as $vlan) {
4976
			if ($int == $vlan['if']) {
4977
				if ($action == "update") {
4978
					interfaces_bring_up($int);
4979
				} else {
4980
					$ifaces[$vlan['tag']] = $vlan;
4981
				}
4982
			}
4983
		}
4984
		if (!empty($ifaces)) {
4985
			return $ifaces;
4986
		}
4987
	}
4988
}
4989

    
4990
function link_interface_to_vips($int, $action = "", $vhid = '') {
4991
	global $config;
4992

    
4993
	if (is_array($config['virtualip']['vip'])) {
4994
		$result = array();
4995
		foreach ($config['virtualip']['vip'] as $vip) {
4996
			if ($int == $vip['interface']) {
4997
				if ($action == "update") {
4998
					interfaces_vips_configure($int);
4999
				} else {
5000
					if (empty($vhid) || ($vhid == $vip['vhid'])) {
5001
						$result[] = $vip;
5002
					}
5003
				}
5004
			}
5005
		}
5006
		return $result;
5007
	}
5008
}
5009

    
5010
/****f* interfaces/link_interface_to_bridge
5011
 * NAME
5012
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5013
 * INPUTS
5014
 *   $ip
5015
 * RESULT
5016
 *   bridge[0-99]
5017
 ******/
5018
function link_interface_to_bridge($int) {
5019
	global $config;
5020

    
5021
	if (is_array($config['bridges']['bridged'])) {
5022
		foreach ($config['bridges']['bridged'] as $bridge) {
5023
			if (in_array($int, explode(',', $bridge['members']))) {
5024
				return "{$bridge['bridgeif']}";
5025
			}
5026
		}
5027
	}
5028
}
5029

    
5030
function link_interface_to_group($int) {
5031
	global $config;
5032

    
5033
	$result = array();
5034

    
5035
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5036
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5037
			if (in_array($int, explode(" ", $group['members']))) {
5038
				$result[$group['ifname']] = $int;
5039
			}
5040
		}
5041
	}
5042

    
5043
	return $result;
5044
}
5045

    
5046
function link_interface_to_gre($interface) {
5047
	global $config;
5048

    
5049
	$result = array();
5050

    
5051
	if (is_array($config['gres']['gre'])) {
5052
		foreach ($config['gres']['gre'] as $gre) {
5053
			if ($gre['if'] == $interface) {
5054
				$result[] = $gre;
5055
			}
5056
		}
5057
	}
5058

    
5059
	return $result;
5060
}
5061

    
5062
function link_interface_to_gif($interface) {
5063
	global $config;
5064

    
5065
	$result = array();
5066

    
5067
	if (is_array($config['gifs']['gif'])) {
5068
		foreach ($config['gifs']['gif'] as $gif) {
5069
			if ($gif['if'] == $interface) {
5070
				$result[] = $gif;
5071
			}
5072
		}
5073
	}
5074

    
5075
	return $result;
5076
}
5077

    
5078
/*
5079
 * find_interface_ip($interface): return the interface ip (first found)
5080
 */
5081
function find_interface_ip($interface, $flush = false) {
5082
	global $interface_ip_arr_cache;
5083
	global $interface_sn_arr_cache;
5084

    
5085
	$interface = str_replace("\n", "", $interface);
5086

    
5087
	if (!does_interface_exist($interface)) {
5088
		return;
5089
	}
5090

    
5091
	/* Setup IP cache */
5092
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5093
		$ifinfo = pfSense_get_interface_addresses($interface);
5094
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5095
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5096
	}
5097

    
5098
	return $interface_ip_arr_cache[$interface];
5099
}
5100

    
5101
/*
5102
 * find_interface_ipv6($interface): return the interface ip (first found)
5103
 */
5104
function find_interface_ipv6($interface, $flush = false) {
5105
	global $interface_ipv6_arr_cache;
5106
	global $interface_snv6_arr_cache;
5107
	global $config;
5108

    
5109
	$interface = trim($interface);
5110
	$interface = get_real_interface($interface);
5111

    
5112
	if (!does_interface_exist($interface)) {
5113
		return;
5114
	}
5115

    
5116
	/* Setup IP cache */
5117
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5118
		$ifinfo = pfSense_get_interface_addresses($interface);
5119
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5120
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5121
	}
5122

    
5123
	return $interface_ipv6_arr_cache[$interface];
5124
}
5125

    
5126
/*
5127
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5128
 */
5129
function find_interface_ipv6_ll($interface, $flush = false) {
5130
	global $interface_llv6_arr_cache;
5131
	global $config;
5132

    
5133
	$interface = str_replace("\n", "", $interface);
5134

    
5135
	if (!does_interface_exist($interface)) {
5136
		return;
5137
	}
5138

    
5139
	/* Setup IP cache */
5140
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5141
		$ifinfo = pfSense_getall_interface_addresses($interface);
5142
		foreach ($ifinfo as $line) {
5143
			if (strstr($line, ":")) {
5144
				$parts = explode("/", $line);
5145
				if (is_linklocal($parts[0])) {
5146
					$ifinfo['linklocal'] = $parts[0];
5147
				}
5148
			}
5149
		}
5150
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5151
	}
5152
	return $interface_llv6_arr_cache[$interface];
5153
}
5154

    
5155
function find_interface_subnet($interface, $flush = false) {
5156
	global $interface_sn_arr_cache;
5157
	global $interface_ip_arr_cache;
5158

    
5159
	$interface = str_replace("\n", "", $interface);
5160
	if (does_interface_exist($interface) == false) {
5161
		return;
5162
	}
5163

    
5164
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5165
		$ifinfo = pfSense_get_interface_addresses($interface);
5166
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5167
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5168
	}
5169

    
5170
	return $interface_sn_arr_cache[$interface];
5171
}
5172

    
5173
function find_interface_subnetv6($interface, $flush = false) {
5174
	global $interface_snv6_arr_cache;
5175
	global $interface_ipv6_arr_cache;
5176

    
5177
	$interface = str_replace("\n", "", $interface);
5178
	if (does_interface_exist($interface) == false) {
5179
		return;
5180
	}
5181

    
5182
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5183
		$ifinfo = pfSense_get_interface_addresses($interface);
5184
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5185
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5186
	}
5187

    
5188
	return $interface_snv6_arr_cache[$interface];
5189
}
5190

    
5191
function ip_in_interface_alias_subnet($interface, $ipalias) {
5192
	global $config;
5193

    
5194
	if (empty($interface) || !is_ipaddr($ipalias)) {
5195
		return false;
5196
	}
5197
	if (is_array($config['virtualip']['vip'])) {
5198
		foreach ($config['virtualip']['vip'] as $vip) {
5199
			switch ($vip['mode']) {
5200
				case "ipalias":
5201
					if ($vip['interface'] <> $interface) {
5202
						break;
5203
					}
5204
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5205
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5206
						return true;
5207
					}
5208
					break;
5209
			}
5210
		}
5211
	}
5212

    
5213
	return false;
5214
}
5215

    
5216
function get_possible_listen_ips($include_ipv6_link_local=false) {
5217

    
5218
	$interfaces = get_configured_interface_with_descr();
5219
	foreach ($interfaces as $iface => $ifacename) {
5220
		if ($include_ipv6_link_local) {
5221
			/* This is to avoid going though added ll below */
5222
			if (substr($iface, 0, 5) == '_lloc') {
5223
				continue;
5224
			}
5225
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5226
			if (!empty($llip)) {
5227
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5228
			}
5229
		}
5230
	}
5231
	/* XXX: Maybe use array_merge below? */
5232
	$carplist = get_configured_carp_interface_list();
5233
	foreach ($carplist as $cif => $carpip) {
5234
		$interfaces[$cif] = $carpip . ' (' . get_vip_descr($carpip) . ')';
5235
	}
5236
	$aliaslist = get_configured_ip_aliases_list();
5237
	foreach ($aliaslist as $aliasip => $aliasif) {
5238
		$interfaces[$aliasip] = $aliasip . ' (' . get_vip_descr($aliasip) . ')';
5239
	}
5240

    
5241
	$interfaces['lo0'] = 'Localhost';
5242

    
5243
	return $interfaces;
5244
}
5245

    
5246
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5247
	global $config;
5248

    
5249
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5250
	foreach (array('server', 'client') as $mode) {
5251
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5252
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5253
				if (!isset($setting['disable'])) {
5254
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5255
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
5256
				}
5257
			}
5258
		}
5259
	}
5260
	return $sourceips;
5261
}
5262

    
5263
function get_interface_ip($interface = "wan") {
5264

    
5265
	$realif = get_failover_interface($interface);
5266
	if (!$realif) {
5267
		return null;
5268
	}
5269

    
5270
	if (substr($realif, 0, 4) == '_vip') {
5271
		return get_configured_carp_interface_list($realif, 'inet', 'ip');
5272
	}
5273

    
5274
	if (strstr($realif, "_vip")) {
5275
		return get_configured_carp_interface_list($realif);
5276
	}
5277

    
5278
	$curip = find_interface_ip($realif);
5279
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5280
		return $curip;
5281
	} else {
5282
		return null;
5283
	}
5284
}
5285

    
5286
function get_interface_ipv6($interface = "wan", $flush = false) {
5287
	global $config;
5288

    
5289
	$realif = get_failover_interface($interface, 'inet6');
5290
	if (!$realif) {
5291
		return null;
5292
	}
5293

    
5294
	if (substr($realif, 0, 4) == '_vip') {
5295
		return get_configured_carp_interface_list($realif, 'inet6', 'ip');
5296
	} else if (substr($realif, 0, 5) == '_lloc') {
5297
		return get_interface_linklocal($interface);
5298
	}
5299

    
5300
	if (is_array($config['interfaces'][$interface])) {
5301
		switch ($config['interfaces'][$interface]['ipaddr']) {
5302
			case 'pppoe':
5303
			case 'l2tp':
5304
			case 'pptp':
5305
			case 'ppp':
5306
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5307
					$realif = get_real_interface($interface, 'inet6', false);
5308
				}
5309
				break;
5310
		}
5311
	}
5312

    
5313
	$curip = find_interface_ipv6($realif, $flush);
5314
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5315
		return $curip;
5316
	} else {
5317
		/*
5318
		 * NOTE: On the case when only the prefix is requested,
5319
		 * the communication on WAN will be done over link-local.
5320
		 */
5321
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5322
			$curip = find_interface_ipv6_ll($realif, $flush);
5323
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5324
				return $curip;
5325
			}
5326
		}
5327
	}
5328
	return null;
5329
}
5330

    
5331
function get_interface_linklocal($interface = "wan") {
5332

    
5333
	$realif = get_failover_interface($interface, 'inet6');
5334
	if (!$realif) {
5335
		return null;
5336
	}
5337

    
5338
	if (substr($interface, 0, 4) == '_vip') {
5339
		$realif = get_real_interface($interface);
5340
	} else if (substr($interface, 0, 5) == '_lloc') {
5341
		$realif = get_real_interface(substr($interface, 5));
5342
	}
5343

    
5344
	$curip = find_interface_ipv6_ll($realif);
5345
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5346
		return $curip;
5347
	} else {
5348
		return null;
5349
	}
5350
}
5351

    
5352
function get_interface_subnet($interface = "wan") {
5353

    
5354
	if (substr($interface, 0, 4) == '_vip') {
5355
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5356
	}
5357

    
5358
	$realif = get_real_interface($interface);
5359
	if (!$realif) {
5360
		return null;
5361
	}
5362

    
5363
	$cursn = find_interface_subnet($realif);
5364
	if (!empty($cursn)) {
5365
		return $cursn;
5366
	}
5367

    
5368
	return null;
5369
}
5370

    
5371
function get_interface_subnetv6($interface = "wan") {
5372

    
5373
	if (substr($interface, 0, 4) == '_vip') {
5374
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5375
	} else if (substr($interface, 0, 5) == '_lloc') {
5376
		$interface = substr($interface, 5);
5377
	}
5378

    
5379
	$realif = get_real_interface($interface, 'inet6');
5380
	if (!$realif) {
5381
		return null;
5382
	}
5383

    
5384
	$cursn = find_interface_subnetv6($realif);
5385
	if (!empty($cursn)) {
5386
		return $cursn;
5387
	}
5388

    
5389
	return null;
5390
}
5391

    
5392
/* return outside interfaces with a gateway */
5393
function get_interfaces_with_gateway() {
5394
	global $config;
5395

    
5396
	$ints = array();
5397

    
5398
	/* loop interfaces, check config for outbound */
5399
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5400
		switch ($ifname['ipaddr']) {
5401
			case "dhcp":
5402
			case "pppoe":
5403
			case "pptp":
5404
			case "l2tp":
5405
			case "ppp":
5406
				$ints[$ifdescr] = $ifdescr;
5407
				break;
5408
			default:
5409
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5410
				    !empty($ifname['gateway'])) {
5411
					$ints[$ifdescr] = $ifdescr;
5412
				}
5413
				break;
5414
		}
5415
	}
5416
	return $ints;
5417
}
5418

    
5419
/* return true if interface has a gateway */
5420
function interface_has_gateway($friendly) {
5421
	global $config;
5422

    
5423
	if (!empty($config['interfaces'][$friendly])) {
5424
		$ifname = &$config['interfaces'][$friendly];
5425
		switch ($ifname['ipaddr']) {
5426
			case "dhcp":
5427
			case "pppoe":
5428
			case "pptp":
5429
			case "l2tp":
5430
			case "ppp":
5431
				return true;
5432
			break;
5433
			default:
5434
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5435
					return true;
5436
				}
5437
				$tunnelif = substr($ifname['if'], 0, 3);
5438
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5439
					return true;
5440
				}
5441
				if (!empty($ifname['gateway'])) {
5442
					return true;
5443
				}
5444
			break;
5445
		}
5446
	}
5447

    
5448
	return false;
5449
}
5450

    
5451
/* return true if interface has a gateway */
5452
function interface_has_gatewayv6($friendly) {
5453
	global $config;
5454

    
5455
	if (!empty($config['interfaces'][$friendly])) {
5456
		$ifname = &$config['interfaces'][$friendly];
5457
		switch ($ifname['ipaddrv6']) {
5458
			case "slaac":
5459
			case "dhcp6":
5460
			case "6to4":
5461
			case "6rd":
5462
				return true;
5463
				break;
5464
			default:
5465
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5466
					return true;
5467
				}
5468
				$tunnelif = substr($ifname['if'], 0, 3);
5469
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5470
					return true;
5471
				}
5472
				if (!empty($ifname['gatewayv6'])) {
5473
					return true;
5474
				}
5475
				break;
5476
		}
5477
	}
5478

    
5479
	return false;
5480
}
5481

    
5482
/****f* interfaces/is_altq_capable
5483
 * NAME
5484
 *   is_altq_capable - Test if interface is capable of using ALTQ
5485
 * INPUTS
5486
 *   $int            - string containing interface name
5487
 * RESULT
5488
 *   boolean         - true or false
5489
 ******/
5490

    
5491
function is_altq_capable($int) {
5492
	/* Per:
5493
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+8.3-RELEASE&arch=default&format=html
5494
	 * Only the following drivers have ALTQ support
5495
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
5496
	 */
5497
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
5498
			"bfe", "bge", "bridge", "cas", "dc", "de", "ed", "em", "ep", "epair", "et", "fxp", "gem",
5499
			"hme", "hn", "igb", "ixgbe", "jme", "le", "lem", "msk", "mxge", "my", "nfe",
5500
			"nge", "npe", "nve", "re", "rl", "sf", "sge", "sis", "sk",
5501
			"ste", "stge", "ti", "txp", "udav", "ural", "vge", "vmx", "vr", "vte", "xl",
5502
			"ndis", "tun", "ovpns", "ovpnc", "vlan", "pppoe", "pptp", "ng",
5503
			"l2tp", "ppp", "vtnet");
5504

    
5505
	$int_family = remove_ifindex($int);
5506

    
5507
	if (in_array($int_family, $capable)) {
5508
		return true;
5509
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5510
		return true;
5511
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5512
		return true;
5513
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5514
		return true;
5515
	} else {
5516
		return false;
5517
	}
5518
}
5519

    
5520
/****f* interfaces/is_interface_wireless
5521
 * NAME
5522
 *   is_interface_wireless - Returns if an interface is wireless
5523
 * RESULT
5524
 *   $tmp       - Returns if an interface is wireless
5525
 ******/
5526
function is_interface_wireless($interface) {
5527
	global $config, $g;
5528

    
5529
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5530
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5531
		if (preg_match($g['wireless_regex'], $interface)) {
5532
			if (isset($config['interfaces'][$friendly])) {
5533
				$config['interfaces'][$friendly]['wireless'] = array();
5534
			}
5535
			return true;
5536
		}
5537
		return false;
5538
	} else {
5539
		return true;
5540
	}
5541
}
5542

    
5543
function get_wireless_modes($interface) {
5544
	/* return wireless modes and channels */
5545
	$wireless_modes = array();
5546

    
5547
	$cloned_interface = get_real_interface($interface);
5548

    
5549
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5550
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5551
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5552
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5553

    
5554
		$interface_channels = "";
5555
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5556
		$interface_channel_count = count($interface_channels);
5557

    
5558
		$c = 0;
5559
		while ($c < $interface_channel_count) {
5560
			$channel_line = explode(",", $interface_channels["$c"]);
5561
			$wireless_mode = trim($channel_line[0]);
5562
			$wireless_channel = trim($channel_line[1]);
5563
			if (trim($wireless_mode) != "") {
5564
				/* if we only have 11g also set 11b channels */
5565
				if ($wireless_mode == "11g") {
5566
					if (!isset($wireless_modes["11b"])) {
5567
						$wireless_modes["11b"] = array();
5568
					}
5569
				} else if ($wireless_mode == "11g ht") {
5570
					if (!isset($wireless_modes["11b"])) {
5571
						$wireless_modes["11b"] = array();
5572
					}
5573
					if (!isset($wireless_modes["11g"])) {
5574
						$wireless_modes["11g"] = array();
5575
					}
5576
					$wireless_mode = "11ng";
5577
				} else if ($wireless_mode == "11a ht") {
5578
					if (!isset($wireless_modes["11a"])) {
5579
						$wireless_modes["11a"] = array();
5580
					}
5581
					$wireless_mode = "11na";
5582
				}
5583
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5584
			}
5585
			$c++;
5586
		}
5587
	}
5588
	return($wireless_modes);
5589
}
5590

    
5591
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5592
function get_wireless_channel_info($interface) {
5593
	$wireless_channels = array();
5594

    
5595
	$cloned_interface = get_real_interface($interface);
5596

    
5597
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5598
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5599
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5600
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5601

    
5602
		$interface_channels = "";
5603
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5604

    
5605
		foreach ($interface_channels as $channel_line) {
5606
			$channel_line = explode(",", $channel_line);
5607
			if (!isset($wireless_channels[$channel_line[0]])) {
5608
				$wireless_channels[$channel_line[0]] = $channel_line;
5609
			}
5610
		}
5611
	}
5612
	return($wireless_channels);
5613
}
5614

    
5615
/****f* interfaces/get_interface_mtu
5616
 * NAME
5617
 *   get_interface_mtu - Return the mtu of an interface
5618
 * RESULT
5619
 *   $tmp       - Returns the mtu of an interface
5620
 ******/
5621
function get_interface_mtu($interface) {
5622
	$mtu = pfSense_interface_getmtu($interface);
5623
	return $mtu['mtu'];
5624
}
5625

    
5626
function get_interface_mac($interface) {
5627

    
5628
	$macinfo = pfSense_get_interface_addresses($interface);
5629
	return $macinfo["macaddr"];
5630
}
5631

    
5632
/****f* pfsense-utils/generate_random_mac_address
5633
 * NAME
5634
 *   generate_random_mac - generates a random mac address
5635
 * INPUTS
5636
 *   none
5637
 * RESULT
5638
 *   $mac - a random mac address
5639
 ******/
5640
function generate_random_mac_address() {
5641
	$mac = "02";
5642
	for ($x = 0; $x < 5; $x++) {
5643
		$mac .= ":" . dechex(rand(16, 255));
5644
	}
5645
	return $mac;
5646
}
5647

    
5648
/****f* interfaces/is_jumbo_capable
5649
 * NAME
5650
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5651
 * INPUTS
5652
 *   $int             - string containing interface name
5653
 * RESULT
5654
 *   boolean          - true or false
5655
 ******/
5656
function is_jumbo_capable($iface) {
5657
	$iface = trim($iface);
5658
	$capable = pfSense_get_interface_addresses($iface);
5659

    
5660
	if (isset($capable['caps']['vlanmtu'])) {
5661
		return true;
5662
	}
5663

    
5664
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5665
	if (substr($iface, 0, 4) == "lagg") {
5666
		return true;
5667
	}
5668

    
5669
	return false;
5670
}
5671

    
5672
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5673
	global $g;
5674

    
5675
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5676

    
5677
	if (!empty($iface) && !empty($pppif)) {
5678
		$cron_cmd = <<<EOD
5679
#!/bin/sh
5680
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5681
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5682

    
5683
EOD;
5684

    
5685
		@file_put_contents($cron_file, $cron_cmd);
5686
		chmod($cron_file, 0755);
5687
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5688
	} else {
5689
		unlink_if_exists($cron_file);
5690
	}
5691
}
5692

    
5693
function get_interface_default_mtu($type = "ethernet") {
5694
	switch ($type) {
5695
		case "gre":
5696
			return 1476;
5697
			break;
5698
		case "gif":
5699
			return 1280;
5700
			break;
5701
		case "tun":
5702
		case "vlan":
5703
		case "tap":
5704
		case "ethernet":
5705
		default:
5706
			return 1500;
5707
			break;
5708
	}
5709

    
5710
	/* Never reached */
5711
	return 1500;
5712
}
5713

    
5714
function get_vip_descr($ipaddress) {
5715
	global $config;
5716

    
5717
	foreach ($config['virtualip']['vip'] as $vip) {
5718
		if ($vip['subnet'] == $ipaddress) {
5719
			return ($vip['descr']);
5720
		}
5721
	}
5722
	return "";
5723
}
5724

    
5725
function interfaces_staticarp_configure($if) {
5726
	global $config, $g;
5727
	if (isset($config['system']['developerspew'])) {
5728
		$mt = microtime();
5729
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5730
	}
5731

    
5732
	$ifcfg = $config['interfaces'][$if];
5733

    
5734
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5735
		return 0;
5736
	}
5737

    
5738
	/* Enable staticarp, if enabled */
5739
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5740
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5741
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5742
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5743
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5744
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5745
			}
5746
		}
5747
	} else {
5748
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5749
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5750
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5751
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5752
				if (isset($arpent['arp_table_static_entry'])) {
5753
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5754
				}
5755
			}
5756
		}
5757
	}
5758

    
5759
	return 0;
5760
}
5761

    
5762
function get_failover_interface($interface, $family = "all") {
5763
	global $config;
5764

    
5765
	/* shortcut to get_real_interface if we find it in the config */
5766
	if (is_array($config['interfaces'][$interface])) {
5767
		return get_real_interface($interface, $family);
5768
	}
5769

    
5770
	/* compare against gateway groups */
5771
	$a_groups = return_gateway_groups_array();
5772
	if (is_array($a_groups[$interface])) {
5773
		/* we found a gateway group, fetch the interface or vip */
5774
		if (!empty($a_groups[$interface][0]['vip'])) {
5775
			return $a_groups[$interface][0]['vip'];
5776
		} else {
5777
			return $a_groups[$interface][0]['int'];
5778
		}
5779
	}
5780
	/* fall through to get_real_interface */
5781
	/* XXX: Really needed? */
5782
	return get_real_interface($interface, $family);
5783
}
5784

    
5785
function remove_ifindex($ifname) {
5786
	return preg_replace("/[0-9]+$/", "", $ifname);
5787
}
5788

    
5789
?>
(26-26/67)