Project

General

Profile

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

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

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

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

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

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

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

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

    
42
*/
43

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

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

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

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

    
69
	return $interface_arr_cache;
70
}
71

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

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

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

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

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

    
102

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

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

    
125
	return false;
126
}
127

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
261
	interfaces_bring_up($vlanif);
262

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

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

    
269
	return $vlanif;
270
}
271

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

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

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

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

    
292
	$vlanif = interface_vlan_configure($vlan);
293

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

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

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

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

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

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

    
348
	return $vlanif;
349
}
350

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

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

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

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

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

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

    
393
	return $vlanif;
394
}
395

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

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

    
403
	$iflist = get_configured_interface_list();
404

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

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

    
428
}
429

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

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

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

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

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

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

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

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

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

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

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

    
533
	$checklist = get_configured_interface_list();
534

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
768
	interfaces_bring_up($laggif);
769

    
770
	return $laggif;
771
}
772

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

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

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

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

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

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

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

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

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

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

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

    
864
	interfaces_bring_up($greif);
865

    
866
	return $greif;
867
}
868

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

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

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

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

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

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

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

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

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

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

    
982

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

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

    
997
	interfaces_bring_up($gifif);
998

    
999
	return $gifif;
1000
}
1001

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

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

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

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

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

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

    
1021
	interfaces_qinq_configure();
1022

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

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

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

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

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

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

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

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

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

    
1085
		interface_configure($if, $reload);
1086

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

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

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

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

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

    
1109
		interface_configure($if, $reload);
1110

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

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

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

    
1127
		interface_configure($if, $reload);
1128

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

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

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

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

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

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

    
1155
	return 0;
1156
}
1157

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

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

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

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

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

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

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

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

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

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

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

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

    
1365
	$old_router = '';
1366
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1367
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1368
	}
1369

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

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

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

    
1392
	return;
1393
}
1394

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

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

    
1413
function interface_isppp_type($interface) {
1414
	global $config;
1415

    
1416
	if (!is_array($config['interfaces'][$interface])) {
1417
		return false;
1418
	}
1419

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

    
1433
function interfaces_ptpid_used($ptpid) {
1434
	global $config;
1435

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

    
1444
	return false;
1445
}
1446

    
1447
function interfaces_ptpid_next() {
1448

    
1449
	$ptpid = 0;
1450
	while (interfaces_ptpid_used($ptpid)) {
1451
		$ptpid++;
1452
	}
1453

    
1454
	return $ptpid;
1455
}
1456

    
1457
function getMPDCRONSettings($pppif) {
1458
	global $config;
1459

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

    
1469
	return NULL;
1470
}
1471

    
1472
function handle_pppoe_reset($post_array) {
1473
	global $config, $g;
1474

    
1475
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1476
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1477

    
1478
	if (!is_array($config['cron']['item'])) {
1479
		$config['cron']['item'] = array();
1480
	}
1481

    
1482
	$itemhash = getMPDCRONSettings($pppif);
1483

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

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

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

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

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

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

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

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

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

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

    
1667
	if (is_array($ports) && count($ports) > 1) {
1668
		$multilink = "enable";
1669
	} else {
1670
		$multilink = "disable";
1671
	}
1672

    
1673
	if ($type == "modem") {
1674
		if (is_ipaddr($ppp['localip'])) {
1675
			$localip = $ppp['localip'];
1676
		} else {
1677
			$localip = '0.0.0.0';
1678
		}
1679

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

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

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

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

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

    
1721
	if (isset($ppp['mrru'])) {
1722
		$mrrus = explode(',',$ppp['mrru']);
1723
	}
1724

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

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

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

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

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

    
1765
EOD;
1766

    
1767
	if (isset($ppp['ondemand'])) {
1768
		$mpdconf .= <<<EOD
1769
	set iface addrs 10.10.1.1 10.10.1.2
1770

    
1771
EOD;
1772
	}
1773

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

    
1782
EOD;
1783

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

    
1789
EOD;
1790
	if (isset($ppp['vjcomp'])) {
1791
		$mpdconf .= <<<EOD
1792
	set ipcp no vjcomp
1793

    
1794
EOD;
1795
	}
1796

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

    
1802
EOD;
1803
	}
1804

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

    
1809
EOD;
1810
	}
1811

    
1812
	foreach ($ports as $pid => $port) {
1813
		$port = get_real_interface($port);
1814
		$mpdconf .= <<<EOD
1815

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

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

    
1827
EOD;
1828
		}
1829

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

    
1834
EOD;
1835
		}
1836

    
1837
		if (isset($ppp['protocomp'])) {
1838
			$mpdconf .= <<<EOD
1839
	set link no protocomp
1840

    
1841
EOD;
1842
		}
1843

    
1844
		$mpdconf .= <<<EOD
1845
	set link disable chap pap
1846
	set link accept chap pap eap
1847
	set link disable incoming
1848

    
1849
EOD;
1850

    
1851

    
1852
		if (!empty($bandwidths[$pid])) {
1853
			$mpdconf .= <<<EOD
1854
	set link bandwidth {$bandwidths[$pid]}
1855

    
1856
EOD;
1857
		}
1858

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

    
1865
EOD;
1866

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

    
1871
EOD;
1872
		}
1873

    
1874
		if (!empty($mrrus[$pid])) {
1875
			$mpdconf .= <<<EOD
1876
	set link mrru {$mrrus[$pid]}
1877

    
1878
EOD;
1879
		}
1880

    
1881
		$mpdconf .= <<<EOD
1882
	set auth authname "{$ppp['username']}"
1883
	set auth password {$passwd}
1884

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

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

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

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

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

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

    
1933
EOD;
1934
		}
1935
		if ($type == "pppoe") {
1936
			$mpdconf .= <<<EOD
1937
	set pppoe iface {$port}
1938

    
1939
EOD;
1940
		}
1941

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

    
1947
EOD;
1948
		}
1949

    
1950
		$mpdconf .= "\topen\n";
1951
	} //end foreach ($port)
1952

    
1953

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

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

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

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

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

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

    
2033
	return 1;
2034
}
2035

    
2036
function interfaces_sync_setup() {
2037
	global $g, $config;
2038

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

    
2044
	if (platform_booting()) {
2045
		echo gettext("Configuring CARP settings...");
2046
		mute_kernel_msgs();
2047
	}
2048

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

    
2059
	set_sysctl(array(
2060
		"net.inet.carp.preempt" => "1",
2061
		"net.inet.carp.log" => "1")
2062
	);
2063

    
2064
	if (!empty($pfsyncinterface)) {
2065
		$carp_sync_int = get_real_interface($pfsyncinterface);
2066
	} else {
2067
		unset($carp_sync_int);
2068
	}
2069

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

    
2078
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2079

    
2080
		sleep(1);
2081

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

    
2097
	if ($config['virtualip']['vip']) {
2098
		set_single_sysctl("net.inet.carp.allow", "1");
2099
	} else {
2100
		set_single_sysctl("net.inet.carp.allow", "0");
2101
	}
2102

    
2103
	if (platform_booting()) {
2104
		unmute_kernel_msgs();
2105
		echo gettext("done.") . "\n";
2106
	}
2107
}
2108

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

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

    
2126
	$paa = array();
2127
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2128

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

    
2138
				if (!empty($interface) && $interface != $proxyif) {
2139
					continue;
2140
				}
2141

    
2142
				if (!is_array($paa[$proxyif])) {
2143
					$paa[$proxyif] = array();
2144
				}
2145

    
2146
				$paa[$proxyif][] = $vipent;
2147
			}
2148
		}
2149
	}
2150

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

    
2186
function interface_ipalias_cleanup($interface, $inet = "inet4") {
2187
	global $g, $config;
2188

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

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

    
2247
function interface_ipalias_configure(&$vip) {
2248
	global $config;
2249

    
2250
	if ($vip['mode'] != 'ipalias') {
2251
		return;
2252
	}
2253

    
2254
	if ($vip['interface'] != 'lo0' && stripos($vip['interface'], '_vip') === false) {
2255
		if (!isset($config['interfaces'][$vip['interface']])) {
2256
			return;
2257
		}
2258

    
2259
		if (!isset($config['interfaces'][$vip['interface']]['enable'])) {
2260
			return;
2261
		}
2262
	}
2263

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

    
2280
function interface_reload_carps($cif) {
2281
	global $config;
2282

    
2283
	$carpifs = link_ip_to_carp_interface(find_interface_ip($cif));
2284
	if (empty($carpifs)) {
2285
		return;
2286
	}
2287

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

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

    
2317
	if ($vip['mode'] != "carp") {
2318
		return;
2319
	}
2320

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

    
2328
	$vip_password = $vip['password'];
2329
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2330
	if ($vip['password'] != "") {
2331
		$password = " pass {$vip_password}";
2332
	}
2333

    
2334
	$advbase = "";
2335
	if (!empty($vip['advbase'])) {
2336
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2337
	}
2338

    
2339
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2340
	if ($carp_maintenancemode) {
2341
		$advskew = "advskew 254";
2342
	} else {
2343
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2344
	}
2345

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

    
2348
	if (is_ipaddrv4($vip['subnet'])) {
2349
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2350
	} else if (is_ipaddrv6($vip['subnet'])) {
2351
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2352
	}
2353

    
2354
	return $realif;
2355
}
2356

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

    
2399
	if ($needs_clone == true) {
2400
		/* remove previous instance if it exists */
2401
		if (does_interface_exist($realif)) {
2402
			pfSense_interface_destroy($realif);
2403
		}
2404

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

    
2421
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2422
	global $config, $g;
2423

    
2424
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2425
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2426
				 'regdomain', 'regcountry', 'reglocation');
2427

    
2428
	if (!is_interface_wireless($ifcfg['if'])) {
2429
		return;
2430
	}
2431

    
2432
	$baseif = interface_get_wireless_base($ifcfg['if']);
2433

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

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

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

    
2496
function interface_wireless_configure($if, &$wl, &$wlcfg) {
2497
	global $config, $g;
2498

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

    
2506
	// Remove script file
2507
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
2508

    
2509
	// Clone wireless nic if needed.
2510
	interface_wireless_clone($if, $wl);
2511

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

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

    
2521
	/* set values for /path/program */
2522
	$hostapd = "/usr/sbin/hostapd";
2523
	$wpa_supplicant = "/usr/sbin/wpa_supplicant";
2524
	$ifconfig = "/sbin/ifconfig";
2525
	$sysctl = "/sbin/sysctl";
2526
	$killall = "/usr/bin/killall";
2527

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

    
2530
	$wlcmd = array();
2531
	$wl_sysctl = array();
2532
	/* Make sure it's up */
2533
	$wlcmd[] = "up";
2534
	/* Set a/b/g standard */
2535
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
2536
	$wlcmd[] = "mode " . escapeshellarg($standard);
2537

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

    
2544
	/* Set ssid */
2545
	if ($wlcfg['ssid']) {
2546
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
2547
	}
2548

    
2549
	/* Set 802.11g protection mode */
2550
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
2551

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

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

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

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

    
2576
	/* set Distance value */
2577
	if ($wlcfg['distance']) {
2578
		$distance = escapeshellarg($wlcfg['distance']);
2579
	}
2580

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

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

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

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

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

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

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

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

    
2632
	/* handle txpower setting */
2633
	// or don't. this has issues at the moment.
2634
	/*
2635
	if($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
2636
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
2637
	}*/
2638
	
2639
	/* handle wme option */
2640
	if (isset($wlcfg['wme']['enable'])) {
2641
		$wlcmd[] = "wme";
2642
	} else {
2643
		$wlcmd[] = "-wme";
2644
	}
2645

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

    
2674
	kill_hostapd($if);
2675
	mwexec(kill_wpasupplicant("{$if}"));
2676

    
2677
	/* generate wpa_supplicant/hostap config if wpa is enabled */
2678
	conf_mount_rw();
2679

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

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

    
2734
EOD;
2735

    
2736
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
2737
					$wpa .= <<<EOD
2738
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP you want to roam from/to
2739
rsn_preauth=1
2740
rsn_preauth_interfaces={$if}
2741

    
2742
EOD;
2743
				}
2744
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
2745
					$wpa .= "ieee8021x=1\n";
2746

    
2747
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
2748
						$auth_server_port = "1812";
2749
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
2750
							$auth_server_port = intval($wlcfg['auth_server_port']);
2751
						}
2752
						$wpa .= <<<EOD
2753

    
2754
auth_server_addr={$wlcfg['auth_server_addr']}
2755
auth_server_port={$auth_server_port}
2756
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
2757

    
2758
EOD;
2759
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
2760
							$auth_server_port2 = "1812";
2761
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
2762
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
2763
							}
2764

    
2765
							$wpa .= <<<EOD
2766
auth_server_addr={$wlcfg['auth_server_addr2']}
2767
auth_server_port={$auth_server_port2}
2768
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
2769

    
2770
EOD;
2771
						}
2772
					}
2773
				}
2774

    
2775
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
2776
				unset($wpa);
2777
			}
2778
			break;
2779
	}
2780

    
2781
	/*
2782
	 *    all variables are set, lets start up everything
2783
	 */
2784

    
2785
	$baseif = interface_get_wireless_base($if);
2786
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
2787
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
2788

    
2789
	/* set sysctls for the wireless interface */
2790
	if (!empty($wl_sysctl)) {
2791
		fwrite($fd_set, "# sysctls for {$baseif}\n");
2792
		foreach ($wl_sysctl as $wl_sysctl_line) {
2793
			fwrite($fd_set, "{$sysctl} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
2794
		}
2795
	}
2796

    
2797
	/* set ack timers according to users preference (if he/she has any) */
2798
	if ($distance) {
2799
		fwrite($fd_set, "# Enable ATH distance settings\n");
2800
		fwrite($fd_set, "/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
2801
	}
2802

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

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

    
2819
			/* add line to script to restore spoofed mac after running hostapd */
2820
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
2821
				if ($wl['spoofmac']) {
2822
					$if_curmac = $wl['spoofmac'];
2823
				} else {
2824
					$if_curmac = get_interface_mac($if);
2825
				}
2826
				if (is_macaddr($if_curmac)) {
2827
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
2828
						" link " . escapeshellarg($if_curmac) . "\n");
2829
				}
2830
			}
2831
		}
2832
	}
2833

    
2834
	fclose($fd_set);
2835
	conf_mount_ro();
2836

    
2837
	/* Making sure regulatory settings have actually changed
2838
	 * before applying, because changing them requires bringing
2839
	 * down all wireless networks on the interface. */
2840
	exec("{$ifconfig} " . escapeshellarg($if), $output);
2841
	$ifconfig_str = implode($output);
2842
	unset($output);
2843
	$reg_changing = false;
2844

    
2845
	/* special case for the debug country code */
2846
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
2847
		$reg_changing = true;
2848
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
2849
		$reg_changing = true;
2850
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
2851
		$reg_changing = true;
2852
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
2853
		$reg_changing = true;
2854
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
2855
		$reg_changing = true;
2856
	}
2857

    
2858
	if ($reg_changing) {
2859
		/* set regulatory domain */
2860
		if ($wlcfg['regdomain']) {
2861
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
2862
		}
2863

    
2864
		/* set country */
2865
		if ($wlcfg['regcountry']) {
2866
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
2867
		}
2868

    
2869
		/* set location */
2870
		if ($wlcfg['reglocation']) {
2871
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
2872
		}
2873

    
2874
		$wlregcmd_args = implode(" ", $wlregcmd);
2875

    
2876
		/* build a complete list of the wireless clones for this interface */
2877
		$clone_list = array();
2878
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
2879
			$clone_list[] = interface_get_wireless_clone($baseif);
2880
		}
2881
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2882
			foreach ($config['wireless']['clone'] as $clone) {
2883
				if ($clone['if'] == $baseif) {
2884
					$clone_list[] = $clone['cloneif'];
2885
				}
2886
			}
2887
		}
2888

    
2889
		/* find which clones are up and bring them down */
2890
		$clones_up = array();
2891
		foreach ($clone_list as $clone_if) {
2892
			$clone_status = pfSense_get_interface_addresses($clone_if);
2893
			if ($clone_status['status'] == 'up') {
2894
				$clones_up[] = $clone_if;
2895
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
2896
			}
2897
		}
2898

    
2899
		/* apply the regulatory settings */
2900
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
2901
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
2902

    
2903
		/* bring the clones back up that were previously up */
2904
		foreach ($clones_up as $clone_if) {
2905
			interfaces_bring_up($clone_if);
2906

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

    
2923
	/* The mode must be specified in a separate command before ifconfig
2924
	 * will allow the mode and channel at the same time in the next. */
2925
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
2926
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
2927

    
2928
	/* configure wireless */
2929
	$wlcmd_args = implode(" ", $wlcmd);
2930
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
2931
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
2932
	fclose($wlan_setup_log);
2933
	
2934
	unset($wlcmd_args, $wlcmd);
2935

    
2936

    
2937
	sleep(1);
2938
	/* execute hostapd and wpa_supplicant if required in shell */
2939
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
2940

    
2941
	return 0;
2942

    
2943
}
2944

    
2945
function kill_hostapd($interface) {
2946
	global $g;
2947

    
2948
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
2949
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
2950
	}
2951
}
2952

    
2953
function kill_wpasupplicant($interface) {
2954
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
2955
}
2956

    
2957
function find_dhclient_process($interface) {
2958
	if ($interface) {
2959
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
2960
	} else {
2961
		$pid = 0;
2962
	}
2963

    
2964
	return intval($pid);
2965
}
2966

    
2967
function kill_dhclient_process($interface) {
2968
	if (empty($interface) || !does_interface_exist($interface)) {
2969
		return;
2970
	}
2971

    
2972
	$i = 0;
2973
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
2974
		/* 3rd time make it die for sure */
2975
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
2976
		posix_kill($pid, $sig);
2977
		sleep(1);
2978
		$i++;
2979
	}
2980
	unset($i);
2981
}
2982

    
2983
function find_dhcp6c_process($interface) {
2984
	global $g;
2985

    
2986
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
2987
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
2988
	} else {
2989
		return(false);
2990
	}
2991

    
2992
	return intval($pid);
2993
}
2994

    
2995
function interface_virtual_create($interface) {
2996
	global $config;
2997

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

    
3037
function interface_vlan_mtu_configured($realhwif, $mtu) {
3038
	global $config;
3039

    
3040
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3041
		foreach ($config['vlans']['vlan'] as $vlan) {
3042
			if ($vlan['if'] != $realhwif) {
3043
				continue;
3044
			}
3045
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3046
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3047
				if (intval($config['interfaces'][$assignedport]['mtu']) > $mtu) {
3048
					$mtu = $config['interfaces'][$assignedport]['mtu'];
3049
				}
3050
			}
3051
		}
3052
	}
3053

    
3054
	return $mtu;
3055
}
3056

    
3057
function interface_vlan_adapt_mtu($vlanifs, $mtu) {
3058
	global $config;
3059

    
3060
	if (!is_array($vlanifs)) {
3061
		return;
3062
	}
3063

    
3064
	/* All vlans need to use the same mtu value as their parent. */
3065
	foreach ($vlanifs as $vlan) {
3066
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3067
		if (!empty($assignedport)) {
3068
			if (!empty($config['interfaces'][$assignedport]['mtu'])) {
3069
				pfSense_interface_mtu($vlan['vlanif'], $config['interfaces'][$assignedport]['mtu']);
3070
			} else {
3071
				if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3072
					pfSense_interface_mtu($vlan['vlanif'], $mtu);
3073
				}
3074
			}
3075
		} else if (get_interface_mtu($vlan['vlanif']) != $mtu) {
3076
			pfSense_interface_mtu($vlan['vlanif'], $mtu);
3077
		}
3078
	}
3079
}
3080

    
3081
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3082
	global $config, $g;
3083
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3084
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3085

    
3086
	$wancfg = $config['interfaces'][$interface];
3087

    
3088
	if (!isset($wancfg['enable'])) {
3089
		return;
3090
	}
3091

    
3092
	$realif = get_real_interface($interface);
3093
	$realhwif_array = get_parent_interface($interface);
3094
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3095
	$realhwif = $realhwif_array[0];
3096

    
3097
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn")) {
3098
		/* remove all IPv4 and IPv6 addresses */
3099
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3100
		if (is_array($tmpifaces)) {
3101
			foreach ($tmpifaces as $tmpiface) {
3102
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3103
					if (!is_linklocal($tmpiface)) {
3104
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3105
					}
3106
				} else {
3107
					if (is_subnetv4($tmpiface)) {
3108
						$tmpip = explode('/', $tmpiface);
3109
						$tmpip = $tmpip[0];
3110
					} else {
3111
						$tmpip = $tmpiface;
3112
					}
3113
					pfSense_interface_deladdress($realif, $tmpip);
3114
				}
3115
			}
3116
		}
3117

    
3118
		/* only bring down the interface when both v4 and v6 are set to NONE */
3119
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3120
			interface_bring_down($interface);
3121
		}
3122
	}
3123

    
3124
	$interface_to_check = $realif;
3125
	if (interface_isppp_type($interface)) {
3126
		$interface_to_check = $realhwif;
3127
	}
3128

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

    
3134
	/* Disable Accepting router advertisements unless specifically requested */
3135
	if ($g['debug']) {
3136
		log_error("Deny router advertisements for interface {$interface}");
3137
	}
3138
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3139

    
3140
	/* wireless configuration? */
3141
	if (is_array($wancfg['wireless'])) {
3142
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3143
	}
3144

    
3145
	$mac = get_interface_mac($realhwif);
3146
	/*
3147
	 * Don't try to reapply the spoofed MAC if it's already applied.
3148
	 * When ifconfig link is used, it cycles the interface down/up, which triggers
3149
	 * the interface config again, which attempts to spoof the MAC again,
3150
	 * which cycles the link again...
3151
	 */
3152
	if ($wancfg['spoofmac'] && ($wancfg['spoofmac'] != $mac)) {
3153
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3154
			" link " . escapeshellarg($wancfg['spoofmac']));
3155
	}  else {
3156

    
3157
		if ($mac == "ff:ff:ff:ff:ff:ff") {
3158
			/*   this is not a valid mac address.  generate a
3159
			 *   temporary mac address so the machine can get online.
3160
			 */
3161
			echo gettext("Generating new MAC address.");
3162
			$random_mac = generate_random_mac_address();
3163
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3164
				" link " . escapeshellarg($random_mac));
3165
			$wancfg['spoofmac'] = $random_mac;
3166
			write_config();
3167
			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");
3168
		}
3169
	}
3170

    
3171
	/* media */
3172
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3173
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3174
		if ($wancfg['media']) {
3175
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3176
		}
3177
		if ($wancfg['mediaopt']) {
3178
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3179
		}
3180
		mwexec($cmd);
3181
	}
3182

    
3183
	/* Apply hw offloading policies as configured */
3184
	enable_hardware_offloading($interface);
3185

    
3186
	/* invalidate interface/ip/sn cache */
3187
	get_interface_arr(true);
3188
	unset($interface_ip_arr_cache[$realif]);
3189
	unset($interface_sn_arr_cache[$realif]);
3190
	unset($interface_ipv6_arr_cache[$realif]);
3191
	unset($interface_snv6_arr_cache[$realif]);
3192

    
3193
	$tunnelif = substr($realif, 0, 3);
3194

    
3195
	if (does_interface_exist($wancfg['if'])) {
3196
		interfaces_bring_up($wancfg['if']);
3197
	}
3198

    
3199
	if (!empty($wancfg['mtu'])) {
3200
		if (stristr($realif, "_vlan")) {
3201
			$assignedparent = convert_real_interface_to_friendly_interface_name($realhwif);
3202
			if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3203
				$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3204
				if ($wancfg['mtu'] > $parentmtu) {
3205
					log_error("There is a conflict on MTU between parent {$realhwif} and VLAN({$realif})");
3206
				}
3207
			} else {
3208
				$parentmtu = 0;
3209
			}
3210

    
3211
			$parentmtu = interface_vlan_mtu_configured($realhwif, $parentmtu);
3212

    
3213
			if (get_interface_mtu($realhwif) != $parentmtu) {
3214
				pfSense_interface_mtu($realhwif, $parentmtu);
3215
			}
3216

    
3217
			/* All vlans need to use the same mtu value as their parent. */
3218
			interface_vlan_adapt_mtu(link_interface_to_vlans($realhwif), $parentmtu);
3219
		} else if (substr($realif, 0, 4) == 'lagg') {
3220
			/* LAGG interface must be destroyed and re-created to change MTU */
3221
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3222
				if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3223
					foreach ($config['laggs']['lagg'] as $lagg) {
3224
						if ($lagg['laggif'] == $realif) {
3225
							interface_lagg_configure($lagg);
3226
							break;
3227
						}
3228
					}
3229
				}
3230
			}
3231
		} else {
3232
			if ($wancfg['mtu'] != get_interface_mtu($realif)) {
3233
				pfSense_interface_mtu($realif, $wancfg['mtu']);
3234
			}
3235

    
3236
			/* This case is needed when the parent of vlans is being configured */
3237
			$vlans = link_interface_to_vlans($realif);
3238
			if (is_array($vlans)) {
3239
				interface_vlan_adapt_mtu($vlans, $wancfg['mtu']);
3240
			}
3241
			unset($vlans);
3242
		}
3243
		/* XXX: What about gre/gif/.. ? */
3244
	}
3245

    
3246
	switch ($wancfg['ipaddr']) {
3247
		case 'dhcp':
3248
			interface_dhcp_configure($interface);
3249
			break;
3250
		case 'pppoe':
3251
		case 'l2tp':
3252
		case 'pptp':
3253
		case 'ppp':
3254
			interface_ppps_configure($interface);
3255
			break;
3256
		default:
3257
			/* XXX: Kludge for now related to #3280 */
3258
			if (!in_array($tunnelif, array("gif", "gre", "ovp"))) {
3259
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3260
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3261
				}
3262
			}
3263
			break;
3264
	}
3265

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

    
3292
	interface_netgraph_needed($interface);
3293

    
3294
	if (!platform_booting()) {
3295
		link_interface_to_vips($interface, "update");
3296

    
3297
		if ($tunnelif != 'gre') {
3298
			unset($gre);
3299
			$gre = link_interface_to_gre($interface);
3300
			if (!empty($gre)) {
3301
				array_walk($gre, 'interface_gre_configure');
3302
			}
3303
		}
3304

    
3305
		if ($tunnelif != 'gif') {
3306
			unset($gif);
3307
			$gif = link_interface_to_gif ($interface);
3308
			if (!empty($gif)) {
3309
				array_walk($gif, 'interface_gif_configure');
3310
			}
3311
		}
3312

    
3313
		if ($linkupevent == false || substr($realif, 0, 4) == "ovpn") {
3314
			unset($bridgetmp);
3315
			$bridgetmp = link_interface_to_bridge($interface);
3316
			if (!empty($bridgetmp)) {
3317
				interface_bridge_add_member($bridgetmp, $realif);
3318
			}
3319
		}
3320

    
3321
		$grouptmp = link_interface_to_group($interface);
3322
		if (!empty($grouptmp)) {
3323
			array_walk($grouptmp, 'interface_group_add_member');
3324
		}
3325

    
3326
		if ($interface == "lan") {
3327
			/* make new hosts file */
3328
			system_hosts_generate();
3329
		}
3330

    
3331
		if ($reloadall == true) {
3332

    
3333
			/* reconfigure static routes (kernel may have deleted them) */
3334
			system_routing_configure($interface);
3335

    
3336
			/* reload ipsec tunnels */
3337
			send_event("service reload ipsecdns");
3338

    
3339
			/* restart dnsmasq or unbound */
3340
			if (isset($config['dnsmasq']['enable'])) {
3341
				services_dnsmasq_configure();
3342
			} elseif (isset($config['unbound']['enable'])) {
3343
				services_unbound_configure();
3344
			}
3345

    
3346
			/* update dyndns */
3347
			send_event("service reload dyndns {$interface}");
3348

    
3349
			/* reload captive portal */
3350
			if (!function_exists('captiveportal_init_rules_byinterface')) {
3351
				require_once('captiveportal.inc');
3352
			}
3353
			captiveportal_init_rules_byinterface($interface);
3354
		}
3355
	}
3356

    
3357
	interfaces_staticarp_configure($interface);
3358
	return 0;
3359
}
3360

    
3361
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
3362
	global $config, $g;
3363

    
3364
	if (!is_array($wancfg)) {
3365
		return;
3366
	}
3367

    
3368
	if (!isset($wancfg['enable'])) {
3369
		return;
3370
	}
3371

    
3372
	/* If the interface is not configured via another, exit */
3373
	if (empty($wancfg['track6-interface'])) {
3374
		return;
3375
	}
3376

    
3377
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
3378
	$realif = get_real_interface($interface);
3379
	$linklocal = find_interface_ipv6_ll($realif);
3380
	if (!empty($linklocal)) {
3381
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
3382
	}
3383
	/* XXX: This might break for good on a carp installation using link-local as network ips */
3384
	/* XXX: Probably should remove? */
3385
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
3386

    
3387
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
3388
	if (!isset($trackcfg['enable'])) {
3389
		log_error("Interface {$interface} tracking non-existant interface {$wancfg['track6-interface']}");
3390
		return;
3391
	}
3392

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

    
3423
	if ($linkupevent == false) {
3424
		if (!function_exists('services_dhcpd_configure')) {
3425
			require_once("services.inc");
3426
		}
3427

    
3428
		if (isset($config['unbound']['enable'])) {
3429
			services_unbound_configure();
3430
		}
3431

    
3432
		services_dhcpd_configure("inet6");
3433
	}
3434

    
3435
	return 0;
3436
}
3437

    
3438
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
3439
	global $config, $g;
3440
	global $interface_ipv6_arr_cache;
3441
	global $interface_snv6_arr_cache;
3442

    
3443
	if (!is_array($lancfg)) {
3444
		return;
3445
	}
3446

    
3447
	/* If the interface is not configured via another, exit */
3448
	if (empty($lancfg['track6-interface'])) {
3449
		return;
3450
	}
3451

    
3452
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3453
	if (empty($wancfg)) {
3454
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3455
		return;
3456
	}
3457

    
3458
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3459
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
3460
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not valid, not configuring 6RD tunnel");
3461
		return;
3462
	}
3463
	$hexwanv4 = return_hex_ipv4($ip4address);
3464

    
3465
	/* create the long prefix notation for math, save the prefix length */
3466
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3467
	$rd6prefixlen = $rd6prefix[1];
3468
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3469

    
3470
	/* binary presentation of the prefix for all 128 bits. */
3471
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
3472

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

    
3478
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
3479
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
3480
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
3481
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
3482
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
3483
	/* fill the rest out with zeros */
3484
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
3485

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

    
3489
	$lanif = get_real_interface($interface);
3490
	$oip = find_interface_ipv6($lanif);
3491
	if (is_ipaddrv6($oip)) {
3492
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3493
	}
3494
	unset($interface_ipv6_arr_cache[$lanif]);
3495
	unset($interface_snv6_arr_cache[$lanif]);
3496
	log_error("rd6 {$interface} with ipv6 address {$rd6lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3497
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
3498

    
3499
	return 0;
3500
}
3501

    
3502
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
3503
	global $config, $g;
3504
	global $interface_ipv6_arr_cache;
3505
	global $interface_snv6_arr_cache;
3506

    
3507
	if (!is_array($lancfg)) {
3508
		return;
3509
	}
3510

    
3511
	/* If the interface is not configured via another, exit */
3512
	if (empty($lancfg['track6-interface'])) {
3513
		return;
3514
	}
3515

    
3516
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
3517
	if (empty($wancfg)) {
3518
		log_error("Interface {$interface} tracking non-existant interface {$lancfg['track6-interface']}");
3519
		return;
3520
	}
3521

    
3522
	$ip4address = get_interface_ip($lancfg['track6-interface']);
3523
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
3524
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$lancfg['track6-interface']}' is not public, not configuring 6RD tunnel");
3525
		return;
3526
	}
3527
	$hexwanv4 = return_hex_ipv4($ip4address);
3528

    
3529
	/* create the long prefix notation for math, save the prefix length */
3530
	$sixto4prefix = "2002::";
3531
	$sixto4prefixlen = 16;
3532
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
3533

    
3534
	/* binary presentation of the prefix for all 128 bits. */
3535
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
3536

    
3537
	/* just save the left prefix length bits */
3538
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
3539
	/* add the v4 address */
3540
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
3541
	/* add the custom prefix id */
3542
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
3543
	/* fill the rest out with zeros */
3544
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
3545

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

    
3549
	$lanif = get_real_interface($interface);
3550
	$oip = find_interface_ipv6($lanif);
3551
	if (is_ipaddrv6($oip)) {
3552
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
3553
	}
3554
	unset($interface_ipv6_arr_cache[$lanif]);
3555
	unset($interface_snv6_arr_cache[$lanif]);
3556
	log_error("sixto4 {$interface} with ipv6 address {$sixto4lan} based on {$lancfg['track6-interface']} ipv4 {$ip4address}");
3557
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
3558

    
3559
	return 0;
3560
}
3561

    
3562
function interface_6rd_configure($interface = "wan", $wancfg) {
3563
	global $config, $g;
3564

    
3565
	/* because this is a tunnel interface we can only function
3566
	 *	with a public IPv4 address on the interface */
3567

    
3568
	if (!is_array($wancfg)) {
3569
		return;
3570
	}
3571

    
3572
	if (!is_module_loaded('if_stf.ko')) {
3573
		mwexec('/sbin/kldload if_stf.ko');
3574
	}
3575

    
3576
	$wanif = get_real_interface($interface);
3577
	$ip4address = find_interface_ip($wanif);
3578
	if (!is_ipaddrv4($ip4address)) {
3579
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3580
		return false;
3581
	}
3582
	$hexwanv4 = return_hex_ipv4($ip4address);
3583

    
3584
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
3585
		$wancfg['prefix-6rd-v4plen'] = 0;
3586
	}
3587

    
3588
	/* create the long prefix notation for math, save the prefix length */
3589
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
3590
	$rd6prefixlen = $rd6prefix[1];
3591
	$brgw = explode('.', $wancfg['gateway-6rd']);
3592
	$rd6brgw = substr(Net_IPv6::_ip2Bin($rd6prefix[0]), 0, $rd6prefixlen);
3593
	$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);
3594
	if (strlen($rd6brgw) < 128) {
3595
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
3596
	}
3597
	$rd6brgw = Net_IPv6::compress(Net_IPv6::_bin2Ip($rd6brgw));
3598
	unset($brgw);
3599
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
3600

    
3601
	/* binary presentation of the prefix for all 128 bits. */
3602
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
3603

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

    
3611
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3612
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
3613

    
3614

    
3615
	/* XXX: need to extend to support variable prefix size for v4 */
3616
	if (!is_module_loaded("if_stf")) {
3617
		mwexec("/sbin/kldload if_stf.ko");
3618
	}
3619
	$stfiface = "{$interface}_stf";
3620
	if (does_interface_exist($stfiface)) {
3621
		pfSense_interface_destroy($stfiface);
3622
	}
3623
	$tmpstfiface = pfSense_interface_create("stf");
3624
	pfSense_interface_rename($tmpstfiface, $stfiface);
3625
	pfSense_interface_flags($stfiface, IFF_LINK2);
3626
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
3627
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
3628
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
3629
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
3630
	}
3631
	if ($g['debug']) {
3632
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
3633
	}
3634

    
3635
	/* write out a default router file */
3636
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
3637
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
3638

    
3639
	$ip4gateway = get_interface_gateway($interface);
3640
	if (is_ipaddrv4($ip4gateway)) {
3641
		mwexec("/sbin/route change -host " . escapeshellarg($wancfg['gateway-6rd']) . " {$ip4gateway}");
3642
	}
3643

    
3644
	/* configure dependent interfaces */
3645
	if (!platform_booting()) {
3646
		link_interface_to_track6($interface, "update");
3647
	}
3648

    
3649
	return 0;
3650
}
3651

    
3652
function interface_6to4_configure($interface = "wan", $wancfg) {
3653
	global $config, $g;
3654

    
3655
	/* because this is a tunnel interface we can only function
3656
	 *	with a public IPv4 address on the interface */
3657

    
3658
	if (!is_array($wancfg)) {
3659
		return;
3660
	}
3661

    
3662
	$wanif = get_real_interface($interface);
3663
	$ip4address = find_interface_ip($wanif);
3664
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
3665
		log_error("The interface IPv4 '{$ip4address}' address on interface '{$wanif}' is not public, not configuring 6RD tunnel");
3666
		return false;
3667
	}
3668

    
3669
	/* create the long prefix notation for math, save the prefix length */
3670
	$stfprefixlen = 16;
3671
	$stfprefix = Net_IPv6::uncompress("2002::");
3672
	$stfarr = explode(":", $stfprefix);
3673
	$v4prefixlen = "0";
3674

    
3675
	/* we need the hex form of the interface IPv4 address */
3676
	$ip4arr = explode(".", $ip4address);
3677
	$hexwanv4 = "";
3678
	foreach ($ip4arr as $octet) {
3679
		$hexwanv4 .= sprintf("%02x", $octet);
3680
	}
3681

    
3682
	/* we need the hex form of the broker IPv4 address */
3683
	$ip4arr = explode(".", "192.88.99.1");
3684
	$hexbrv4 = "";
3685
	foreach ($ip4arr as $octet) {
3686
		$hexbrv4 .= sprintf("%02x", $octet);
3687
	}
3688

    
3689
	/* binary presentation of the prefix for all 128 bits. */
3690
	$stfprefixbin = "";
3691
	foreach ($stfarr as $element) {
3692
		$stfprefixbin .= sprintf("%016b", hexdec($element));
3693
	}
3694
	/* just save the left prefix length bits */
3695
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
3696

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

    
3701
	/* for the local subnet too. */
3702
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
3703
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
3704

    
3705
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3706
	$stfbrarr = array();
3707
	$stfbrbinarr = array();
3708
	$stfbrbinarr = str_split($stfbrokerbin, 16);
3709
	foreach ($stfbrbinarr as $bin) {
3710
		$stfbrarr[] = dechex(bindec($bin));
3711
	}
3712
	$stfbrgw = Net_IPv6::compress(implode(":", $stfbrarr));
3713

    
3714
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
3715
	$stflanarr = array();
3716
	$stflanbinarr = array();
3717
	$stflanbinarr = str_split($stflanbin, 16);
3718
	foreach ($stflanbinarr as $bin) {
3719
		$stflanarr[] = dechex(bindec($bin));
3720
	}
3721
	$stflanpr = Net_IPv6::compress(implode(":", $stflanarr));
3722
	$stflanarr[7] = 1;
3723
	$stflan = Net_IPv6::compress(implode(":", $stflanarr));
3724

    
3725
	/* setup the stf interface */
3726
	if (!is_module_loaded("if_stf")) {
3727
		mwexec("/sbin/kldload if_stf.ko");
3728
	}
3729
	$stfiface = "{$interface}_stf";
3730
	if (does_interface_exist($stfiface)) {
3731
		pfSense_interface_destroy($stfiface);
3732
	}
3733
	$tmpstfiface = pfSense_interface_create("stf");
3734
	pfSense_interface_rename($tmpstfiface, $stfiface);
3735
	pfSense_interface_flags($stfiface, IFF_LINK2);
3736
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
3737

    
3738
	if ($g['debug']) {
3739
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
3740
	}
3741

    
3742
	/* write out a default router file */
3743
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
3744
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
3745

    
3746
	$ip4gateway = get_interface_gateway($interface);
3747
	if (is_ipaddrv4($ip4gateway)) {
3748
		mwexec("/sbin/route change -host 192.88.99.1 {$ip4gateway}");
3749
	}
3750

    
3751
	if (!platform_booting()) {
3752
		link_interface_to_track6($interface, "update");
3753
	}
3754

    
3755
	return 0;
3756
}
3757

    
3758
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
3759
	global $config, $g;
3760

    
3761
	if (!is_array($wancfg)) {
3762
		return;
3763
	}
3764

    
3765
	$wanif = get_real_interface($interface, "inet6");
3766
	$dhcp6cconf = "";
3767
	$dhcp6cconf .= "interface {$wanif} {\n";
3768

    
3769
	/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
3770
	if ($wancfg['ipaddrv6'] == "slaac") {
3771
		$dhcp6cconf .= "	information-only;\n";
3772
		$dhcp6cconf .= "	request domain-name-servers;\n";
3773
		$dhcp6cconf .= "	request domain-name;\n";
3774
		$dhcp6cconf .= "	script \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3775
		$dhcp6cconf .= "};\n";
3776
	} else {
3777
		$trackiflist = array();
3778
		$iflist = link_interface_to_track6($interface);
3779
		foreach ($iflist as $ifname => $ifcfg) {
3780
			if (is_numeric($ifcfg['track6-prefix-id'])) {
3781
				$trackiflist[$ifname] = $ifcfg;
3782
			}
3783
		}
3784

    
3785
		/* skip address request if this is set */
3786
		if (!isset($wancfg['dhcp6prefixonly'])) {
3787
			$dhcp6cconf .= "        send ia-na 0;   # request stateful address\n";
3788
		}
3789
		if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3790
			$dhcp6cconf .= "	send ia-pd 0;	# request prefix delegation\n";
3791
		}
3792

    
3793
		$dhcp6cconf .= "\trequest domain-name-servers;\n";
3794
		$dhcp6cconf .= "\trequest domain-name;\n";
3795
		$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
3796

    
3797
		$dhcp6cconf .= "};\n";
3798

    
3799
		if (!isset($wancfg['dhcp6prefixonly'])) {
3800
			$dhcp6cconf .= "id-assoc na 0 { };\n";
3801
		}
3802

    
3803
		if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
3804
			/* Setup the prefix delegation */
3805
			$dhcp6cconf .= "id-assoc pd 0 {\n";
3806
			$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
3807
			if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
3808
				$dhcp6cconf .= "	prefix ::/{$preflen} infinity;\n";
3809
			}
3810
			foreach ($trackiflist as $friendly => $ifcfg) {
3811
				if ($g['debug']) {
3812
					log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
3813
				}
3814
				$realif = get_real_interface($friendly);
3815
				$dhcp6cconf .= "	prefix-interface {$realif} {\n";
3816
				$dhcp6cconf .= "		sla-id {$ifcfg['track6-prefix-id']};\n";
3817
				$dhcp6cconf .= "		sla-len {$wancfg['dhcp6-ia-pd-len']};\n";
3818
				$dhcp6cconf .= "	};\n";
3819
			}
3820
			unset($preflen, $iflist, $ifcfg, $ifname);
3821
			$dhcp6cconf .= "};\n";
3822
		}
3823
		unset($trackiflist);
3824
	}
3825

    
3826
	// DHCP6 Config File Advanced
3827
	if ($wancfg['adv_dhcp6_config_advanced']) {
3828
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
3829
	}
3830

    
3831
	// DHCP6 Config File Override
3832
	if ($wancfg['adv_dhcp6_config_file_override']) {
3833
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
3834
	}
3835

    
3836
	/* wide-dhcp6c works for now. */
3837
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
3838
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
3839
		unset($dhcp6cconf);
3840
		return 1;
3841
	}
3842
	unset($dhcp6cconf);
3843

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

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

    
3878
	/* accept router advertisements for this interface */
3879
	set_single_sysctl("net.inet6.ip6.accept_rtadv", "1");
3880
	log_error("Accept router advertisements on interface {$wanif} ");
3881
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
3882

    
3883
	/* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
3884
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
3885
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
3886
		sleep(2);
3887
	}
3888
	mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
3889

    
3890
	/* NOTE: will be called from rtsold invoked script
3891
	 * link_interface_to_track6($interface, "update");
3892
	 */
3893

    
3894
	return 0;
3895
}
3896

    
3897
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
3898
	global $g;
3899

    
3900
	$send_options = "";
3901
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
3902
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_send_options']);
3903
		foreach ($options as $option) {
3904
			$send_options .= "\tsend " . trim($option) . ";\n";
3905
		}
3906
	}
3907

    
3908
	$request_options = "";
3909
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
3910
		$options = explode(',', $wancfg['adv_dhcp6_interface_statement_request_options']);
3911
		foreach ($options as $option) {
3912
			$request_options .= "\trequest " . trim($option) . ";\n";
3913
		}
3914
	}
3915

    
3916
	$information_only = "";
3917
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
3918
		$information_only = "\tinformation-only;\n";
3919
	}
3920

    
3921
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
3922
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
3923
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
3924
	}
3925

    
3926
	$interface_statement  = "interface";
3927
	$interface_statement .= " {$wanif}";
3928
	$interface_statement .= " {\n";
3929
	$interface_statement .= "$send_options";
3930
	$interface_statement .= "$request_options";
3931
	$interface_statement .= "$information_only";
3932
	$interface_statement .= "$script";
3933
	$interface_statement .= "};\n";
3934

    
3935
	$id_assoc_statement_address = "";
3936
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
3937
		$id_assoc_statement_address .= "id-assoc";
3938
		$id_assoc_statement_address .= " na";
3939
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
3940
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
3941
		}
3942
		$id_assoc_statement_address .= " { ";
3943

    
3944
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
3945
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
3946
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
3947
			$id_assoc_statement_address .= "\n\taddress";
3948
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
3949
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
3950
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
3951
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
3952
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
3953
			}
3954
			$id_assoc_statement_address .= ";\n";
3955
		}
3956

    
3957
		$id_assoc_statement_address  .= "};\n";
3958
	}
3959

    
3960
	$id_assoc_statement_prefix = "";
3961
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
3962
		$id_assoc_statement_prefix .= "id-assoc";
3963
		$id_assoc_statement_prefix .= " pd";
3964
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
3965
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
3966
		}
3967
		$id_assoc_statement_prefix .= " { ";
3968

    
3969
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
3970
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
3971
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity')) ) {
3972
			$id_assoc_statement_prefix .= "\n\tprefix";
3973
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
3974
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
3975
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
3976
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
3977
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
3978
			}
3979
			$id_assoc_statement_prefix .= ";";
3980
		}
3981

    
3982
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
3983
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
3984
			$id_assoc_statement_prefix .= " {$wanif}";
3985
			$id_assoc_statement_prefix .= " {\n";
3986
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
3987
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
3988
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
3989
				 $id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
3990
			}
3991
			$id_assoc_statement_prefix .= "\t};";
3992
		}
3993

    
3994
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
3995
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) ) {
3996
			$id_assoc_statement_prefix .= "\n";
3997
		}
3998

    
3999
		$id_assoc_statement_prefix  .= "};\n";
4000
	}
4001

    
4002
	$authentication_statement = "";
4003
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4004
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4005
		$authentication_statement .= "authentication";
4006
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4007
		$authentication_statement .= " {\n";
4008
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4009
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4010
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4011
		}
4012
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4013
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4014
		}
4015
		$authentication_statement .= "};\n";
4016
	}
4017

    
4018
	$key_info_statement = "";
4019
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4020
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4021
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4022
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4023
		$key_info_statement .= "keyinfo";
4024
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4025
		$key_info_statement .= " {\n";
4026
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4027
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4028
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4029
		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'])) {
4030
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4031
		}
4032
		$key_info_statement .= "};\n";
4033
	}
4034

    
4035
	$dhcp6cconf  = $interface_statement;
4036
	$dhcp6cconf .= $id_assoc_statement_address;
4037
	$dhcp6cconf .= $id_assoc_statement_prefix;
4038
	$dhcp6cconf .= $authentication_statement;
4039
	$dhcp6cconf .= $key_info_statement;
4040

    
4041
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4042

    
4043
	return $dhcp6cconf;
4044
}
4045

    
4046

    
4047
function DHCP6_Config_File_Override($wancfg, $wanif) {
4048

    
4049
	$dhcp6cconf = file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4050
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4051

    
4052
	return $dhcp6cconf;
4053
}
4054

    
4055

    
4056
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4057

    
4058
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4059

    
4060
	return $dhcp6cconf;
4061
}
4062

    
4063

    
4064
function interface_dhcp_configure($interface = "wan") {
4065
	global $config, $g;
4066

    
4067
	$wancfg = $config['interfaces'][$interface];
4068
	$wanif = $wancfg['if'];
4069
	if (empty($wancfg)) {
4070
		$wancfg = array();
4071
	}
4072

    
4073
	/* generate dhclient_wan.conf */
4074
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4075
	if (!$fd) {
4076
		printf(printf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing.%s"), $interface, "\n"));
4077
		return 1;
4078
	}
4079

    
4080
	if ($wancfg['dhcphostname']) {
4081
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$wancfg['dhcphostname']}\";\n";
4082
		$dhclientconf_hostname .= "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4083
	} else {
4084
		$dhclientconf_hostname = "";
4085
	}
4086

    
4087
	$wanif = get_real_interface($interface);
4088
	if (empty($wanif)) {
4089
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4090
		return 0;
4091
	}
4092
	$dhclientconf = "";
4093

    
4094
	$dhclientconf .= <<<EOD
4095
interface "{$wanif}" {
4096
timeout 60;
4097
retry 15;
4098
select-timeout 0;
4099
initial-interval 1;
4100
	{$dhclientconf_hostname}
4101
	script "/sbin/dhclient-script";
4102
EOD;
4103

    
4104
	if (is_ipaddrv4($wancfg['dhcprejectfrom'])) {
4105
		$dhclientconf .= <<<EOD
4106

    
4107
	reject {$wancfg['dhcprejectfrom']};
4108
EOD;
4109
	}
4110
	$dhclientconf .= <<<EOD
4111

    
4112
}
4113

    
4114
EOD;
4115

    
4116
	// DHCP Config File Advanced
4117
	if ($wancfg['adv_dhcp_config_advanced']) {
4118
		$dhclientconf = DHCP_Config_File_Advanced($interface, $wancfg, $wanif);
4119
	}
4120

    
4121
	if (is_ipaddr($wancfg['alias-address'])) {
4122
		$subnetmask = gen_subnet_mask($wancfg['alias-subnet']);
4123
		$dhclientconf .= <<<EOD
4124
alias {
4125
	interface  "{$wanif}";
4126
	fixed-address {$wancfg['alias-address']};
4127
	option subnet-mask {$subnetmask};
4128
}
4129

    
4130
EOD;
4131
	}
4132

    
4133
	// DHCP Config File Override
4134
	if ($wancfg['adv_dhcp_config_file_override']) {
4135
		$dhclientconf = DHCP_Config_File_Override($wancfg, $wanif);
4136
	}
4137

    
4138
	fwrite($fd, $dhclientconf);
4139
	fclose($fd);
4140

    
4141
	/* bring wan interface up before starting dhclient */
4142
	if ($wanif) {
4143
		interfaces_bring_up($wanif);
4144
	} else {
4145
		log_error(printf(gettext("Could not bring up %s interface in interface_dhcp_configure()"), $wanif));
4146
	}
4147

    
4148
	/* Make sure dhclient is not running */
4149
	kill_dhclient_process($wanif);
4150

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

    
4154
	return 0;
4155
}
4156

    
4157
function DHCP_Config_File_Advanced($interface, $wancfg, $wanif) {
4158

    
4159
	$hostname = "";
4160
	if ($wancfg['dhcphostname'] != '') {
4161
		$hostname = "\tsend host-name \"{$wancfg['dhcphostname']}\";\n";
4162
	}
4163

    
4164
	/* DHCP Protocol Timings */
4165
	$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");
4166
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
4167
		$pt_variable = "{$Protocol_Timing}";
4168
		${$pt_variable} = "";
4169
		if ($wancfg[$Protocol_Timing] != "") {
4170
			${$pt_variable} = "{$PT_Name} {$wancfg[$Protocol_Timing]};\n";
4171
		}
4172
	}
4173

    
4174
	$send_options = "";
4175
	if ($wancfg['adv_dhcp_send_options'] != '') {
4176
		$options = explode(',', $wancfg['adv_dhcp_send_options']);
4177
		foreach ($options as $option) {
4178
			$send_options .= "\tsend " . trim($option) . ";\n";
4179
		}
4180
	}
4181

    
4182
	$request_options = "";
4183
	if ($wancfg['adv_dhcp_request_options'] != '') {
4184
		$request_options = "\trequest {$wancfg['adv_dhcp_request_options']};\n";
4185
	}
4186

    
4187
	$required_options = "";
4188
	if ($wancfg['adv_dhcp_required_options'] != '') {
4189
		$required_options = "\trequire {$wancfg['adv_dhcp_required_options']};\n";
4190
	}
4191

    
4192
	$option_modifiers = "";
4193
	if ($wancfg['adv_dhcp_option_modifiers'] != '') {
4194
		$modifiers = explode(',', $wancfg['adv_dhcp_option_modifiers']);
4195
		foreach ($modifiers as $modifier) {
4196
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
4197
		}
4198
	}
4199

    
4200
	$dhclientconf  = "interface \"{$wanif}\" {\n";
4201
	$dhclientconf .= "\n";
4202
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
4203
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
4204
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
4205
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
4206
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
4207
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
4208
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
4209
	$dhclientconf .= "\n";
4210
	$dhclientconf .= "# DHCP Protocol Options\n";
4211
	$dhclientconf .= "{$hostname}";
4212
	$dhclientconf .= "{$send_options}";
4213
	$dhclientconf .= "{$request_options}";
4214
	$dhclientconf .= "{$required_options}";
4215
	$dhclientconf .= "{$option_modifiers}";
4216
	$dhclientconf .= "\n";
4217
	$dhclientconf .= "\tscript \"/sbin/dhclient-script\";\n";
4218
	$dhclientconf .= "}\n";
4219

    
4220
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4221

    
4222
	return $dhclientconf;
4223
}
4224

    
4225

    
4226
function DHCP_Config_File_Override($wancfg, $wanif) {
4227

    
4228
	$dhclientconf = file_get_contents($wancfg['adv_dhcp_config_file_override_path']);
4229
	$dhclientconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf);
4230

    
4231
	return $dhclientconf;
4232
}
4233

    
4234

    
4235
function DHCP_Config_File_Substitutions($wancfg, $wanif, $dhclientconf) {
4236

    
4237
	/* Apply Interface Substitutions */
4238
	$dhclientconf = str_replace("{interface}", "{$wanif}", $dhclientconf);
4239

    
4240
	/* Apply Hostname Substitutions */
4241
	$dhclientconf = str_replace("{hostname}", $wancfg['dhcphostname'], $dhclientconf);
4242

    
4243
	/* Arrays of MAC Address Types, Cases, Delimiters */
4244
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
4245
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
4246
	$various_mac_cases      = array("U", "L");
4247
	$various_mac_delimiters = array("", " ", ":", "-", ".");
4248

    
4249
	/* Apply MAC Address Substitutions */
4250
	foreach ($various_mac_types as $various_mac_type) {
4251
		foreach ($various_mac_cases as $various_mac_case) {
4252
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
4253

    
4254
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
4255
				if ($res !== false) {
4256

    
4257
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
4258
					if ("$various_mac_case" == "U") {
4259
						$dhcpclientconf_mac = strtoupper(get_interface_mac($wanif));
4260
					}
4261
					if ("$various_mac_case" == "L") {
4262
						$dhcpclientconf_mac = strtolower(get_interface_mac($wanif));
4263
					}
4264

    
4265
					if ("$various_mac_type" == "mac_addr_hex") {
4266
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
4267
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
4268
						$dhcpclientconf_mac_hex = "";
4269
						$delimiter = "";
4270
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
4271
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
4272
							$delimiter = ":";
4273
						}
4274
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
4275
					}
4276

    
4277
					/* MAC Address Delimiter Substitutions */
4278
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
4279

    
4280
					/* Apply MAC Address Substitutions */
4281
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
4282
				}
4283
			}
4284
		}
4285
	}
4286

    
4287
	return $dhclientconf;
4288
}
4289

    
4290
function interfaces_group_setup() {
4291
	global $config;
4292

    
4293
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
4294
		return;
4295
	}
4296

    
4297
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
4298
		interface_group_setup($groupar);
4299
	}
4300

    
4301
	return;
4302
}
4303

    
4304
function interface_group_setup(&$groupname /* The parameter is an array */) {
4305
	global $config;
4306

    
4307
	if (!is_array($groupname)) {
4308
		return;
4309
	}
4310
	$members = explode(" ", $groupname['members']);
4311
	foreach ($members as $ifs) {
4312
		$realif = get_real_interface($ifs);
4313
		if ($realif && does_interface_exist($realif)) {
4314
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
4315
		}
4316
	}
4317

    
4318
	return;
4319
}
4320

    
4321
function is_interface_group($if) {
4322
	global $config;
4323

    
4324
	if (is_array($config['ifgroups']['ifgroupentry'])) {
4325
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
4326
			if ($groupentry['ifname'] === $if) {
4327
				return true;
4328
			}
4329
		}
4330
	}
4331

    
4332
	return false;
4333
}
4334

    
4335
function interface_group_add_member($interface, $groupname) {
4336
	$interface = get_real_interface($interface);
4337
	if (does_interface_exist($interface)) {
4338
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
4339
	}
4340
}
4341

    
4342
/* COMPAT Function */
4343
function convert_friendly_interface_to_real_interface_name($interface) {
4344
	return get_real_interface($interface);
4345
}
4346

    
4347
/* COMPAT Function */
4348
function get_real_wan_interface($interface = "wan") {
4349
	return get_real_interface($interface);
4350
}
4351

    
4352
/* COMPAT Function */
4353
function get_current_wan_address($interface = "wan") {
4354
	return get_interface_ip($interface);
4355
}
4356

    
4357
/*
4358
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
4359
 */
4360
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
4361
	global $config;
4362

    
4363
	if (stripos($interface, "_vip")) {
4364
		foreach ($config['virtualip']['vip'] as $counter => $vip) {
4365
			if ($vip['mode'] == "carp")  {
4366
				if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4367
					return $vip['interface'];
4368
				}
4369
			}
4370
		}
4371
	}
4372

    
4373
	/* XXX: For speed reasons reference directly the interface array */
4374
	$ifdescrs = &$config['interfaces'];
4375
	//$ifdescrs = get_configured_interface_list(false, true);
4376

    
4377
	foreach ($ifdescrs as $if => $ifname) {
4378
		if ($if == $interface || $ifname['if'] == $interface) {
4379
			return $if;
4380
		}
4381

    
4382
		if (get_real_interface($if) == $interface) {
4383
			return $if;
4384
		}
4385

    
4386
		if ($checkparent == false) {
4387
			continue;
4388
		}
4389

    
4390
		$int = get_parent_interface($if, true);
4391
		if (is_array($int)) {
4392
			foreach ($int as $iface) {
4393
				if ($iface == $interface) {
4394
					return $if;
4395
				}
4396
			}
4397
		}
4398
	}
4399

    
4400
	if ($interface == "enc0") {
4401
		return 'IPsec';
4402
	}
4403
}
4404

    
4405
/* attempt to resolve interface to friendly descr */
4406
function convert_friendly_interface_to_friendly_descr($interface) {
4407
	global $config;
4408

    
4409
	switch ($interface) {
4410
		case "l2tp":
4411
			$ifdesc = "L2TP";
4412
			break;
4413
		case "pptp":
4414
			$ifdesc = "PPTP";
4415
			break;
4416
		case "pppoe":
4417
			$ifdesc = "PPPoE";
4418
			break;
4419
		case "openvpn":
4420
			$ifdesc = "OpenVPN";
4421
			break;
4422
		case "enc0":
4423
		case "ipsec":
4424
		case "IPsec":
4425
			$ifdesc = "IPsec";
4426
			break;
4427
		default:
4428
			if (isset($config['interfaces'][$interface])) {
4429
				if (empty($config['interfaces'][$interface]['descr'])) {
4430
					$ifdesc = strtoupper($interface);
4431
				} else {
4432
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
4433
				}
4434
				break;
4435
			} else if (substr($interface, 0, 4) == '_vip') {
4436
				if (is_array($config['virtualip']['vip'])) {
4437
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
4438
						if ($vip['mode'] == "carp")  {
4439
							if ($interface == "{$vip['interface']}_vip{$vip['vhid']}") {
4440
								return "{$vip['subnet']} - {$vip['descr']}";
4441
							}
4442
						}
4443
					}
4444
				}
4445
			} else if (substr($interface, 0, 5) == '_lloc') {
4446
				return get_interface_linklocal($interface);
4447
			} else {
4448
				/* if list */
4449
				$ifdescrs = get_configured_interface_with_descr(false, true);
4450
				foreach ($ifdescrs as $if => $ifname) {
4451
					if ($if == $interface || $ifname == $interface) {
4452
						return $ifname;
4453
					}
4454
				}
4455
			}
4456
			break;
4457
	}
4458

    
4459
	return $ifdesc;
4460
}
4461

    
4462
function convert_real_interface_to_friendly_descr($interface) {
4463

    
4464
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
4465

    
4466
	if (!empty($ifdesc)) {
4467
		return convert_friendly_interface_to_friendly_descr($ifdesc);
4468
	}
4469

    
4470
	return $interface;
4471
}
4472

    
4473
/*
4474
 *  get_parent_interface($interface):
4475
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
4476
 *				or virtual interface (i.e. vlan)
4477
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
4478
 *			-- returns $interface passed in if $interface parent is not found
4479
 *			-- returns empty array if an invalid interface is passed
4480
 *	(Only handles ppps and vlans now.)
4481
 */
4482
function get_parent_interface($interface, $avoidrecurse = false) {
4483
	global $config;
4484

    
4485
	$parents = array();
4486
	//Check that we got a valid interface passed
4487
	$realif = get_real_interface($interface);
4488
	if ($realif == NULL) {
4489
		return $parents;
4490
	}
4491

    
4492
	// If we got a real interface, find it's friendly assigned name
4493
	if ($interface == $realif && $avoidrecurse == false) {
4494
		$interface = convert_real_interface_to_friendly_interface_name($interface);
4495
	}
4496

    
4497
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
4498
		$ifcfg = $config['interfaces'][$interface];
4499
		switch ($ifcfg['ipaddr']) {
4500
			case "ppp":
4501
			case "pppoe":
4502
			case "pptp":
4503
			case "l2tp":
4504
				if (empty($parents)) {
4505
					if (is_array($config['ppps']['ppp'])) {
4506
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
4507
							if ($ifcfg['if'] == $ppp['if']) {
4508
								$ports = explode(',', $ppp['ports']);
4509
								foreach ($ports as $pid => $parent_if) {
4510
									$parents[$pid] = get_real_interface($parent_if);
4511
								}
4512
								break;
4513
							}
4514
						}
4515
					}
4516
				}
4517
				break;
4518
			case "dhcp":
4519
			case "static":
4520
			default:
4521
				// Handle _vlans
4522
				if (strpos($realif, '_vlan') !== FALSE) {
4523
					if (is_array($config['vlans']['vlan'])) {
4524
						foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
4525
							if ($ifcfg['if'] == $vlan['vlanif']) {
4526
								$parents[0] = $vlan['if'];
4527
								break;
4528
							}
4529
						}
4530
					}
4531
				}
4532
				break;
4533
		}
4534
	}
4535

    
4536
	if (empty($parents)) {
4537
		$parents[0] = $realif;
4538
	}
4539

    
4540
	return $parents;
4541
}
4542

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

    
4551
function interface_get_wireless_base($wlif) {
4552
	if (!stristr($wlif, "_wlan")) {
4553
		return $wlif;
4554
	} else {
4555
		return substr($wlif, 0, stripos($wlif, "_wlan"));
4556
	}
4557
}
4558

    
4559
function interface_get_wireless_clone($wlif) {
4560
	if (!stristr($wlif, "_wlan")) {
4561
		return $wlif . "_wlan0";
4562
	} else {
4563
		return $wlif;
4564
	}
4565
}
4566

    
4567
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
4568
	global $config, $g;
4569

    
4570
	$wanif = NULL;
4571

    
4572
	switch ($interface) {
4573
		case "l2tp":
4574
			$wanif = "l2tp";
4575
			break;
4576
		case "pptp":
4577
			$wanif = "pptp";
4578
			break;
4579
		case "pppoe":
4580
			$wanif = "pppoe";
4581
			break;
4582
		case "openvpn":
4583
			$wanif = "openvpn";
4584
			break;
4585
		case "ipsec":
4586
		case "enc0":
4587
			$wanif = "enc0";
4588
			break;
4589
		case "ppp":
4590
			$wanif = "ppp";
4591
			break;
4592
		default:
4593
			if (substr($interface, 0, 4) == '_vip') {
4594
				$wanif = get_configured_carp_interface_list($interface, '', 'iface');
4595
				if (!empty($wanif)) {
4596
					$wanif = get_real_interface($wanif, $family);
4597
				}
4598
				break;
4599
			} else if (substr($interface, 0, 5) == '_lloc') {
4600
				$interface = substr($interface, 5);
4601
			} else if (does_interface_exist($interface, $flush)) {
4602
				/*
4603
				 * If a real interface was already passed simply
4604
				 * pass the real interface back.  This encourages
4605
				 * the usage of this function in more cases so that
4606
				 * we can combine logic for more flexibility.
4607
				 */
4608
				$wanif = $interface;
4609
				break;
4610
			}
4611

    
4612
			if (empty($config['interfaces'][$interface])) {
4613
				break;
4614
			}
4615

    
4616
			$cfg = &$config['interfaces'][$interface];
4617

    
4618
			if ($family == "inet6") {
4619
				switch ($cfg['ipaddrv6']) {
4620
					case "6rd":
4621
					case "6to4":
4622
						$wanif = "{$interface}_stf";
4623
						break;
4624
					case 'pppoe':
4625
					case 'ppp':
4626
					case 'l2tp':
4627
					case 'pptp':
4628
						if ( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4629
							$wanif = interface_get_wireless_clone($cfg['if']);
4630
						} else {
4631
							$wanif = $cfg['if'];
4632
						}
4633
						break;
4634
					default:
4635
						switch ($cfg['ipaddr']) {
4636
							case 'pppoe':
4637
							case 'ppp':
4638
							case 'l2tp':
4639
							case 'pptp':
4640
								if (isset($cfg['dhcp6usev4iface']) && $realv6iface === false) {
4641
									$wanif = $cfg['if'];
4642
								} else {
4643
									$parents = get_parent_interface($interface);
4644
									if (!empty($parents[0])) {
4645
										$wanif = $parents[0];
4646
									} else {
4647
										$wanif = $cfg['if'];
4648
									}
4649
								}
4650
								break;
4651
							default:
4652
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4653
									$wanif = interface_get_wireless_clone($cfg['if']);
4654
								} else {
4655
									$wanif = $cfg['if'];
4656
								}
4657
								break;
4658
						}
4659
						break;
4660
				}
4661
			} else {
4662
				// Wireless cloned NIC support (FreeBSD 8+)
4663
				// interface name format: $parentnic_wlanparentnic#
4664
				// example: ath0_wlan0
4665
				if ( is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
4666
					$wanif = interface_get_wireless_clone($cfg['if']);
4667
				} else {
4668
					$wanif = $cfg['if'];
4669
				}
4670
			}
4671
			break;
4672
	}
4673

    
4674
	return $wanif;
4675
}
4676

    
4677
/* Guess the physical interface by providing a IP address */
4678
function guess_interface_from_ip($ipaddress) {
4679

    
4680
	$family = '';
4681
	if (is_ipaddrv4($ipaddress)) {
4682
		$family = 'inet';
4683
	}
4684
	if (empty($family) && is_ipaddrv6($ipaddress)) {
4685
		$family = 'inet6';
4686
	}
4687

    
4688
	if (empty($family)) {
4689
		return false;
4690
	}
4691

    
4692
	/* create a route table we can search */
4693
	$output = '';
4694
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
4695
	$output[0] = trim($output[0], " \n");
4696
	if (!empty($output[0])) {
4697
		return $output[0];
4698
	}
4699

    
4700
	return false;
4701
}
4702

    
4703
/*
4704
 * find_ip_interface($ip): return the interface where an ip is defined
4705
 *   (or if $bits is specified, where an IP within the subnet is defined)
4706
 */
4707
function find_ip_interface($ip, $bits = null) {
4708
	if (!is_ipaddr($ip)) {
4709
		return false;
4710
	}
4711

    
4712
	$isv6ip = is_ipaddrv6($ip);
4713

    
4714
	/* if list */
4715
	$ifdescrs = get_configured_interface_list();
4716

    
4717
	foreach ($ifdescrs as $ifdescr => $ifname) {
4718
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
4719
		if (is_null($ifip)) {
4720
			continue;
4721
		}
4722
		if (is_null($bits)) {
4723
			if ($ip == $ifip) {
4724
				$int = get_real_interface($ifname);
4725
				return $int;
4726
			}
4727
		} else {
4728
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
4729
				$int = get_real_interface($ifname);
4730
				return $int;
4731
			}
4732
		}
4733
	}
4734

    
4735
	return false;
4736
}
4737

    
4738
/*
4739
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
4740
 *   (or if $bits is specified, where an IP within the subnet is found)
4741
 */
4742
function find_virtual_ip_alias($ip, $bits = null) {
4743
	global $config;
4744

    
4745
	if (!is_array($config['virtualip']['vip'])) {
4746
		return false;
4747
	}
4748
	if (!is_ipaddr($ip)) {
4749
		return false;
4750
	}
4751

    
4752
	$isv6ip = is_ipaddrv6($ip);
4753

    
4754
	foreach ($config['virtualip']['vip'] as $vip) {
4755
		if ($vip['mode'] === "ipalias") {
4756
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
4757
				continue;
4758
			}
4759
			if (is_null($bits)) {
4760
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
4761
					return $vip;
4762
				}
4763
			} else {
4764
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
4765
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
4766
					return $vip;
4767
				}
4768
			}
4769
		}
4770
	}
4771
	return false;
4772
}
4773

    
4774
/*
4775
 *   find_number_of_created_carp_interfaces: return the number of carp interfaces
4776
 */
4777
function find_number_of_created_carp_interfaces() {
4778
	return `/sbin/ifconfig | grep "carp:" | wc -l`;
4779
}
4780

    
4781
/*
4782
 * find_carp_interface($ip): return the carp interface where an ip is defined
4783
 */
4784
function find_carp_interface($ip) {
4785
	global $config;
4786
	if (is_array($config['virtualip']['vip'])) {
4787
		foreach ($config['virtualip']['vip'] as $vip) {
4788
			if ($vip['mode'] == "carp") {
4789
				if (is_ipaddrv4($ip)) {
4790
					$carp_ip = get_interface_ip($vip['interface']);
4791
				}
4792
				if (is_ipaddrv6($ip)) {
4793
					$carp_ip = get_interface_ipv6($vip['interface']);
4794
				}
4795
				exec("/sbin/ifconfig", $output, $return);
4796
				foreach ($output as $line) {
4797
					$elements = preg_split("/[ ]+/i", $line);
4798
					if (strstr($elements[0], "vip")) {
4799
						$curif = str_replace(":", "", $elements[0]);
4800
					}
4801
					if (stristr($line, $ip)) {
4802
						$if = $curif;
4803
						continue;
4804
					}
4805
				}
4806

    
4807
				if ($if) {
4808
					return $if;
4809
				}
4810
			}
4811
		}
4812
	}
4813
}
4814

    
4815
function link_carp_interface_to_parent($interface) {
4816
	global $config;
4817

    
4818
	if (empty($interface)) {
4819
		return;
4820
	}
4821

    
4822
	$carp_ip = get_interface_ip($interface);
4823
	$carp_ipv6 = get_interface_ipv6($interface);
4824

    
4825
	if ((!is_ipaddrv4($carp_ip)) && (!is_ipaddrv6($carp_ipv6))) {
4826
		return;
4827
	}
4828

    
4829
	/* if list */
4830
	$ifdescrs = get_configured_interface_list();
4831
	foreach ($ifdescrs as $ifdescr => $ifname) {
4832
		/* check IPv4 */
4833
		if (is_ipaddrv4($carp_ip)) {
4834
			$interfaceip = get_interface_ip($ifname);
4835
			$subnet_bits = get_interface_subnet($ifname);
4836
			$subnet_ip = gen_subnet("{$interfaceip}", "{$subnet_bits}");
4837
			if (ip_in_subnet($carp_ip, "{$subnet_ip}/{$subnet_bits}")) {
4838
				return $ifname;
4839
			}
4840
		}
4841
		/* Check IPv6 */
4842
		if (is_ipaddrv6($carp_ipv6)) {
4843
			$interfaceipv6 = get_interface_ipv6($ifname);
4844
			$prefixlen = get_interface_subnetv6($ifname);
4845
			if (ip_in_subnet($carp_ipv6, "{$interfaceipv6}/{$prefixlen}")) {
4846
				return $ifname;
4847
			}
4848
		}
4849
	}
4850
	return "";
4851
}
4852

    
4853

    
4854
/****f* interfaces/link_ip_to_carp_interface
4855
 * NAME
4856
 *   link_ip_to_carp_interface - Find where a CARP interface links to.
4857
 * INPUTS
4858
 *   $ip
4859
 * RESULT
4860
 *   $carp_ints
4861
 ******/
4862
function link_ip_to_carp_interface($ip) {
4863
	global $config;
4864

    
4865
	if (!is_ipaddr($ip)) {
4866
		return;
4867
	}
4868

    
4869
	$carp_ints = "";
4870
	if (is_array($config['virtualip']['vip'])) {
4871
		$first = 0;
4872
		$carp_int = array();
4873
		foreach ($config['virtualip']['vip'] as $vip) {
4874
			if ($vip['mode'] == "carp") {
4875
				$carp_ip = $vip['subnet'];
4876
				$carp_sn = $vip['subnet_bits'];
4877
				$carp_nw = gen_subnet($carp_ip, $carp_sn);
4878
				if (ip_in_subnet($ip, "{$carp_nw}/{$carp_sn}")) {
4879
					$carp_int[] = get_real_interface($vip['interface']);
4880
				}
4881
			}
4882
		}
4883
		if (!empty($carp_int)) {
4884
			$carp_ints = implode(" ", array_unique($carp_int));
4885
		}
4886
	}
4887

    
4888
	return $carp_ints;
4889
}
4890

    
4891
function link_interface_to_track6($int, $action = "") {
4892
	global $config;
4893

    
4894
	if (empty($int)) {
4895
		return;
4896
	}
4897

    
4898
	if (is_array($config['interfaces'])) {
4899
		$list = array();
4900
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
4901
			if (!isset($ifcfg['enable'])) {
4902
				continue;
4903
			}
4904
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
4905
				if ($action == "update") {
4906
					interface_track6_configure($ifname, $ifcfg);
4907
				} else if ($action == "") {
4908
					$list[$ifname] = $ifcfg;
4909
				}
4910
			}
4911
		}
4912
		return $list;
4913
	}
4914
}
4915

    
4916
function interface_find_child_cfgmtu($realiface) {
4917
	global $config;
4918

    
4919
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
4920
	$vlans = link_interface_to_vlans($realiface);
4921
	$bridge = link_interface_to_bridge($realiface);
4922
	if (!empty($interface)) {
4923
		$gifs = link_interface_to_gif($interface);
4924
		$gres = link_interface_to_gre($interface);
4925
	} else {
4926
		$gifs = array();
4927
		$gres = array();
4928
	}
4929

    
4930
	$mtu = 0;
4931
	if (is_array($vlans)) {
4932
		foreach ($vlans as $vlan) {
4933
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4934
			if (empty($ifass)) {
4935
				continue;
4936
			}
4937
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4938
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4939
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4940
				}
4941
			}
4942
		}
4943
	}
4944
	if (is_array($gifs)) {
4945
		foreach ($gifs as $vlan) {
4946
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['gifif']);
4947
			if (empty($ifass)) {
4948
				continue;
4949
			}
4950
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4951
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4952
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4953
				}
4954
			}
4955
		}
4956
	}
4957
	if (is_array($gres)) {
4958
		foreach ($gres as $vlan) {
4959
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['greif']);
4960
			if (empty($ifass)) {
4961
				continue;
4962
			}
4963
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
4964
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4965
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
4966
				}
4967
			}
4968
		}
4969
	}
4970
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
4971
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
4972
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
4973
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
4974
		}
4975
	}
4976
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
4977

    
4978
	return $mtu;
4979
}
4980

    
4981
function link_interface_to_vlans($int, $action = "") {
4982
	global $config;
4983

    
4984
	if (empty($int)) {
4985
		return;
4986
	}
4987

    
4988
	if (is_array($config['vlans']['vlan'])) {
4989
		$ifaces = array();
4990
		foreach ($config['vlans']['vlan'] as $vlan) {
4991
			if ($int == $vlan['if']) {
4992
				if ($action == "update") {
4993
					interfaces_bring_up($int);
4994
				} else {
4995
					$ifaces[$vlan['tag']] = $vlan;
4996
				}
4997
			}
4998
		}
4999
		if (!empty($ifaces)) {
5000
			return $ifaces;
5001
		}
5002
	}
5003
}
5004

    
5005
function link_interface_to_vips($int, $action = "", $vhid = '') {
5006
	global $config;
5007

    
5008
	if (is_array($config['virtualip']['vip'])) {
5009
		$result = array();
5010
		foreach ($config['virtualip']['vip'] as $vip) {
5011
			if ($int == $vip['interface']) {
5012
				if ($action == "update") {
5013
					interfaces_vips_configure($int);
5014
				} else {
5015
					if (empty($vhid) || ($vhid == $vip['vhid'])) {
5016
						$result[] = $vip;
5017
					}
5018
				}
5019
			}
5020
		}
5021
		return $result;
5022
	}
5023
}
5024

    
5025
/****f* interfaces/link_interface_to_bridge
5026
 * NAME
5027
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5028
 * INPUTS
5029
 *   $ip
5030
 * RESULT
5031
 *   bridge[0-99]
5032
 ******/
5033
function link_interface_to_bridge($int) {
5034
	global $config;
5035

    
5036
	if (is_array($config['bridges']['bridged'])) {
5037
		foreach ($config['bridges']['bridged'] as $bridge) {
5038
			if (in_array($int, explode(',', $bridge['members']))) {
5039
				return "{$bridge['bridgeif']}";
5040
			}
5041
		}
5042
	}
5043
}
5044

    
5045
function link_interface_to_group($int) {
5046
	global $config;
5047

    
5048
	$result = array();
5049

    
5050
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5051
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5052
			if (in_array($int, explode(" ", $group['members']))) {
5053
				$result[$group['ifname']] = $int;
5054
			}
5055
		}
5056
	}
5057

    
5058
	return $result;
5059
}
5060

    
5061
function link_interface_to_gre($interface) {
5062
	global $config;
5063

    
5064
	$result = array();
5065

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

    
5074
	return $result;
5075
}
5076

    
5077
function link_interface_to_gif($interface) {
5078
	global $config;
5079

    
5080
	$result = array();
5081

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

    
5090
	return $result;
5091
}
5092

    
5093
/*
5094
 * find_interface_ip($interface): return the interface ip (first found)
5095
 */
5096
function find_interface_ip($interface, $flush = false) {
5097
	global $interface_ip_arr_cache;
5098
	global $interface_sn_arr_cache;
5099

    
5100
	$interface = str_replace("\n", "", $interface);
5101

    
5102
	if (!does_interface_exist($interface)) {
5103
		return;
5104
	}
5105

    
5106
	/* Setup IP cache */
5107
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5108
		$ifinfo = pfSense_get_interface_addresses($interface);
5109
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5110
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5111
	}
5112

    
5113
	return $interface_ip_arr_cache[$interface];
5114
}
5115

    
5116
/*
5117
 * find_interface_ipv6($interface): return the interface ip (first found)
5118
 */
5119
function find_interface_ipv6($interface, $flush = false) {
5120
	global $interface_ipv6_arr_cache;
5121
	global $interface_snv6_arr_cache;
5122
	global $config;
5123

    
5124
	$interface = trim($interface);
5125
	$interface = get_real_interface($interface);
5126

    
5127
	if (!does_interface_exist($interface)) {
5128
		return;
5129
	}
5130

    
5131
	/* Setup IP cache */
5132
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
5133
		$ifinfo = pfSense_get_interface_addresses($interface);
5134
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5135
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5136
	}
5137

    
5138
	return $interface_ipv6_arr_cache[$interface];
5139
}
5140

    
5141
/*
5142
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
5143
 */
5144
function find_interface_ipv6_ll($interface, $flush = false) {
5145
	global $interface_llv6_arr_cache;
5146
	global $config;
5147

    
5148
	$interface = str_replace("\n", "", $interface);
5149

    
5150
	if (!does_interface_exist($interface)) {
5151
		return;
5152
	}
5153

    
5154
	/* Setup IP cache */
5155
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
5156
		$ifinfo = pfSense_getall_interface_addresses($interface);
5157
		foreach ($ifinfo as $line) {
5158
			if (strstr($line, ":")) {
5159
				$parts = explode("/", $line);
5160
				if (is_linklocal($parts[0])) {
5161
					$ifinfo['linklocal'] = $parts[0];
5162
				}
5163
			}
5164
		}
5165
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
5166
	}
5167
	return $interface_llv6_arr_cache[$interface];
5168
}
5169

    
5170
function find_interface_subnet($interface, $flush = false) {
5171
	global $interface_sn_arr_cache;
5172
	global $interface_ip_arr_cache;
5173

    
5174
	$interface = str_replace("\n", "", $interface);
5175
	if (does_interface_exist($interface) == false) {
5176
		return;
5177
	}
5178

    
5179
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
5180
		$ifinfo = pfSense_get_interface_addresses($interface);
5181
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5182
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5183
	}
5184

    
5185
	return $interface_sn_arr_cache[$interface];
5186
}
5187

    
5188
function find_interface_subnetv6($interface, $flush = false) {
5189
	global $interface_snv6_arr_cache;
5190
	global $interface_ipv6_arr_cache;
5191

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

    
5197
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
5198
		$ifinfo = pfSense_get_interface_addresses($interface);
5199
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
5200
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
5201
	}
5202

    
5203
	return $interface_snv6_arr_cache[$interface];
5204
}
5205

    
5206
function ip_in_interface_alias_subnet($interface, $ipalias) {
5207
	global $config;
5208

    
5209
	if (empty($interface) || !is_ipaddr($ipalias)) {
5210
		return false;
5211
	}
5212
	if (is_array($config['virtualip']['vip'])) {
5213
		foreach ($config['virtualip']['vip'] as $vip) {
5214
			switch ($vip['mode']) {
5215
				case "ipalias":
5216
					if ($vip['interface'] <> $interface) {
5217
						break;
5218
					}
5219
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
5220
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
5221
						return true;
5222
					}
5223
					break;
5224
			}
5225
		}
5226
	}
5227

    
5228
	return false;
5229
}
5230

    
5231
function get_possible_listen_ips($include_ipv6_link_local=false) {
5232

    
5233
	$interfaces = get_configured_interface_with_descr();
5234
	foreach ($interfaces as $iface => $ifacename) {
5235
		if ($include_ipv6_link_local) {
5236
			/* This is to avoid going though added ll below */
5237
			if (substr($iface, 0, 5) == '_lloc') {
5238
				continue;
5239
			}
5240
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
5241
			if (!empty($llip)) {
5242
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
5243
			}
5244
		}
5245
	}
5246
	/* XXX: Maybe use array_merge below? */
5247
	$carplist = get_configured_carp_interface_list();
5248
	foreach ($carplist as $cif => $carpip) {
5249
		$interfaces[$cif] = $carpip . ' (' . get_vip_descr($carpip) . ')';
5250
	}
5251
	$aliaslist = get_configured_ip_aliases_list();
5252
	foreach ($aliaslist as $aliasip => $aliasif) {
5253
		$interfaces[$aliasip] = $aliasip . ' (' . get_vip_descr($aliasip) . ')';
5254
	}
5255

    
5256
	$interfaces['lo0'] = 'Localhost';
5257

    
5258
	return $interfaces;
5259
}
5260

    
5261
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
5262
	global $config;
5263

    
5264
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
5265
	foreach (array('server', 'client') as $mode) {
5266
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
5267
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
5268
				if (!isset($setting['disable'])) {
5269
					$vpn = array();
5270
					$vpn['value'] = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
5271
					$vpn['name'] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
5272
					$sourceips[] = $vpn;
5273
				}
5274
			}
5275
		}
5276
	}
5277
	return $sourceips;
5278
}
5279

    
5280
function get_interface_ip($interface = "wan") {
5281

    
5282
	$realif = get_failover_interface($interface);
5283
	if (!$realif) {
5284
		return null;
5285
	}
5286

    
5287
	if (substr($realif, 0, 4) == '_vip') {
5288
		return get_configured_carp_interface_list($realif, 'inet', 'ip');
5289
	}
5290

    
5291
	$curip = find_interface_ip($realif);
5292
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
5293
		return $curip;
5294
	} else {
5295
		return null;
5296
	}
5297
}
5298

    
5299
function get_interface_ipv6($interface = "wan", $flush = false) {
5300
	global $config;
5301

    
5302
	$realif = get_failover_interface($interface, 'inet6');
5303
	if (!$realif) {
5304
		return null;
5305
	}
5306

    
5307
	if (substr($realif, 0, 4) == '_vip') {
5308
		return get_configured_carp_interface_list($realif, 'inet6', 'ip');
5309
	} else if (substr($realif, 0, 5) == '_lloc') {
5310
		return get_interface_linklocal($interface);
5311
	}
5312

    
5313
	/*
5314
	 * NOTE: On the case when only the prefix is requested,
5315
	 * the communication on WAN will be done over link-local.
5316
	 */
5317
	if (is_array($config['interfaces'][$interface])) {
5318
		switch ($config['interfaces'][$interface]['ipaddr']) {
5319
			case 'pppoe':
5320
			case 'l2tp':
5321
			case 'pptp':
5322
			case 'ppp':
5323
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
5324
					$realif = get_real_interface($interface, 'inet6', true);
5325
				}
5326
				break;
5327
		}
5328
		if (isset($config['interfaces'][$interface]['dhcp6prefixonly'])) {
5329
			$curip = find_interface_ipv6_ll($realif, $flush);
5330
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5331
				return $curip;
5332
			}
5333
		}
5334
	}
5335

    
5336
	$curip = find_interface_ipv6($realif, $flush);
5337
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5338
		return $curip;
5339
	} else {
5340
		return null;
5341
	}
5342
}
5343

    
5344
function get_interface_linklocal($interface = "wan") {
5345

    
5346
	$realif = get_failover_interface($interface, 'inet6');
5347
	if (!$realif) {
5348
		return null;
5349
	}
5350

    
5351
	if (substr($interface, 0, 4) == '_vip') {
5352
		$realif = get_real_interface($interface);
5353
	} else if (substr($interface, 0, 5) == '_lloc') {
5354
		$realif = get_real_interface(substr($interface, 5));
5355
	}
5356

    
5357
	$curip = find_interface_ipv6_ll($realif);
5358
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
5359
		return $curip;
5360
	} else {
5361
		return null;
5362
	}
5363
}
5364

    
5365
function get_interface_subnet($interface = "wan") {
5366

    
5367
	if (substr($interface, 0, 4) == '_vip') {
5368
		return get_configured_carp_interface_list($interface, 'inet', 'subnet');
5369
	}
5370

    
5371
	$realif = get_real_interface($interface);
5372
	if (!$realif) {
5373
		return null;
5374
	}
5375

    
5376
	$cursn = find_interface_subnet($realif);
5377
	if (!empty($cursn)) {
5378
		return $cursn;
5379
	}
5380

    
5381
	return null;
5382
}
5383

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

    
5386
	if (substr($interface, 0, 4) == '_vip') {
5387
		return get_configured_carp_interface_list($interface, 'inet6', 'subnet');
5388
	} else if (substr($interface, 0, 5) == '_lloc') {
5389
		$interface = substr($interface, 5);
5390
	}
5391

    
5392
	$realif = get_real_interface($interface, 'inet6');
5393
	if (!$realif) {
5394
		return null;
5395
	}
5396

    
5397
	$cursn = find_interface_subnetv6($realif);
5398
	if (!empty($cursn)) {
5399
		return $cursn;
5400
	}
5401

    
5402
	return null;
5403
}
5404

    
5405
/* return outside interfaces with a gateway */
5406
function get_interfaces_with_gateway() {
5407
	global $config;
5408

    
5409
	$ints = array();
5410

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

    
5433
/* return true if interface has a gateway */
5434
function interface_has_gateway($friendly) {
5435
	global $config;
5436

    
5437
	if (!empty($config['interfaces'][$friendly])) {
5438
		$ifname = &$config['interfaces'][$friendly];
5439
		switch ($ifname['ipaddr']) {
5440
			case "dhcp":
5441
			case "pppoe":
5442
			case "pptp":
5443
			case "l2tp":
5444
			case "ppp";
5445
				return true;
5446
			break;
5447
			default:
5448
				if (substr($ifname['if'], 0, 4) ==  "ovpn") {
5449
					return true;
5450
				}
5451
				$tunnelif = substr($ifname['if'], 0, 3);
5452
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5453
					return true;
5454
				}
5455
				if (!empty($ifname['gateway'])) {
5456
					return true;
5457
				}
5458
			break;
5459
		}
5460
	}
5461

    
5462
	return false;
5463
}
5464

    
5465
/* return true if interface has a gateway */
5466
function interface_has_gatewayv6($friendly) {
5467
	global $config;
5468

    
5469
	if (!empty($config['interfaces'][$friendly])) {
5470
		$ifname = &$config['interfaces'][$friendly];
5471
		switch ($ifname['ipaddrv6']) {
5472
			case "slaac":
5473
			case "dhcp6":
5474
			case "6to4":
5475
			case "6rd":
5476
				return true;
5477
				break;
5478
			default:
5479
				if (substr($ifname['if'], 0, 4) ==  "ovpn") {
5480
					return true;
5481
				}
5482
				$tunnelif = substr($ifname['if'], 0, 3);
5483
				if ($tunnelif == "gif" || $tunnelif == "gre") {
5484
					return true;
5485
				}
5486
				if (!empty($ifname['gatewayv6'])) {
5487
					return true;
5488
				}
5489
				break;
5490
		}
5491
	}
5492

    
5493
	return false;
5494
}
5495

    
5496
/****f* interfaces/is_altq_capable
5497
 * NAME
5498
 *   is_altq_capable - Test if interface is capable of using ALTQ
5499
 * INPUTS
5500
 *   $int            - string containing interface name
5501
 * RESULT
5502
 *   boolean         - true or false
5503
 ******/
5504

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

    
5518
	$int_family = remove_ifindex($int);
5519

    
5520
	if (in_array($int_family, $capable)) {
5521
		return true;
5522
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
5523
		return true;
5524
	} else if (stristr($int, "_vlan")) { /* VLANs are named $parent_$vlan now */
5525
		return true;
5526
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
5527
		return true;
5528
	} else {
5529
		return false;
5530
	}
5531
}
5532

    
5533
/****f* interfaces/is_interface_wireless
5534
 * NAME
5535
 *   is_interface_wireless - Returns if an interface is wireless
5536
 * RESULT
5537
 *   $tmp       - Returns if an interface is wireless
5538
 ******/
5539
function is_interface_wireless($interface) {
5540
	global $config, $g;
5541

    
5542
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
5543
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
5544
		if (preg_match($g['wireless_regex'], $interface)) {
5545
			if (isset($config['interfaces'][$friendly])) {
5546
				$config['interfaces'][$friendly]['wireless'] = array();
5547
			}
5548
			return true;
5549
		}
5550
		return false;
5551
	} else {
5552
		return true;
5553
	}
5554
}
5555

    
5556
function get_wireless_modes($interface) {
5557
	/* return wireless modes and channels */
5558
	$wireless_modes = array();
5559

    
5560
	$cloned_interface = get_real_interface($interface);
5561

    
5562
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5563
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
5564
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5565
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
5566

    
5567
		$interface_channels = "";
5568
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5569
		$interface_channel_count = count($interface_channels);
5570

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

    
5604
/* return channel numbers, frequency, max txpower, and max regulation txpower */
5605
function get_wireless_channel_info($interface) {
5606
	$wireless_channels = array();
5607

    
5608
	$cloned_interface = get_real_interface($interface);
5609

    
5610
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
5611
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
5612
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
5613
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
5614

    
5615
		$interface_channels = "";
5616
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
5617

    
5618
		foreach ($interface_channels as $channel_line) {
5619
			$channel_line = explode(",", $channel_line);
5620
			if (!isset($wireless_channels[$channel_line[0]])) {
5621
				$wireless_channels[$channel_line[0]] = $channel_line;
5622
			}
5623
		}
5624
	}
5625
	return($wireless_channels);
5626
}
5627

    
5628
/****f* interfaces/get_interface_mtu
5629
 * NAME
5630
 *   get_interface_mtu - Return the mtu of an interface
5631
 * RESULT
5632
 *   $tmp       - Returns the mtu of an interface
5633
 ******/
5634
function get_interface_mtu($interface) {
5635
	$mtu = pfSense_interface_getmtu($interface);
5636
	return $mtu['mtu'];
5637
}
5638

    
5639
function get_interface_mac($interface) {
5640

    
5641
	$macinfo = pfSense_get_interface_addresses($interface);
5642
	return $macinfo["macaddr"];
5643
}
5644

    
5645
/****f* pfsense-utils/generate_random_mac_address
5646
 * NAME
5647
 *   generate_random_mac - generates a random mac address
5648
 * INPUTS
5649
 *   none
5650
 * RESULT
5651
 *   $mac - a random mac address
5652
 ******/
5653
function generate_random_mac_address() {
5654
	$mac = "02";
5655
	for ($x=0; $x<5; $x++) {
5656
		$mac .= ":" . dechex(rand(16, 255));
5657
	}
5658
	return $mac;
5659
}
5660

    
5661
/****f* interfaces/is_jumbo_capable
5662
 * NAME
5663
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
5664
 * INPUTS
5665
 *   $int             - string containing interface name
5666
 * RESULT
5667
 *   boolean          - true or false
5668
 ******/
5669
function is_jumbo_capable($iface) {
5670
	$iface = trim($iface);
5671
	$capable = pfSense_get_interface_addresses($iface);
5672

    
5673
	if (isset($capable['caps']['vlanmtu'])) {
5674
		return true;
5675
	}
5676

    
5677
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
5678
	if (substr($iface, 0, 4) == "lagg") {
5679
		return true;
5680
	}
5681

    
5682
	return false;
5683
}
5684

    
5685
function interface_setup_pppoe_reset_file($pppif, $iface="") {
5686
	global $g;
5687

    
5688
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
5689

    
5690
	if (!empty($iface) && !empty($pppif)) {
5691
		$cron_cmd = <<<EOD
5692
#!/bin/sh
5693
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
5694
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
5695

    
5696
EOD;
5697

    
5698
		@file_put_contents($cron_file, $cron_cmd);
5699
		chmod($cron_file, 0755);
5700
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
5701
	} else {
5702
		unlink_if_exists($cron_file);
5703
	}
5704
}
5705

    
5706
function get_interface_default_mtu($type = "ethernet") {
5707
	switch ($type) {
5708
		case "gre":
5709
			return 1476;
5710
			break;
5711
		case "gif":
5712
			return 1280;
5713
			break;
5714
		case "tun":
5715
		case "vlan":
5716
		case "tap":
5717
		case "ethernet":
5718
		default:
5719
			return 1500;
5720
			break;
5721
	}
5722

    
5723
	/* Never reached */
5724
	return 1500;
5725
}
5726

    
5727
function get_vip_descr($ipaddress) {
5728
	global $config;
5729

    
5730
	foreach ($config['virtualip']['vip'] as $vip) {
5731
		if ($vip['subnet'] == $ipaddress) {
5732
			return ($vip['descr']);
5733
		}
5734
	}
5735
	return "";
5736
}
5737

    
5738
function interfaces_staticarp_configure($if) {
5739
	global $config, $g;
5740
	if (isset($config['system']['developerspew'])) {
5741
		$mt = microtime();
5742
		echo "interfaces_staticarp_configure($if) being called $mt\n";
5743
	}
5744

    
5745
	$ifcfg = $config['interfaces'][$if];
5746

    
5747
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
5748
		return 0;
5749
	}
5750

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

    
5772
	return 0;
5773
}
5774

    
5775
function get_failover_interface($interface, $family = "all") {
5776
	global $config;
5777

    
5778
	/* shortcut to get_real_interface if we find it in the config */
5779
	if (is_array($config['interfaces'][$interface])) {
5780
		return get_real_interface($interface, $family);
5781
	}
5782

    
5783
	/* compare against gateway groups */
5784
	$a_groups = return_gateway_groups_array();
5785
	if (is_array($a_groups[$interface])) {
5786
		/* we found a gateway group, fetch the interface or vip */
5787
		if (!empty($a_groups[$interface][0]['vip'])) {
5788
			return $a_groups[$interface][0]['vip'];
5789
		} else {
5790
			return $a_groups[$interface][0]['int'];
5791
		}
5792
	}
5793
	/* fall through to get_real_interface */
5794
	/* XXX: Really needed? */
5795
	return get_real_interface($interface, $family);
5796
}
5797

    
5798
function remove_ifindex($ifname) {
5799
	return preg_replace("/[0-9]+$/", "", $ifname);
5800
}
5801

    
5802
?>
(26-26/68)