Project

General

Profile

Download (166 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['pptpd']) &&
133
	    $config['pptpd']['mode'] == "server") {
134
		$found = true;
135
	}
136
	if ($found == false && !empty($config['l2tp']) &&
137
	    $config['l2tp']['mode'] == "server") {
138
		$found = true;
139
	}
140
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
141
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
142
			if ($pppoe['mode'] != "server") {
143
				continue;
144
			}
145
			if ($pppoe['interface'] == $interface) {
146
				$found = true;
147
				break;
148
			}
149
		}
150
	}
151
	if ($found == false) {
152
		$found = interface_isppp_type($interface);
153
	}
154

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

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

    
190
function interfaces_loopback_configure() {
191
	global $g;
192

    
193
	if ($g['platform'] == 'jail') {
194
		return;
195
	}
196
	if (platform_booting()) {
197
		echo gettext("Configuring loopback interface...");
198
	}
199
	pfSense_interface_setaddress("lo0", "127.0.0.1");
200
	interfaces_bring_up("lo0");
201
	if (platform_booting()) {
202
		echo gettext("done.") . "\n";
203
	}
204
	return 0;
205
}
206

    
207
function interfaces_vlan_configure($realif = "") {
208
	global $config, $g;
209
	if (platform_booting()) {
210
		echo gettext("Configuring VLAN interfaces...");
211
	}
212
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
213
		foreach ($config['vlans']['vlan'] as $vlan) {
214
			if (empty($vlan['vlanif'])) {
215
				$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
216
			}
217
			if (!empty($realif) && $realif != $vlan['vlanif']) {
218
				continue;
219
			}
220

    
221
			/* XXX: Maybe we should report any errors?! */
222
			interface_vlan_configure($vlan);
223
		}
224
	}
225
	if (platform_booting()) {
226
		echo gettext("done.") . "\n";
227
	}
228
}
229

    
230
function interface_vlan_configure(&$vlan) {
231
	global $config, $g;
232

    
233
	if (!is_array($vlan)) {
234
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
235
		return;
236
	}
237
	$if = $vlan['if'];
238
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
239
	$tag = $vlan['tag'];
240

    
241
	if (empty($if)) {
242
		log_error(gettext("interface_vlan_configure called with if undefined."));
243
		return;
244
	}
245

    
246
	/* make sure the parent interface is up */
247
	interfaces_bring_up($if);
248
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
249
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
250

    
251
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
252
		interface_bring_down($vlanif, true);
253
	} else {
254
		$tmpvlanif = pfSense_interface_create("vlan");
255
		pfSense_interface_rename($tmpvlanif, $vlanif);
256
		pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
257
	}
258

    
259
	pfSense_vlan_create($vlanif, $if, $tag);
260

    
261
	interfaces_bring_up($vlanif);
262

    
263
	/* invalidate interface cache */
264
	get_interface_arr(true);
265

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

    
269
	return $vlanif;
270
}
271

    
272
function interface_qinq_configure(&$vlan, $fd = NULL) {
273
	global $config, $g;
274

    
275
	if (!is_array($vlan)) {
276
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
277
		return;
278
	}
279

    
280
	$qinqif = $vlan['if'];
281
	$tag = $vlan['tag'];
282
	if (empty($qinqif)) {
283
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
284
		return;
285
	}
286

    
287
	if (!does_interface_exist($qinqif)) {
288
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
289
		return;
290
	}
291

    
292
	$vlanif = interface_vlan_configure($vlan);
293

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

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

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

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

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

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

    
348
	return $vlanif;
349
}
350

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

    
367
function interface_qinq2_configure(&$qinq, $fd, $macaddr) {
368
	global $config, $g;
369

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

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

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

    
390
	/* invalidate interface cache */
391
	get_interface_arr(true);
392

    
393
	return $vlanif;
394
}
395

    
396
function interfaces_create_wireless_clones() {
397
	global $config, $g;
398

    
399
	if (platform_booting()) {
400
		echo gettext("Creating wireless clone interfaces...");
401
	}
402

    
403
	$iflist = get_configured_interface_list();
404

    
405
	foreach ($iflist as $if) {
406
		$realif = $config['interfaces'][$if]['if'];
407
		if (is_interface_wireless($realif)) {
408
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
409
		}
410
	}
411

    
412
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
413
		foreach ($config['wireless']['clone'] as $clone) {
414
			if (empty($clone['cloneif'])) {
415
				continue;
416
			}
417
			if (does_interface_exist($clone['cloneif'])) {
418
				continue;
419
			}
420
			/* XXX: Maybe we should report any errors?! */
421
			interface_wireless_clone($clone['cloneif'], $clone);
422
		}
423
	}
424
	if (platform_booting()) {
425
		echo gettext("done.") . "\n";
426
	}
427

    
428
}
429

    
430
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
431
	global $config;
432

    
433
	$i = 0;
434
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
435
		foreach ($config['bridges']['bridged'] as $bridge) {
436
			if (empty($bridge['bridgeif'])) {
437
				$bridge['bridgeif'] = "bridge{$i}";
438
			}
439
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
440
				continue;
441
			}
442

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

    
470
function interface_bridge_configure(&$bridge, $checkmember = 0) {
471
	global $config, $g;
472

    
473
	if (!is_array($bridge)) {
474
		return;
475
	}
476

    
477
	if (empty($bridge['members'])) {
478
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
479
		return;
480
	}
481

    
482
	$members = explode(',', $bridge['members']);
483
	if (!count($members)) {
484
		return;
485
	}
486

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

    
514
	/* Just in case anything is not working well */
515
	if ($smallermtu == 0) {
516
		$smallermtu = 1500;
517
	}
518

    
519
	if (platform_booting() || !empty($bridge['bridgeif'])) {
520
		pfSense_interface_destroy($bridge['bridgeif']);
521
		pfSense_interface_create($bridge['bridgeif']);
522
		$bridgeif = escapeshellarg($bridge['bridgeif']);
523
	} else {
524
		$bridgeif = pfSense_interface_create("bridge");
525
		$bridge['bridgeif'] = $bridgeif;
526
	}
527

    
528
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
529
	if ($bridgemtu > $smallermtu) {
530
		$smallermtu = $bridgemtu;
531
	}
532

    
533
	$checklist = get_configured_interface_list();
534

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

    
552
	if (isset($bridge['enablestp'])) {
553
		/* Choose spanning tree proto */
554
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
555

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

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

    
661
	if ($bridge['bridgeif']) {
662
		interfaces_bring_up($bridge['bridgeif']);
663
	} else {
664
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
665
	}
666
}
667

    
668
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
669

    
670
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
671
		return;
672
	}
673

    
674
	if ($flagsapplied == false) {
675
		$mtu = get_interface_mtu($bridgeif);
676
		$mtum = get_interface_mtu($interface);
677
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
678
			pfSense_interface_mtu($interface, $mtu);
679
		}
680

    
681
		hardware_offloading_applyflags($interface);
682
		interfaces_bring_up($interface);
683
	}
684

    
685
	pfSense_bridge_add_member($bridgeif, $interface);
686
}
687

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

    
712
function interface_lagg_configure($lagg) {
713
	global $config, $g;
714

    
715
	if (!is_array($lagg)) {
716
		return -1;
717
	}
718

    
719
	$members = explode(',', $lagg['members']);
720
	if (!count($members)) {
721
		return -1;
722
	}
723

    
724
	if (platform_booting() || !(empty($lagg['laggif']))) {
725
		pfSense_interface_destroy($lagg['laggif']);
726
		pfSense_interface_create($lagg['laggif']);
727
		$laggif = $lagg['laggif'];
728
	} else {
729
		$laggif = pfSense_interface_create("lagg");
730
	}
731

    
732
	/* Check if MTU was defined for this lagg interface */
733
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
734
	if ($lagg_mtu == 0) {
735
		/* Calculate smaller mtu and enforce it */
736
		$smallermtu = 0;
737
		foreach ($members as $member) {
738
			$mtu = get_interface_mtu($member);
739
			if ($smallermtu == 0 && !empty($mtu)) {
740
				$smallermtu = $mtu;
741
			} else if (!empty($mtu) && $mtu < $smallermtu) {
742
				$smallermtu = $mtu;
743
			}
744
		}
745
		$lagg_mtu = $smallermtu;
746
	}
747

    
748
	/* Just in case anything is not working well */
749
	if ($lagg_mtu == 0) {
750
		$lagg_mtu = 1500;
751
	}
752

    
753
	foreach ($members as $member) {
754
		if (!does_interface_exist($member)) {
755
			continue;
756
		}
757
		/* make sure the parent interface is up */
758
		pfSense_interface_mtu($member, $lagg_mtu);
759
		interfaces_bring_up($member);
760
		hardware_offloading_applyflags($member);
761
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
762
	}
763
	pfSense_interface_capabilities($laggif, -$flags_off);
764
	pfSense_interface_capabilities($laggif, $flags_on);
765

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

    
768
	interfaces_bring_up($laggif);
769

    
770
	return $laggif;
771
}
772

    
773
function interfaces_gre_configure($checkparent = 0, $realif = "") {
774
	global $config;
775

    
776
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
777
		foreach ($config['gres']['gre'] as $i => $gre) {
778
			if (empty($gre['greif'])) {
779
				$gre['greif'] = "gre{$i}";
780
			}
781
			if (!empty($realif) && $realif != $gre['greif']) {
782
				continue;
783
			}
784

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

    
807
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
808
function interface_gre_configure(&$gre, $grekey = "") {
809
	global $config, $g;
810

    
811
	if (!is_array($gre)) {
812
		return -1;
813
	}
814

    
815
	$realif = get_real_interface($gre['if']);
816
	$realifip = get_interface_ip($gre['if']);
817

    
818
	/* make sure the parent interface is up */
819
	interfaces_bring_up($realif);
820

    
821
	if (platform_booting() || !(empty($gre['greif']))) {
822
		pfSense_interface_destroy($gre['greif']);
823
		pfSense_interface_create($gre['greif']);
824
		$greif = $gre['greif'];
825
	} else {
826
		$greif = pfSense_interface_create("gre");
827
	}
828

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

    
848
	if ($greif) {
849
		interfaces_bring_up($greif);
850
	} else {
851
		log_error(gettext("Could not bring greif up -- variable not defined."));
852
	}
853

    
854
	if (isset($gre['link1']) && $gre['link1']) {
855
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
856
	}
857
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
858
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
859
	}
860
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
861
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
862
	}
863

    
864
	interfaces_bring_up($greif);
865

    
866
	return $greif;
867
}
868

    
869
function interfaces_gif_configure($checkparent = 0, $realif = "") {
870
	global $config;
871

    
872
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
873
		foreach ($config['gifs']['gif'] as $i => $gif) {
874
			if (empty($gif['gifif'])) {
875
				$gre['gifif'] = "gif{$i}";
876
			}
877
			if (!empty($realif) && $realif != $gif['gifif']) {
878
				continue;
879
			}
880

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

    
904
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
905
function interface_gif_configure(&$gif, $gifkey = "") {
906
	global $config, $g;
907

    
908
	if (!is_array($gif)) {
909
		return -1;
910
	}
911

    
912
	$realif = get_real_interface($gif['if']);
913
	$ipaddr = get_interface_ip($gif['if']);
914

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

    
937
	if (platform_booting() || !(empty($gif['gifif']))) {
938
		pfSense_interface_destroy($gif['gifif']);
939
		pfSense_interface_create($gif['gifif']);
940
		$gifif = $gif['gifif'];
941
	} else {
942
		$gifif = pfSense_interface_create("gif");
943
	}
944

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

    
966
	if (!platform_booting()) {
967
		$iflist = get_configured_interface_list();
968
		foreach ($iflist as $ifname) {
969
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
970
				if (get_interface_gateway($ifname)) {
971
					system_routing_configure($ifname);
972
					break;
973
				}
974
				if (get_interface_gateway_v6($ifname)) {
975
					system_routing_configure($ifname);
976
					break;
977
				}
978
			}
979
		}
980
	}
981

    
982

    
983
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
984
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
985
	}
986
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
987
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
988
	}
989

    
990
	if (is_ipaddrv4($realifgw)) {
991
		mwexec("/sbin/route change -host " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
992
	}
993
	if (is_ipaddrv6($realifgw)) {
994
		mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gif['remote-addr']) . " {$realifgw}");
995
	}
996

    
997
	interfaces_bring_up($gifif);
998

    
999
	return $gifif;
1000
}
1001

    
1002
function interfaces_configure() {
1003
	global $config, $g;
1004

    
1005
	if ($g['platform'] == 'jail') {
1006
		return;
1007
	}
1008

    
1009
	/* Set up our loopback interface */
1010
	interfaces_loopback_configure();
1011

    
1012
	/* create the unconfigured wireless clones */
1013
	interfaces_create_wireless_clones();
1014

    
1015
	/* set up LAGG virtual interfaces */
1016
	interfaces_lagg_configure();
1017

    
1018
	/* set up VLAN virtual interfaces */
1019
	interfaces_vlan_configure();
1020

    
1021
	interfaces_qinq_configure();
1022

    
1023
	$iflist = get_configured_interface_with_descr();
1024
	$delayed_list = array();
1025
	$bridge_list = array();
1026
	$track6_list = array();
1027

    
1028
	/* This is needed to speedup interfaces on bootup. */
1029
	$reload = false;
1030
	if (!platform_booting()) {
1031
		$reload = true;
1032
	}
1033

    
1034
	foreach ($iflist as $if => $ifname) {
1035
		$realif = $config['interfaces'][$if]['if'];
1036
		if (strstr($realif, "bridge")) {
1037
			$bridge_list[$if] = $ifname;
1038
		} else if (strstr($realif, "gre")) {
1039
			$delayed_list[$if] = $ifname;
1040
		} else if (strstr($realif, "gif")) {
1041
			$delayed_list[$if] = $ifname;
1042
		} else if (strstr($realif, "ovpn")) {
1043
			//echo "Delaying OpenVPN interface configuration...done.\n";
1044
			continue;
1045
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1046
			$track6_list[$if] = $ifname;
1047
		} else {
1048
			if (platform_booting()) {
1049
				printf(gettext("Configuring %s interface..."), $ifname);
1050
			}
1051

    
1052
			if ($g['debug']) {
1053
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1054
			}
1055
			interface_configure($if, $reload);
1056
			if (platform_booting()) {
1057
				echo gettext("done.") . "\n";
1058
			}
1059
		}
1060
	}
1061

    
1062
	/*
1063
	 * NOTE: The following function parameter consists of
1064
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1065
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1066
	 */
1067

    
1068
	/* set up GRE virtual interfaces */
1069
	interfaces_gre_configure(1);
1070

    
1071
	/* set up GIF virtual interfaces */
1072
	interfaces_gif_configure(1);
1073

    
1074
	/* set up BRIDGe virtual interfaces */
1075
	interfaces_bridge_configure(1);
1076

    
1077
	foreach ($track6_list as $if => $ifname) {
1078
		if (platform_booting()) {
1079
			printf(gettext("Configuring %s interface..."), $ifname);
1080
		}
1081
		if ($g['debug']) {
1082
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1083
		}
1084

    
1085
		interface_configure($if, $reload);
1086

    
1087
		if (platform_booting()) {
1088
			echo gettext("done.") . "\n";
1089
		}
1090
	}
1091

    
1092
	/* bring up vip interfaces */
1093
	interfaces_vips_configure();
1094

    
1095
	/* set up GRE virtual interfaces */
1096
	interfaces_gre_configure(2);
1097

    
1098
	/* set up GIF virtual interfaces */
1099
	interfaces_gif_configure(2);
1100

    
1101
	foreach ($delayed_list as $if => $ifname) {
1102
		if (platform_booting()) {
1103
			printf(gettext("Configuring %s interface..."), $ifname);
1104
		}
1105
		if ($g['debug']) {
1106
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1107
		}
1108

    
1109
		interface_configure($if, $reload);
1110

    
1111
		if (platform_booting()) {
1112
			echo gettext("done.") . "\n";
1113
		}
1114
	}
1115

    
1116
	/* set up BRIDGe virtual interfaces */
1117
	interfaces_bridge_configure(2);
1118

    
1119
	foreach ($bridge_list as $if => $ifname) {
1120
		if (platform_booting()) {
1121
			printf(gettext("Configuring %s interface..."), $ifname);
1122
		}
1123
		if ($g['debug']) {
1124
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1125
		}
1126

    
1127
		interface_configure($if, $reload);
1128

    
1129
		if (platform_booting()) {
1130
			echo gettext("done.") . "\n";
1131
		}
1132
	}
1133

    
1134
	/* configure interface groups */
1135
	interfaces_group_setup();
1136

    
1137
	if (!platform_booting()) {
1138
		/* reconfigure static routes (kernel may have deleted them) */
1139
		system_routing_configure();
1140

    
1141
		/* reload IPsec tunnels */
1142
		vpn_ipsec_configure();
1143

    
1144
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1145
		services_dhcpd_configure();
1146

    
1147
		/* restart dnsmasq or unbound */
1148
		if (isset($config['dnsmasq']['enable'])) {
1149
			services_dnsmasq_configure();
1150
		} elseif (isset($config['unbound']['enable'])) {
1151
			services_unbound_configure();
1152
		}
1153
	}
1154

    
1155
	return 0;
1156
}
1157

    
1158
function interface_reconfigure($interface = "wan", $reloadall = false) {
1159
	interface_bring_down($interface);
1160
	interface_configure($interface, $reloadall);
1161
}
1162

    
1163
function interface_vip_bring_down($vip) {
1164
	global $g;
1165

    
1166
	if (strpos($vip['interface'], '_vip')) {
1167
		if (is_ipaddrv6($vip['subnet'])) {
1168
			$family = 'inet6';
1169
		} else {
1170
			$family = 'inet';
1171
		}
1172

    
1173
		$carpvip = get_configured_carp_interface_list($vip['interface'], $family, 'vip');
1174
		$iface = $carpvip['interface'];
1175
	} else {
1176
		$iface = $vip['interface'];
1177
	}
1178

    
1179
	$vipif = get_real_interface($iface);
1180
	switch ($vip['mode']) {
1181
		case "proxyarp":
1182
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1183
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1184
			}
1185
			break;
1186
		case "ipalias":
1187
			if (does_interface_exist($vipif)) {
1188
				if (is_ipaddrv6($vip['subnet'])) {
1189
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1190
				} else {
1191
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1192
				}
1193
			}
1194
			break;
1195
		case "carp":
1196
			/* XXX: Is enough to delete ip address? */
1197
			if (does_interface_exist($vipif)) {
1198
				if (is_ipaddrv6($vip['subnet'])) {
1199
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1200
				} else {
1201
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1202
				}
1203
			}
1204
			break;
1205
	}
1206
}
1207

    
1208
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1209
	global $config, $g;
1210

    
1211
	if (!isset($config['interfaces'][$interface])) {
1212
		return;
1213
	}
1214

    
1215
	if ($g['debug']) {
1216
		log_error("Calling interface down for interface {$interface}, destroy is " . (($destroy) ? 'true' : 'false'));
1217
	}
1218

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

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

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

    
1360
	if (!empty($track6) && is_array($track6)) {
1361
		if (!function_exists('services_dhcpd_configure')) {
1362
			require_once('services.inc');
1363
		}
1364
		/* Bring down radvd and dhcp6 on these interfaces */
1365
		services_dhcpd_configure('inet6', $track6);
1366
	}
1367

    
1368
	$old_router = '';
1369
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1370
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1371
	}
1372

    
1373
	/* remove interface up file if it exists */
1374
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1375
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1376
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1377
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1378
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1379
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1380
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1381

    
1382
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1383
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1384
	if (is_array($ifcfg['wireless'])) {
1385
		kill_hostapd($realif);
1386
		mwexec(kill_wpasupplicant($realif));
1387
	}
1388

    
1389
	if ($destroy == true) {
1390
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1391
			pfSense_interface_destroy($realif);
1392
		}
1393
	}
1394

    
1395
	return;
1396
}
1397

    
1398
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1399
	global $config;
1400
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1401
		unset($config["virtualip_carp_maintenancemode"]);
1402
		write_config("Leave CARP maintenance mode");
1403
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1404
		$config["virtualip_carp_maintenancemode"] = true;
1405
		write_config("Enter CARP maintenance mode");
1406
	}
1407

    
1408
	$viparr = &$config['virtualip']['vip'];
1409
	foreach ($viparr as $vip) {
1410
		if ($vip['mode'] == "carp") {
1411
			interface_carp_configure($vip);
1412
		}
1413
	}
1414
}
1415

    
1416
function interface_isppp_type($interface) {
1417
	global $config;
1418

    
1419
	if (!is_array($config['interfaces'][$interface])) {
1420
		return false;
1421
	}
1422

    
1423
	switch ($config['interfaces'][$interface]['ipaddr']) {
1424
		case 'pptp':
1425
		case 'l2tp':
1426
		case 'pppoe':
1427
		case 'ppp':
1428
			return true;
1429
			break;
1430
		default:
1431
			return false;
1432
			break;
1433
	}
1434
}
1435

    
1436
function interfaces_ptpid_used($ptpid) {
1437
	global $config;
1438

    
1439
	if (is_array($config['ppps']['ppp'])) {
1440
		foreach ($config['ppps']['ppp'] as & $settings) {
1441
			if ($ptpid == $settings['ptpid']) {
1442
				return true;
1443
			}
1444
		}
1445
	}
1446

    
1447
	return false;
1448
}
1449

    
1450
function interfaces_ptpid_next() {
1451

    
1452
	$ptpid = 0;
1453
	while (interfaces_ptpid_used($ptpid)) {
1454
		$ptpid++;
1455
	}
1456

    
1457
	return $ptpid;
1458
}
1459

    
1460
function getMPDCRONSettings($pppif) {
1461
	global $config;
1462

    
1463
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1464
	if (is_array($config['cron']['item'])) {
1465
		foreach ($config['cron']['item'] as $i => $item) {
1466
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1467
				return array("ID" => $i, "ITEM" => $item);
1468
			}
1469
		}
1470
	}
1471

    
1472
	return NULL;
1473
}
1474

    
1475
function handle_pppoe_reset($post_array) {
1476
	global $config, $g;
1477

    
1478
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1479
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1480

    
1481
	if (!is_array($config['cron']['item'])) {
1482
		$config['cron']['item'] = array();
1483
	}
1484

    
1485
	$itemhash = getMPDCRONSettings($pppif);
1486

    
1487
	// reset cron items if necessary and return
1488
	if (empty($post_array['pppoe-reset-type'])) {
1489
		if (isset($itemhash)) {
1490
			unset($config['cron']['item'][$itemhash['ID']]);
1491
		}
1492
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1493
		return;
1494
	}
1495

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

    
1558
/*
1559
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1560
 * It writes the mpd config file to /var/etc every time the link is opened.
1561
 */
1562
function interface_ppps_configure($interface) {
1563
	global $config, $g;
1564

    
1565
	/* Return for unassigned interfaces. This is a minimum requirement. */
1566
	if (empty($config['interfaces'][$interface])) {
1567
		return 0;
1568
	}
1569
	$ifcfg = $config['interfaces'][$interface];
1570
	if (!isset($ifcfg['enable'])) {
1571
		return 0;
1572
	}
1573

    
1574
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
1575
	if (!is_dir("/var/spool/lock")) {
1576
		mkdir("/var/spool/lock", 0777, true);
1577
	}
1578
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
1579
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
1580
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
1581
	}
1582

    
1583
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1584
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1585
			if ($ifcfg['if'] == $ppp['if']) {
1586
				break;
1587
			}
1588
		}
1589
	}
1590
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
1591
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
1592
		return 0;
1593
	}
1594
	$pppif = $ifcfg['if'];
1595
	if ($ppp['type'] == "ppp") {
1596
		$type = "modem";
1597
	} else {
1598
		$type = $ppp['type'];
1599
	}
1600
	$upper_type = strtoupper($ppp['type']);
1601

    
1602
	/* XXX: This does not make sense and may create trouble
1603
	 * comment it for now to be removed later on.
1604
	if (platform_booting()) {
1605
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
1606
		echo "starting {$pppif} link...";
1607
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
1608
			return 0;
1609
	}
1610
	*/
1611

    
1612
	$ports = explode(',', $ppp['ports']);
1613
	if ($type != "modem") {
1614
		foreach ($ports as $pid => $port) {
1615
			$ports[$pid] = get_real_interface($port);
1616
			if (empty($ports[$pid])) {
1617
				return 0;
1618
			}
1619
		}
1620
	}
1621
	$localips = explode(',', $ppp['localip']);
1622
	$gateways = explode(',', $ppp['gateway']);
1623
	$subnets = explode(',', $ppp['subnet']);
1624

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

    
1648
				if (!is_ipaddr($localips[$pid])) {
1649
					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!");
1650
					$localips[$pid] = "0.0.0.0";
1651
				}
1652
				if (!is_ipaddr($gateways[$pid])) {
1653
					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));
1654
					return 0;
1655
				}
1656
				pfSense_ngctl_attach(".", $port);
1657
				break;
1658
			case "ppp":
1659
				if (!file_exists("{$port}")) {
1660
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
1661
					return 0;
1662
				}
1663
				break;
1664
			default:
1665
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
1666
				break;
1667
		}
1668
	}
1669

    
1670
	if (is_array($ports) && count($ports) > 1) {
1671
		$multilink = "enable";
1672
	} else {
1673
		$multilink = "disable";
1674
	}
1675

    
1676
	if ($type == "modem") {
1677
		if (is_ipaddr($ppp['localip'])) {
1678
			$localip = $ppp['localip'];
1679
		} else {
1680
			$localip = '0.0.0.0';
1681
		}
1682

    
1683
		if (is_ipaddr($ppp['gateway'])) {
1684
			$gateway = $ppp['gateway'];
1685
		} else {
1686
			$gateway = "10.64.64.{$pppid}";
1687
		}
1688
		$ranges = "{$localip}/0 {$gateway}/0";
1689

    
1690
		if (empty($ppp['apnum'])) {
1691
			$ppp['apnum'] = 1;
1692
		}
1693
	} else {
1694
		$ranges = "0.0.0.0/0 0.0.0.0/0";
1695
	}
1696

    
1697
	if (isset($ppp['ondemand'])) {
1698
		$ondemand = "enable";
1699
	} else {
1700
		$ondemand = "disable";
1701
	}
1702
	if (!isset($ppp['idletimeout'])) {
1703
		$ppp['idletimeout'] = 0;
1704
	}
1705

    
1706
	if (empty($ppp['username']) && $type == "modem") {
1707
		$ppp['username'] = "user";
1708
		$ppp['password'] = "none";
1709
	}
1710
	if (empty($ppp['password']) && $type == "modem") {
1711
		$passwd = "none";
1712
	} else {
1713
		$passwd = base64_decode($ppp['password']);
1714
	}
1715

    
1716
	$bandwidths = explode(',', $ppp['bandwidth']);
1717
	$defaultmtu = "1492";
1718
	if (!empty($ifcfg['mtu'])) {
1719
		$defaultmtu = intval($ifcfg['mtu']);
1720
	}
1721
	$mtus = explode(',', $ppp['mtu']);
1722
	$mrus = explode(',', $ppp['mru']);
1723

    
1724
	if (isset($ppp['mrru'])) {
1725
		$mrrus = explode(',', $ppp['mrru']);
1726
	}
1727

    
1728
	// Construct the mpd.conf file
1729
	$mpdconf = <<<EOD
1730
startup:
1731
	# configure the console
1732
	set console close
1733
	# configure the web server
1734
	set web close
1735

    
1736
default:
1737
{$ppp['type']}client:
1738
	create bundle static {$interface}
1739
	set bundle enable ipv6cp
1740
	set iface name {$pppif}
1741

    
1742
EOD;
1743
	$setdefaultgw = false;
1744
	$founddefaultgw = false;
1745
	if (is_array($config['gateways']['gateway_item'])) {
1746
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1747
			if ($interface == $gateway['interface'] && isset($gateway['defaultgw'])) {
1748
				$setdefaultgw = true;
1749
				break;
1750
			} else if (isset($gateway['defaultgw']) && !empty($gateway['interface'])) {
1751
				$founddefaultgw = true;
1752
				break;
1753
			}
1754
		}
1755
	}
1756

    
1757
	if (($interface == "wan" && $founddefaultgw == false) || $setdefaultgw == true) {
1758
		$setdefaultgw = true;
1759
		$mpdconf .= <<<EOD
1760
	set iface route default
1761

    
1762
EOD;
1763
	}
1764
	$mpdconf .= <<<EOD
1765
	set iface {$ondemand} on-demand
1766
	set iface idle {$ppp['idletimeout']}
1767

    
1768
EOD;
1769

    
1770
	if (isset($ppp['ondemand'])) {
1771
		$mpdconf .= <<<EOD
1772
	set iface addrs 10.10.1.1 10.10.1.2
1773

    
1774
EOD;
1775
	}
1776

    
1777
	if (isset($ppp['tcpmssfix'])) {
1778
		$tcpmss = "disable";
1779
	} else {
1780
		$tcpmss = "enable";
1781
	}
1782
	$mpdconf .= <<<EOD
1783
	set iface {$tcpmss} tcpmssfix
1784

    
1785
EOD;
1786

    
1787
	$mpdconf .= <<<EOD
1788
	set iface up-script /usr/local/sbin/ppp-linkup
1789
	set iface down-script /usr/local/sbin/ppp-linkdown
1790
	set ipcp ranges {$ranges}
1791

    
1792
EOD;
1793
	if (isset($ppp['vjcomp'])) {
1794
		$mpdconf .= <<<EOD
1795
	set ipcp no vjcomp
1796

    
1797
EOD;
1798
	}
1799

    
1800
	if (isset($config['system']['dnsallowoverride'])) {
1801
		$mpdconf .= <<<EOD
1802
	set ipcp enable req-pri-dns
1803
	set ipcp enable req-sec-dns
1804

    
1805
EOD;
1806
	}
1807

    
1808
	if (!isset($ppp['verbose_log'])) {
1809
		$mpdconf .= <<<EOD
1810
	#log -bund -ccp -chat -iface -ipcp -lcp -link
1811

    
1812
EOD;
1813
	}
1814

    
1815
	foreach ($ports as $pid => $port) {
1816
		$port = get_real_interface($port);
1817
		$mpdconf .= <<<EOD
1818

    
1819
	create link static {$interface}_link{$pid} {$type}
1820
	set link action bundle {$interface}
1821
	set link {$multilink} multilink
1822
	set link keep-alive 10 60
1823
	set link max-redial 0
1824

    
1825
EOD;
1826
		if (isset($ppp['shortseq'])) {
1827
			$mpdconf .= <<<EOD
1828
	set link no shortseq
1829

    
1830
EOD;
1831
		}
1832

    
1833
		if (isset($ppp['acfcomp'])) {
1834
			$mpdconf .= <<<EOD
1835
	set link no acfcomp
1836

    
1837
EOD;
1838
		}
1839

    
1840
		if (isset($ppp['protocomp'])) {
1841
			$mpdconf .= <<<EOD
1842
	set link no protocomp
1843

    
1844
EOD;
1845
		}
1846

    
1847
		$mpdconf .= <<<EOD
1848
	set link disable chap pap
1849
	set link accept chap pap eap
1850
	set link disable incoming
1851

    
1852
EOD;
1853

    
1854

    
1855
		if (!empty($bandwidths[$pid])) {
1856
			$mpdconf .= <<<EOD
1857
	set link bandwidth {$bandwidths[$pid]}
1858

    
1859
EOD;
1860
		}
1861

    
1862
		if (empty($mtus[$pid])) {
1863
			$mtus[$pid] = $defaultmtu;
1864
		}
1865
		$mpdconf .= <<<EOD
1866
	set link mtu {$mtus[$pid]}
1867

    
1868
EOD;
1869

    
1870
		if (!empty($mrus[$pid])) {
1871
			$mpdconf .= <<<EOD
1872
	set link mru {$mrus[$pid]}
1873

    
1874
EOD;
1875
		}
1876

    
1877
		if (!empty($mrrus[$pid])) {
1878
			$mpdconf .= <<<EOD
1879
	set link mrru {$mrrus[$pid]}
1880

    
1881
EOD;
1882
		}
1883

    
1884
		$mpdconf .= <<<EOD
1885
	set auth authname "{$ppp['username']}"
1886
	set auth password {$passwd}
1887

    
1888
EOD;
1889
		if ($type == "modem") {
1890
			$mpdconf .= <<<EOD
1891
	set modem device {$ppp['ports']}
1892
	set modem script DialPeer
1893
	set modem idle-script Ringback
1894
	set modem watch -cd
1895
	set modem var \$DialPrefix "DT"
1896
	set modem var \$Telephone "{$ppp['phone']}"
1897

    
1898
EOD;
1899
		}
1900
		if (isset($ppp['connect-timeout']) && $type == "modem") {
1901
			$mpdconf .= <<<EOD
1902
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
1903

    
1904
EOD;
1905
		}
1906
		if (isset($ppp['initstr']) && $type == "modem") {
1907
			$initstr = base64_decode($ppp['initstr']);
1908
			$mpdconf .= <<<EOD
1909
	set modem var \$InitString "{$initstr}"
1910

    
1911
EOD;
1912
		}
1913
		if (isset($ppp['simpin']) && $type == "modem") {
1914
			if ($ppp['pin-wait'] == "") {
1915
				$ppp['pin-wait'] = 0;
1916
			}
1917
			$mpdconf .= <<<EOD
1918
	set modem var \$SimPin "{$ppp['simpin']}"
1919
	set modem var \$PinWait "{$ppp['pin-wait']}"
1920

    
1921
EOD;
1922
		}
1923
		if (isset($ppp['apn']) && $type == "modem") {
1924
			$mpdconf .= <<<EOD
1925
	set modem var \$APN "{$ppp['apn']}"
1926
	set modem var \$APNum "{$ppp['apnum']}"
1927

    
1928
EOD;
1929
		}
1930
		if ($type == "pppoe") {
1931
			// Send a null service name if none is set.
1932
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
1933
			$mpdconf .= <<<EOD
1934
	set pppoe service "{$provider}"
1935

    
1936
EOD;
1937
		}
1938
		if ($type == "pppoe") {
1939
			$mpdconf .= <<<EOD
1940
	set pppoe iface {$port}
1941

    
1942
EOD;
1943
		}
1944

    
1945
		if ($type == "pptp" || $type == "l2tp") {
1946
			$mpdconf .= <<<EOD
1947
	set {$type} self {$localips[$pid]}
1948
	set {$type} peer {$gateways[$pid]}
1949

    
1950
EOD;
1951
		}
1952

    
1953
		$mpdconf .= "\topen\n";
1954
	} //end foreach ($port)
1955

    
1956

    
1957
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
1958
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
1959
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
1960
	} else {
1961
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
1962
		if (!$fd) {
1963
			log_error(sprintf(gettext("Error: cannot open mpd_%s.conf in interface_ppps_configure().%s"), $interface, "\n"));
1964
			return 0;
1965
		}
1966
		// Write out mpd_ppp.conf
1967
		fwrite($fd, $mpdconf);
1968
		fclose($fd);
1969
		unset($mpdconf);
1970
	}
1971

    
1972
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
1973
	if (isset($ppp['uptime'])) {
1974
		if (!file_exists("/conf/{$pppif}.log")) {
1975
			conf_mount_rw();
1976
			file_put_contents("/conf/{$pppif}.log", '');
1977
			conf_mount_ro();
1978
		}
1979
	} else {
1980
		if (file_exists("/conf/{$pppif}.log")) {
1981
			conf_mount_rw();
1982
			@unlink("/conf/{$pppif}.log");
1983
			conf_mount_ro();
1984
		}
1985
	}
1986

    
1987
	/* clean up old lock files */
1988
	foreach ($ports as $port) {
1989
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
1990
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
1991
		}
1992
	}
1993

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

    
1998
	// Check for PPPoE periodic reset request
1999
	if ($type == "pppoe") {
2000
		if (!empty($ppp['pppoe-reset-type'])) {
2001
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2002
		} else {
2003
			interface_setup_pppoe_reset_file($ppp['if']);
2004
		}
2005
	}
2006
	/* wait for upto 10 seconds for the interface to appear (ppp(oe)) */
2007
	$i = 0;
2008
	while ($i < 3) {
2009
		sleep(10);
2010
		if (does_interface_exist($ppp['if'], true)) {
2011
			break;
2012
		}
2013
		$i++;
2014
	}
2015

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

    
2036
	return 1;
2037
}
2038

    
2039
function interfaces_sync_setup() {
2040
	global $g, $config;
2041

    
2042
	if (isset($config['system']['developerspew'])) {
2043
		$mt = microtime();
2044
		echo "interfaces_sync_setup() being called $mt\n";
2045
	}
2046

    
2047
	if (platform_booting()) {
2048
		echo gettext("Configuring CARP settings...");
2049
		mute_kernel_msgs();
2050
	}
2051

    
2052
	/* suck in configuration items */
2053
	if ($config['hasync']) {
2054
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2055
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2056
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2057
	} else {
2058
		unset($pfsyncinterface);
2059
		unset($pfsyncenabled);
2060
	}
2061

    
2062
	set_sysctl(array(
2063
		"net.inet.carp.preempt" => "1",
2064
		"net.inet.carp.log" => "1")
2065
	);
2066

    
2067
	if (!empty($pfsyncinterface)) {
2068
		$carp_sync_int = get_real_interface($pfsyncinterface);
2069
	} else {
2070
		unset($carp_sync_int);
2071
	}
2072

    
2073
	/* setup pfsync interface */
2074
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2075
		if (is_ipaddr($pfsyncpeerip)) {
2076
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2077
		} else {
2078
			$syncpeer = "-syncpeer";
2079
		}
2080

    
2081
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2082
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2083

    
2084
		sleep(1);
2085

    
2086
		/* 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
2087
		 * for existing sessions.
2088
		 */
2089
		log_error("waiting for pfsync...");
2090
		$i = 0;
2091
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2092
			$i++;
2093
			sleep(1);
2094
		}
2095
		log_error("pfsync done in $i seconds.");
2096
		log_error("Configuring CARP settings finalize...");
2097
	} else {
2098
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2099
	}
2100

    
2101
	if ($config['virtualip']['vip']) {
2102
		set_single_sysctl("net.inet.carp.allow", "1");
2103
	} else {
2104
		set_single_sysctl("net.inet.carp.allow", "0");
2105
	}
2106

    
2107
	if (platform_booting()) {
2108
		unmute_kernel_msgs();
2109
		echo gettext("done.") . "\n";
2110
	}
2111
}
2112

    
2113
function interface_proxyarp_configure($interface = "") {
2114
	global $config, $g;
2115
	if (isset($config['system']['developerspew'])) {
2116
		$mt = microtime();
2117
		echo "interface_proxyarp_configure() being called $mt\n";
2118
	}
2119

    
2120
	/* kill any running choparp */
2121
	if (empty($interface)) {
2122
		killbyname("choparp");
2123
	} else {
2124
		$vipif = get_real_interface($interface);
2125
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2126
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2127
		}
2128
	}
2129

    
2130
	$paa = array();
2131
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2132

    
2133
		/* group by interface */
2134
		foreach ($config['virtualip']['vip'] as $vipent) {
2135
			if ($vipent['mode'] === "proxyarp") {
2136
				if ($vipent['interface']) {
2137
					$proxyif = $vipent['interface'];
2138
				} else {
2139
					$proxyif = "wan";
2140
				}
2141

    
2142
				if (!empty($interface) && $interface != $proxyif) {
2143
					continue;
2144
				}
2145

    
2146
				if (!is_array($paa[$proxyif])) {
2147
					$paa[$proxyif] = array();
2148
				}
2149

    
2150
				$paa[$proxyif][] = $vipent;
2151
			}
2152
		}
2153
	}
2154

    
2155
	if (!empty($interface)) {
2156
		if (is_array($paa[$interface])) {
2157
			$paaifip = get_interface_ip($interface);
2158
			if (!is_ipaddr($paaifip)) {
2159
				return;
2160
			}
2161
			$args = get_real_interface($interface) . " auto";
2162
			foreach ($paa[$interface] as $paent) {
2163
				if (isset($paent['subnet'])) {
2164
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2165
				} else if (isset($paent['range'])) {
2166
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2167
				}
2168
			}
2169
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2170
		}
2171
	} else if (count($paa) > 0) {
2172
		foreach ($paa as $paif => $paents) {
2173
			$paaifip = get_interface_ip($paif);
2174
			if (!is_ipaddr($paaifip)) {
2175
				continue;
2176
			}
2177
			$args = get_real_interface($paif) . " auto";
2178
			foreach ($paents as $paent) {
2179
				if (isset($paent['subnet'])) {
2180
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2181
				} else if (isset($paent['range'])) {
2182
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2183
				}
2184
			}
2185
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2186
		}
2187
	}
2188
}
2189

    
2190
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2191
	global $g, $config;
2192

    
2193
	if (is_array($config['virtualip']['vip'])) {
2194
		foreach ($config['virtualip']['vip'] as $vip) {
2195
			if ($vip['mode'] == "ipalias" && $vip['interface'] == $interface) {
2196
				if ($inet == "inet6" && is_ipaddrv6($vip['subnet'])) {
2197
					interface_vip_bring_down($vip);
2198
				} else if ($inet == "inet4" && is_ipaddrv4($vip['subnet'])) {
2199
					interface_vip_bring_down($vip);
2200
				}
2201
			}
2202
		}
2203
	}
2204
}
2205

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

    
2251
function interface_ipalias_configure(&$vip) {
2252
	global $config;
2253

    
2254
	if ($vip['mode'] != 'ipalias') {
2255
		return;
2256
	}
2257

    
2258
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2259
		if (!isset($config['interfaces'][$vip['interface']])) {
2260
			return;
2261
		}
2262

    
2263
		if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
2264
			return;
2265
		}
2266
	}
2267

    
2268
	$af = 'inet';
2269
	if (is_ipaddrv6($vip['subnet'])) {
2270
		$af = 'inet6';
2271
	}
2272
	$iface = $vip['interface'];
2273
	$vipadd = '';
2274
	if (strpos($vip['interface'], '_vip')) {
2275
		$carpvip = get_configured_carp_interface_list($vip['interface'], $af, 'vip');
2276
		$iface = $carpvip['interface'];
2277
		$vipadd = "vhid {$carpvip['vhid']}";
2278
	}
2279
	$if = get_real_interface($iface);
2280
	mwexec("/sbin/ifconfig " . escapeshellarg($if) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vipadd}");
2281
	unset($iface, $af, $if, $carpvip, $vipadd);
2282
}
2283

    
2284
function interface_reload_carps($cif) {
2285
	global $config;
2286

    
2287
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2288
	if (empty($carpifs)) {
2289
		return;
2290
	}
2291

    
2292
	$carps = explode(" ", $carpifs);
2293
	if (is_array($config['virtualip']['vip'])) {
2294
		$viparr = &$config['virtualip']['vip'];
2295
		foreach ($viparr as $vip) {
2296
			if (in_array($vip['carpif'], $carps)) {
2297
				switch ($vip['mode']) {
2298
					case "carp":
2299
						interface_vip_bring_down($vip);
2300
						sleep(1);
2301
						interface_carp_configure($vip);
2302
						break;
2303
					case "ipalias":
2304
						interface_vip_bring_down($vip);
2305
						sleep(1);
2306
						interface_ipalias_configure($vip);
2307
						break;
2308
				}
2309
			}
2310
		}
2311
	}
2312
}
2313

    
2314
function interface_carp_configure(&$vip) {
2315
	global $config, $g;
2316
	if (isset($config['system']['developerspew'])) {
2317
		$mt = microtime();
2318
		echo "interface_carp_configure() being called $mt\n";
2319
	}
2320

    
2321
	if ($vip['mode'] != "carp") {
2322
		return;
2323
	}
2324

    
2325
	/* NOTE: Maybe its useless nowadays */
2326
	$realif = get_real_interface($vip['interface']);
2327
	if (!does_interface_exist($realif)) {
2328
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2329
		return;
2330
	}
2331

    
2332
	$vip_password = $vip['password'];
2333
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2334
	if ($vip['password'] != "") {
2335
		$password = " pass {$vip_password}";
2336
	}
2337

    
2338
	$advbase = "";
2339
	if (!empty($vip['advbase'])) {
2340
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2341
	}
2342

    
2343
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2344
	if ($carp_maintenancemode) {
2345
		$advskew = "advskew 254";
2346
	} else {
2347
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2348
	}
2349

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

    
2352
	if (is_ipaddrv4($vip['subnet'])) {
2353
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2354
	} else if (is_ipaddrv6($vip['subnet'])) {
2355
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2356
	}
2357

    
2358
	return $realif;
2359
}
2360

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

    
2403
	if ($needs_clone == true) {
2404
		/* remove previous instance if it exists */
2405
		if (does_interface_exist($realif)) {
2406
			pfSense_interface_destroy($realif);
2407
		}
2408

    
2409
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2410
		// Create the new wlan interface. FreeBSD returns the new interface name.
2411
		// example:  wlan2
2412
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2413
		if ($ret <> 0) {
2414
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2415
			return false;
2416
		}
2417
		$newif = trim($out[0]);
2418
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2419
		pfSense_interface_rename($newif, $realif);
2420
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2421
	}
2422
	return true;
2423
}
2424

    
2425
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2426
	global $config, $g;
2427

    
2428
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2429
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2430
				 'regdomain', 'regcountry', 'reglocation');
2431

    
2432
	if (!is_interface_wireless($ifcfg['if'])) {
2433
		return;
2434
	}
2435

    
2436
	$baseif = interface_get_wireless_base($ifcfg['if']);
2437

    
2438
	// Sync shared settings for assigned clones
2439
	$iflist = get_configured_interface_list(false, true);
2440
	foreach ($iflist as $if) {
2441
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2442
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2443
				foreach ($shared_settings as $setting) {
2444
					if ($sync_changes) {
2445
						if (isset($ifcfg['wireless'][$setting])) {
2446
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2447
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2448
							unset($config['interfaces'][$if]['wireless'][$setting]);
2449
						}
2450
					} else {
2451
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2452
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2453
						} else if (isset($ifcfg['wireless'][$setting])) {
2454
							unset($ifcfg['wireless'][$setting]);
2455
						}
2456
					}
2457
				}
2458
				if (!$sync_changes) {
2459
					break;
2460
				}
2461
			}
2462
		}
2463
	}
2464

    
2465
	// Read or write settings at shared area
2466
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2467
		foreach ($shared_settings as $setting) {
2468
			if ($sync_changes) {
2469
				if (isset($ifcfg['wireless'][$setting])) {
2470
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2471
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2472
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2473
				}
2474
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2475
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2476
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2477
				} else if (isset($ifcfg['wireless'][$setting])) {
2478
					unset($ifcfg['wireless'][$setting]);
2479
				}
2480
			}
2481
		}
2482
	}
2483

    
2484
	// Sync the mode on the clone creation page with the configured mode on the interface
2485
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2486
		foreach ($config['wireless']['clone'] as &$clone) {
2487
			if ($clone['cloneif'] == $ifcfg['if']) {
2488
				if ($sync_changes) {
2489
					$clone['mode'] = $ifcfg['wireless']['mode'];
2490
				} else {
2491
					$ifcfg['wireless']['mode'] = $clone['mode'];
2492
				}
2493
				break;
2494
			}
2495
		}
2496
		unset($clone);
2497
	}
2498
}
2499

    
2500
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2501
	global $config, $g;
2502

    
2503
	/*    open up a shell script that will be used to output the commands.
2504
	 *    since wireless is changing a lot, these series of commands are fragile
2505
	 *    and will sometimes need to be verified by a operator by executing the command
2506
	 *    and returning the output of the command to the developers for inspection.  please
2507
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
2508
	 */
2509

    
2510
	// Remove script file
2511
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2512

    
2513
	// Clone wireless nic if needed.
2514
	interface_wireless_clone($if, $wl);
2515

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

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

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

    
2525
	/* set values for /path/program */
2526
	$hostapd = "/usr/sbin/hostapd";
2527
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2528
	$ifconfig = "/sbin/ifconfig";
2529
	$sysctl = "/sbin/sysctl";
2530
	$killall = "/usr/bin/killall";
2531

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

    
2534
	$wlcmd = array();
2535
	$wl_sysctl = array();
2536
	/* Make sure it's up */
2537
	$wlcmd[] = "up";
2538
	/* Set a/b/g standard */
2539
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2540
	/* skip mode entirely for "auto" */
2541
	if ($wlcfg['standard'] != "auto") {
2542
		$wlcmd[] = "mode " . escapeshellarg($standard);
2543
	}
2544

    
2545
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
2546
	 * to prevent massive packet loss under certain conditions. */
2547
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
2548
		$wlcmd[] = "-ampdu";
2549
	}
2550

    
2551
	/* Set ssid */
2552
	if ($wlcfg['ssid']) {
2553
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2554
	}
2555

    
2556
	/* Set 802.11g protection mode */
2557
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2558

    
2559
	/* set wireless channel value */
2560
	if (isset($wlcfg['channel'])) {
2561
		if ($wlcfg['channel'] == "0") {
2562
			$wlcmd[] = "channel any";
2563
		} else {
2564
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
2565
		}
2566
	}
2567

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

    
2573
	/* Set txantenna value */
2574
	if (isset($wlcfg['txantenna'])) {
2575
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
2576
	}
2577

    
2578
	/* Set rxantenna value */
2579
	if (isset($wlcfg['rxantenna'])) {
2580
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
2581
	}
2582

    
2583
	/* set Distance value */
2584
	if ($wlcfg['distance']) {
2585
		$distance = escapeshellarg($wlcfg['distance']);
2586
	}
2587

    
2588
	/* Set wireless hostap mode */
2589
	if ($wlcfg['mode'] == "hostap") {
2590
		$wlcmd[] = "mediaopt hostap";
2591
	} else {
2592
		$wlcmd[] = "-mediaopt hostap";
2593
	}
2594

    
2595
	/* Set wireless adhoc mode */
2596
	if ($wlcfg['mode'] == "adhoc") {
2597
		$wlcmd[] = "mediaopt adhoc";
2598
	} else {
2599
		$wlcmd[] = "-mediaopt adhoc";
2600
	}
2601

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

    
2604
	/* handle hide ssid option */
2605
	if (isset($wlcfg['hidessid']['enable'])) {
2606
		$wlcmd[] = "hidessid";
2607
	} else {
2608
		$wlcmd[] = "-hidessid";
2609
	}
2610

    
2611
	/* handle pureg (802.11g) only option */
2612
	if (isset($wlcfg['pureg']['enable'])) {
2613
		$wlcmd[] = "mode 11g pureg";
2614
	} else {
2615
		$wlcmd[] = "-pureg";
2616
	}
2617

    
2618
	/* handle puren (802.11n) only option */
2619
	if (isset($wlcfg['puren']['enable'])) {
2620
		$wlcmd[] = "puren";
2621
	} else {
2622
		$wlcmd[] = "-puren";
2623
	}
2624

    
2625
	/* enable apbridge option */
2626
	if (isset($wlcfg['apbridge']['enable'])) {
2627
		$wlcmd[] = "apbridge";
2628
	} else {
2629
		$wlcmd[] = "-apbridge";
2630
	}
2631

    
2632
	/* handle turbo option */
2633
	if (isset($wlcfg['turbo']['enable'])) {
2634
		$wlcmd[] = "mediaopt turbo";
2635
	} else {
2636
		$wlcmd[] = "-mediaopt turbo";
2637
	}
2638

    
2639
	/* handle txpower setting */
2640
	// or don't. this has issues at the moment.
2641
	/*
2642
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2643
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2644
	}*/
2645

    
2646
	/* handle wme option */
2647
	if (isset($wlcfg['wme']['enable'])) {
2648
		$wlcmd[] = "wme";
2649
	} else {
2650
		$wlcmd[] = "-wme";
2651
	}
2652

    
2653
	/* set up wep if enabled */
2654
	$wepset = "";
2655
	if (isset($wlcfg['wep']['enable']) && is_array($wlcfg['wep']['key'])) {
2656
		switch ($wlcfg['wpa']['auth_algs']) {
2657
			case "1":
2658
				$wepset .= "authmode open wepmode on ";
2659
				break;
2660
			case "2":
2661
				$wepset .= "authmode shared wepmode on ";
2662
				break;
2663
			case "3":
2664
				$wepset .= "authmode mixed wepmode on ";
2665
		}
2666
		$i = 1;
2667
		foreach ($wlcfg['wep']['key'] as $wepkey) {
2668
			$wepset .= "wepkey " . escapeshellarg("{$i}:{$wepkey['value']}") . " ";
2669
			if (isset($wepkey['txkey'])) {
2670
				$wlcmd[] = "weptxkey {$i} ";
2671
			}
2672
			$i++;
2673
		}
2674
		$wlcmd[] = $wepset;
2675
	} else if (isset($wlcfg['wpa']['enable'])) {
2676
		$wlcmd[] = "authmode wpa wepmode off ";
2677
	} else {
2678
		$wlcmd[] = "authmode open wepmode off ";
2679
	}
2680

    
2681
	kill_hostapd($if);
2682
	mwexec(kill_wpasupplicant("{$if}"));
2683

    
2684
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2685
	conf_mount_rw();
2686

    
2687
	switch ($wlcfg['mode']) {
2688
		case 'bss':
2689
			if (isset($wlcfg['wpa']['enable'])) {
2690
				$wpa .= <<<EOD
2691
ctrl_interface={$g['varrun_path']}/wpa_supplicant
2692
ctrl_interface_group=0
2693
ap_scan=1
2694
#fast_reauth=1
2695
network={
2696
ssid="{$wlcfg['ssid']}"
2697
scan_ssid=1
2698
priority=5
2699
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2700
psk="{$wlcfg['wpa']['passphrase']}"
2701
pairwise={$wlcfg['wpa']['wpa_pairwise']}
2702
group={$wlcfg['wpa']['wpa_pairwise']}
2703
}
2704
EOD;
2705

    
2706
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
2707
				unset($wpa);
2708
			}
2709
			break;
2710
		case 'hostap':
2711
			if (!empty($wlcfg['wpa']['passphrase'])) {
2712
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
2713
			} else {
2714
				$wpa_passphrase = "";
2715
			}
2716
			if (isset($wlcfg['wpa']['enable'])) {
2717
				$wpa .= <<<EOD
2718
interface={$if}
2719
driver=bsd
2720
logger_syslog=-1
2721
logger_syslog_level=0
2722
logger_stdout=-1
2723
logger_stdout_level=0
2724
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
2725
ctrl_interface={$g['varrun_path']}/hostapd
2726
ctrl_interface_group=wheel
2727
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
2728
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
2729
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
2730
ssid={$wlcfg['ssid']}
2731
debug={$wlcfg['wpa']['debug_mode']}
2732
auth_algs={$wlcfg['wpa']['auth_algs']}
2733
wpa={$wlcfg['wpa']['wpa_mode']}
2734
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
2735
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
2736
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
2737
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
2738
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
2739
{$wpa_passphrase}
2740

    
2741
EOD;
2742

    
2743
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2744
					$wpa .= <<<EOD
2745
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2746
rsn_preauth=1
2747
rsn_preauth_interfaces={$if}
2748

    
2749
EOD;
2750
				}
2751
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2752
					$wpa .= "ieee8021x=1\n";
2753

    
2754
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2755
						$auth_server_port = "1812";
2756
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2757
							$auth_server_port = intval($wlcfg['auth_server_port']);
2758
						}
2759
						$wpa .= <<<EOD
2760

    
2761
auth_server_addr={$wlcfg['auth_server_addr']}
2762
auth_server_port={$auth_server_port}
2763
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2764

    
2765
EOD;
2766
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2767
							$auth_server_port2 = "1812";
2768
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2769
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2770
							}
2771

    
2772
							$wpa .= <<<EOD
2773
auth_server_addr={$wlcfg['auth_server_addr2']}
2774
auth_server_port={$auth_server_port2}
2775
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2776

    
2777
EOD;
2778
						}
2779
					}
2780
				}
2781

    
2782
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2783
				unset($wpa);
2784
			}
2785
			break;
2786
	}
2787

    
2788
	/*
2789
	 *    all variables are set, lets start up everything
2790
	 */
2791

    
2792
	$baseif = interface_get_wireless_base($if);
2793
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2794
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2795

    
2796
	/* set sysctls for the wireless interface */
2797
	if (!empty($wl_sysctl)) {
2798
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2799
		foreach ($wl_sysctl as $wl_sysctl_line) {
2800
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2801
		}
2802
	}
2803

    
2804
	/* set ack timers according to users preference (if he/she has any) */
2805
	if ($distance) {
2806
		fwrite($fd_set, "# Enable ATH distance settings\n");
2807
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2808
	}
2809

    
2810
	if (isset($wlcfg['wpa']['enable'])) {
2811
		if ($wlcfg['mode'] == "bss") {
2812
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
2813
		}
2814
		if ($wlcfg['mode'] == "hostap") {
2815
			/* add line to script to restore old mac to make hostapd happy */
2816
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2817
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
2818
				if (is_macaddr($if_oldmac)) {
2819
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2820
						" link " . escapeshellarg($if_oldmac) . "\n");
2821
				}
2822
			}
2823

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

    
2826
			/* add line to script to restore spoofed mac after running hostapd */
2827
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2828
				if ($wl['spoofmac']) {
2829
					$if_curmac = $wl['spoofmac'];
2830
				} else {
2831
					$if_curmac = get_interface_mac($if);
2832
				}
2833
				if (is_macaddr($if_curmac)) {
2834
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2835
						" link " . escapeshellarg($if_curmac) . "\n");
2836
				}
2837
			}
2838
		}
2839
	}
2840

    
2841
	fclose($fd_set);
2842
	conf_mount_ro();
2843

    
2844
	/* Making sure regulatory settings have actually changed
2845
	 * before applying, because changing them requires bringing
2846
	 * down all wireless networks on the interface. */
2847
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2848
	$ifconfig_str = implode($output);
2849
	unset($output);
2850
	$reg_changing = false;
2851

    
2852
	/* special case for the debug country code */
2853
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2854
		$reg_changing = true;
2855
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2856
		$reg_changing = true;
2857
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2858
		$reg_changing = true;
2859
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2860
		$reg_changing = true;
2861
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2862
		$reg_changing = true;
2863
	}
2864

    
2865
	if ($reg_changing) {
2866
		/* set regulatory domain */
2867
		if ($wlcfg['regdomain']) {
2868
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2869
		}
2870

    
2871
		/* set country */
2872
		if ($wlcfg['regcountry']) {
2873
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2874
		}
2875

    
2876
		/* set location */
2877
		if ($wlcfg['reglocation']) {
2878
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2879
		}
2880

    
2881
		$wlregcmd_args = implode(" ", $wlregcmd);
2882

    
2883
		/* build a complete list of the wireless clones for this interface */
2884
		$clone_list = array();
2885
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2886
			$clone_list[] = interface_get_wireless_clone($baseif);
2887
		}
2888
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2889
			foreach ($config['wireless']['clone'] as $clone) {
2890
				if ($clone['if'] == $baseif) {
2891
					$clone_list[] = $clone['cloneif'];
2892
				}
2893
			}
2894
		}
2895

    
2896
		/* find which clones are up and bring them down */
2897
		$clones_up = array();
2898
		foreach ($clone_list as $clone_if) {
2899
			$clone_status = pfSense_get_interface_addresses($clone_if);
2900
			if ($clone_status['status'] == 'up') {
2901
				$clones_up[] = $clone_if;
2902
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2903
			}
2904
		}
2905

    
2906
		/* apply the regulatory settings */
2907
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2908
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2909

    
2910
		/* bring the clones back up that were previously up */
2911
		foreach ($clones_up as $clone_if) {
2912
			interfaces_bring_up($clone_if);
2913

    
2914
			/*
2915
			 * Rerun the setup script for the interface if it isn't this interface, the interface
2916
			 * is in infrastructure mode, and WPA is enabled.
2917
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
2918
			 */
2919
			if ($clone_if != $if) {
2920
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
2921
				if ((!empty($friendly_if)) &&
2922
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
2923
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
2924
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
2925
				}
2926
			}
2927
		}
2928
	}
2929

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

    
2933
	 * The mode must be specified in a separate command before ifconfig
2934
	 * will allow the mode and channel at the same time in the next. */
2935
	//mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2936
	//fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2937

    
2938
	/* configure wireless */
2939
	$wlcmd_args = implode(" ", $wlcmd);
2940
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2941
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2942
	fclose($wlan_setup_log);
2943

    
2944
	unset($wlcmd_args, $wlcmd);
2945

    
2946

    
2947
	sleep(1);
2948
	/* execute hostapd and wpa_supplicant if required in shell */
2949
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2950

    
2951
	return 0;
2952

    
2953
}
2954

    
2955
function kill_hostapd($interface) {
2956
	global $g;
2957

    
2958
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2959
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2960
	}
2961
}
2962

    
2963
function kill_wpasupplicant($interface) {
2964
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2965
}
2966

    
2967
function find_dhclient_process($interface) {
2968
	if ($interface) {
2969
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2970
	} else {
2971
		$pid = 0;
2972
	}
2973

    
2974
	return intval($pid);
2975
}
2976

    
2977
function kill_dhclient_process($interface) {
2978
	if (empty($interface) || !does_interface_exist($interface)) {
2979
		return;
2980
	}
2981

    
2982
	$i = 0;
2983
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2984
		/* 3rd time make it die for sure */
2985
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2986
		posix_kill($pid, $sig);
2987
		sleep(1);
2988
		$i++;
2989
	}
2990
	unset($i);
2991
}
2992

    
2993
function find_dhcp6c_process($interface) {
2994
	global $g;
2995

    
2996
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
2997
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2998
	} else {
2999
		return(false);
3000
	}
3001

    
3002
	return intval($pid);
3003
}
3004

    
3005
function interface_virtual_create($interface) {
3006
	global $config;
3007

    
3008
	if (strstr($interface, "_vlan")) {
3009
		interfaces_vlan_configure($vlan);
3010
	} else if (substr($interface, 0, 3) == "gre") {
3011
		interfaces_gre_configure(0, $interface);
3012
	} else if (substr($interface, 0, 3) == "gif") {
3013
		interfaces_gif_configure(0, $interface);
3014
	} else if (substr($interface, 0, 5) == "ovpns") {
3015
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3016
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3017
				if ($interface == "ovpns{$server['vpnid']}") {
3018
					if (!function_exists('openvpn_resync')) {
3019
						require_once('openvpn.inc');
3020
					}
3021
					log_error("OpenVPN: Resync server {$server['description']}");
3022
					openvpn_resync('server', $server);
3023
				}
3024
			}
3025
			unset($server);
3026
		}
3027
	} else if (substr($interface, 0, 5) == "ovpnc") {
3028
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3029
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3030
				if ($interface == "ovpnc{$client['vpnid']}") {
3031
					if (!function_exists('openvpn_resync')) {
3032
						require_once('openvpn.inc');
3033
					}
3034
					log_error("OpenVPN: Resync server {$client['description']}");
3035
					openvpn_resync('client', $client);
3036
				}
3037
			}
3038
			unset($client);
3039
		}
3040
	} else if (substr($interface, 0, 4) == "lagg") {
3041
		interfaces_lagg_configure($interface);
3042
	} else if (substr($interface, 0, 6) == "bridge") {
3043
		interfaces_bridge_configure(0, $interface);
3044
	}
3045
}
3046

    
3047
function interface_vlan_mtu_configured($realhwif, $mtu) {
3048
	global $config;
3049

    
3050
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3051
		foreach ($config['vlans']['vlan'] as $vlan) {
3052
			if ($vlan['if'] != $realhwif) {
3053
				continue;
3054
			}
3055
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3056
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3057
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
3058
					$mtu = $config['interfaces'][$assignedport]['mtu'];
3059
				}
3060
			}
3061
		}
3062
	}
3063

    
3064
	return $mtu;
3065
}
3066

    
3067
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
3068
	global $config;
3069

    
3070
	if (!is_array($vlanifs)) {
3071
		return;
3072
	}
3073

    
3074
	/* All vlans need to use the same mtu value as their parent. */
3075
	foreach ($vlanifs as $vlan) {
3076
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3077
		if (!empty($assignedport)) {
3078
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
3079
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
3080
			} else {
3081
				if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3082
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3083
				}
3084
			}
3085
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3086
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
3087
		}
3088
	}
3089
}
3090

    
3091
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3092
	global $config, $g;
3093
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3094
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3095

    
3096
	$wancfg = $config['interfaces'][$interface];
3097

    
3098
	if (!isset($wancfg['enable'])) {
3099
		return;
3100
	}
3101

    
3102
	$realif = get_real_interface($interface);
3103
	$realhwif_array = get_parent_interface($interface);
3104
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3105
	$realhwif = $realhwif_array[0];
3106

    
3107
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3108
		/* remove all IPv4 and IPv6 addresses */
3109
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3110
		if (is_array($tmpifaces)) {
3111
			foreach ($tmpifaces as $tmpiface) {
3112
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3113
					if (!is_linklocal($tmpiface)) {
3114
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3115
					}
3116
				} else {
3117
					if (is_subnetv4($tmpiface)) {
3118
						$tmpip = explode('/', $tmpiface);
3119
						$tmpip = $tmpip[0];
3120
					} else {
3121
						$tmpip = $tmpiface;
3122
					}
3123
					pfSense_interface_deladdress($realif, $tmpip);
3124
				}
3125
			}
3126
		}
3127

    
3128
		/* only bring down the interface when both v4 and v6 are set to NONE */
3129
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3130
			interface_bring_down($interface);
3131
		}
3132
	}
3133

    
3134
	$interface_to_check = $realif;
3135
	if (interface_isppp_type($interface)) {
3136
		$interface_to_check = $realhwif;
3137
	}
3138

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

    
3144
	/* Disable Accepting router advertisements unless specifically requested */
3145
	if ($g['debug']) {
3146
		log_error("Deny router advertisements for interface {$interface}");
3147
	}
3148
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3149

    
3150
	/* wireless configuration? */
3151
	if (is_array($wancfg['wireless'])) {
3152
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3153
	}
3154

    
3155
	$mac = get_interface_mac($realhwif);
3156
	/*
3157
	 * Don't try to reapply the spoofed MAC if it's already applied.
3158
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3159
	 * the interface config again, which attempts to spoof the MAC again,
3160
	 * which cycles the link again...
3161
	 */
3162
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3163
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3164
			" link " . escapeshellarg($wancfg['spoofmac']));
3165
	} else {
3166

    
3167
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3168
			/*   this is not a valid mac address.  generate a
3169
			 *   temporary mac address so the machine can get online.
3170
			 */
3171
			echo gettext("Generating new MAC address.");
3172
			$random_mac = generate_random_mac_address();
3173
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3174
				" link " . escapeshellarg($random_mac));
3175
			$wancfg['spoofmac'] = $random_mac;
3176
			write_config();
3177
			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");
3178
		}
3179
	}
3180

    
3181
	/* media */
3182
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3183
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3184
		if ($wancfg['media']) {
3185
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3186
		}
3187
		if ($wancfg['mediaopt']) {
3188
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3189
		}
3190
		mwexec($cmd);
3191
	}
3192

    
3193
	/* Apply hw offloading policies as configured */
3194
	enable_hardware_offloading($interface);
3195

    
3196
	/* invalidate interface/ip/sn cache */
3197
	get_interface_arr(true);
3198
	unset($interface_ip_arr_cache[$realif]);
3199
	unset($interface_sn_arr_cache[$realif]);
3200
	unset($interface_ipv6_arr_cache[$realif]);
3201
	unset($interface_snv6_arr_cache[$realif]);
3202

    
3203
	$tunnelif = substr($realif, 0, 3);
3204

    
3205
	if (does_interface_exist($wancfg['if'])) {
3206
		interfaces_bring_up($wancfg['if']);
3207
	}
3208

    
3209
	if (!empty($wancfg['mtu'])) {
3210
		if (stristr($realif, "_vlan")) {
3211
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3212
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3213
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3214
				if ($wancfg['mtu'] > $parentmtu) {
3215
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
3216
				}
3217
			} else {
3218
				$parentmtu = 0;
3219
			}
3220

    
3221
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
3222

    
3223
			if (get_interface_mtu($realhwif) != $parentmtu) {
3224
				pfSense_interface_mtu($realhwif, $parentmtu);
3225
			}
3226

    
3227
			/* All vlans need to use the same mtu value as their parent. */
3228
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
3229
		} else if (substr($realif, 0, 4) == 'lagg') {
3230
			/* LAGG interface must be destroyed and re-created to change MTU */
3231
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3232
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3233
					foreach ($config['laggs']['lagg'] as $lagg) {
3234
						if ($lagg['laggif'] == $realif) {
3235
							interface_lagg_configure($lagg);
3236
							break;
3237
						}
3238
					}
3239
				}
3240
			}
3241
		} else {
3242
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3243
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3244
			}
3245

    
3246
			/* This case is needed when the parent of vlans is being configured */
3247
			$vlans = link_interface_to_vlans($realif);
3248
			if (is_array($vlans)) {
3249
				interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
3250
			}
3251
			unset($vlans);
3252
		}
3253
		/* XXX: What about gre/gif/.. ? */
3254
	}
3255

    
3256
	switch ($wancfg['ipaddr']) {
3257
		case 'dhcp':
3258
			interface_dhcp_configure($interface);
3259
			break;
3260
		case 'pppoe':
3261
		case 'l2tp':
3262
		case 'pptp':
3263
		case 'ppp':
3264
			interface_ppps_configure($interface);
3265
			break;
3266
		default:
3267
			/* XXX: Kludge for now related to #3280 */
3268
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3269
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3270
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3271
				}
3272
			}
3273
			break;
3274
	}
3275

    
3276
	switch ($wancfg['ipaddrv6']) {
3277
		case 'slaac':
3278
		case 'dhcp6':
3279
			interface_dhcpv6_configure($interface, $wancfg);
3280
			break;
3281
		case '6rd':
3282
			interface_6rd_configure($interface, $wancfg);
3283
			break;
3284
		case '6to4':
3285
			interface_6to4_configure($interface, $wancfg);
3286
			break;
3287
		case 'track6':
3288
			interface_track6_configure($interface, $wancfg, $linkupevent);
3289
			break;
3290
		default:
3291
			/* XXX: Kludge for now related to #3280 */
3292
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3293
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3294
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3295
					// FIXME: Add IPv6 Support to the pfSense module
3296
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3297
				}
3298
			}
3299
			break;
3300
	}
3301

    
3302
	interface_netgraph_needed($interface);
3303

    
3304
	if (!platform_booting()) {
3305
		link_interface_to_vips($interface, "update");
3306

    
3307
		if ($tunnelif != 'gre') {
3308
			unset($gre);
3309
			$gre = link_interface_to_gre($interface);
3310
			if (!empty($gre)) {
3311
				array_walk($gre, 'interface_gre_configure');
3312
			}
3313
		}
3314

    
3315
		if ($tunnelif != 'gif') {
3316
			unset($gif);
3317
			$gif = link_interface_to_gif ($interface);
3318
			if (!empty($gif)) {
3319
				array_walk($gif, 'interface_gif_configure');
3320
			}
3321
		}
3322

    
3323
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3324
			unset($bridgetmp);
3325
			$bridgetmp = link_interface_to_bridge($interface);
3326
			if (!empty($bridgetmp)) {
3327
				interface_bridge_add_member($bridgetmp, $realif);
3328
			}
3329
		}
3330

    
3331
		$grouptmp = link_interface_to_group($interface);
3332
		if (!empty($grouptmp)) {
3333
			array_walk($grouptmp, 'interface_group_add_member');
3334
		}
3335

    
3336
		if ($interface == "lan") {
3337
			/* make new hosts file */
3338
			system_hosts_generate();
3339
		}
3340

    
3341
		if ($reloadall == true) {
3342

    
3343
			/* reconfigure static routes (kernel may have deleted them) */
3344
			system_routing_configure($interface);
3345

    
3346
			/* reload ipsec tunnels */
3347
			send_event("service reload ipsecdns");
3348

    
3349
			/* restart dnsmasq or unbound */
3350
			if (isset($config['dnsmasq']['enable'])) {
3351
				services_dnsmasq_configure();
3352
			} elseif (isset($config['unbound']['enable'])) {
3353
				services_unbound_configure();
3354
			}
3355

    
3356
			/* update dyndns */
3357
			send_event("service reload dyndns {$interface}");
3358

    
3359
			/* reload captive portal */
3360
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3361
				require_once('captiveportal.inc');
3362
			}
3363
			captiveportal_init_rules_byinterface($interface);
3364
		}
3365
	}
3366

    
3367
	interfaces_staticarp_configure($interface);
3368
	return 0;
3369
}
3370

    
3371
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3372
	global $config, $g;
3373

    
3374
	if (!is_array($wancfg)) {
3375
		return;
3376
	}
3377

    
3378
	if (!isset($wancfg['enable'])) {
3379
		return;
3380
	}
3381

    
3382
	/* If the interface is not configured via another, exit */
3383
	if (empty($wancfg['track6-interface'])) {
3384
		return;
3385
	}
3386

    
3387
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3388
	$realif = get_real_interface($interface);
3389
	$linklocal = find_interface_ipv6_ll($realif);
3390
	if (!empty($linklocal)) {
3391
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3392
	}
3393
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3394
	/* XXX: Probably should remove? */
3395
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3396

    
3397
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3398
	if (!isset($trackcfg['enable'])) {
3399
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3400
		return;
3401
	}
3402

    
3403
	switch ($trackcfg['ipaddrv6']) {
3404
		case "6to4":
3405
			if ($g['debug']) {
3406
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3407
			}
3408
			interface_track6_6to4_configure($interface, $wancfg);
3409
			break;
3410
		case "6rd":
3411
			if ($g['debug']) {
3412
				log_error("Interface {$interface} configured via {$wancfg['track6-interface']}  type {$type}");
3413
			}
3414
			interface_track6_6rd_configure($interface, $wancfg);
3415
			break;
3416
		case "dhcp6":
3417
			if ($linkupevent == true) {
3418
				/*
3419
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
3420
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
3421
				 *
3422
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
3423
				 */
3424
				$parentrealif = get_real_interface($wancfg['track6-interface']);
3425
				$pidv6 = find_dhcp6c_process($parentrealif);
3426
				if ($pidv6) {
3427
					posix_kill($pidv6, SIGHUP);
3428
				}
3429
			}
3430
			break;
3431
	}
3432

    
3433
	if ($linkupevent == false) {
3434
		if (!function_exists('services_dhcpd_configure')) {
3435
			require_once("services.inc");
3436
		}
3437

    
3438
		if (isset($config['unbound']['enable'])) {
3439
			services_unbound_configure();
3440
		}
3441

    
3442
		services_dhcpd_configure("inet6");
3443
	}
3444

    
3445
	return 0;
3446
}
3447

    
3448
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3449
	global $config, $g;
3450
	global $interface_ipv6_arr_cache;
3451
	global $interface_snv6_arr_cache;
3452

    
3453
	if (!is_array($lancfg)) {
3454
		return;
3455
	}
3456

    
3457
	/* If the interface is not configured via another, exit */
3458
	if (empty($lancfg['track6-interface'])) {
3459
		return;
3460
	}
3461

    
3462
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3463
	if (empty($wancfg)) {
3464
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3465
		return;
3466
	}
3467

    
3468
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3469
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3470
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3471
		return;
3472
	}
3473
	$hexwanv4 = return_hex_ipv4($ip4address);
3474

    
3475
	/* create the long prefix notation for math, save the prefix length */
3476
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3477
	$rd6prefixlen = $rd6prefix[1];
3478
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3479

    
3480
	/* binary presentation of the prefix for all 128 bits. */
3481
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3482

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

    
3488
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3489
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3490
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3491
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3492
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3493
	/* fill the rest out with zeros */
3494
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3495

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

    
3499
	$lanif = get_real_interface($interface);
3500
	$oip = find_interface_ipv6($lanif);
3501
	if (is_ipaddrv6($oip)) {
3502
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3503
	}
3504
	unset($interface_ipv6_arr_cache[$lanif]);
3505
	unset($interface_snv6_arr_cache[$lanif]);
3506
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3507
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3508

    
3509
	return 0;
3510
}
3511

    
3512
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3513
	global $config, $g;
3514
	global $interface_ipv6_arr_cache;
3515
	global $interface_snv6_arr_cache;
3516

    
3517
	if (!is_array($lancfg)) {
3518
		return;
3519
	}
3520

    
3521
	/* If the interface is not configured via another, exit */
3522
	if (empty($lancfg['track6-interface'])) {
3523
		return;
3524
	}
3525

    
3526
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3527
	if (empty($wancfg)) {
3528
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3529
		return;
3530
	}
3531

    
3532
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3533
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3534
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3535
		return;
3536
	}
3537
	$hexwanv4 = return_hex_ipv4($ip4address);
3538

    
3539
	/* create the long prefix notation for math, save the prefix length */
3540
	$sixto4prefix = "2002::";
3541
	$sixto4prefixlen = 16;
3542
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3543

    
3544
	/* binary presentation of the prefix for all 128 bits. */
3545
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3546

    
3547
	/* just save the left prefix length bits */
3548
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3549
	/* add the v4 address */
3550
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3551
	/* add the custom prefix id */
3552
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3553
	/* fill the rest out with zeros */
3554
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3555

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

    
3559
	$lanif = get_real_interface($interface);
3560
	$oip = find_interface_ipv6($lanif);
3561
	if (is_ipaddrv6($oip)) {
3562
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3563
	}
3564
	unset($interface_ipv6_arr_cache[$lanif]);
3565
	unset($interface_snv6_arr_cache[$lanif]);
3566
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3567
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3568

    
3569
	return 0;
3570
}
3571

    
3572
function interface_6rd_configure($interface = "wan", $wancfg) {
3573
	global $config, $g;
3574

    
3575
	/* because this is a tunnel interface we can only function
3576
	 *	with a public IPv4 address on the interface */
3577

    
3578
	if (!is_array($wancfg)) {
3579
		return;
3580
	}
3581

    
3582
	if (!is_module_loaded('if_stf.ko')) {
3583
		mwexec('/sbin/kldload if_stf.ko');
3584
	}
3585

    
3586
	$wanif = get_real_interface($interface);
3587
	$ip4address = find_interface_ip($wanif);
3588
	if (!is_ipaddrv4($ip4address)) {
3589
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3590
		return false;
3591
	}
3592
	$hexwanv4 = return_hex_ipv4($ip4address);
3593

    
3594
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3595
		$wancfg['prefix-6rd-v4plen'] = 0;
3596
	}
3597

    
3598
	/* create the long prefix notation for math, save the prefix length */
3599
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3600
	$rd6prefixlen = $rd6prefix[1];
3601
	$brgw = explode('.', $wancfg['gateway-6rd']);
3602
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3603
	$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);
3604
	if (strlen($rd6brgw) < 128) {
3605
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3606
	}
3607
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3608
	unset($brgw);
3609
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3610

    
3611
	/* binary presentation of the prefix for all 128 bits. */
3612
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3613

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

    
3621
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3622
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3623

    
3624

    
3625
	/* XXX: need to extend to support variable prefix size for v4 */
3626
	if (!is_module_loaded("if_stf")) {
3627
		mwexec("/sbin/kldload if_stf.ko");
3628
	}
3629
	$stfiface = "{$interface}_stf";
3630
	if (does_interface_exist($stfiface)) {
3631
		pfSense_interface_destroy($stfiface);
3632
	}
3633
	$tmpstfiface = pfSense_interface_create("stf");
3634
	pfSense_interface_rename($tmpstfiface, $stfiface);
3635
	pfSense_interface_flags($stfiface, IFF_LINK2);
3636
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3637
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3638
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3639
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3640
	}
3641
	if ($g['debug']) {
3642
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3643
	}
3644

    
3645
	/* write out a default router file */
3646
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3647
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3648

    
3649
	$ip4gateway = get_interface_gateway($interface);
3650
	if (is_ipaddrv4($ip4gateway)) {
3651
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3652
	}
3653

    
3654
	/* configure dependent interfaces */
3655
	if (!platform_booting()) {
3656
		link_interface_to_track6($interface, "update");
3657
	}
3658

    
3659
	return 0;
3660
}
3661

    
3662
function interface_6to4_configure($interface = "wan", $wancfg) {
3663
	global $config, $g;
3664

    
3665
	/* because this is a tunnel interface we can only function
3666
	 *	with a public IPv4 address on the interface */
3667

    
3668
	if (!is_array($wancfg)) {
3669
		return;
3670
	}
3671

    
3672
	$wanif = get_real_interface($interface);
3673
	$ip4address = find_interface_ip($wanif);
3674
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3675
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3676
		return false;
3677
	}
3678

    
3679
	/* create the long prefix notation for math, save the prefix length */
3680
	$stfprefixlen = 16;
3681
	$stfprefix = Net_IPv6::uncompress("2002::");
3682
	$stfarr = explode(":", $stfprefix);
3683
	$v4prefixlen = "0";
3684

    
3685
	/* we need the hex form of the interface IPv4 address */
3686
	$ip4arr = explode(".", $ip4address);
3687
	$hexwanv4 = "";
3688
	foreach ($ip4arr as $octet) {
3689
		$hexwanv4 .= sprintf("%02x", $octet);
3690
	}
3691

    
3692
	/* we need the hex form of the broker IPv4 address */
3693
	$ip4arr = explode(".", "192.88.99.1");
3694
	$hexbrv4 = "";
3695
	foreach ($ip4arr as $octet) {
3696
		$hexbrv4 .= sprintf("%02x", $octet);
3697
	}
3698

    
3699
	/* binary presentation of the prefix for all 128 bits. */
3700
	$stfprefixbin = "";
3701
	foreach ($stfarr as $element) {
3702
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3703
	}
3704
	/* just save the left prefix length bits */
3705
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3706

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

    
3711
	/* for the local subnet too. */
3712
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3713
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3714

    
3715
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3716
	$stfbrarr = array();
3717
	$stfbrbinarr = array();
3718
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3719
	foreach ($stfbrbinarr as $bin) {
3720
		$stfbrarr[] = dechex(bindec($bin));
3721
	}
3722
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3723

    
3724
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3725
	$stflanarr = array();
3726
	$stflanbinarr = array();
3727
	$stflanbinarr = str_split($stflanbin, 16);
3728
	foreach ($stflanbinarr as $bin) {
3729
		$stflanarr[] = dechex(bindec($bin));
3730
	}
3731
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3732
	$stflanarr[7] = 1;
3733
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3734

    
3735
	/* setup the stf interface */
3736
	if (!is_module_loaded("if_stf")) {
3737
		mwexec("/sbin/kldload if_stf.ko");
3738
	}
3739
	$stfiface = "{$interface}_stf";
3740
	if (does_interface_exist($stfiface)) {
3741
		pfSense_interface_destroy($stfiface);
3742
	}
3743
	$tmpstfiface = pfSense_interface_create("stf");
3744
	pfSense_interface_rename($tmpstfiface, $stfiface);
3745
	pfSense_interface_flags($stfiface, IFF_LINK2);
3746
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3747

    
3748
	if ($g['debug']) {
3749
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3750
	}
3751

    
3752
	/* write out a default router file */
3753
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3754
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3755

    
3756
	$ip4gateway = get_interface_gateway($interface);
3757
	if (is_ipaddrv4($ip4gateway)) {
3758
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3759
	}
3760

    
3761
	if (!platform_booting()) {
3762
		link_interface_to_track6($interface, "update");
3763
	}
3764

    
3765
	return 0;
3766
}
3767

    
3768
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3769
	global $config, $g;
3770

    
3771
	if (!is_array($wancfg)) {
3772
		return;
3773
	}
3774

    
3775
	$wanif = get_real_interface($interface, "inet6");
3776
	$dhcp6cconf = "";
3777

    
3778
	if ($wancfg['adv_dhcp6_config_file_override']) {
3779
		// DHCP6 Config File Override
3780
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3781
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
3782
		// DHCP6 Config File Advanced
3783
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3784
	} else {
3785
		// DHCP6 Config File Basic
3786
		$dhcp6cconf .= "interface {$wanif} {\n";
3787

    
3788
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3789
		if ($wancfg['ipaddrv6'] == "slaac") {
3790
			$dhcp6cconf .= "\tinformation-only;\n";
3791
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3792
			$dhcp6cconf .= "\trequest domain-name;\n";
3793
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3794
			$dhcp6cconf .= "};\n";
3795
		} else {
3796
			$trackiflist = array();
3797
			$iflist = link_interface_to_track6($interface);
3798
			foreach ($iflist as $ifname => $ifcfg) {
3799
				if (is_numeric($ifcfg['track6-prefix-id'])) {
3800
					$trackiflist[$ifname] = $ifcfg;
3801
				}
3802
			}
3803

    
3804
			/* skip address request if this is set */
3805
			if (!isset($wancfg['dhcp6prefixonly'])) {
3806
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
3807
			}
3808
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3809
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
3810
			}
3811

    
3812
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
3813
			$dhcp6cconf .= "\trequest domain-name;\n";
3814
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3815
			$dhcp6cconf .= "};\n";
3816

    
3817
			if (!isset($wancfg['dhcp6prefixonly'])) {
3818
				$dhcp6cconf .= "id-assoc na 0 { };\n";
3819
			}
3820

    
3821
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3822
				/* Setup the prefix delegation */
3823
				$dhcp6cconf .= "id-assoc pd 0 {\n";
3824
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3825
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3826
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
3827
				}
3828
				foreach ($trackiflist as $friendly => $ifcfg) {
3829
					if ($g['debug']) {
3830
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3831
					}
3832
					$realif = get_real_interface($friendly);
3833
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
3834
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
3835
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3836
					$dhcp6cconf .= "\t};\n";
3837
				}
3838
				unset($preflen, $iflist, $ifcfg, $ifname);
3839
				$dhcp6cconf .= "};\n";
3840
			}
3841
			unset($trackiflist);
3842
		}
3843
	}
3844

    
3845
	/* wide-dhcp6c works for now. */
3846
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3847
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3848
		unset($dhcp6cconf);
3849
		return 1;
3850
	}
3851
	unset($dhcp6cconf);
3852

    
3853
	$dhcp6cscript = "#!/bin/sh\n";
3854
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
3855
	$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
3856
	$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
3857
	$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
3858
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3859
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
3860
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3861
		unset($dhcp6cscript);
3862
		return 1;
3863
	}
3864
	unset($dhcp6cscript);
3865
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
3866

    
3867
	$rtsoldscript = "#!/bin/sh\n";
3868
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
3869
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
3870
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
3871
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Recieved RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
3872
	$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
3873
	$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
3874
	$rtsoldscript .= "\t/bin/sleep 1\n";
3875
	$rtsoldscript .= "fi\n";
3876
	$rtsoldscript .= "/usr/local/sbin/dhcp6c -d -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
3877
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
3878
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
3879
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
3880
		printf("Error: cannot open rtsold_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
3881
		unset($rtsoldscript);
3882
		return 1;
3883
	}
3884
	unset($rtsoldscript);
3885
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
3886

    
3887
	/* accept router advertisements for this interface */
3888
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3889
	log_error("Accept router advertisements on interface {$wanif} ");
3890
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3891

    
3892
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3893
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3894
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3895
		sleep(2);
3896
	}
3897
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3898

    
3899
	/* NOTE: will be called from rtsold invoked script
3900
	 * link_interface_to_track6($interface, "update");
3901
	 */
3902

    
3903
	return 0;
3904
}
3905

    
3906
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3907
	global $g;
3908

    
3909
	$send_options = "";
3910
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3911
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
3912
		foreach ($options as $option) {
3913
			$send_options .= "\tsend " . trim($option) . ";\n";
3914
		}
3915
	}
3916

    
3917
	$request_options = "";
3918
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3919
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
3920
		foreach ($options as $option) {
3921
			$request_options .= "\trequest " . trim($option) . ";\n";
3922
		}
3923
	}
3924

    
3925
	$information_only = "";
3926
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
3927
		$information_only = "\tinformation-only;\n";
3928
	}
3929

    
3930
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3931
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
3932
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3933
	}
3934

    
3935
	$interface_statement  = "interface";
3936
	$interface_statement .= " {$wanif}";
3937
	$interface_statement .= " {\n";
3938
	$interface_statement .= "$send_options";
3939
	$interface_statement .= "$request_options";
3940
	$interface_statement .= "$information_only";
3941
	$interface_statement .= "$script";
3942
	$interface_statement .= "};\n";
3943

    
3944
	$id_assoc_statement_address = "";
3945
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3946
		$id_assoc_statement_address .= "id-assoc";
3947
		$id_assoc_statement_address .= " na";
3948
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
3949
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3950
		}
3951
		$id_assoc_statement_address .= " { ";
3952

    
3953
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
3954
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
3955
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
3956
			$id_assoc_statement_address .= "\n\taddress";
3957
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3958
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3959
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
3960
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
3961
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3962
			}
3963
			$id_assoc_statement_address .= ";\n";
3964
		}
3965

    
3966
		$id_assoc_statement_address .= "};\n";
3967
	}
3968

    
3969
	$id_assoc_statement_prefix = "";
3970
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3971
		$id_assoc_statement_prefix .= "id-assoc";
3972
		$id_assoc_statement_prefix .= " pd";
3973
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
3974
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3975
		}
3976
		$id_assoc_statement_prefix .= " { ";
3977

    
3978
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
3979
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
3980
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
3981
			$id_assoc_statement_prefix .= "\n\tprefix";
3982
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3983
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3984
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
3985
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
3986
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3987
			}
3988
			$id_assoc_statement_prefix .= ";";
3989
		}
3990

    
3991
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3992
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3993
			$id_assoc_statement_prefix .= " {$wanif}";
3994
			$id_assoc_statement_prefix .= " {\n";
3995
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3996
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
3997
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
3998
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3999
			}
4000
			$id_assoc_statement_prefix .= "\t};";
4001
		}
4002

    
4003
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4004
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4005
			$id_assoc_statement_prefix .= "\n";
4006
		}
4007

    
4008
		$id_assoc_statement_prefix .= "};\n";
4009
	}
4010

    
4011
	$authentication_statement = "";
4012
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4013
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4014
		$authentication_statement .= "authentication";
4015
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4016
		$authentication_statement .= " {\n";
4017
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4018
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4019
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4020
		}
4021
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4022
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4023
		}
4024
		$authentication_statement .= "};\n";
4025
	}
4026

    
4027
	$key_info_statement = "";
4028
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4029
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4030
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4031
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4032
		$key_info_statement .= "keyinfo";
4033
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4034
		$key_info_statement .= " {\n";
4035
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4036
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4037
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4038
		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'])) {
4039
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4040
		}
4041
		$key_info_statement .= "};\n";
4042
	}
4043

    
4044
	$dhcp6cconf  = $interface_statement;
4045
	$dhcp6cconf .= $id_assoc_statement_address;
4046
	$dhcp6cconf .= $id_assoc_statement_prefix;
4047
	$dhcp6cconf .= $authentication_statement;
4048
	$dhcp6cconf .= $key_info_statement;
4049

    
4050
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4051

    
4052
	return $dhcp6cconf;
4053
}
4054

    
4055

    
4056
function DHCP6_Config_File_Override($wancfg, $wanif) {
4057

    
4058
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4059

    
4060
	if ($dhcp6cconf === false) {
4061
		log_error("Error: cannot open {$wancfg['adv_dhcp6_config_file_override_path']} in DHCP6_Config_File_Override() for reading.\n");
4062
		return '';
4063
	} else {
4064
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4065
	}
4066
}
4067

    
4068

    
4069
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4070

    
4071
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4072

    
4073
	return $dhcp6cconf;
4074
}
4075

    
4076

    
4077
function interface_dhcp_configure($interface = "wan") {
4078
	global $config, $g;
4079

    
4080
	$wancfg = $config['interfaces'][$interface];
4081
	$wanif = $wancfg['if'];
4082
	if (empty($wancfg)) {
4083
		$wancfg = array();
4084
	}
4085

    
4086
	/* generate dhclient_wan.conf */
4087
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4088
	if (!$fd) {
4089
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
4090
		return 1;
4091
	}
4092

    
4093
	if ($wancfg['dhcphostname']) {
4094
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4095
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4096
	} else {
4097
		$dhclientconf_hostname = "";
4098
	}
4099

    
4100
	$wanif = get_real_interface($interface);
4101
	if (empty($wanif)) {
4102
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4103
		return 0;
4104
	}
4105
	$dhclientconf = "";
4106

    
4107
	$dhclientconf .= <<<EOD
4108
interface "{$wanif}" {
4109
timeout 60;
4110
retry 15;
4111
select-timeout 0;
4112
initial-interval 1;
4113
	{$dhclientconf_hostname}
4114
	script "/sbin/dhclient-script";
4115
EOD;
4116

    
4117
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4118
		$dhclientconf .= <<<EOD
4119

    
4120
	reject {$wancfg['dhcprejectfrom']};
4121
EOD;
4122
	}
4123
	$dhclientconf .= <<<EOD
4124

    
4125
}
4126

    
4127
EOD;
4128

    
4129
	// DHCP Config File Advanced
4130
	if ($wancfg['adv_dhcp_config_advanced']) {
4131
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4132
	}
4133

    
4134
	if (is_ipaddr($wancfg['alias-address'])) {
4135
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4136
		$dhclientconf .= <<<EOD
4137
alias {
4138
	interface "{$wanif}";
4139
	fixed-address {$wancfg['alias-address']};
4140
	option subnet-mask {$subnetmask};
4141
}
4142

    
4143
EOD;
4144
	}
4145

    
4146
	// DHCP Config File Override
4147
	if ($wancfg['adv_dhcp_config_file_override']) {
4148
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4149
	}
4150

    
4151
	fwrite($fd, $dhclientconf);
4152
	fclose($fd);
4153

    
4154
	/* bring wan interface up before starting dhclient */
4155
	if ($wanif) {
4156
		interfaces_bring_up($wanif);
4157
	} else {
4158
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4159
	}
4160

    
4161
	/* Make sure dhclient is not running */
4162
	kill_dhclient_process($wanif);
4163

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

    
4167
	return 0;
4168
}
4169

    
4170
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4171

    
4172
	$hostname = "";
4173
	if ($wancfg['dhcphostname'] != '') {
4174
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4175
	}
4176

    
4177
	/* DHCP Protocol Timings */
4178
	$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");
4179
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4180
		$pt_variable = "{$Protocol_Timing}";
4181
		${$pt_variable} = "";
4182
		if ($wancfg[$Protocol_Timing] != "") {
4183
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4184
		}
4185
	}
4186

    
4187
	$send_options = "";
4188
	if ($wancfg['adv_dhcp_send_options'] != '') {
4189
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4190
		foreach ($options as $option) {
4191
			$send_options .= "\tsend " . trim($option) . ";\n";
4192
		}
4193
	}
4194

    
4195
	$request_options = "";
4196
	if ($wancfg['adv_dhcp_request_options'] != '') {
4197
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4198
	}
4199

    
4200
	$required_options = "";
4201
	if ($wancfg['adv_dhcp_required_options'] != '') {
4202
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4203
	}
4204

    
4205
	$option_modifiers = "";
4206
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4207
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4208
		foreach ($modifiers as $modifier) {
4209
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4210
		}
4211
	}
4212

    
4213
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4214
	$dhclientconf .= "\n";
4215
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4216
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4217
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4218
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4219
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4220
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4221
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4222
	$dhclientconf .= "\n";
4223
	$dhclientconf .= "# DHCP Protocol Options\n";
4224
	$dhclientconf .= "{$hostname}";
4225
	$dhclientconf .= "{$send_options}";
4226
	$dhclientconf .= "{$request_options}";
4227
	$dhclientconf .= "{$required_options}";
4228
	$dhclientconf .= "{$option_modifiers}";
4229
	$dhclientconf .= "\n";
4230
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4231
	$dhclientconf .= "}\n";
4232

    
4233
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4234

    
4235
	return $dhclientconf;
4236
}
4237

    
4238

    
4239
function DHCP_Config_File_Override($wancfg, $wanif) {
4240

    
4241
	$dhclientconf = @file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4242

    
4243
	if ($dhclientconf === false) {
4244
		log_error("Error: cannot open {$wancfg['adv_dhcp_config_file_override_path']} in DHCP_Config_File_Override() for reading.\n");
4245
		return '';
4246
	} else {
4247
		return DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4248
	}
4249
}
4250

    
4251

    
4252
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4253

    
4254
	/* Apply Interface Substitutions */
4255
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4256

    
4257
	/* Apply Hostname Substitutions */
4258
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4259

    
4260
	/* Arrays of MAC Address Types, Cases, Delimiters */
4261
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4262
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4263
	$various_mac_cases      = array("U", "L");
4264
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4265

    
4266
	/* Apply MAC Address Substitutions */
4267
	foreach ($various_mac_types as $various_mac_type) {
4268
		foreach ($various_mac_cases as $various_mac_case) {
4269
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4270

    
4271
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4272
				if ($res !== false) {
4273

    
4274
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4275
					if ("$various_mac_case" == "U") {
4276
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4277
					}
4278
					if ("$various_mac_case" == "L") {
4279
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4280
					}
4281

    
4282
					if ("$various_mac_type" == "mac_addr_hex") {
4283
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4284
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4285
						$dhcpclientconf_mac_hex = "";
4286
						$delimiter = "";
4287
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4288
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4289
							$delimiter = ":";
4290
						}
4291
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4292
					}
4293

    
4294
					/* MAC Address Delimiter Substitutions */
4295
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4296

    
4297
					/* Apply MAC Address Substitutions */
4298
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4299
				}
4300
			}
4301
		}
4302
	}
4303

    
4304
	return $dhclientconf;
4305
}
4306

    
4307
function interfaces_group_setup() {
4308
	global $config;
4309

    
4310
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4311
		return;
4312
	}
4313

    
4314
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4315
		interface_group_setup($groupar);
4316
	}
4317

    
4318
	return;
4319
}
4320

    
4321
function interface_group_setup(&$groupname /* The parameter is an array */) {
4322
	global $config;
4323

    
4324
	if (!is_array($groupname)) {
4325
		return;
4326
	}
4327
	$members = explode(" ", $groupname['members']);
4328
	foreach ($members as $ifs) {
4329
		$realif = get_real_interface($ifs);
4330
		if ($realif && does_interface_exist($realif)) {
4331
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4332
		}
4333
	}
4334

    
4335
	return;
4336
}
4337

    
4338
function is_interface_group($if) {
4339
	global $config;
4340

    
4341
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4342
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4343
			if ($groupentry['ifname'] === $if) {
4344
				return true;
4345
			}
4346
		}
4347
	}
4348

    
4349
	return false;
4350
}
4351

    
4352
function interface_group_add_member($interface, $groupname) {
4353
	$interface = get_real_interface($interface);
4354
	if (does_interface_exist($interface)) {
4355
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4356
	}
4357
}
4358

    
4359
/* COMPAT Function */
4360
function convert_friendly_interface_to_real_interface_name($interface) {
4361
	return get_real_interface($interface);
4362
}
4363

    
4364
/* COMPAT Function */
4365
function get_real_wan_interface($interface = "wan") {
4366
	return get_real_interface($interface);
4367
}
4368

    
4369
/* COMPAT Function */
4370
function get_current_wan_address($interface = "wan") {
4371
	return get_interface_ip($interface);
4372
}
4373

    
4374
/*
4375
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4376
 */
4377
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4378
	global $config;
4379

    
4380
	if (stripos($interface, "_vip")) {
4381
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4382
			if ($vip['mode'] == "carp") {
4383
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4384
					return $vip['interface'];
4385
				}
4386
			}
4387
		}
4388
	}
4389

    
4390
	/* XXX: For speed reasons reference directly the interface array */
4391
	$ifdescrs = &$config['interfaces'];
4392
	//$ifdescrs = get_configured_interface_list(false, true);
4393

    
4394
	foreach ($ifdescrs as $if => $ifname) {
4395
		if ($if == $interface || $ifname['if'] == $interface) {
4396
			return $if;
4397
		}
4398

    
4399
		if (get_real_interface($if) == $interface) {
4400
			return $if;
4401
		}
4402

    
4403
		if ($checkparent == false) {
4404
			continue;
4405
		}
4406

    
4407
		$int = get_parent_interface($if, true);
4408
		if (is_array($int)) {
4409
			foreach ($int as $iface) {
4410
				if ($iface == $interface) {
4411
					return $if;
4412
				}
4413
			}
4414
		}
4415
	}
4416

    
4417
	if ($interface == "enc0") {
4418
		return 'IPsec';
4419
	}
4420
}
4421

    
4422
/* attempt to resolve interface to friendly descr */
4423
function convert_friendly_interface_to_friendly_descr($interface) {
4424
	global $config;
4425

    
4426
	switch ($interface) {
4427
		case "l2tp":
4428
			$ifdesc = "L2TP";
4429
			break;
4430
		case "pptp":
4431
			$ifdesc = "PPTP";
4432
			break;
4433
		case "pppoe":
4434
			$ifdesc = "PPPoE";
4435
			break;
4436
		case "openvpn":
4437
			$ifdesc = "OpenVPN";
4438
			break;
4439
		case "enc0":
4440
		case "ipsec":
4441
		case "IPsec":
4442
			$ifdesc = "IPsec";
4443
			break;
4444
		default:
4445
			if (isset($config['interfaces'][$interface])) {
4446
				if (empty($config['interfaces'][$interface]['descr'])) {
4447
					$ifdesc = strtoupper($interface);
4448
				} else {
4449
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4450
				}
4451
				break;
4452
			} else if (substr($interface, 0, 4) == '_vip') {
4453
				if (is_array($config['virtualip']['vip'])) {
4454
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4455
						if ($vip['mode'] == "carp") {
4456
							if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4457
								return "{$vip['subnet']} - {$vip['descr']}";
4458
							}
4459
						}
4460
					}
4461
				}
4462
			} else if (substr($interface, 0, 5) == '_lloc') {
4463
				return get_interface_linklocal($interface);
4464
			} else {
4465
				/* if list */
4466
				$ifdescrs = get_configured_interface_with_descr(false, true);
4467
				foreach ($ifdescrs as $if => $ifname) {
4468
					if ($if == $interface || $ifname == $interface) {
4469
						return $ifname;
4470
					}
4471
				}
4472
			}
4473
			break;
4474
	}
4475

    
4476
	return $ifdesc;
4477
}
4478

    
4479
function convert_real_interface_to_friendly_descr($interface) {
4480

    
4481
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4482

    
4483
	if (!empty($ifdesc)) {
4484
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4485
	}
4486

    
4487
	return $interface;
4488
}
4489

    
4490
/*
4491
 *  get_parent_interface($interface):
4492
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4493
 *				or virtual interface (i.e. vlan)
4494
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4495
 *			-- returns $interface passed in if $interface parent is not found
4496
 *			-- returns empty array if an invalid interface is passed
4497
 *	(Only handles ppps and vlans now.)
4498
 */
4499
function get_parent_interface($interface, $avoidrecurse = false) {
4500
	global $config;
4501

    
4502
	$parents = array();
4503
	//Check that we got a valid interface passed
4504
	$realif = get_real_interface($interface);
4505
	if ($realif == NULL) {
4506
		return $parents;
4507
	}
4508

    
4509
	// If we got a real interface, find it's friendly assigned name
4510
	if ($interface == $realif && $avoidrecurse == false) {
4511
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4512
	}
4513

    
4514
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4515
		$ifcfg = $config['interfaces'][$interface];
4516
		switch ($ifcfg['ipaddr']) {
4517
			case "ppp":
4518
			case "pppoe":
4519
			case "pptp":
4520
			case "l2tp":
4521
				if (empty($parents)) {
4522
					if (is_array($config['ppps']['ppp'])) {
4523
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4524
							if ($ifcfg['if'] == $ppp['if']) {
4525
								$ports = explode(',', $ppp['ports']);
4526
								foreach ($ports as $pid => $parent_if) {
4527
									$parents[$pid] = get_real_interface($parent_if);
4528
								}
4529
								break;
4530
							}
4531
						}
4532
					}
4533
				}
4534
				break;
4535
			case "dhcp":
4536
			case "static":
4537
			default:
4538
				// Handle _vlans
4539
				if (strpos($realif, '_vlan') !== FALSE) {
4540
					if (is_array($config['vlans']['vlan'])) {
4541
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4542
							if ($ifcfg['if'] == $vlan['vlanif']) {
4543
								$parents[0] = $vlan['if'];
4544
								break;
4545
							}
4546
						}
4547
					}
4548
				}
4549
				break;
4550
		}
4551
	}
4552

    
4553
	if (empty($parents)) {
4554
		$parents[0] = $realif;
4555
	}
4556

    
4557
	return $parents;
4558
}
4559

    
4560
function interface_is_wireless_clone($wlif) {
4561
	if (!stristr($wlif, "_wlan")) {
4562
		return false;
4563
	} else {
4564
		return true;
4565
	}
4566
}
4567

    
4568
function interface_get_wireless_base($wlif) {
4569
	if (!stristr($wlif, "_wlan")) {
4570
		return $wlif;
4571
	} else {
4572
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4573
	}
4574
}
4575

    
4576
function interface_get_wireless_clone($wlif) {
4577
	if (!stristr($wlif, "_wlan")) {
4578
		return $wlif . "_wlan0";
4579
	} else {
4580
		return $wlif;
4581
	}
4582
}
4583

    
4584
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4585
	global $config, $g;
4586

    
4587
	$wanif = NULL;
4588

    
4589
	switch ($interface) {
4590
		case "l2tp":
4591
			$wanif = "l2tp";
4592
			break;
4593
		case "pptp":
4594
			$wanif = "pptp";
4595
			break;
4596
		case "pppoe":
4597
			$wanif = "pppoe";
4598
			break;
4599
		case "openvpn":
4600
			$wanif = "openvpn";
4601
			break;
4602
		case "ipsec":
4603
		case "enc0":
4604
			$wanif = "enc0";
4605
			break;
4606
		case "ppp":
4607
			$wanif = "ppp";
4608
			break;
4609
		default:
4610
			if (substr($interface, 0, 4) == '_vip') {
4611
				$wanif = get_configured_carp_interface_list($interface, '', 'iface');
4612
				if (!empty($wanif)) {
4613
					$wanif = get_real_interface($wanif, $family);
4614
				}
4615
				break;
4616
			} else if (substr($interface, 0, 5) == '_lloc') {
4617
				$interface = substr($interface, 5);
4618
			} else if (does_interface_exist($interface, $flush)) {
4619
				/*
4620
				 * If a real interface was already passed simply
4621
				 * pass the real interface back.  This encourages
4622
				 * the usage of this function in more cases so that
4623
				 * we can combine logic for more flexibility.
4624
				 */
4625
				$wanif = $interface;
4626
				break;
4627
			}
4628

    
4629
			if (empty($config['interfaces'][$interface])) {
4630
				break;
4631
			}
4632

    
4633
			$cfg = &$config['interfaces'][$interface];
4634

    
4635
			if ($family == "inet6") {
4636
				switch ($cfg['ipaddrv6']) {
4637
					case "6rd":
4638
					case "6to4":
4639
						$wanif = "{$interface}_stf";
4640
						break;
4641
					case 'pppoe':
4642
					case 'ppp':
4643
					case 'l2tp':
4644
					case 'pptp':
4645
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4646
							$wanif = interface_get_wireless_clone($cfg['if']);
4647
						} else {
4648
							$wanif = $cfg['if'];
4649
						}
4650
						break;
4651
					default:
4652
						switch ($cfg['ipaddr']) {
4653
							case 'pppoe':
4654
							case 'ppp':
4655
							case 'l2tp':
4656
							case 'pptp':
4657
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4658
									$wanif = $cfg['if'];
4659
								} else {
4660
									$parents = get_parent_interface($interface);
4661
									if (!empty($parents[0])) {
4662
										$wanif = $parents[0];
4663
									} else {
4664
										$wanif = $cfg['if'];
4665
									}
4666
								}
4667
								break;
4668
							default:
4669
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4670
									$wanif = interface_get_wireless_clone($cfg['if']);
4671
								} else {
4672
									$wanif = $cfg['if'];
4673
								}
4674
								break;
4675
						}
4676
						break;
4677
				}
4678
			} else {
4679
				// Wireless cloned NIC support (FreeBSD 8+)
4680
				// interface name format: $parentnic_wlanparentnic#
4681
				// example: ath0_wlan0
4682
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4683
					$wanif = interface_get_wireless_clone($cfg['if']);
4684
				} else {
4685
					$wanif = $cfg['if'];
4686
				}
4687
			}
4688
			break;
4689
	}
4690

    
4691
	return $wanif;
4692
}
4693

    
4694
/* Guess the physical interface by providing a IP address */
4695
function guess_interface_from_ip($ipaddress) {
4696

    
4697
	$family = '';
4698
	if (is_ipaddrv4($ipaddress)) {
4699
		$family = 'inet';
4700
	}
4701
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4702
		$family = 'inet6';
4703
	}
4704

    
4705
	if (empty($family)) {
4706
		return false;
4707
	}
4708

    
4709
	/* create a route table we can search */
4710
	$output = '';
4711
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4712
	$output[0] = trim($output[0], " \n");
4713
	if (!empty($output[0])) {
4714
		return $output[0];
4715
	}
4716

    
4717
	return false;
4718
}
4719

    
4720
/*
4721
 * find_ip_interface($ip): return the interface where an ip is defined
4722
 *   (or if $bits is specified, where an IP within the subnet is defined)
4723
 */
4724
function find_ip_interface($ip, $bits = null) {
4725
	if (!is_ipaddr($ip)) {
4726
		return false;
4727
	}
4728

    
4729
	$isv6ip = is_ipaddrv6($ip);
4730

    
4731
	/* if list */
4732
	$ifdescrs = get_configured_interface_list();
4733

    
4734
	foreach ($ifdescrs as $ifdescr => $ifname) {
4735
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4736
		if (is_null($ifip)) {
4737
			continue;
4738
		}
4739
		if (is_null($bits)) {
4740
			if ($ip == $ifip) {
4741
				$int = get_real_interface($ifname);
4742
				return $int;
4743
			}
4744
		} else {
4745
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4746
				$int = get_real_interface($ifname);
4747
				return $int;
4748
			}
4749
		}
4750
	}
4751

    
4752
	return false;
4753
}
4754

    
4755
/*
4756
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4757
 *   (or if $bits is specified, where an IP within the subnet is found)
4758
 */
4759
function find_virtual_ip_alias($ip, $bits = null) {
4760
	global $config;
4761

    
4762
	if (!is_array($config['virtualip']['vip'])) {
4763
		return false;
4764
	}
4765
	if (!is_ipaddr($ip)) {
4766
		return false;
4767
	}
4768

    
4769
	$isv6ip = is_ipaddrv6($ip);
4770

    
4771
	foreach ($config['virtualip']['vip'] as $vip) {
4772
		if ($vip['mode'] === "ipalias") {
4773
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4774
				continue;
4775
			}
4776
			if (is_null($bits)) {
4777
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4778
					return $vip;
4779
				}
4780
			} else {
4781
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4782
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4783
					return $vip;
4784
				}
4785
			}
4786
		}
4787
	}
4788
	return false;
4789
}
4790

    
4791
/*
4792
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4793
 */
4794
function find_number_of_created_carp_interfaces() {
4795
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4796
}
4797

    
4798
/*
4799
 * find_carp_interface($ip): return the carp interface where an ip is defined
4800
 */
4801
function find_carp_interface($ip) {
4802
	global $config;
4803
	if (is_array($config['virtualip']['vip'])) {
4804
		foreach ($config['virtualip']['vip'] as $vip) {
4805
			if ($vip['mode'] == "carp") {
4806
				if (is_ipaddrv4($ip)) {
4807
					$carp_ip = get_interface_ip($vip['interface']);
4808
				}
4809
				if (is_ipaddrv6($ip)) {
4810
					$carp_ip = get_interface_ipv6($vip['interface']);
4811
				}
4812
				exec("/sbin/ifconfig", $output, $return);
4813
				foreach ($output as $line) {
4814
					$elements = preg_split("/[ ]+/i", $line);
4815
					if (strstr($elements[0], "vip")) {
4816
						$curif = str_replace(":", "", $elements[0]);
4817
					}
4818
					if (stristr($line, $ip)) {
4819
						$if = $curif;
4820
						continue;
4821
					}
4822
				}
4823

    
4824
				if ($if) {
4825
					return $if;
4826
				}
4827
			}
4828
		}
4829
	}
4830
}
4831

    
4832
function link_carp_interface_to_parent($interface) {
4833
	global $config;
4834

    
4835
	if (empty($interface)) {
4836
		return;
4837
	}
4838

    
4839
	$carp_ip = get_interface_ip($interface);
4840
	$carp_ipv6 = get_interface_ipv6($interface);
4841

    
4842
	if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
4843
		return;
4844
	}
4845

    
4846
	/* if list */
4847
	$ifdescrs = get_configured_interface_list();
4848
	foreach ($ifdescrs as $ifdescr => $ifname) {
4849
		/* check IPv4 */
4850
		if (is_ipaddrv4($carp_ip)) {
4851
			$interfaceip = get_interface_ip($ifname);
4852
			$subnet_bits = get_interface_subnet($ifname);
4853
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4854
			if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
4855
				return $ifname;
4856
			}
4857
		}
4858
		/* Check IPv6 */
4859
		if (is_ipaddrv6($carp_ipv6)) {
4860
			$interfaceipv6 = get_interface_ipv6($ifname);
4861
			$prefixlen = get_interface_subnetv6($ifname);
4862
			if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
4863
				return $ifname;
4864
			}
4865
		}
4866
	}
4867
	return "";
4868
}
4869

    
4870

    
4871
/****f* interfaces/link_ip_to_carp_interface
4872
 * NAME
4873
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4874
 * INPUTS
4875
 *   $ip
4876
 * RESULT
4877
 *   $carp_ints
4878
 ******/
4879
function link_ip_to_carp_interface($ip) {
4880
	global $config;
4881

    
4882
	if (!is_ipaddr($ip)) {
4883
		return;
4884
	}
4885

    
4886
	$carp_ints = "";
4887
	if (is_array($config['virtualip']['vip'])) {
4888
		$first = 0;
4889
		$carp_int = array();
4890
		foreach ($config['virtualip']['vip'] as $vip) {
4891
			if ($vip['mode'] == "carp") {
4892
				$carp_ip = $vip['subnet'];
4893
				$carp_sn = $vip['subnet_bits'];
4894
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4895
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4896
					$carp_int[] = get_real_interface($vip['interface']);
4897
				}
4898
			}
4899
		}
4900
		if (!empty($carp_int)) {
4901
			$carp_ints = implode(" ", array_unique($carp_int));
4902
		}
4903
	}
4904

    
4905
	return $carp_ints;
4906
}
4907

    
4908
function link_interface_to_track6($int, $action = "") {
4909
	global $config;
4910

    
4911
	if (empty($int)) {
4912
		return;
4913
	}
4914

    
4915
	if (is_array($config['interfaces'])) {
4916
		$list = array();
4917
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4918
			if (!isset($ifcfg['enable'])) {
4919
				continue;
4920
			}
4921
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4922
				if ($action == "update") {
4923
					interface_track6_configure($ifname, $ifcfg);
4924
				} else if ($action == "") {
4925
					$list[$ifname] = $ifcfg;
4926
				}
4927
			}
4928
		}
4929
		return $list;
4930
	}
4931
}
4932

    
4933
function interface_find_child_cfgmtu($realiface) {
4934
	global $config;
4935

    
4936
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4937
	$vlans = link_interface_to_vlans($realiface);
4938
	$bridge = link_interface_to_bridge($realiface);
4939
	if (!empty($interface)) {
4940
		$gifs = link_interface_to_gif($interface);
4941
		$gres = link_interface_to_gre($interface);
4942
	} else {
4943
		$gifs = array();
4944
		$gres = array();
4945
	}
4946

    
4947
	$mtu = 0;
4948
	if (is_array($vlans)) {
4949
		foreach ($vlans as $vlan) {
4950
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4951
			if (empty($ifass)) {
4952
				continue;
4953
			}
4954
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4955
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4956
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4957
				}
4958
			}
4959
		}
4960
	}
4961
	if (is_array($gifs)) {
4962
		foreach ($gifs as $vlan) {
4963
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4964
			if (empty($ifass)) {
4965
				continue;
4966
			}
4967
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4968
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4969
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4970
				}
4971
			}
4972
		}
4973
	}
4974
	if (is_array($gres)) {
4975
		foreach ($gres as $vlan) {
4976
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4977
			if (empty($ifass)) {
4978
				continue;
4979
			}
4980
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4981
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4982
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4983
				}
4984
			}
4985
		}
4986
	}
4987
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4988
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4989
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4990
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4991
		}
4992
	}
4993
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4994

    
4995
	return $mtu;
4996
}
4997

    
4998
function link_interface_to_vlans($int, $action = "") {
4999
	global $config;
5000

    
5001
	if (empty($int)) {
5002
		return;
5003
	}
5004

    
5005
	if (is_array($config['vlans']['vlan'])) {
5006
		$ifaces = array();
5007
		foreach ($config['vlans']['vlan'] as $vlan) {
5008
			if ($int == $vlan['if']) {
5009
				if ($action == "update") {
5010
					interfaces_bring_up($int);
5011
				} else {
5012
					$ifaces[$vlan['tag']] = $vlan;
5013
				}
5014
			}
5015
		}
5016
		if (!empty($ifaces)) {
5017
			return $ifaces;
5018
		}
5019
	}
5020
}
5021

    
5022
function link_interface_to_vips($int, $action = "", $vhid = '') {
5023
	global $config;
5024

    
5025
	if (is_array($config['virtualip']['vip'])) {
5026
		$result = array();
5027
		foreach ($config['virtualip']['vip'] as $vip) {
5028
			if ($int == $vip['interface']) {
5029
				if ($action == "update") {
5030
					interfaces_vips_configure($int);
5031
				} else {
5032
					if (empty($vhid) || ($vhid == $vip['vhid'])) {
5033
						$result[] = $vip;
5034
					}
5035
				}
5036
			}
5037
		}
5038
		return $result;
5039
	}
5040
}
5041

    
5042
/****f* interfaces/link_interface_to_bridge
5043
 * NAME
5044
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5045
 * INPUTS
5046
 *   $ip
5047
 * RESULT
5048
 *   bridge[0-99]
5049
 ******/
5050
function link_interface_to_bridge($int) {
5051
	global $config;
5052

    
5053
	if (is_array($config['bridges']['bridged'])) {
5054
		foreach ($config['bridges']['bridged'] as $bridge) {
5055
			if (in_array($int, explode(',', $bridge['members']))) {
5056
				return "{$bridge['bridgeif']}";
5057
			}
5058
		}
5059
	}
5060
}
5061

    
5062
function link_interface_to_group($int) {
5063
	global $config;
5064

    
5065
	$result = array();
5066

    
5067
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5068
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5069
			if (in_array($int, explode(" ", $group['members']))) {
5070
				$result[$group['ifname']] = $int;
5071
			}
5072
		}
5073
	}
5074

    
5075
	return $result;
5076
}
5077

    
5078
function link_interface_to_gre($interface) {
5079
	global $config;
5080

    
5081
	$result = array();
5082

    
5083
	if (is_array($config['gres']['gre'])) {
5084
		foreach ($config['gres']['gre'] as $gre) {
5085
			if ($gre['if'] == $interface) {
5086
				$result[] = $gre;
5087
			}
5088
		}
5089
	}
5090

    
5091
	return $result;
5092
}
5093

    
5094
function link_interface_to_gif($interface) {
5095
	global $config;
5096

    
5097
	$result = array();
5098

    
5099
	if (is_array($config['gifs']['gif'])) {
5100
		foreach ($config['gifs']['gif'] as $gif) {
5101
			if ($gif['if'] == $interface) {
5102
				$result[] = $gif;
5103
			}
5104
		}
5105
	}
5106

    
5107
	return $result;
5108
}
5109

    
5110
/*
5111
 * find_interface_ip($interface): return the interface ip (first found)
5112
 */
5113
function find_interface_ip($interface, $flush = false) {
5114
	global $interface_ip_arr_cache;
5115
	global $interface_sn_arr_cache;
5116

    
5117
	$interface = str_replace("\n", "", $interface);
5118

    
5119
	if (!does_interface_exist($interface)) {
5120
		return;
5121
	}
5122

    
5123
	/* Setup IP cache */
5124
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5125
		$ifinfo = pfSense_get_interface_addresses($interface);
5126
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5127
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5128
	}
5129

    
5130
	return $interface_ip_arr_cache[$interface];
5131
}
5132

    
5133
/*
5134
 * find_interface_ipv6($interface): return the interface ip (first found)
5135
 */
5136
function find_interface_ipv6($interface, $flush = false) {
5137
	global $interface_ipv6_arr_cache;
5138
	global $interface_snv6_arr_cache;
5139
	global $config;
5140

    
5141
	$interface = trim($interface);
5142
	$interface = get_real_interface($interface);
5143

    
5144
	if (!does_interface_exist($interface)) {
5145
		return;
5146
	}
5147

    
5148
	/* Setup IP cache */
5149
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5150
		$ifinfo = pfSense_get_interface_addresses($interface);
5151
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5152
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5153
	}
5154

    
5155
	return $interface_ipv6_arr_cache[$interface];
5156
}
5157

    
5158
/*
5159
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5160
 */
5161
function find_interface_ipv6_ll($interface, $flush = false) {
5162
	global $interface_llv6_arr_cache;
5163
	global $config;
5164

    
5165
	$interface = str_replace("\n", "", $interface);
5166

    
5167
	if (!does_interface_exist($interface)) {
5168
		return;
5169
	}
5170

    
5171
	/* Setup IP cache */
5172
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5173
		$ifinfo = pfSense_getall_interface_addresses($interface);
5174
		foreach ($ifinfo as $line) {
5175
			if (strstr($line, ":")) {
5176
				$parts = explode("/", $line);
5177
				if (is_linklocal($parts[0])) {
5178
					$ifinfo['linklocal'] = $parts[0];
5179
				}
5180
			}
5181
		}
5182
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5183
	}
5184
	return $interface_llv6_arr_cache[$interface];
5185
}
5186

    
5187
function find_interface_subnet($interface, $flush = false) {
5188
	global $interface_sn_arr_cache;
5189
	global $interface_ip_arr_cache;
5190

    
5191
	$interface = str_replace("\n", "", $interface);
5192
	if (does_interface_exist($interface) == false) {
5193
		return;
5194
	}
5195

    
5196
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5197
		$ifinfo = pfSense_get_interface_addresses($interface);
5198
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5199
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5200
	}
5201

    
5202
	return $interface_sn_arr_cache[$interface];
5203
}
5204

    
5205
function find_interface_subnetv6($interface, $flush = false) {
5206
	global $interface_snv6_arr_cache;
5207
	global $interface_ipv6_arr_cache;
5208

    
5209
	$interface = str_replace("\n", "", $interface);
5210
	if (does_interface_exist($interface) == false) {
5211
		return;
5212
	}
5213

    
5214
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5215
		$ifinfo = pfSense_get_interface_addresses($interface);
5216
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5217
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5218
	}
5219

    
5220
	return $interface_snv6_arr_cache[$interface];
5221
}
5222

    
5223
function ip_in_interface_alias_subnet($interface, $ipalias) {
5224
	global $config;
5225

    
5226
	if (empty($interface) || !is_ipaddr($ipalias)) {
5227
		return false;
5228
	}
5229
	if (is_array($config['virtualip']['vip'])) {
5230
		foreach ($config['virtualip']['vip'] as $vip) {
5231
			switch ($vip['mode']) {
5232
				case "ipalias":
5233
					if ($vip['interface'] <> $interface) {
5234
						break;
5235
					}
5236
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5237
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5238
						return true;
5239
					}
5240
					break;
5241
			}
5242
		}
5243
	}
5244

    
5245
	return false;
5246
}
5247

    
5248
function get_possible_listen_ips($include_ipv6_link_local=false) {
5249

    
5250
	$interfaces = get_configured_interface_with_descr();
5251
	foreach ($interfaces as $iface => $ifacename) {
5252
		if ($include_ipv6_link_local) {
5253
			/* This is to avoid going though added ll below */
5254
			if (substr($iface, 0, 5) == '_lloc') {
5255
				continue;
5256
			}
5257
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5258
			if (!empty($llip)) {
5259
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5260
			}
5261
		}
5262
	}
5263
	/* XXX: Maybe use array_merge below? */
5264
	$carplist = get_configured_carp_interface_list();
5265
	foreach ($carplist as $cif => $carpip) {
5266
		$interfaces[$cif] = $carpip . ' (' . get_vip_descr($carpip) . ')';
5267
	}
5268
	$aliaslist = get_configured_ip_aliases_list();
5269
	foreach ($aliaslist as $aliasip => $aliasif) {
5270
		$interfaces[$aliasip] = $aliasip . ' (' . get_vip_descr($aliasip) . ')';
5271
	}
5272

    
5273
	$interfaces['lo0'] = 'Localhost';
5274

    
5275
	return $interfaces;
5276
}
5277

    
5278
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5279
	global $config;
5280

    
5281
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5282
	foreach (array('server', 'client') as $mode) {
5283
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5284
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5285
				if (!isset($setting['disable'])) {
5286
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5287
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
5288
				}
5289
			}
5290
		}
5291
	}
5292
	return $sourceips;
5293
}
5294

    
5295
function get_interface_ip($interface = "wan") {
5296

    
5297
	$realif = get_failover_interface($interface);
5298
	if (!$realif) {
5299
		return null;
5300
	}
5301

    
5302
	if (substr($realif, 0, 4) == '_vip') {
5303
		return get_configured_carp_interface_list($realif, 'inet', 'ip');
5304
	}
5305
	
5306
	if (strstr($realif, "_vip")) {
5307
		return get_configured_carp_interface_list($realif);
5308
	}
5309

    
5310
	$curip = find_interface_ip($realif);
5311
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5312
		return $curip;
5313
	} else {
5314
		return null;
5315
	}
5316
}
5317

    
5318
function get_interface_ipv6($interface = "wan", $flush = false) {
5319
	global $config;
5320

    
5321
	$realif = get_failover_interface($interface, 'inet6');
5322
	if (!$realif) {
5323
		return null;
5324
	}
5325

    
5326
	if (substr($realif, 0, 4) == '_vip') {
5327
		return get_configured_carp_interface_list($realif, 'inet6', 'ip');
5328
	} else if (substr($realif, 0, 5) == '_lloc') {
5329
		return get_interface_linklocal($interface);
5330
	}
5331

    
5332
	if (is_array($config['interfaces'][$interface])) {
5333
		switch ($config['interfaces'][$interface]['ipaddr']) {
5334
			case 'pppoe':
5335
			case 'l2tp':
5336
			case 'pptp':
5337
			case 'ppp':
5338
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5339
					$realif = get_real_interface($interface, 'inet6', true);
5340
				}
5341
				break;
5342
		}
5343
	}
5344

    
5345
	$curip = find_interface_ipv6($realif, $flush);
5346
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5347
		return $curip;
5348
	} else {
5349
		/*
5350
		 * NOTE: On the case when only the prefix is requested,
5351
		 * the communication on WAN will be done over link-local.
5352
		 */
5353
		if (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5354
			$curip = find_interface_ipv6_ll($realif, $flush);
5355
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5356
				return $curip;
5357
			}
5358
		}
5359
	}
5360
	return null;
5361
}
5362

    
5363
function get_interface_linklocal($interface = "wan") {
5364

    
5365
	$realif = get_failover_interface($interface, 'inet6');
5366
	if (!$realif) {
5367
		return null;
5368
	}
5369

    
5370
	if (substr($interface, 0, 4) == '_vip') {
5371
		$realif = get_real_interface($interface);
5372
	} else if (substr($interface, 0, 5) == '_lloc') {
5373
		$realif = get_real_interface(substr($interface, 5));
5374
	}
5375

    
5376
	$curip = find_interface_ipv6_ll($realif);
5377
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5378
		return $curip;
5379
	} else {
5380
		return null;
5381
	}
5382
}
5383

    
5384
function get_interface_subnet($interface = "wan") {
5385

    
5386
	if (substr($interface, 0, 4) == '_vip') {
5387
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5388
	}
5389

    
5390
	$realif = get_real_interface($interface);
5391
	if (!$realif) {
5392
		return null;
5393
	}
5394

    
5395
	$cursn = find_interface_subnet($realif);
5396
	if (!empty($cursn)) {
5397
		return $cursn;
5398
	}
5399

    
5400
	return null;
5401
}
5402

    
5403
function get_interface_subnetv6($interface = "wan") {
5404

    
5405
	if (substr($interface, 0, 4) == '_vip') {
5406
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5407
	} else if (substr($interface, 0, 5) == '_lloc') {
5408
		$interface = substr($interface, 5);
5409
	}
5410

    
5411
	$realif = get_real_interface($interface, 'inet6');
5412
	if (!$realif) {
5413
		return null;
5414
	}
5415

    
5416
	$cursn = find_interface_subnetv6($realif);
5417
	if (!empty($cursn)) {
5418
		return $cursn;
5419
	}
5420

    
5421
	return null;
5422
}
5423

    
5424
/* return outside interfaces with a gateway */
5425
function get_interfaces_with_gateway() {
5426
	global $config;
5427

    
5428
	$ints = array();
5429

    
5430
	/* loop interfaces, check config for outbound */
5431
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
5432
		switch ($ifname['ipaddr']) {
5433
			case "dhcp":
5434
			case "pppoe":
5435
			case "pptp":
5436
			case "l2tp":
5437
			case "ppp":
5438
				$ints[$ifdescr] = $ifdescr;
5439
				break;
5440
			default:
5441
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
5442
				    !empty($ifname['gateway'])) {
5443
					$ints[$ifdescr] = $ifdescr;
5444
				}
5445
				break;
5446
		}
5447
	}
5448
	return $ints;
5449
}
5450

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

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

    
5480
	return false;
5481
}
5482

    
5483
/* return true if interface has a gateway */
5484
function interface_has_gatewayv6($friendly) {
5485
	global $config;
5486

    
5487
	if (!empty($config['interfaces'][$friendly])) {
5488
		$ifname = &$config['interfaces'][$friendly];
5489
		switch ($ifname['ipaddrv6']) {
5490
			case "slaac":
5491
			case "dhcp6":
5492
			case "6to4":
5493
			case "6rd":
5494
				return true;
5495
				break;
5496
			default:
5497
				if (substr($ifname['if'], 0, 4) == "ovpn") {
5498
					return true;
5499
				}
5500
				$tunnelif = substr($ifname['if'], 0, 3);
5501
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5502
					return true;
5503
				}
5504
				if (!empty($ifname['gatewayv6'])) {
5505
					return true;
5506
				}
5507
				break;
5508
		}
5509
	}
5510

    
5511
	return false;
5512
}
5513

    
5514
/****f* interfaces/is_altq_capable
5515
 * NAME
5516
 *   is_altq_capable - Test if interface is capable of using ALTQ
5517
 * INPUTS
5518
 *   $int            - string containing interface name
5519
 * RESULT
5520
 *   boolean         - true or false
5521
 ******/
5522

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

    
5537
	$int_family = remove_ifindex($int);
5538

    
5539
	if (in_array($int_family, $capable)) {
5540
		return true;
5541
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5542
		return true;
5543
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5544
		return true;
5545
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5546
		return true;
5547
	} else {
5548
		return false;
5549
	}
5550
}
5551

    
5552
/****f* interfaces/is_interface_wireless
5553
 * NAME
5554
 *   is_interface_wireless - Returns if an interface is wireless
5555
 * RESULT
5556
 *   $tmp       - Returns if an interface is wireless
5557
 ******/
5558
function is_interface_wireless($interface) {
5559
	global $config, $g;
5560

    
5561
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5562
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5563
		if (preg_match($g['wireless_regex'], $interface)) {
5564
			if (isset($config['interfaces'][$friendly])) {
5565
				$config['interfaces'][$friendly]['wireless'] = array();
5566
			}
5567
			return true;
5568
		}
5569
		return false;
5570
	} else {
5571
		return true;
5572
	}
5573
}
5574

    
5575
function get_wireless_modes($interface) {
5576
	/* return wireless modes and channels */
5577
	$wireless_modes = array();
5578

    
5579
	$cloned_interface = get_real_interface($interface);
5580

    
5581
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5582
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5583
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5584
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5585

    
5586
		$interface_channels = "";
5587
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5588
		$interface_channel_count = count($interface_channels);
5589

    
5590
		$c = 0;
5591
		while ($c < $interface_channel_count) {
5592
			$channel_line = explode(",", $interface_channels["$c"]);
5593
			$wireless_mode = trim($channel_line[0]);
5594
			$wireless_channel = trim($channel_line[1]);
5595
			if (trim($wireless_mode) != "") {
5596
				/* if we only have 11g also set 11b channels */
5597
				if ($wireless_mode == "11g") {
5598
					if (!isset($wireless_modes["11b"])) {
5599
						$wireless_modes["11b"] = array();
5600
					}
5601
				} else if ($wireless_mode == "11g ht") {
5602
					if (!isset($wireless_modes["11b"])) {
5603
						$wireless_modes["11b"] = array();
5604
					}
5605
					if (!isset($wireless_modes["11g"])) {
5606
						$wireless_modes["11g"] = array();
5607
					}
5608
					$wireless_mode = "11ng";
5609
				} else if ($wireless_mode == "11a ht") {
5610
					if (!isset($wireless_modes["11a"])) {
5611
						$wireless_modes["11a"] = array();
5612
					}
5613
					$wireless_mode = "11na";
5614
				}
5615
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
5616
			}
5617
			$c++;
5618
		}
5619
	}
5620
	return($wireless_modes);
5621
}
5622

    
5623
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5624
function get_wireless_channel_info($interface) {
5625
	$wireless_channels = array();
5626

    
5627
	$cloned_interface = get_real_interface($interface);
5628

    
5629
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5630
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5631
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5632
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5633

    
5634
		$interface_channels = "";
5635
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5636

    
5637
		foreach ($interface_channels as $channel_line) {
5638
			$channel_line = explode(",", $channel_line);
5639
			if (!isset($wireless_channels[$channel_line[0]])) {
5640
				$wireless_channels[$channel_line[0]] = $channel_line;
5641
			}
5642
		}
5643
	}
5644
	return($wireless_channels);
5645
}
5646

    
5647
/****f* interfaces/get_interface_mtu
5648
 * NAME
5649
 *   get_interface_mtu - Return the mtu of an interface
5650
 * RESULT
5651
 *   $tmp       - Returns the mtu of an interface
5652
 ******/
5653
function get_interface_mtu($interface) {
5654
	$mtu = pfSense_interface_getmtu($interface);
5655
	return $mtu['mtu'];
5656
}
5657

    
5658
function get_interface_mac($interface) {
5659

    
5660
	$macinfo = pfSense_get_interface_addresses($interface);
5661
	return $macinfo["macaddr"];
5662
}
5663

    
5664
/****f* pfsense-utils/generate_random_mac_address
5665
 * NAME
5666
 *   generate_random_mac - generates a random mac address
5667
 * INPUTS
5668
 *   none
5669
 * RESULT
5670
 *   $mac - a random mac address
5671
 ******/
5672
function generate_random_mac_address() {
5673
	$mac = "02";
5674
	for ($x = 0; $x < 5; $x++) {
5675
		$mac .= ":" . dechex(rand(16, 255));
5676
	}
5677
	return $mac;
5678
}
5679

    
5680
/****f* interfaces/is_jumbo_capable
5681
 * NAME
5682
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5683
 * INPUTS
5684
 *   $int             - string containing interface name
5685
 * RESULT
5686
 *   boolean          - true or false
5687
 ******/
5688
function is_jumbo_capable($iface) {
5689
	$iface = trim($iface);
5690
	$capable = pfSense_get_interface_addresses($iface);
5691

    
5692
	if (isset($capable['caps']['vlanmtu'])) {
5693
		return true;
5694
	}
5695

    
5696
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5697
	if (substr($iface, 0, 4) == "lagg") {
5698
		return true;
5699
	}
5700

    
5701
	return false;
5702
}
5703

    
5704
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5705
	global $g;
5706

    
5707
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5708

    
5709
	if (!empty($iface) && !empty($pppif)) {
5710
		$cron_cmd = <<<EOD
5711
#!/bin/sh
5712
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5713
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5714

    
5715
EOD;
5716

    
5717
		@file_put_contents($cron_file, $cron_cmd);
5718
		chmod($cron_file, 0755);
5719
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5720
	} else {
5721
		unlink_if_exists($cron_file);
5722
	}
5723
}
5724

    
5725
function get_interface_default_mtu($type = "ethernet") {
5726
	switch ($type) {
5727
		case "gre":
5728
			return 1476;
5729
			break;
5730
		case "gif":
5731
			return 1280;
5732
			break;
5733
		case "tun":
5734
		case "vlan":
5735
		case "tap":
5736
		case "ethernet":
5737
		default:
5738
			return 1500;
5739
			break;
5740
	}
5741

    
5742
	/* Never reached */
5743
	return 1500;
5744
}
5745

    
5746
function get_vip_descr($ipaddress) {
5747
	global $config;
5748

    
5749
	foreach ($config['virtualip']['vip'] as $vip) {
5750
		if ($vip['subnet'] == $ipaddress) {
5751
			return ($vip['descr']);
5752
		}
5753
	}
5754
	return "";
5755
}
5756

    
5757
function interfaces_staticarp_configure($if) {
5758
	global $config, $g;
5759
	if (isset($config['system']['developerspew'])) {
5760
		$mt = microtime();
5761
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5762
	}
5763

    
5764
	$ifcfg = $config['interfaces'][$if];
5765

    
5766
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5767
		return 0;
5768
	}
5769

    
5770
	/* Enable staticarp, if enabled */
5771
	if (isset($config['dhcpd'][$if]['staticarp'])) {
5772
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
5773
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5774
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
5775
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5776
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5777
			}
5778
		}
5779
	} else {
5780
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
5781
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
5782
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
5783
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
5784
				if (isset($arpent['arp_table_static_entry'])) {
5785
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
5786
				}
5787
			}
5788
		}
5789
	}
5790

    
5791
	return 0;
5792
}
5793

    
5794
function get_failover_interface($interface, $family = "all") {
5795
	global $config;
5796

    
5797
	/* shortcut to get_real_interface if we find it in the config */
5798
	if (is_array($config['interfaces'][$interface])) {
5799
		return get_real_interface($interface, $family);
5800
	}
5801

    
5802
	/* compare against gateway groups */
5803
	$a_groups = return_gateway_groups_array();
5804
	if (is_array($a_groups[$interface])) {
5805
		/* we found a gateway group, fetch the interface or vip */
5806
		if (!empty($a_groups[$interface][0]['vip'])) {
5807
			return $a_groups[$interface][0]['vip'];
5808
		} else {
5809
			return $a_groups[$interface][0]['int'];
5810
		}
5811
	}
5812
	/* fall through to get_real_interface */
5813
	/* XXX: Really needed? */
5814
	return get_real_interface($interface, $family);
5815
}
5816

    
5817
function remove_ifindex($ifname) {
5818
	return preg_replace("/[0-9]+$/", "", $ifname);
5819
}
5820

    
5821
?>
(26-26/68)