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

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

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

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

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

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

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

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

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

    
236
	$vlanif = empty($vlan['vlanif']) ? "{$if}_vlan{$vlan['tag']}" : $vlan['vlanif'];
237
	$tag = $vlan['tag'];
238
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
239

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

    
245
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
246
		pfSense_interface_destroy($vlanif);
247
	}
248

    
249
	$tmpvlanif = pfSense_interface_create("vlan");
250
	pfSense_interface_rename($tmpvlanif, $vlanif);
251
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
252

    
253
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
254

    
255
	interfaces_bring_up($vlanif);
256

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

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

    
263
	return $vlanif;
264
}
265

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

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

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

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

    
286
	$vlanif = interface_vlan_configure($vlan);
287

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

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

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

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

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

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

    
342
	return $vlanif;
343
}
344

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

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

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

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

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

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

    
387
	return $vlanif;
388
}
389

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

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

    
397
	$iflist = get_configured_interface_list();
398

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

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

    
422
}
423

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

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

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

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

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

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

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

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

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

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

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

    
527
	$checklist = get_configured_interface_list();
528

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
762
	interfaces_bring_up($laggif);
763

    
764
	return $laggif;
765
}
766

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

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

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

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

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

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

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

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

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

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

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

    
858
	interfaces_bring_up($greif);
859

    
860
	return $greif;
861
}
862

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

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

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

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

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

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

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

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

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

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

    
976

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

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

    
991
	interfaces_bring_up($gifif);
992

    
993
	return $gifif;
994
}
995

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

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

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

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

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

    
1011
	interfaces_qinq_configure();
1012

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

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

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

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

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

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

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

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

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

    
1075
		interface_configure($if, $reload);
1076

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

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

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

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

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

    
1099
		interface_configure($if, $reload);
1100

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

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

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

    
1117
		interface_configure($if, $reload);
1118

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

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

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

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

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

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

    
1145
	return 0;
1146
}
1147

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1385
	return;
1386
}
1387

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

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

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

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

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

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

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

    
1437
	return false;
1438
}
1439

    
1440
function interfaces_ptpid_next() {
1441

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

    
1447
	return $ptpid;
1448
}
1449

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

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

    
1462
	return NULL;
1463
}
1464

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

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

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

    
1475
	$itemhash = getMPDCRONSettings($pppif);
1476

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1758
EOD;
1759

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

    
1764
EOD;
1765
	}
1766

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

    
1775
EOD;
1776

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

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

    
1787
EOD;
1788
	}
1789

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

    
1795
EOD;
1796
	}
1797

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

    
1802
EOD;
1803
	}
1804

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

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

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

    
1820
EOD;
1821
		}
1822

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

    
1827
EOD;
1828
		}
1829

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

    
1834
EOD;
1835
		}
1836

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

    
1842
EOD;
1843

    
1844

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

    
1849
EOD;
1850
		}
1851

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

    
1858
EOD;
1859

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

    
1864
EOD;
1865
		}
1866

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

    
1871
EOD;
1872
		}
1873

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

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

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

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

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

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

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

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

    
1932
EOD;
1933
		}
1934

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

    
1940
EOD;
1941
		}
1942

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

    
1946

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

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

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

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

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

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

    
2026
	return 1;
2027
}
2028

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

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

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

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

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

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

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

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

    
2074
		sleep(1);
2075

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2348
	return $realif;
2349
}
2350

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2709
EOD;
2710

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

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

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

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

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

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

    
2745
EOD;
2746
						}
2747
					}
2748
				}
2749

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2912
	unset($wlcmd_args, $wlcmd);
2913

    
2914

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

    
2919
	return 0;
2920

    
2921
}
2922

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

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

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

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

    
2942
	return intval($pid);
2943
}
2944

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

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

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

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

    
2970
	return intval($pid);
2971
}
2972

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

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

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

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

    
3032
	return $mtu;
3033
}
3034

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3270
	interface_netgraph_needed($interface);
3271

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

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

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

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

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

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

    
3309
		if ($reloadall == true) {
3310

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3410
		services_dhcpd_configure("inet6");
3411
	}
3412

    
3413
	return 0;
3414
}
3415

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

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

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

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

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

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

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

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

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

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

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

    
3477
	return 0;
3478
}
3479

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

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

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

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

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

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

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

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

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

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

    
3537
	return 0;
3538
}
3539

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

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

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

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

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

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

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

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

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

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

    
3592

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

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

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

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

    
3627
	return 0;
3628
}
3629

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3733
	return 0;
3734
}
3735

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3871
	return 0;
3872
}
3873

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3995
	$key_info_statement = "";
3996
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
3997
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
3998
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
3999
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4000
		$key_info_statement .= "keyinfo";
4001
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4002
		$key_info_statement .= " {\n";
4003
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4004
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4005
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4006
		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'])) {
4007
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4008
		}
4009
		$key_info_statement .= "};\n";
4010
	}
4011

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

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

    
4020
	return $dhcp6cconf;
4021
}
4022

    
4023

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

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

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

    
4036

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

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

    
4041
	return $dhcp6cconf;
4042
}
4043

    
4044

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

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

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

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

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

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

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

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

    
4093
}
4094

    
4095
EOD;
4096

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

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

    
4111
EOD;
4112
	}
4113

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

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

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

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

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

    
4135
	return 0;
4136
}
4137

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

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

    
4145
	/* DHCP Protocol Timings */
4146
	$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");
4147
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4148
		$pt_variable = "{$Protocol_Timing}";
4149
		${$pt_variable} = "";
4150
		if ($wancfg[$Protocol_Timing] != "") {
4151
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4152
		}
4153
	}
4154

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

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

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

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

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

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

    
4203
	return $dhclientconf;
4204
}
4205

    
4206

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

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

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

    
4219

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

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

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

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

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

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

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

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

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

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

    
4272
	return $dhclientconf;
4273
}
4274

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

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

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

    
4286
	return;
4287
}
4288

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

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

    
4303
	return;
4304
}
4305

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

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

    
4317
	return false;
4318
}
4319

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4444
	return $ifdesc;
4445
}
4446

    
4447
function convert_real_interface_to_friendly_descr($interface) {
4448

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

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

    
4455
	return $interface;
4456
}
4457

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

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

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

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

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

    
4525
	return $parents;
4526
}
4527

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

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

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

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

    
4555
	$wanif = NULL;
4556

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

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

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

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

    
4660
	return $wanif;
4661
}
4662

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

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

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

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

    
4686
	return false;
4687
}
4688

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

    
4698
	$isv6ip = is_ipaddrv6($ip);
4699

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

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

    
4721
	return false;
4722
}
4723

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

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

    
4738
	$isv6ip = is_ipaddrv6($ip);
4739

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

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

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

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

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

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

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

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

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

    
4839

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

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

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

    
4874
	return $carp_ints;
4875
}
4876

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

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

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

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

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

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

    
4964
	return $mtu;
4965
}
4966

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

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

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

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

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

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

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

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

    
5034
	$result = array();
5035

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

    
5044
	return $result;
5045
}
5046

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

    
5050
	$result = array();
5051

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

    
5060
	return $result;
5061
}
5062

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

    
5066
	$result = array();
5067

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

    
5076
	return $result;
5077
}
5078

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5214
	return false;
5215
}
5216

    
5217
function get_possible_listen_ips($include_ipv6_link_local=false) {
5218

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

    
5248
	$interfaces['lo0'] = 'Localhost';
5249

    
5250
	return $interfaces;
5251
}
5252

    
5253
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5254
	global $config;
5255

    
5256
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5257
	foreach (array('server', 'client') as $mode) {
5258
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5259
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5260
				if (!isset($setting['disable'])) {
5261
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5262
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
5263
				}
5264
			}
5265
		}
5266
	}
5267
	return $sourceips;
5268
}
5269

    
5270
function get_interface_ip($interface = "wan") {
5271

    
5272
	$realif = get_failover_interface($interface, 'inet');
5273
	if (!$realif) {
5274
		return null;
5275
	}
5276

    
5277
	if (substr($interface, 0, 4) == '_vip') {
5278
		return get_configured_carp_interface_list($interface, 'inet', 'ip');
5279
	} else if (substr($interface, 0, 5) == '_lloc') {
5280
		/* No link-local address for v4. */
5281
		return null;
5282
	}
5283

    
5284
	$curip = find_interface_ip($realif);
5285
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5286
		return $curip;
5287
	} else {
5288
		return null;
5289
	}
5290
}
5291

    
5292
function get_interface_ipv6($interface = "wan", $flush = false) {
5293
	global $config;
5294

    
5295
	$realif = get_failover_interface($interface, 'inet6');
5296
	if (!$realif) {
5297
		return null;
5298
	}
5299

    
5300
	if (substr($interface, 0, 4) == '_vip') {
5301
		return get_configured_carp_interface_list($interface, 'inet6', 'ip');
5302
	} else if (substr($interface, 0, 5) == '_lloc') {
5303
		return get_interface_linklocal($interface);
5304
	}
5305

    
5306
	if (is_array($config['interfaces'][$interface])) {
5307
		switch ($config['interfaces'][$interface]['ipaddr']) {
5308
			case 'pppoe':
5309
			case 'l2tp':
5310
			case 'pptp':
5311
			case 'ppp':
5312
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5313
					$realif = get_real_interface($interface, 'inet6', false);
5314
				}
5315
				break;
5316
		}
5317
	}
5318

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

    
5337
function get_interface_linklocal($interface = "wan") {
5338

    
5339
	$realif = get_failover_interface($interface, 'inet6');
5340
	if (!$realif) {
5341
		return null;
5342
	}
5343

    
5344
	if (substr($interface, 0, 4) == '_vip') {
5345
		$realif = get_real_interface($interface);
5346
	} else if (substr($interface, 0, 5) == '_lloc') {
5347
		$realif = get_real_interface(substr($interface, 5));
5348
	}
5349

    
5350
	$curip = find_interface_ipv6_ll($realif);
5351
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5352
		return $curip;
5353
	} else {
5354
		return null;
5355
	}
5356
}
5357

    
5358
function get_interface_subnet($interface = "wan") {
5359

    
5360
	if (substr($interface, 0, 4) == '_vip') {
5361
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5362
	}
5363

    
5364
	$realif = get_real_interface($interface);
5365
	if (!$realif) {
5366
		return null;
5367
	}
5368

    
5369
	$cursn = find_interface_subnet($realif);
5370
	if (!empty($cursn)) {
5371
		return $cursn;
5372
	}
5373

    
5374
	return null;
5375
}
5376

    
5377
function get_interface_subnetv6($interface = "wan") {
5378

    
5379
	if (substr($interface, 0, 4) == '_vip') {
5380
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5381
	} else if (substr($interface, 0, 5) == '_lloc') {
5382
		$interface = substr($interface, 5);
5383
	}
5384

    
5385
	$realif = get_real_interface($interface, 'inet6');
5386
	if (!$realif) {
5387
		return null;
5388
	}
5389

    
5390
	$cursn = find_interface_subnetv6($realif);
5391
	if (!empty($cursn)) {
5392
		return $cursn;
5393
	}
5394

    
5395
	return null;
5396
}
5397

    
5398
/* return outside interfaces with a gateway */
5399
function get_interfaces_with_gateway() {
5400
	global $config;
5401

    
5402
	$ints = array();
5403

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

    
5425
/* return true if interface has a gateway */
5426
function interface_has_gateway($friendly) {
5427
	global $config;
5428

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

    
5454
	return false;
5455
}
5456

    
5457
/* return true if interface has a gateway */
5458
function interface_has_gatewayv6($friendly) {
5459
	global $config;
5460

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

    
5485
	return false;
5486
}
5487

    
5488
/****f* interfaces/is_altq_capable
5489
 * NAME
5490
 *   is_altq_capable - Test if interface is capable of using ALTQ
5491
 * INPUTS
5492
 *   $int            - string containing interface name
5493
 * RESULT
5494
 *   boolean         - true or false
5495
 ******/
5496

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

    
5511
	$int_family = remove_ifindex($int);
5512

    
5513
	if (in_array($int_family, $capable)) {
5514
		return true;
5515
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5516
		return true;
5517
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5518
		return true;
5519
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5520
		return true;
5521
	} else {
5522
		return false;
5523
	}
5524
}
5525

    
5526
/****f* interfaces/is_interface_wireless
5527
 * NAME
5528
 *   is_interface_wireless - Returns if an interface is wireless
5529
 * RESULT
5530
 *   $tmp       - Returns if an interface is wireless
5531
 ******/
5532
function is_interface_wireless($interface) {
5533
	global $config, $g;
5534

    
5535
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5536
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5537
		if (preg_match($g['wireless_regex'], $interface)) {
5538
			if (isset($config['interfaces'][$friendly])) {
5539
				$config['interfaces'][$friendly]['wireless'] = array();
5540
			}
5541
			return true;
5542
		}
5543
		return false;
5544
	} else {
5545
		return true;
5546
	}
5547
}
5548

    
5549
function get_wireless_modes($interface) {
5550
	/* return wireless modes and channels */
5551
	$wireless_modes = array();
5552

    
5553
	$cloned_interface = get_real_interface($interface);
5554

    
5555
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5556
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5557
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5558
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5559

    
5560
		$interface_channels = "";
5561
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5562
		$interface_channel_count = count($interface_channels);
5563

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

    
5597
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5598
function get_wireless_channel_info($interface) {
5599
	$wireless_channels = array();
5600

    
5601
	$cloned_interface = get_real_interface($interface);
5602

    
5603
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5604
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5605
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5606
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5607

    
5608
		$interface_channels = "";
5609
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5610

    
5611
		foreach ($interface_channels as $channel_line) {
5612
			$channel_line = explode(",", $channel_line);
5613
			if (!isset($wireless_channels[$channel_line[0]])) {
5614
				$wireless_channels[$channel_line[0]] = $channel_line;
5615
			}
5616
		}
5617
	}
5618
	return($wireless_channels);
5619
}
5620

    
5621
/****f* interfaces/get_interface_mtu
5622
 * NAME
5623
 *   get_interface_mtu - Return the mtu of an interface
5624
 * RESULT
5625
 *   $tmp       - Returns the mtu of an interface
5626
 ******/
5627
function get_interface_mtu($interface) {
5628
	$mtu = pfSense_interface_getmtu($interface);
5629
	return $mtu['mtu'];
5630
}
5631

    
5632
function get_interface_mac($interface) {
5633

    
5634
	$macinfo = pfSense_get_interface_addresses($interface);
5635
	return $macinfo["macaddr"];
5636
}
5637

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

    
5654
/****f* interfaces/is_jumbo_capable
5655
 * NAME
5656
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5657
 * INPUTS
5658
 *   $int             - string containing interface name
5659
 * RESULT
5660
 *   boolean          - true or false
5661
 ******/
5662
function is_jumbo_capable($iface) {
5663
	$iface = trim($iface);
5664
	$capable = pfSense_get_interface_addresses($iface);
5665

    
5666
	if (isset($capable['caps']['vlanmtu'])) {
5667
		return true;
5668
	}
5669

    
5670
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5671
	if (substr($iface, 0, 4) == "lagg") {
5672
		return true;
5673
	}
5674

    
5675
	return false;
5676
}
5677

    
5678
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5679
	global $g;
5680

    
5681
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5682

    
5683
	if (!empty($iface) && !empty($pppif)) {
5684
		$cron_cmd = <<<EOD
5685
#!/bin/sh
5686
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5687
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5688

    
5689
EOD;
5690

    
5691
		@file_put_contents($cron_file, $cron_cmd);
5692
		chmod($cron_file, 0755);
5693
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5694
	} else {
5695
		unlink_if_exists($cron_file);
5696
	}
5697
}
5698

    
5699
function get_interface_default_mtu($type = "ethernet") {
5700
	switch ($type) {
5701
		case "gre":
5702
			return 1476;
5703
			break;
5704
		case "gif":
5705
			return 1280;
5706
			break;
5707
		case "tun":
5708
		case "vlan":
5709
		case "tap":
5710
		case "ethernet":
5711
		default:
5712
			return 1500;
5713
			break;
5714
	}
5715

    
5716
	/* Never reached */
5717
	return 1500;
5718
}
5719

    
5720
function get_vip_descr($ipaddress) {
5721
	global $config;
5722

    
5723
	foreach ($config['virtualip']['vip'] as $vip) {
5724
		if ($vip['subnet'] == $ipaddress) {
5725
			return ($vip['descr']);
5726
		}
5727
	}
5728
	return "";
5729
}
5730

    
5731
function interfaces_staticarp_configure($if) {
5732
	global $config, $g;
5733
	if (isset($config['system']['developerspew'])) {
5734
		$mt = microtime();
5735
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5736
	}
5737

    
5738
	$ifcfg = $config['interfaces'][$if];
5739

    
5740
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5741
		return 0;
5742
	}
5743

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

    
5765
	return 0;
5766
}
5767

    
5768
function get_failover_interface($interface, $family = "all") {
5769
	global $config;
5770

    
5771
	/* shortcut to get_real_interface if we find it in the config */
5772
	if (is_array($config['interfaces'][$interface])) {
5773
		return get_real_interface($interface, $family);
5774
	}
5775

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

    
5791
function remove_ifindex($ifname) {
5792
	return preg_replace("/[0-9]+$/", "", $ifname);
5793
}
5794

    
5795
?>
(25-25/65)