Project

General

Profile

Download (203 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2018 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * originally based on m0n0wall (http://m0n0.ch/wall)
10
 * Copyright (c) 2004 Manuel Kasper <mk@neon1.net>.
11
 * All rights reserved.
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 * http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25

    
26
/* include all configuration functions */
27
require_once("globals.inc");
28
require_once("util.inc");
29
require_once("gwlb.inc");
30

    
31
function interfaces_bring_up($interface) {
32
	if (!$interface) {
33
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
34
		log_error("Backtrace: " . debug_backtrace());
35
		return;
36
	}
37
	pfSense_interface_flags($interface, IFF_UP);
38
}
39

    
40
/*
41
 * Validate comma-separated list of IPv4 addresses
42
 */
43
function validate_ipv4_list($value) {
44
	$value = trim($value);
45

    
46
	if (empty($value)) {
47
		return false;
48
	}
49

    
50
	$list = explode(',', $value);
51

    
52
	foreach ($list as $ip) {
53
		if (!is_ipaddrv4($ip)) {
54
			return false;
55
		}
56
	}
57

    
58
	return true;
59
}
60

    
61
/*
62
 * Return the interface array
63
 */
64
function get_interface_arr($flush = false) {
65
	global $interface_arr_cache;
66

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

    
72
	return $interface_arr_cache;
73
}
74

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

    
82
	if (!$interface) {
83
		return false;
84
	}
85

    
86
	$ints = get_interface_arr($flush);
87
	if (in_array($interface, $ints)) {
88
		return true;
89
	} else {
90
		return false;
91
	}
92
}
93

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

    
101
	if (!$vip) {
102
		return false;
103
	}
104

    
105

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

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

    
128
	return false;
129
}
130

    
131
function interface_netgraph_needed($interface = "wan") {
132
	global $config;
133

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

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

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

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

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

    
203
function vlan_valid_tag($tag = NULL) {
204

    
205
	if ($tag == NULL || empty($tag) ||
206
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
207
		return (false);
208
	}
209
	return (true);
210
}
211

    
212
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
213
        global $config;
214

    
215
	if ($qinq == NULL || $inqtag == NULL ||
216
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
217
		return (false);
218
	}
219

    
220
        $iflist = get_configured_interface_list(true);
221
        foreach ($iflist as $if) {
222
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
223
                        return (true);
224
                }
225
        }
226

    
227
        return (false);
228
}
229

    
230
function qinq_interface($qinq = NULL, $inqtag = NULL) {
231

    
232
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
233
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
234
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
235
		return (NULL);
236
	}
237
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
238
}
239

    
240
function interface_is_qinq($if = NULL) {
241
	global $config;
242

    
243
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
244
		return (NULL);
245
	}
246

    
247
	/* Check basic format. */
248
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
249
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
250
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
251
		return (NULL);
252
	}
253

    
254
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
255
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
256
			continue;
257
		}
258
		if (empty($qinq['members'])) {
259
			continue;
260
		}
261
		foreach (explode(" ", $qinq['members']) as $tag) {
262
			if ($if == qinq_interface($qinq, $tag)) {
263
				return ($qinq);
264
			}
265
		}
266
	}
267

    
268
	return (NULL);
269
}
270

    
271
function interface_is_lagg($if = NULL) {
272
	global $config;
273

    
274
	if (!isset($config['laggs']['lagg']) || !is_array($config['laggs']['lagg'])) {
275
		return (NULL);
276
	}
277

    
278
	foreach ($config['laggs']['lagg'] as $lagg) {
279
		if ($lagg['laggif'] == $if) {
280
			return ($lagg);
281
		}
282
	}
283
	return (NULL);
284
}
285

    
286
function vlan_inuse($vlan) {
287
	global $config;
288

    
289
	if ($vlan == NULL || !is_array($vlan)) {
290
		return (false);
291
	}
292

    
293
	$iflist = get_configured_interface_list(true);
294
	foreach ($iflist as $if) {
295
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
296
			return (true);
297
		}
298
	}
299

    
300
	return (false);
301
}
302

    
303
function interface_is_vlan($if = NULL) {
304
	global $config;
305

    
306
	if ($if == NULL || empty($if) || is_array($if)) {
307
		return (NULL);
308
	}
309

    
310
	/* Check basic format. */
311
	list($vlanif, $vlantag) = explode(".", $if);
312
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
313
		return (NULL);
314
	}
315

    
316
	/* Find the VLAN interface. */
317
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
318
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
319
			if ($if == $vlan['vlanif']) {
320
				return ($vlan);
321
			}
322
		}
323
	}
324

    
325
	/* Check for the first level tag in QinQ interfaces. */
326
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
327
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
328
			if ($if == $qinq['vlanif']) {
329
				return ($qinq);
330
			}
331
		}
332
	}
333

    
334
	return (NULL);
335
}
336

    
337
function vlan_interface($vlan = NULL) {
338

    
339
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
340
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
341
		return (NULL);
342
	}
343
	return ("{$vlan['if']}.{$vlan['tag']}");
344
}
345

    
346
function interfaces_vlan_configure($realif = "") {
347
	global $config, $g;
348
	if (platform_booting()) {
349
		echo gettext("Configuring VLAN interfaces...");
350
	}
351
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
352
		foreach ($config['vlans']['vlan'] as $vlan) {
353
			if (empty($vlan['vlanif'])) {
354
				$vlan['vlanif'] = vlan_interface($vlan);
355
			}
356
			if (!empty($realif) && $realif != $vlan['vlanif']) {
357
				continue;
358
			}
359

    
360
			/* XXX: Maybe we should report any errors?! */
361
			interface_vlan_configure($vlan);
362
		}
363
	}
364
	if (platform_booting()) {
365
		echo gettext("done.") . "\n";
366
	}
367
}
368

    
369
function interface_vlan_configure(&$vlan) {
370
	global $config, $g;
371

    
372
	if (!is_array($vlan)) {
373
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
374
		return(NULL);
375
	}
376
	$if = $vlan['if'];
377
	if (empty($if)) {
378
		log_error(gettext("interface_vlan_configure called with if undefined."));
379
		return(NULL);
380
	}
381

    
382
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
383
	if ($vlanif == NULL) {
384
		log_error(gettext("vlan_interface called with if undefined var."));
385
		return(NULL);
386
	}
387
	$tag = $vlan['tag'];
388
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
389

    
390
	/* make sure the parent interface is up */
391
	interfaces_bring_up($if);
392
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
393
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
394

    
395
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
396
		pfSense_interface_destroy($vlanif);
397
	}
398

    
399
	$tmpvlanif = pfSense_interface_create("vlan");
400
	pfSense_interface_rename($tmpvlanif, $vlanif);
401
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
402

    
403
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
404

    
405
	interfaces_bring_up($vlanif);
406

    
407
	/* invalidate interface cache */
408
	get_interface_arr(true);
409

    
410
	/* configure interface if assigned */
411
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
412
	if ($assignedif) {
413
		if (isset($config['interfaces'][$assignedif]['enable'])) {
414
			interface_configure($assignedif, true);
415
		}
416
	}
417

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

    
421
	return $vlanif;
422
}
423

    
424
function interface_qinq_configure(&$qinq, $fd = NULL) {
425
	global $config, $g;
426

    
427
	if (!is_array($qinq)) {
428
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
429
		return;
430
	}
431

    
432
	$qinqif = $qinq['if'];
433
	$tag = $qinq['tag'];
434
	if (empty($qinqif)) {
435
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
436
		return;
437
	}
438

    
439
	if (!does_interface_exist($qinqif)) {
440
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
441
		return;
442
	}
443

    
444
	$vlanif = interface_vlan_configure($qinq);
445
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
446
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
447
		return;
448
	}
449

    
450
	if ($fd == NULL) {
451
		$exec = true;
452
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
453
	} else {
454
		$exec = false;
455
	}
456
	/* make sure the parent is converted to ng_vlan(4) and is up */
457
	interfaces_bring_up($qinqif);
458

    
459
	pfSense_ngctl_attach(".", $qinqif);
460
	$ngif = str_replace(".", "_", $vlanif);
461
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
462
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
463
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
464
		if (empty($result)) {
465
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
466
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
467
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
468
		}
469
	} else {
470
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
471
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
472
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
473
	}
474

    
475
	/* invalidate interface cache */
476
	get_interface_arr(true);
477

    
478
	if (interface_is_vlan($qinqif) == NULL) {
479
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
480
	}
481

    
482
	$macaddr = get_interface_mac($qinqif);
483
	if (!empty($qinq['members'])) {
484
		$qinqcmdbuf = "";
485
		$members = explode(" ", $qinq['members']);
486
		foreach ($members as $qtag) {
487
			$qinq2 = array();
488
			$qinq2['tag'] = $qtag;
489
			$qinq2['if'] = $vlanif;
490
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr);
491
			unset($qinq2);
492
		}
493
		if (strlen($qinqcmdbuf) > 0) {
494
			fwrite($fd, $qinqcmdbuf);
495
		}
496
	}
497
	if ($exec == true) {
498
		fclose($fd);
499
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
500
	}
501

    
502
	interfaces_bring_up($qinqif);
503
	if (!empty($qinq['members'])) {
504
		$members = explode(" ", $qinq['members']);
505
		foreach ($members as $qtag) {
506
			interfaces_bring_up(qinq_interface($qinq, $qtag));
507
		}
508
	}
509

    
510
	return $vlanif;
511
}
512

    
513
function interfaces_qinq_configure() {
514
	global $config, $g;
515
	if (platform_booting()) {
516
		echo gettext("Configuring QinQ interfaces...");
517
	}
518
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
519
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
520
			/* XXX: Maybe we should report any errors?! */
521
			interface_qinq_configure($qinq);
522
		}
523
	}
524
	if (platform_booting()) {
525
		echo gettext("done.") . "\n";
526
	}
527
}
528

    
529
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) {
530
	global $config, $g;
531

    
532
	if (!is_array($qinq)) {
533
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
534
		return;
535
	}
536

    
537
	$if = $qinq['if'];
538
	if (empty($if)) {
539
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
540
		return;
541
	}
542
	$tag = $qinq['tag'];
543
	$vlanif = "{$if}.{$tag}";
544
	$ngif = str_replace(".", "_", $if);
545
	if (strlen($vlanif) > IF_NAMESIZE) {
546
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
547
		    $vlanif, IF_NAMESIZE, "\n"));
548
		return;
549
	}
550

    
551
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
552
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
553
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
554
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
555
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
556
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
557

    
558
	/* invalidate interface cache */
559
	get_interface_arr(true);
560

    
561
	return $vlanif;
562
}
563

    
564
function interfaces_create_wireless_clones() {
565
	global $config, $g;
566

    
567
	if (platform_booting()) {
568
		echo gettext("Creating wireless clone interfaces...");
569
	}
570

    
571
	$iflist = get_configured_interface_list();
572

    
573
	foreach ($iflist as $if) {
574
		$realif = $config['interfaces'][$if]['if'];
575
		if (is_interface_wireless($realif)) {
576
			interface_wireless_clone(interface_get_wireless_clone($realif), $config['interfaces'][$if]);
577
		}
578
	}
579

    
580
	if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone']) && count($config['wireless']['clone'])) {
581
		foreach ($config['wireless']['clone'] as $clone) {
582
			if (empty($clone['cloneif'])) {
583
				continue;
584
			}
585
			if (does_interface_exist($clone['cloneif'])) {
586
				continue;
587
			}
588
			/* XXX: Maybe we should report any errors?! */
589
			interface_wireless_clone($clone['cloneif'], $clone);
590
		}
591
	}
592
	if (platform_booting()) {
593
		echo gettext("done.") . "\n";
594
	}
595

    
596
}
597

    
598
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
599
	global $config;
600

    
601
	$i = 0;
602
	if (is_array($config['bridges']['bridged']) && count($config['bridges']['bridged'])) {
603
		foreach ($config['bridges']['bridged'] as $bridge) {
604
			if (empty($bridge['bridgeif'])) {
605
				$bridge['bridgeif'] = "bridge{$i}";
606
			}
607
			if (!empty($realif) && $realif != $bridge['bridgeif']) {
608
				continue;
609
			}
610

    
611
			if ($checkmember == 1) {
612
				/* XXX: It should not be possible no? */
613
				if (strstr($bridge['if'], '_vip')) {
614
					continue;
615
				}
616
				$members = explode(',', $bridge['members']);
617
				foreach ($members as $member) {
618
					if (!empty($config['interfaces'][$bridge['if']]) && $config['interfaces'][$bridge['if']]['ipaddrv6'] == "track6") {
619
						continue 2;
620
					}
621
				}
622
			}
623
			else if ($checkmember == 2) {
624
				$members = explode(',', $bridge['members']);
625
				foreach ($members as $member) {
626
					if (empty($config['interfaces'][$bridge['if']]) || $config['interfaces'][$bridge['if']]['ipaddrv6'] != "track6") {
627
						continue 2;
628
					}
629
				}
630
			}
631
			/* XXX: Maybe we should report any errors?! */
632
			interface_bridge_configure($bridge, $checkmember);
633
			$i++;
634
		}
635
	}
636
}
637

    
638
function interface_bridge_configure(&$bridge, $checkmember = 0) {
639
	global $config, $g;
640

    
641
	if (!is_array($bridge)) {
642
		return;
643
	}
644

    
645
	if (empty($bridge['members'])) {
646
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
647
		return;
648
	}
649

    
650
	$members = explode(',', $bridge['members']);
651
	if (!count($members)) {
652
		return;
653
	}
654

    
655
	/* Calculate smaller mtu and enforce it */
656
	$smallermtu = 0;
657
	$foundgif = false;
658
	foreach ($members as $member) {
659
		$realif = get_real_interface($member);
660
		$mtu = get_interface_mtu($realif);
661
		if (substr($realif, 0, 3) == "gif") {
662
			$foundgif = true;
663
			if ($checkmember == 1) {
664
				return;
665
			}
666
			if ($mtu <= 1500) {
667
				continue;
668
			}
669
		}
670
		if ($smallermtu == 0 && !empty($mtu)) {
671
			$smallermtu = $mtu;
672
		} else if (!empty($mtu) && $mtu < $smallermtu) {
673
			$smallermtu = $mtu;
674
		}
675
	}
676
	if ($foundgif == false && $checkmember == 2) {
677
		return;
678
	}
679

    
680
	/* Just in case anything is not working well */
681
	if ($smallermtu == 0) {
682
		$smallermtu = 1500;
683
	}
684

    
685
	if (!empty($bridge['bridgeif'])) {
686
		pfSense_interface_destroy($bridge['bridgeif']);
687
		pfSense_interface_create($bridge['bridgeif']);
688
		$bridgeif = escapeshellarg($bridge['bridgeif']);
689
	} else {
690
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
691
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
692
		$bridgeif = pfSense_interface_create("bridge");
693
		$bridge['bridgeif'] = $bridgeif;
694
	}
695

    
696
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
697
	if ($bridgemtu > $smallermtu) {
698
		$smallermtu = $bridgemtu;
699
	}
700

    
701
	$checklist = get_configured_interface_list();
702

    
703
	/* Add interfaces to bridge */
704
	foreach ($members as $member) {
705
		if (empty($checklist[$member])) {
706
			continue;
707
		}
708
		$realif = get_real_interface($member);
709
		if (!$realif) {
710
			log_error(gettext("realif not defined in interfaces bridge - up"));
711
			continue;
712
		}
713
		/* make sure the parent interface is up */
714
		pfSense_interface_mtu($realif, $smallermtu);
715
		interfaces_bring_up($realif);
716
		enable_hardware_offloading($member);
717
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
718
	}
719

    
720
	if (isset($bridge['enablestp'])) {
721
		interface_bridge_configure_stp($bridge);
722
	}
723

    
724
	interface_bridge_configure_advanced($bridge);
725

    
726
	interface_bridge_configure_ip6linklocal($bridge);
727

    
728
	if ($bridge['bridgeif']) {
729
		interfaces_bring_up($bridge['bridgeif']);
730
	} else {
731
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
732
	}
733
}
734

    
735
function interface_bridge_configure_stp($bridge) {
736
	if (isset($bridge['enablestp'])) {
737
		$bridgeif = trim($bridge['bridgeif']);
738
		/* configure spanning tree proto */
739
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
740

    
741
		if (!empty($bridge['stp'])) {
742
			$stpifs = explode(',', $bridge['stp']);
743
			foreach ($stpifs as $stpif) {
744
				$realif = get_real_interface($stpif);
745
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
746
			}
747
		}
748
		if (!empty($bridge['maxage'])) {
749
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
750
		}
751
		if (!empty($bridge['fwdelay'])) {
752
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
753
		}
754
		if (!empty($bridge['hellotime'])) {
755
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
756
		}
757
		if (!empty($bridge['priority'])) {
758
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
759
		}
760
		if (!empty($bridge['holdcnt'])) {
761
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
762
		}
763
		if (!empty($bridge['ifpriority'])) {
764
			$pconfig = explode(",", $bridge['ifpriority']);
765
			$ifpriority = array();
766
			foreach ($pconfig as $cfg) {
767
				$embcfg = explode_assoc(":", $cfg);
768
				foreach ($embcfg as $key => $value) {
769
					$ifpriority[$key] = $value;
770
				}
771
			}
772
			foreach ($ifpriority as $key => $value) {
773
				$realif = get_real_interface($key);
774
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
775
			}
776
		}
777
		if (!empty($bridge['ifpathcost'])) {
778
			$pconfig = explode(",", $bridge['ifpathcost']);
779
			$ifpathcost = array();
780
			foreach ($pconfig as $cfg) {
781
				$embcfg = explode_assoc(":", $cfg);
782
				foreach ($embcfg as $key => $value) {
783
					$ifpathcost[$key] = $value;
784
				}
785
			}
786
			foreach ($ifpathcost as $key => $value) {
787
				$realif = get_real_interface($key);
788
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
789
			}
790
		}
791
	}
792
}
793

    
794
function interface_bridge_configure_advanced($bridge) {
795
	$bridgeif = trim($bridge['bridgeif']);
796

    
797
	if ($bridge['maxaddr'] <> "") {
798
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
799
	}
800
	if ($bridge['timeout'] <> "") {
801
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
802
	}
803
	if (!empty($bridge['span'])) {
804
		$spanifs = explode(",", $bridge['span']);
805
		foreach ($spanifs as $spanif) {
806
			$realif = get_real_interface($spanif);
807
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
808
		}
809
	}
810
	if (!empty($bridge['edge'])) {
811
		$edgeifs = explode(',', $bridge['edge']);
812
		foreach ($edgeifs as $edgeif) {
813
			$realif = get_real_interface($edgeif);
814
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
815
		}
816
	}
817
	if (!empty($bridge['autoedge'])) {
818
		$edgeifs = explode(',', $bridge['autoedge']);
819
		foreach ($edgeifs as $edgeif) {
820
			$realif = get_real_interface($edgeif);
821
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
822
		}
823
	}
824
	if (!empty($bridge['ptp'])) {
825
		$ptpifs = explode(',', $bridge['ptp']);
826
		foreach ($ptpifs as $ptpif) {
827
			$realif = get_real_interface($ptpif);
828
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
829
		}
830
	}
831
	if (!empty($bridge['autoptp'])) {
832
		$ptpifs = explode(',', $bridge['autoptp']);
833
		foreach ($ptpifs as $ptpif) {
834
			$realif = get_real_interface($ptpif);
835
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
836
		}
837
	}
838
	if (!empty($bridge['static'])) {
839
		$stickyifs = explode(',', $bridge['static']);
840
		foreach ($stickyifs as $stickyif) {
841
			$realif = get_real_interface($stickyif);
842
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
843
		}
844
	}
845
	if (!empty($bridge['private'])) {
846
		$privateifs = explode(',', $bridge['private']);
847
		foreach ($privateifs as $privateif) {
848
			$realif = get_real_interface($privateif);
849
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
850
		}
851
	}
852
}
853

    
854
function interface_bridge_configure_ip6linklocal($bridge) {
855
	$bridgeif = trim($bridge['bridgeif']);
856

    
857
	$members = explode(',', $bridge['members']);
858
	if (!count($members)) {
859
		return;
860
	}
861

    
862
	$auto_linklocal = isset($bridge['ip6linklocal']);
863
	$bridgeop = $auto_linklocal ? '' : '-';
864
	$memberop = $auto_linklocal ? '-' : '';
865

    
866
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
867
	foreach ($members as $member) {
868
		$realif = get_real_interface($member);
869
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
870
	}
871
}
872

    
873
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
874
	global $config;
875

    
876
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
877
		return;
878
	}
879

    
880
	if ($flagsapplied == false) {
881
		$mtu = get_interface_mtu($bridgeif);
882
		$mtum = get_interface_mtu($interface);
883
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
884
			pfSense_interface_mtu($interface, $mtu);
885
		}
886

    
887
		hardware_offloading_applyflags($interface);
888
		interfaces_bring_up($interface);
889
	}
890

    
891
	pfSense_bridge_add_member($bridgeif, $interface);
892
	if (is_array($config['bridges']['bridged'])) {
893
		foreach ($config['bridges']['bridged'] as $bridge) {
894
			if ($bridgeif == $bridge['bridgeif']) {
895
				interface_bridge_configure_stp($bridge);
896
				interface_bridge_configure_advanced($bridge);
897
			}
898
		}
899
	}
900
}
901

    
902
function interfaces_lagg_configure($realif = "") {
903
	global $config, $g;
904
	if (platform_booting()) {
905
		echo gettext("Configuring LAGG interfaces...");
906
	}
907
	$i = 0;
908
	if (is_array($config['laggs']['lagg']) && count($config['laggs']['lagg'])) {
909
		foreach ($config['laggs']['lagg'] as $lagg) {
910
			if (empty($lagg['laggif'])) {
911
				$lagg['laggif'] = "lagg{$i}";
912
			}
913
			if (!empty($realif) && $realif != $lagg['laggif']) {
914
				continue;
915
			}
916
			/* XXX: Maybe we should report any errors?! */
917
			interface_lagg_configure($lagg);
918
			$i++;
919
		}
920
	}
921
	if (platform_booting()) {
922
		echo gettext("done.") . "\n";
923
	}
924
}
925

    
926
function interface_lagg_configure($lagg) {
927
	global $config, $g;
928

    
929
	if (!is_array($lagg)) {
930
		return -1;
931
	}
932

    
933
	$members = explode(',', $lagg['members']);
934
	if (!count($members)) {
935
		return -1;
936
	}
937

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

    
946
	/* Check if MTU was defined for this lagg interface */
947
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
948
	if ($lagg_mtu == 0 &&
949
	    is_array($config['interfaces'])) {
950
		foreach ($config['interfaces'] as $tmpinterface) {
951
			if ($tmpinterface['if'] == $lagg['laggif'] &&
952
			    !empty($tmpinterface['mtu'])) {
953
				$lagg_mtu = $tmpinterface['mtu'];
954
				break;
955
			}
956
		}
957
	}
958

    
959
	/* Just in case anything is not working well */
960
	if ($lagg_mtu == 0) {
961
		$lagg_mtu = 1500;
962
	}
963

    
964
	foreach ($members as $member) {
965
		if (!does_interface_exist($member)) {
966
			continue;
967
		}
968

    
969
		/* make sure the parent interface is up */
970
		pfSense_interface_mtu($member, $lagg_mtu);
971
		interfaces_bring_up($member);
972
		hardware_offloading_applyflags($member);
973

    
974
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
975
		$laggif = str_replace("\0", "", $laggif);
976
		$member = str_replace("\0", "", $member);
977
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
978
	}
979

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

    
982
	interfaces_bring_up($laggif);
983

    
984
	return $laggif;
985
}
986

    
987
function interfaces_gre_configure($checkparent = 0, $realif = "") {
988
	global $config;
989

    
990
	if (is_array($config['gres']['gre']) && count($config['gres']['gre'])) {
991
		foreach ($config['gres']['gre'] as $i => $gre) {
992
			if (empty($gre['greif'])) {
993
				$gre['greif'] = "gre{$i}";
994
			}
995
			if (!empty($realif) && $realif != $gre['greif']) {
996
				continue;
997
			}
998

    
999
			if ($checkparent == 1) {
1000
				if (substr($gre['if'], 0, 4) == '_vip') {
1001
					continue;
1002
				}
1003
				if (substr($gre['if'], 0, 5) == '_lloc') {
1004
					continue;
1005
				}
1006
				if (!empty($config['interfaces'][$gre['if']]) && $config['interfaces'][$gre['if']]['ipaddrv6'] == "track6") {
1007
					continue;
1008
				}
1009
			} else if ($checkparent == 2) {
1010
				if ((substr($gre['if'], 0, 4) != '_vip' && substr($gre['if'], 0, 5) != '_lloc') &&
1011
				    (empty($config['interfaces'][$gre['if']]) || $config['interfaces'][$gre['if']]['ipaddrv6'] != "track6")) {
1012
					continue;
1013
				}
1014
			}
1015
			/* XXX: Maybe we should report any errors?! */
1016
			interface_gre_configure($gre);
1017
		}
1018
	}
1019
}
1020

    
1021
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1022
function interface_gre_configure(&$gre, $grekey = "") {
1023
	global $config, $g;
1024

    
1025
	if (!is_array($gre)) {
1026
		return -1;
1027
	}
1028

    
1029
	$realif = get_real_interface($gre['if']);
1030
	$realifip = get_interface_ip($gre['if']);
1031
	$realifip6 = get_interface_ipv6($gre['if']);
1032

    
1033
	/* make sure the parent interface is up */
1034
	interfaces_bring_up($realif);
1035

    
1036
	if (platform_booting() || !(empty($gre['greif']))) {
1037
		pfSense_interface_destroy($gre['greif']);
1038
		pfSense_interface_create($gre['greif']);
1039
		$greif = $gre['greif'];
1040
	} else {
1041
		$greif = pfSense_interface_create("gre");
1042
	}
1043

    
1044
	/* Do not change the order here for more see gre(4) NOTES section. */
1045
	if (is_ipaddrv6($gre['remote-addr'])) {
1046
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1047
	} else {
1048
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1049
	}
1050
	if ((is_ipaddrv6($gre['tunnel-local-addr'])) || (is_ipaddrv6($gre['tunnel-remote-addr']))) {
1051
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1052
		//mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gre['tunnel-remote-net']));
1053
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " prefixlen 128");
1054
	} else {
1055
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1056
	}
1057

    
1058
	if ($greif) {
1059
		interfaces_bring_up($greif);
1060
	} else {
1061
		log_error(gettext("Could not bring greif up -- variable not defined."));
1062
	}
1063

    
1064
	if (isset($gre['link1']) && $gre['link1']) {
1065
		mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1066
	}
1067
	if (is_ipaddrv4($gre['tunnel-remote-addr'])) {
1068
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1069
	}
1070
	if (is_ipaddrv6($gre['tunnel-remote-addr'])) {
1071
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr']);
1072
	}
1073

    
1074
	interfaces_bring_up($greif);
1075

    
1076
	return $greif;
1077
}
1078

    
1079
function interfaces_gif_configure($checkparent = 0, $realif = "") {
1080
	global $config;
1081

    
1082
	if (is_array($config['gifs']['gif']) && count($config['gifs']['gif'])) {
1083
		foreach ($config['gifs']['gif'] as $i => $gif) {
1084
			if (empty($gif['gifif'])) {
1085
				$gre['gifif'] = "gif{$i}";
1086
			}
1087
			if (!empty($realif) && $realif != $gif['gifif']) {
1088
				continue;
1089
			}
1090

    
1091
			if ($checkparent == 1) {
1092
				if (substr($gif['if'], 0, 4) == '_vip') {
1093
					continue;
1094
				}
1095
				if (substr($gif['if'], 0, 5) == '_lloc') {
1096
					continue;
1097
				}
1098
				if (!empty($config['interfaces'][$gif['if']]) && $config['interfaces'][$gif['if']]['ipaddrv6'] == "track6") {
1099
					continue;
1100
				}
1101
			}
1102
			else if ($checkparent == 2) {
1103
				if ((substr($gif['if'], 0, 4) != '_vip' && substr($gif['if'], 0, 5) != '_lloc') &&
1104
				    (empty($config['interfaces'][$gif['if']]) || $config['interfaces'][$gif['if']]['ipaddrv6'] != "track6")) {
1105
					continue;
1106
				}
1107
			}
1108
			/* XXX: Maybe we should report any errors?! */
1109
			interface_gif_configure($gif);
1110
		}
1111
	}
1112
}
1113

    
1114
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1115
function interface_gif_configure(&$gif, $gifkey = "") {
1116
	global $config, $g;
1117

    
1118
	if (!is_array($gif)) {
1119
		return -1;
1120
	}
1121

    
1122
	$realif = get_real_interface($gif['if']);
1123
	$ipaddr = get_interface_ip($gif['if']);
1124

    
1125
	if (is_ipaddrv4($gif['remote-addr'])) {
1126
		if (is_ipaddrv4($ipaddr)) {
1127
			$realifip = $ipaddr;
1128
		} else {
1129
			$realifip = get_interface_ip($gif['if']);
1130
		}
1131
		$realifgw = get_interface_gateway($gif['if']);
1132
	} else if (is_ipaddrv6($gif['remote-addr'])) {
1133
		if (is_ipaddrv6($ipaddr)) {
1134
			$realifip = $ipaddr;
1135
		} else {
1136
			$realifip = get_interface_ipv6($gif['if']);
1137
		}
1138
		$realifgw = get_interface_gateway_v6($gif['if']);
1139
	}
1140
	/* make sure the parent interface is up */
1141
	if ($realif) {
1142
		interfaces_bring_up($realif);
1143
	} else {
1144
		log_error(gettext("could not bring realif up -- variable not defined -- interface_gif_configure()"));
1145
	}
1146

    
1147
	if (platform_booting() || !(empty($gif['gifif']))) {
1148
		pfSense_interface_destroy($gif['gifif']);
1149
		pfSense_interface_create($gif['gifif']);
1150
		$gifif = $gif['gifif'];
1151
	} else {
1152
		$gifif = pfSense_interface_create("gif");
1153
	}
1154

    
1155
	/* Do not change the order here for more see gif(4) NOTES section. */
1156
	if (is_ipaddrv6($gif['remote-addr'])) {
1157
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1158
	} else {
1159
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1160
	}
1161
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1162
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1163
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1164
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1165
	} else {
1166
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1167
	}
1168
	if (isset($gif['link1'])) {
1169
		pfSense_interface_flags($gifif, IFF_LINK1);
1170
	}
1171
	if (isset($gif['link2'])) {
1172
		pfSense_interface_flags($gifif, IFF_LINK2);
1173
	}
1174
	if ($gifif) {
1175
		interfaces_bring_up($gifif);
1176
		$gifmtu = "";
1177
		$currentgifmtu = get_interface_mtu($gifif);
1178
		foreach ($config['interfaces'] as $tmpinterface) {
1179
			if ($tmpinterface['if'] == $gifif) {
1180
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1181
					$gifmtu = $tmpinterface['mtu'];
1182
				}
1183
			}
1184
		}
1185
		if (is_numericint($gifmtu)) {
1186
			if ($gifmtu != $currentgifmtu) {
1187
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1188
			}
1189
		}
1190
	} else {
1191
		log_error(gettext("could not bring gifif up -- variable not defined"));
1192
	}
1193

    
1194
	if (!platform_booting()) {
1195
		$iflist = get_configured_interface_list();
1196
		foreach ($iflist as $ifname) {
1197
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1198
				if (get_interface_gateway($ifname)) {
1199
					system_routing_configure($ifname);
1200
					break;
1201
				}
1202
				if (get_interface_gateway_v6($ifname)) {
1203
					system_routing_configure($ifname);
1204
					break;
1205
				}
1206
			}
1207
		}
1208
	}
1209

    
1210

    
1211
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1212
		file_put_contents("{$g['tmp_path']}/{$gifif}_router", $gif['tunnel-remote-addr']);
1213
	}
1214
	if (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1215
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6", $gif['tunnel-remote-addr']);
1216
	}
1217

    
1218
	if (is_ipaddrv4($realifgw)) {
1219
		route_add_or_change("-host {$gif['remote-addr']} {$realifgw}");
1220
	}
1221
	if (is_ipaddrv6($realifgw)) {
1222
		route_add_or_change("-host -inet6 {$gif['remote-addr']} {$realifgw}");
1223
	}
1224

    
1225
	interfaces_bring_up($gifif);
1226

    
1227
	return $gifif;
1228
}
1229

    
1230
/* Build a list of IPsec interfaces */
1231
function interface_ipsec_vti_list_p1($ph1ent) {
1232
	global $config;
1233
	$iface_list = array();
1234

    
1235
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1236
		return $iface_list;
1237
	}
1238

    
1239
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1240
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1241
		return $iface_list;
1242
	}
1243

    
1244
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1245
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1246
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1247
			$iface_list["ipsec{$ph1ent['ikeid']}00{$idx}"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1248
		}
1249
	} else {
1250
		/* For IKEv2, only create one interface with additional addresses as aliases */
1251
		$iface_list["ipsec{$ph1ent['ikeid']}000"] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1252
	}
1253
	return $iface_list;
1254
}
1255
function interface_ipsec_vti_list_all() {
1256
	global $config;
1257
	$iface_list = array();
1258
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1259
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1260
			if ($ph1ent['disabled']) {
1261
				continue;
1262
			}
1263
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1264
		}
1265
	}
1266
	return $iface_list;
1267
}
1268

    
1269
function is_interface_ipsec_vti_assigned($phase2) {
1270
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1271
	$vti_interface = null;
1272
	$vtisubnet_spec = ipsec_vti($phase1, true);
1273
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1274
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1275
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1276
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1277
				/* Is this for this P2? */
1278
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1279
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1280
					$vti_interface = "ipsec{$phase1['ikeid']}00{$idx}";
1281
				}
1282
			}
1283
		} else {
1284
			$vti_interface = "ipsec{$phase1['ikeid']}000";
1285
		}
1286
	}
1287
	/* Check if this interface is assigned */
1288
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1289
}
1290
function interface_ipsec_vti_configure($ph1ent) {
1291
	global $config;
1292

    
1293
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1294
		return false;
1295
	}
1296

    
1297
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1298
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1299
		return false;
1300
	}
1301

    
1302
	$left_spec = ipsec_get_phase1_src($ph1ent);
1303
	$right_spec = $ph1ent['remote-gateway'];
1304

    
1305
	$iface_addrs = array();
1306

    
1307
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1308
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1309
		/* Form a single interface for each P2 entry */
1310
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1311
			$ipsecifnum = "{$ph1ent['ikeid']}00{$idx}";
1312
			if (!is_array($iface_addrs[$ipsecifnum])) {
1313
				$iface_addrs[$ipsecifnum] = array();
1314
			}
1315
			$vtisub['alias'] = "";
1316
			$iface_addrs[$ipsecifnum][] = $vtisub;
1317
		}
1318
	} else {
1319
		/* For IKEv2, only create one interface with additional addresses as aliases */
1320
		$ipsecifnum = "{$ph1ent['ikeid']}000";
1321
		if (!is_array($iface_addrs[$ipsecifnum])) {
1322
			$iface_addrs[$ipsecifnum] = array();
1323
		}
1324
		$have_v4 = false;
1325
		$have_v6 = false;
1326
		foreach ($vtisubnet_spec as $vtisub) {
1327
			// Alias stuff
1328
			$vtisub['alias'] = "";
1329
			if (is_ipaddrv6($vtisub['left'])) {
1330
				if ($have_v6) {
1331
					$vtisub['alias'] = " alias";
1332
				}
1333
				$have_v6 = true;
1334
			} else {
1335
				if ($have_v4) {
1336
					$vtisub['alias'] = " alias";
1337
				}
1338
				$have_v4 = true;
1339
			}
1340
			$iface_addrs[$ipsecifnum][] = $vtisub;
1341
		}
1342
	}
1343

    
1344
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1345
		$ipsecif = "ipsec{$ipsecifnum}";
1346
		if (!is_array($addrs)) {
1347
			continue;
1348
		}
1349
		// Create IPsec interface
1350
		if (platform_booting() || !does_interface_exist($ipsecif)) {
1351
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy", false);
1352
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1353
		} else {
1354
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum), false);
1355
		}
1356

    
1357
		/* Apply the outer tunnel addresses to the interface */
1358
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1359
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up", false);
1360

    
1361
		/* Loop through all of the addresses for this interface and apply them as needed */
1362
		foreach ($addrs as $addr) {
1363
			// apply interface addresses
1364
			if (is_ipaddrv6($addr['left'])) {
1365
				$inet = "inet6";
1366
				$gwtype = "v6";
1367
			} else {
1368
				$inet = "inet";
1369
				$gwtype = "";
1370
			}
1371

    
1372
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . escapeshellarg($addr['right']) . $addr['alias'], false);
1373
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1374
			if (empty($addr['alias'])) {
1375
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1376
			}
1377
		}
1378
		if (!platform_booting()) {
1379
			system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1380
		}
1381
	}
1382
}
1383

    
1384
function interfaces_ipsec_vti_configure() {
1385
	global $config;
1386
	if (platform_booting()) {
1387
		echo gettext("Configuring IPsec VTI interfaces...");
1388
	}
1389
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1390
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1391
			if ($ph1ent['disabled']) {
1392
				continue;
1393
			}
1394
			interface_ipsec_vti_configure($ph1ent);
1395
		}
1396
	}
1397
	if (platform_booting()) {
1398
		echo gettext("done.") . "\n";
1399
	}
1400
}
1401

    
1402
function interfaces_configure() {
1403
	global $config, $g;
1404

    
1405
	/* Set up our loopback interface */
1406
	interfaces_loopback_configure();
1407

    
1408
	/* create the unconfigured wireless clones */
1409
	interfaces_create_wireless_clones();
1410

    
1411
	/* set up LAGG virtual interfaces */
1412
	interfaces_lagg_configure();
1413

    
1414
	/* set up VLAN virtual interfaces */
1415
	interfaces_vlan_configure();
1416

    
1417
	interfaces_qinq_configure();
1418

    
1419
	/* set up IPsec VTI interfaces */
1420
	interfaces_ipsec_vti_configure();
1421

    
1422
	$iflist = get_configured_interface_with_descr();
1423
	$delayed_list = array();
1424
	$bridge_list = array();
1425
	$track6_list = array();
1426

    
1427
	/* This is needed to speedup interfaces on bootup. */
1428
	$reload = false;
1429
	if (!platform_booting()) {
1430
		$reload = true;
1431
	}
1432

    
1433
	foreach ($iflist as $if => $ifname) {
1434
		$realif = $config['interfaces'][$if]['if'];
1435
		if (strstr($realif, "bridge")) {
1436
			$bridge_list[$if] = $ifname;
1437
		} else if (strstr($realif, "gre")) {
1438
			$delayed_list[$if] = $ifname;
1439
		} else if (strstr($realif, "gif")) {
1440
			$delayed_list[$if] = $ifname;
1441
		} else if (strstr($realif, "ovpn")) {
1442
			//echo "Delaying OpenVPN interface configuration...done.\n";
1443
			continue;
1444
		} else if (strstr($realif, "ipsec")) {
1445
			continue;
1446
		} else if (!empty($config['interfaces'][$if]['ipaddrv6']) && $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1447
			$track6_list[$if] = $ifname;
1448
		} else {
1449
			if (platform_booting()) {
1450
				printf(gettext("Configuring %s interface..."), $ifname);
1451
			}
1452

    
1453
			if ($g['debug']) {
1454
				log_error(sprintf(gettext("Configuring %s"), $ifname));
1455
			}
1456
			interface_configure($if, $reload);
1457
			if (platform_booting()) {
1458
				echo gettext("done.") . "\n";
1459
			}
1460
		}
1461
	}
1462

    
1463
	/*
1464
	 * NOTE: The following function parameter consists of
1465
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1466
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1467
	 */
1468

    
1469
	/* set up GRE virtual interfaces */
1470
	interfaces_gre_configure(1);
1471

    
1472
	/* set up GIF virtual interfaces */
1473
	interfaces_gif_configure(1);
1474

    
1475
	/* set up BRIDGe virtual interfaces */
1476
	interfaces_bridge_configure(1);
1477

    
1478
	foreach ($track6_list as $if => $ifname) {
1479
		if (platform_booting()) {
1480
			printf(gettext("Configuring %s interface..."), $ifname);
1481
		}
1482
		if ($g['debug']) {
1483
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1484
		}
1485

    
1486
		interface_configure($if, $reload);
1487

    
1488
		if (platform_booting()) {
1489
			echo gettext("done.") . "\n";
1490
		}
1491
	}
1492

    
1493
	/* bring up vip interfaces */
1494
	interfaces_vips_configure();
1495

    
1496
	/* set up GRE virtual interfaces */
1497
	interfaces_gre_configure(2);
1498

    
1499
	/* set up GIF virtual interfaces */
1500
	interfaces_gif_configure(2);
1501

    
1502
	foreach ($delayed_list as $if => $ifname) {
1503
		if (platform_booting()) {
1504
			printf(gettext("Configuring %s interface..."), $ifname);
1505
		}
1506
		if ($g['debug']) {
1507
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1508
		}
1509

    
1510
		interface_configure($if, $reload);
1511

    
1512
		if (platform_booting()) {
1513
			echo gettext("done.") . "\n";
1514
		}
1515
	}
1516

    
1517
	/* set up BRIDGe virtual interfaces */
1518
	interfaces_bridge_configure(2);
1519

    
1520
	foreach ($bridge_list as $if => $ifname) {
1521
		if (platform_booting()) {
1522
			printf(gettext("Configuring %s interface..."), $ifname);
1523
		}
1524
		if ($g['debug']) {
1525
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1526
		}
1527

    
1528
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1529
		// redmine #3997
1530
		interface_reconfigure($if, $reload);
1531
		interfaces_vips_configure($if);
1532

    
1533
		if (platform_booting()) {
1534
			echo gettext("done.") . "\n";
1535
		}
1536
	}
1537

    
1538
	/* configure interface groups */
1539
	interfaces_group_setup();
1540

    
1541
	if (!platform_booting()) {
1542
		/* reconfigure static routes (kernel may have deleted them) */
1543
		system_routing_configure();
1544

    
1545
		/* reload IPsec tunnels */
1546
		vpn_ipsec_configure();
1547

    
1548
		/* restart dns servers (defering dhcpd reload) */
1549
		if (isset($config['dnsmasq']['enable'])) {
1550
			services_dnsmasq_configure(false);
1551
		}
1552
		if (isset($config['unbound']['enable'])) {
1553
			services_unbound_configure(false);
1554
		}
1555

    
1556
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1557
		services_dhcpd_configure();
1558
	}
1559

    
1560
	return 0;
1561
}
1562

    
1563
function interface_reconfigure($interface = "wan", $reloadall = false) {
1564
	interface_bring_down($interface);
1565
	interface_configure($interface, $reloadall);
1566
}
1567

    
1568
function interface_vip_bring_down($vip) {
1569
	global $g;
1570

    
1571
	$vipif = get_real_interface($vip['interface']);
1572
	switch ($vip['mode']) {
1573
		case "proxyarp":
1574
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1575
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1576
			}
1577
			break;
1578
		case "ipalias":
1579
			if (does_interface_exist($vipif)) {
1580
				if (is_ipaddrv6($vip['subnet'])) {
1581
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1582
				} else {
1583
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1584
				}
1585
			}
1586
			break;
1587
		case "carp":
1588
			/* XXX: Is enough to delete ip address? */
1589
			if (does_interface_exist($vipif)) {
1590
				if (is_ipaddrv6($vip['subnet'])) {
1591
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1592
				} else {
1593
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1594
				}
1595
			}
1596
			break;
1597
	}
1598
}
1599

    
1600
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1601
	global $config, $g;
1602

    
1603
	if (!isset($config['interfaces'][$interface])) {
1604
		return;
1605
	}
1606

    
1607
	if ($g['debug']) {
1608
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1609
	}
1610

    
1611
	/*
1612
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1613
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1614
	 * Keep this in mind while doing changes here!
1615
	 */
1616
	if ($ifacecfg === false) {
1617
		$ifcfg = $config['interfaces'][$interface];
1618
		$ppps = $config['ppps']['ppp'];
1619
		$realif = get_real_interface($interface);
1620
		$realifv6 = get_real_interface($interface, "inet6", true);
1621
	} elseif (!is_array($ifacecfg)) {
1622
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1623
		$ifcfg = $config['interfaces'][$interface];
1624
		$ppps = $config['ppps']['ppp'];
1625
		$realif = get_real_interface($interface);
1626
		$realifv6 = get_real_interface($interface, "inet6", true);
1627
	} else {
1628
		$ifcfg = $ifacecfg['ifcfg'];
1629
		$ppps = $ifacecfg['ppps'];
1630
		if (isset($ifacecfg['ifcfg']['realif'])) {
1631
			$realif = $ifacecfg['ifcfg']['realif'];
1632
			/* XXX: Any better way? */
1633
			$realifv6 = $realif;
1634
		} else {
1635
			$realif = get_real_interface($interface);
1636
			$realifv6 = get_real_interface($interface, "inet6", true);
1637
		}
1638
	}
1639

    
1640
	switch ($ifcfg['ipaddr']) {
1641
		case "ppp":
1642
		case "pppoe":
1643
		case "pptp":
1644
		case "l2tp":
1645
			if (is_array($ppps) && count($ppps)) {
1646
				foreach ($ppps as $pppid => $ppp) {
1647
					if ($realif == $ppp['if']) {
1648
						if (isset($ppp['ondemand']) && !$destroy) {
1649
							send_event("interface reconfigure {$interface}");
1650
							break;
1651
						}
1652
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1653
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1654
							sleep(2);
1655
						}
1656
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1657
						break;
1658
					}
1659
				}
1660
			}
1661
			break;
1662
		case "dhcp":
1663
			kill_dhclient_process($realif);
1664
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1665
			if (does_interface_exist("$realif")) {
1666
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1667
				interface_vip_cleanup($interface, "inet4");
1668
				if ($destroy == true) {
1669
					pfSense_interface_flags($realif, -IFF_UP);
1670
				}
1671
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1672
			}
1673
			break;
1674
		default:
1675
			if (does_interface_exist("$realif")) {
1676
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1677
				interface_vip_cleanup($interface, "inet4");
1678
				if ($destroy == true) {
1679
					pfSense_interface_flags($realif, -IFF_UP);
1680
				}
1681
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1682
			}
1683
			break;
1684
	}
1685

    
1686
	$track6 = array();
1687
	switch ($ifcfg['ipaddrv6']) {
1688
		case "slaac":
1689
		case "dhcp6":
1690
			kill_dhcp6client_process($realif, $destroy, false);
1691
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
1692
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
1693
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
1694
			if (does_interface_exist($realifv6)) {
1695
				$ip6 = find_interface_ipv6($realifv6);
1696
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1697
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1698
				}
1699
				interface_vip_cleanup($interface, "inet6");
1700
				if ($destroy == true) {
1701
					pfSense_interface_flags($realif, -IFF_UP);
1702
				}
1703
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1704
			}
1705
			$track6 = link_interface_to_track6($interface);
1706
			break;
1707
		case "6rd":
1708
		case "6to4":
1709
			$realif = "{$interface}_stf";
1710
			if (does_interface_exist("$realif")) {
1711
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1712
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1713
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1714
					$destroy = true;
1715
				} else {
1716
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1717
					$ip6 = get_interface_ipv6($interface);
1718
					if (is_ipaddrv6($ip6)) {
1719
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1720
					}
1721
				}
1722
				interface_vip_cleanup($interface, "inet6");
1723
				if ($destroy == true) {
1724
					pfSense_interface_flags($realif, -IFF_UP);
1725
				}
1726
			}
1727
			$track6 = link_interface_to_track6($interface);
1728
			break;
1729
		default:
1730
			if (does_interface_exist("$realif")) {
1731
				$ip6 = get_interface_ipv6($interface);
1732
				if (is_ipaddrv6($ip6)) {
1733
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1734
				}
1735
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1736
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1737
				}
1738
				interface_vip_cleanup($interface, "inet6");
1739
				if ($destroy == true) {
1740
					pfSense_interface_flags($realif, -IFF_UP);
1741
				}
1742
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1743
			}
1744
			$track6 = link_interface_to_track6($interface);
1745
			break;
1746
	}
1747

    
1748
	if (!empty($track6) && is_array($track6)) {
1749
		if (!function_exists('services_dhcpd_configure')) {
1750
			require_once('services.inc');
1751
		}
1752
		/* Bring down radvd and dhcp6 on these interfaces */
1753
		services_dhcpd_configure('inet6', $track6);
1754
	}
1755

    
1756
	$old_router = '';
1757
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1758
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
1759
	}
1760

    
1761
	/* remove interface up file if it exists */
1762
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1763
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1764
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1765
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
1766
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
1767
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1768
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1769

    
1770
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1771
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1772
	if (is_array($ifcfg['wireless'])) {
1773
		kill_hostapd($realif);
1774
		mwexec(kill_wpasupplicant($realif));
1775
	}
1776

    
1777
	if ($destroy == true) {
1778
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1779
			pfSense_interface_destroy($realif);
1780
		}
1781
	}
1782

    
1783
	return;
1784
}
1785

    
1786
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1787
	global $config;
1788
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
1789
		unset($config["virtualip_carp_maintenancemode"]);
1790
		write_config("Leave CARP maintenance mode");
1791
	} else if (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
1792
		$config["virtualip_carp_maintenancemode"] = true;
1793
		write_config(gettext("Enter CARP maintenance mode"));
1794
	}
1795

    
1796
	$viparr = &$config['virtualip']['vip'];
1797

    
1798
	if (is_array($viparr)) {
1799
		foreach ($viparr as $vip) {
1800
			if ($vip['mode'] == "carp") {
1801
				interface_carp_configure($vip);
1802
			}
1803
		}
1804
	}
1805
}
1806

    
1807
function interface_wait_tentative($interface, $timeout = 10) {
1808
	if (!does_interface_exist($interface)) {
1809
		return false;
1810
	}
1811

    
1812
	$time = 0;
1813
	while ($time <= $timeout) {
1814
		$if = pfSense_get_interface_addresses($interface);
1815
		if (!isset($if['tentative'])) {
1816
			return true;
1817
		}
1818
		sleep(1);
1819
		$time++;
1820
	}
1821

    
1822
	return false;
1823
}
1824

    
1825
function interface_isppp_type($interface) {
1826
	global $config;
1827

    
1828
	if (!is_array($config['interfaces'][$interface])) {
1829
		return false;
1830
	}
1831

    
1832
	switch ($config['interfaces'][$interface]['ipaddr']) {
1833
		case 'pptp':
1834
		case 'l2tp':
1835
		case 'pppoe':
1836
		case 'ppp':
1837
			return true;
1838
			break;
1839
		default:
1840
			return false;
1841
			break;
1842
	}
1843
}
1844

    
1845
function interfaces_ptpid_used($ptpid) {
1846
	global $config;
1847

    
1848
	if (is_array($config['ppps']['ppp'])) {
1849
		foreach ($config['ppps']['ppp'] as & $settings) {
1850
			if ($ptpid == $settings['ptpid']) {
1851
				return true;
1852
			}
1853
		}
1854
	}
1855

    
1856
	return false;
1857
}
1858

    
1859
function interfaces_ptpid_next() {
1860

    
1861
	$ptpid = 0;
1862
	while (interfaces_ptpid_used($ptpid)) {
1863
		$ptpid++;
1864
	}
1865

    
1866
	return $ptpid;
1867
}
1868

    
1869
function getMPDCRONSettings($pppif) {
1870
	global $config;
1871

    
1872
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1873
	if (is_array($config['cron']['item'])) {
1874
		foreach ($config['cron']['item'] as $i => $item) {
1875
			if (stripos($item['command'], $cron_cmd_file) !== false) {
1876
				return array("ID" => $i, "ITEM" => $item);
1877
			}
1878
		}
1879
	}
1880

    
1881
	return NULL;
1882
}
1883

    
1884
function handle_pppoe_reset($post_array) {
1885
	global $config, $g;
1886

    
1887
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
1888
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
1889

    
1890
	if (!is_array($config['cron']['item'])) {
1891
		$config['cron']['item'] = array();
1892
	}
1893

    
1894
	$itemhash = getMPDCRONSettings($pppif);
1895

    
1896
	// reset cron items if necessary and return
1897
	if (empty($post_array['pppoe-reset-type'])) {
1898
		if (isset($itemhash)) {
1899
			unset($config['cron']['item'][$itemhash['ID']]);
1900
		}
1901
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
1902
		return;
1903
	}
1904

    
1905
	if (empty($itemhash)) {
1906
		$itemhash = array();
1907
	}
1908
	$item = array();
1909
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
1910
		$item['minute'] = $post_array['pppoe_resetminute'];
1911
		$item['hour'] = $post_array['pppoe_resethour'];
1912
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
1913
			$date = explode("/", $post_array['pppoe_resetdate']);
1914
			$item['mday'] = $date[1];
1915
			$item['month'] = $date[0];
1916
		} else {
1917
			$item['mday'] = "*";
1918
			$item['month'] = "*";
1919
		}
1920
		$item['wday'] = "*";
1921
		$item['who'] = "root";
1922
		$item['command'] = $cron_cmd_file;
1923
	} else if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
1924
		switch ($post_array['pppoe_pr_preset_val']) {
1925
			case "monthly":
1926
				$item['minute'] = "0";
1927
				$item['hour'] = "0";
1928
				$item['mday'] = "1";
1929
				$item['month'] = "*";
1930
				$item['wday'] = "*";
1931
				break;
1932
			case "weekly":
1933
				$item['minute'] = "0";
1934
				$item['hour'] = "0";
1935
				$item['mday'] = "*";
1936
				$item['month'] = "*";
1937
				$item['wday'] = "0";
1938
				break;
1939
			case "daily":
1940
				$item['minute'] = "0";
1941
				$item['hour'] = "0";
1942
				$item['mday'] = "*";
1943
				$item['month'] = "*";
1944
				$item['wday'] = "*";
1945
				break;
1946
			case "hourly":
1947
				$item['minute'] = "0";
1948
				$item['hour'] = "*";
1949
				$item['mday'] = "*";
1950
				$item['month'] = "*";
1951
				$item['wday'] = "*";
1952
				break;
1953
		} // end switch
1954
		$item['who'] = "root";
1955
		$item['command'] = $cron_cmd_file;
1956
	}
1957
	if (empty($item)) {
1958
		return;
1959
	}
1960
	if (isset($itemhash['ID'])) {
1961
		$config['cron']['item'][$itemhash['ID']] = $item;
1962
	} else {
1963
		$config['cron']['item'][] = $item;
1964
	}
1965
}
1966

    
1967
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
1968
	global $config;
1969
	$ppp_list = array();
1970
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1971
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1972
			$ports = explode(",", $ppp['ports']);
1973
			foreach($ports as $port) {
1974
				foreach($triggerinterfaces as $vip) {
1975
					if ($port == "_vip{$vip['uniqid']}") {
1976
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
1977
						$ppp_list[$if] = 1;
1978
					}
1979
				}
1980
			}
1981
		}
1982
	}
1983
	foreach($ppp_list as $pppif => $dummy) {
1984
		interface_ppps_configure($pppif);
1985
	}
1986
}
1987

    
1988
/*
1989
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
1990
 * It writes the mpd config file to /var/etc every time the link is opened.
1991
 */
1992
function interface_ppps_configure($interface) {
1993
	global $config, $g;
1994

    
1995
	/* Return for unassigned interfaces. This is a minimum requirement. */
1996
	if (empty($config['interfaces'][$interface])) {
1997
		return 0;
1998
	}
1999
	$ifcfg = $config['interfaces'][$interface];
2000
	if (!isset($ifcfg['enable'])) {
2001
		return 0;
2002
	}
2003

    
2004
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2005
	if (!is_dir("/var/spool/lock")) {
2006
		mkdir("/var/spool/lock", 0777, true);
2007
	}
2008
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2009
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2010
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2011
	}
2012

    
2013
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2014
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2015
			if ($ifcfg['if'] == $ppp['if']) {
2016
				break;
2017
			}
2018
		}
2019
	}
2020
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2021
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2022
		return 0;
2023
	}
2024
	$pppif = $ifcfg['if'];
2025
	if ($ppp['type'] == "ppp") {
2026
		$type = "modem";
2027
	} else {
2028
		$type = $ppp['type'];
2029
	}
2030
	$upper_type = strtoupper($ppp['type']);
2031

    
2032
	/* XXX: This does not make sense and may create trouble
2033
	 * comment it for now to be removed later on.
2034
	if (platform_booting()) {
2035
		$descr = isset($ifcfg['descr']) ? $ifcfg['descr'] : strtoupper($interface);
2036
		echo "starting {$pppif} link...";
2037
		if (isvalidpid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid"))
2038
			return 0;
2039
	}
2040
	*/
2041
	$confports = explode(',', $ppp['ports']);
2042
	if ($type == "modem") {
2043
		$ports = $confports;
2044
	} else {
2045
		$ports = array();
2046
		foreach ($confports as $pid => $port) {
2047
			if (strstr($port, "_vip")) {
2048
				if (get_carp_interface_status($port) != "MASTER") {
2049
					continue;
2050
				}
2051
			}
2052
			$ports[$pid] = get_real_interface($port);
2053
			if (empty($ports[$pid])) {
2054
				return 0;
2055
			}
2056
		}
2057
	}
2058
	$localips = explode(',', $ppp['localip']);
2059
	$gateways = explode(',', $ppp['gateway']);
2060
	$subnets = explode(',', $ppp['subnet']);
2061

    
2062
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2063
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2064
	 */
2065
	foreach ($ports as $pid => $port) {
2066
		switch ($ppp['type']) {
2067
			case "pppoe":
2068
				/* Bring the parent interface up */
2069
				interfaces_bring_up($port);
2070
				pfSense_ngctl_attach(".", $port);
2071
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2072
				$ngif = str_replace(".", "_", $port);
2073
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2074
				break;
2075
			case "pptp":
2076
			case "l2tp":
2077
				/* configure interface */
2078
				if (is_ipaddr($localips[$pid])) {
2079
					// Manually configure interface IP/subnet
2080
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2081
					interfaces_bring_up($port);
2082
				} else if (empty($localips[$pid])) {
2083
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2084
				}
2085

    
2086
				if (!is_ipaddr($localips[$pid])) {
2087
					log_error(sprintf(gettext("Could not get a Local IP address for PPTP/L2TP link on %s in interfaces_ppps_configure. Using 0.0.0.0 ip!"), $port));
2088
					$localips[$pid] = "0.0.0.0";
2089
				}
2090
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2091
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2092
				}
2093
				if (!is_ipaddr($gateways[$pid])) {
2094
					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));
2095
					return 0;
2096
				}
2097
				pfSense_ngctl_attach(".", $port);
2098
				break;
2099
			case "ppp":
2100
				if (!file_exists("{$port}")) {
2101
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2102
					return 0;
2103
				}
2104
				break;
2105
			default:
2106
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2107
				break;
2108
		}
2109
	}
2110

    
2111
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2112
	    (is_array($ports) && count($ports) > 1)) {
2113
		$multilink = "enable";
2114
	} else {
2115
		$multilink = "disable";
2116
	}
2117

    
2118
	if ($type == "modem") {
2119
		if (is_ipaddr($ppp['localip'])) {
2120
			$localip = $ppp['localip'];
2121
		} else {
2122
			$localip = '0.0.0.0';
2123
		}
2124

    
2125
		if (is_ipaddr($ppp['gateway'])) {
2126
			$gateway = $ppp['gateway'];
2127
		} else {
2128
			$gateway = "10.64.64.{$pppid}";
2129
		}
2130
		$ranges = "{$localip}/0 {$gateway}/0";
2131

    
2132
		if (empty($ppp['apnum'])) {
2133
			$ppp['apnum'] = 1;
2134
		}
2135
	} else {
2136
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2137
	}
2138

    
2139
	if (isset($ppp['ondemand'])) {
2140
		$ondemand = "enable";
2141
	} else {
2142
		$ondemand = "disable";
2143
	}
2144
	if (!isset($ppp['idletimeout'])) {
2145
		$ppp['idletimeout'] = 0;
2146
	}
2147

    
2148
	if (empty($ppp['username']) && $type == "modem") {
2149
		$ppp['username'] = "user";
2150
		$ppp['password'] = "none";
2151
	}
2152
	if (empty($ppp['password']) && $type == "modem") {
2153
		$passwd = "none";
2154
	} else {
2155
		$passwd = base64_decode($ppp['password']);
2156
	}
2157

    
2158
	$bandwidths = explode(',', $ppp['bandwidth']);
2159
	$defaultmtu = "1492";
2160
	if (!empty($ifcfg['mtu'])) {
2161
		$defaultmtu = intval($ifcfg['mtu']);
2162
	}
2163
	if (isset($ppp['mtu'])) {
2164
		$mtus = explode(',', $ppp['mtu']);
2165
	}
2166
	if (isset($ppp['mru'])) {
2167
		$mrus = explode(',', $ppp['mru']);
2168
	}
2169
	if (isset($ppp['mrru'])) {
2170
		$mrrus = explode(',', $ppp['mrru']);
2171
	}
2172

    
2173
	// Construct the mpd.conf file
2174
	$mpdconf = <<<EOD
2175
startup:
2176
	# configure the console
2177
	set console close
2178
	# configure the web server
2179
	set web close
2180

    
2181
default:
2182
{$ppp['type']}client:
2183
	create bundle static {$interface}
2184
	set bundle enable ipv6cp
2185
	set iface name {$pppif}
2186

    
2187
EOD;
2188
	$setdefaultgw = false;
2189
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2190
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2191
	if ($defgw4['interface'] == $interface) {
2192
		$setdefaultgw = true;
2193
	}
2194

    
2195
/* Omit this, we maintain the default route by other means, and it causes problems with
2196
 * default gateway switching. See redmine #1837 for original issue
2197
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2198
 * edge case. redmine #6495 open to address.
2199
 */
2200
	if ($setdefaultgw == true) {
2201
		$mpdconf .= <<<EOD
2202
	set iface route default
2203

    
2204
EOD;
2205
	}
2206

    
2207
	$mpdconf .= <<<EOD
2208
	set iface {$ondemand} on-demand
2209
	set iface idle {$ppp['idletimeout']}
2210

    
2211
EOD;
2212

    
2213
	if (isset($ppp['ondemand'])) {
2214
		$mpdconf .= <<<EOD
2215
	set iface addrs 10.10.1.1 10.10.1.2
2216

    
2217
EOD;
2218
	}
2219

    
2220
	if (isset($ppp['mtu-override']) &&
2221
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2222
		/* Find the smaller MTU set on ports */
2223
		$mtu = $defaultmtu;
2224
		foreach ($ports as $pid => $port) {
2225
			if (empty($mtus[$pid])) {
2226
				$mtus[$pid] = $defaultmtu;
2227
			}
2228
			if ($type == "pppoe") {
2229
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2230
					$mtus[$pid] = get_interface_mtu($port) - 8;
2231
				}
2232
			}
2233
			if ($mtu > $mtus[$pid]) {
2234
				$mtu = $mtus[$pid];
2235
			}
2236
		}
2237
		$mpdconf .= <<<EOD
2238
	set iface mtu {$mtu} override
2239

    
2240
EOD;
2241
	}
2242

    
2243
	if (isset($ppp['tcpmssfix'])) {
2244
		$tcpmss = "disable";
2245
	} else {
2246
		$tcpmss = "enable";
2247
	}
2248
	$mpdconf .= <<<EOD
2249
	set iface {$tcpmss} tcpmssfix
2250

    
2251
EOD;
2252

    
2253
	$mpdconf .= <<<EOD
2254
	set iface up-script /usr/local/sbin/ppp-linkup
2255
	set iface down-script /usr/local/sbin/ppp-linkdown
2256
	set ipcp ranges {$ranges}
2257

    
2258
EOD;
2259
	if (isset($ppp['vjcomp'])) {
2260
		$mpdconf .= <<<EOD
2261
	set ipcp no vjcomp
2262

    
2263
EOD;
2264
	}
2265

    
2266
	if (isset($config['system']['dnsallowoverride'])) {
2267
		$mpdconf .= <<<EOD
2268
	set ipcp enable req-pri-dns
2269
	set ipcp enable req-sec-dns
2270

    
2271
EOD;
2272
	}
2273

    
2274
	if (!isset($ppp['verbose_log'])) {
2275
		$mpdconf .= <<<EOD
2276
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2277

    
2278
EOD;
2279
	}
2280

    
2281
	foreach ($ports as $pid => $port) {
2282
		$port = get_real_interface($port);
2283
		$mpdconf .= <<<EOD
2284

    
2285
	create link static {$interface}_link{$pid} {$type}
2286
	set link action bundle {$interface}
2287
	set link {$multilink} multilink
2288
	set link keep-alive 10 60
2289
	set link max-redial 0
2290

    
2291
EOD;
2292
		if (isset($ppp['shortseq'])) {
2293
			$mpdconf .= <<<EOD
2294
	set link no shortseq
2295

    
2296
EOD;
2297
		}
2298

    
2299
		if (isset($ppp['acfcomp'])) {
2300
			$mpdconf .= <<<EOD
2301
	set link no acfcomp
2302

    
2303
EOD;
2304
		}
2305

    
2306
		if (isset($ppp['protocomp'])) {
2307
			$mpdconf .= <<<EOD
2308
	set link no protocomp
2309

    
2310
EOD;
2311
		}
2312

    
2313
		$mpdconf .= <<<EOD
2314
	set link disable chap pap
2315
	set link accept chap pap eap
2316
	set link disable incoming
2317

    
2318
EOD;
2319

    
2320

    
2321
		if (!empty($bandwidths[$pid])) {
2322
			$mpdconf .= <<<EOD
2323
	set link bandwidth {$bandwidths[$pid]}
2324

    
2325
EOD;
2326
		}
2327

    
2328
		if (empty($mtus[$pid])) {
2329
			$mtus[$pid] = $defaultmtu;
2330
		}
2331
		if ($type == "pppoe") {
2332
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2333
				$mtus[$pid] = get_interface_mtu($port) - 8;
2334
			}
2335
		}
2336
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2337
		    !isset($ppp['mtu-override']) &&
2338
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2339
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2340
			$mpdconf .= <<<EOD
2341
	set link mtu {$mtus[$pid]}
2342

    
2343
EOD;
2344
		}
2345

    
2346
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2347
		    !isset($ppp['mtu-override']) &&
2348
		    !empty($mrus[$pid])) {
2349
			$mpdconf .= <<<EOD
2350
	set link mru {$mrus[$pid]}
2351

    
2352
EOD;
2353
		}
2354

    
2355
		if (!empty($mrrus[$pid])) {
2356
			$mpdconf .= <<<EOD
2357
	set link mrru {$mrrus[$pid]}
2358

    
2359
EOD;
2360
		}
2361

    
2362
		$mpdconf .= <<<EOD
2363
	set auth authname "{$ppp['username']}"
2364
	set auth password {$passwd}
2365

    
2366
EOD;
2367
		if ($type == "modem") {
2368
			$mpdconf .= <<<EOD
2369
	set modem device {$ppp['ports']}
2370
	set modem script DialPeer
2371
	set modem idle-script Ringback
2372
	set modem watch -cd
2373
	set modem var \$DialPrefix "DT"
2374
	set modem var \$Telephone "{$ppp['phone']}"
2375

    
2376
EOD;
2377
		}
2378
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2379
			$mpdconf .= <<<EOD
2380
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2381

    
2382
EOD;
2383
		}
2384
		if (isset($ppp['initstr']) && $type == "modem") {
2385
			$initstr = base64_decode($ppp['initstr']);
2386
			$mpdconf .= <<<EOD
2387
	set modem var \$InitString "{$initstr}"
2388

    
2389
EOD;
2390
		}
2391
		if (isset($ppp['simpin']) && $type == "modem") {
2392
			if ($ppp['pin-wait'] == "") {
2393
				$ppp['pin-wait'] = 0;
2394
			}
2395
			$mpdconf .= <<<EOD
2396
	set modem var \$SimPin "{$ppp['simpin']}"
2397
	set modem var \$PinWait "{$ppp['pin-wait']}"
2398

    
2399
EOD;
2400
		}
2401
		if (isset($ppp['apn']) && $type == "modem") {
2402
			$mpdconf .= <<<EOD
2403
	set modem var \$APN "{$ppp['apn']}"
2404
	set modem var \$APNum "{$ppp['apnum']}"
2405

    
2406
EOD;
2407
		}
2408
		if ($type == "pppoe") {
2409
			// Send a null service name if none is set.
2410
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2411
			$mpdconf .= <<<EOD
2412
	set pppoe service "{$provider}"
2413

    
2414
EOD;
2415
		}
2416
		if ($type == "pppoe" && $mtus[$pid] > 1492) {
2417
			$mpdconf .= <<<EOD
2418
	set pppoe max-payload {$mtus[$pid]}
2419

    
2420
EOD;
2421
		}
2422
		if ($type == "pppoe") {
2423
			$mpdconf .= <<<EOD
2424
	set pppoe iface {$port}
2425

    
2426
EOD;
2427
		}
2428

    
2429
		if ($type == "pptp" || $type == "l2tp") {
2430
			$mpdconf .= <<<EOD
2431
	set {$type} self {$localips[$pid]}
2432
	set {$type} peer {$gateways[$pid]}
2433

    
2434
EOD;
2435
		}
2436

    
2437
		$mpdconf .= "\topen\n";
2438
	} //end foreach ($port)
2439

    
2440

    
2441
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2442
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2443
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2444
	} else {
2445
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2446
		if (!$fd) {
2447
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2448
			return 0;
2449
		}
2450
		// Write out mpd_ppp.conf
2451
		fwrite($fd, $mpdconf);
2452
		fclose($fd);
2453
		unset($mpdconf);
2454
	}
2455

    
2456
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2457
	if (isset($ppp['uptime'])) {
2458
		if (!file_exists("/conf/{$pppif}.log")) {
2459
			file_put_contents("/conf/{$pppif}.log", '');
2460
		}
2461
	} else {
2462
		if (file_exists("/conf/{$pppif}.log")) {
2463
			@unlink("/conf/{$pppif}.log");
2464
		}
2465
	}
2466

    
2467
	/* clean up old lock files */
2468
	foreach ($ports as $port) {
2469
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2470
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2471
		}
2472
	}
2473

    
2474
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2475
	/* random IPv6 interface identifier during boot. More details at */
2476
	/* https://forum.pfsense.org/index.php?topic=101967.msg570519#msg570519 */
2477
	if (platform_booting() && is_array($config['interfaces'])) {
2478
		$count = 0;
2479
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2480
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2481
				$tempaddr[$count]['if'] = $tempiface['if'];
2482
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2483
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2484
				$count++;
2485
			}
2486
			// Maximum /31 is is x.y.z.254/31
2487
			if ($count > 122) {
2488
				break;
2489
			}
2490
		}
2491
		unset($count);
2492
	}
2493

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

    
2499
	// Check for PPPoE periodic reset request
2500
	if ($type == "pppoe") {
2501
		if (!empty($ppp['pppoe-reset-type'])) {
2502
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2503
		} else {
2504
			interface_setup_pppoe_reset_file($ppp['if']);
2505
		}
2506
	}
2507
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2508
	$i = 0;
2509
	while ($i < 10) {
2510
		if (does_interface_exist($ppp['if'], true)) {
2511
			break;
2512
		}
2513
		sleep(3);
2514
		$i++;
2515
	}
2516

    
2517
	/* Remove all temporary bogon IPv4 addresses */
2518
	if (is_array($tempaddr)) {
2519
		foreach ($tempaddr as $tempiface) {
2520
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2521
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2522
			}
2523
		}
2524
		unset ($tempaddr);
2525
	}
2526

    
2527
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2528
	/* We should be able to launch the right version for each modem */
2529
	/* We can also guess the mondev from the manufacturer */
2530
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2531
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2532
	foreach ($ports as $port) {
2533
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2534
			$mondev = substr(basename($port), 0, -1);
2535
			$devlist = glob("/dev/{$mondev}?");
2536
			$mondev = basename(end($devlist));
2537
		}
2538
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2539
			$mondev = substr(basename($port), 0, -1) . "1";
2540
		}
2541
		if ($mondev != '') {
2542
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2543
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2544
		}
2545
	}
2546

    
2547
	return 1;
2548
}
2549

    
2550
function interfaces_sync_setup() {
2551
	global $g, $config;
2552

    
2553
	if (isset($config['system']['developerspew'])) {
2554
		$mt = microtime();
2555
		echo "interfaces_sync_setup() being called $mt\n";
2556
	}
2557

    
2558
	if (platform_booting()) {
2559
		echo gettext("Configuring CARP settings...");
2560
		mute_kernel_msgs();
2561
	}
2562

    
2563
	/* suck in configuration items */
2564
	if ($config['hasync']) {
2565
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2566
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2567
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2568
	} else {
2569
		unset($pfsyncinterface);
2570
		unset($pfsyncenabled);
2571
	}
2572

    
2573
	set_sysctl(array(
2574
		"net.inet.carp.preempt" => "1",
2575
		"net.inet.carp.log" => "1")
2576
	);
2577

    
2578
	if (!empty($pfsyncinterface)) {
2579
		$carp_sync_int = get_real_interface($pfsyncinterface);
2580
	} else {
2581
		unset($carp_sync_int);
2582
	}
2583

    
2584
	/* setup pfsync interface */
2585
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2586
		if (is_ipaddr($pfsyncpeerip)) {
2587
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2588
		} else {
2589
			$syncpeer = "-syncpeer";
2590
		}
2591

    
2592
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} {$syncpeer} up", false);
2593
		mwexec("/sbin/ifconfig pfsync0 -defer", false);
2594

    
2595
		sleep(1);
2596

    
2597
		/* 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
2598
		 * for existing sessions.
2599
		 */
2600
		log_error(gettext("waiting for pfsync..."));
2601
		$i = 0;
2602
		while (intval(trim(`/sbin/ifconfig pfsync0 | /usr/bin/grep 'syncok: 0' | /usr/bin/grep -v grep | /usr/bin/wc -l`)) == 0 && $i < 30) {
2603
			$i++;
2604
			sleep(1);
2605
		}
2606
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2607
		log_error(gettext("Configuring CARP settings finalize..."));
2608
	} else {
2609
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down", false);
2610
	}
2611

    
2612
	$carplist = get_configured_vip_list('all', VIP_CARP);
2613
	if (isset($carplist) && is_array($carplist) && count($carplist) > 0) {
2614
		set_single_sysctl("net.inet.carp.allow", "1");
2615
	} else {
2616
		set_single_sysctl("net.inet.carp.allow", "0");
2617
	}
2618

    
2619
	if (platform_booting()) {
2620
		unmute_kernel_msgs();
2621
		echo gettext("done.") . "\n";
2622
	}
2623
}
2624

    
2625
function interface_proxyarp_configure($interface = "") {
2626
	global $config, $g;
2627
	if (isset($config['system']['developerspew'])) {
2628
		$mt = microtime();
2629
		echo "interface_proxyarp_configure() being called $mt\n";
2630
	}
2631

    
2632
	/* kill any running choparp */
2633
	if (empty($interface)) {
2634
		killbyname("choparp");
2635
	} else {
2636
		$vipif = get_real_interface($interface);
2637
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2638
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2639
		}
2640
	}
2641

    
2642
	$paa = array();
2643
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2644

    
2645
		/* group by interface */
2646
		foreach ($config['virtualip']['vip'] as $vipent) {
2647
			if ($vipent['mode'] === "proxyarp") {
2648
				if ($vipent['interface']) {
2649
					$proxyif = $vipent['interface'];
2650
				} else {
2651
					$proxyif = "wan";
2652
				}
2653

    
2654
				if (!empty($interface) && $interface != $proxyif) {
2655
					continue;
2656
				}
2657

    
2658
				if (!is_array($paa[$proxyif])) {
2659
					$paa[$proxyif] = array();
2660
				}
2661

    
2662
				$paa[$proxyif][] = $vipent;
2663
			}
2664
		}
2665
	}
2666

    
2667
	if (!empty($interface)) {
2668
		if (is_array($paa[$interface])) {
2669
			$paaifip = get_interface_ip($interface);
2670
			if (!is_ipaddr($paaifip)) {
2671
				return;
2672
			}
2673
			$vipif = get_real_interface($interface);
2674
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2675
			$args .= $vipif . " auto";
2676
			foreach ($paa[$interface] as $paent) {
2677
				if (isset($paent['subnet'])) {
2678
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2679
				} else if (isset($paent['range'])) {
2680
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2681
				}
2682
			}
2683
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2684
		}
2685
	} else if (count($paa) > 0) {
2686
		foreach ($paa as $paif => $paents) {
2687
			$paaifip = get_interface_ip($paif);
2688
			if (!is_ipaddr($paaifip)) {
2689
				continue;
2690
			}
2691
			$vipif = get_real_interface($paif);
2692
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2693
			$args .= $vipif . " auto";
2694
			foreach ($paents as $paent) {
2695
				if (isset($paent['subnet'])) {
2696
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2697
				} else if (isset($paent['range'])) {
2698
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2699
				}
2700
			}
2701
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2702
		}
2703
	}
2704
}
2705

    
2706
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2707
	global $g, $config;
2708

    
2709
	if (is_array($config['virtualip']['vip'])) {
2710
		foreach ($config['virtualip']['vip'] as $vip) {
2711

    
2712
			$iface = $vip['interface'];
2713
			if (substr($iface, 0, 4) == "_vip")
2714
				$iface = get_configured_vip_interface($vip['interface']);
2715
			if ($iface != $interface)
2716
				continue;
2717
			if ($type == VIP_CARP) {
2718
				if ($vip['mode'] != "carp")
2719
					continue;
2720
			} elseif ($type == VIP_IPALIAS) {
2721
				if ($vip['mode'] != "ipalias")
2722
					continue;
2723
			} else {
2724
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2725
					continue;
2726
			}
2727

    
2728
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2729
				interface_vip_bring_down($vip);
2730
			else if ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2731
				interface_vip_bring_down($vip);
2732
			else if ($inet == "all")
2733
				interface_vip_bring_down($vip);
2734
		}
2735
	}
2736
}
2737

    
2738
function interfaces_vips_configure($interface = "") {
2739
	global $g, $config;
2740
	if (isset($config['system']['developerspew'])) {
2741
		$mt = microtime();
2742
		echo "interfaces_vips_configure() being called $mt\n";
2743
	}
2744
	$paa = array();
2745
	if (is_array($config['virtualip']['vip'])) {
2746
		$carp_setuped = false;
2747
		$anyproxyarp = false;
2748
		foreach ($config['virtualip']['vip'] as $vip) {
2749
			if ($interface <> "" && get_root_interface($vip['interface']) <> $interface) {
2750
				continue;
2751
			}
2752
			switch ($vip['mode']) {
2753
				case "proxyarp":
2754
					/* nothing it is handled on interface_proxyarp_configure() */
2755
					$anyproxyarp = true;
2756
					break;
2757
				case "ipalias":
2758
					interface_ipalias_configure($vip);
2759
					break;
2760
				case "carp":
2761
					if ($carp_setuped == false) {
2762
						$carp_setuped = true;
2763
					}
2764
					interface_carp_configure($vip);
2765
					break;
2766
			}
2767
		}
2768
		if ($carp_setuped == true) {
2769
			interfaces_sync_setup();
2770
		}
2771
		if ($anyproxyarp == true) {
2772
			interface_proxyarp_configure();
2773
		}
2774
	}
2775
}
2776

    
2777
function interface_ipalias_configure(&$vip) {
2778
	global $config;
2779

    
2780
	if ($vip['mode'] != 'ipalias') {
2781
		return;
2782
	}
2783

    
2784
	$realif = get_real_interface("_vip{$vip['uniqid']}");
2785
	if ($realif != "lo0") {
2786
		$if = convert_real_interface_to_friendly_interface_name($realif);
2787
		if (!isset($config['interfaces'][$if]) ||
2788
		    !isset($config['interfaces'][$if]['enable'])) {
2789
			return;
2790
		}
2791
	}
2792

    
2793
	$af = 'inet';
2794
	if (is_ipaddrv6($vip['subnet'])) {
2795
		$af = 'inet6';
2796
	}
2797
	$iface = $vip['interface'];
2798
	$vhid = '';
2799
	if (substr($vip['interface'], 0, 4) == "_vip") {
2800
		$carpvip = get_configured_vip($vip['interface']);
2801
		$iface = $carpvip['interface'];
2802
		$vhid = "vhid {$carpvip['vhid']}";
2803
	}
2804
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$vhid}");
2805
	unset($iface, $af, $realif, $carpvip, $vhid);
2806
}
2807

    
2808
function interface_carp_configure(&$vip) {
2809
	global $config, $g;
2810
	if (isset($config['system']['developerspew'])) {
2811
		$mt = microtime();
2812
		echo "interface_carp_configure() being called $mt\n";
2813
	}
2814

    
2815
	if ($vip['mode'] != "carp") {
2816
		return;
2817
	}
2818

    
2819
	$realif = get_real_interface($vip['interface']);
2820
	if (!does_interface_exist($realif)) {
2821
		file_notice("CARP", sprintf(gettext("Interface specified for the virtual IP address %s does not exist. Skipping this VIP."), $vip['subnet']), "Firewall: Virtual IP", "");
2822
		return;
2823
	}
2824
	if ($realif != "lo0") {
2825
		if (!isset($config['interfaces'][$vip['interface']]) ||
2826
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
2827
			return;
2828
		}
2829
	}
2830

    
2831
	$vip_password = $vip['password'];
2832
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "", $vip_password)));
2833
	if ($vip['password'] != "") {
2834
		$password = " pass {$vip_password}";
2835
	}
2836

    
2837
	$advbase = "";
2838
	if (!empty($vip['advbase'])) {
2839
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
2840
	}
2841

    
2842
	$carp_maintenancemode = isset($config["virtualip_carp_maintenancemode"]);
2843
	if ($carp_maintenancemode) {
2844
		$advskew = "advskew 254";
2845
	} else {
2846
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
2847
	}
2848

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

    
2851
	if (is_ipaddrv4($vip['subnet'])) {
2852
		mwexec("/sbin/ifconfig {$realif} " . escapeshellarg($vip['subnet']) . "/" . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2853
	} else if (is_ipaddrv6($vip['subnet'])) {
2854
		mwexec("/sbin/ifconfig {$realif} inet6 " . escapeshellarg($vip['subnet']) . " prefixlen " . escapeshellarg($vip['subnet_bits']) . " alias vhid " . escapeshellarg($vip['vhid']));
2855
	}
2856

    
2857
	return $realif;
2858
}
2859

    
2860
function interface_wireless_clone($realif, $wlcfg) {
2861
	global $config, $g;
2862
	/*   Check to see if interface has been cloned as of yet.
2863
	 *   If it has not been cloned then go ahead and clone it.
2864
	 */
2865
	$needs_clone = false;
2866
	if (is_array($wlcfg['wireless'])) {
2867
		$wlcfg_mode = $wlcfg['wireless']['mode'];
2868
	} else {
2869
		$wlcfg_mode = $wlcfg['mode'];
2870
	}
2871
	switch ($wlcfg_mode) {
2872
		case "hostap":
2873
			$mode = "wlanmode hostap";
2874
			break;
2875
		case "adhoc":
2876
			$mode = "wlanmode adhoc";
2877
			break;
2878
		default:
2879
			$mode = "";
2880
			break;
2881
	}
2882
	$baseif = interface_get_wireless_base($wlcfg['if']);
2883
	if (does_interface_exist($realif)) {
2884
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
2885
		$ifconfig_str = implode($output);
2886
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
2887
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
2888
			$needs_clone = true;
2889
		}
2890
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
2891
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
2892
			$needs_clone = true;
2893
		}
2894
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
2895
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
2896
			$needs_clone = true;
2897
		}
2898
	} else {
2899
		$needs_clone = true;
2900
	}
2901

    
2902
	if ($needs_clone == true) {
2903
		/* remove previous instance if it exists */
2904
		if (does_interface_exist($realif)) {
2905
			pfSense_interface_destroy($realif);
2906
		}
2907

    
2908
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
2909
		// Create the new wlan interface. FreeBSD returns the new interface name.
2910
		// example:  wlan2
2911
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
2912
		if ($ret <> 0) {
2913
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
2914
			return false;
2915
		}
2916
		$newif = trim($out[0]);
2917
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
2918
		pfSense_interface_rename($newif, $realif);
2919
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
2920
	}
2921
	return true;
2922
}
2923

    
2924
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
2925
	global $config, $g;
2926

    
2927
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
2928
				 'diversity', 'txantenna', 'rxantenna', 'distance',
2929
				 'regdomain', 'regcountry', 'reglocation');
2930

    
2931
	if (!is_interface_wireless($ifcfg['if'])) {
2932
		return;
2933
	}
2934

    
2935
	$baseif = interface_get_wireless_base($ifcfg['if']);
2936

    
2937
	// Sync shared settings for assigned clones
2938
	$iflist = get_configured_interface_list(true);
2939
	foreach ($iflist as $if) {
2940
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
2941
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
2942
				foreach ($shared_settings as $setting) {
2943
					if ($sync_changes) {
2944
						if (isset($ifcfg['wireless'][$setting])) {
2945
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
2946
						} else if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2947
							unset($config['interfaces'][$if]['wireless'][$setting]);
2948
						}
2949
					} else {
2950
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
2951
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
2952
						} else if (isset($ifcfg['wireless'][$setting])) {
2953
							unset($ifcfg['wireless'][$setting]);
2954
						}
2955
					}
2956
				}
2957
				if (!$sync_changes) {
2958
					break;
2959
				}
2960
			}
2961
		}
2962
	}
2963

    
2964
	// Read or write settings at shared area
2965
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
2966
		foreach ($shared_settings as $setting) {
2967
			if ($sync_changes) {
2968
				if (isset($ifcfg['wireless'][$setting])) {
2969
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
2970
				} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2971
					unset($config['wireless']['interfaces'][$baseif][$setting]);
2972
				}
2973
			} else if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2974
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
2975
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
2976
				} else if (isset($ifcfg['wireless'][$setting])) {
2977
					unset($ifcfg['wireless'][$setting]);
2978
				}
2979
			}
2980
		}
2981
	}
2982

    
2983
	// Sync the mode on the clone creation page with the configured mode on the interface
2984
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
2985
		foreach ($config['wireless']['clone'] as &$clone) {
2986
			if ($clone['cloneif'] == $ifcfg['if']) {
2987
				if ($sync_changes) {
2988
					$clone['mode'] = $ifcfg['wireless']['mode'];
2989
				} else {
2990
					$ifcfg['wireless']['mode'] = $clone['mode'];
2991
				}
2992
				break;
2993
			}
2994
		}
2995
		unset($clone);
2996
	}
2997
}
2998

    
2999
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3000
	global $config, $g;
3001

    
3002
	/*    open up a shell script that will be used to output the commands.
3003
	 *    since wireless is changing a lot, these series of commands are fragile
3004
	 *    and will sometimes need to be verified by a operator by executing the command
3005
	 *    and returning the output of the command to the developers for inspection.  please
3006
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3007
	 */
3008

    
3009
	// Remove script file
3010
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3011

    
3012
	// Clone wireless nic if needed.
3013
	interface_wireless_clone($if, $wl);
3014

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

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

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

    
3024
	/* set values for /path/program */
3025
	if (file_exists("/usr/local/sbin/hostapd")) {
3026
		$hostapd = "/usr/local/sbin/hostapd";
3027
	} else {
3028
		$hostapd = "/usr/sbin/hostapd";
3029
	}
3030
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3031
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3032
	} else {
3033
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3034
	}
3035
	$ifconfig = "/sbin/ifconfig";
3036
	$sysctl = "/sbin/sysctl";
3037
	$sysctl_args = "-q";
3038
	$killall = "/usr/bin/killall";
3039

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

    
3042
	$wlcmd = array();
3043
	$wl_sysctl = array();
3044
	/* Set a/b/g standard */
3045
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3046
	/* skip mode entirely for "auto" */
3047
	if ($wlcfg['standard'] != "auto") {
3048
		$wlcmd[] = "mode " . escapeshellarg($standard);
3049
	}
3050

    
3051
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3052
	 * to prevent massive packet loss under certain conditions. */
3053
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3054
		$wlcmd[] = "-ampdu";
3055
	}
3056

    
3057
	/* Set ssid */
3058
	if ($wlcfg['ssid']) {
3059
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3060
	}
3061

    
3062
	/* Set 802.11g protection mode */
3063
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3064

    
3065
	/* set wireless channel value */
3066
	if (isset($wlcfg['channel'])) {
3067
		if ($wlcfg['channel'] == "0") {
3068
			$wlcmd[] = "channel any";
3069
		} else {
3070
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']);
3071
		}
3072
	}
3073

    
3074
	/* Set antenna diversity value */
3075
	if (isset($wlcfg['diversity'])) {
3076
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3077
	}
3078

    
3079
	/* Set txantenna value */
3080
	if (isset($wlcfg['txantenna'])) {
3081
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3082
	}
3083

    
3084
	/* Set rxantenna value */
3085
	if (isset($wlcfg['rxantenna'])) {
3086
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3087
	}
3088

    
3089
	/* set Distance value */
3090
	if ($wlcfg['distance']) {
3091
		$distance = escapeshellarg($wlcfg['distance']);
3092
	}
3093

    
3094
	/* Set wireless hostap mode */
3095
	if ($wlcfg['mode'] == "hostap") {
3096
		$wlcmd[] = "mediaopt hostap";
3097
	} else {
3098
		$wlcmd[] = "-mediaopt hostap";
3099
	}
3100

    
3101
	/* Set wireless adhoc mode */
3102
	if ($wlcfg['mode'] == "adhoc") {
3103
		$wlcmd[] = "mediaopt adhoc";
3104
	} else {
3105
		$wlcmd[] = "-mediaopt adhoc";
3106
	}
3107

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

    
3110
	/* handle hide ssid option */
3111
	if (isset($wlcfg['hidessid']['enable'])) {
3112
		$wlcmd[] = "hidessid";
3113
	} else {
3114
		$wlcmd[] = "-hidessid";
3115
	}
3116

    
3117
	/* handle pureg (802.11g) only option */
3118
	if (isset($wlcfg['pureg']['enable'])) {
3119
		$wlcmd[] = "mode 11g pureg";
3120
	} else {
3121
		$wlcmd[] = "-pureg";
3122
	}
3123

    
3124
	/* handle puren (802.11n) only option */
3125
	if (isset($wlcfg['puren']['enable'])) {
3126
		$wlcmd[] = "puren";
3127
	} else {
3128
		$wlcmd[] = "-puren";
3129
	}
3130

    
3131
	/* enable apbridge option */
3132
	if (isset($wlcfg['apbridge']['enable'])) {
3133
		$wlcmd[] = "apbridge";
3134
	} else {
3135
		$wlcmd[] = "-apbridge";
3136
	}
3137

    
3138
	/* handle turbo option */
3139
	if (isset($wlcfg['turbo']['enable'])) {
3140
		$wlcmd[] = "mediaopt turbo";
3141
	} else {
3142
		$wlcmd[] = "-mediaopt turbo";
3143
	}
3144

    
3145
	/* handle txpower setting */
3146
	// or don't. this has issues at the moment.
3147
	/*
3148
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3149
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3150
	}*/
3151

    
3152
	/* handle wme option */
3153
	if (isset($wlcfg['wme']['enable'])) {
3154
		$wlcmd[] = "wme";
3155
	} else {
3156
		$wlcmd[] = "-wme";
3157
	}
3158

    
3159
	/* Enable wpa if it's configured. No WEP support anymore. */
3160
	if (isset($wlcfg['wpa']['enable'])) {
3161
		$wlcmd[] = "authmode wpa wepmode off ";
3162
	} else {
3163
		$wlcmd[] = "authmode open wepmode off ";
3164
	}
3165

    
3166
	kill_hostapd($if);
3167
	mwexec(kill_wpasupplicant("{$if}"));
3168

    
3169
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3170

    
3171
	switch ($wlcfg['mode']) {
3172
		case 'bss':
3173
			if (isset($wlcfg['wpa']['enable'])) {
3174
				$wpa .= <<<EOD
3175
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3176
ctrl_interface_group=0
3177
ap_scan=1
3178
#fast_reauth=1
3179
network={
3180
ssid="{$wlcfg['ssid']}"
3181
scan_ssid=1
3182
priority=5
3183
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3184
psk="{$wlcfg['wpa']['passphrase']}"
3185
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3186
group={$wlcfg['wpa']['wpa_pairwise']}
3187
}
3188
EOD;
3189

    
3190
				@file_put_contents("{$g['varetc_path']}/wpa_supplicant_{$if}.conf", $wpa);
3191
				unset($wpa);
3192
			}
3193
			break;
3194
		case 'hostap':
3195
			if (!empty($wlcfg['wpa']['passphrase'])) {
3196
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3197
			} else {
3198
				$wpa_passphrase = "";
3199
			}
3200
			if (isset($wlcfg['wpa']['enable'])) {
3201
				$wpa .= <<<EOD
3202
interface={$if}
3203
driver=bsd
3204
logger_syslog=-1
3205
logger_syslog_level=0
3206
logger_stdout=-1
3207
logger_stdout_level=0
3208
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3209
ctrl_interface={$g['varrun_path']}/hostapd
3210
ctrl_interface_group=wheel
3211
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3212
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3213
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3214
ssid={$wlcfg['ssid']}
3215
debug={$wlcfg['wpa']['debug_mode']}
3216
wpa={$wlcfg['wpa']['wpa_mode']}
3217
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3218
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3219
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3220
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3221
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3222
{$wpa_passphrase}
3223

    
3224
EOD;
3225

    
3226
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3227
					$wpa .= <<<EOD
3228
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3229
rsn_preauth=1
3230
rsn_preauth_interfaces={$if}
3231

    
3232
EOD;
3233
				}
3234
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3235
					$wpa .= "ieee8021x=1\n";
3236

    
3237
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3238
						$auth_server_port = "1812";
3239
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3240
							$auth_server_port = intval($wlcfg['auth_server_port']);
3241
						}
3242
						$wpa .= <<<EOD
3243

    
3244
auth_server_addr={$wlcfg['auth_server_addr']}
3245
auth_server_port={$auth_server_port}
3246
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3247

    
3248
EOD;
3249
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3250
							$auth_server_port2 = "1812";
3251
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3252
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3253
							}
3254

    
3255
							$wpa .= <<<EOD
3256
auth_server_addr={$wlcfg['auth_server_addr2']}
3257
auth_server_port={$auth_server_port2}
3258
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3259

    
3260
EOD;
3261
						}
3262
					}
3263
				}
3264

    
3265
				@file_put_contents("{$g['varetc_path']}/hostapd_{$if}.conf", $wpa);
3266
				unset($wpa);
3267
			}
3268
			break;
3269
	}
3270

    
3271
	/*
3272
	 *    all variables are set, lets start up everything
3273
	 */
3274

    
3275
	$baseif = interface_get_wireless_base($if);
3276
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3277
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3278

    
3279
	/* set sysctls for the wireless interface */
3280
	if (!empty($wl_sysctl)) {
3281
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3282
		foreach ($wl_sysctl as $wl_sysctl_line) {
3283
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3284
		}
3285
	}
3286

    
3287
	/* set ack timers according to users preference (if he/she has any) */
3288
	if ($distance) {
3289
		fwrite($fd_set, "# Enable ATH distance settings\n");
3290
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3291
	}
3292

    
3293
	if (isset($wlcfg['wpa']['enable'])) {
3294
		if ($wlcfg['mode'] == "bss") {
3295
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3296
		}
3297
		if ($wlcfg['mode'] == "hostap") {
3298
			/* add line to script to restore old mac to make hostapd happy */
3299
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3300
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3301
				$if_curmac = get_interface_mac($if);
3302
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3303
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3304
						" link " . escapeshellarg($if_oldmac) . "\n");
3305
				}
3306
			}
3307

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

    
3310
			/* add line to script to restore spoofed mac after running hostapd */
3311
			if ($wl['spoofmac']) {
3312
				$if_curmac = get_interface_mac($if);
3313
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3314
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3315
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3316
				}
3317
			}
3318
		}
3319
	}
3320

    
3321
	fclose($fd_set);
3322

    
3323
	/* Making sure regulatory settings have actually changed
3324
	 * before applying, because changing them requires bringing
3325
	 * down all wireless networks on the interface. */
3326
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3327
	$ifconfig_str = implode($output);
3328
	unset($output);
3329
	$reg_changing = false;
3330

    
3331
	/* special case for the debug country code */
3332
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3333
		$reg_changing = true;
3334
	} else if ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3335
		$reg_changing = true;
3336
	} else if ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3337
		$reg_changing = true;
3338
	} else if ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3339
		$reg_changing = true;
3340
	} else if ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3341
		$reg_changing = true;
3342
	}
3343

    
3344
	if ($reg_changing) {
3345
		/* set regulatory domain */
3346
		if ($wlcfg['regdomain']) {
3347
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3348
		}
3349

    
3350
		/* set country */
3351
		if ($wlcfg['regcountry']) {
3352
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3353
		}
3354

    
3355
		/* set location */
3356
		if ($wlcfg['reglocation']) {
3357
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3358
		}
3359

    
3360
		$wlregcmd_args = implode(" ", $wlregcmd);
3361

    
3362
		/* build a complete list of the wireless clones for this interface */
3363
		$clone_list = array();
3364
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3365
			$clone_list[] = interface_get_wireless_clone($baseif);
3366
		}
3367
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3368
			foreach ($config['wireless']['clone'] as $clone) {
3369
				if ($clone['if'] == $baseif) {
3370
					$clone_list[] = $clone['cloneif'];
3371
				}
3372
			}
3373
		}
3374

    
3375
		/* find which clones are up and bring them down */
3376
		$clones_up = array();
3377
		foreach ($clone_list as $clone_if) {
3378
			$clone_status = pfSense_get_interface_addresses($clone_if);
3379
			if ($clone_status['status'] == 'up') {
3380
				$clones_up[] = $clone_if;
3381
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3382
			}
3383
		}
3384

    
3385
		/* apply the regulatory settings */
3386
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3387
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3388

    
3389
		/* bring the clones back up that were previously up */
3390
		foreach ($clones_up as $clone_if) {
3391
			interfaces_bring_up($clone_if);
3392

    
3393
			/*
3394
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3395
			 * is in infrastructure mode, and WPA is enabled.
3396
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3397
			 */
3398
			if ($clone_if != $if) {
3399
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3400
				if ((!empty($friendly_if)) &&
3401
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3402
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3403
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3404
				}
3405
			}
3406
		}
3407
	}
3408

    
3409
	/* The mode must be specified in a separate command before ifconfig
3410
	 * will allow the mode and channel at the same time in the next.
3411
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3412
	 */
3413
	if ($wlcfg['mode'] == "hostap") {
3414
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3415
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3416
	}
3417

    
3418
	/* configure wireless */
3419
	$wlcmd_args = implode(" ", $wlcmd);
3420
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args, false);
3421
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3422
	/* Bring the interface up only after setting up all the other parameters. */
3423
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up", false);
3424
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3425
	fclose($wlan_setup_log);
3426

    
3427
	unset($wlcmd_args, $wlcmd);
3428

    
3429

    
3430
	sleep(1);
3431
	/* execute hostapd and wpa_supplicant if required in shell */
3432
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3433

    
3434
	return 0;
3435

    
3436
}
3437

    
3438
function kill_hostapd($interface) {
3439
	global $g;
3440

    
3441
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3442
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3443
	}
3444
}
3445

    
3446
function kill_wpasupplicant($interface) {
3447
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3448
}
3449

    
3450
function find_dhclient_process($interface) {
3451
	if ($interface) {
3452
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3453
	} else {
3454
		$pid = 0;
3455
	}
3456

    
3457
	return intval($pid);
3458
}
3459

    
3460
function kill_dhclient_process($interface) {
3461
	if (empty($interface) || !does_interface_exist($interface)) {
3462
		return;
3463
	}
3464

    
3465
	$i = 0;
3466
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3467
		/* 3rd time make it die for sure */
3468
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3469
		posix_kill($pid, $sig);
3470
		sleep(1);
3471
		$i++;
3472
	}
3473
	unset($i);
3474
}
3475

    
3476
function find_dhcp6c_process($interface) {
3477
	global $g;
3478

    
3479
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3480
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3481
	} else {
3482
		return(false);
3483
	}
3484

    
3485
	return intval($pid);
3486
}
3487

    
3488
function kill_dhcp6client_process($interface, $force, $release = false) {
3489
	global $g;
3490

    
3491
	$i = 0;
3492

    
3493
	/*
3494
	Beware of the following: Reason, the interface may be down, but
3495
	dhcp6c may still be running, it just complains it cannot send
3496
	and carries on. Commented out as will stop the call to kill.
3497

    
3498
	if (empty($interface) || !does_interface_exist($interface)) {
3499
		return;
3500
	}
3501
	*/
3502

    
3503
	/*********** Notes on signals for dhcp6c and this function *************
3504

    
3505
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3506
	a release and waiting for the response that never comes.
3507
	So we need to tell it that the interface is down and to just die quickly
3508
	otherwise a new client may launch and we have duplicate proceses.
3509
	In this case use SIGUSR1.
3510

    
3511
	If we want to exit normally obeying the no release flag then use SIGTERM.
3512
	If we want to exit with a release overiding the no release flag then
3513
	use SIGUSR2.
3514

    
3515
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3516
	exit quickly without sending release signals.
3517

    
3518
	If $Force is set to false and $release is also set to false dhcp6c will
3519
	follow the no-release flag.
3520

    
3521
	If $Force is set to false and $release is true then dhcp6c will send a
3522
	release regardless of the no-release flag.
3523
	***********************************************************************/
3524

    
3525
	if ($force == true) {
3526
		$psig=SIGUSR1;
3527
	} else if ($release == false) {
3528
		$psig=SIGTERM;
3529
	} else {
3530
		$psig=SIGUSR2;
3531
	}
3532

    
3533
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3534
		/* 3rd time make it die for sure */
3535
		$sig = ($i == 2 ? SIGKILL : $psig);
3536
		posix_kill($pid, $sig);
3537
		sleep(1);
3538
		$i++;
3539
	}
3540
	/* Clear the RTSOLD script created lock & tidy up */
3541
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3542
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3543
}
3544
function reset_dhcp6client_process($interface) {
3545

    
3546
	$pid = find_dhcp6c_process($interface);
3547

    
3548
	if($pid != 0) {
3549
		posix_kill($pid, SIGHUP);
3550
	}
3551
}
3552

    
3553
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
3554
	global $g;
3555

    
3556
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
3557
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
3558

    
3559
	/*
3560
	 * Only run this if the lock does not exist. In theory the lock being
3561
	 * there in this mode means the user has selected dhcp6withoutRA while
3562
	 * a session is active in the other mode.
3563
	 *
3564
	 * It should not happen as the process should have been killed and the
3565
	 * lock deleted.
3566
	 */
3567

    
3568
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
3569
		kill_dhcp6client_process($interface, true);
3570
		/* Lock it to avoid multiple runs */
3571
		touch("/tmp/dhcp6c_{$interface}_lock");
3572
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3573
		    "{$noreleaseOption} " .
3574
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
3575
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
3576
		    $interface);
3577
		log_error(sprintf(gettext(
3578
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
3579
		    $interface));
3580
	}
3581
}
3582

    
3583
function interface_virtual_create($interface) {
3584
	global $config;
3585

    
3586
	if (interface_is_vlan($interface) != NULL) {
3587
		interfaces_vlan_configure($interface);
3588
	} else if (substr($interface, 0, 3) == "gre") {
3589
		interfaces_gre_configure(0, $interface);
3590
	} else if (substr($interface, 0, 3) == "gif") {
3591
		interfaces_gif_configure(0, $interface);
3592
	} else if (substr($interface, 0, 5) == "ovpns") {
3593
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3594
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3595
				if ($interface == "ovpns{$server['vpnid']}") {
3596
					if (!function_exists('openvpn_resync')) {
3597
						require_once('openvpn.inc');
3598
					}
3599
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3600
					openvpn_resync('server', $server);
3601
				}
3602
			}
3603
			unset($server);
3604
		}
3605
	} else if (substr($interface, 0, 5) == "ovpnc") {
3606
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3607
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3608
				if ($interface == "ovpnc{$client['vpnid']}") {
3609
					if (!function_exists('openvpn_resync')) {
3610
						require_once('openvpn.inc');
3611
					}
3612
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3613
					openvpn_resync('client', $client);
3614
				}
3615
			}
3616
			unset($client);
3617
		}
3618
	} else if (substr($interface, 0, 5) == "ipsec") {
3619
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3620
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3621
				if ($ph1ent['disabled']) {
3622
					continue;
3623
				}
3624
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
3625
					interface_ipsec_vti_configure($ph1ent);
3626
				}
3627
			}
3628
		}
3629
	} else if (substr($interface, 0, 4) == "lagg") {
3630
		interfaces_lagg_configure($interface);
3631
	} else if (substr($interface, 0, 6) == "bridge") {
3632
		interfaces_bridge_configure(0, $interface);
3633
	}
3634
}
3635

    
3636
function interface_vlan_mtu_configured($iface) {
3637
	global $config;
3638

    
3639
	$mtu = 0;
3640
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
3641
		foreach ($config['vlans']['vlan'] as $vlan) {
3642

    
3643
			if ($vlan['vlanif'] != $iface)
3644
				continue;
3645

    
3646
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3647
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
3648
				/* VLAN MTU */
3649
				$mtu = $config['interfaces'][$assignedport]['mtu'];
3650
			} elseif (!empty($config['interfaces'][$vlan['if']]['mtu'])) {
3651
				/* Parent MTU */
3652
				$mtu = $config['interfaces'][$vlan['if']]['mtu'];
3653
			}
3654
		}
3655
	}
3656

    
3657
	return $mtu;
3658
}
3659

    
3660
function interface_mtu_wanted_for_pppoe($realif) {
3661
	global $config;
3662

    
3663
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
3664
		return 0;
3665

    
3666
	$mtu = 0;
3667
	foreach ($config['ppps']['ppp'] as $ppp) {
3668
		if ($ppp['type'] != "pppoe") {
3669
			continue;
3670
		}
3671

    
3672
		$mtus = array();
3673
		if (!empty($ppp['mtu'])) {
3674
			$mtus = explode(',', $ppp['mtu']);
3675
		}
3676
		$ports = explode(',', $ppp['ports']);
3677

    
3678
		foreach ($ports as $pid => $port) {
3679
			$parentifa = get_parent_interface($port);
3680
			$parentif = $parentifa[0];
3681
			if ($parentif != $realif)
3682
				continue;
3683

    
3684
			// there is an MTU configured on the port in question
3685
			if (!empty($mtus[$pid])) {
3686
				$mtu = intval($mtus[$pid]) + 8;
3687
			// or use the MTU configured on the interface ...
3688
			} elseif (is_array($config['interfaces'])) {
3689
				foreach ($config['interfaces'] as $interface) {
3690
					if ($interface['if'] == $ppp['if'] &&
3691
					    !empty($interface['mtu'])) {
3692
						$mtu = intval($interface['mtu']) + 8;
3693
						break;
3694
					}
3695
				}
3696
			}
3697
		}
3698
	}
3699

    
3700
	return $mtu;
3701
}
3702

    
3703
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3704
	global $config, $g;
3705
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3706
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3707

    
3708
	$wancfg = $config['interfaces'][$interface];
3709

    
3710
	if (!isset($wancfg['enable'])) {
3711
		return;
3712
	}
3713

    
3714
	$realif = get_real_interface($interface);
3715
	$realhwif_array = get_parent_interface($interface);
3716
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3717
	$realhwif = $realhwif_array[0];
3718

    
3719
	if (!platform_booting() && !(substr($realif, 0, 4) == "ovpn") && !(substr($realif, 0, 5) == "ipsec")) {
3720
		/* remove all IPv4 and IPv6 addresses */
3721
		$tmpifaces = pfSense_getall_interface_addresses($realif);
3722
		if (is_array($tmpifaces)) {
3723
			foreach ($tmpifaces as $tmpiface) {
3724
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
3725
					if (!is_linklocal($tmpiface)) {
3726
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
3727
					}
3728
				} else {
3729
					if (is_subnetv4($tmpiface)) {
3730
						$tmpip = explode('/', $tmpiface);
3731
						$tmpip = $tmpip[0];
3732
					} else {
3733
						$tmpip = $tmpiface;
3734
					}
3735
					pfSense_interface_deladdress($realif, $tmpip);
3736
				}
3737
			}
3738
		}
3739

    
3740
		/* only bring down the interface when both v4 and v6 are set to NONE */
3741
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
3742
			interface_bring_down($interface);
3743
		}
3744
	}
3745

    
3746
	$interface_to_check = $realif;
3747
	if (interface_isppp_type($interface)) {
3748
		$interface_to_check = $realhwif;
3749
	}
3750

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

    
3756
	/* Disable Accepting router advertisements unless specifically requested */
3757
	if ($g['debug']) {
3758
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
3759
	}
3760
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
3761
	{
3762
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
3763
	}
3764
	/* wireless configuration? */
3765
	if (is_array($wancfg['wireless']) && !$linkupevent) {
3766
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
3767
	}
3768

    
3769
	$current_mac = get_interface_mac($realhwif);
3770
	$vendor_mac = get_interface_vendor_mac($realhwif);
3771
	/*
3772
	 * Do not change the MAC address if the interface does not store the original
3773
	 * vendor MAC address.
3774
	 */
3775
	if ($vendor_mac != NULL) {
3776
		/* Get the vendor MAC.  Use source dependent upon whether or not booting. */
3777
		if (platform_booting()) {
3778
			$vendor_mac = $current_mac;
3779
		}
3780
		$mac_addr = $wancfg['spoofmac'] ?: $vendor_mac;
3781
		/*
3782
		 * Don't try to reapply the MAC if it's already applied.
3783
		 * When ifconfig link is used, it cycles the interface down/up, which triggers
3784
		 * the interface config again, which attempts to apply the MAC again,
3785
		 * which cycles the link again...
3786
		 */
3787
		if (!empty($mac_addr) && ($mac_addr != $current_mac)) {
3788
			mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3789
				" link " . escapeshellarg($mac_addr));
3790
		}
3791
	} elseif ($current_mac == "ff:ff:ff:ff:ff:ff") {
3792
		/*   this is not a valid mac address.  generate a
3793
		 *   temporary mac address so the machine can get online.
3794
		 */
3795
		echo gettext("Generating new MAC address.");
3796
		$random_mac = generate_random_mac_address();
3797
		mwexec("/sbin/ifconfig " . escapeshellarg($realhwif) .
3798
			" link " . escapeshellarg($random_mac));
3799
		$wancfg['spoofmac'] = $random_mac;
3800
		write_config(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));
3801
		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");
3802
	}
3803

    
3804
	/* media */
3805
	if ($wancfg['media'] || $wancfg['mediaopt']) {
3806
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
3807
		if ($wancfg['media']) {
3808
			$cmd .= " media " . escapeshellarg($wancfg['media']);
3809
		}
3810
		if ($wancfg['mediaopt']) {
3811
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
3812
		}
3813
		mwexec($cmd);
3814
	}
3815

    
3816
	/* Apply hw offloading policies as configured */
3817
	enable_hardware_offloading($interface);
3818

    
3819
	/* invalidate interface/ip/sn cache */
3820
	get_interface_arr(true);
3821
	unset($interface_ip_arr_cache[$realif]);
3822
	unset($interface_sn_arr_cache[$realif]);
3823
	unset($interface_ipv6_arr_cache[$realif]);
3824
	unset($interface_snv6_arr_cache[$realif]);
3825

    
3826
	$tunnelif = substr($realif, 0, 3);
3827

    
3828
	$mtuif = $realif;
3829
	$mtuhwif = $realhwif;
3830

    
3831
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
3832
	if (interface_isppp_type($interface)) {
3833
		$mtuif = $realhwif;
3834
		$mtuhwif_array = get_parent_interface($mtuif);
3835
		$mtuhwif = $mtuhwif_array[0];
3836
	}
3837

    
3838
	$wantedmtu = 0;
3839
	if (is_array($config['interfaces'])) {
3840
		foreach ($config['interfaces'] as $tmpinterface) {
3841
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
3842
				$wantedmtu = $tmpinterface['mtu'];
3843
				break;
3844
			}
3845
		}
3846
	}
3847

    
3848
	/* MTU is not specified for interface, try the pppoe settings. */
3849
	if ($wantedmtu == 0) {
3850
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
3851
	}
3852
	if ($wantedmtu == 0 && interface_is_vlan($mtuif) != NULL && interface_isppp_type($interface)) {
3853
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
3854
	}
3855

    
3856
	/* Set the MTU to 1500 if no explicit MTU configured. */
3857
	if ($wantedmtu == 0) {
3858
		$wantedmtu = 1500; /* Default */
3859
	}
3860

    
3861
	if (interface_is_vlan($mtuif) != NULL) {
3862
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
3863
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
3864
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
3865
			if ($wancfg['mtu'] > $parentmtu) {
3866
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
3867
			}
3868
		}
3869

    
3870
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
3871

    
3872
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
3873
			$configuredmtu = $parentmtu;
3874
		if ($configuredmtu != 0)
3875
			$mtu = $configuredmtu;
3876
		else
3877
			$mtu = $wantedmtu;
3878

    
3879
		/* Set the parent MTU. */
3880
		if (get_interface_mtu($mtuhwif) < $mtu)
3881
			set_interface_mtu($mtuhwif, $mtu);
3882
		/* Set the VLAN MTU. */
3883
		if (get_interface_mtu($mtuif) != $mtu)
3884
			set_interface_mtu($mtuif, $mtu);
3885
	} else if (substr($mtuif, 0, 4) == 'lagg') {
3886
		/* LAGG interface must be destroyed and re-created to change MTU */
3887
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3888
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
3889
				foreach ($config['laggs']['lagg'] as $lagg) {
3890
					if ($lagg['laggif'] == $mtuif) {
3891
						interface_lagg_configure($lagg);
3892
						break;
3893
					}
3894
				}
3895
			}
3896
		}
3897
	} else {
3898
		if ($wantedmtu != get_interface_mtu($mtuif)) {
3899
			pfSense_interface_mtu($mtuif, $wantedmtu);
3900
		}
3901
	}
3902
	/* XXX: What about gre/gif/.. ? */
3903

    
3904
	if (does_interface_exist($wancfg['if'])) {
3905
		interfaces_bring_up($wancfg['if']);
3906
	}
3907

    
3908
	switch ($wancfg['ipaddr']) {
3909
		case 'dhcp':
3910
			interface_dhcp_configure($interface);
3911
			break;
3912
		case 'pppoe':
3913
		case 'l2tp':
3914
		case 'pptp':
3915
		case 'ppp':
3916
			interface_ppps_configure($interface);
3917
			break;
3918
		default:
3919
			/* XXX: Kludge for now related to #3280 */
3920
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
3921
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
3922
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
3923
				}
3924
			}
3925
			break;
3926
	}
3927

    
3928
	switch ($wancfg['ipaddrv6']) {
3929
		case 'slaac':
3930
		case 'dhcp6':
3931
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
3932
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
3933
			// handles all non-PPP connections with 'dhcp6usev4iface' set
3934
			/* Remove the check file. Should not be there but just in case */
3935
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
3936
			log_error(gettext("calling interface_dhcpv6_configure."));
3937
			if (!(isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')) {
3938
				interface_dhcpv6_configure($interface, $wancfg);
3939
			}
3940
			break;
3941
		case '6rd':
3942
			interface_6rd_configure($interface, $wancfg);
3943
			break;
3944
		case '6to4':
3945
			interface_6to4_configure($interface, $wancfg);
3946
			break;
3947
		case 'track6':
3948
			interface_track6_configure($interface, $wancfg, $linkupevent);
3949
			break;
3950
		default:
3951
			/* XXX: Kludge for now related to #3280 */
3952
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
3953
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
3954
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
3955
					// FIXME: Add IPv6 Support to the pfSense module
3956
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
3957
				}
3958
			}
3959
			break;
3960
	}
3961

    
3962
	interface_netgraph_needed($interface);
3963

    
3964
	if (!platform_booting()) {
3965
		link_interface_to_vips($interface, "update");
3966

    
3967
		if ($tunnelif != 'gre') {
3968
			unset($gre);
3969
			$gre = link_interface_to_gre($interface);
3970
			if (!empty($gre)) {
3971
				array_walk($gre, 'interface_gre_configure');
3972
			}
3973
		}
3974

    
3975
		if ($tunnelif != 'gif') {
3976
			unset($gif);
3977
			$gif = link_interface_to_gif ($interface);
3978
			if (!empty($gif)) {
3979
				array_walk($gif, 'interface_gif_configure');
3980
			}
3981
		}
3982

    
3983
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
3984
			unset($bridgetmp);
3985
			$bridgetmp = link_interface_to_bridge($interface);
3986
			if (!empty($bridgetmp)) {
3987
				interface_bridge_add_member($bridgetmp, $realif);
3988
			}
3989
		}
3990

    
3991
		$grouptmp = link_interface_to_group($interface);
3992
		if (!empty($grouptmp)) {
3993
			array_walk($grouptmp, 'interface_group_add_member');
3994
		}
3995

    
3996
		if ($interface == "lan") {
3997
			/* make new hosts file */
3998
			system_hosts_generate();
3999
		}
4000

    
4001
		if ($reloadall == true) {
4002

    
4003
			/* reconfigure static routes (kernel may have deleted them) */
4004
			system_routing_configure($interface);
4005

    
4006
			/* reload ipsec tunnels */
4007
			send_event("service reload ipsecdns");
4008

    
4009
			if (isset($config['dnsmasq']['enable'])) {
4010
				services_dnsmasq_configure();
4011
			}
4012

    
4013
			if (isset($config['unbound']['enable'])) {
4014
				services_unbound_configure();
4015
			}
4016

    
4017
			/* update dyndns */
4018
			send_event("service reload dyndns {$interface}");
4019

    
4020
			/* reload captive portal */
4021
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4022
				require_once('captiveportal.inc');
4023
			}
4024
			captiveportal_init_rules_byinterface($interface);
4025
		}
4026
	}
4027

    
4028
	interfaces_staticarp_configure($interface);
4029
	return 0;
4030
}
4031

    
4032
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4033
	global $config, $g;
4034

    
4035
	if (!is_array($wancfg)) {
4036
		return;
4037
	}
4038

    
4039
	if (!isset($wancfg['enable'])) {
4040
		return;
4041
	}
4042

    
4043
	/* If the interface is not configured via another, exit */
4044
	if (empty($wancfg['track6-interface'])) {
4045
		return;
4046
	}
4047

    
4048
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4049
	$realif = get_real_interface($interface);
4050
	$linklocal = find_interface_ipv6_ll($realif, true);
4051
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4052
		mwexec("/sbin/ifconfig {$realif} inet6 {$linklocal} delete");
4053
	}
4054
	/* XXX: This might break for good on a carp installation using link-local as network ips */
4055
	/* XXX: Probably should remove? */
4056
	mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif}");
4057

    
4058
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4059
	if (!isset($trackcfg['enable'])) {
4060
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4061
		return;
4062
	}
4063

    
4064
	switch ($trackcfg['ipaddrv6']) {
4065
		case "6to4":
4066
			if ($g['debug']) {
4067
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4068
			}
4069
			interface_track6_6to4_configure($interface, $wancfg);
4070
			break;
4071
		case "6rd":
4072
			if ($g['debug']) {
4073
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4074
			}
4075
			interface_track6_6rd_configure($interface, $wancfg);
4076
			break;
4077
		case "dhcp6":
4078
			if ($linkupevent == true) {
4079
				/*
4080
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4081
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4082
				 *
4083
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4084
				 */
4085
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4086
				$pidv6 = find_dhcp6c_process($parentrealif);
4087
				if ($pidv6) {
4088
					posix_kill($pidv6, SIGHUP);
4089
				}
4090
			}
4091
			break;
4092
	}
4093

    
4094
	if ($linkupevent == false && !platform_booting()) {
4095
		if (!function_exists('services_dhcpd_configure')) {
4096
			require_once("services.inc");
4097
		}
4098

    
4099
		/* restart dns servers (defering dhcpd reload) */
4100
		if (isset($config['unbound']['enable'])) {
4101
			services_unbound_configure(false);
4102
		}
4103
		if (isset($config['dnsmasq']['enable'])) {
4104
			services_dnsmasq_configure(false);
4105
		}
4106

    
4107
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4108
		services_dhcpd_configure("inet6");
4109
	}
4110

    
4111
	return 0;
4112
}
4113

    
4114
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4115
	global $config, $g;
4116
	global $interface_ipv6_arr_cache;
4117
	global $interface_snv6_arr_cache;
4118

    
4119
	if (!is_array($lancfg)) {
4120
		return;
4121
	}
4122

    
4123
	/* If the interface is not configured via another, exit */
4124
	if (empty($lancfg['track6-interface'])) {
4125
		return;
4126
	}
4127

    
4128
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4129
	if (empty($wancfg)) {
4130
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4131
		return;
4132
	}
4133

    
4134
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4135
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4136
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not valid, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
4137
		return;
4138
	}
4139
	$hexwanv4 = return_hex_ipv4($ip4address);
4140

    
4141
	/* create the long prefix notation for math, save the prefix length */
4142
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4143
	$rd6prefixlen = $rd6prefix[1];
4144
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4145

    
4146
	/* binary presentation of the prefix for all 128 bits. */
4147
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4148

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

    
4154
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4155
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4156
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4157
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4158
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4159
	/* fill the rest out with zeros */
4160
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4161

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

    
4165
	$lanif = get_real_interface($interface);
4166
	$oip = find_interface_ipv6($lanif);
4167
	if (is_ipaddrv6($oip)) {
4168
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4169
	}
4170
	unset($interface_ipv6_arr_cache[$lanif]);
4171
	unset($interface_snv6_arr_cache[$lanif]);
4172
	log_error(sprintf(gettext('rd6 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $rd6lan, $lancfg['track6-interface'], $ip4address));
4173
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4174

    
4175
	return 0;
4176
}
4177

    
4178
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4179
	global $config, $g;
4180
	global $interface_ipv6_arr_cache;
4181
	global $interface_snv6_arr_cache;
4182

    
4183
	if (!is_array($lancfg)) {
4184
		return;
4185
	}
4186

    
4187
	/* If the interface is not configured via another, exit */
4188
	if (empty($lancfg['track6-interface'])) {
4189
		return;
4190
	}
4191

    
4192
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4193
	if (empty($wancfg)) {
4194
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4195
		return;
4196
	}
4197

    
4198
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4199
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4200
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
4201
		return;
4202
	}
4203
	$hexwanv4 = return_hex_ipv4($ip4address);
4204

    
4205
	/* create the long prefix notation for math, save the prefix length */
4206
	$sixto4prefix = "2002::";
4207
	$sixto4prefixlen = 16;
4208
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4209

    
4210
	/* binary presentation of the prefix for all 128 bits. */
4211
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4212

    
4213
	/* just save the left prefix length bits */
4214
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4215
	/* add the v4 address */
4216
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4217
	/* add the custom prefix id */
4218
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4219
	/* fill the rest out with zeros */
4220
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4221

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

    
4225
	$lanif = get_real_interface($interface);
4226
	$oip = find_interface_ipv6($lanif);
4227
	if (is_ipaddrv6($oip)) {
4228
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4229
	}
4230
	unset($interface_ipv6_arr_cache[$lanif]);
4231
	unset($interface_snv6_arr_cache[$lanif]);
4232
	log_error(sprintf(gettext('sixto4 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $sixto4lan, $lancfg['track6-interface'], $ip4address));
4233
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4234

    
4235
	return 0;
4236
}
4237

    
4238
function interface_6rd_configure($interface = "wan", $wancfg) {
4239
	global $config, $g;
4240

    
4241
	/* because this is a tunnel interface we can only function
4242
	 *	with a public IPv4 address on the interface */
4243

    
4244
	if (!is_array($wancfg)) {
4245
		return;
4246
	}
4247

    
4248
	if (!is_module_loaded('if_stf.ko')) {
4249
		mwexec('/sbin/kldload if_stf.ko');
4250
	}
4251

    
4252
	$wanif = get_real_interface($interface);
4253
	$ip4address = find_interface_ip($wanif);
4254
	if (!is_ipaddrv4($ip4address)) {
4255
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4256
		return false;
4257
	}
4258
	$hexwanv4 = return_hex_ipv4($ip4address);
4259

    
4260
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4261
		$wancfg['prefix-6rd-v4plen'] = 0;
4262
	}
4263

    
4264
	/* create the long prefix notation for math, save the prefix length */
4265
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4266
	$rd6prefixlen = $rd6prefix[1];
4267
	$brgw = explode('.', $wancfg['gateway-6rd']);
4268
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4269
	$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);
4270
	if (strlen($rd6brgw) < 128) {
4271
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4272
	}
4273
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4274
	unset($brgw);
4275
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4276

    
4277
	/* binary presentation of the prefix for all 128 bits. */
4278
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4279

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

    
4287
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4288
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4289

    
4290

    
4291
	/* XXX: need to extend to support variable prefix size for v4 */
4292
	$stfiface = "{$interface}_stf";
4293
	if (does_interface_exist($stfiface)) {
4294
		pfSense_interface_destroy($stfiface);
4295
	}
4296
	$tmpstfiface = pfSense_interface_create("stf");
4297
	pfSense_interface_rename($tmpstfiface, $stfiface);
4298
	pfSense_interface_flags($stfiface, IFF_LINK2);
4299
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4300
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4301
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4302
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4303
	}
4304
	if ($g['debug']) {
4305
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4306
	}
4307

    
4308
	/* write out a default router file */
4309
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4310
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4311

    
4312
	$ip4gateway = get_interface_gateway($interface);
4313
	if (is_ipaddrv4($ip4gateway)) {
4314
		route_add_or_change("-host {$wancfg['gateway-6rd']} {$ip4gateway}");
4315
	}
4316

    
4317
	/* configure dependent interfaces */
4318
	if (!platform_booting()) {
4319
		link_interface_to_track6($interface, "update");
4320
	}
4321

    
4322
	return 0;
4323
}
4324

    
4325
function interface_6to4_configure($interface = "wan", $wancfg) {
4326
	global $config, $g;
4327

    
4328
	/* because this is a tunnel interface we can only function
4329
	 *	with a public IPv4 address on the interface */
4330

    
4331
	if (!is_array($wancfg)) {
4332
		return;
4333
	}
4334

    
4335
	$wanif = get_real_interface($interface);
4336
	$ip4address = find_interface_ip($wanif);
4337
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4338
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4339
		return false;
4340
	}
4341

    
4342
	/* create the long prefix notation for math, save the prefix length */
4343
	$stfprefixlen = 16;
4344
	$stfprefix = Net_IPv6::uncompress("2002::");
4345
	$stfarr = explode(":", $stfprefix);
4346
	$v4prefixlen = "0";
4347

    
4348
	/* we need the hex form of the interface IPv4 address */
4349
	$ip4arr = explode(".", $ip4address);
4350
	$hexwanv4 = "";
4351
	foreach ($ip4arr as $octet) {
4352
		$hexwanv4 .= sprintf("%02x", $octet);
4353
	}
4354

    
4355
	/* we need the hex form of the broker IPv4 address */
4356
	$ip4arr = explode(".", "192.88.99.1");
4357
	$hexbrv4 = "";
4358
	foreach ($ip4arr as $octet) {
4359
		$hexbrv4 .= sprintf("%02x", $octet);
4360
	}
4361

    
4362
	/* binary presentation of the prefix for all 128 bits. */
4363
	$stfprefixbin = "";
4364
	foreach ($stfarr as $element) {
4365
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4366
	}
4367
	/* just save the left prefix length bits */
4368
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4369

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

    
4374
	/* for the local subnet too. */
4375
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4376
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4377

    
4378
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4379
	$stfbrarr = array();
4380
	$stfbrbinarr = array();
4381
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4382
	foreach ($stfbrbinarr as $bin) {
4383
		$stfbrarr[] = dechex(bindec($bin));
4384
	}
4385
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4386

    
4387
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4388
	$stflanarr = array();
4389
	$stflanbinarr = array();
4390
	$stflanbinarr = str_split($stflanbin, 16);
4391
	foreach ($stflanbinarr as $bin) {
4392
		$stflanarr[] = dechex(bindec($bin));
4393
	}
4394
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4395
	$stflanarr[7] = 1;
4396
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4397

    
4398
	/* setup the stf interface */
4399
	if (!is_module_loaded("if_stf")) {
4400
		mwexec("/sbin/kldload if_stf.ko");
4401
	}
4402
	$stfiface = "{$interface}_stf";
4403
	if (does_interface_exist($stfiface)) {
4404
		pfSense_interface_destroy($stfiface);
4405
	}
4406
	$tmpstfiface = pfSense_interface_create("stf");
4407
	pfSense_interface_rename($tmpstfiface, $stfiface);
4408
	pfSense_interface_flags($stfiface, IFF_LINK2);
4409
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4410

    
4411
	if ($g['debug']) {
4412
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4413
	}
4414

    
4415
	/* write out a default router file */
4416
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4417
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4418

    
4419
	$ip4gateway = get_interface_gateway($interface);
4420
	if (is_ipaddrv4($ip4gateway)) {
4421
		route_add_or_change("-host 192.88.99.1 {$ip4gateway}");
4422
	}
4423

    
4424
	if (!platform_booting()) {
4425
		link_interface_to_track6($interface, "update");
4426
	}
4427

    
4428
	return 0;
4429
}
4430

    
4431
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4432
	global $config, $g;
4433

    
4434
	if (!is_array($wancfg)) {
4435
		return;
4436
	}
4437

    
4438
	$wanif = get_real_interface($interface, "inet6");
4439
	$dhcp6cconf = "";
4440

    
4441
	if (!empty($config['system']['global-v6duid'])) {
4442
		// Write the DUID file
4443
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4444
		    log_error(gettext("Failed to write user DUID file!"));
4445
		}
4446
	}
4447

    
4448
	/* accept router advertisements for this interface                 */
4449
	/* Moved to early in the function as sometimes interface not ready */
4450
	/* RTSOLD fails as interface does not accept .....                 */
4451

    
4452
	log_error("Accept router advertisements on interface {$wanif} ");
4453
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4454

    
4455
	if ($wancfg['adv_dhcp6_config_file_override']) {
4456
		// DHCP6 Config File Override
4457
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4458
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4459
		// DHCP6 Config File Advanced
4460
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4461
	} else {
4462
		// DHCP6 Config File Basic
4463
		$dhcp6cconf .= "interface {$wanif} {\n";
4464

    
4465
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4466
		if ($wancfg['ipaddrv6'] == "slaac") {
4467
			$dhcp6cconf .= "\tinformation-only;\n";
4468
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4469
			$dhcp6cconf .= "\trequest domain-name;\n";
4470
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4471
			$dhcp6cconf .= "};\n";
4472
		} else {
4473
			$trackiflist = array();
4474
			$iflist = link_interface_to_track6($interface);
4475
			foreach ($iflist as $ifname => $ifcfg) {
4476
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4477
					$trackiflist[$ifname] = $ifcfg;
4478
				}
4479
			}
4480

    
4481
			/* skip address request if this is set */
4482
			if (!isset($wancfg['dhcp6prefixonly'])) {
4483
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4484
			}
4485
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4486
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4487
			}
4488

    
4489
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4490
			$dhcp6cconf .= "\trequest domain-name;\n";
4491

    
4492
			/*
4493
			 * dhcp6c will run different scripts depending on
4494
			 * whether dhcpwithoutra is set or unset.
4495
			 */
4496
			if (isset($wancfg['dhcp6withoutra'])) {
4497
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4498
			} else {
4499
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4500
			}
4501
			$dhcp6cconf .= "};\n";
4502

    
4503
			if (!isset($wancfg['dhcp6prefixonly'])) {
4504
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4505
			}
4506

    
4507
			if (is_numeric($wancfg['dhcp6-ia-pd-len']) && !empty($trackiflist)) {
4508
				/* Setup the prefix delegation */
4509
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4510
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4511
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4512
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4513
				}
4514
				foreach ($trackiflist as $friendly => $ifcfg) {
4515
					if ($g['debug']) {
4516
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4517
					}
4518
					$realif = get_real_interface($friendly);
4519
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4520
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4521
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4522
					$dhcp6cconf .= "\t};\n";
4523
				}
4524
				unset($preflen, $iflist, $ifcfg, $ifname);
4525
				$dhcp6cconf .= "};\n";
4526
			}
4527
			unset($trackiflist);
4528
		}
4529
	}
4530

    
4531
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4532
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4533

    
4534
	/* wide-dhcp6c works for now. */
4535
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
4536
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
4537
		unset($dhcp6cconf);
4538
		return 1;
4539
	}
4540
	unset($dhcp6cconf);
4541

    
4542
	/*************** Script Debug Logging ***************************
4543
	Both dhcp6 scripts now have a logging message built in.
4544
	These logging messages ONLY appear if dhcp6c debug logging is set.
4545
	The logging messages appear in the dhcp section of the logs,
4546
	not in system.
4547

    
4548
	These scripts now also take advantage of the REASON= env vars
4549
	supplied by dhcp6c.
4550
	****************************************************************/
4551

    
4552
	/* Script create for dhcp6withoutRA mode */
4553
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4554
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4555
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4556
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4557
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4558
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4559
	// Need to pass params to  the final script
4560
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4561
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4562
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4563
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4564
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
4565
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4566
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4567
	if ($debugOption == '-D') {
4568
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4569
	}
4570
	$dhcp6cscriptwithoutra .= ";;\n";
4571
	$dhcp6cscriptwithoutra .= "REBIND)\n";
4572
	if ($debugOption == '-D') {
4573
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4574
	}
4575
	$dhcp6cscriptwithoutra .= ";;\n";
4576
	if (isset($wancfg['dhcp6norelease'])) {
4577
		$dhcp6cscriptwithoutra .= "EXIT)\n";
4578
	} else {
4579
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
4580
	}
4581
	if ($debugOption == '-D') {
4582
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4583
	}
4584
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4585
	$dhcp6cscriptwithoutra .= ";;\n";
4586
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4587
	if ($debugOption == '-D') {
4588
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4589
	}
4590
	$dhcp6cscriptwithoutra .= "esac\n";
4591
	if (!@file_put_contents(
4592
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4593
	    $dhcp6cscriptwithoutra)) {
4594
		printf("Error: cannot open " .
4595
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4596
		    "interface_dhcpv6_configure() for writing.\n");
4597
		unset($dhcp6cscriptwithoutra);
4598
		return 1;
4599
	}
4600

    
4601
	unset($dhcp6cscriptwithoutra);
4602
	@chmod(
4603
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4604
	    0755);
4605

    
4606
	/*
4607
	 * Dual mode wan_dhcp6c script with variations depending on node
4608
	 * dhcp6 will run the wan ipv6 configure
4609
	 */
4610
	$dhcp6cscript  = "#!/bin/sh\n";
4611
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4612
	if (!isset($wancfg['dhcp6withoutra'])) {
4613
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4614
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4615
		$dhcp6cscript .= "case \$REASON in\n";
4616
		$dhcp6cscript .= "REQUEST)\n";
4617
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4618
		if ($debugOption == '-D') {
4619
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n";
4620
		}
4621
		$dhcp6cscript .= ";;\n";
4622
		$dhcp6cscript .= "REBIND)\n";
4623
		if ($debugOption == '-D') {
4624
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4625
		}
4626
		$dhcp6cscript .= ";;\n";
4627
		if (isset($wancfg['dhcp6norelease'])) {
4628
			$dhcp6cscript .= "EXIT)\n";
4629
		} else {
4630
			$dhcp6cscript .= "RELEASE)\n";
4631
		}
4632
		if ($debugOption == '-D') {
4633
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4634
		}
4635
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4636
		$dhcp6cscript .= ";;\n";
4637
		$dhcp6cscript .= "RENEW|INFO)\n";
4638
		if ($debugOption == '-D') {
4639
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4640
		}
4641
		$dhcp6cscript .= "esac\n";
4642
	} else {
4643
		// Need to get the parameters from the dhcp6cwithoutRA run
4644
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4645
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4646
		$dhcp6cscript .= "/bin/sleep 1\n";
4647
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4648
	}
4649

    
4650
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4651
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4652
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4653
		unset($dhcp6cscript);
4654
		return 1;
4655
	}
4656
	unset($dhcp6cscript);
4657
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4658

    
4659
	$rtsoldscript = "#!/bin/sh\n";
4660
	$rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n";
4661
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n";
4662
	$rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_defaultgwv6\n";
4663
	$rtsoldscript .= "/usr/bin/logger -t rtsold \"Received RA specifying route \$2 for interface {$interface}({$wanif})\"\n";
4664

    
4665
	/* non ipoe Process */
4666
	if (!isset($wancfg['dhcp6withoutra'])) {
4667
		/*
4668
		 * We only want this script to run once, and if it runs twice
4669
		 * then do not launch dhcp6c again, this only happens if
4670
		 * dhcpwithoutra is not set.
4671
		 *
4672
		 * Check for a lock file, trying to prevent multiple instances
4673
		 * of dhcp6c being launched
4674
		 */
4675
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
4676
		/*
4677
		 * Create the lock file, trying to prevent multiple instances
4678
		 * of dhcp6c being launched
4679
		 */
4680
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
4681
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
4682
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4683
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
4684
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
4685
		$rtsoldscript .= "\tfi\n";
4686
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
4687
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
4688
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
4689
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
4690
		$rtsoldscript .= "else\n";
4691
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
4692
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
4693
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
4694
		$rtsoldscript .= "fi\n";
4695
	} else {
4696
		/*
4697
		 * The script needs to run in dhcp6withoutra mode as RA may
4698
		 * not have been received, or there can be a delay with
4699
		 * certain ISPs
4700
		 */
4701
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
4702
		$rtsoldscript .= "/bin/sleep 1\n";
4703
	}
4704
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4705
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
4706
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
4707
		unset($rtsoldscript);
4708
		return 1;
4709
	}
4710
	unset($rtsoldscript);
4711
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
4712

    
4713
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
4714
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
4715
		log_error("Killing running rtsold process");
4716
		sleep(2);
4717
	}
4718

    
4719
	if (isset($wancfg['dhcp6withoutra'])) {
4720
		/*
4721
		 * Start dhcp6c here if we don't want to wait for ra - calls
4722
		 * seperate function
4723
		 *
4724
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
4725
		 * will then run the configure on receipt of the RA.
4726
		 *
4727
		 * Already started. interface_dhcpv6_configure() appears to get
4728
		 * called multiple times.
4729
		 *
4730
		 * Taking the interface down or releasing will kill the client.
4731
		 */
4732
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
4733
		{
4734
			/*
4735
			 * If the interface is being brought up, wait for the
4736
			 * interface to configure accept RA before launching.
4737
			 * Otherwise it is not ready to accept and will fail.
4738
			 */
4739
			sleep(3);
4740
			run_dhcp6client_process($wanif,$interface,$wancfg);
4741
		}
4742
	} else {
4743
		/*
4744
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
4745
		 * ( it does not background, it exits! ) It will launch dhcp6c
4746
		 * if dhcpwihtoutra is not set
4747
		 */
4748
		log_error("Starting rtsold process");
4749
		sleep(2);
4750
		mwexec("/usr/sbin/rtsold -1 " .
4751
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
4752
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
4753
		    $wanif);
4754
	}
4755
	/*
4756
	 * NOTE: will be called from rtsold invoked script
4757
	 * link_interface_to_track6($interface, "update");
4758
	 */
4759

    
4760
	return 0;
4761
}
4762

    
4763
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
4764
	global $g;
4765

    
4766
	$send_options = "";
4767
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
4768
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
4769
		foreach ($options as $option) {
4770
			$send_options .= "\tsend " . trim($option) . ";\n";
4771
		}
4772
	}
4773

    
4774
	$request_options = "";
4775
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
4776
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
4777
		foreach ($options as $option) {
4778
			$request_options .= "\trequest " . trim($option) . ";\n";
4779
		}
4780
	}
4781

    
4782
	$information_only = "";
4783
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
4784
		$information_only = "\tinformation-only;\n";
4785
	}
4786

    
4787
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
4788
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
4789
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
4790
	}
4791

    
4792
	$interface_statement  = "interface";
4793
	$interface_statement .= " {$wanif}";
4794
	$interface_statement .= " {\n";
4795
	$interface_statement .= "$send_options";
4796
	$interface_statement .= "$request_options";
4797
	$interface_statement .= "$information_only";
4798
	$interface_statement .= "$script";
4799
	$interface_statement .= "};\n";
4800

    
4801
	$id_assoc_statement_address = "";
4802
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
4803
		$id_assoc_statement_address .= "id-assoc";
4804
		$id_assoc_statement_address .= " na";
4805
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
4806
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
4807
		}
4808
		$id_assoc_statement_address .= " { ";
4809

    
4810
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
4811
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
4812
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
4813
			$id_assoc_statement_address .= "\n\taddress";
4814
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
4815
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
4816
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
4817
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
4818
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
4819
			}
4820
			$id_assoc_statement_address .= ";\n";
4821
		}
4822

    
4823
		$id_assoc_statement_address .= "};\n";
4824
	}
4825

    
4826
	$id_assoc_statement_prefix = "";
4827
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
4828
		$id_assoc_statement_prefix .= "id-assoc";
4829
		$id_assoc_statement_prefix .= " pd";
4830
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
4831
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
4832
		}
4833
		$id_assoc_statement_prefix .= " { ";
4834

    
4835
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
4836
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
4837
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
4838
			$id_assoc_statement_prefix .= "\n\tprefix";
4839
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
4840
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
4841
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
4842
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
4843
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
4844
			}
4845
			$id_assoc_statement_prefix .= ";";
4846
		}
4847

    
4848
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
4849
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
4850
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
4851
			$id_assoc_statement_prefix .= " {$realif}";
4852
			$id_assoc_statement_prefix .= " {\n";
4853
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
4854
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
4855
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
4856
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
4857
			}
4858
			$id_assoc_statement_prefix .= "\t};";
4859
		}
4860

    
4861
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
4862
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
4863
			$id_assoc_statement_prefix .= "\n";
4864
		}
4865

    
4866
		$id_assoc_statement_prefix .= "};\n";
4867
	}
4868

    
4869
	$authentication_statement = "";
4870
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
4871
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
4872
		$authentication_statement .= "authentication";
4873
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
4874
		$authentication_statement .= " {\n";
4875
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
4876
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
4877
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
4878
		}
4879
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
4880
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
4881
		}
4882
		$authentication_statement .= "};\n";
4883
	}
4884

    
4885
	$key_info_statement = "";
4886
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
4887
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
4888
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
4889
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
4890
		$key_info_statement .= "keyinfo";
4891
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
4892
		$key_info_statement .= " {\n";
4893
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
4894
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
4895
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
4896
		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'])) {
4897
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
4898
		}
4899
		$key_info_statement .= "};\n";
4900
	}
4901

    
4902
	$dhcp6cconf  = $interface_statement;
4903
	$dhcp6cconf .= $id_assoc_statement_address;
4904
	$dhcp6cconf .= $id_assoc_statement_prefix;
4905
	$dhcp6cconf .= $authentication_statement;
4906
	$dhcp6cconf .= $key_info_statement;
4907

    
4908
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4909

    
4910
	return $dhcp6cconf;
4911
}
4912

    
4913

    
4914
function DHCP6_Config_File_Override($wancfg, $wanif) {
4915

    
4916
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
4917

    
4918
	if ($dhcp6cconf === false) {
4919
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
4920
		return '';
4921
	} else {
4922
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
4923
	}
4924
}
4925

    
4926

    
4927
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
4928

    
4929
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
4930

    
4931
	return $dhcp6cconf;
4932
}
4933

    
4934

    
4935
function interface_dhcp_configure($interface = "wan") {
4936
	global $config, $g;
4937

    
4938
	$ifcfg = $config['interfaces'][$interface];
4939
	if (empty($ifcfg)) {
4940
		$ifcfg = array();
4941
	}
4942

    
4943
	/* generate dhclient_wan.conf */
4944
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
4945
	if (!$fd) {
4946
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
4947
		return 1;
4948
	}
4949

    
4950
	if ($ifcfg['dhcphostname']) {
4951
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
4952
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
4953
	} else {
4954
		$dhclientconf_hostname = "";
4955
	}
4956

    
4957
	$realif = get_real_interface($interface);
4958
	if (empty($realif)) {
4959
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
4960
		return 0;
4961
	}
4962
	$dhclientconf = "";
4963

    
4964
	$dhclientconf .= <<<EOD
4965
interface "{$realif}" {
4966
	supersede interface-mtu 0;
4967
	timeout 60;
4968
	retry 15;
4969
	select-timeout 0;
4970
	initial-interval 1;
4971
	{$dhclientconf_hostname}
4972
	script "/usr/local/sbin/pfSense-dhclient-script";
4973
EOD;
4974

    
4975
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
4976
		$dhclientconf .= <<<EOD
4977

    
4978
	reject {$ifcfg['dhcprejectfrom']};
4979
EOD;
4980
	}
4981
	$dhclientconf .= <<<EOD
4982

    
4983
}
4984

    
4985
EOD;
4986

    
4987
	// DHCP Config File Advanced
4988
	if ($ifcfg['adv_dhcp_config_advanced']) {
4989
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
4990
	}
4991

    
4992
	if (is_ipaddr($ifcfg['alias-address'])) {
4993
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
4994
		$dhclientconf .= <<<EOD
4995
alias {
4996
	interface "{$realif}";
4997
	fixed-address {$ifcfg['alias-address']};
4998
	option subnet-mask {$subnetmask};
4999
}
5000

    
5001
EOD;
5002
	}
5003

    
5004
	// DHCP Config File Override
5005
	if ($ifcfg['adv_dhcp_config_file_override']) {
5006
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5007
	}
5008

    
5009
	fwrite($fd, $dhclientconf);
5010
	fclose($fd);
5011

    
5012
	/* bring wan interface up before starting dhclient */
5013
	if ($realif) {
5014
		interfaces_bring_up($realif);
5015
	}
5016

    
5017
	/* Make sure dhclient is not running */
5018
	kill_dhclient_process($realif);
5019

    
5020
	/* fire up dhclient */
5021
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$realif} > {$g['tmp_path']}/{$realif}_output 2> {$g['tmp_path']}/{$realif}_error_output");
5022

    
5023
	return 0;
5024
}
5025

    
5026
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5027

    
5028
	$hostname = "";
5029
	if ($ifcfg['dhcphostname'] != '') {
5030
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5031
	}
5032

    
5033
	/* DHCP Protocol Timings */
5034
	$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");
5035
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5036
		$pt_variable = "{$Protocol_Timing}";
5037
		${$pt_variable} = "";
5038
		if ($ifcfg[$Protocol_Timing] != "") {
5039
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5040
		}
5041
	}
5042

    
5043
	$send_options = "";
5044
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5045
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5046
		foreach ($options as $option) {
5047
			$send_options .= "\tsend " . trim($option) . ";\n";
5048
		}
5049
	}
5050

    
5051
	$request_options = "";
5052
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5053
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5054
	}
5055

    
5056
	$required_options = "";
5057
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5058
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5059
	}
5060

    
5061
	$option_modifiers = "";
5062
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5063
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5064
		foreach ($modifiers as $modifier) {
5065
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5066
		}
5067
	}
5068

    
5069
	$dhclientconf  = "interface \"{$realif}\" {\n";
5070
	$dhclientconf .= "\n";
5071
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5072
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5073
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5074
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5075
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5076
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5077
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5078
	$dhclientconf .= "\n";
5079
	$dhclientconf .= "# DHCP Protocol Options\n";
5080
	$dhclientconf .= "{$hostname}";
5081
	$dhclientconf .= "{$send_options}";
5082
	$dhclientconf .= "{$request_options}";
5083
	$dhclientconf .= "{$required_options}";
5084
	$dhclientconf .= "{$option_modifiers}";
5085
	$dhclientconf .= "\n";
5086
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5087
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5088
	}
5089
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5090
	$dhclientconf .= "}\n";
5091

    
5092
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5093

    
5094
	return $dhclientconf;
5095
}
5096

    
5097
function DHCP_Config_Option_Split($option_string) {
5098
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5099
	return $matches ? $matches[0] : [];
5100
}
5101

    
5102
function DHCP_Config_File_Override($ifcfg, $realif) {
5103

    
5104
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5105

    
5106
	if ($dhclientconf === false) {
5107
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5108
		return '';
5109
	} else {
5110
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5111
	}
5112
}
5113

    
5114

    
5115
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5116

    
5117
	/* Apply Interface Substitutions */
5118
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5119

    
5120
	/* Apply Hostname Substitutions */
5121
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5122

    
5123
	/* Arrays of MAC Address Types, Cases, Delimiters */
5124
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5125
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5126
	$various_mac_cases      = array("U", "L");
5127
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5128

    
5129
	/* Apply MAC Address Substitutions */
5130
	foreach ($various_mac_types as $various_mac_type) {
5131
		foreach ($various_mac_cases as $various_mac_case) {
5132
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5133

    
5134
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5135
				if ($res !== false) {
5136

    
5137
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5138
					if ("$various_mac_case" == "U") {
5139
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5140
					}
5141
					if ("$various_mac_case" == "L") {
5142
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5143
					}
5144

    
5145
					if ("$various_mac_type" == "mac_addr_hex") {
5146
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5147
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5148
						$dhcpclientconf_mac_hex = "";
5149
						$delimiter = "";
5150
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5151
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5152
							$delimiter = ":";
5153
						}
5154
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5155
					}
5156

    
5157
					/* MAC Address Delimiter Substitutions */
5158
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5159

    
5160
					/* Apply MAC Address Substitutions */
5161
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5162
				}
5163
			}
5164
		}
5165
	}
5166

    
5167
	return $dhclientconf;
5168
}
5169

    
5170
function interfaces_group_setup() {
5171
	global $config;
5172

    
5173
	if (!is_array($config['ifgroups']['ifgroupentry'])) {
5174
		return;
5175
	}
5176

    
5177
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5178
		interface_group_setup($groupar);
5179
	}
5180

    
5181
	return;
5182
}
5183

    
5184
function interface_group_setup(&$groupname /* The parameter is an array */) {
5185
	global $config;
5186

    
5187
	if (!is_array($groupname)) {
5188
		return;
5189
	}
5190
	$members = explode(" ", $groupname['members']);
5191
	foreach ($members as $ifs) {
5192
		$realif = get_real_interface($ifs);
5193
		if ($realif && does_interface_exist($realif)) {
5194
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5195
		}
5196
	}
5197

    
5198
	return;
5199
}
5200

    
5201
function is_interface_group($if) {
5202
	global $config;
5203

    
5204
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5205
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5206
			if ($groupentry['ifname'] === $if) {
5207
				return true;
5208
			}
5209
		}
5210
	}
5211

    
5212
	return false;
5213
}
5214

    
5215
function interface_group_add_member($interface, $groupname) {
5216
	$interface = get_real_interface($interface);
5217
	if (does_interface_exist($interface)) {
5218
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5219
	}
5220
}
5221

    
5222
/* COMPAT Function */
5223
function convert_friendly_interface_to_real_interface_name($interface) {
5224
	return get_real_interface($interface);
5225
}
5226

    
5227
/* COMPAT Function */
5228
function get_real_wan_interface($interface = "wan") {
5229
	return get_real_interface($interface);
5230
}
5231

    
5232
/* COMPAT Function */
5233
function get_current_wan_address($interface = "wan") {
5234
	return get_interface_ip($interface);
5235
}
5236

    
5237
/*
5238
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5239
 */
5240
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5241
	global $config;
5242

    
5243
	/* XXX: For speed reasons reference directly the interface array */
5244
	$ifdescrs = &$config['interfaces'];
5245
	//$ifdescrs = get_configured_interface_list(true);
5246

    
5247
	foreach ($ifdescrs as $if => $ifname) {
5248
		if ($if == $interface || $ifname['if'] == $interface) {
5249
			return $if;
5250
		}
5251

    
5252
		if (get_real_interface($if) == $interface) {
5253
			return $if;
5254
		}
5255

    
5256
		if ($checkparent == false) {
5257
			continue;
5258
		}
5259

    
5260
		$int = get_parent_interface($if, true);
5261
		if (is_array($int)) {
5262
			foreach ($int as $iface) {
5263
				if ($iface == $interface) {
5264
					return $if;
5265
				}
5266
			}
5267
		}
5268
	}
5269

    
5270
	if ($interface == "enc0") {
5271
		return 'IPsec';
5272
	}
5273
}
5274

    
5275
/* attempt to resolve interface to friendly descr */
5276
function convert_friendly_interface_to_friendly_descr($interface) {
5277
	global $config;
5278

    
5279
	switch ($interface) {
5280
		case "l2tp":
5281
			$ifdesc = "L2TP";
5282
			break;
5283
		case "pptp":
5284
			$ifdesc = "PPTP";
5285
			break;
5286
		case "pppoe":
5287
			$ifdesc = "PPPoE";
5288
			break;
5289
		case "openvpn":
5290
			$ifdesc = "OpenVPN";
5291
			break;
5292
		case "lo0":
5293
			$ifdesc = "Loopback";
5294
			break;
5295
		case "enc0":
5296
		case "ipsec":
5297
		case "IPsec":
5298
			$ifdesc = "IPsec";
5299
			break;
5300
		default:
5301
			if (isset($config['interfaces'][$interface])) {
5302
				if (empty($config['interfaces'][$interface]['descr'])) {
5303
					$ifdesc = strtoupper($interface);
5304
				} else {
5305
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5306
				}
5307
				break;
5308
			} else if (substr($interface, 0, 4) == '_vip') {
5309
				if (is_array($config['virtualip']['vip'])) {
5310
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5311
						if ($vip['mode'] == "carp") {
5312
							if ($interface == "_vip{$vip['uniqid']}") {
5313
								$descr = $vip['subnet'];
5314
								$descr .= " (vhid {$vip['vhid']})";
5315
								if (!empty($vip['descr'])) {
5316
									$descr .= " - " .$vip['descr'];
5317
								}
5318
								return $descr;
5319
							}
5320
						}
5321
					}
5322
				}
5323
			} else if (substr($interface, 0, 5) == '_lloc') {
5324
				return get_interface_linklocal($interface);
5325
			} else {
5326
				if (is_array($config['ifgroups']['ifgroupentry'])) {
5327
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5328
						if ($ifgen['ifname'] === $interface) {
5329
							return $ifgen['ifname'];
5330
						}
5331
					}
5332
				}
5333

    
5334
				/* if list */
5335
				$ifdescrs = get_configured_interface_with_descr(true);
5336
				foreach ($ifdescrs as $if => $ifname) {
5337
					if ($if == $interface || $ifname == $interface) {
5338
						return $ifname;
5339
					}
5340
				}
5341
			}
5342
			break;
5343
	}
5344

    
5345
	return $ifdesc;
5346
}
5347

    
5348
function convert_real_interface_to_friendly_descr($interface) {
5349

    
5350
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5351

    
5352
	if (!empty($ifdesc)) {
5353
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5354
	}
5355

    
5356
	return $interface;
5357
}
5358

    
5359
/*
5360
 *  get_parent_interface($interface):
5361
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5362
 *				or virtual interface (i.e. vlan)
5363
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5364
 *			-- returns $interface passed in if $interface parent is not found
5365
 *			-- returns empty array if an invalid interface is passed
5366
 *	(Only handles ppps and vlans now.)
5367
 */
5368
function get_parent_interface($interface, $avoidrecurse = false) {
5369
	global $config;
5370

    
5371
	$parents = array();
5372
	//Check that we got a valid interface passed
5373
	$realif = get_real_interface($interface);
5374
	if ($realif == NULL) {
5375
		return $parents;
5376
	}
5377

    
5378
	// If we got a real interface, find it's friendly assigned name
5379
	if ($interface == $realif && $avoidrecurse == false) {
5380
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5381
	}
5382

    
5383
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5384
		$ifcfg = $config['interfaces'][$interface];
5385
		switch ($ifcfg['ipaddr']) {
5386
			case "ppp":
5387
			case "pppoe":
5388
			case "pptp":
5389
			case "l2tp":
5390
				if (empty($parents)) {
5391
					if (is_array($config['ppps']['ppp'])) {
5392
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5393
							if ($ifcfg['if'] == $ppp['if']) {
5394
								$ports = explode(',', $ppp['ports']);
5395
								foreach ($ports as $pid => $parent_if) {
5396
									$parents[$pid] = get_real_interface($parent_if);
5397
								}
5398
								break;
5399
							}
5400
						}
5401
					}
5402
				}
5403
				break;
5404
			case "dhcp":
5405
			case "static":
5406
			default:
5407
				// Handle _vlans
5408
				$vlan = interface_is_vlan($ifcfg['if']);
5409
				if ($vlan != NULL) {
5410
					$parents[0] = $vlan['if'];
5411
				}
5412
				break;
5413
		}
5414
	}
5415

    
5416
	if (empty($parents)) {
5417
		// Handle _vlans not assigned to an interface
5418
		$vlan = interface_is_vlan($realif);
5419
		if ($vlan != NULL) {
5420
			$parents[0] = $vlan['if'];
5421
		}
5422
	}
5423

    
5424
	if (empty($parents)) {
5425
		/* Handle LAGGs. */
5426
		$lagg = interface_is_lagg($realif);
5427
		if ($lagg != NULL && isset($lagg['members'])) {
5428
			$parents = explode(",", $lagg['members']);
5429
		}
5430
	}
5431

    
5432
	if (empty($parents)) {
5433
		$parents[0] = $realif;
5434
	}
5435

    
5436
	return $parents;
5437
}
5438

    
5439
/*
5440
 *  get_parent_physical_interface($interface):
5441
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5442
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5443
 */
5444
function get_parent_physical_interface($interface) {
5445
	global $config;
5446

    
5447
	$realif = get_parent_interface($interface);
5448

    
5449
	if (substr($realif[0], 0, 4) == "lagg") {
5450
		foreach ($config['laggs']['lagg'] as $lagg) {
5451
			if ($realif[0] == $lagg['laggif']) {
5452
				return explode(",", $lagg['members']);
5453
			}
5454
		}
5455
	} else {
5456
		return $realif;
5457
	}
5458
}
5459

    
5460
function interface_is_wireless_clone($wlif) {
5461
	if (!stristr($wlif, "_wlan")) {
5462
		return false;
5463
	} else {
5464
		return true;
5465
	}
5466
}
5467

    
5468
function interface_get_wireless_base($wlif) {
5469
	if (!stristr($wlif, "_wlan")) {
5470
		return $wlif;
5471
	} else {
5472
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5473
	}
5474
}
5475

    
5476
function interface_get_wireless_clone($wlif) {
5477
	if (!stristr($wlif, "_wlan")) {
5478
		return $wlif . "_wlan0";
5479
	} else {
5480
		return $wlif;
5481
	}
5482
}
5483

    
5484
function interface_list_wireless() {
5485
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5486

    
5487
	$result = array();
5488
	foreach ($portlist as $port) {
5489
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5490
			continue;
5491
		}
5492

    
5493
		$desc = $port . " ( " . get_single_sysctl(
5494
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5495

    
5496
		$result[] = array(
5497
		    "if" => $port,
5498
		    "descr" => $desc
5499
		);
5500
	}
5501

    
5502
	return $result;
5503
}
5504

    
5505
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = true) {
5506
	global $config, $g;
5507

    
5508
	$wanif = NULL;
5509

    
5510
	switch ($interface) {
5511
		case "l2tp":
5512
			$wanif = "l2tp";
5513
			break;
5514
		case "pptp":
5515
			$wanif = "pptp";
5516
			break;
5517
		case "pppoe":
5518
			$wanif = "pppoe";
5519
			break;
5520
		case "openvpn":
5521
			$wanif = "openvpn";
5522
			break;
5523
		case "IPsec":
5524
		case "ipsec":
5525
		case "enc0":
5526
			$wanif = "enc0";
5527
			break;
5528
		case "ppp":
5529
			$wanif = "ppp";
5530
			break;
5531
		default:
5532
			if (substr($interface, 0, 4) == '_vip') {
5533
				$wanif = get_configured_vip_interface($interface);
5534
				if (!empty($wanif)) {
5535
					$wanif = get_real_interface($wanif);
5536
				}
5537
				break;
5538
			} else if (substr($interface, 0, 5) == '_lloc') {
5539
				$interface = substr($interface, 5);
5540
			} else if (interface_is_vlan($interface) != NULL ||
5541
			    does_interface_exist($interface, $flush)) {
5542
				/*
5543
				 * If a real interface was already passed simply
5544
				 * pass the real interface back.  This encourages
5545
				 * the usage of this function in more cases so that
5546
				 * we can combine logic for more flexibility.
5547
				 */
5548
				$wanif = $interface;
5549
				break;
5550
			}
5551

    
5552
			if (empty($config['interfaces'][$interface])) {
5553
				break;
5554
			}
5555

    
5556
			$cfg = &$config['interfaces'][$interface];
5557

    
5558
			if ($family == "inet6") {
5559
				switch ($cfg['ipaddrv6']) {
5560
					case "6rd":
5561
					case "6to4":
5562
						$wanif = "{$interface}_stf";
5563
						break;
5564
					case 'pppoe':
5565
					case 'ppp':
5566
					case 'l2tp':
5567
					case 'pptp':
5568
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5569
							$wanif = interface_get_wireless_clone($cfg['if']);
5570
						} else {
5571
							$wanif = $cfg['if'];
5572
						}
5573
						break;
5574
					default:
5575
						switch ($cfg['ipaddr']) {
5576
							case 'pppoe':
5577
							case 'ppp':
5578
							case 'l2tp':
5579
							case 'pptp':
5580
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5581
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) || isset($cfg['ipv6usev4iface'])) {
5582
									$wanif = $cfg['if'];
5583
								} else {
5584
									$parents = get_parent_interface($interface);
5585
									if (!empty($parents[0])) {
5586
										$wanif = $parents[0];
5587
									} else {
5588
										$wanif = $cfg['if'];
5589
									}
5590
								}
5591
								break;
5592
							default:
5593
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5594
									$wanif = interface_get_wireless_clone($cfg['if']);
5595
								} else {
5596
									$wanif = $cfg['if'];
5597
								}
5598
								break;
5599
						}
5600
						break;
5601
				}
5602
			} else {
5603
				// Wireless cloned NIC support (FreeBSD 8+)
5604
				// interface name format: $parentnic_wlanparentnic#
5605
				// example: ath0_wlan0
5606
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5607
					$wanif = interface_get_wireless_clone($cfg['if']);
5608
				} else {
5609
					$wanif = $cfg['if'];
5610
				}
5611
			}
5612
			break;
5613
	}
5614

    
5615
	return $wanif;
5616
}
5617

    
5618
/* Guess the physical interface by providing a IP address */
5619
function guess_interface_from_ip($ipaddress) {
5620

    
5621
	$family = '';
5622
	if (is_ipaddrv4($ipaddress)) {
5623
		$family = 'inet';
5624
	}
5625
	if (empty($family) && is_ipaddrv6($ipaddress)) {
5626
		$family = 'inet6';
5627
	}
5628

    
5629
	if (empty($family)) {
5630
		return false;
5631
	}
5632

    
5633
	/* create a route table we can search */
5634
	$output = '';
5635
	$_gb = exec("/sbin/route -n get -{$family} " . escapeshellarg($ipaddress) . " | /usr/bin/awk '/interface/ { print \$2; };'", $output);
5636
	$output[0] = trim($output[0], " \n");
5637
	if (!empty($output[0])) {
5638
		return $output[0];
5639
	}
5640

    
5641
	return false;
5642
}
5643

    
5644
/*
5645
 * find_ip_interface($ip): return the interface where an ip is defined
5646
 *   (or if $bits is specified, where an IP within the subnet is defined)
5647
 */
5648
function find_ip_interface($ip, $bits = null) {
5649
	if (!is_ipaddr($ip)) {
5650
		return false;
5651
	}
5652

    
5653
	$isv6ip = is_ipaddrv6($ip);
5654

    
5655
	/* if list */
5656
	$ifdescrs = get_configured_interface_list();
5657

    
5658
	foreach ($ifdescrs as $ifdescr => $ifname) {
5659
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
5660
		if (is_null($ifip)) {
5661
			continue;
5662
		}
5663
		if (is_null($bits)) {
5664
			if ($ip == $ifip) {
5665
				$int = get_real_interface($ifname);
5666
				return $int;
5667
			}
5668
		} else {
5669
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
5670
				$int = get_real_interface($ifname);
5671
				return $int;
5672
			}
5673
		}
5674
	}
5675

    
5676
	return false;
5677
}
5678

    
5679
/*
5680
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
5681
 *   (or if $bits is specified, where an IP within the subnet is found)
5682
 */
5683
function find_virtual_ip_alias($ip, $bits = null) {
5684
	global $config;
5685

    
5686
	if (!is_array($config['virtualip']['vip'])) {
5687
		return false;
5688
	}
5689
	if (!is_ipaddr($ip)) {
5690
		return false;
5691
	}
5692

    
5693
	$isv6ip = is_ipaddrv6($ip);
5694

    
5695
	foreach ($config['virtualip']['vip'] as $vip) {
5696
		if ($vip['mode'] === "ipalias") {
5697
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
5698
				continue;
5699
			}
5700
			if (is_null($bits)) {
5701
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
5702
					return $vip;
5703
				}
5704
			} else {
5705
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
5706
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
5707
					return $vip;
5708
				}
5709
			}
5710
		}
5711
	}
5712
	return false;
5713
}
5714

    
5715
function link_interface_to_track6($int, $action = "") {
5716
	global $config;
5717

    
5718
	if (empty($int)) {
5719
		return;
5720
	}
5721

    
5722
	if (is_array($config['interfaces'])) {
5723
		$list = array();
5724
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
5725
			if (!isset($ifcfg['enable'])) {
5726
				continue;
5727
			}
5728
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
5729
				if ($action == "update") {
5730
					interface_track6_configure($ifname, $ifcfg);
5731
				} else if ($action == "") {
5732
					$list[$ifname] = $ifcfg;
5733
				}
5734
			}
5735
		}
5736
		return $list;
5737
	}
5738
}
5739

    
5740
function interface_find_child_cfgmtu($realiface) {
5741
	global $config;
5742

    
5743
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
5744
	$vlans = link_interface_to_vlans($realiface);
5745
	$qinqs = link_interface_to_qinqs($realiface);
5746
	$bridge = link_interface_to_bridge($realiface);
5747
	if (!empty($interface)) {
5748
		$gifs = link_interface_to_gif($interface);
5749
		$gres = link_interface_to_gre($interface);
5750
	} else {
5751
		$gifs = array();
5752
		$gres = array();
5753
	}
5754

    
5755
	$mtu = 0;
5756
	if (is_array($vlans)) {
5757
		foreach ($vlans as $vlan) {
5758
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
5759
			if (empty($ifass)) {
5760
				continue;
5761
			}
5762
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5763
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5764
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5765
				}
5766
			}
5767
		}
5768
	}
5769
	if (is_array($qinqs)) {
5770
		foreach ($qinqs as $qinq) {
5771
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
5772
			if (empty($ifass)) {
5773
				continue;
5774
			}
5775
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5776
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5777
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5778
				}
5779
			}
5780
		}
5781
	}
5782
	if (is_array($gifs)) {
5783
		foreach ($gifs as $gif) {
5784
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
5785
			if (empty($ifass)) {
5786
				continue;
5787
			}
5788
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5789
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5790
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5791
				}
5792
			}
5793
		}
5794
	}
5795
	if (is_array($gres)) {
5796
		foreach ($gres as $gre) {
5797
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
5798
			if (empty($ifass)) {
5799
				continue;
5800
			}
5801
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
5802
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5803
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
5804
				}
5805
			}
5806
		}
5807
	}
5808
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
5809
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
5810
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
5811
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
5812
		}
5813
	}
5814
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
5815

    
5816
	return $mtu;
5817
}
5818

    
5819
function link_interface_to_vlans($int, $action = "") {
5820
	global $config;
5821

    
5822
	if (empty($int)) {
5823
		return;
5824
	}
5825

    
5826
	if (is_array($config['vlans']['vlan'])) {
5827
		$ifaces = array();
5828
		foreach ($config['vlans']['vlan'] as $vlan) {
5829
			if ($int == $vlan['if']) {
5830
				if ($action == "update") {
5831
					interfaces_bring_up($int);
5832
				} else {
5833
					$ifaces[$vlan['tag']] = $vlan;
5834
				}
5835
			}
5836
		}
5837
		if (!empty($ifaces)) {
5838
			return $ifaces;
5839
		}
5840
	}
5841
}
5842

    
5843
function link_interface_to_qinqs($int, $action = "") {
5844
	global $config;
5845

    
5846
	if (empty($int)) {
5847
		return;
5848
	}
5849

    
5850
	if (is_array($config['qinqs']['qinqentry'])) {
5851
		$ifaces = array();
5852
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
5853
			if ($int == $qinq['if']) {
5854
				if ($action == "update") {
5855
					interfaces_bring_up($int);
5856
				} else {
5857
					$ifaces[$qinq['tag']] = $qinq;
5858
				}
5859
			}
5860
		}
5861
		if (!empty($ifaces)) {
5862
			return $ifaces;
5863
		}
5864
	}
5865
}
5866

    
5867
function link_interface_to_vips($int, $action = "", $vhid = '') {
5868
	global $config;
5869

    
5870
	$updatevips = false;
5871
	if (is_array($config['virtualip']['vip'])) {
5872
		$result = array();
5873
		foreach ($config['virtualip']['vip'] as $vip) {
5874
			if (substr($vip['interface'], 0, 4) == "_vip") {
5875
				$iface = get_configured_vip_interface($vip['interface']);
5876
			} else {
5877
				$iface = $vip['interface'];
5878
			}
5879
			if ($int != $iface) {
5880
				continue;
5881
			}
5882
			if ($action == "update") {
5883
				$updatevips = true;
5884
			} else {
5885
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
5886
				    substr($vip['interface'], 0, 4) == "_vip") {
5887
					$result[] = $vip;
5888
				}
5889
			}
5890
		}
5891
		if ($updatevips === true) {
5892
			interfaces_vips_configure($int);
5893
		}
5894
		return $result;
5895
	}
5896

    
5897
	return NULL;
5898
}
5899

    
5900
/****f* interfaces/link_interface_to_bridge
5901
 * NAME
5902
 *   link_interface_to_bridge - Finds out a bridge group for an interface
5903
 * INPUTS
5904
 *   $ip
5905
 * RESULT
5906
 *   bridge[0-99]
5907
 ******/
5908
function link_interface_to_bridge($int) {
5909
	global $config;
5910

    
5911
	if (is_array($config['bridges']['bridged'])) {
5912
		foreach ($config['bridges']['bridged'] as $bridge) {
5913
			if (in_array($int, explode(',', $bridge['members']))) {
5914
				return "{$bridge['bridgeif']}";
5915
			}
5916
		}
5917
	}
5918
}
5919

    
5920
function link_interface_to_group($int) {
5921
	global $config;
5922

    
5923
	$result = array();
5924

    
5925
	if (is_array($config['ifgroups']['ifgroupentry'])) {
5926
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
5927
			if (in_array($int, explode(" ", $group['members']))) {
5928
				$result[$group['ifname']] = $int;
5929
			}
5930
		}
5931
	}
5932

    
5933
	return $result;
5934
}
5935

    
5936
function link_interface_to_gre($interface) {
5937
	global $config;
5938

    
5939
	$result = array();
5940

    
5941
	if (is_array($config['gres']['gre'])) {
5942
		foreach ($config['gres']['gre'] as $gre) {
5943
			if ($gre['if'] == $interface) {
5944
				$result[] = $gre;
5945
			}
5946
		}
5947
	}
5948

    
5949
	return $result;
5950
}
5951

    
5952
function link_interface_to_gif($interface) {
5953
	global $config;
5954

    
5955
	$result = array();
5956

    
5957
	if (is_array($config['gifs']['gif'])) {
5958
		foreach ($config['gifs']['gif'] as $gif) {
5959
			if ($gif['if'] == $interface) {
5960
				$result[] = $gif;
5961
			}
5962
		}
5963
	}
5964

    
5965
	return $result;
5966
}
5967

    
5968
/*
5969
 * find_interface_ip($interface): return the interface ip (first found)
5970
 */
5971
function find_interface_ip($interface, $flush = false) {
5972
	global $interface_ip_arr_cache;
5973
	global $interface_sn_arr_cache;
5974

    
5975
	$interface = str_replace("\n", "", $interface);
5976

    
5977
	if (!does_interface_exist($interface)) {
5978
		return;
5979
	}
5980

    
5981
	/* Setup IP cache */
5982
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
5983
		if (file_exists("/var/db/${interface}_ip")) {
5984
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
5985
			$ifaddrs = pfSense_getall_interface_addresses($interface);
5986
			foreach ($ifaddrs as $ifaddr) {
5987
				list($ip, $mask) = explode("/", $ifaddr);
5988
				if ($ip == $ifip) {
5989
					$interface_ip_arr_cache[$interface] = $ip;
5990
					$interface_sn_arr_cache[$interface] = $mask;
5991
					break;
5992
				}
5993
			}
5994
		}
5995
		if (!isset($interface_ip_arr_cache[$interface])) {
5996
			$ifinfo = pfSense_get_interface_addresses($interface);
5997
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
5998
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
5999
		}
6000
	}
6001

    
6002
	return $interface_ip_arr_cache[$interface];
6003
}
6004

    
6005
/*
6006
 * find_interface_ipv6($interface): return the interface ip (first found)
6007
 */
6008
function find_interface_ipv6($interface, $flush = false) {
6009
	global $interface_ipv6_arr_cache;
6010
	global $interface_snv6_arr_cache;
6011
	global $config;
6012

    
6013
	$interface = trim($interface);
6014
	$interface = get_real_interface($interface);
6015

    
6016
	if (!does_interface_exist($interface)) {
6017
		return;
6018
	}
6019

    
6020
	/* Setup IP cache */
6021
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6022
		$ifinfo = pfSense_get_interface_addresses($interface);
6023
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6024
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6025
	}
6026

    
6027
	return $interface_ipv6_arr_cache[$interface];
6028
}
6029

    
6030
/*
6031
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6032
 */
6033
function find_interface_ipv6_ll($interface, $flush = false) {
6034
	global $interface_llv6_arr_cache;
6035
	global $config;
6036

    
6037
	$interface = str_replace("\n", "", $interface);
6038

    
6039
	if (!does_interface_exist($interface)) {
6040
		return;
6041
	}
6042

    
6043
	/* Setup IP cache */
6044
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6045
		$ifinfo = pfSense_getall_interface_addresses($interface);
6046
		foreach ($ifinfo as $line) {
6047
			if (strstr($line, ":")) {
6048
				$parts = explode("/", $line);
6049
				if (is_linklocal($parts[0])) {
6050
					$ifinfo['linklocal'] = $parts[0];
6051
				}
6052
			}
6053
		}
6054
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6055
	}
6056
	return $interface_llv6_arr_cache[$interface];
6057
}
6058

    
6059
function find_interface_subnet($interface, $flush = false) {
6060
	global $interface_sn_arr_cache;
6061
	global $interface_ip_arr_cache;
6062

    
6063
	$interface = str_replace("\n", "", $interface);
6064
	if (does_interface_exist($interface) == false) {
6065
		return;
6066
	}
6067

    
6068
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6069
		$ifinfo = pfSense_get_interface_addresses($interface);
6070
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6071
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6072
	}
6073

    
6074
	return $interface_sn_arr_cache[$interface];
6075
}
6076

    
6077
function find_interface_subnetv6($interface, $flush = false) {
6078
	global $interface_snv6_arr_cache;
6079
	global $interface_ipv6_arr_cache;
6080

    
6081
	$interface = str_replace("\n", "", $interface);
6082
	if (does_interface_exist($interface) == false) {
6083
		return;
6084
	}
6085

    
6086
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6087
		$ifinfo = pfSense_get_interface_addresses($interface);
6088
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6089
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6090
	}
6091

    
6092
	return $interface_snv6_arr_cache[$interface];
6093
}
6094

    
6095
function ip_in_interface_alias_subnet($interface, $ipalias) {
6096
	global $config;
6097

    
6098
	if (empty($interface) || !is_ipaddr($ipalias)) {
6099
		return false;
6100
	}
6101
	if (is_array($config['virtualip']['vip'])) {
6102
		foreach ($config['virtualip']['vip'] as $vip) {
6103
			switch ($vip['mode']) {
6104
				case "ipalias":
6105
					if ($vip['interface'] <> $interface) {
6106
						break;
6107
					}
6108
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6109
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6110
						return true;
6111
					}
6112
					break;
6113
			}
6114
		}
6115
	}
6116

    
6117
	return false;
6118
}
6119

    
6120
function get_possible_listen_ips($include_ipv6_link_local=false) {
6121

    
6122
	$interfaces = get_configured_interface_with_descr();
6123
	foreach ($interfaces as $iface => $ifacename) {
6124
		if ($include_ipv6_link_local) {
6125
			/* This is to avoid going though added ll below */
6126
			if (substr($iface, 0, 5) == '_lloc') {
6127
				continue;
6128
			}
6129
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6130
			if (!empty($llip)) {
6131
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6132
			}
6133
		}
6134
	}
6135
	$viplist = get_configured_vip_list();
6136
	foreach ($viplist as $vip => $address) {
6137
		$interfaces[$vip] = $address;
6138
		if (get_vip_descr($address)) {
6139
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6140
		}
6141
	}
6142

    
6143
	$interfaces['lo0'] = 'Localhost';
6144

    
6145
	return $interfaces;
6146
}
6147

    
6148
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6149
	global $config;
6150

    
6151
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6152
	foreach (array('server', 'client') as $mode) {
6153
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6154
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6155
				if (!isset($setting['disable'])) {
6156
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6157
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6158
				}
6159
			}
6160
		}
6161
	}
6162
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6163
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6164
			if ($ph1ent['disabled']) {
6165
				continue;
6166
			}
6167
			if (ipsec_vti($ph1ent)) {
6168
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6169
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6170
			}
6171
		}
6172
	}
6173
	return $sourceips;
6174
}
6175

    
6176
function get_interface_ip($interface = "wan") {
6177
	global $config;
6178

    
6179
	if (substr($interface, 0, 4) == '_vip') {
6180
		return get_configured_vip_ipv4($interface);
6181
	} else if (substr($interface, 0, 5) == '_lloc') {
6182
		/* No link-local address for v4. */
6183
		return null;
6184
	}
6185

    
6186
	$realif = get_failover_interface($interface, 'inet');
6187
	if (!$realif) {
6188
		return null;
6189
	}
6190

    
6191
	if (substr($realif, 0, 4) == '_vip') {
6192
		return get_configured_vip_ipv4($realif);
6193
	} else if (substr($realif, 0, 5) == '_lloc') {
6194
		/* No link-local address for v4. */
6195
		return null;
6196
	}
6197

    
6198
	if (is_array($config['interfaces'][$interface]) &&
6199
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6200
		return ($config['interfaces'][$interface]['ipaddr']);
6201
	}
6202

    
6203
	/*
6204
	 * Beaware that find_interface_ip() is our last option, it will
6205
	 * return the first IP it find on interface, not necessarily the
6206
	 * main IP address.
6207
	 */
6208
	$curip = find_interface_ip($realif);
6209
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6210
		return $curip;
6211
	} else {
6212
		return null;
6213
	}
6214
}
6215

    
6216
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6217
	global $config;
6218

    
6219
	if (substr($interface, 0, 4) == '_vip') {
6220
		return get_configured_vip_ipv6($interface);
6221
	} else if (substr($interface, 0, 5) == '_lloc') {
6222
		return get_interface_linklocal($interface);
6223
	}
6224

    
6225
	$realif = get_failover_interface($interface, 'inet6');
6226
	if (!$realif) {
6227
		return null;
6228
	}
6229

    
6230
	if (substr($realif, 0, 4) == '_vip') {
6231
		return get_configured_vip_ipv6($realif);
6232
	} else if (substr($realif, 0, 5) == '_lloc') {
6233
		return get_interface_linklocal($realif);
6234
	}
6235

    
6236
	if (is_array($config['interfaces'][$interface])) {
6237
		switch ($config['interfaces'][$interface]['ipaddr']) {
6238
			case 'pppoe':
6239
			case 'l2tp':
6240
			case 'pptp':
6241
			case 'ppp':
6242
				if ($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') {
6243
					$realif = get_real_interface($interface, 'inet6', false);
6244
				}
6245
				break;
6246
		}
6247
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6248
			return ($config['interfaces'][$interface]['ipaddrv6']);
6249
		}
6250
	}
6251

    
6252
	/*
6253
	 * Beaware that find_interface_ip() is our last option, it will
6254
	 * return the first IP it find on interface, not necessarily the
6255
	 * main IP address.
6256
	 */
6257
	$curip = find_interface_ipv6($realif, $flush);
6258
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6259
		return $curip;
6260
	} else {
6261
		/*
6262
		 * NOTE: On the case when only the prefix is requested,
6263
		 * the communication on WAN will be done over link-local.
6264
		 */
6265
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6266
			$curip = find_interface_ipv6_ll($realif, $flush);
6267
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6268
				return $curip;
6269
			}
6270
		}
6271
	}
6272
	return null;
6273
}
6274

    
6275
function get_interface_linklocal($interface = "wan") {
6276

    
6277
	$realif = get_failover_interface($interface, 'inet6');
6278
	if (!$realif) {
6279
		return null;
6280
	}
6281

    
6282
	if (substr($interface, 0, 4) == '_vip') {
6283
		$realif = get_real_interface($interface);
6284
	} else if (substr($interface, 0, 5) == '_lloc') {
6285
		$realif = get_real_interface(substr($interface, 5));
6286
	}
6287

    
6288
	$curip = find_interface_ipv6_ll($realif);
6289
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6290
		return $curip;
6291
	} else {
6292
		return null;
6293
	}
6294
}
6295

    
6296
function get_interface_subnet($interface = "wan") {
6297
	global $config;
6298

    
6299
	if (substr($interface, 0, 4) == '_vip') {
6300
		return (get_configured_vip_subnetv4($interface));
6301
	}
6302

    
6303
	if (is_array($config['interfaces'][$interface]) &&
6304
		!empty($config['interfaces'][$interface]['subnet'])) {
6305
		return ($config['interfaces'][$interface]['subnet']);
6306
	}
6307

    
6308
	$realif = get_real_interface($interface);
6309
	if (!$realif) {
6310
		return (NULL);
6311
	}
6312

    
6313
	$cursn = find_interface_subnet($realif);
6314
	if (!empty($cursn)) {
6315
		return ($cursn);
6316
	}
6317

    
6318
	return (NULL);
6319
}
6320

    
6321
function get_interface_subnetv6($interface = "wan") {
6322
	global $config;
6323

    
6324
	if (substr($interface, 0, 4) == '_vip') {
6325
		return (get_configured_vip_subnetv6($interface));
6326
	} else if (substr($interface, 0, 5) == '_lloc') {
6327
		$interface = substr($interface, 5);
6328
	}
6329

    
6330
	if (is_array($config['interfaces'][$interface]) &&
6331
		!empty($config['interfaces'][$interface]['subnetv6'])) {
6332
		return ($config['interfaces'][$interface]['subnetv6']);
6333
	}
6334

    
6335
	$realif = get_real_interface($interface, 'inet6');
6336
	if (!$realif) {
6337
		return (NULL);
6338
	}
6339

    
6340
	$cursn = find_interface_subnetv6($realif);
6341
	if (!empty($cursn)) {
6342
		return ($cursn);
6343
	}
6344

    
6345
	return (NULL);
6346
}
6347

    
6348
/* return outside interfaces with a gateway */
6349
function get_interfaces_with_gateway() {
6350
	global $config;
6351

    
6352
	$ints = array();
6353

    
6354
	/* loop interfaces, check config for outbound */
6355
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6356
		switch ($ifname['ipaddr']) {
6357
			case "dhcp":
6358
			case "pppoe":
6359
			case "pptp":
6360
			case "l2tp":
6361
			case "ppp":
6362
				$ints[$ifdescr] = $ifdescr;
6363
				break;
6364
			default:
6365
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6366
				    !empty($ifname['gateway'])) {
6367
					$ints[$ifdescr] = $ifdescr;
6368
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6369
				    !empty($ifname['gateway'])) {
6370
					$ints[$ifdescr] = $ifdescr;
6371
				}
6372

    
6373
				break;
6374
		}
6375
	}
6376
	return $ints;
6377
}
6378

    
6379
/* return true if interface has a gateway */
6380
function interface_has_gateway($friendly) {
6381
	global $config;
6382

    
6383
	if (!empty($config['interfaces'][$friendly])) {
6384
		$ifname = &$config['interfaces'][$friendly];
6385
		switch ($ifname['ipaddr']) {
6386
			case "dhcp":
6387
			case "pppoe":
6388
			case "pptp":
6389
			case "l2tp":
6390
			case "ppp":
6391
				return true;
6392
			break;
6393
			default:
6394
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6395
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6396
					return true;
6397
				}
6398
				$tunnelif = substr($ifname['if'], 0, 3);
6399
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6400
					if (find_interface_ip($ifname['if'])) {
6401
						return true;
6402
					}
6403
				}
6404
				if (!empty($ifname['gateway'])) {
6405
					return true;
6406
				}
6407
			break;
6408
		}
6409
	}
6410

    
6411
	return false;
6412
}
6413

    
6414
/* return true if interface has a gateway */
6415
function interface_has_gatewayv6($friendly) {
6416
	global $config;
6417

    
6418
	if (!empty($config['interfaces'][$friendly])) {
6419
		$ifname = &$config['interfaces'][$friendly];
6420
		switch ($ifname['ipaddrv6']) {
6421
			case "slaac":
6422
			case "dhcp6":
6423
			case "6to4":
6424
			case "6rd":
6425
				return true;
6426
				break;
6427
			default:
6428
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6429
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6430
					return true;
6431
				}
6432
				$tunnelif = substr($ifname['if'], 0, 3);
6433
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6434
					if (find_interface_ipv6($ifname['if'])) {
6435
						return true;
6436
					}
6437
				}
6438
				if (!empty($ifname['gatewayv6'])) {
6439
					return true;
6440
				}
6441
				break;
6442
		}
6443
	}
6444

    
6445
	return false;
6446
}
6447

    
6448
/****f* interfaces/is_altq_capable
6449
 * NAME
6450
 *   is_altq_capable - Test if interface is capable of using ALTQ
6451
 * INPUTS
6452
 *   $int            - string containing interface name
6453
 * RESULT
6454
 *   boolean         - true or false
6455
 ******/
6456

    
6457
function is_altq_capable($int) {
6458
	/* Per:
6459
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+11.0-RELEASE&arch=default&format=html
6460
	 * Only the following drivers have ALTQ support
6461
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
6462
	 */
6463
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
6464
			"bfe", "bge", "bridge", "cas", "cpsw", "cxl", "dc", "de",
6465
			"ed", "em", "ep", "epair", "et", "fxp", "gem", "hme", "hn",
6466
			"igb", "jme", "l2tp", "le", "lem", "msk", "mxge", "my",
6467
			"ndis", "nfe", "ng", "nge", "npe", "nve", "ovpnc", "ovpns",
6468
			"ppp", "pppoe", "pptp", "re", "rl", "sf", "sge", "sis", "sk",
6469
			"ste", "stge", "ti", "tun", "txp", "udav", "ural", "vge",
6470
			"vlan", "vmx", "vr", "vte", "vtnet", "xl");
6471

    
6472
	$int_family = remove_ifindex($int);
6473

    
6474
	if (in_array($int_family, $capable)) {
6475
		return true;
6476
	} else if (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6477
		return true;
6478
	} else if (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6479
		return true;
6480
	} else if (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6481
		return true;
6482
	} else {
6483
		return false;
6484
	}
6485
}
6486

    
6487
/****f* interfaces/is_interface_wireless
6488
 * NAME
6489
 *   is_interface_wireless - Returns if an interface is wireless
6490
 * RESULT
6491
 *   $tmp       - Returns if an interface is wireless
6492
 ******/
6493
function is_interface_wireless($interface) {
6494
	global $config, $g;
6495

    
6496
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6497
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6498
		if (preg_match($g['wireless_regex'], $interface)) {
6499
			if (isset($config['interfaces'][$friendly])) {
6500
				$config['interfaces'][$friendly]['wireless'] = array();
6501
			}
6502
			return true;
6503
		}
6504
		return false;
6505
	} else {
6506
		return true;
6507
	}
6508
}
6509

    
6510
function get_wireless_modes($interface) {
6511
	/* return wireless modes and channels */
6512
	$wireless_modes = array();
6513

    
6514
	$cloned_interface = get_real_interface($interface);
6515

    
6516
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6517
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6518
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6519
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6520

    
6521
		$interface_channels = "";
6522
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6523
		$interface_channel_count = count($interface_channels);
6524

    
6525
		$c = 0;
6526
		while ($c < $interface_channel_count) {
6527
			$channel_line = explode(",", $interface_channels["$c"]);
6528
			$wireless_mode = trim($channel_line[0]);
6529
			$wireless_channel = trim($channel_line[1]);
6530
			if (trim($wireless_mode) != "") {
6531
				/* if we only have 11g also set 11b channels */
6532
				if ($wireless_mode == "11g") {
6533
					if (!isset($wireless_modes["11b"])) {
6534
						$wireless_modes["11b"] = array();
6535
					}
6536
				} else if ($wireless_mode == "11g ht") {
6537
					if (!isset($wireless_modes["11b"])) {
6538
						$wireless_modes["11b"] = array();
6539
					}
6540
					if (!isset($wireless_modes["11g"])) {
6541
						$wireless_modes["11g"] = array();
6542
					}
6543
					$wireless_mode = "11ng";
6544
				} else if ($wireless_mode == "11a ht") {
6545
					if (!isset($wireless_modes["11a"])) {
6546
						$wireless_modes["11a"] = array();
6547
					}
6548
					$wireless_mode = "11na";
6549
				}
6550
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6551
			}
6552
			$c++;
6553
		}
6554
	}
6555
	return($wireless_modes);
6556
}
6557

    
6558
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6559
function get_wireless_channel_info($interface) {
6560
	$wireless_channels = array();
6561

    
6562
	$cloned_interface = get_real_interface($interface);
6563

    
6564
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6565
		$chan_list = "/sbin/ifconfig {$cloned_interface} list txpower";
6566
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
6567
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6568

    
6569
		$interface_channels = "";
6570
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
6571

    
6572
		foreach ($interface_channels as $channel_line) {
6573
			$channel_line = explode(",", $channel_line);
6574
			if (!isset($wireless_channels[$channel_line[0]])) {
6575
				$wireless_channels[$channel_line[0]] = $channel_line;
6576
			}
6577
		}
6578
	}
6579
	return($wireless_channels);
6580
}
6581

    
6582
function set_interface_mtu($interface, $mtu) {
6583

    
6584
	/* LAGG interface must be destroyed and re-created to change MTU */
6585
	if (substr($interface, 0, 4) == 'lagg') {
6586
		if (isset($config['laggs']['lagg']) &&
6587
		    is_array($config['laggs']['lagg'])) {
6588
			foreach ($config['laggs']['lagg'] as $lagg) {
6589
				if ($lagg['laggif'] == $interface) {
6590
					interface_lagg_configure($lagg);
6591
					break;
6592
				}
6593
			}
6594
		}
6595
	} else {
6596
		pfSense_interface_mtu($interface, $mtu);
6597
	}
6598
}
6599

    
6600
/****f* interfaces/get_interface_mtu
6601
 * NAME
6602
 *   get_interface_mtu - Return the mtu of an interface
6603
 * RESULT
6604
 *   $tmp       - Returns the mtu of an interface
6605
 ******/
6606
function get_interface_mtu($interface) {
6607
	$mtu = pfSense_interface_getmtu($interface);
6608
	return $mtu['mtu'];
6609
}
6610

    
6611
function get_interface_mac($interface) {
6612
	$macinfo = pfSense_get_interface_addresses($interface);
6613
	return $macinfo["macaddr"];
6614
}
6615

    
6616
function get_interface_vendor_mac($interface) {
6617
	$macinfo = pfSense_get_interface_addresses($interface);
6618
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] != "00:00:00:00:00:00") {
6619
		return ($macinfo["hwaddr"]);
6620
	}
6621
	return (NULL);
6622
}
6623

    
6624
/****f* pfsense-utils/generate_random_mac_address
6625
 * NAME
6626
 *   generate_random_mac - generates a random mac address
6627
 * INPUTS
6628
 *   none
6629
 * RESULT
6630
 *   $mac - a random mac address
6631
 ******/
6632
function generate_random_mac_address() {
6633
	$mac = "02";
6634
	for ($x = 0; $x < 5; $x++) {
6635
		$mac .= ":" . dechex(rand(16, 255));
6636
	}
6637
	return $mac;
6638
}
6639

    
6640
/****f* interfaces/is_jumbo_capable
6641
 * NAME
6642
 *   is_jumbo_capable - Test if interface is jumbo frame capable.  Useful for determining VLAN capability.
6643
 * INPUTS
6644
 *   $int             - string containing interface name
6645
 * RESULT
6646
 *   boolean          - true or false
6647
 ******/
6648
function is_jumbo_capable($iface) {
6649
	$iface = trim($iface);
6650
	$capable = pfSense_get_interface_addresses($iface);
6651

    
6652
	if (isset($capable['caps']['vlanmtu'])) {
6653
		return true;
6654
	}
6655

    
6656
	// hack for some lagg modes missing vlanmtu, but work fine w/VLANs
6657
	if (substr($iface, 0, 4) == "lagg") {
6658
		return true;
6659
	}
6660

    
6661
	return false;
6662
}
6663

    
6664
function interface_setup_pppoe_reset_file($pppif, $iface="") {
6665
	global $g;
6666

    
6667
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
6668

    
6669
	if (!empty($iface) && !empty($pppif)) {
6670
		$cron_cmd = <<<EOD
6671
#!/bin/sh
6672
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
6673
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
6674

    
6675
EOD;
6676

    
6677
		@file_put_contents($cron_file, $cron_cmd);
6678
		chmod($cron_file, 0755);
6679
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
6680
	} else {
6681
		unlink_if_exists($cron_file);
6682
	}
6683
}
6684

    
6685
function get_interface_default_mtu($type = "ethernet") {
6686
	switch ($type) {
6687
		case "gre":
6688
			return 1476;
6689
			break;
6690
		case "gif":
6691
			return 1280;
6692
			break;
6693
		case "tun":
6694
		case "vlan":
6695
		case "tap":
6696
		case "ethernet":
6697
		default:
6698
			return 1500;
6699
			break;
6700
	}
6701

    
6702
	/* Never reached */
6703
	return 1500;
6704
}
6705

    
6706
function get_vip_descr($ipaddress) {
6707
	global $config;
6708

    
6709
	foreach ($config['virtualip']['vip'] as $vip) {
6710
		if ($vip['subnet'] == $ipaddress) {
6711
			return ($vip['descr']);
6712
		}
6713
	}
6714
	return "";
6715
}
6716

    
6717
function interfaces_staticarp_configure($if) {
6718
	global $config, $g;
6719
	if (isset($config['system']['developerspew'])) {
6720
		$mt = microtime();
6721
		echo "interfaces_staticarp_configure($if) being called $mt\n";
6722
	}
6723

    
6724
	$ifcfg = $config['interfaces'][$if];
6725

    
6726
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
6727
		return 0;
6728
	}
6729

    
6730
	/* Enable staticarp, if enabled */
6731
	if (isset($config['dhcpd'][$if]['staticarp'])) {
6732
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
6733
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6734
		if (is_array($config['dhcpd'][$if]['staticmap'])) {
6735
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6736
				if (!empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6737
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6738
				}
6739
			}
6740
		}
6741
	} else {
6742
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
6743
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
6744
		if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
6745
			foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
6746
				if (isset($arpent['arp_table_static_entry']) && !empty($arpent['ipaddr']) && !empty($arpent['mac'])) {
6747
					mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
6748
				}
6749
			}
6750
		}
6751
	}
6752

    
6753
	return 0;
6754
}
6755

    
6756
function get_failover_interface($interface, $family = "all") {
6757
	global $config;
6758

    
6759
	/* shortcut to get_real_interface if we find it in the config */
6760
	if (is_array($config['interfaces'][$interface])) {
6761
		return get_real_interface($interface, $family);
6762
	}
6763

    
6764
	/* compare against gateway groups */
6765
	$a_groups = return_gateway_groups_array(true);
6766
	if (is_array($a_groups[$interface])) {
6767
		/* we found a gateway group, fetch the interface or vip */
6768
		if (!empty($a_groups[$interface][0]['vip'])) {
6769
			return $a_groups[$interface][0]['vip'];
6770
		} else {
6771
			return $a_groups[$interface][0]['int'];
6772
		}
6773
	}
6774
	/* fall through to get_real_interface */
6775
	/* XXX: Really needed? */
6776
	return get_real_interface($interface, $family);
6777
}
6778

    
6779
/****f* interfaces/interface_has_dhcp
6780
 * NAME
6781
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
6782
 * INPUTS
6783
 *   interface or gateway group name
6784
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
6785
 * RESULT
6786
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
6787
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
6788
 ******/
6789
function interface_has_dhcp($interface, $family = 4) {
6790
	global $config;
6791

    
6792
	if ($config['interfaces'][$interface]) {
6793
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
6794
			return true;
6795
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
6796
			return true;
6797
		} else {
6798
			return false;
6799
		}
6800
	}
6801

    
6802
	if (!is_array($config['gateways']['gateway_group'])) {
6803
		return false;
6804
	}
6805

    
6806
	if ($family == 6) {
6807
		$dhcp_string = "_DHCP6";
6808
	} else {
6809
		$dhcp_string = "_DHCP";
6810
	}
6811

    
6812
	foreach ($config['gateways']['gateway_group'] as $group) {
6813
		if (($group['name'] != $interface) || !is_array($group['item'])) {
6814
			continue;
6815
		}
6816
		foreach ($group['item'] as $item) {
6817
			$item_data = explode("|", $item);
6818
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
6819
				return true;
6820
			}
6821
		}
6822
	}
6823

    
6824
	return false;
6825
}
6826

    
6827
function remove_ifindex($ifname) {
6828
	return preg_replace("/[0-9]+$/", "", $ifname);
6829
}
6830

    
6831
function get_configured_vip_list_with_descr($family = 'all', $type = VIP_ALL) {
6832
	$interfaces = array();	// In case there are no VIPs defined
6833

    
6834
	$viplist = get_configured_vip_list($family, $type);
6835
	foreach ($viplist as $vip => $address) {
6836
		$interfaces[$vip] = $address;
6837
		if ($type = VIP_CARP) {
6838
			$vip = get_configured_vip($vipid);
6839
			if (isset($vip) && is_array($vip) ) {
6840
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
6841
			}
6842
		}
6843
		if (get_vip_descr($address)) {
6844
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
6845
		}
6846
	}
6847
	return $interfaces;
6848
}
6849

    
6850
function return_gateway_groups_array_with_descr() {
6851
	$interfaces = array();
6852
	$grouplist = return_gateway_groups_array();
6853
	foreach ($grouplist as $name => $group) {
6854
		if ($group[0]['vip'] != "") {
6855
			$vipif = $group[0]['vip'];
6856
		} else {
6857
			$vipif = $group[0]['int'];
6858
		}
6859

    
6860
		$interfaces[$name] = "GW Group {$name}";
6861
	}
6862
	return $interfaces;
6863
}
6864

    
6865
function get_serial_ports() {
6866
	$linklist = array();
6867
	if (!is_dir("/var/spool/lock")) {
6868
		mwexec("/bin/mkdir -p /var/spool/lock");
6869
	}
6870
	$serialports = glob("/dev/cua[a-zA-Z][0-9]{,.[0-9],.[0-9][0-9],[0-9],[0-9].[0-9],[0-9].[0-9][0-9]}", GLOB_BRACE);
6871
	foreach ($serialports as $port) {
6872
		$linklist[$port] = trim($port);
6873
	}
6874
	return $linklist;
6875
}
6876

    
6877
function get_interface_ports() {
6878
	global $config;
6879
	$linklist = array();
6880
	$portlist = get_interface_list();
6881
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
6882
		foreach ($config['vlans']['vlan'] as $vlan) {
6883
			$portlist[$vlan['vlanif']] = $vlan;
6884
		}
6885
	}
6886

    
6887
	foreach ($portlist as $ifn => $ifinfo) {
6888
		$string = "";
6889
		if (is_array($ifinfo)) {
6890
			$string .= $ifn;
6891
			if ($ifinfo['mac']) {
6892
				$string .= " ({$ifinfo['mac']})";
6893
			}
6894
			if ($ifinfo['friendly']) {
6895
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
6896
			} elseif ($ifinfo['descr']) {
6897
				$string .= " - {$ifinfo['descr']}";
6898
			}
6899
		} else {
6900
			$string .= $ifinfo;
6901
		}
6902

    
6903
		$linklist[$ifn] = $string;
6904
	}
6905
	return $linklist;
6906
}
6907

    
6908
function build_ppps_link_list() {
6909
	global $pconfig;
6910

    
6911
	$linklist = array('list' => array(), 'selected' => array());
6912

    
6913
	if ($pconfig['type'] == 'ppp') {
6914
		$linklist['list'] = get_serial_ports();
6915
	} else {
6916
		$iflist = get_interface_ports();
6917

    
6918
		$viplist = get_configured_vip_list_with_descr('all', VIP_CARP);
6919

    
6920
		$linklist['list'] = array_merge($iflist, $viplist);
6921

    
6922
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
6923
		$lagglist = get_lagg_interface_list();
6924
		foreach ($lagglist as $laggif => $lagg) {
6925
			/* LAGG members cannot be assigned */
6926
			$laggmembers = explode(',', $lagg['members']);
6927
			foreach ($laggmembers as $lagm) {
6928
				if (isset($linklist['list'][$lagm])) {
6929
					unset($linklist['list'][$lagm]);
6930
				}
6931
			}
6932
		}
6933
	}
6934

    
6935
	$selected_ports = array();
6936
	if (is_array($pconfig['interfaces'])) {
6937
		$selected_ports = $pconfig['interfaces'];
6938
	} elseif (!empty($pconfig['interfaces'])) {
6939
		$selected_ports = explode(',', $pconfig['interfaces']);
6940
	}
6941
	foreach ($selected_ports as $port) {
6942
		if (isset($linklist['list'][$port])) {
6943
			array_push($linklist['selected'], $port);
6944
		}
6945
	}
6946
	return($linklist);
6947
}
6948

    
6949
function create_interface_list() {
6950
	global $config;
6951

    
6952
	$iflist = array();
6953

    
6954
	// add group interfaces
6955
	if (is_array($config['ifgroups']['ifgroupentry'])) {
6956
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
6957
			if (have_ruleint_access($ifgen['ifname'])) {
6958
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
6959
			}
6960
		}
6961
	}
6962

    
6963
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
6964
		if (have_ruleint_access($ifent)) {
6965
			$iflist[$ifent] = $ifdesc;
6966
		}
6967
	}
6968

    
6969
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
6970
		$iflist['l2tp'] = gettext('L2TP VPN');
6971
	}
6972

    
6973
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
6974
		$iflist['pppoe'] = gettext("PPPoE Server");
6975
	}
6976

    
6977
	// add ipsec interfaces
6978
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
6979
		$iflist["enc0"] = gettext("IPsec");
6980
	}
6981

    
6982
	// add openvpn/tun interfaces
6983
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
6984
		$iflist["openvpn"] = gettext("OpenVPN");
6985
	}
6986

    
6987
	return($iflist);
6988
}
6989

    
6990
?>
(23-23/60)