Project

General

Profile

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

    
28
/* include all configuration functions */
29
require_once("config.lib.inc");
30
require_once("globals.inc");
31
require_once("util.inc");
32
require_once("gwlb.inc");
33
require_once("ipsec.inc");
34
require_once("vpn.inc");
35
require_once("Net/IPv6.php");
36

    
37
function interfaces_bring_up($interface) {
38
	if (!$interface) {
39
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
40
		log_error("Backtrace: " . debug_backtrace());
41
		return;
42
	}
43
	pfSense_interface_flags($interface, IFF_UP);
44
}
45

    
46
/*
47
 * Validate comma-separated list of IPv4 addresses
48
 */
49
function validate_ipv4_list($value) {
50
	$value = trim($value);
51

    
52
	if (empty($value)) {
53
		return false;
54
	}
55

    
56
	$list = explode(',', $value);
57

    
58
	foreach ($list as $ip) {
59
		if (!is_ipaddrv4($ip)) {
60
			return false;
61
		}
62
	}
63

    
64
	return true;
65
}
66

    
67
/*
68
 * Return the interface array
69
 */
70
function get_interface_arr($flush = false) {
71
	global $interface_arr_cache;
72

    
73
	/* If the cache doesn't exist, build it */
74
	if (!isset($interface_arr_cache) or $flush) {
75
		$interface_arr_cache = pfSense_interface_listget();
76
	}
77

    
78
	return $interface_arr_cache;
79
}
80

    
81
/*
82
 * does_interface_exist($interface): return true or false if a interface is
83
 * detected.
84
 */
85
function does_interface_exist($interface, $flush = false) {
86
	if (!$interface) {
87
		return false;
88
	}
89

    
90
	$ints = get_interface_arr($flush);
91
	if (in_array($interface, $ints)) {
92
		return true;
93
	} else {
94
		return false;
95
	}
96
}
97

    
98
/*
99
 * does_vip_exist($vip): return true or false if a vip is
100
 * configured.
101
 */
102
function does_vip_exist($vip) {
103
	if (!$vip) {
104
		return false;
105
	}
106

    
107

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

    
123
	$ifacedata = pfSense_getall_interface_addresses($realif);
124

    
125
	if (is_subnetv6("{$vip['subnet']}/{$vip['subnet_bits']}")) {
126
		$comparevip = text_to_compressed_ip6($vip['subnet']);
127
		if (is_linklocal($vip['subnet'])) {
128
			$comparevip .= "%{$realif}";
129
		}
130
		$comparevip .= "/{$vip['subnet_bits']}";
131
	} else {
132
		$comparevip = "{$vip['subnet']}/{$vip['subnet_bits']}";
133
	}
134

    
135
	foreach ($ifacedata as $vipips) {
136
		if ($vipips == $comparevip) {
137
			return true;
138
		}
139
	}
140

    
141
	return false;
142
}
143

    
144
function interfaces_loopback_configure() {
145
	if (platform_booting()) {
146
		echo gettext("Configuring loopback interface...");
147
		mute_kernel_msgs();
148
	}
149
	pfSense_interface_setaddress("lo0", "127.0.0.1");
150
	interfaces_bring_up("lo0");
151
	if (platform_booting()) {
152
		unmute_kernel_msgs();
153
		echo gettext("done.") . "\n";
154
	}
155
	return 0;
156
}
157

    
158
function vlan_valid_tag($tag = NULL) {
159

    
160
	if ($tag == NULL || empty($tag) ||
161
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
162
		return (false);
163
	}
164
	return (true);
165
}
166

    
167
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
168
	if ($qinq == NULL || $inqtag == NULL ||
169
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
170
		return (false);
171
	}
172

    
173
        $iflist = get_configured_interface_list(true);
174
        foreach ($iflist as $if) {
175
                if (config_get_path("interfaces/{$if}/if") == qinq_interface($qinq, $inqtag)) {
176
                        return (true);
177
                }
178
        }
179

    
180
        return (false);
181
}
182

    
183
function qinq_interface($qinq = NULL, $inqtag = NULL) {
184

    
185
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
186
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
187
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
188
		return (NULL);
189
	}
190
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
191
}
192

    
193
function interface_is_qinq($if = NULL) {
194
	if (!$if) {
195
		return (NULL);
196
	}
197

    
198
	/* Check basic format. */
199
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
200
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
201
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
202
		return (NULL);
203
	}
204

    
205
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
206
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
207
			continue;
208
		}
209
		if (empty($qinq['members'])) {
210
			continue;
211
		}
212
		foreach (explode(" ", $qinq['members']) as $tag) {
213
			if ($if == qinq_interface($qinq, $tag)) {
214
				return ($qinq);
215
			}
216
		}
217
	}
218

    
219
	return (NULL);
220
}
221

    
222
function vlan_inuse($vlan) {
223
	if ($vlan == NULL || !is_array($vlan)) {
224
		return (false);
225
	}
226

    
227
	$iflist = get_configured_interface_list(true);
228
	foreach ($iflist as $if) {
229
		if (config_get_path("interfaces/{$if}/if") == $vlan['vlanif']) {
230
			return (true);
231
		}
232
	}
233

    
234
	return (false);
235
}
236

    
237
function interface_is_vlan($if = NULL) {
238
	if ($if == NULL || empty($if) || is_array($if)) {
239
		return (NULL);
240
	}
241

    
242
	/* Check basic format. */
243
	$items = explode(".", $if, 2);
244
	$vlanif = array_shift($items);
245
	$vlantag = array_shift($items);
246
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
247
		return (NULL);
248
	}
249

    
250
	/* Find the VLAN interface. */
251
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
252
		if ($if == $vlan['vlanif']) {
253
			return ($vlan);
254
		}
255
	}
256

    
257
	/* Check for the first level tag in QinQ interfaces. */
258
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
259
		if ($if == $qinq['vlanif']) {
260
			return ($qinq);
261
		}
262
	}
263

    
264
	return (NULL);
265
}
266

    
267
function vlan_interface($vlan = NULL) {
268
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
269
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
270
		return (NULL);
271
	}
272
	return ("{$vlan['if']}.{$vlan['tag']}");
273
}
274

    
275
function interface_set_macaddr($interface, $mac_addr) {
276
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
277
		return;
278
	}
279

    
280
	$current_mac = get_interface_mac($interface);
281

    
282
	/*
283
	 * Don't try to reapply the MAC if it's already applied.
284
	 * When ifconfig link is used, it cycles the interface down/up, which
285
	 * triggers the interface config again, which attempts to apply the
286
	 * MAC again, which cycles the link again...
287
	 */
288
	if ($mac_addr != $current_mac) {
289
		mwexec("/sbin/ifconfig " . escapeshellarg($interface) .
290
		    " link " . escapeshellarg($mac_addr));
291
	}
292
}
293

    
294
function interface_is_parent($if, $parent_check) {
295

    
296
	$parent_array = get_parent_interface($if);
297
	if (count($parent_array) > 1) {
298
		$parent = $parent_array;
299
	} else {
300
		$parent = $parent_array[0];
301
	}
302
	if (is_array($parent)) {
303
		foreach ($parent as $parentif) {
304
			if (strcasecmp($parent_check, $parentif) == 0) {
305
				return (TRUE);
306
			}
307
		}
308
	} else {
309
		$realif = get_real_interface($parent);
310
		if (strcasecmp($parent_check, $realif) == 0) {
311
			return (TRUE);
312
		}
313
	}
314
	return (FALSE);
315
}
316

    
317
function interface_has_clones($if) {
318
	/* Check LAGGs. */
319
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
320
		if (interface_is_parent($lagg['laggif'], $if)) {
321
			return (TRUE);
322
		}
323
	}
324
	/* Check VLANs. */
325
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
326
		if (interface_is_parent($vlan['if'], $if)) {
327
			return (TRUE);
328
		}
329
	}
330
	/* Check bridges. */
331
	foreach (config_get_path('bridges/bridged', []) as $bridge) {
332
		$members = explode(',', $bridge['members']);
333
		foreach ($members as $member) {
334
			if (interface_is_parent($member, $if)) {
335
				return (TRUE);
336
			}
337
		}
338
	}
339

    
340
	return (FALSE);
341
}
342

    
343
function interfaces_vlan_configure($parentif = "") {
344
	$dhcp6c_list = array();
345

    
346
	$vlans = config_get_path('vlans/vlan');
347
	if (is_array($vlans) && count($vlans)) {
348
		if (platform_booting()) {
349
			echo gettext("Configuring VLAN interfaces...");
350
		}
351
		foreach ($vlans as $vlan) {
352
			if (empty($vlan['vlanif'])) {
353
				$vlan['vlanif'] = vlan_interface($vlan);
354
			}
355
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
356
				continue;
357
			}
358
			/* configure dhcp6 enabled VLAN interfaces later
359
			 * see https://redmine.pfsense.org/issues/3965 */
360
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
361
			if (config_get_path("interfaces/{$if}/ipaddrv6", "") == "dhcp6") {
362
				$dhcp6c_list[$if] = $vlan;
363
				continue;
364
			}
365

    
366
			/* XXX: Maybe we should report any errors?! */
367
			interface_vlan_configure($vlan, false);
368
		}
369
		foreach ($dhcp6c_list as $if => $vlan) {
370
			interface_vlan_configure($vlan, false);
371
		}
372
		/* Invalidate cache */
373
		get_interface_arr(true);
374
		if (platform_booting()) {
375
			echo gettext("done.") . "\n";
376
		}
377
	}
378
}
379

    
380
function interface_vlan_configure(&$vlan, $flush = true) {
381
	if (!is_array($vlan)) {
382
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
383
		return(NULL);
384
	}
385
	$if = $vlan['if'];
386
	if (empty($if)) {
387
		log_error(gettext("interface_vlan_configure called with if undefined."));
388
		return(NULL);
389
	}
390

    
391
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
392
	if ($vlanif == NULL) {
393
		log_error(gettext("vlan_interface called with if undefined var."));
394
		return(NULL);
395
	}
396
	$tag = $vlan['tag'];
397
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
398

    
399
	/* make sure the parent interface is up */
400
	interfaces_bring_up($if);
401
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
402
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
403

    
404
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
405
		pfSense_interface_destroy($vlanif);
406
	}
407

    
408
	$tmpvlanif = pfSense_interface_create2("vlan");
409
	pfSense_interface_rename($tmpvlanif, $vlanif);
410
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
411

    
412
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
413

    
414
	interfaces_bring_up($vlanif);
415

    
416
	/* invalidate interface cache */
417
	if ($flush) {
418
		get_interface_arr(true);
419
	}
420

    
421
	/* configure interface if assigned */
422
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
423
	if ($assignedif) {
424
		if (config_path_enabled("interfaces/{$assignedif}")) {
425
			interface_configure($assignedif, true);
426
		}
427
	}
428

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

    
432
	if (interface_vlan_mtu_configured($vlanif)) {
433
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
434
	}
435

    
436
	return $vlanif;
437
}
438

    
439
/*
440
 * reconfigure VLAN childs interfaces after MTU changes, see
441
 * https://redmine.pfsense.org/issues/11035
442
 */
443
function interfaces_vlan_configure_mtu($parentif = "") {
444
	init_config_arr(array('ppps', 'ppp'));
445
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
446
		if ($parentif != $vlan['if']) {
447
			continue;
448
		}
449
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
450
		       set_interface_mtu($vlan['vlanif'],
451
			   interface_vlan_mtu_configured($vlan['vlanif']));
452
		}
453
		if (empty(config_get_path('ppps/ppp'))) {
454
			continue;
455
		}
456
		// PPP interfaces must be restarted to adjust MTU changes
457
		foreach (config_get_path('ppps/ppp') as $ppp) {
458
			$ports = explode(',', $ppp['ports']);
459
			foreach ($ports as $port) {
460
				if ($port != $vlan['vlanif']) {
461
					continue;
462
				}
463
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
464
				interface_configure($confif);
465
			}
466
		}
467
	}
468
}
469

    
470
function interface_qinq_configure(&$qinq, $flush = true) {
471
	global $g;
472

    
473
	if (!is_array($qinq)) {
474
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
475
		return;
476
	}
477

    
478
	$qinqif = $qinq['if'];
479
	if (empty($qinqif)) {
480
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
481
		return;
482
	}
483

    
484
	if (!does_interface_exist($qinqif)) {
485
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
486
		return;
487
	}
488

    
489
	$vlanif = interface_vlan_configure($qinq);
490
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
491
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
492
		return;
493
	}
494

    
495
	exec("/sbin/ifconfig {$vlanif} vlanproto 802.1ad > /dev/null 2>&1");
496

    
497
	/* make sure the parent is up */
498
	interfaces_bring_up($qinqif);
499

    
500
	/* invalidate interface cache */
501
	if ($flush) {
502
		get_interface_arr(true);
503
	}
504

    
505
	if (interface_is_vlan($qinqif) == NULL) {
506
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
507
	}
508

    
509
	$macaddr = get_interface_mac($qinqif);
510
	if (!empty($qinq['members'])) {
511
		$members = explode(" ", $qinq['members']);
512
		foreach ($members as $qtag) {
513
			$qinq2 = array();
514
			$qinq2['tag'] = $qtag;
515
			$qinq2['if'] = $vlanif;
516
			interface_qinq2_configure($qinq2, $macaddr);
517
			unset($qinq2);
518
		}
519
	}
520

    
521
	interfaces_bring_up($qinqif);
522
	if (!empty($qinq['members'])) {
523
		$members = explode(" ", $qinq['members']);
524
		foreach ($members as $qtag) {
525
			interfaces_bring_up(qinq_interface($qinq, $qtag));
526
		}
527
	}
528

    
529
	return $vlanif;
530
}
531

    
532
function interfaces_qinq_configure($ovpn=false) {
533
	$qinqentry = config_get_path('qinqs/qinqentry');
534
	if (is_array($qinqentry) && count($qinqentry)) {
535
		if (platform_booting() && $ovpn) {
536
			echo gettext("Configuring OpenVPN QinQ interfaces...");
537
		} elseif (platform_booting()) {
538
			echo gettext("Configuring QinQ interfaces...");
539
		}
540
		foreach ($qinqentry as $qinq) {
541
			if (($ovpn && strstr($qinq['if'], "ovpn")) ||
542
			    (!$ovpn && !strstr($qinq['if'], "ovpn"))) {
543
				interface_qinq_configure($qinq, false);
544
			}
545
		}
546
		/* Invalidate cache */
547
		get_interface_arr(true);
548
		if (platform_booting()) {
549
			echo gettext("done.") . "\n";
550
		}
551
	}
552
}
553

    
554
function interface_qinq2_configure(&$qinq, $macaddr) {
555
	if (!is_array($qinq)) {
556
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
557
		return;
558
	}
559

    
560
	$if = $qinq['if'];
561
	if (empty($if)) {
562
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
563
		return;
564
	}
565
	$tag = $qinq['tag'];
566
	$vlanif = "{$if}.{$tag}";
567
	$ngif = str_replace(".", "_", $if);
568
	if (strlen($vlanif) > IF_NAMESIZE) {
569
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
570
		    $vlanif, IF_NAMESIZE, "\n"));
571
		return;
572
	}
573

    
574
	exec("/sbin/ifconfig vlan create vlandev {$if} vlan {$tag} name {$vlanif}");
575

    
576
	return $vlanif;
577
}
578

    
579
function interfaces_create_wireless_clones() {
580
	$iflist = get_configured_interface_list();
581

    
582
	foreach ($iflist as $if) {
583
		$realif = config_get_path("interfaces/{$if}/if");
584
		if (!is_interface_wireless($realif)) {
585
			continue;
586
		}
587
		interface_wireless_clone(interface_get_wireless_clone($realif),
588
								 config_get_path("interfaces/{$if}"));
589
	}
590

    
591
	$wclone = config_get_path('wireless/clone');
592
	if (is_array($wclone) && count($wclone)) {
593
		if (platform_booting()) {
594
			echo gettext("Creating wireless clone interfaces...");
595
		}
596
		/* Invalidate cache */
597
		get_interface_arr(true);
598
		foreach ($wclone as $clone) {
599
			if (empty($clone['cloneif'])) {
600
				continue;
601
			}
602
			if (does_interface_exist($clone['cloneif'])) {
603
				continue;
604
			}
605
			/* XXX: Maybe we should report any errors?! */
606
			interface_wireless_clone($clone['cloneif'], $clone);
607
		}
608
		if (platform_booting()) {
609
			echo gettext("done.") . "\n";
610
		}
611
	}
612
}
613

    
614
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
615
	$bridged = config_get_path('bridges/bridged');
616
	if (!is_array($bridged) || !count($bridged)) {
617
		return;
618
	}
619

    
620
	$i = 0;
621
	foreach ($bridged as $bridge) {
622
		if (empty($bridge['bridgeif'])) {
623
			$bridge['bridgeif'] = "bridge{$i}";
624
		}
625
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
626
			continue;
627
		}
628
		$ifname = false;
629
		foreach (config_get_path('interfaces', []) as $intname => $intpar) {
630
			if ($intpar['if'] == $bridge['bridgeif']) {
631
				$ifname = $intname;
632
				break;
633
			}
634
		}
635

    
636
		if ($ifname && (config_get_path("interfaces/{$ifname}/ipaddrv6", "") == "track6")) {
637
			if ($checkmember == 1) {
638
				continue;
639
			} else {
640
				$checkmember = 0;
641
			}
642
		} elseif (($checkmember == 2) && !$ifname) {
643
			continue;
644
		}
645

    
646
		/* XXX: Maybe we should report any errors?! */
647
		interface_bridge_configure($bridge, $checkmember, false);
648
		$i++;
649
	}
650

    
651
	/* Invalidate cache */
652
	get_interface_arr(true);
653
}
654

    
655
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
656
	if (!is_array($bridge)) {
657
		return;
658
	}
659

    
660
	if (empty($bridge['members'])) {
661
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
662
		return;
663
	}
664

    
665
	$members = explode(',', $bridge['members']);
666
	if (!count($members)) {
667
		return;
668
	}
669

    
670
	/* Calculate smaller mtu and enforce it */
671
	$smallermtu = 0;
672
	$foundgif = false;
673
	foreach ($members as $member) {
674
		$realif = get_real_interface($member);
675
		$mtu = get_interface_mtu($realif);
676
		if (substr($realif, 0, 3) == "gif") {
677
			$foundgif = true;
678
			if ($checkmember == 1) {
679
				return;
680
			}
681
			if ($mtu <= 1500) {
682
				continue;
683
			}
684
		}
685
		if ($smallermtu == 0 && !empty($mtu)) {
686
			$smallermtu = $mtu;
687
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
688
			$smallermtu = $mtu;
689
		}
690
	}
691
	if ($foundgif == false && $checkmember == 2) {
692
		return;
693
	}
694

    
695
	/* Just in case anything is not working well */
696
	if ($smallermtu == 0) {
697
		$smallermtu = 1500;
698
	}
699

    
700
	if (!empty($bridge['bridgeif'])) {
701
		pfSense_interface_destroy($bridge['bridgeif']);
702
		pfSense_interface_create2($bridge['bridgeif']);
703
		$bridgeif = escapeshellarg($bridge['bridgeif']);
704
	} else {
705
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
706
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
707
		$bridgeif = pfSense_interface_create2("bridge");
708
		$bridge['bridgeif'] = $bridgeif;
709
	}
710

    
711
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
712
	if ($bridgemtu > $smallermtu) {
713
		$smallermtu = $bridgemtu;
714
	}
715

    
716
	$checklist = get_configured_interface_list();
717

    
718
	/* Add interfaces to bridge */
719
	foreach ($members as $member) {
720
		if (empty($checklist[$member])) {
721
			continue;
722
		}
723
		$realif = get_real_interface($member);
724
		if (!$realif) {
725
			log_error(gettext("realif not defined in interfaces bridge - up"));
726
			continue;
727
		}
728
		/* make sure the parent interface is up */
729
		pfSense_interface_mtu($realif, $smallermtu);
730
		interfaces_bring_up($realif);
731
		enable_hardware_offloading($member);
732
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
733
	}
734

    
735
	if (isset($bridge['enablestp'])) {
736
		interface_bridge_configure_stp($bridge);
737
	}
738

    
739
	interface_bridge_configure_advanced($bridge);
740

    
741
	interface_bridge_configure_ip6linklocal($bridge);
742

    
743
	if ($flush) {
744
		get_interface_arr(true);
745
	}
746

    
747
	if ($bridge['bridgeif']) {
748
		interfaces_bring_up($bridge['bridgeif']);
749
	} else {
750
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
751
	}
752
}
753

    
754
function interface_bridge_configure_stp($bridge) {
755
	if (isset($bridge['enablestp'])) {
756
		$bridgeif = escapeshellarg(trim($bridge['bridgeif']));
757
		/* configure spanning tree proto */
758
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
759

    
760
		if (!empty($bridge['stp'])) {
761
			$stpifs = explode(',', $bridge['stp']);
762
			foreach ($stpifs as $stpif) {
763
				$realif = get_real_interface($stpif);
764
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
765
			}
766
		}
767
		if (!empty($bridge['maxage'])) {
768
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
769
		}
770
		if (!empty($bridge['fwdelay'])) {
771
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
772
		}
773
		if (!empty($bridge['hellotime'])) {
774
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
775
		}
776
		if (!empty($bridge['priority'])) {
777
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
778
		}
779
		if (!empty($bridge['holdcnt'])) {
780
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
781
		}
782
		if (!empty($bridge['ifpriority'])) {
783
			$pconfig = explode(",", $bridge['ifpriority']);
784
			$ifpriority = array();
785
			foreach ($pconfig as $cfg) {
786
				$embcfg = explode_assoc(":", $cfg);
787
				foreach ($embcfg as $key => $value) {
788
					$ifpriority[$key] = $value;
789
				}
790
			}
791
			foreach ($ifpriority as $key => $value) {
792
				$realif = get_real_interface($key);
793
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
794
			}
795
		}
796
		if (!empty($bridge['ifpathcost'])) {
797
			$pconfig = explode(",", $bridge['ifpathcost']);
798
			$ifpathcost = array();
799
			foreach ($pconfig as $cfg) {
800
				$embcfg = explode_assoc(":", $cfg);
801
				foreach ($embcfg as $key => $value) {
802
					$ifpathcost[$key] = $value;
803
				}
804
			}
805
			foreach ($ifpathcost as $key => $value) {
806
				$realif = get_real_interface($key);
807
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
808
			}
809
		}
810
	}
811
}
812

    
813
function interface_bridge_configure_advanced($bridge) {
814
	$bridgeif = escapeshellarg(trim($bridge['bridgeif']));
815

    
816
	if ($bridge['maxaddr'] <> "") {
817
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
818
	}
819
	if ($bridge['timeout'] <> "") {
820
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
821
	}
822
	if (!empty($bridge['span'])) {
823
		$spanifs = explode(",", $bridge['span']);
824
		foreach ($spanifs as $spanif) {
825
			$realif = get_real_interface($spanif);
826
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
827
		}
828
	}
829
	if (!empty($bridge['edge'])) {
830
		$edgeifs = explode(',', $bridge['edge']);
831
		foreach ($edgeifs as $edgeif) {
832
			$realif = get_real_interface($edgeif);
833
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
834
		}
835
	}
836
	if (!empty($bridge['autoedge'])) {
837
		$edgeifs = explode(',', $bridge['autoedge']);
838
		foreach ($edgeifs as $edgeif) {
839
			$realif = get_real_interface($edgeif);
840
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
841
		}
842
	}
843
	if (!empty($bridge['ptp'])) {
844
		$ptpifs = explode(',', $bridge['ptp']);
845
		foreach ($ptpifs as $ptpif) {
846
			$realif = get_real_interface($ptpif);
847
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
848
		}
849
	}
850
	if (!empty($bridge['autoptp'])) {
851
		$ptpifs = explode(',', $bridge['autoptp']);
852
		foreach ($ptpifs as $ptpif) {
853
			$realif = get_real_interface($ptpif);
854
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
855
		}
856
	}
857
	if (!empty($bridge['static'])) {
858
		$stickyifs = explode(',', $bridge['static']);
859
		foreach ($stickyifs as $stickyif) {
860
			$realif = get_real_interface($stickyif);
861
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
862
		}
863
	}
864
	if (!empty($bridge['private'])) {
865
		$privateifs = explode(',', $bridge['private']);
866
		foreach ($privateifs as $privateif) {
867
			$realif = get_real_interface($privateif);
868
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
869
		}
870
	}
871
}
872

    
873
function interface_bridge_configure_ip6linklocal($bridge) {
874
	$bridgeif = escapeshellarg(trim($bridge['bridgeif']));
875

    
876
	$members = explode(',', $bridge['members']);
877
	if (!count($members)) {
878
		return;
879
	}
880

    
881
	$auto_linklocal = isset($bridge['ip6linklocal']);
882
	$bridgeop = $auto_linklocal ? '' : '-';
883
	$memberop = $auto_linklocal ? '-' : '';
884

    
885
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
886
	foreach ($members as $member) {
887
		$realif = escapeshellarg(get_real_interface($member));
888
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
889
	}
890
}
891

    
892
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
893
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
894
		return;
895
	}
896

    
897
	if ($flagsapplied == false) {
898
		$mtu = get_interface_mtu($bridgeif);
899
		$mtum = get_interface_mtu($interface);
900
		/* Reconfigure the bridge mtu if the new member's MTU is lower, or
901
		 * reconfigure a non-gif interface MTU if the bridge's MTU is lower */
902
		if ($mtu > $mtum) {
903
			pfSense_interface_mtu($bridgeif, $mtum);
904
		} else if ($mtu < $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
905
			pfSense_interface_mtu($interface, $mtu);
906
		}
907

    
908
		hardware_offloading_applyflags($interface);
909
		interfaces_bring_up($interface);
910
	}
911

    
912
	pfSense_bridge_add_member($bridgeif, $interface);
913
	$bridged = config_get_path('bridges/bridged');
914
	if (is_array($bridged)) {
915
		foreach ($bridged as $bridge) {
916
			if ($bridgeif == $bridge['bridgeif']) {
917
				interface_bridge_configure_stp($bridge);
918
				interface_bridge_configure_advanced($bridge);
919
			}
920
		}
921
	}
922
}
923

    
924
function interfaces_lagg_configure($realif = "") {
925
	$i = 0;
926
	$laggs = config_get_path('laggs/lagg');
927
	if (is_array($laggs) && count($laggs)) {
928
		if (platform_booting()) {
929
			echo gettext("Configuring LAGG interfaces...");
930
		}
931
		foreach ($laggs as $lagg) {
932
			if (empty($lagg['laggif'])) {
933
				$lagg['laggif'] = "lagg{$i}";
934
			}
935
			if (!empty($realif) && $realif != $lagg['laggif']) {
936
				continue;
937
			}
938
			/* XXX: Maybe we should report any errors?! */
939
			interface_lagg_configure($lagg, false);
940
			$i++;
941
		}
942
		/* Invalidate cache */
943
		get_interface_arr(true);
944
		if (platform_booting()) {
945
			echo gettext("done.") . "\n";
946
		}
947
	}
948
}
949

    
950
function interface_lagg_configure($lagg, $flush = true) {
951
	if (!is_array($lagg)) {
952
		return -1;
953
	}
954

    
955
	$members = explode(',', $lagg['members']);
956
	if (!count($members)) {
957
		return -1;
958
	}
959

    
960
	if (platform_booting() || !(empty($lagg['laggif']))) {
961
		pfSense_interface_destroy($lagg['laggif']);
962
		pfSense_interface_create2($lagg['laggif']);
963
		$laggif = $lagg['laggif'];
964
	} else {
965
		$laggif = pfSense_interface_create2("lagg");
966
	}
967

    
968
	/* Check if MTU was defined for this lagg interface */
969
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
970
	if ($lagg_mtu == 0) {
971
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
972
			if ($tmpinterface['if'] == $lagg['laggif'] &&
973
			    !empty($tmpinterface['mtu'])) {
974
				$lagg_mtu = $tmpinterface['mtu'];
975
				break;
976
			}
977
		}
978
	}
979

    
980
	/* Just in case anything is not working well */
981
	if ($lagg_mtu == 0) {
982
		$lagg_mtu = 1500;
983
	}
984

    
985
	// put failover master interface on top of list
986
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
987
	    ($lagg['failovermaster'] != 'auto')) {
988
		unset($members[array_search($lagg['failovermaster'], $members)]);
989
		$members = array_merge(array($lagg['failovermaster']), $members);
990
	}
991

    
992
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
993
	    ($lagg['lacptimeout'] != 'slow')) {
994
		$lacptimeout = 'lacp_fast_timeout';
995
	} else {
996
		$lacptimeout = '';
997
	}
998

    
999
	if ((($lagg['proto'] == 'lacp') || ($lagg['proto'] == 'loadbalance')) &&
1000
	    isset($lagg['lagghash']) && !empty($lagg['lagghash'])) {
1001
		$lagghash = 'lagghash ' . escapeshellarg($lagg['lagghash']);
1002
	} else {
1003
		$lagghash = '';
1004
	}
1005

    
1006
	foreach ($members as $member) {
1007
		if (!does_interface_exist($member)) {
1008
			continue;
1009
		}
1010

    
1011
		/* make sure the parent interface is up */
1012
		pfSense_interface_mtu($member, $lagg_mtu);
1013
		interfaces_bring_up($member);
1014
		hardware_offloading_applyflags($member);
1015

    
1016
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1017
		$laggif = str_replace("\0", "", $laggif);
1018
		$member = str_replace("\0", "", $member);
1019
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1020
	}
1021

    
1022
	mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggproto " . escapeshellarg($lagg['proto']) . " {$lacptimeout} {$lagghash}");
1023

    
1024
	if ($flush) {
1025
		get_interface_arr(true);
1026
	}
1027

    
1028
	interfaces_bring_up($laggif);
1029

    
1030
	return $laggif;
1031
}
1032

    
1033
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1034
function interface_gre_configure(&$gre, $grekey = "", $flush = true) {
1035
	global $g;
1036

    
1037
	if (!is_array($gre)) {
1038
		return -1;
1039
	}
1040

    
1041
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1042
	if (!interface_is_vlan($realif)) {
1043
		$realif = get_real_interface($gre['if']);
1044
	}
1045
	$realifip = get_interface_ip($gre['if']);
1046
	$realifip6 = get_interface_ipv6($gre['if']);
1047

    
1048
	/* do not run ifconfig without correct $realifip */
1049
	if ((!$realifip && is_ipaddrv4($gre['remote-addr'])) ||
1050
	    (!$realifip6 && is_ipaddrv6($gre['remote-addr']))) {
1051
		return -1;
1052
	}
1053

    
1054
	/* make sure the parent interface is up */
1055
	interfaces_bring_up($realif);
1056

    
1057
	if (platform_booting() || !(empty($gre['greif']))) {
1058
		pfSense_interface_destroy($gre['greif']);
1059
		pfSense_interface_create2($gre['greif']);
1060
		$greif = $gre['greif'];
1061
	} else {
1062
		$greif = pfSense_interface_create2("gre");
1063
	}
1064

    
1065
	$tunnel_type = '';
1066
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1067
		$tunnel_type = 'v4';
1068
	}
1069
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1070
		$tunnel_type .= 'v6';
1071
	}
1072

    
1073
	/* Do not change the order here for more see gre(4) NOTES section. */
1074
	if (is_ipaddrv6($gre['remote-addr'])) {
1075
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1076
	} else {
1077
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1078
	}
1079
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1080
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1081
	}
1082
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1083
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1084
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1085
	}
1086

    
1087
	$parentif = get_real_interface($gre['if']);
1088
	if ($parentif) {
1089
		interfaces_bring_up($parentif);
1090
	} else {
1091
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1092
	}
1093

    
1094
	if (isset($gre['link1'])) {
1095
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1096
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1097
		}
1098
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1099
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1100
		}
1101
	}
1102
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1103
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1104
		unlink_if_exists("{$g['tmp_path']}/{$greif}_router.last");
1105
	}
1106
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1107
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1108
		unlink_if_exists("{$g['tmp_path']}/{$greif}_routerv6.last");
1109
	}
1110

    
1111
	if ($flush) {
1112
		get_interface_arr(true);
1113
	}
1114

    
1115
	interfaces_bring_up($greif);
1116

    
1117
	return $greif;
1118
}
1119

    
1120
function interface_is_type($if, $type) {
1121
	switch ($type) {
1122
		case "gre":
1123
			$list = 'gres';
1124
			$entry = 'gre';
1125
			$entif = 'greif';
1126
			break;
1127
		case "gif":
1128
			$list = 'gifs';
1129
			$entry = 'gif';
1130
			$entif = 'gifif';
1131
			break;
1132
		case "lagg":
1133
			$list = 'laggs';
1134
			$entry = 'lagg';
1135
			$entif = 'laggif';
1136
			break;
1137
		default:
1138
			break;
1139
	}
1140

    
1141
	$entries = config_get_path("{$list}/{$entry}");
1142
	if (!is_array($entries)) {
1143
		return (NULL);
1144
	}
1145

    
1146
	foreach ($entries as $ent) {
1147
		if ($ent[$entif] == $if) {
1148
			return ($ent);
1149
		}
1150
	}
1151
	return (NULL);
1152
}
1153

    
1154
function is_greipsec($if) {
1155
	if (ipsec_enabled()) {
1156
		foreach (config_get_path('gres/gre', []) as $gre) {
1157
			foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
1158
				foreach (config_get_path('ipsec/phase2', []) as $ph2ent) {
1159
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1160
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1161
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1162
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1163
						    return true;
1164
					}
1165
				}
1166
			}
1167
		}
1168
	}
1169
	return false;
1170
}
1171

    
1172
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1173
function interface_gif_configure(&$gif, $gifkey = "", $flush = true) {
1174
	global $g;
1175
	if (!is_array($gif)) {
1176
		return -1;
1177
	}
1178

    
1179
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1180
	if (!interface_is_vlan($realif)) {
1181
		$realif = get_real_interface($gif['if']);
1182
	}
1183
	$ipaddr = get_interface_ip($gif['if']);
1184

    
1185
	if (is_ipaddrv4($gif['remote-addr'])) {
1186
		if (is_ipaddrv4($ipaddr)) {
1187
			$realifip = $ipaddr;
1188
		} else {
1189
			$realifip = get_interface_ip($gif['if']);
1190
		}
1191
		$realifgw = get_interface_gateway($gif['if']);
1192
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1193
		if (is_ipaddrv6($ipaddr)) {
1194
			$realifip = $ipaddr;
1195
		} else {
1196
			$realifip = get_interface_ipv6($gif['if']);
1197
		}
1198
		$realifgw = get_interface_gateway_v6($gif['if']);
1199
	}
1200

    
1201
	/* do not run ifconfig without correct $realifip */
1202
	if ((!is_ipaddrv4($realifip) && is_ipaddrv4($gif['remote-addr'])) ||
1203
	    (!is_ipaddrv6($realifip) && is_ipaddrv6($gif['remote-addr']))) {
1204
		return -1;
1205
	}
1206

    
1207
	/* make sure the parent interface is up */
1208
	$parentif = get_real_interface($gif['if']);
1209
	if ($parentif) {
1210
		interfaces_bring_up($parentif);
1211
	} else {
1212
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1213
	}
1214

    
1215
	/* some kernels may need to load if_gif */
1216
	if (!is_module_loaded("if_gif")) {
1217
		mwexec("/sbin/kldload if_gif");
1218
	}
1219

    
1220
	if (platform_booting() || !(empty($gif['gifif']))) {
1221
		pfSense_interface_destroy($gif['gifif']);
1222
		pfSense_interface_create2($gif['gifif']);
1223
		$gifif = $gif['gifif'];
1224
	} else {
1225
		$gifif = pfSense_interface_create2("gif");
1226
	}
1227

    
1228
	/* Do not change the order here for more see gif(4) NOTES section. */
1229
	if (is_ipaddrv6($gif['remote-addr'])) {
1230
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1231
	} else {
1232
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1233
	}
1234
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1235
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1236
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1237
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1238
	} else {
1239
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1240
	}
1241
	if (isset($gif['link1'])) {
1242
		pfSense_interface_flags($gifif, IFF_LINK1);
1243
	}
1244
	if (isset($gif['link2'])) {
1245
		pfSense_interface_flags($gifif, IFF_LINK2);
1246
	}
1247
	if ($gifif) {
1248
		interfaces_bring_up($gifif);
1249
		$gifmtu = "";
1250
		$currentgifmtu = get_interface_mtu($gifif);
1251
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1252
			if ($tmpinterface['if'] == $gifif) {
1253
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1254
					$gifmtu = $tmpinterface['mtu'];
1255
				}
1256
			}
1257
		}
1258
		if (is_numericint($gifmtu)) {
1259
			if ($gifmtu != $currentgifmtu) {
1260
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1261
			}
1262
		}
1263
	} else {
1264
		log_error(gettext("could not bring gifif up -- variable not defined"));
1265
	}
1266

    
1267
	if (!platform_booting()) {
1268
		$iflist = get_configured_interface_list();
1269
		foreach ($iflist as $ifname) {
1270
			$if = config_get_path("interfaces/{$ifname}/if", "");
1271
			if ($if == $gifif) {
1272
				if (get_interface_gateway($ifname)) {
1273
					system_routing_configure($ifname);
1274
					break;
1275
				}
1276
				if (get_interface_gateway_v6($ifname)) {
1277
					system_routing_configure($ifname);
1278
					break;
1279
				}
1280
			}
1281
		}
1282
	}
1283

    
1284

    
1285
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1286
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1287
		    $gif['tunnel-remote-addr']);
1288
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_router.last");
1289
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1290
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1291
		    $gif['tunnel-remote-addr']);
1292
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_routerv6.last");
1293
	}
1294

    
1295
	route_add_or_change($gif['remote-addr'], $realifgw);
1296

    
1297
	if ($flush) {
1298
		get_interface_arr(true);
1299
	}
1300

    
1301
	interfaces_bring_up($gifif);
1302

    
1303
	return $gifif;
1304
}
1305

    
1306
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1307
	if (!in_array($type, array('gre', 'gif'))) {
1308
		return;
1309
	}
1310

    
1311
	$tuns = config_get_path("{$type}s/{$type}");
1312
	if (!is_array($tuns) || !count($tuns)) {
1313
		return;
1314
	}
1315

    
1316
	foreach ($tuns as $i => $tunnel) {
1317
		if (empty($tunnel["{$type}if"])) {
1318
			$tunnel["{$type}if"] = $type . $i;
1319
		}
1320
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1321
			continue;
1322
		}
1323

    
1324
		$ipaddrv6 = config_get_path("interfaces/{$tunnel}/if/ipaddrv6");
1325
		if ($checkparent == 1) {
1326
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1327
				continue;
1328
			}
1329
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1330
				continue;
1331
			}
1332

    
1333
			if ($ipaddrv6 == "track6") {
1334
				continue;
1335
			}
1336
		} elseif ($checkparent == 2) {
1337
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1338
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1339
				$ipaddrv6 != "track6") {
1340
				continue;
1341
			}
1342
		}
1343
		if ($type == 'gif') {
1344
			interface_gif_configure($tunnel, "", false);
1345
		} elseif ($type == 'gre') {
1346
			interface_gre_configure($tunnel, "", false);
1347
		}
1348
	}
1349

    
1350
	/* Invalidate cache */
1351
	get_interface_arr(true);
1352
}
1353

    
1354
/* Build a list of IPsec interfaces */
1355
function interface_ipsec_vti_list_p1($ph1ent) {
1356
	$iface_list = array();
1357

    
1358
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array(config_get_path('ipsec/phase2'))) {
1359
		return $iface_list;
1360
	}
1361

    
1362
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1363
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1364
		return $iface_list;
1365
	}
1366

    
1367
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1368
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1369
		foreach ($vtisubnet_spec as $vtisub) {
1370
			$iface_list[ipsec_get_ifname($ph1ent, $vtisub['reqid'])] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1371
		}
1372
	} else {
1373
		/* For IKEv2, only create one interface with additional addresses as aliases */
1374
		$iface_list[ipsec_get_ifname($ph1ent)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1375
	}
1376
	return $iface_list;
1377
}
1378
function interface_ipsec_vti_list_all() {
1379
	$iface_list = array();
1380
	$phase1 = config_get_path('ipsec/phase1');
1381
	$phase2 = config_get_path('ipsec/phase2');
1382
	if (is_array($phase1) && is_array($phase2)) {
1383
		foreach ($phase1 as $ph1ent) {
1384
			if ($ph1ent['disabled']) {
1385
				continue;
1386
			}
1387
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1388
		}
1389
	}
1390
	return $iface_list;
1391
}
1392

    
1393
function is_interface_ipsec_vti_assigned($phase2) {
1394
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1395
	$vti_interface = null;
1396
	$vtisubnet_spec = ipsec_vti($phase1, true);
1397
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1398
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1399
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1400
			foreach ($vtisubnet_spec as $vtisub) {
1401
				/* Is this for this P2? */
1402
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1403
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1404
					$vti_interface = ipsec_get_ifname($phase1, $vtisub['reqid']);
1405
				}
1406
			}
1407
		} else {
1408
			$vti_interface = ipsec_get_ifname($phase1);
1409
		}
1410
	}
1411
	/* Check if this interface is assigned */
1412
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1413
}
1414
function interface_ipsec_vti_configure($ph1ent, $gateways_status = false) {
1415
	global $ipsec_reqid_base;
1416

    
1417
	if (empty($ph1ent) || !is_array($ph1ent) || empty(config_get_path('ipsec/phase2'))) {
1418
		return false;
1419
	}
1420

    
1421
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1422
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1423
		return false;
1424
	}
1425

    
1426
	$left_spec = ipsec_get_phase1_src($ph1ent, $gateways_status);
1427

    
1428
	/* Attempt to resolve the remote gateway if needed */
1429
	$right_spec = ipsec_get_phase1_dst($ph1ent);
1430
	if (empty($right_spec)) {
1431
		/* Far end cannot be resolved */
1432
		return false;
1433
	}
1434

    
1435
	$iface_addrs = array();
1436
	$reqids = array();
1437

    
1438
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1439
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1440
		/* Form a single interface for each P2 entry */
1441
		foreach ($vtisubnet_spec as $vtisub) {
1442
			$ipsecif = ipsec_get_ifname($ph1ent, $vtisub['reqid']);
1443
			if (!is_array($iface_addrs[$ipsecif])) {
1444
				$iface_addrs[$ipsecif] = array();
1445
			}
1446
			$vtisub['alias'] = "";
1447
			$iface_addrs[$ipsecif][] = $vtisub;
1448
			$reqids[$ipsecif] = $vtisub['reqid'];
1449
		}
1450
	} else {
1451
		/* For IKEv2, only create one interface with additional addresses as aliases */
1452
		$ipsecif = ipsec_get_ifname($ph1ent);
1453
		if (!is_array($iface_addrs[$ipsecif])) {
1454
			$iface_addrs[$ipsecif] = array();
1455
		}
1456
		$have_v4 = false;
1457
		$have_v6 = false;
1458
		foreach ($vtisubnet_spec as $vtisub) {
1459
			// Alias stuff
1460
			$vtisub['alias'] = "";
1461
			if (is_ipaddrv6($vtisub['left'])) {
1462
				if ($have_v6) {
1463
					$vtisub['alias'] = " alias";
1464
				}
1465
				$have_v6 = true;
1466
			} else {
1467
				if ($have_v4) {
1468
					$vtisub['alias'] = " alias";
1469
				}
1470
				$have_v4 = true;
1471
			}
1472
			$iface_addrs[$ipsecif][] = $vtisub;
1473
		}
1474
		/* IKEv2 w/o Split uses the reqid of the first P2 */
1475
		$reqids[$ipsecif] = $vtisubnet_spec[0]['reqid'];
1476
	}
1477

    
1478
	foreach ($iface_addrs as $ipsecif => $addrs) {
1479
		if (!is_array($addrs)) {
1480
			continue;
1481
		}
1482
		// Create IPsec interface
1483
		if (does_interface_exist($ipsecif)) {
1484
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1485
		}
1486
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
1487

    
1488
		/* Apply the outer tunnel addresses to the interface */
1489
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1490
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1491

    
1492
		/* Loop through all of the addresses for this interface and apply them as needed */
1493
		foreach ($addrs as $addr) {
1494
			// apply interface addresses
1495
			if (is_v6($addr['left'])) {
1496
				$inet = "inet6";
1497
				$gwtype = "v6";
1498
				$right = '';
1499
			} else {
1500
				$inet = "inet";
1501
				$gwtype = "";
1502
				$right = escapeshellarg($addr['right']);
1503
			}
1504

    
1505
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1506
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1507
			if (empty($addr['alias'])) {
1508
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1509
				unlink_if_exists("/tmp/{$ipsecif}_router{$gwtype}.last");
1510
			}
1511
		}
1512
		/* Check/set the MTU if the user configured a custom value.
1513
		 * https://redmine.pfsense.org/issues/9111 */
1514
		$currentvtimtu = get_interface_mtu($ipsecif);
1515
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1516
			if ($tmpinterface['if'] == $ipsecif) {
1517
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1518
					$vtimtu = $tmpinterface['mtu'];
1519
				}
1520
			}
1521
		}
1522
		if (is_numericint($vtimtu)) {
1523
			if ($vtimtu != $currentvtimtu) {
1524
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1525
			}
1526
		}
1527
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1528
	}
1529
	return true;
1530
}
1531

    
1532
function interfaces_ipsec_vti_configure($gateways_status = false) {
1533
	$bootmsg = false;
1534

    
1535
	/* Fetch gateway status if not passed */
1536
	if (!is_array($gateways_status)) {
1537
		$gateways_status = return_gateways_status(true);
1538
	}
1539
	foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
1540
		if ($ph1ent['disabled']) {
1541
			continue;
1542
		}
1543
		if (interface_ipsec_vti_configure($ph1ent, $gateways_status) &&
1544
			!$bootmsg && platform_booting()) {
1545
			echo gettext("Configuring IPsec VTI interfaces...");
1546
			$bootmsg = true;
1547
		}
1548
	}
1549
	if (platform_booting() && $bootmsg) {
1550
		echo gettext("done.") . "\n";
1551
	}
1552
}
1553

    
1554
function interfaces_configure() {
1555
	global $g;
1556

    
1557
	/* Set up our loopback interface */
1558
	interfaces_loopback_configure();
1559

    
1560
	/* create the unconfigured wireless clones */
1561
	interfaces_create_wireless_clones();
1562

    
1563
	/* set up LAGG virtual interfaces */
1564
	interfaces_lagg_configure();
1565

    
1566
	/* set up VLAN virtual interfaces */
1567
	interfaces_vlan_configure();
1568

    
1569
	interfaces_qinq_configure(false);
1570

    
1571
	$iflist = get_configured_interface_with_descr();
1572
	$delayed_list = array();
1573
	$bridge_list = array();
1574
	$track6_list = array();
1575
	$dhcp6c_list = array();
1576

    
1577
	/* This is needed to speedup interfaces on bootup. */
1578
	$reload = false;
1579
	if (!platform_booting()) {
1580
		$reload = true;
1581
	}
1582

    
1583
	foreach ($iflist as $if => $ifname) {
1584
		$realif = config_get_path("interfaces/{$if}/if","");
1585
		$ipaddrv6 = config_get_path("interfaces/{$if}/ipaddrv6", "");
1586
		if (strstr($realif, "bridge")) {
1587
			$bridge_list[$if] = $ifname;
1588
		} elseif (strstr($realif, "gre")) {
1589
			$delayed_list[$if] = $ifname;
1590
		} elseif (strstr($realif, "gif")) {
1591
			$delayed_list[$if] = $ifname;
1592
		} elseif (strstr($realif, "ovpn")) {
1593
			continue;
1594
		} elseif (strstr($realif, "ipsec")) {
1595
			continue;
1596
		} elseif ($ipaddrv6 == "track6") {
1597
			$track6_list[$if] = $ifname;
1598
		} else {
1599
			/* do not run dhcp6c if track interface does not exists
1600
			 * see https://redmine.pfsense.org/issues/3965
1601
			 * and https://redmine.pfsense.org/issues/11633 */
1602
			if ($ipaddrv6 == "dhcp6") {
1603
				$tr6list = link_interface_to_track6($if);
1604
				if (is_array($tr6list) && !empty($tr6list)) {
1605
					$dhcp6c_list[$if] = $ifname;
1606
					continue;
1607
				}
1608
			}
1609
			if (platform_booting()) {
1610
				printf(gettext("Configuring %s interface..."),
1611
				    $ifname);
1612
			}
1613

    
1614
			if (g_get('debug')) {
1615
				log_error(sprintf(gettext("Configuring %s"),
1616
				    $ifname));
1617
			}
1618
			interface_configure($if, $reload);
1619
			if (platform_booting()) {
1620
				echo gettext("done.") . "\n";
1621
			}
1622
		}
1623
	}
1624

    
1625
	/*
1626
	 * NOTE: The following function parameter consists of
1627
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1628
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1629
	 */
1630

    
1631
	/* set up GRE virtual interfaces */
1632
	interfaces_tunnel_configure(1,'','gre');
1633

    
1634
	/* set up GIF virtual interfaces */
1635
	interfaces_tunnel_configure(1,'','gif');
1636

    
1637
	/* set up BRIDGE virtual interfaces */
1638
	interfaces_bridge_configure(1);
1639

    
1640
	foreach ($track6_list as $if => $ifname) {
1641
		if (platform_booting()) {
1642
			printf(gettext("Configuring %s interface..."), $ifname);
1643
		}
1644
		if (g_get('debug')) {
1645
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1646
		}
1647

    
1648
		interface_configure($if, $reload);
1649

    
1650
		if (platform_booting()) {
1651
			echo gettext("done.") . "\n";
1652
		}
1653
	}
1654

    
1655
	/* bring up vip interfaces */
1656
	interfaces_vips_configure();
1657

    
1658
	/* set up GRE virtual interfaces */
1659
	interfaces_tunnel_configure(2,'','gre');
1660

    
1661
	/* set up GIF virtual interfaces */
1662
	interfaces_tunnel_configure(2,'','gif');
1663

    
1664
	foreach ($delayed_list as $if => $ifname) {
1665
		if (platform_booting()) {
1666
			printf(gettext("Configuring %s interface..."), $ifname);
1667
		}
1668
		if (g_get('debug')) {
1669
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1670
		}
1671

    
1672
		interface_configure($if, $reload);
1673

    
1674
		if (platform_booting()) {
1675
			echo gettext("done.") . "\n";
1676
		}
1677
	}
1678

    
1679
	/* set up BRIDGE virtual interfaces */
1680
	interfaces_bridge_configure(2);
1681

    
1682
	foreach ($bridge_list as $if => $ifname) {
1683
		if (platform_booting()) {
1684
			printf(gettext("Configuring %s interface..."), $ifname);
1685
		}
1686
		if (g_get('debug')) {
1687
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1688
		}
1689

    
1690
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1691
		// redmine #3997
1692
		interface_reconfigure($if, $reload);
1693
		interfaces_vips_configure($if);
1694

    
1695
		if (platform_booting()) {
1696
			echo gettext("done.") . "\n";
1697
		}
1698
	}
1699

    
1700
	foreach ($dhcp6c_list as $if => $ifname) {
1701
		if (platform_booting()) {
1702
			printf(gettext("Configuring %s interface..."), $ifname);
1703
		}
1704
		if (g_get('debug')) {
1705
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1706
		}
1707

    
1708
		interface_configure($if, $reload);
1709

    
1710
		if (platform_booting()) {
1711
			echo gettext("done.") . "\n";
1712
		}
1713
	}
1714

    
1715
	/* set up IPsec VTI interfaces */
1716
	interfaces_ipsec_vti_configure();
1717

    
1718
	/* configure interface groups */
1719
	interfaces_group_setup();
1720

    
1721
	if (!platform_booting()) {
1722
		/* reconfigure static routes (kernel may have deleted them) */
1723
		system_routing_configure();
1724

    
1725
		/* reload IPsec tunnels */
1726
		ipsec_configure();
1727

    
1728
		/* restart dns servers (defering dhcpd reload) */
1729
		if (config_get_path('dnsmasq/enable')) {
1730
			services_dnsmasq_configure(false);
1731
		}
1732
		if (config_get_path('unbound/enable')) {
1733
			services_unbound_configure(false);
1734
		}
1735

    
1736
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1737
		services_dhcpd_configure();
1738
	}
1739

    
1740
	return 0;
1741
}
1742

    
1743
function interface_reconfigure($interface = "wan", $reloadall = false) {
1744
	interface_bring_down($interface);
1745
	interface_configure($interface, $reloadall);
1746
}
1747

    
1748
function interface_vip_bring_down($vip) {
1749
	global $g;
1750

    
1751
	$vipif = get_real_interface($vip['interface']);
1752
	switch ($vip['mode']) {
1753
		case "proxyarp":
1754
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1755
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1756
			}
1757
			break;
1758
		case "ipalias":
1759
			if (does_interface_exist($vipif)) {
1760
				if (is_ipaddrv6($vip['subnet'])) {
1761
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1762
				} else {
1763
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1764
				}
1765
			}
1766
			break;
1767
		case "carp":
1768
			/* XXX: Is enough to delete ip address? */
1769
			if (does_interface_exist($vipif)) {
1770
				if (is_ipaddrv6($vip['subnet'])) {
1771
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1772
				} else {
1773
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1774
				}
1775
			}
1776
			break;
1777
	}
1778
}
1779

    
1780
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1781
	global $g;
1782

    
1783
	$iface = config_get_path("interfaces/{$interface}");
1784
	if (!$iface) {
1785
		return;
1786
	}
1787

    
1788
	if (g_get('debug')) {
1789
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1790
	}
1791

    
1792
	/*
1793
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1794
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1795
	 * Keep this in mind while doing changes here!
1796
	 */
1797
	if ($ifacecfg === false) {
1798
		$ifcfg = $iface;
1799
		$ppps = config_get_path('ppps/ppp', []);
1800
		$realif = get_real_interface($interface);
1801
		$realifv6 = get_real_interface($interface, "inet6", true);
1802
	} elseif (!is_array($ifacecfg)) {
1803
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1804
		$ifcfg = $iface;
1805
		$ppps = config_get_path('ppps/ppp', []);
1806
		$realif = get_real_interface($interface);
1807
		$realifv6 = get_real_interface($interface, "inet6", true);
1808
	} else {
1809
		$ifcfg = $ifacecfg['ifcfg'];
1810
		$ppps = $ifacecfg['ppps'];
1811
		if (isset($ifacecfg['ifcfg']['realif'])) {
1812
			$realif = $ifacecfg['ifcfg']['realif'];
1813
			/* XXX: Any better way? */
1814
			$realifv6 = $realif;
1815
		} else {
1816
			$realif = get_real_interface($interface);
1817
			$realifv6 = get_real_interface($interface, "inet6", true);
1818
		}
1819
	}
1820

    
1821
	/* check all gateways, including dynamic,
1822
	 * see https://redmine.pfsense.org/issues/12920 */
1823
	foreach (return_gateways_array(true) as $gw) {
1824
		if ($gw['friendlyiface'] == $interface) {
1825
			$restart_gateways_monitor = true;
1826
			break;
1827
		}
1828
	}
1829

    
1830
	switch ($ifcfg['ipaddr']) {
1831
		case "ppp":
1832
		case "pppoe":
1833
		case "pptp":
1834
		case "l2tp":
1835
			if (is_array($ppps) && count($ppps)) {
1836
				foreach ($ppps as  $ppp) {
1837
					if ($realif == $ppp['if']) {
1838
						if (isset($ppp['ondemand']) && !$destroy) {
1839
							send_event("interface reconfigure {$interface}");
1840
							break;
1841
						}
1842
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1843
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1844
							sleep(2);
1845
						}
1846
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1847
						break;
1848
					}
1849
				}
1850
			}
1851
			break;
1852
		case "dhcp":
1853
			kill_dhclient_process($realif);
1854
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1855
			if (does_interface_exist("$realif")) {
1856
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1857
				interface_vip_cleanup($interface, "inet4");
1858
				if ($destroy == true) {
1859
					pfSense_interface_flags($realif, -IFF_UP);
1860
				}
1861
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1862
			}
1863
			break;
1864
		default:
1865
			if (does_interface_exist("$realif")) {
1866
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1867
				interface_vip_cleanup($interface, "inet4");
1868
				if ($destroy == true) {
1869
					pfSense_interface_flags($realif, -IFF_UP);
1870
				}
1871
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1872
			}
1873
			break;
1874
	}
1875

    
1876
	$track6 = array();
1877
	switch ($ifcfg['ipaddrv6']) {
1878
		case "slaac":
1879
		case "dhcp6":
1880
			interface_dhcpv6_configure($interface, $ifcfg, true);
1881
			if (does_interface_exist($realifv6)) {
1882
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
1883
				$ip6 = find_interface_ipv6($realifv6);
1884
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1885
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1886
				}
1887
				interface_vip_cleanup($interface, "inet6");
1888
				if ($destroy == true) {
1889
					pfSense_interface_flags($realif, -IFF_UP);
1890
				}
1891
			}
1892
			$track6 = link_interface_to_track6($interface);
1893
			break;
1894
		case "6rd":
1895
		case "6to4":
1896
			$realif = "{$interface}_stf";
1897
			if (does_interface_exist("$realif")) {
1898
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1899
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($iface['ipaddrv6']) || $iface['ipaddrv6'] != '6rd')) ||
1900
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($iface['ipaddrv6']) || $iface['ipaddrv6'] != '6to4'))) {
1901
					$destroy = true;
1902
				} else {
1903
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1904
					$ip6 = get_interface_ipv6($interface);
1905
					if (is_ipaddrv6($ip6)) {
1906
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1907
					}
1908
				}
1909
				interface_vip_cleanup($interface, "inet6");
1910
				if ($destroy == true) {
1911
					pfSense_interface_flags($realif, -IFF_UP);
1912
				}
1913
			}
1914
			$track6 = link_interface_to_track6($interface);
1915
			break;
1916
		default:
1917
			if (does_interface_exist("$realif")) {
1918
				$ip6 = get_interface_ipv6($interface);
1919
				if (is_ipaddrv6($ip6)) {
1920
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1921
				}
1922
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1923
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1924
				}
1925
				interface_vip_cleanup($interface, "inet6");
1926
				if ($destroy == true) {
1927
					pfSense_interface_flags($realif, -IFF_UP);
1928
				}
1929
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1930
			}
1931
			$track6 = link_interface_to_track6($interface);
1932
			break;
1933
	}
1934

    
1935
	if (!empty($track6) && is_array($track6)) {
1936
		if (!function_exists('services_dhcpd_configure')) {
1937
			require_once('services.inc');
1938
		}
1939
		/* Bring down radvd and dhcp6 on these interfaces */
1940
		services_dhcpd_configure('inet6', $track6);
1941
	}
1942

    
1943
	/* remove interface up file if it exists */
1944
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1945
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1946
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1947
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1948
		rename("{$g['tmp_path']}/{$realif}_router", "{$g['tmp_path']}/{$realif}_router.last");
1949
	}
1950
	if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
1951
		rename("{$g['tmp_path']}/{$realif}_routerv6", "{$g['tmp_path']}/{$realif}_routerv6.last");
1952
	}
1953
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1954
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
1955
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1956
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
1957
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart4");
1958
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart6");
1959

    
1960
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1961
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1962
	if (is_array($ifcfg['wireless'])) {
1963
		kill_hostapd($realif);
1964
		mwexec(kill_wpasupplicant($realif));
1965
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
1966
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
1967
	}
1968

    
1969
	if ($destroy == true) {
1970
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
1971
			pfSense_interface_destroy($realif);
1972

    
1973
			/* Invalidate cache */
1974
			get_interface_arr(true);
1975
		}
1976
	}
1977

    
1978
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
1979
	if ($restart_gateways_monitor) {
1980
		setup_gateways_monitor();
1981
	}
1982

    
1983
	return;
1984
}
1985

    
1986
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1987
	if (config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == false)) {
1988
		config_del_path('virtualip_carp_maintenancemode');
1989
		write_config("Leave CARP maintenance mode");
1990
	} elseif (!config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == true)) {
1991
		config_set_path('virtualip_carp_maintenancemode', true);
1992
		write_config(gettext("Enter CARP maintenance mode"));
1993
	}
1994
	init_config_arr(array('virtualip', 'vip'));
1995

    
1996
	foreach (config_get_path('virtualip/vip', []) as $vip) {
1997
		if ($vip['mode'] == "carp") {
1998
			interface_carp_configure($vip, true);
1999
		}
2000
	}
2001
}
2002

    
2003
function interface_wait_tentative($interface, $timeout = 10) {
2004
	if (!does_interface_exist($interface)) {
2005
		return false;
2006
	}
2007

    
2008
	$time = 0;
2009
	while ($time <= $timeout) {
2010
		$if = get_interface_addresses($interface);
2011
		if (!isset($if['tentative'])) {
2012
			return true;
2013
		}
2014
		sleep(1);
2015
		$time++;
2016
	}
2017

    
2018
	return false;
2019
}
2020

    
2021
function interface_isppp_type($interface) {
2022
	$iface = config_get_path("interfaces/{$interface}");
2023
	if (!is_array($iface)) {
2024
		return false;
2025
	}
2026

    
2027
	switch ($iface['ipaddr']) {
2028
		case 'pptp':
2029
		case 'l2tp':
2030
		case 'pppoe':
2031
		case 'ppp':
2032
			return true;
2033
			break;
2034
		default:
2035
			return false;
2036
			break;
2037
	}
2038
}
2039

    
2040
function interfaces_ptpid_used($ptpid) {
2041
	$ppps = config_get_path('ppps/ppp');
2042
	if (is_array($ppps)) {
2043
		foreach ($ppps as $settings) {
2044
			if ($ptpid == $settings['ptpid']) {
2045
				return true;
2046
			}
2047
		}
2048
	}
2049

    
2050
	return false;
2051
}
2052

    
2053
function interfaces_ptpid_next() {
2054
	$ptpid = 0;
2055
	while (interfaces_ptpid_used($ptpid)) {
2056
		$ptpid++;
2057
	}
2058

    
2059
	return $ptpid;
2060
}
2061

    
2062
function getMPDCRONSettings($pppif) {
2063
	global $g;
2064

    
2065
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2066
	foreach (config_get_path('cron/item', []) as $i => $item) {
2067
		if (stripos($item['command'], $cron_cmd_file) !== false) {
2068
			return array("ID" => $i, "ITEM" => $item);
2069
		}
2070
	}
2071

    
2072
	return NULL;
2073
}
2074

    
2075
function handle_pppoe_reset($post_array) {
2076
	global $g;
2077

    
2078
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2079
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2080

    
2081
	if (!is_array(config_get_path('cron/item'))) {
2082
		if (config_set_path('cron/item', array()) === null)
2083
			log_error(gettext('Cron section in config root is invalid.'));
2084
			return;
2085
	}
2086

    
2087
	$itemhash = getMPDCRONSettings($pppif);
2088

    
2089
	// reset cron items if necessary and return
2090
	if (empty($post_array['pppoe-reset-type'])) {
2091
		if (isset($itemhash)) {
2092
			config_del_path("cron/item/{$itemhash['ID']}");
2093
		}
2094
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2095
		return;
2096
	}
2097

    
2098
	if (empty($itemhash)) {
2099
		$itemhash = array();
2100
	}
2101
	$item = array();
2102
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2103
		$item['minute'] = (strlen($post_array['pppoe_resetminute']) > 0) ? $post_array['pppoe_resetminute'] : "*";
2104
		$item['hour'] = (strlen($post_array['pppoe_resethour']) > 0) ? $post_array['pppoe_resethour'] : "*";
2105
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2106
			$date = explode("/", $post_array['pppoe_resetdate']);
2107
			$item['mday'] = $date[1];
2108
			$item['month'] = $date[0];
2109
		} else {
2110
			$item['mday'] = "*";
2111
			$item['month'] = "*";
2112
		}
2113
		$item['wday'] = "*";
2114
		$item['who'] = "root";
2115
		$item['command'] = $cron_cmd_file;
2116
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2117
		switch ($post_array['pppoe_pr_preset_val']) {
2118
			case "monthly":
2119
				$item['minute'] = "0";
2120
				$item['hour'] = "0";
2121
				$item['mday'] = "1";
2122
				$item['month'] = "*";
2123
				$item['wday'] = "*";
2124
				break;
2125
			case "weekly":
2126
				$item['minute'] = "0";
2127
				$item['hour'] = "0";
2128
				$item['mday'] = "*";
2129
				$item['month'] = "*";
2130
				$item['wday'] = "0";
2131
				break;
2132
			case "daily":
2133
				$item['minute'] = "0";
2134
				$item['hour'] = "0";
2135
				$item['mday'] = "*";
2136
				$item['month'] = "*";
2137
				$item['wday'] = "*";
2138
				break;
2139
			case "hourly":
2140
				$item['minute'] = "0";
2141
				$item['hour'] = "*";
2142
				$item['mday'] = "*";
2143
				$item['month'] = "*";
2144
				$item['wday'] = "*";
2145
				break;
2146
		} // end switch
2147
		$item['who'] = "root";
2148
		$item['command'] = $cron_cmd_file;
2149
	}
2150
	if (empty($item)) {
2151
		return;
2152
	}
2153
	if (isset($itemhash['ID'])) {
2154
		config_set_path("cron/item/{$itemhash['ID']}", $item);
2155
	} else {
2156
		$items = config_get_path('cron/item', []);
2157
		$items[] = $item;
2158
		config_set_path('cron/item', $items);
2159
	}
2160
}
2161

    
2162
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2163
	$ppp_list = array();
2164
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
2165
		$ports = explode(",", $ppp['ports']);
2166
		foreach($ports as $port) {
2167
			foreach($triggerinterfaces as $vip) {
2168
				if ($port == "_vip{$vip['uniqid']}") {
2169
					$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2170
					$ppp_list[$if] = 1;
2171
				}
2172
			}
2173
		}
2174
	}
2175
	foreach(array_keys($ppp_list) as $pppif) {
2176
		interface_ppps_configure($pppif);
2177
	}
2178
}
2179

    
2180
/*
2181
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2182
 * It writes the mpd config file to /var/etc every time the link is opened.
2183
 */
2184
function interface_ppps_configure($interface) {
2185
	global $g;
2186

    
2187
	$iface = config_get_path("interfaces/{$interface}");
2188
	/* Return for unassigned interfaces. This is a minimum requirement. */
2189
	if (empty($iface)) {
2190
		return 0;
2191
	}
2192
	$ifcfg = $iface;
2193
	if (!isset($ifcfg['enable'])) {
2194
		return 0;
2195
	}
2196

    
2197
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2198
	if (!is_dir("/var/spool/lock")) {
2199
		mkdir("/var/spool/lock", 0777, true);
2200
	}
2201
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2202
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2203
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2204
	}
2205

    
2206
	$pppid = "";
2207
	$ppp = array();
2208
	$ppps = config_get_path('ppps/ppp');
2209
	if (is_array($ppps) && count($ppps)) {
2210
		foreach ($ppps as $pppid => $ppp) {
2211
			if ($ifcfg['if'] == $ppp['if']) {
2212
				break;
2213
			}
2214
		}
2215
	}
2216
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2217
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2218
		return 0;
2219
	}
2220
	$pppif = $ifcfg['if'];
2221
	if ($ppp['type'] == "ppp") {
2222
		$type = "modem";
2223
	} else {
2224
		$type = $ppp['type'];
2225
	}
2226

    
2227
	$confports = explode(',', $ppp['ports']);
2228
	if ($type == "modem") {
2229
		$ports = $confports;
2230
	} else {
2231
		$ports = array();
2232
		foreach ($confports as $pid => $port) {
2233
			if (strstr($port, "_vip")) {
2234
				if (get_carp_interface_status($port) != "MASTER") {
2235
					continue;
2236
				}
2237
			}
2238
			$ports[$pid] = get_real_interface($port);
2239
			if (empty($ports[$pid])) {
2240
				return 0;
2241
			}
2242
		}
2243
	}
2244
	$localips = explode(',', $ppp['localip']);
2245
	$gateways = explode(',', $ppp['gateway']);
2246
	$subnets = explode(',', $ppp['subnet']);
2247

    
2248
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2249
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2250
	 */
2251
	foreach ($ports as $pid => $port) {
2252
		switch ($ppp['type']) {
2253
			case "pppoe":
2254
				/* Bring the parent interface up */
2255
				interfaces_bring_up($port);
2256
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2257
				$ngif = str_replace(".", "_", $port);
2258
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2259
				break;
2260
			case "pptp":
2261
			case "l2tp":
2262
				/* configure interface */
2263
				if (is_ipaddr($localips[$pid])) {
2264
					// Manually configure interface IP/subnet
2265
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2266
					interfaces_bring_up($port);
2267
				} elseif (empty($localips[$pid])) {
2268
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2269
				}
2270

    
2271
				if (!is_ipaddr($localips[$pid])) {
2272
					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));
2273
					$localips[$pid] = "0.0.0.0";
2274
				}
2275
				if (!g_get('booting') && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2276
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2277
				}
2278
				if (!is_ipaddr($gateways[$pid])) {
2279
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $localips[$pid], $ppp['gateway']));
2280
					return 0;
2281
				}
2282
				break;
2283
			case "ppp":
2284
				if (!file_exists("{$port}")) {
2285
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2286
					return 0;
2287
				}
2288
				break;
2289
			default:
2290
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2291
				break;
2292
		}
2293
	}
2294

    
2295
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2296
	    (is_array($ports) && count($ports) > 1)) {
2297
		$multilink = "enable";
2298
	} else {
2299
		$multilink = "disable";
2300
	}
2301

    
2302
	if ($type == "modem") {
2303
		if (is_ipaddr($ppp['localip'])) {
2304
			$localip = $ppp['localip'];
2305
		} else {
2306
			$localip = '0.0.0.0';
2307
		}
2308

    
2309
		if (is_ipaddr($ppp['gateway'])) {
2310
			$gateway = $ppp['gateway'];
2311
		} else {
2312
			$gateway = "10.64.64.{$pppid}";
2313
		}
2314
		$ranges = "{$localip}/0 {$gateway}/0";
2315

    
2316
		if (empty($ppp['apnum'])) {
2317
			$ppp['apnum'] = 1;
2318
		}
2319
	} else {
2320
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2321
	}
2322

    
2323
	if (isset($ppp['ondemand'])) {
2324
		$ondemand = "enable";
2325
	} else {
2326
		$ondemand = "disable";
2327
	}
2328
	if (!isset($ppp['idletimeout'])) {
2329
		$ppp['idletimeout'] = 0;
2330
	}
2331

    
2332
	if (empty($ppp['username']) && $type == "modem") {
2333
		$ppp['username'] = "user";
2334
		$ppp['password'] = "none";
2335
	}
2336
	if (empty($ppp['password']) && $type == "modem") {
2337
		$passwd = "none";
2338
	} else {
2339
		$passwd = base64_decode($ppp['password']);
2340
	}
2341

    
2342
	$bandwidths = explode(',', $ppp['bandwidth']);
2343
	$defaultmtu = "1492";
2344
	if (!empty($ifcfg['mtu'])) {
2345
		$defaultmtu = intval($ifcfg['mtu']);
2346
	}
2347
	if (isset($ppp['mtu'])) {
2348
		$mtus = explode(',', $ppp['mtu']);
2349
	}
2350
	if (isset($ppp['mru'])) {
2351
		$mrus = explode(',', $ppp['mru']);
2352
	}
2353
	if (isset($ppp['mrru'])) {
2354
		$mrrus = explode(',', $ppp['mrru']);
2355
	}
2356
	if (!empty($ifcfg['ipaddrv6'])) {
2357
		$ipv6cp = "set bundle enable ipv6cp";
2358
	}
2359

    
2360
	// Construct the mpd.conf file
2361
	$mpdconf = <<<EOD
2362
startup:
2363
	# configure the console
2364
	set console close
2365
	# configure the web server
2366
	set web close
2367

    
2368
default:
2369
{$ppp['type']}client:
2370
	create bundle static {$interface}
2371
	set bundle period 6
2372
	set bundle lowat 0
2373
	set bundle hiwat 0
2374
	set bundle min-con 3
2375
	set bundle min-dis 6
2376
	set bundle enable bw-manage
2377
	{$ipv6cp}
2378
	set iface name {$pppif}
2379

    
2380
EOD;
2381

    
2382
	if (isset($ifcfg['descr'])) {
2383
		$mpdconf .= <<<EOD
2384
	set iface description "{$ifcfg['descr']}"
2385

    
2386
EOD;
2387
	}
2388
	$setdefaultgw = false;
2389
	$defgw4 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw4'));
2390
//	$defgw6 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw6'));
2391
	if ($defgw4['interface'] == $interface) {
2392
		$setdefaultgw = true;
2393
	}
2394

    
2395
/* Omit this, we maintain the default route by other means, and it causes problems with
2396
 * default gateway switching. See redmine #1837 for original issue
2397
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2398
 * edge case. redmine #6495 open to address.
2399
 */
2400
	if ($setdefaultgw == true) {
2401
		$mpdconf .= <<<EOD
2402
	set iface route default
2403

    
2404
EOD;
2405
	}
2406

    
2407
	$mpdconf .= <<<EOD
2408
	set iface {$ondemand} on-demand
2409
	set iface idle {$ppp['idletimeout']}
2410

    
2411
EOD;
2412

    
2413
	if (isset($ppp['ondemand'])) {
2414
		$mpdconf .= <<<EOD
2415
	set iface addrs 10.10.1.1 10.10.1.2
2416

    
2417
EOD;
2418
	}
2419

    
2420
	if (isset($ppp['mtu-override']) &&
2421
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2422
		/* Find the smaller MTU set on ports */
2423
		$mtu = $defaultmtu;
2424
		foreach ($ports as $pid => $port) {
2425
			if (empty($mtus[$pid])) {
2426
				$mtus[$pid] = $defaultmtu;
2427
			}
2428
			if ($type == "pppoe") {
2429
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2430
					$mtus[$pid] = get_interface_mtu($port) - 8;
2431
				}
2432
			}
2433
			if ($mtu > $mtus[$pid]) {
2434
				$mtu = $mtus[$pid];
2435
			}
2436
		}
2437
		$mpdconf .= <<<EOD
2438
	set iface mtu {$mtu} override
2439

    
2440
EOD;
2441
	}
2442

    
2443
	if (isset($ppp['tcpmssfix'])) {
2444
		$tcpmss = "disable";
2445
	} else {
2446
		$tcpmss = "enable";
2447
	}
2448
	$mpdconf .= <<<EOD
2449
	set iface {$tcpmss} tcpmssfix
2450

    
2451
EOD;
2452

    
2453
	$mpdconf .= <<<EOD
2454
	set iface up-script /usr/local/sbin/ppp-linkup
2455
	set iface down-script /usr/local/sbin/ppp-linkdown
2456
	set ipcp ranges {$ranges}
2457

    
2458
EOD;
2459
	if (isset($ppp['vjcomp'])) {
2460
		$mpdconf .= <<<EOD
2461
	set ipcp no vjcomp
2462

    
2463
EOD;
2464
	}
2465

    
2466
	if (config_path_enabled('system', 'dnsallowoverride')) {
2467
		$mpdconf .= <<<EOD
2468
	set ipcp enable req-pri-dns
2469
	set ipcp enable req-sec-dns
2470

    
2471
EOD;
2472
	}
2473

    
2474
	if (!isset($ppp['verbose_log'])) {
2475
		$mpdconf .= <<<EOD
2476
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2477

    
2478
EOD;
2479
	}
2480

    
2481
	foreach ($ports as $pid => $port) {
2482
		$port = get_real_interface($port);
2483
		$mpdconf .= <<<EOD
2484

    
2485
	create link static {$interface}_link{$pid} {$type}
2486
	set link action bundle {$interface}
2487
	set link {$multilink} multilink
2488
	set link keep-alive 10 60
2489
	set link max-redial 0
2490

    
2491
EOD;
2492
		if (isset($ppp['shortseq'])) {
2493
			$mpdconf .= <<<EOD
2494
	set link no shortseq
2495

    
2496
EOD;
2497
		}
2498

    
2499
		if (isset($ppp['acfcomp'])) {
2500
			$mpdconf .= <<<EOD
2501
	set link no acfcomp
2502

    
2503
EOD;
2504
		}
2505

    
2506
		if (isset($ppp['protocomp'])) {
2507
			$mpdconf .= <<<EOD
2508
	set link no protocomp
2509

    
2510
EOD;
2511
		}
2512

    
2513
		$mpdconf .= <<<EOD
2514
	set link disable chap pap
2515
	set link accept chap pap eap
2516
	set link disable incoming
2517

    
2518
EOD;
2519

    
2520

    
2521
		if (!empty($bandwidths[$pid])) {
2522
			$mpdconf .= <<<EOD
2523
	set link bandwidth {$bandwidths[$pid]}
2524

    
2525
EOD;
2526
		}
2527

    
2528
		if (empty($mtus[$pid])) {
2529
			$mtus[$pid] = $defaultmtu;
2530
		}
2531
		if ($type == "pppoe") {
2532
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2533
				$mtus[$pid] = get_interface_mtu($port) - 8;
2534
			}
2535
		}
2536
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2537
		    !isset($ppp['mtu-override']) &&
2538
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2539
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2540
			$mpdconf .= <<<EOD
2541
	set link mtu {$mtus[$pid]}
2542

    
2543
EOD;
2544
		}
2545

    
2546
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2547
		    !isset($ppp['mtu-override']) &&
2548
		    !empty($mrus[$pid])) {
2549
			$mpdconf .= <<<EOD
2550
	set link mru {$mrus[$pid]}
2551

    
2552
EOD;
2553
		}
2554

    
2555
		if (!empty($mrrus[$pid])) {
2556
			$mpdconf .= <<<EOD
2557
	set link mrru {$mrrus[$pid]}
2558

    
2559
EOD;
2560
		}
2561

    
2562
		$mpdconf .= <<<EOD
2563
	set auth authname "{$ppp['username']}"
2564
	set auth password {$passwd}
2565

    
2566
EOD;
2567
		if ($type == "modem") {
2568
			$mpdconf .= <<<EOD
2569
	set modem device {$ppp['ports']}
2570
	set modem script DialPeer
2571
	set modem idle-script Ringback
2572
	set modem watch -cd
2573
	set modem var \$DialPrefix "DT"
2574
	set modem var \$Telephone "{$ppp['phone']}"
2575

    
2576
EOD;
2577
		}
2578
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2579
			$mpdconf .= <<<EOD
2580
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2581

    
2582
EOD;
2583
		}
2584
		if (isset($ppp['initstr']) && $type == "modem") {
2585
			$initstr = base64_decode($ppp['initstr']);
2586
			$mpdconf .= <<<EOD
2587
	set modem var \$InitString "{$initstr}"
2588

    
2589
EOD;
2590
		}
2591
		if (isset($ppp['simpin']) && $type == "modem") {
2592
			if ($ppp['pin-wait'] == "") {
2593
				$ppp['pin-wait'] = 0;
2594
			}
2595
			$mpdconf .= <<<EOD
2596
	set modem var \$SimPin "{$ppp['simpin']}"
2597
	set modem var \$PinWait "{$ppp['pin-wait']}"
2598

    
2599
EOD;
2600
		}
2601
		if (isset($ppp['apn']) && $type == "modem") {
2602
			$mpdconf .= <<<EOD
2603
	set modem var \$APN "{$ppp['apn']}"
2604
	set modem var \$APNum "{$ppp['apnum']}"
2605

    
2606
EOD;
2607
		}
2608
		if ($type == "pppoe") {
2609
			$hostuniq = '';
2610
			if (!empty($ppp['hostuniq'])) {
2611
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2612
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2613
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2614
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2615
				}
2616
			}
2617
			// Send a null service name if none is set.
2618
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2619
			$mpdconf .= <<<EOD
2620
	set pppoe service "{$hostuniq}{$provider}"
2621

    
2622
EOD;
2623
		}
2624
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2625
			$mpdconf .= <<<EOD
2626
	set pppoe max-payload {$mtus[$pid]}
2627

    
2628
EOD;
2629
		}
2630
		if ($type == "pppoe") {
2631
			$mpdconf .= <<<EOD
2632
	set pppoe iface {$port}
2633

    
2634
EOD;
2635
		}
2636

    
2637
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2638
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2639
			$mpdconf .= <<<EOD
2640
	set l2tp secret "{$secret}"
2641

    
2642
EOD;
2643
		}
2644

    
2645
		if (($type == "pptp") || ($type == "l2tp")) {
2646
			$mpdconf .= <<<EOD
2647
	set {$type} self {$localips[$pid]}
2648
	set {$type} peer {$gateways[$pid]}
2649

    
2650
EOD;
2651
		}
2652

    
2653
		$mpdconf .= "\topen\n";
2654
	} //end foreach ($port)
2655

    
2656

    
2657
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2658
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2659
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2660
	} else {
2661
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2662
		if (!$fd) {
2663
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2664
			return 0;
2665
		}
2666
		// Write out mpd_ppp.conf
2667
		fwrite($fd, $mpdconf);
2668
		fclose($fd);
2669
		unset($mpdconf);
2670
	}
2671

    
2672
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2673
	if (isset($ppp['uptime'])) {
2674
		if (!file_exists("/conf/{$pppif}.log")) {
2675
			file_put_contents("/conf/{$pppif}.log", '');
2676
		}
2677
	} else {
2678
		if (file_exists("/conf/{$pppif}.log")) {
2679
			@unlink("/conf/{$pppif}.log");
2680
		}
2681
	}
2682

    
2683
	/* clean up old lock files */
2684
	foreach ($ports as $port) {
2685
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2686
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2687
		}
2688
	}
2689

    
2690
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2691
	/* random IPv6 interface identifier during boot. More details at */
2692
	/* https://forum.netgate.com/post/592474 */
2693
	if (platform_booting()) {
2694
		$count = 0;
2695
		foreach (config_get_path('interfaces', []) as $tempifacename => $tempiface) {
2696
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2697
				$tempaddr[$count]['if'] = $tempiface['if'];
2698
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2699
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2700
				$count++;
2701
			}
2702
			// Maximum /31 is is x.y.z.254/31
2703
			if ($count > 122) {
2704
				break;
2705
			}
2706
		}
2707
		unset($count);
2708
	}
2709

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

    
2715
	// Check for PPPoE periodic reset request
2716
	if ($type == "pppoe") {
2717
		if (!empty($ppp['pppoe-reset-type'])) {
2718
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2719
		} else {
2720
			interface_setup_pppoe_reset_file($ppp['if']);
2721
		}
2722
	}
2723
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2724
	$i = 0;
2725
	while ($i < 10) {
2726
		if (does_interface_exist($ppp['if'], true)) {
2727
			break;
2728
		}
2729
		sleep(3);
2730
		$i++;
2731
	}
2732

    
2733
	/* Remove all temporary bogon IPv4 addresses */
2734
	if (is_array($tempaddr)) {
2735
		foreach ($tempaddr as $tempiface) {
2736
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2737
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2738
			}
2739
		}
2740
		unset ($tempaddr);
2741
	}
2742

    
2743
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2744
	/* We should be able to launch the right version for each modem */
2745
	/* We can also guess the mondev from the manufacturer */
2746
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2747
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2748
	foreach ($ports as $port) {
2749
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2750
			$mondev = substr(basename($port), 0, -1);
2751
			$devlist = glob("/dev/{$mondev}?");
2752
			$mondev = basename(end($devlist));
2753
		}
2754
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2755
			$mondev = substr(basename($port), 0, -1) . "1";
2756
		}
2757
		if ($mondev != '') {
2758
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2759
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2760
		}
2761
	}
2762

    
2763
	return 1;
2764
}
2765

    
2766
function interfaces_sync_setup() {
2767

    
2768
	if (config_get_path('system/developerspew')) {
2769
		$mt = microtime();
2770
		echo "interfaces_sync_setup() being called $mt\n";
2771
	}
2772

    
2773
	if (platform_booting()) {
2774
		echo gettext("Configuring CARP settings...");
2775
		mute_kernel_msgs();
2776
	}
2777

    
2778
	/* suck in configuration items */
2779
	if (!empty(config_get_path('hasync'))) {
2780
		$pfsyncenabled = config_get_path('hasync/pfsyncenabled');
2781
		$pfsyncinterface = config_get_path('hasync/pfsyncinterface');
2782
		$pfsyncpeerip = config_get_path('hasync/pfsyncpeerip');
2783
	}
2784

    
2785
	set_sysctl(array(
2786
		"net.inet.carp.preempt" => "1",
2787
		"net.inet.carp.log" => "1")
2788
	);
2789

    
2790
	if (!empty($pfsyncinterface)) {
2791
		$carp_sync_int = get_real_interface($pfsyncinterface);
2792
	}
2793

    
2794
	/* setup pfsync interface */
2795
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2796
		if (is_ipaddr($pfsyncpeerip)) {
2797
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2798
		} else {
2799
			$syncpeer = "-syncpeer";
2800
		}
2801

    
2802
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2803
		    "{$syncpeer} up");
2804
		mwexec("/sbin/ifconfig pfsync0 -defer");
2805

    
2806
		/*
2807
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2808
		 * cluster carp will come up before pfsync(4) has updated and
2809
		 * so will cause issues for existing sessions.
2810
		 */
2811
		log_error(gettext("waiting for pfsync..."));
2812

    
2813
		$i = 0;
2814
		do {
2815
			sleep(1);
2816
			exec('/sbin/ifconfig pfsync0 | ' .
2817
				 '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2818
				 $rc);
2819
			$i++;
2820
		} while ($rc != 0 && $i <= 30);
2821

    
2822
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2823
		log_error(gettext("Configuring CARP settings finalize..."));
2824
	} else {
2825
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2826
	}
2827

    
2828
	$carplist = get_configured_vip_list('all', VIP_CARP);
2829
	if (is_array($carplist) && count($carplist) > 0) {
2830
		set_single_sysctl("net.inet.carp.allow", "1");
2831
	} else {
2832
		set_single_sysctl("net.inet.carp.allow", "0");
2833
	}
2834

    
2835
	if (platform_booting()) {
2836
		unmute_kernel_msgs();
2837
		echo gettext("done.") . "\n";
2838
	}
2839
}
2840

    
2841
function interface_proxyarp_configure($interface = "") {
2842
	global $g;
2843
	if (config_get_path('system/developerspew')) {
2844
		$mt = microtime();
2845
		echo "interface_proxyarp_configure() being called $mt\n";
2846
	}
2847

    
2848
	/* kill any running choparp */
2849
	if (empty($interface)) {
2850
		killbyname("choparp");
2851
	} else {
2852
		$vipif = get_real_interface($interface);
2853
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2854
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2855
		}
2856
	}
2857

    
2858
	$paa = array();
2859
	$vips = config_get_path('virtualip/vip');
2860
	if (is_array($vips)) {
2861

    
2862
		/* group by interface */
2863
		foreach ($vips as $vipent) {
2864
			if ($vipent['mode'] === "proxyarp") {
2865
				if ($vipent['interface']) {
2866
					$proxyif = $vipent['interface'];
2867
				} else {
2868
					$proxyif = "wan";
2869
				}
2870

    
2871
				if (!empty($interface) && $interface != $proxyif) {
2872
					continue;
2873
				}
2874

    
2875
				if (!is_array($paa[$proxyif])) {
2876
					$paa[$proxyif] = array();
2877
				}
2878

    
2879
				$paa[$proxyif][] = $vipent;
2880
			}
2881
		}
2882
	}
2883

    
2884
	if (!empty($interface)) {
2885
		if (is_array($paa[$interface])) {
2886
			$paaifip = get_interface_ip($interface);
2887
			if (!is_ipaddr($paaifip)) {
2888
				return;
2889
			}
2890
			$vipif = get_real_interface($interface);
2891
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2892
			$args .= $vipif . " auto";
2893
			foreach ($paa[$interface] as $paent) {
2894
				if (isset($paent['subnet'])) {
2895
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2896
				} elseif (isset($paent['range'])) {
2897
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2898
				}
2899
			}
2900
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2901
		}
2902
	} elseif (count($paa) > 0) {
2903
		foreach ($paa as $paif => $paents) {
2904
			$paaifip = get_interface_ip($paif);
2905
			if (!is_ipaddr($paaifip)) {
2906
				continue;
2907
			}
2908
			$vipif = get_real_interface($paif);
2909
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2910
			$args .= $vipif . " auto";
2911
			foreach ($paents as $paent) {
2912
				if (isset($paent['subnet'])) {
2913
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2914
				} elseif (isset($paent['range'])) {
2915
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2916
				}
2917
			}
2918
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2919
		}
2920
	}
2921
}
2922

    
2923
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2924
	$vips = config_get_path('virtualip/vip');
2925
	if (is_array($vips)) {
2926
		foreach ($vips as $vip) {
2927

    
2928
			$iface = $vip['interface'];
2929
			if (substr($iface, 0, 4) == "_vip")
2930
				$iface = get_configured_vip_interface($vip['interface']);
2931
			if ($iface != $interface)
2932
				continue;
2933
			if ($type == VIP_CARP) {
2934
				if ($vip['mode'] != "carp")
2935
					continue;
2936
			} elseif ($type == VIP_IPALIAS) {
2937
				if ($vip['mode'] != "ipalias")
2938
					continue;
2939
			} else {
2940
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2941
					continue;
2942
			}
2943

    
2944
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2945
				interface_vip_bring_down($vip);
2946
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2947
				interface_vip_bring_down($vip);
2948
			elseif ($inet == "all")
2949
				interface_vip_bring_down($vip);
2950
		}
2951
	}
2952
}
2953

    
2954
function interfaces_vips_configure($interface = "") {
2955
	if (config_get_path('system/developerspew')) {
2956
		$mt = microtime();
2957
		echo "interfaces_vips_configure() being called $mt\n";
2958
	}
2959

    
2960
	$vips = config_get_path('virtualip/vip');
2961
	if (!is_array($vips)) {
2962
		return;
2963
	}
2964

    
2965
	$carp_setuped = false;
2966
	$anyproxyarp = false;
2967
	foreach ($vips as $vip) {
2968
		if ($interface <> "" &&
2969
		    get_root_interface($vip['interface']) <> $interface) {
2970
			continue;
2971
		}
2972
		switch ($vip['mode']) {
2973
			case "proxyarp":
2974
				/*
2975
				 * nothing it is handled on
2976
				 * interface_proxyarp_configure()
2977
				 */
2978
				$anyproxyarp = true;
2979
				break;
2980
			case "ipalias":
2981
				interface_ipalias_configure($vip);
2982
				break;
2983
			case "carp":
2984
				if ($carp_setuped == false) {
2985
					$carp_setuped = true;
2986
				}
2987
				interface_carp_configure($vip);
2988
				break;
2989
		}
2990
	}
2991
	if ($carp_setuped == true) {
2992
		interfaces_sync_setup();
2993
	}
2994
	if ($anyproxyarp == true) {
2995
		interface_proxyarp_configure();
2996
	}
2997
}
2998

    
2999
function interface_ipalias_configure(&$vip) {
3000
	$gateway = '';
3001
	if ($vip['mode'] != 'ipalias') {
3002
		return;
3003
	}
3004

    
3005
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3006
	if ($realif != "lo0") {
3007
		$if = convert_real_interface_to_friendly_interface_name($realif);
3008
		if (!config_path_enabled("interfaces/{$if}")) {
3009
			return;
3010
		}
3011
		if (is_pseudo_interface($realif)) {
3012
			if (is_ipaddrv4($vip['subnet'])) {
3013
				$gateway = get_interface_gateway($if);
3014
			} else {
3015
				$gateway = get_interface_gateway_v6($if);
3016
			}
3017
		}
3018
	}
3019

    
3020
	$af = 'inet';
3021
	if (is_ipaddrv6($vip['subnet'])) {
3022
		$af = 'inet6';
3023
	}
3024
	$iface = $vip['interface'];
3025
	$vhid = '';
3026
	if (substr($vip['interface'], 0, 4) == "_vip") {
3027
		$carpvip = get_configured_vip($vip['interface']);
3028
		$iface = $carpvip['interface'];
3029
		$vhid = "vhid {$carpvip['vhid']}";
3030
	}
3031
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3032
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3033
}
3034

    
3035
function interface_carp_configure(&$vip, $maintenancemode_only = false, $ipalias_reload = false) {
3036
	if (config_get_path('system/developerspew')) {
3037
		$mt = microtime();
3038
		echo "interface_carp_configure() being called $mt\n";
3039
	}
3040

    
3041
	if ($vip['mode'] != "carp") {
3042
		return;
3043
	}
3044

    
3045
	$realif = get_real_interface($vip['interface']);
3046
	if (!does_interface_exist($realif)) {
3047
		file_notice("CARP", sprintf(gettext(
3048
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3049
		    $vip['subnet']), "Firewall: Virtual IP", "");
3050
		return;
3051
	}
3052
	if ($realif != "lo0") {
3053
		if (!config_path_enabled("interfaces/{$vip['interface']}")) {
3054
			return;
3055
		}
3056
	}
3057

    
3058
	$vip_password = $vip['password'];
3059
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3060
	    $vip_password)));
3061
	if ($vip['password'] != "") {
3062
		$password = " pass {$vip_password}";
3063
	}
3064

    
3065
	$advbase = "";
3066
	if (!empty($vip['advbase'])) {
3067
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3068
	}
3069

    
3070
	$carp_maintenancemode = config_path_enabled('/','virtualip_carp_maintenancemode');
3071
	if ($carp_maintenancemode) {
3072
		$advskew = "advskew 254";
3073
	} else {
3074
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3075
	}
3076

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

    
3080
	if (!$maintenancemode_only) {
3081
		if (is_ipaddrv4($vip['subnet'])) {
3082
			mwexec("/sbin/ifconfig {$realif} " .
3083
			    escapeshellarg($vip['subnet']) . "/" .
3084
			    escapeshellarg($vip['subnet_bits']) .
3085
			    " alias vhid " . escapeshellarg($vip['vhid']));
3086
		} elseif (is_ipaddrv6($vip['subnet'])) {
3087
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3088
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3089
			    escapeshellarg($vip['subnet_bits']) .
3090
			    " alias vhid " . escapeshellarg($vip['vhid']));
3091
		}
3092
	}
3093

    
3094
	/* reconfigure stacked IP Aliases after CARP VIP changes
3095
	 * see https://redmine.pfsense.org/issues/12227
3096
	 * and https://redmine.pfsense.org/issues/12961 */
3097
	if ($ipalias_reload) {
3098
		foreach (config_get_path('virtualip/vip', []) as $viface) {
3099
			if (($viface['mode'] == 'ipalias') &&
3100
			    (get_root_interface($viface['interface']) == $vip['interface'])) {
3101
				interface_vip_bring_down($viface);
3102
				interface_ipalias_configure($viface);
3103
			}
3104
		}
3105
	}
3106

    
3107
	return $realif;
3108
}
3109

    
3110
function interface_wireless_clone($realif, $wlcfg) {
3111
	global $g;
3112
	/*   Check to see if interface has been cloned as of yet.
3113
	 *   If it has not been cloned then go ahead and clone it.
3114
	 */
3115
	$needs_clone = false;
3116
	if (is_array($wlcfg['wireless'])) {
3117
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3118
	} else {
3119
		$wlcfg_mode = $wlcfg['mode'];
3120
	}
3121
	switch ($wlcfg_mode) {
3122
		case "hostap":
3123
			$mode = "wlanmode hostap";
3124
			break;
3125
		case "adhoc":
3126
			$mode = "wlanmode adhoc";
3127
			break;
3128
		default:
3129
			$mode = "";
3130
			break;
3131
	}
3132
	$baseif = interface_get_wireless_base($wlcfg['if']);
3133
	if (does_interface_exist($realif)) {
3134
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3135
		$ifconfig_str = implode($output);
3136
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3137
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3138
			$needs_clone = true;
3139
		}
3140
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3141
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3142
			$needs_clone = true;
3143
		}
3144
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3145
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3146
			$needs_clone = true;
3147
		}
3148
	} else {
3149
		$needs_clone = true;
3150
	}
3151

    
3152
	if ($needs_clone == true) {
3153
		/* remove previous instance if it exists */
3154
		if (does_interface_exist($realif)) {
3155
			pfSense_interface_destroy($realif);
3156

    
3157
			/* Invalidate cache */
3158
			get_interface_arr(true);
3159
		}
3160

    
3161
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3162
		// Create the new wlan interface. FreeBSD returns the new interface name.
3163
		// example:  wlan2
3164
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3165
		if ($ret <> 0) {
3166
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3167
			return false;
3168
		}
3169
		$newif = trim($out[0]);
3170
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3171
		pfSense_interface_rename($newif, $realif);
3172
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3173
	}
3174
	return true;
3175
}
3176

    
3177
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3178

    
3179
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3180
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3181
				 'regdomain', 'regcountry', 'reglocation');
3182

    
3183
	if (!is_interface_wireless($ifcfg['if'])) {
3184
		return;
3185
	}
3186

    
3187
	$baseif = interface_get_wireless_base($ifcfg['if']);
3188

    
3189
	// Sync shared settings for assigned clones
3190
	$iflist = get_configured_interface_list(true);
3191
	foreach ($iflist as $if) {
3192
		if (($baseif == interface_get_wireless_base(config_get_path("interfaces/{$if}/if"))) &&
3193
			($ifcfg['if'] != config_get_path("interfaces/{$if}/if"))) {
3194
			if (config_path_enabled("interfaces/{$if}/wireless", 'standard') || $sync_changes) {
3195
				foreach ($shared_settings as $setting) {
3196
					if ($sync_changes) {
3197
						if (isset($ifcfg['wireless'][$setting])) {
3198
							config_set_path("interfaces/{$if}/wireless/{$setting}",
3199
											$ifcfg['wireless'][$setting]);
3200
						} elseif (!empty(config_get_path("interfaces/{$if}/wireless/{$setting}"))) {
3201
							config_del_path("interfaces/{$if}/wireless/{$setting}");
3202
						}
3203
					} else {
3204
						if (!empty(config_get_path("interfaces/{$if}/wireless/{$setting}"))) {
3205
							$ifcfg['wireless'][$setting] =
3206
							    config_get_path("interfaces/{$if}/wireless/{$setting}");
3207
						} elseif (isset($ifcfg['wireless'][$setting])) {
3208
							unset($ifcfg['wireless'][$setting]);
3209
						}
3210
					}
3211
				}
3212
				if (!$sync_changes) {
3213
					break;
3214
				}
3215
			}
3216
		}
3217
	}
3218

    
3219
	// Read or write settings at shared area
3220
	if (!empty(config_get_path("wireless/interfaces/{$baseif}"))) {
3221
		foreach ($shared_settings as $setting) {
3222
			if ($sync_changes) {
3223
				if (isset($ifcfg['wireless'][$setting])) {
3224
					config_set_path("wireless/interfaces/{$baseif}/{$setting}",
3225
									$ifcfg['wireless'][$setting]);
3226
				} elseif (!empty(config_get_path("wireless/interfaces/{$baseif}/{$setting}"))) {
3227
					config_del_path("wireless/interfaces/{$baseif}/{$setting}");
3228
				}
3229
			} else {
3230
				if (!empty(config_get_path("wireless/interfaces/{$baseif}/{$setting}"))) {
3231
					$ifcfg['wireless'][$setting] = config_get_path("wireless/interfaces/{$baseif}/{$setting}");
3232
				} elseif (isset($ifcfg['wireless'][$setting])) {
3233
					unset($ifcfg['wireless'][$setting]);
3234
				}
3235
			}
3236
		}
3237
	}
3238

    
3239
	// Sync the mode on the clone creation page with the configured mode on the interface
3240
	if (interface_is_wireless_clone($ifcfg['if'])) {
3241
		foreach (config_get_path('wireless/clone', []) as $key => $clone) {
3242
			if ($clone['cloneif'] == $ifcfg['if']) {
3243
				if ($sync_changes) {
3244
					config_set_path("wireless/clone/{$key}/mode", $ifcfg['wireless']['mode']);
3245
				} else {
3246
					$ifcfg['wireless']['mode'] = $clone['mode'];
3247
				}
3248
				break;
3249
			}
3250
		}
3251
		unset($clone);
3252
	}
3253
}
3254

    
3255
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3256
	global $g;
3257

    
3258
	/*    open up a shell script that will be used to output the commands.
3259
	 *    since wireless is changing a lot, these series of commands are fragile
3260
	 *    and will sometimes need to be verified by a operator by executing the command
3261
	 *    and returning the output of the command to the developers for inspection.  please
3262
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3263
	 */
3264

    
3265
	// Remove script file
3266
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3267

    
3268
	// Clone wireless nic if needed.
3269
	interface_wireless_clone($if, $wl);
3270

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

    
3274
	$fd_set = fopen("{$g['tmp_path']}/{$if}_setup.sh", "w");
3275
	fwrite($fd_set, "#!/bin/sh\n");
3276
	fwrite($fd_set, "# {$g['product_label']} wireless configuration script.\n\n");
3277

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

    
3280
	/* set values for /path/program */
3281
	if (file_exists("/usr/local/sbin/hostapd")) {
3282
		$hostapd = "/usr/local/sbin/hostapd";
3283
	} else {
3284
		$hostapd = "/usr/sbin/hostapd";
3285
	}
3286
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3287
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3288
	} else {
3289
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3290
	}
3291
	$ifconfig = "/sbin/ifconfig";
3292
	$sysctl = "/sbin/sysctl";
3293
	$sysctl_args = "-q";
3294

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

    
3297
	$wlcmd = array();
3298
	$wl_sysctl = array();
3299
	/* Set a/b/g standard */
3300
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3301
	/* skip mode entirely for "auto" */
3302
	if ($wlcfg['standard'] != "auto") {
3303
		$wlcmd[] = "mode " . escapeshellarg($standard);
3304
	}
3305

    
3306
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3307
	 * to prevent massive packet loss under certain conditions. */
3308
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3309
		$wlcmd[] = "-ampdu";
3310
	}
3311

    
3312
	/* Set ssid */
3313
	if ($wlcfg['ssid']) {
3314
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3315
	}
3316

    
3317
	/* Set 802.11g protection mode */
3318
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3319

    
3320
	/* set wireless channel value */
3321
	if (isset($wlcfg['channel'])) {
3322
		if ($wlcfg['channel'] == "0") {
3323
			$wlcmd[] = "channel any";
3324
		} else {
3325
			if ($wlcfg['channel_width'] != "0") {
3326
				$channel_width = ":" . $wlcfg['channel_width'];
3327
			} else {
3328
				$channel_width = '';
3329
			}
3330
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3331
		}
3332
	}
3333

    
3334
	/* Set antenna diversity value */
3335
	if (isset($wlcfg['diversity'])) {
3336
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3337
	}
3338

    
3339
	/* Set txantenna value */
3340
	if (isset($wlcfg['txantenna'])) {
3341
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3342
	}
3343

    
3344
	/* Set rxantenna value */
3345
	if (isset($wlcfg['rxantenna'])) {
3346
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3347
	}
3348

    
3349
	/* set Distance value */
3350
	if ($wlcfg['distance']) {
3351
		$distance = escapeshellarg($wlcfg['distance']);
3352
	}
3353

    
3354
	/* Set wireless hostap mode */
3355
	if ($wlcfg['mode'] == "hostap") {
3356
		$wlcmd[] = "mediaopt hostap";
3357
	} else {
3358
		$wlcmd[] = "-mediaopt hostap";
3359
	}
3360

    
3361
	/* Set wireless adhoc mode */
3362
	if ($wlcfg['mode'] == "adhoc") {
3363
		$wlcmd[] = "mediaopt adhoc";
3364
	} else {
3365
		$wlcmd[] = "-mediaopt adhoc";
3366
	}
3367

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

    
3370
	/* handle hide ssid option */
3371
	if (isset($wlcfg['hidessid']['enable'])) {
3372
		$wlcmd[] = "hidessid";
3373
	} else {
3374
		$wlcmd[] = "-hidessid";
3375
	}
3376

    
3377
	/* handle pureg (802.11g) only option */
3378
	if (isset($wlcfg['pureg']['enable'])) {
3379
		$wlcmd[] = "mode 11g pureg";
3380
	} else {
3381
		$wlcmd[] = "-pureg";
3382
	}
3383

    
3384
	/* handle puren (802.11n) only option */
3385
	if (isset($wlcfg['puren']['enable'])) {
3386
		$wlcmd[] = "puren";
3387
	} else {
3388
		$wlcmd[] = "-puren";
3389
	}
3390

    
3391
	/* enable apbridge option */
3392
	if (isset($wlcfg['apbridge']['enable'])) {
3393
		$wlcmd[] = "apbridge";
3394
	} else {
3395
		$wlcmd[] = "-apbridge";
3396
	}
3397

    
3398
	/* handle turbo option */
3399
	if (isset($wlcfg['turbo']['enable'])) {
3400
		$wlcmd[] = "mediaopt turbo";
3401
	} else {
3402
		$wlcmd[] = "-mediaopt turbo";
3403
	}
3404

    
3405
	/* handle txpower setting */
3406
	// or don't. this has issues at the moment.
3407
	/*
3408
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3409
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3410
	}*/
3411

    
3412
	/* handle wme option */
3413
	if (isset($wlcfg['wme']['enable'])) {
3414
		$wlcmd[] = "wme";
3415
	} else {
3416
		$wlcmd[] = "-wme";
3417
	}
3418

    
3419
	/* Enable wpa if it's configured. No WEP support anymore. */
3420
	if (isset($wlcfg['wpa']['enable'])) {
3421
		$wlcmd[] = "authmode wpa wepmode off ";
3422
	} else {
3423
		$wlcmd[] = "authmode open wepmode off ";
3424
	}
3425

    
3426
	kill_hostapd($if);
3427
	mwexec(kill_wpasupplicant("{$if}"));
3428

    
3429
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3430
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3431

    
3432
	unlink_if_exists("{$wpa_supplicant_file}*");
3433
	unlink_if_exists($hostapd_conf);
3434

    
3435
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3436
	$wpa = "";
3437
	switch ($wlcfg['mode']) {
3438
		case 'bss':
3439
			if (isset($wlcfg['wpa']['enable'])) {
3440
				$wpa .= <<<EOD
3441
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3442
ctrl_interface_group=0
3443
ap_scan=1
3444
#fast_reauth=1
3445
network={
3446
ssid="{$wlcfg['ssid']}"
3447
scan_ssid=1
3448
priority=5
3449
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3450
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3451
group={$wlcfg['wpa']['wpa_pairwise']}
3452

    
3453
EOD;
3454
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3455
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3456
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3457
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3458
							$wpa .= "phase1=\"peaplabel=0\"\n";
3459
						}
3460
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3461
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3462
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3463
						$wpa .= "password=\"{$eappass}\"\n";
3464
					}
3465
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) {
3466
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3467
						$wpa_supplicant_crt = $wpa_supplicant_file . "crt";
3468
						$wpa_supplicant_key = $wpa_supplicant_file . "key";
3469
						@file_put_contents($wpa_supplicant_crt, base64_decode($cert['crt']) . "\n" .
3470
						    ca_chain($cert));
3471
						@file_put_contents($wpa_supplicant_key, base64_decode($cert['prv']));
3472
						@chmod($wpa_supplicant_crt, 0600);
3473
						@chmod($wpa_supplicant_key, 0600);
3474
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3475
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3476
					}
3477
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3478
					$wpa_supplicant_ca = $wpa_supplicant_file . "ca";
3479
					@file_put_contents($wpa_supplicant_ca, base64_decode($ca['crt']) . "\n" .
3480
					    ca_chain($ca));
3481
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3482
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3483
				} else {
3484
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3485
				}
3486
				$wpa .= "}\n";
3487

    
3488
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3489
				unset($wpa);
3490
			}
3491
			break;
3492
		case 'hostap':
3493
			if (!empty($wlcfg['wpa']['passphrase'])) {
3494
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3495
			} else {
3496
				$wpa_passphrase = "";
3497
			}
3498
			if (isset($wlcfg['wpa']['enable'])) {
3499
				$wpa .= <<<EOD
3500
interface={$if}
3501
driver=bsd
3502
logger_syslog=-1
3503
logger_syslog_level=0
3504
logger_stdout=-1
3505
logger_stdout_level=0
3506
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3507
ctrl_interface={$g['varrun_path']}/hostapd
3508
ctrl_interface_group=wheel
3509
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3510
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3511
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3512
ssid={$wlcfg['ssid']}
3513
debug={$wlcfg['wpa']['debug_mode']}
3514
wpa={$wlcfg['wpa']['wpa_mode']}
3515
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3516
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3517
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3518
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3519
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3520
{$wpa_passphrase}
3521

    
3522
EOD;
3523

    
3524
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3525
					$wpa .= <<<EOD
3526
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3527
rsn_preauth=1
3528
rsn_preauth_interfaces={$if}
3529

    
3530
EOD;
3531
				}
3532
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3533
					$wpa .= "ieee8021x=1\n";
3534

    
3535
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3536
						$auth_server_port = "1812";
3537
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3538
							$auth_server_port = intval($wlcfg['auth_server_port']);
3539
						}
3540
						$wpa .= <<<EOD
3541

    
3542
auth_server_addr={$wlcfg['auth_server_addr']}
3543
auth_server_port={$auth_server_port}
3544
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3545

    
3546
EOD;
3547
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3548
							$auth_server_port2 = "1812";
3549
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3550
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3551
							}
3552

    
3553
							$wpa .= <<<EOD
3554
auth_server_addr={$wlcfg['auth_server_addr2']}
3555
auth_server_port={$auth_server_port2}
3556
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3557

    
3558
EOD;
3559
						}
3560
					}
3561
				}
3562

    
3563
				@file_put_contents($hostapd_conf, $wpa);
3564
				unset($wpa);
3565
			}
3566
			break;
3567
	}
3568

    
3569
	/*
3570
	 *    all variables are set, lets start up everything
3571
	 */
3572

    
3573
	$baseif = interface_get_wireless_base($if);
3574
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3575
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3576

    
3577
	/* set sysctls for the wireless interface */
3578
	if (!empty($wl_sysctl)) {
3579
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3580
		foreach ($wl_sysctl as $wl_sysctl_line) {
3581
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3582
		}
3583
	}
3584

    
3585
	/* set ack timers according to users preference (if he/she has any) */
3586
	if ($distance) {
3587
		fwrite($fd_set, "# Enable ATH distance settings\n");
3588
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3589
	}
3590

    
3591
	if (isset($wlcfg['wpa']['enable'])) {
3592
		if ($wlcfg['mode'] == "bss") {
3593
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3594
		}
3595
		if ($wlcfg['mode'] == "hostap") {
3596
			/* add line to script to restore old mac to make hostapd happy */
3597
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3598
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3599
				$if_curmac = get_interface_mac($if);
3600
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3601
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3602
						" link " . escapeshellarg($if_oldmac) . "\n");
3603
				}
3604
			}
3605

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

    
3608
			/* add line to script to restore spoofed mac after running hostapd */
3609
			if ($wl['spoofmac']) {
3610
				$if_curmac = get_interface_mac($if);
3611
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3612
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3613
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3614
				}
3615
			}
3616
		}
3617
	}
3618

    
3619
	fclose($fd_set);
3620

    
3621
	/* Making sure regulatory settings have actually changed
3622
	 * before applying, because changing them requires bringing
3623
	 * down all wireless networks on the interface. */
3624
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3625
	$ifconfig_str = implode($output);
3626
	unset($output);
3627
	$reg_changing = false;
3628

    
3629
	/* special case for the debug country code */
3630
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3631
		$reg_changing = true;
3632
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3633
		$reg_changing = true;
3634
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3635
		$reg_changing = true;
3636
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3637
		$reg_changing = true;
3638
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3639
		$reg_changing = true;
3640
	}
3641

    
3642
	if ($reg_changing) {
3643
		/* set regulatory domain */
3644
		if ($wlcfg['regdomain']) {
3645
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3646
		}
3647

    
3648
		/* set country */
3649
		if ($wlcfg['regcountry']) {
3650
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3651
		}
3652

    
3653
		/* set location */
3654
		if ($wlcfg['reglocation']) {
3655
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3656
		}
3657

    
3658
		$wlregcmd_args = implode(" ", $wlregcmd);
3659

    
3660
		/* build a complete list of the wireless clones for this interface */
3661
		$clone_list = array();
3662
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3663
			$clone_list[] = interface_get_wireless_clone($baseif);
3664
		}
3665
		foreach (config_get_path('wireless/clone', []) as $clone) {
3666
			if ($clone['if'] == $baseif) {
3667
				$clone_list[] = $clone['cloneif'];
3668
			}
3669
		}
3670

    
3671
		/* find which clones are up and bring them down */
3672
		$clones_up = array();
3673
		foreach ($clone_list as $clone_if) {
3674
			$clone_status = get_interface_addresses($clone_if);
3675
			if ($clone_status['status'] == 'up') {
3676
				$clones_up[] = $clone_if;
3677
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3678
			}
3679
		}
3680

    
3681
		/* apply the regulatory settings */
3682
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3683
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3684

    
3685
		/* bring the clones back up that were previously up */
3686
		foreach ($clones_up as $clone_if) {
3687
			interfaces_bring_up($clone_if);
3688

    
3689
			/*
3690
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3691
			 * is in infrastructure mode, and WPA is enabled.
3692
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3693
			 */
3694
			if ($clone_if != $if) {
3695
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3696
				if ((!empty($friendly_if)) &&
3697
				    (config_get_path("interfaces/{$friendly_if}/wireless/mode") == "bss") &&
3698
				    config_path_enabled("interfaces/{$friendly_if}/wireless/wpa")) {
3699
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3700
				}
3701
			}
3702
		}
3703
	}
3704

    
3705
	/* The mode must be specified in a separate command before ifconfig
3706
	 * will allow the mode and channel at the same time in the next.
3707
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3708
	 */
3709
	if ($wlcfg['mode'] == "hostap") {
3710
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3711
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3712
	}
3713

    
3714
	/* configure wireless */
3715
	$wlcmd_args = implode(" ", $wlcmd);
3716
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3717
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3718
	/* Bring the interface up only after setting up all the other parameters. */
3719
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3720
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3721
	fclose($wlan_setup_log);
3722

    
3723
	unset($wlcmd_args, $wlcmd);
3724

    
3725

    
3726
	sleep(1);
3727
	/* execute hostapd and wpa_supplicant if required in shell */
3728
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3729

    
3730
	return 0;
3731

    
3732
}
3733

    
3734
function kill_hostapd($interface) {
3735
	global $g;
3736

    
3737
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3738
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3739
	}
3740
}
3741

    
3742
function kill_wpasupplicant($interface) {
3743
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3744
}
3745

    
3746
function find_dhclient_process($interface) {
3747
	if ($interface) {
3748
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3749
	} else {
3750
		$pid = 0;
3751
	}
3752

    
3753
	return intval($pid);
3754
}
3755

    
3756
function kill_dhclient_process($interface) {
3757
	if (empty($interface) || !does_interface_exist($interface)) {
3758
		return;
3759
	}
3760

    
3761
	$i = 0;
3762
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3763
		/* 3rd time make it die for sure */
3764
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3765
		posix_kill($pid, $sig);
3766
		sleep(1);
3767
		$i++;
3768
	}
3769
	unset($i);
3770
}
3771

    
3772
function find_dhcp6c_process() {
3773
	global $g;
3774

    
3775
	if (isvalidpid("{$g['varrun_path']}/dhcp6c.pid")) {
3776
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c.pid"), " \n");
3777
	} else {
3778
		return(false);
3779
	}
3780

    
3781
	return intval($pid);
3782
}
3783

    
3784
function kill_dhcp6client_process($force, $release = false) {
3785
	global $g;
3786

    
3787
	$i = 0;
3788

    
3789
	/*
3790
	Beware of the following: Reason, the interface may be down, but
3791
	dhcp6c may still be running, it just complains it cannot send
3792
	and carries on. Commented out as will stop the call to kill.
3793

    
3794
	if (empty($interface) || !does_interface_exist($interface)) {
3795
		return;
3796
	}
3797
	*/
3798

    
3799
	/*********** Notes on signals for dhcp6c and this function *************
3800

    
3801
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3802
	a release and waiting for the response that never comes.
3803
	So we need to tell it that the interface is down and to just die quickly
3804
	otherwise a new client may launch and we have duplicate processes.
3805
	In this case use SIGUSR1.
3806

    
3807
	If we want to exit normally obeying the no release flag then use SIGTERM.
3808
	If we want to exit with a release overriding the no release flag then
3809
	use SIGUSR2.
3810

    
3811
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3812
	exit quickly without sending release signals.
3813

    
3814
	If $Force is set to false and $release is also set to false dhcp6c will
3815
	follow the no-release flag.
3816

    
3817
	If $Force is set to false and $release is true then dhcp6c will send a
3818
	release regardless of the no-release flag.
3819
	***********************************************************************/
3820

    
3821
	if ($force == true) {
3822
		$psig=SIGUSR1;
3823
	} elseif ($release == false) {
3824
		$psig=SIGTERM;
3825
	} else {
3826
		$psig=SIGUSR2;
3827
	}
3828

    
3829
	while ((($pid = find_dhcp6c_process()) != 0) && ($i < 3)) {
3830
		/* 3rd time make it die for sure */
3831
		$sig = ($i == 2 ? SIGKILL : $psig);
3832
		posix_kill($pid, $sig);
3833
		sleep(1);
3834
		$i++;
3835
	}
3836
	/* Clear the RTSOLD script created lock & tidy up */
3837
	unlink_if_exists("/tmp/dhcp6c_lock");
3838
	unlink_if_exists("{$g['varrun_path']}/dhcp6c.pid"); // just in case!
3839
}
3840
function reset_dhcp6client_process() {
3841

    
3842
	$pid = find_dhcp6c_process();
3843

    
3844
	if($pid != 0) {
3845
		posix_kill($pid, SIGHUP);
3846
	}
3847
}
3848

    
3849
function run_dhcp6client_process($interfaces, $debugOption, $noreleaseOption) {
3850
	global $g;
3851

    
3852
	/*
3853
	 * Only run this if the lock does not exist. In theory the lock being
3854
	 * there in this mode means the user has selected dhcp6withoutRA while
3855
	 * a session is active in the other mode.
3856
	 *
3857
	 * It should not happen as the process should have been killed and the
3858
	 * lock deleted.
3859
	 */
3860

    
3861
	if (!file_exists("/tmp/dhcp6c_lock")) {
3862
		kill_dhcp6client_process(true);
3863
		/* Lock it to avoid multiple runs */
3864
		touch("/tmp/dhcp6c_lock");
3865
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3866
		    "{$noreleaseOption} " .
3867
		    "-c {$g['varetc_path']}/dhcp6c.conf " .
3868
		    "-p {$g['varrun_path']}/dhcp6c.pid " .
3869
		    implode(' ', $interfaces));
3870
		log_error(sprintf(gettext(
3871
		    "Starting DHCP6 client for interfaces %s in DHCP6 without RA mode"),
3872
		    implode(',', $interfaces)));
3873
	}
3874
}
3875

    
3876
function interface_virtual_create($interface, $gateways_status = false) {
3877

    
3878
	/* Fetch gateway status if not passed */
3879
	if (!is_array($gateways_status)) {
3880
		$gateways_status = return_gateways_status(true);
3881
	}
3882

    
3883
	if (interface_is_vlan($interface) != NULL) {
3884
		interface_vlan_configure(interface_is_vlan($interface));
3885
	} elseif (substr($interface, 0, 3) == "gre") {
3886
		interfaces_tunnel_configure(0, $interface, 'gre');
3887
	} elseif (substr($interface, 0, 3) == "gif") {
3888
		interfaces_tunnel_configure(0, $interface, 'gif');
3889
	} elseif (substr($interface, 0, 5) == "ovpns") {
3890
		foreach (config_get_path('openvpn/openvpn-server', []) as $server) {
3891
			if ($interface == "ovpns{$server['vpnid']}") {
3892
				if (!function_exists('openvpn_resync')) {
3893
					require_once('openvpn.inc');
3894
				}
3895
				log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3896
				openvpn_resync('server', $server);
3897
			}
3898
		}
3899
		unset($server);
3900
	} elseif (substr($interface, 0, 5) == "ovpnc") {
3901
		foreach (config_get_path('openvpn/openvpn-client', []) as $client) {
3902
			if ($interface == "ovpnc{$client['vpnid']}") {
3903
				if (!function_exists('openvpn_resync')) {
3904
					require_once('openvpn.inc');
3905
				}
3906
				log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3907
				openvpn_resync('client', $client);
3908
			}
3909
		}
3910
		unset($client);
3911
	} elseif (substr($interface, 0, 5) == "ipsec") {
3912
		foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
3913
			if ($ph1ent['disabled']) {
3914
				continue;
3915
			}
3916
			interface_ipsec_vti_configure($ph1ent, $gateways_status);
3917
		}
3918
	} elseif (substr($interface, 0, 4) == "lagg") {
3919
		interfaces_lagg_configure($interface);
3920
	} elseif (substr($interface, 0, 6) == "bridge") {
3921
		interfaces_bridge_configure(0, $interface);
3922
	}
3923
}
3924

    
3925
function interface_vlan_mtu_configured($iface) {
3926

    
3927
	$mtu = 0;
3928
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
3929

    
3930
		if ($vlan['vlanif'] != $iface)
3931
			continue;
3932

    
3933
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3934
		$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
3935
		if (!empty($assignedport) && !empty(config_get_path("interfaces/{$assignedport}/mtu"))) {
3936
			/* VLAN MTU */
3937
			$mtu = config_get_path("interfaces/{$assignedport}/mtu");
3938
		} elseif (!empty(config_get_path("interfaces/{$parentinf}/mtu"))) {
3939
			/* Parent MTU */
3940
			$mtu = config_get_path("interfaces/{$parentinf}/mtu");
3941
		}
3942
	}
3943

    
3944
	return $mtu;
3945
}
3946

    
3947
function interface_mtu_wanted_for_pppoe($realif) {
3948

    
3949
	$mtu = 0;
3950
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
3951
		if ($ppp['type'] != "pppoe") {
3952
			continue;
3953
		}
3954

    
3955
		$mtus = array();
3956
		if (!empty($ppp['mtu'])) {
3957
			$mtus = explode(',', $ppp['mtu']);
3958
		}
3959
		$ports = explode(',', $ppp['ports']);
3960

    
3961
		foreach ($ports as $pid => $port) {
3962
			$parentifa = get_parent_interface($port);
3963
			$parentif = $parentifa[0];
3964
			if ($parentif != $realif)
3965
				continue;
3966

    
3967
			// there is an MTU configured on the port in question
3968
			if (!empty($mtus[$pid])) {
3969
				$mtu = intval($mtus[$pid]) + 8;
3970
			// or use the MTU configured on the interface ...
3971
			} else {
3972
				foreach (config_get_path('interfaces', []) as $interface) {
3973
					if ($interface['if'] == $ppp['if'] &&
3974
					    !empty($interface['mtu'])) {
3975
						$mtu = intval($interface['mtu']) + 8;
3976
						break;
3977
					}
3978
				}
3979
			}
3980
		}
3981
	}
3982

    
3983
	return $mtu;
3984
}
3985

    
3986
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3987
	global $g;
3988
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3989
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3990

    
3991
	$wancfg = config_get_path("interfaces/{$interface}");
3992

    
3993
	if (!isset($wancfg['enable'])) {
3994
		return;
3995
	}
3996

    
3997
	$realif = get_real_interface($interface);
3998
	$realhwif_array = get_parent_interface($interface);
3999
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4000
	$realhwif = $realhwif_array[0];
4001

    
4002
	$mac_if_cfg = $wancfg;
4003
	if (interface_is_vlan($realif)) {
4004
		$mac_if = convert_real_interface_to_friendly_interface_name(
4005
		    $realhwif);
4006
		if (is_array(config_get_path("interfaces/{$mac_if}"))) {
4007
			$mac_if_cfg = config_get_path("interfaces/{$mac_if}");
4008
		} else {
4009
			$mac_if = $interface;
4010
		}
4011
	}
4012

    
4013
	if (!platform_booting() && (substr($realif, 0, 4) != "ovpn") && (substr($realif, 0, 5) != "ipsec")) {
4014
		/* remove all IPv4 and IPv6 addresses */
4015
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4016
		if (is_array($tmpifaces)) {
4017
			foreach ($tmpifaces as $tmpiface) {
4018
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4019
					if (!is_linklocal($tmpiface)) {
4020
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4021
					}
4022
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4023
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4024
				} else {
4025
					if (is_subnetv4($tmpiface)) {
4026
						$tmpip = explode('/', $tmpiface);
4027
						$tmpip = $tmpip[0];
4028
					} else {
4029
						$tmpip = $tmpiface;
4030
					}
4031
					pfSense_interface_deladdress($realif, $tmpip);
4032
				}
4033
			}
4034
		}
4035

    
4036
		/* only bring down the interface when both v4 and v6 are set to NONE */
4037
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4038
			interface_bring_down($interface);
4039
		}
4040
	}
4041

    
4042
	$interface_to_check = $realif;
4043
	if (interface_isppp_type($interface)) {
4044
		$interface_to_check = $realhwif;
4045
	}
4046

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

    
4053
	/* Disable Accepting router advertisements unless specifically requested */
4054
	if (g_get('debug')) {
4055
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4056
	}
4057
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4058
	{
4059
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4060
	}
4061
	/* wireless configuration? */
4062
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4063
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4064
	}
4065

    
4066
	$current_mac = get_interface_mac($realhwif);
4067
	$vendor_mac = get_interface_vendor_mac($realhwif);
4068

    
4069
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4070
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4071

    
4072
		interface_set_macaddr($realhwif, $mac_addr);
4073

    
4074
		/* Regenerate link-local address on MAC change.
4075
		 *
4076
		 * Some network devices respond to a DHCPv6 Solicit message only when
4077
		 * the IPv6 source address is consistent with what they expect.
4078
		 *
4079
		 * See https://redmine.pfsense.org/issues/12794 */
4080
		if ($mac_addr != $current_mac) {
4081
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 ifdisabled");
4082
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 " . get_interface_linklocal($interface) . " delete");
4083
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -ifdisabled");
4084
		}
4085
	} else {
4086
		/*
4087
		 * this is not a valid mac address.  generate a
4088
		 * temporary mac address so the machine can get online.
4089
		 */
4090
		echo gettext("Generating new MAC address.");
4091
		$random_mac = generate_random_mac_address();
4092
		interface_set_macaddr($realhwif, $random_mac);
4093
		config_set_path("interfaces/{$mac_if}/spoofmac", $random_mac);
4094
		write_config(sprintf(gettext('The invalid MAC address ' .
4095
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4096
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4097
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4098
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4099
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4100
		    $random_mac), "Interfaces");
4101
	}
4102

    
4103
	/* media */
4104
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4105
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4106
		if ($wancfg['media']) {
4107
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4108
		}
4109
		if ($wancfg['mediaopt']) {
4110
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4111
		}
4112
		mwexec($cmd);
4113
	}
4114

    
4115
	/* Apply hw offloading policies as configured */
4116
	enable_hardware_offloading($interface);
4117

    
4118
	/* invalidate interface/ip/sn cache */
4119
	get_interface_arr(true);
4120
	unset($interface_ip_arr_cache[$realif]);
4121
	unset($interface_sn_arr_cache[$realif]);
4122
	unset($interface_ipv6_arr_cache[$realif]);
4123
	unset($interface_snv6_arr_cache[$realif]);
4124

    
4125
	$tunnelif = substr($realif, 0, 3);
4126

    
4127
	$mtuif = $realif;
4128
	$mtuhwif = $realhwif;
4129

    
4130
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4131
	if (interface_isppp_type($interface)) {
4132
		$mtuif = $realhwif;
4133
		$mtuhwif_array = get_parent_interface($mtuif);
4134
		$mtuhwif = $mtuhwif_array[0];
4135
	}
4136

    
4137
	$wantedmtu = 0;
4138
	foreach (config_get_path('interfaces', []) as $tmpinterface) {
4139
		if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4140
			$wantedmtu = $tmpinterface['mtu'];
4141
			break;
4142
		}
4143
	}
4144

    
4145
	/* MTU is not specified for interface, try the pppoe settings. */
4146
	if ($wantedmtu == 0) {
4147
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4148
	}
4149
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4150
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4151
	}
4152
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4153
		/* set MTU to 1400 for GRE over IPsec */
4154
		if (is_greipsec($mtuif)) {
4155
			$wantedmtu = 1400;
4156
		} else {
4157
			$wantedmtu = 1476;
4158
		}
4159
	}
4160
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4161
		$wantedmtu = 1280;
4162
	}
4163

    
4164
	/* Set the MTU to 1500 if no explicit MTU configured. */
4165
	if ($wantedmtu == 0) {
4166
		$wantedmtu = 1500; /* Default */
4167
	}
4168

    
4169
	if (interface_is_vlan($mtuif) != NULL) {
4170
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4171
		if (!empty($assignedparent) && !empty(config_get_path("interfaces/{$assignedparent}/mtu"))) {
4172
			$parentmtu = config_get_path("interfaces/{$assignedparent}/mtu");
4173
			if ($wancfg['mtu'] > $parentmtu) {
4174
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4175
			}
4176
		}
4177

    
4178
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4179

    
4180
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4181
			$configuredmtu = $parentmtu;
4182
		if ($configuredmtu != 0)
4183
			$mtu = $configuredmtu;
4184
		else
4185
			$mtu = $wantedmtu;
4186

    
4187
		/* Set the parent MTU. */
4188
		if (get_interface_mtu($mtuhwif) < $mtu)
4189
			set_interface_mtu($mtuhwif, $mtu);
4190
		/* Set the VLAN MTU. */
4191
		if (get_interface_mtu($mtuif) != $mtu)
4192
			set_interface_mtu($mtuif, $mtu);
4193
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4194
		/* LAGG interface must be destroyed and re-created to change MTU */
4195
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4196
			foreach (config_get_path('laggs/lagg', []) as $lagg) {
4197
				if ($lagg['laggif'] == $mtuif) {
4198
					interface_lagg_configure($lagg);
4199
					break;
4200
				}
4201
			}
4202
		}
4203
	} else {
4204
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4205
			pfSense_interface_mtu($mtuif, $wantedmtu);
4206
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4207
		}
4208
	}
4209
	/* XXX: What about gre/gif/.. ? */
4210

    
4211
	if (does_interface_exist($wancfg['if'])) {
4212
		interfaces_bring_up($wancfg['if']);
4213
	}
4214

    
4215
	switch ($wancfg['ipaddr']) {
4216
		case 'dhcp':
4217
			interface_dhcp_configure($interface);
4218
			break;
4219
		case 'pppoe':
4220
		case 'l2tp':
4221
		case 'pptp':
4222
		case 'ppp':
4223
			interface_ppps_configure($interface);
4224
			break;
4225
		default:
4226
			/* XXX: Kludge for now related to #3280 */
4227
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4228
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4229
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4230
				}
4231
			}
4232
			break;
4233
	}
4234

    
4235
	switch ($wancfg['ipaddrv6']) {
4236
		case 'slaac':
4237
		case 'dhcp6':
4238
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4239
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4240
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4241
			log_error(gettext("calling interface_dhcpv6_configure."));
4242
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4243
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4244
			    !interface_isppp_type($interface)) {
4245
				interface_dhcpv6_configure($interface, $wancfg);
4246
			}
4247
			break;
4248
		case '6rd':
4249
			interface_6rd_configure($interface, $wancfg);
4250
			break;
4251
		case '6to4':
4252
			interface_6to4_configure($interface, $wancfg);
4253
			break;
4254
		case 'track6':
4255
			interface_track6_configure($interface, $wancfg, $linkupevent);
4256
			break;
4257
		default:
4258
			/* XXX: Kludge for now related to #3280 */
4259
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4260
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4261
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4262
					// FIXME: Add IPv6 Support to the pfSense module
4263
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4264
				}
4265
			}
4266
			break;
4267
	}
4268

    
4269
	if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4270
		$bridgetmp = link_interface_to_bridge($interface);
4271
		if (!empty($bridgetmp)) {
4272
			interface_bridge_add_member($bridgetmp, $realif);
4273
		}
4274
	}
4275

    
4276
	if (!platform_booting()) {
4277
		link_interface_to_vips($interface, "update");
4278

    
4279
		if ($tunnelif != 'gre') {
4280
			$gre = link_interface_to_tunnelif($interface, 'gre');
4281
			array_walk($gre, 'interface_gre_configure');
4282
		}
4283

    
4284
		if ($tunnelif != 'gif') {
4285
			$gif = link_interface_to_tunnelif($interface, 'gif');
4286
			array_walk($gif, 'interface_gif_configure');
4287
		}
4288

    
4289
		$grouptmp = link_interface_to_group($interface);
4290
		if (!empty($grouptmp)) {
4291
			array_walk($grouptmp, 'interface_group_add_member');
4292
		}
4293

    
4294
		if ($interface == "lan") {
4295
			/* make new hosts file */
4296
			system_hosts_generate();
4297
		}
4298

    
4299
		if ($reloadall == true) {
4300

    
4301
			/* reconfigure static routes (kernel may have deleted them) */
4302
			system_routing_configure($interface);
4303

    
4304
			/* reload ipsec tunnels */
4305
			send_event("service reload ipsecdns");
4306

    
4307
			if (config_path_enabled('dnsmasq')) {
4308
				services_dnsmasq_configure();
4309
			}
4310

    
4311
			if (config_path_enabled('unbound')) {
4312
				services_unbound_configure(true, $interface);
4313
			}
4314

    
4315
			/* update dyndns */
4316
			send_event("service reload dyndns {$interface}");
4317
		}
4318
	}
4319

    
4320
	if (!platform_booting() && (substr($realif, 0, 5) == 'l2tps')) {
4321
		vpn_l2tp_configure();
4322
	};
4323

    
4324
	if (!empty($wancfg['descr'])) {
4325
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4326
	};
4327

    
4328
	interfaces_staticarp_configure($interface);
4329
	return 0;
4330
}
4331

    
4332
function interface_track6_configure($interface, $wancfg, $linkupevent = false) {
4333
	global $g;
4334

    
4335
	if (!is_array($wancfg)) {
4336
		return;
4337
	}
4338

    
4339
	if (!isset($wancfg['enable'])) {
4340
		return;
4341
	}
4342

    
4343
	/* If the interface is not configured via another, exit */
4344
	if (empty($wancfg['track6-interface'])) {
4345
		return;
4346
	}
4347

    
4348
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4349
	$realif = get_real_interface($interface);
4350
	$linklocal = find_interface_ipv6_ll($realif, true);
4351
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4352
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4353
	}
4354

    
4355
	$trackcfg = config_get_path("interfaces/{$wancfg['track6-interface']}");
4356
	if (!isset($trackcfg['enable'])) {
4357
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4358
		return;
4359
	}
4360

    
4361
	$type = $trackcfg['ipaddrv6'];
4362
	switch ($type) {
4363
		case "6to4":
4364
			if (g_get('debug')) {
4365
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4366
			}
4367
			interface_track6_6to4_configure($interface, $wancfg);
4368
			break;
4369
		case "6rd":
4370
			if (g_get('debug')) {
4371
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4372
			}
4373
			interface_track6_6rd_configure($interface, $wancfg);
4374
			break;
4375
		case "dhcp6":
4376
			if ($linkupevent == true) {
4377
				/*
4378
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4379
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4380
				 *
4381
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4382
				 */
4383
				$pidv6 = find_dhcp6c_process();
4384
				if ($pidv6) {
4385
					posix_kill($pidv6, SIGHUP);
4386
				}
4387
			}
4388
			break;
4389
	}
4390

    
4391
	if ($linkupevent == false && !platform_booting()) {
4392
		if (!function_exists('services_dhcpd_configure')) {
4393
			require_once("services.inc");
4394
		}
4395

    
4396
		/* restart dns servers (defering dhcpd reload) */
4397
		if (config_path_enabled('unbound')) {
4398
			services_unbound_configure(false, $interface);
4399
		}
4400
		if (config_path_enabled('dnsmasq')) {
4401
			services_dnsmasq_configure(false);
4402
		}
4403

    
4404
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4405
		services_dhcpd_configure("inet6");
4406
	}
4407

    
4408
	return 0;
4409
}
4410

    
4411
function interface_track6_6rd_configure($interface, $lancfg) {
4412
	global $interface_ipv6_arr_cache;
4413
	global $interface_snv6_arr_cache;
4414

    
4415
	if (!is_array($lancfg)) {
4416
		return;
4417
	}
4418

    
4419
	/* If the interface is not configured via another, exit */
4420
	if (empty($lancfg['track6-interface'])) {
4421
		return;
4422
	}
4423

    
4424
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4425
	if (empty($wancfg)) {
4426
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4427
		return;
4428
	}
4429

    
4430
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4431
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4432
		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']));
4433
		return;
4434
	}
4435
	$hexwanv4 = return_hex_ipv4($ip4address);
4436

    
4437
	/* create the long prefix notation for math, save the prefix length */
4438
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4439
	$rd6prefixlen = $rd6prefix[1];
4440
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4441

    
4442
	/* binary presentation of the prefix for all 128 bits. */
4443
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4444

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

    
4450
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4451
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4452
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4453
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4454
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4455
	/* fill the rest out with zeros */
4456
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4457

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

    
4461
	$lanif = get_real_interface($interface);
4462
	$oip = find_interface_ipv6($lanif);
4463
	if (is_ipaddrv6($oip)) {
4464
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4465
	}
4466
	unset($interface_ipv6_arr_cache[$lanif]);
4467
	unset($interface_snv6_arr_cache[$lanif]);
4468
	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));
4469
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4470

    
4471
	return 0;
4472
}
4473

    
4474
function interface_track6_6to4_configure($interface, $lancfg) {
4475
	global $interface_ipv6_arr_cache;
4476
	global $interface_snv6_arr_cache;
4477

    
4478
	if (!is_array($lancfg)) {
4479
		return;
4480
	}
4481

    
4482
	/* If the interface is not configured via another, exit */
4483
	if (empty($lancfg['track6-interface'])) {
4484
		return;
4485
	}
4486

    
4487
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4488
	if (empty($wancfg)) {
4489
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4490
		return;
4491
	}
4492

    
4493
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4494
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4495
		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']));
4496
		return;
4497
	}
4498
	$hexwanv4 = return_hex_ipv4($ip4address);
4499

    
4500
	/* create the long prefix notation for math, save the prefix length */
4501
	$sixto4prefix = "2002::";
4502
	$sixto4prefixlen = 16;
4503
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4504

    
4505
	/* binary presentation of the prefix for all 128 bits. */
4506
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4507

    
4508
	/* just save the left prefix length bits */
4509
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4510
	/* add the v4 address */
4511
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4512
	/* add the custom prefix id */
4513
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4514
	/* fill the rest out with zeros */
4515
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4516

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

    
4520
	$lanif = get_real_interface($interface);
4521
	$oip = find_interface_ipv6($lanif);
4522
	if (is_ipaddrv6($oip)) {
4523
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4524
	}
4525
	unset($interface_ipv6_arr_cache[$lanif]);
4526
	unset($interface_snv6_arr_cache[$lanif]);
4527
	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));
4528
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4529

    
4530
	return 0;
4531
}
4532

    
4533
function interface_6rd_configure($interface, $wancfg) {
4534
	global $g;
4535

    
4536
	/* because this is a tunnel interface we can only function
4537
	 *	with a public IPv4 address on the interface */
4538

    
4539
	if (!is_array($wancfg)) {
4540
		return;
4541
	}
4542

    
4543
	if (!is_module_loaded('if_stf.ko')) {
4544
		mwexec('/sbin/kldload if_stf.ko');
4545
	}
4546

    
4547
	$wanif = get_real_interface($interface);
4548
	$ip4address = find_interface_ip($wanif);
4549
	if (!is_ipaddrv4($ip4address)) {
4550
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4551
		return false;
4552
	}
4553
	$hexwanv4 = return_hex_ipv4($ip4address);
4554

    
4555
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4556
		$wancfg['prefix-6rd-v4plen'] = 0;
4557
	}
4558

    
4559
	/* create the long prefix notation for math, save the prefix length */
4560
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4561
	$rd6prefixlen = $rd6prefix[1];
4562
	$brgw = explode('.', $wancfg['gateway-6rd']);
4563
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4564
	$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);
4565
	if (strlen($rd6brgw) < 128) {
4566
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4567
	}
4568
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4569
	unset($brgw);
4570
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4571

    
4572
	/* binary presentation of the prefix for all 128 bits. */
4573
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4574

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

    
4582
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4583
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4584

    
4585

    
4586
	/* XXX: need to extend to support variable prefix size for v4 */
4587
	$stfiface = "{$interface}_stf";
4588
	if (does_interface_exist($stfiface)) {
4589
		pfSense_interface_destroy($stfiface);
4590
	}
4591
	$tmpstfiface = pfSense_interface_create2("stf");
4592
	pfSense_interface_rename($tmpstfiface, $stfiface);
4593
	pfSense_interface_flags($stfiface, IFF_LINK2);
4594
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4595
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4596
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4597
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4598
	}
4599
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4600
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4601
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4602
	} elseif ($parentmtu > 1300) {
4603
		set_interface_mtu($stfiface, $parentmtu - 20);
4604
	}
4605
	if (g_get('debug')) {
4606
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4607
	}
4608

    
4609
	/* write out a default router file */
4610
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4611
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4612
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4613

    
4614
	$ip4gateway = get_interface_gateway($interface);
4615
	if (is_ipaddrv4($ip4gateway)) {
4616
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4617
	}
4618

    
4619
	/* configure dependent interfaces */
4620
	if (!platform_booting()) {
4621
		link_interface_to_track6($interface, "update");
4622
	}
4623

    
4624
	return 0;
4625
}
4626

    
4627
function interface_6to4_configure($interface, $wancfg) {
4628
	global $g;
4629

    
4630
	/* because this is a tunnel interface we can only function
4631
	 *	with a public IPv4 address on the interface */
4632

    
4633
	if (!is_array($wancfg)) {
4634
		return;
4635
	}
4636

    
4637
	$wanif = get_real_interface($interface);
4638
	$ip4address = find_interface_ip($wanif);
4639
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4640
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4641
		return false;
4642
	}
4643

    
4644
	/* create the long prefix notation for math, save the prefix length */
4645
	$stfprefixlen = 16;
4646
	$stfprefix = Net_IPv6::uncompress("2002::");
4647
	$stfarr = explode(":", $stfprefix);
4648
	$v4prefixlen = "0";
4649

    
4650
	/* we need the hex form of the interface IPv4 address */
4651
	$ip4arr = explode(".", $ip4address);
4652
	$hexwanv4 = "";
4653
	foreach ($ip4arr as $octet) {
4654
		$hexwanv4 .= sprintf("%02x", $octet);
4655
	}
4656

    
4657
	/* we need the hex form of the broker IPv4 address */
4658
	$ip4arr = explode(".", "192.88.99.1");
4659
	$hexbrv4 = "";
4660
	foreach ($ip4arr as $octet) {
4661
		$hexbrv4 .= sprintf("%02x", $octet);
4662
	}
4663

    
4664
	/* binary presentation of the prefix for all 128 bits. */
4665
	$stfprefixbin = "";
4666
	foreach ($stfarr as $element) {
4667
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4668
	}
4669
	/* just save the left prefix length bits */
4670
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4671

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

    
4676
	/* for the local subnet too. */
4677
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4678
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4679

    
4680
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4681
	$stfbrarr = array();
4682
	$stfbrbinarr = array();
4683
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4684
	foreach ($stfbrbinarr as $bin) {
4685
		$stfbrarr[] = dechex(bindec($bin));
4686
	}
4687
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4688

    
4689
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4690
	$stflanarr = array();
4691
	$stflanbinarr = array();
4692
	$stflanbinarr = str_split($stflanbin, 16);
4693
	foreach ($stflanbinarr as $bin) {
4694
		$stflanarr[] = dechex(bindec($bin));
4695
	}
4696
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4697
	$stflanarr[7] = 1;
4698

    
4699
	/* setup the stf interface */
4700
	if (!is_module_loaded("if_stf")) {
4701
		mwexec("/sbin/kldload if_stf.ko");
4702
	}
4703
	$stfiface = "{$interface}_stf";
4704
	if (does_interface_exist($stfiface)) {
4705
		pfSense_interface_destroy($stfiface);
4706
	}
4707
	$tmpstfiface = pfSense_interface_create2("stf");
4708
	pfSense_interface_rename($tmpstfiface, $stfiface);
4709
	pfSense_interface_flags($stfiface, IFF_LINK2);
4710
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4711

    
4712
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4713
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4714
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4715
	} elseif ($parentmtu > 1300) {
4716
		set_interface_mtu($stfiface, $parentmtu - 20);
4717
	}
4718
	if (g_get('debug')) {
4719
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4720
	}
4721

    
4722
	/* write out a default router file */
4723
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4724
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4725
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4726

    
4727
	$ip4gateway = get_interface_gateway($interface);
4728
	if (is_ipaddrv4($ip4gateway)) {
4729
		route_add_or_change("192.88.99.1", $ip4gateway);
4730
	}
4731

    
4732
	if (!platform_booting()) {
4733
		link_interface_to_track6($interface, "update");
4734
	}
4735

    
4736
	return 0;
4737
}
4738

    
4739
function interface_dhcpv6_configure($ifconf, $ifcfg, $destroy = false) {
4740
	global $g;
4741

    
4742
	$dhcp6cconf = "";
4743
	$id = "0";
4744
	$dhcp6cinterfaces = array();
4745
	$dhcp6cifs_descr = array();
4746
	$dhcp6crealifs = array();
4747
	$debugOption = "-d";
4748
	$noreleaseOption = "";
4749

    
4750
	if (!empty(config_get_path('system/global-v6duid'))) {
4751
		// Write the DUID file
4752
		if(!write_dhcp6_duid(config_get_path('system/global-v6duid'))) {
4753
		    log_error(gettext("Failed to write user DUID file!"));
4754
		}
4755
	}
4756

    
4757
	foreach (config_get_path('interfaces', []) as $interface => $wancfg) {
4758
		$wanif = get_real_interface($interface, "inet6");
4759

    
4760
		if (($ifconf == $interface) && $destroy) {
4761
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
4762
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
4763
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$wanif}_script.sh");
4764
			continue;
4765
		}
4766

    
4767
		if (!isset($wancfg['enable']) || (($ifconf == $interface) && $destroy) ||
4768
		    (($wancfg['ipaddrv6'] != 'dhcp6') && ($wancfg['ipaddrv6'] != 'slaac'))) {
4769
			continue;
4770
		}
4771

    
4772
		$dhcp6cinterfaces[$interface] = $wancfg;
4773

    
4774
		if (config_path_enabled('system','dhcp6debug')) {
4775
			$debugOption = "-D";
4776
		}
4777
		if (config_path_enabled('system','dhcp6norelease')) {
4778
			$noreleaseOption = "-n";
4779
		}
4780

    
4781
		/* accept router advertisements for this interface                 */
4782
		/* Moved to early in the function as sometimes interface not ready */
4783
		/* RTSOLD fails as interface does not accept .....                 */
4784

    
4785
		log_error("Accept router advertisements on interface {$wanif} ");
4786
		mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4787

    
4788
		if ($wancfg['adv_dhcp6_config_file_override']) {
4789
			// DHCP6 Config File Override
4790
			$dhcp6cconf .= DHCP6_Config_File_Override($wancfg, $wanif);
4791
		} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4792
			// DHCP6 Config File Advanced
4793
			$dhcp6cconf .= DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4794
		} else {
4795
			// DHCP6 Config File Basic
4796
			$dhcp6cconf .= "interface {$wanif} {\n";
4797

    
4798
			/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4799
			if ($wancfg['ipaddrv6'] == "slaac") {
4800
				$dhcp6cconf .= "\tinformation-only;\n";
4801
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4802
				$dhcp6cconf .= "\trequest domain-name;\n";
4803
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4804
				$dhcp6cconf .= "};\n";
4805
			} else {
4806
				$trackiflist = array();
4807
				$iflist = link_interface_to_track6($interface);
4808
				foreach ($iflist as $ifname => $ifcfg) {
4809
					if (is_numeric($ifcfg['track6-prefix-id'])) {
4810
						$trackiflist[$ifname] = $ifcfg;
4811
					}
4812
				}
4813

    
4814
				/* skip address request if this is set */
4815
				if (!isset($wancfg['dhcp6prefixonly'])) {
4816
					$dhcp6cconf .= "\tsend ia-na {$id};\t# request stateful address\n";
4817
				}
4818
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4819
					$dhcp6cconf .= "\tsend ia-pd {$id};\t# request prefix delegation\n";
4820
				}
4821

    
4822
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4823
				$dhcp6cconf .= "\trequest domain-name;\n";
4824

    
4825
				/*
4826
				 * dhcp6c will run different scripts depending on
4827
				 * whether dhcpwithoutra is set or unset.
4828
				 */
4829
				if (isset($wancfg['dhcp6withoutra'])) {
4830
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4831
				} else {
4832
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4833
				}
4834
				$dhcp6cconf .= "};\n";
4835

    
4836
				if (!isset($wancfg['dhcp6prefixonly'])) {
4837
					$dhcp6cconf .= "id-assoc na {$id} { };\n";
4838
				}
4839

    
4840
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4841
					/* Setup the prefix delegation */
4842
					$dhcp6cconf .= "id-assoc pd {$id} {\n";
4843
					$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4844
					if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4845
						$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4846
					}
4847
					foreach ($trackiflist as $friendly => $ifcfg) {
4848
						if (g_get('debug')) {
4849
							log_error("setting up $interface - {$ifcfg['track6-prefix-id']}");
4850
						}
4851
						$realif = get_real_interface($friendly);
4852
						$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4853
						$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4854
						$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4855
						$dhcp6cconf .= "\t};\n";
4856
					}
4857
					unset($preflen, $iflist, $ifcfg, $ifname);
4858
					$dhcp6cconf .= "};\n\n";
4859
				}
4860
				unset($trackiflist);
4861
			}
4862
			$id++;
4863
		}
4864

    
4865
		/*************** Script Debug Logging ***************************
4866
		Both dhcp6 scripts now have a logging message built in.
4867
		These logging messages ONLY appear if dhcp6c debug logging is set.
4868
		The logging messages appear in the dhcp section of the logs,
4869
		not in system.
4870

    
4871
		These scripts now also take advantage of the REASON= env vars
4872
		supplied by dhcp6c.
4873
		****************************************************************/
4874

    
4875
		/* Script create for dhcp6withoutRA mode */
4876
		/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4877
		$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4878
		$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4879
		$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4880
		$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4881
		$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4882
		// Need to pass params to  the final script
4883
		$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4884
		$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4885
		$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4886
		$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4887
		$dhcp6cscriptwithoutra .= "REQUEST)\n";
4888
		$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -A {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4889
		if ($debugOption == '-D') {
4890
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
4891
		}
4892
		$dhcp6cscriptwithoutra .= ";;\n";
4893
		$dhcp6cscriptwithoutra .= "REBIND)\n";
4894
		if ($debugOption == '-D') {
4895
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4896
		}
4897
		$dhcp6cscriptwithoutra .= ";;\n";
4898
		if (isset($wancfg['dhcp6norelease'])) {
4899
			$dhcp6cscriptwithoutra .= "EXIT)\n";
4900
		} else {
4901
			$dhcp6cscriptwithoutra .= "RELEASE)\n";
4902
		}
4903
		if ($debugOption == '-D') {
4904
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4905
		}
4906
		$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4907
		$dhcp6cscriptwithoutra .= ";;\n";
4908
		$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4909
		if ($debugOption == '-D') {
4910
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4911
		}
4912
		$dhcp6cscriptwithoutra .= "esac\n";
4913
		if (!@file_put_contents(
4914
		    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4915
		    $dhcp6cscriptwithoutra)) {
4916
			printf("Error: cannot open " .
4917
			    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4918
			    "interface_dhcpv6_configure() for writing.\n");
4919
			unset($dhcp6cscriptwithoutra);
4920
			return 1;
4921
		}
4922

    
4923
		@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh", 0755);
4924

    
4925
		/*
4926
		 * Dual mode wan_dhcp6c script with variations depending on node
4927
		 * dhcp6 will run the wan ipv6 configure
4928
		 */
4929
		$dhcp6cscript  = "#!/bin/sh\n";
4930
		$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4931
		if (!isset($wancfg['dhcp6withoutra'])) {
4932
			$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4933
			$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4934
			$dhcp6cscript .= "case \$REASON in\n";
4935
			$dhcp6cscript .= "REBIND)\n";
4936
			if ($debugOption == '-D') {
4937
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4938
			}
4939
			$dhcp6cscript .= ";;\n";
4940
			$dhcp6cscript .= "REQUEST|";
4941
			if (isset($wancfg['dhcp6norelease'])) {
4942
				$dhcp6cscript .= "EXIT)\n";
4943
			} else {
4944
				$dhcp6cscript .= "RELEASE)\n";
4945
			}
4946
			if ($debugOption == '-D') {
4947
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
4948
			}
4949
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4950
			$dhcp6cscript .= ";;\n";
4951
			$dhcp6cscript .= "RENEW|INFO)\n";
4952
			if ($debugOption == '-D') {
4953
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4954
			}
4955
			$dhcp6cscript .= "esac\n";
4956
			$rtsold_ra_ifs[] = $wanif;
4957
		} else {
4958
			// Need to get the parameters from the dhcp6cwithoutRA run
4959
			$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4960
			$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4961
			$dhcp6cscript .= "/bin/sleep 1\n";
4962
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4963
		}
4964

    
4965
		/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4966
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4967
			printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4968
			unset($dhcp6cscript);
4969
			return 1;
4970
		}
4971
		unset($dhcp6cscript);
4972
		@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4973
	}
4974

    
4975
	if (!empty($dhcp6cinterfaces)) {
4976
		/* wide-dhcp6c works for now. */
4977
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c.conf", $dhcp6cconf)) {
4978
			printf("Error: cannot open dhcp6c.conf in interface_dhcpv6_configure() for writing.\n");
4979
			return 1;
4980
		}
4981
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
4982
			$dhcp6cifs_descr[] = $interface . '(' . $wancfg['if'] . ')';
4983
			$dhcp6crealifs[] = $wancfg['if'];
4984
		}
4985
		$dhcp6cdescr = implode(',', $dhcp6cifs_descr);
4986
		$dhcp6cifs = implode(' ', $dhcp6crealifs);
4987
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
4988
			$wanif = get_real_interface($interface, "inet6");
4989

    
4990
			$rtsoldscript_header = <<<EOD
4991
#!/bin/sh
4992
# This shell script launches dhcp6c and configured gateways for this interface.
4993
if [ -n "\$2" ]; then
4994
	if [ -n "$(echo \$2 | /usr/bin/grep '^fe80')" ]; then
4995
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_routerv6
4996
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
4997
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_defaultgwv6
4998
	else
4999
		echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5000
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5001
		echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5002
	fi
5003
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5004
fi
5005

    
5006
EOD;
5007

    
5008
			/* non ipoe Process */
5009
			$rtsoldscript = $rtsoldscript_header;
5010
			if (!isset($wancfg['dhcp6withoutra'])) {
5011
				/*
5012
				 * We only want this script to run once, and if it runs twice
5013
				 * then do not launch dhcp6c again, this only happens if
5014
				 * dhcpwithoutra is not set.
5015
				 *
5016
				 * Check for a lock file, trying to prevent multiple instances
5017
				 * of dhcp6c being launched
5018
				 */
5019
				$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_lock ]; then\n";
5020
				/*
5021
				 * Create the lock file, trying to prevent multiple instances
5022
				 * of dhcp6c being launched
5023
				 */
5024
				$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_lock\n";
5025
				$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c.pid ]; then\n";
5026
				$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c.pid\n";
5027
				$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c.pid\n";
5028
				$rtsoldscript .= "\t\t/bin/sleep 1\n";
5029
				$rtsoldscript .= "\tfi\n";
5030
				$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5031
				    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c.conf " .
5032
				    "-p {$g['varrun_path']}/dhcp6c.pid {$dhcp6cifs}\n";
5033
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interfaces {$dhcp6cdescr}\"\n";
5034
				$rtsoldscript .= "else\n";
5035
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5036
				$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c.pid\")\n";
5037
				$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5038
				$rtsoldscript .= "fi\n";
5039
			} else {
5040
				/*
5041
				 * The script needs to run in dhcp6withoutra mode as RA may
5042
				 * not have been received, or there can be a delay with
5043
				 * certain ISPs
5044
				 */
5045
				$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5046
				$rtsoldscript .= "/bin/sleep 1\n";
5047
			}
5048

    
5049
			/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5050
			if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5051
				printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5052
				return 1;
5053
			}
5054
			unset($rtsoldscript);
5055
			@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5056
		}
5057

    
5058
		$realif = get_real_interface($ifconf, "inet6");
5059
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$realif}.pid")) {
5060
			killbypid("{$g['varrun_path']}/rtsold_{$realif}.pid");
5061
			log_error("Killing running rtsold process");
5062
			sleep(2);
5063
		}
5064

    
5065
		if (file_exists("{$g['tmp_path']}/dhcp6c_ifs")) {
5066
			$dhcp6crealifs_run = unserialize(file_get_contents("{$g['tmp_path']}/dhcp6c_ifs"));
5067
		} else {
5068
			$dhcp6crealifs_run = array();
5069
		}
5070

    
5071
		if (($dhcp6crealifs != $dhcp6crealifs_run) || $destroy) {
5072
			kill_dhcp6client_process(false);
5073
			run_dhcp6client_process($dhcp6crealifs, $debugOption, $noreleaseOption);
5074
			file_put_contents("{$g['tmp_path']}/dhcp6c_ifs", serialize($dhcp6crealifs));
5075
			$dhcp6c_restarted = true;
5076
			if ($destroy) {
5077
				$track6 = link_interface_to_track6($ifconf);
5078
				if (is_array($track6) && !empty($track6)) {
5079
					/* remove stale track interfaces IP */
5080
					foreach (array_keys($track6) as $tr6if) {
5081
						interface_reconfigure($tr6if, true);
5082
					}
5083
				}
5084
			}
5085
		}
5086

    
5087
		if (isset($ifcfg['dhcp6withoutra']) && !$dhcp6c_restarted) {
5088
			/*
5089
			 * Start dhcp6c here if we don't want to wait for ra - calls
5090
			 * separate function
5091
			 *
5092
			 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5093
			 * will then run the configure on receipt of the RA.
5094
			 *
5095
			 * Already started. interface_dhcpv6_configure() appears to get
5096
			 * called multiple times.
5097
			 *
5098
			 * Taking the interface down or releasing will kill the client.
5099
			 */
5100

    
5101
			/*
5102
			 * If the interface is being brought up, wait for the
5103
			 * interface to configure accept RA before launching.
5104
			 * Otherwise it is not ready to accept and will fail.
5105
			 */
5106
			sleep(3);
5107
			if (file_exists("/tmp/dhcp6c_lock")) {
5108
				reset_dhcp6client_process();
5109
			}
5110
		} elseif (!$destroy) {
5111
			/*
5112
			 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5113
			 * ( it does not background, it exits! ) It will launch dhcp6c
5114
			 * if dhcpwihtoutra is not set
5115
			 */
5116
			log_error("Starting rtsold process on {$ifconf}({$realif})");
5117
			sleep(2);
5118
			mwexec("/usr/sbin/rtsold -1 " .
5119
			    "-p {$g['varrun_path']}/rtsold_{$realif}.pid " .
5120
			    "-A {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5121
			    $realif);
5122
		}
5123
	} else {
5124
		kill_dhcp6client_process(true);
5125
		unlink_if_exists("{$g['varetc_path']}/dhcp6c.conf");
5126
		unlink_if_exists("{$g['tmp_path']}/dhcp6c_ifs");
5127
	}
5128

    
5129
	/*
5130
	 * NOTE: will be called from rtsold invoked script
5131
	 * link_interface_to_track6($interface, "update");
5132
	 */
5133

    
5134
	return 0;
5135
}
5136

    
5137
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5138
	global $g;
5139

    
5140
	$send_options = "";
5141
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5142
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5143
		foreach ($options as $option) {
5144
			$send_options .= "\tsend " . trim($option) . ";\n";
5145
		}
5146
	}
5147

    
5148
	$request_options = "";
5149
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5150
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5151
		foreach ($options as $option) {
5152
			$request_options .= "\trequest " . trim($option) . ";\n";
5153
		}
5154
	}
5155

    
5156
	$information_only = "";
5157
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5158
		$information_only = "\tinformation-only;\n";
5159
	}
5160

    
5161
	if (isset($wancfg['dhcp6withoutra'])) {
5162
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\";\n";
5163
	} else {
5164
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5165
	}
5166
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5167
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5168
	}
5169

    
5170
	$interface_statement  = "interface";
5171
	$interface_statement .= " {$wanif}";
5172
	$interface_statement .= " {\n";
5173
	$interface_statement .= "$send_options";
5174
	$interface_statement .= "$request_options";
5175
	$interface_statement .= "$information_only";
5176
	$interface_statement .= "$script";
5177
	$interface_statement .= "};\n";
5178

    
5179
	$id_assoc_statement_address = "";
5180
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5181
		$id_assoc_statement_address .= "id-assoc";
5182
		$id_assoc_statement_address .= " na";
5183
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5184
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5185
		}
5186
		$id_assoc_statement_address .= " { ";
5187

    
5188
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5189
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5190
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5191
			$id_assoc_statement_address .= "\n\taddress";
5192
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5193
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5194
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5195
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5196
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5197
			}
5198
			$id_assoc_statement_address .= ";\n";
5199
		}
5200

    
5201
		$id_assoc_statement_address .= "};\n";
5202
	}
5203

    
5204
	$id_assoc_statement_prefix = "";
5205
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5206
		$id_assoc_statement_prefix .= "id-assoc";
5207
		$id_assoc_statement_prefix .= " pd";
5208
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5209
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5210
		}
5211
		$id_assoc_statement_prefix .= " { ";
5212

    
5213
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5214
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5215
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5216
			$id_assoc_statement_prefix .= "\n\tprefix";
5217
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5218
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5219
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5220
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5221
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5222
			}
5223
			$id_assoc_statement_prefix .= ";";
5224
		}
5225

    
5226
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5227
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5228
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5229
			$id_assoc_statement_prefix .= " {$realif}";
5230
			$id_assoc_statement_prefix .= " {\n";
5231
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5232
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5233
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5234
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5235
			}
5236
			$id_assoc_statement_prefix .= "\t};";
5237
		}
5238

    
5239
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5240
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5241
			$id_assoc_statement_prefix .= "\n";
5242
		}
5243

    
5244
		$id_assoc_statement_prefix .= "};\n";
5245
	}
5246

    
5247
	$authentication_statement = "";
5248
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5249
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5250
		$authentication_statement .= "authentication";
5251
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5252
		$authentication_statement .= " {\n";
5253
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5254
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5255
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5256
		}
5257
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5258
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5259
		}
5260
		$authentication_statement .= "};\n";
5261
	}
5262

    
5263
	$key_info_statement = "";
5264
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5265
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5266
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5267
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5268
		$key_info_statement .= "keyinfo";
5269
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5270
		$key_info_statement .= " {\n";
5271
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5272
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5273
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5274
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(forever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
5275
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5276
		}
5277
		$key_info_statement .= "};\n";
5278
	}
5279

    
5280
	$dhcp6cconf  = $interface_statement;
5281
	$dhcp6cconf .= $id_assoc_statement_address;
5282
	$dhcp6cconf .= $id_assoc_statement_prefix;
5283
	$dhcp6cconf .= $authentication_statement;
5284
	$dhcp6cconf .= $key_info_statement;
5285

    
5286
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5287

    
5288
	return $dhcp6cconf;
5289
}
5290

    
5291

    
5292
function DHCP6_Config_File_Override($wancfg, $wanif) {
5293

    
5294
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5295

    
5296
	if ($dhcp6cconf === false) {
5297
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5298
		return '';
5299
	} else {
5300
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5301
	}
5302
}
5303

    
5304

    
5305
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5306

    
5307
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5308

    
5309
	return $dhcp6cconf;
5310
}
5311

    
5312

    
5313
function interface_dhcp_configure($interface) {
5314
	global $g, $vlanprio_values;
5315

    
5316
	$ifcfg = config_get_path("interfaces/{$interface}");
5317
	if (empty($ifcfg)) {
5318
		$ifcfg = array();
5319
	}
5320

    
5321
	$dhclientconf_vlantag = "";
5322
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5323
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5324
	}
5325

    
5326
	/* generate dhclient_wan.conf */
5327
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5328
	if (!$fd) {
5329
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5330
		return 1;
5331
	}
5332

    
5333
	if ($ifcfg['dhcphostname']) {
5334
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5335
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5336
	} else {
5337
		$dhclientconf_hostname = "";
5338
	}
5339

    
5340
	$realif = get_real_interface($interface);
5341
	if (empty($realif)) {
5342
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5343
		return 0;
5344
	}
5345
	$dhclientconf = "";
5346

    
5347
	$dhclientconf .= <<<EOD
5348
interface "{$realif}" {
5349
	supersede interface-mtu 0;
5350
	timeout 60;
5351
	retry 15;
5352
	select-timeout 0;
5353
	initial-interval 1;
5354
	{$dhclientconf_vlantag}
5355
	{$dhclientconf_hostname}
5356
	script "/usr/local/sbin/pfSense-dhclient-script";
5357
EOD;
5358

    
5359
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5360
		$dhclientconf .= <<<EOD
5361

    
5362
	reject {$ifcfg['dhcprejectfrom']};
5363
EOD;
5364
	}
5365
	$dhclientconf .= <<<EOD
5366

    
5367
}
5368

    
5369
EOD;
5370

    
5371
	// DHCP Config File Advanced
5372
	if ($ifcfg['adv_dhcp_config_advanced']) {
5373
		$dhclientconf = DHCP_Config_File_Advanced($ifcfg, $realif);
5374
	}
5375

    
5376
	if (is_ipaddr($ifcfg['alias-address'])) {
5377
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5378
		$dhclientconf .= <<<EOD
5379
alias {
5380
	interface "{$realif}";
5381
	fixed-address {$ifcfg['alias-address']};
5382
	option subnet-mask {$subnetmask};
5383
}
5384

    
5385
EOD;
5386
	}
5387

    
5388
	// DHCP Config File Override
5389
	if ($ifcfg['adv_dhcp_config_file_override']) {
5390
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5391
	}
5392

    
5393
	fwrite($fd, $dhclientconf);
5394
	fclose($fd);
5395

    
5396
	/* bring wan interface up before starting dhclient */
5397
	if ($realif) {
5398
		interfaces_bring_up($realif);
5399
	}
5400

    
5401
	/* Make sure dhclient is not running */
5402
	kill_dhclient_process($realif);
5403

    
5404
	/* fire up dhclient */
5405
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf -p {$g['varrun_path']}/dhclient.{$realif}.pid {$realif} > {$g['tmp_path']}/{$realif}_output 2> {$g['tmp_path']}/{$realif}_error_output");
5406

    
5407
	return 0;
5408
}
5409

    
5410
function DHCP_Config_File_Advanced($ifcfg, $realif) {
5411

    
5412
	$hostname = "";
5413
	if ($ifcfg['dhcphostname'] != '') {
5414
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5415
	}
5416

    
5417
	/* DHCP Protocol Timings */
5418
	$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");
5419
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5420
		$pt_variable = "{$Protocol_Timing}";
5421
		${$pt_variable} = "";
5422
		if ($ifcfg[$Protocol_Timing] != "") {
5423
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5424
		}
5425
	}
5426

    
5427
	$send_options = "";
5428
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5429
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5430
		foreach ($options as $option) {
5431
			$send_options .= "\tsend " . trim($option) . ";\n";
5432
		}
5433
	}
5434

    
5435
	$request_options = "";
5436
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5437
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5438
	}
5439

    
5440
	$required_options = "";
5441
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5442
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5443
	}
5444

    
5445
	$option_modifiers = "";
5446
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5447
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5448
		foreach ($modifiers as $modifier) {
5449
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5450
		}
5451
	}
5452

    
5453
	$dhclientconf  = "interface \"{$realif}\" {\n";
5454
	$dhclientconf .= "\n";
5455
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5456
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5457
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5458
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5459
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5460
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5461
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5462
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5463
	$dhclientconf .= "\n";
5464
	$dhclientconf .= "# DHCP Protocol Options\n";
5465
	$dhclientconf .= "{$hostname}";
5466
	$dhclientconf .= "{$send_options}";
5467
	$dhclientconf .= "{$request_options}";
5468
	$dhclientconf .= "{$required_options}";
5469
	$dhclientconf .= "{$option_modifiers}";
5470
	$dhclientconf .= "\n";
5471
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5472
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5473
	}
5474
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5475
	$dhclientconf .= "}\n";
5476

    
5477
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5478

    
5479
	return $dhclientconf;
5480
}
5481

    
5482
function DHCP_Config_Option_Split($option_string) {
5483
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5484
	return $matches ? $matches[0] : [];
5485
}
5486

    
5487
function DHCP_Config_File_Override($ifcfg, $realif) {
5488

    
5489
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5490

    
5491
	if ($dhclientconf === false) {
5492
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5493
		return '';
5494
	} else {
5495
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5496
	}
5497
}
5498

    
5499

    
5500
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5501

    
5502
	/* Apply Interface Substitutions */
5503
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5504

    
5505
	/* Apply Hostname Substitutions */
5506
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5507

    
5508
	/* Arrays of MAC Address Types, Cases, Delimiters */
5509
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5510
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5511
	$various_mac_cases      = array("U", "L");
5512
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5513

    
5514
	/* Apply MAC Address Substitutions */
5515
	foreach ($various_mac_types as $various_mac_type) {
5516
		foreach ($various_mac_cases as $various_mac_case) {
5517
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5518

    
5519
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5520
				if ($res !== false) {
5521

    
5522
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5523
					if ("$various_mac_case" == "U") {
5524
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5525
					}
5526
					if ("$various_mac_case" == "L") {
5527
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5528
					}
5529

    
5530
					if ("$various_mac_type" == "mac_addr_hex") {
5531
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5532
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5533
						$dhcpclientconf_mac_hex = "";
5534
						$delimiter = "";
5535
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5536
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5537
							$delimiter = ":";
5538
						}
5539
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5540
					}
5541

    
5542
					/* MAC Address Delimiter Substitutions */
5543
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5544

    
5545
					/* Apply MAC Address Substitutions */
5546
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5547
				}
5548
			}
5549
		}
5550
	}
5551

    
5552
	return $dhclientconf;
5553
}
5554

    
5555
function interfaces_group_setup() {
5556
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupar) {
5557
		interface_group_setup($groupar);
5558
	}
5559

    
5560
	return;
5561
}
5562

    
5563
function interface_group_setup(&$groupname /* The parameter is an array */) {
5564
	if (!is_array($groupname)) {
5565
		return;
5566
	}
5567
	$members = explode(" ", $groupname['members']);
5568
	foreach ($members as $ifs) {
5569
		$realif = get_real_interface($ifs);
5570
		if ($realif && does_interface_exist($realif)) {
5571
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5572
		}
5573
	}
5574

    
5575
	return;
5576
}
5577

    
5578
function is_interface_group($if) {
5579
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupentry) {
5580
		if ($groupentry['ifname'] === $if) {
5581
			return true;
5582
		}
5583
	}
5584

    
5585
	return false;
5586
}
5587

    
5588
function interface_group_add_member($interface, $groupname) {
5589
	$interface = get_real_interface($interface);
5590
	if (does_interface_exist($interface)) {
5591
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5592
	}
5593
}
5594

    
5595
/* COMPAT Function */
5596
function convert_friendly_interface_to_real_interface_name($interface) {
5597
	return get_real_interface($interface);
5598
}
5599

    
5600
/* COMPAT Function */
5601
function get_real_wan_interface($interface = "wan") {
5602
	return get_real_interface($interface);
5603
}
5604

    
5605
/* COMPAT Function */
5606
function get_current_wan_address($interface = "wan") {
5607
	return get_interface_ip($interface);
5608
}
5609

    
5610
/*
5611
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5612
 */
5613
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5614

    
5615
	/* XXX: For speed reasons reference directly the interface array */
5616
	init_config_arr(array('interfaces'));
5617
	$ifdescrs = config_get_path('interfaces');
5618
	//$ifdescrs = get_configured_interface_list(true);
5619

    
5620
	foreach ($ifdescrs as $if => $ifname) {
5621
		if ($if == $interface || $ifname['if'] == $interface) {
5622
			return $if;
5623
		}
5624

    
5625
		if (get_real_interface($if) == $interface) {
5626
			return $if;
5627
		}
5628

    
5629
		if ($checkparent == false) {
5630
			continue;
5631
		}
5632

    
5633
		$int = get_parent_interface($if, true);
5634
		if (is_array($int)) {
5635
			foreach ($int as $iface) {
5636
				if ($iface == $interface) {
5637
					return $if;
5638
				}
5639
			}
5640
		}
5641
	}
5642

    
5643
	if ($interface == "enc0") {
5644
		return 'IPsec';
5645
	}
5646
}
5647

    
5648
/* attempt to resolve interface to friendly descr */
5649
function convert_friendly_interface_to_friendly_descr($interface) {
5650

    
5651
	$iface = config_get_path("interfaces/{$interface}");
5652
	switch ($interface) {
5653
		case "l2tp":
5654
			$ifdesc = "L2TP";
5655
			break;
5656
		case "pptp":
5657
			$ifdesc = "PPTP";
5658
			break;
5659
		case "pppoe":
5660
			$ifdesc = "PPPoE";
5661
			break;
5662
		case "openvpn":
5663
			$ifdesc = "OpenVPN";
5664
			break;
5665
		case "lo0":
5666
			$ifdesc = "Loopback";
5667
			break;
5668
		case "enc0":
5669
		case "ipsec":
5670
		case "IPsec":
5671
			$ifdesc = "IPsec";
5672
			break;
5673
		default:
5674
			if ($iface) {
5675
				if (empty($iface['descr'])) {
5676
					$ifdesc = strtoupper($interface);
5677
				} else {
5678
					$ifdesc = strtoupper($iface['descr']);
5679
				}
5680
				break;
5681
			} elseif (substr($interface, 0, 4) == '_vip') {
5682
				foreach (config_get_path('virtualip/vip', []) as $vip) {
5683
					if (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias")) {
5684
						if ($interface == "_vip{$vip['uniqid']}") {
5685
							$descr = $vip['subnet'];
5686
							if (!empty($vip['vhid'])) {
5687
								$descr .= " (vhid {$vip['vhid']})";
5688
							}
5689
							if (!empty($vip['descr'])) {
5690
								$descr .= " - " .$vip['descr'];
5691
							}
5692
							return $descr;
5693
						}
5694
					}
5695
				}
5696
			} elseif (substr($interface, 0, 5) == '_lloc') {
5697
				return get_interface_linklocal($interface);
5698
			} else {
5699
				foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
5700
					if ($ifgen['ifname'] === $interface) {
5701
						return $ifgen['ifname'];
5702
					}
5703
				}
5704

    
5705
				/* if list */
5706
				$ifdescrs = get_configured_interface_with_descr(true);
5707
				foreach ($ifdescrs as $if => $ifname) {
5708
					if ($if == $interface || $ifname == $interface) {
5709
						return $ifname;
5710
					}
5711
				}
5712
			}
5713
			break;
5714
	}
5715

    
5716
	return $ifdesc;
5717
}
5718

    
5719
function convert_real_interface_to_friendly_descr($interface) {
5720

    
5721
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5722

    
5723
	if (!empty($ifdesc)) {
5724
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5725
	}
5726

    
5727
	return $interface;
5728
}
5729

    
5730
/*
5731
 *  get_parent_interface($interface):
5732
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5733
 *				or virtual interface (i.e. vlan)
5734
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5735
 *			-- returns $interface passed in if $interface parent is not found
5736
 *			-- returns empty array if an invalid interface is passed
5737
 *	(Only handles ppps and vlans now.)
5738
 */
5739
function get_parent_interface($interface, $avoidrecurse = false) {
5740
	$parents = array();
5741
	//Check that we got a valid interface passed
5742
	$realif = get_real_interface($interface);
5743
	if ($realif == NULL) {
5744
		return $parents;
5745
	}
5746

    
5747
	// If we got a real interface, find it's friendly assigned name
5748
	if ($interface == $realif && $avoidrecurse == false) {
5749
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5750
	}
5751

    
5752
	$iface = config_get_path("interfaces/{$interface}");
5753
	if (!empty($interface) && $iface) {
5754
		$ifcfg = $iface;
5755
		switch ($ifcfg['ipaddr']) {
5756
			case "ppp":
5757
			case "pppoe":
5758
			case "pptp":
5759
			case "l2tp":
5760
				if (empty($parents)) {
5761
					foreach (config_get_path('ppps/ppp') as $ppp) {
5762
						if ($ifcfg['if'] == $ppp['if']) {
5763
							$ports = explode(',', $ppp['ports']);
5764
							foreach ($ports as $pid => $parent_if) {
5765
								$parents[$pid] = get_real_interface($parent_if);
5766
							}
5767
							break;
5768
						}
5769
					}
5770
				}
5771
				break;
5772
			case "dhcp":
5773
			case "static":
5774
			default:
5775
				// Handle _vlans
5776
				$vlan = interface_is_vlan($ifcfg['if']);
5777
				if ($vlan != NULL) {
5778
					$parents[0] = $vlan['if'];
5779
				}
5780
				break;
5781
		}
5782
	}
5783

    
5784
	if (empty($parents)) {
5785
		// Handle _vlans not assigned to an interface
5786
		$vlan = interface_is_vlan($realif);
5787
		if ($vlan != NULL) {
5788
			$parents[0] = $vlan['if'];
5789
		}
5790
	}
5791

    
5792
	if (empty($parents)) {
5793
		/* Handle LAGGs. */
5794
		$lagg = interface_is_type($realif, 'lagg');
5795
		if ($lagg != NULL && isset($lagg['members'])) {
5796
			$parents = explode(",", $lagg['members']);
5797
		}
5798
	}
5799

    
5800
	if (empty($parents)) {
5801
		$parents[0] = $realif;
5802
	}
5803

    
5804
	return $parents;
5805
}
5806

    
5807
/*
5808
 *  get_parent_physical_interface($interface):
5809
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5810
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5811
 */
5812
function get_parent_physical_interface($interface) {
5813

    
5814
	$realif = get_parent_interface($interface);
5815

    
5816
	if (substr($realif[0], 0, 4) == "lagg") {
5817
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
5818
			if ($realif[0] == $lagg['laggif']) {
5819
				return explode(",", $lagg['members']);
5820
			}
5821
		}
5822
	} else {
5823
		return $realif;
5824
	}
5825
}
5826

    
5827
function interface_is_wireless_clone($wlif) {
5828
	if (!stristr($wlif, "_wlan")) {
5829
		return false;
5830
	} else {
5831
		return true;
5832
	}
5833
}
5834

    
5835
function interface_get_wireless_base($wlif) {
5836
	if (!stristr($wlif, "_wlan")) {
5837
		return $wlif;
5838
	} else {
5839
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5840
	}
5841
}
5842

    
5843
function interface_get_wireless_clone($wlif) {
5844
	if (!stristr($wlif, "_wlan")) {
5845
		return $wlif . "_wlan0";
5846
	} else {
5847
		return $wlif;
5848
	}
5849
}
5850

    
5851
function interface_list_wireless() {
5852
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5853

    
5854
	$result = array();
5855
	foreach ($portlist as $port) {
5856
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5857
			continue;
5858
		}
5859

    
5860
		$desc = $port . " ( " . get_single_sysctl(
5861
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5862

    
5863
		$result[] = array(
5864
		    "if" => $port,
5865
		    "descr" => $desc
5866
		);
5867
	}
5868

    
5869
	return $result;
5870
}
5871

    
5872
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5873
	global $g;
5874

    
5875
	$wanif = NULL;
5876

    
5877
	switch ($interface) {
5878
		case "l2tp":
5879
			$wanif = "l2tp";
5880
			break;
5881
		case "pptp":
5882
			$wanif = "pptp";
5883
			break;
5884
		case "pppoe":
5885
			$wanif = "pppoe";
5886
			break;
5887
		case "openvpn":
5888
			$wanif = "openvpn";
5889
			break;
5890
		case "IPsec":
5891
		case "ipsec":
5892
		case "enc0":
5893
			$wanif = "enc0";
5894
			break;
5895
		case "ppp":
5896
			$wanif = "ppp";
5897
			break;
5898
		default:
5899
			if (substr($interface, 0, 4) == '_vip') {
5900
				$wanif = get_configured_vip_interface($interface);
5901
				if (!empty($wanif)) {
5902
					$wanif = get_real_interface($wanif);
5903
				}
5904
				break;
5905
			} elseif (substr($interface, 0, 5) == '_lloc') {
5906
				$interface = substr($interface, 5);
5907
			} elseif (interface_is_vlan($interface) != NULL ||
5908
			    does_interface_exist($interface, $flush)) {
5909
				/*
5910
				 * If a real interface was already passed simply
5911
				 * pass the real interface back.  This encourages
5912
				 * the usage of this function in more cases so that
5913
				 * we can combine logic for more flexibility.
5914
				 */
5915
				$wanif = $interface;
5916
				break;
5917
			}
5918

    
5919
			$cfg = config_get_path("interfaces/{$interface}");
5920
			if (empty($cfg))
5921
				break;
5922

    
5923
			if ($family == "inet6") {
5924
				switch ($cfg['ipaddrv6']) {
5925
					case "6rd":
5926
					case "6to4":
5927
						$wanif = "{$interface}_stf";
5928
						break;
5929
					case 'pppoe':
5930
					case 'ppp':
5931
					case 'l2tp':
5932
					case 'pptp':
5933
						if (is_array($cfg['wireless']) || preg_match(g_get('wireless_regex'), $cfg['if'])) {
5934
							$wanif = interface_get_wireless_clone($cfg['if']);
5935
						} else {
5936
							$wanif = $cfg['if'];
5937
						}
5938
						break;
5939
					default:
5940
						switch ($cfg['ipaddr']) {
5941
							case 'pppoe':
5942
							case 'ppp':
5943
							case 'l2tp':
5944
							case 'pptp':
5945
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5946
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
5947
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
5948
									$wanif = $cfg['if'];
5949
								} else {
5950
									$parents = get_parent_interface($interface);
5951
									if (!empty($parents[0])) {
5952
										$wanif = $parents[0];
5953
									} else {
5954
										$wanif = $cfg['if'];
5955
									}
5956
								}
5957
								break;
5958
							default:
5959
								if (is_array($cfg['wireless']) || preg_match(g_get('wireless_regex'), $cfg['if'])) {
5960
									$wanif = interface_get_wireless_clone($cfg['if']);
5961
								} else {
5962
									$wanif = $cfg['if'];
5963
								}
5964
								break;
5965
						}
5966
						break;
5967
				}
5968
			} else {
5969
				// Wireless cloned NIC support (FreeBSD 8+)
5970
				// interface name format: $parentnic_wlanparentnic#
5971
				// example: ath0_wlan0
5972
				if (is_array($cfg['wireless']) || preg_match(g_get('wireless_regex'), $cfg['if'])) {
5973
					$wanif = interface_get_wireless_clone($cfg['if']);
5974
				} else {
5975
					$wanif = $cfg['if'];
5976
				}
5977
			}
5978
			break;
5979
	}
5980

    
5981
	return $wanif;
5982
}
5983

    
5984
/* Guess the physical interface by providing a IP address */
5985
function guess_interface_from_ip($ipaddress) {
5986

    
5987
	if (!is_ipaddr($ipaddress)) {
5988
		return false;
5989
	}
5990

    
5991
	$route = route_get($ipaddress, '', true);
5992
	if (empty($route)) {
5993
		return false;
5994
	}
5995

    
5996
	if (!empty($route[0]['interface-name'])) {
5997
		return $route[0]['interface-name'];
5998
	}
5999

    
6000
	return false;
6001
}
6002

    
6003
/*
6004
 * find_ip_interface($ip): return the interface where an ip is defined
6005
 *   (or if $bits is specified, where an IP within the subnet is defined)
6006
 */
6007
function find_ip_interface($ip, $bits = null) {
6008
	if (!is_ipaddr($ip)) {
6009
		return false;
6010
	}
6011

    
6012
	$isv6ip = is_ipaddrv6($ip);
6013

    
6014
	/* if list */
6015
	$ifdescrs = get_configured_interface_list();
6016

    
6017
	foreach ($ifdescrs as $ifname) {
6018
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6019
		if (is_null($ifip)) {
6020
			continue;
6021
		}
6022
		if (is_null($bits)) {
6023
			if ($ip == $ifip) {
6024
				$int = get_real_interface($ifname);
6025
				return $int;
6026
			}
6027
		} else {
6028
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6029
				$int = get_real_interface($ifname);
6030
				return $int;
6031
			}
6032
		}
6033
	}
6034

    
6035
	return false;
6036
}
6037

    
6038
/*
6039
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6040
 *   (or if $bits is specified, where an IP within the subnet is found)
6041
 */
6042
function find_virtual_ip_alias($ip, $bits = null) {
6043

    
6044
	if (!is_ipaddr($ip)) {
6045
		return false;
6046
	}
6047

    
6048
	$isv6ip = is_ipaddrv6($ip);
6049

    
6050
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6051
		if ($vip['mode'] === "ipalias") {
6052
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6053
				continue;
6054
			}
6055
			if (is_null($bits)) {
6056
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6057
					return $vip;
6058
				}
6059
			} else {
6060
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6061
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6062
					return $vip;
6063
				}
6064
			}
6065
		}
6066
	}
6067
	return false;
6068
}
6069

    
6070
function link_interface_to_track6($int, $action = "") {
6071
	$list = array();
6072
	if (empty($int)) {
6073
		return $list;
6074
	}
6075

    
6076
	foreach (config_get_path('interfaces', []) as $ifname => $ifcfg) {
6077
		if (!isset($ifcfg['enable'])) {
6078
			continue;
6079
		}
6080
		if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6081
			if ($action == "update") {
6082
				interface_track6_configure($ifname, $ifcfg);
6083
			} elseif ($action == "") {
6084
				$list[$ifname] = $ifcfg;
6085
			}
6086
		}
6087
	}
6088
	return $list;
6089
}
6090

    
6091
function interface_find_child_cfgmtu($realiface) {
6092
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6093
	$vlans = link_interface_to_vlans($realiface);
6094
	$qinqs = link_interface_to_qinqs($realiface);
6095
	$bridge = link_interface_to_bridge($realiface);
6096
	$gifs = link_interface_to_tunnelif($interface, 'gif');
6097
	$gres = link_interface_to_tunnelif($interface, 'gre');
6098

    
6099
	$mtu = 0;
6100
	if (is_array($vlans)) {
6101
		foreach ($vlans as $vlan) {
6102
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6103
			if (empty($ifass)) {
6104
				continue;
6105
			}
6106
			$vlanmtu = config_get_path("interfaces/{$ifass}/mtu");
6107
			if ($vlanmtu && (intval($vlanmtu) > $mtu)) {
6108
				$mtu = $vlanmtu;
6109
			}
6110
		}
6111
	}
6112
	if (is_array($qinqs)) {
6113
		foreach ($qinqs as $qinq) {
6114
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6115
			if (empty($ifass)) {
6116
				continue;
6117
			}
6118

    
6119
			$qinqmtu = config_get_path("interfaces/{$ifass}/mtu");
6120
			if ($qinqmtu && (intval($qinqmtu) > $mtu)) {
6121
				$mtu = $qinqmtu;
6122
			}
6123
		}
6124
	}
6125
	foreach ($gifs as $gif) {
6126
		$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6127
		if (empty($ifass)) {
6128
			continue;
6129
		}
6130

    
6131
		$gifmtu = config_get_path("interfaces/{$ifass}/mtu");
6132
		if ($gifmtu && (intval($gifmtu) > $mtu)) {
6133
			$mtu = $gifmtu;
6134
		}
6135
	}
6136
	foreach ($gres as $gre) {
6137
		$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6138
		if (empty($ifass)) {
6139
			continue;
6140
		}
6141
		$gremtu = config_get_path("interfaces/{$ifass}/mtu");
6142
		if ($gremtu && (intval($gremtu) > $mtu)) {
6143
			$mtu = $gremtu;
6144
		}
6145
	}
6146
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6147
	$ifassmtu = config_get_path("interfaces/{$ifass}/mtu");
6148
	if (!empty($ifass) && !empty($ifassmtu)) {
6149
		if ($ifassmtu > $mtu) {
6150
			$mtu = $ifassmtu;
6151
		}
6152
	}
6153
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6154

    
6155
	return $mtu;
6156
}
6157

    
6158
function link_interface_to_vlans($int, $action = "") {
6159
	if (empty($int)) {
6160
		return;
6161
	}
6162

    
6163
	$ifaces = array();
6164
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
6165
		if ($int == $vlan['if']) {
6166
			if ($action == "update") {
6167
				interfaces_bring_up($int);
6168
			} else {
6169
				$ifaces[$vlan['tag']] = $vlan;
6170
			}
6171
		}
6172
	}
6173
	if (!empty($ifaces)) {
6174
		return $ifaces;
6175
	}
6176
}
6177

    
6178
function link_interface_to_qinqs($int, $action = "") {
6179
	if (empty($int)) {
6180
		return;
6181
	}
6182

    
6183
	$ifaces = array();
6184
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
6185
		if ($int == $qinq['if']) {
6186
			if ($action == "update") {
6187
				interfaces_bring_up($int);
6188
			} else {
6189
				$ifaces[$qinq['tag']] = $qinq;
6190
			}
6191
		}
6192
	}
6193
	if (!empty($ifaces)) {
6194
		return $ifaces;
6195
	}
6196
}
6197

    
6198
function link_interface_to_vips($int, $action = "", $vhid = '') {
6199
	$updatevips = false;
6200

    
6201
	$result = array();
6202
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6203
		if (substr($vip['interface'], 0, 4) == "_vip") {
6204
			$iface = get_configured_vip_interface($vip['interface']);
6205
		} else {
6206
			$iface = $vip['interface'];
6207
		}
6208
		if ($int != $iface) {
6209
			continue;
6210
		}
6211
		if ($action == "update") {
6212
			$updatevips = true;
6213
		} else {
6214
			if (empty($vhid) || ($vhid == $vip['vhid']) ||
6215
				substr($vip['interface'], 0, 4) == "_vip") {
6216
				$result[] = $vip;
6217
			}
6218
		}
6219
	}
6220
	if ($updatevips === true) {
6221
		interfaces_vips_configure($int);
6222
	}
6223
	return $result;
6224

    
6225
	return NULL;
6226
}
6227

    
6228
/****f* interfaces/link_interface_to_bridge
6229
 * NAME
6230
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6231
 * INPUTS
6232
 *   $ip
6233
 * RESULT
6234
 *   bridge[0-99]
6235
 ******/
6236
function link_interface_to_bridge($int) {
6237
	foreach (config_get_path('bridges/bridged', []) as $bridge) {
6238
		if (in_array($int, explode(',', $bridge['members']))) {
6239
			return "{$bridge['bridgeif']}";
6240
		}
6241
	}
6242
}
6243

    
6244
function link_interface_to_lagg($int) {
6245
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
6246
		if (in_array($int, explode(',', $lagg['members']))) {
6247
			return "{$lagg['laggif']}";
6248
		}
6249
	}
6250
}
6251

    
6252
function link_interface_to_group($int) {
6253
	$result = array();
6254

    
6255
	foreach (config_get_path('ifgroups/ifgroupentry') as $group) {
6256
		if (in_array($int, explode(" ", $group['members']))) {
6257
			$result[$group['ifname']] = $int;
6258
		}
6259
	}
6260

    
6261
	return $result;
6262
}
6263

    
6264
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6265
	$result = array();
6266

    
6267
	if (empty($interface)) {
6268
		return $result;
6269
	}
6270

    
6271
	if (!in_array($type, array('gre', 'gif'))) {
6272
		return $result;
6273
	}
6274

    
6275
	foreach (config_get_path("{$type}s/{$type}", []) as $tunnel) {
6276
		if (($tunnel['if'] == $interface) &&
6277
			(($remote == 'any') ||
6278
			 (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6279
			 (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) {
6280
			$result[] = $tunnel;
6281
		}
6282
	}
6283

    
6284
	return $result;
6285
}
6286

    
6287
function link_interface_to_ppp_tunnelif($interface) {
6288
	$result = array();
6289

    
6290
	if (empty($interface)) {
6291
		return $result;
6292
	}
6293

    
6294
	init_config_arr(array('ppps', 'ppp'));
6295
	$realif = get_real_interface($interface);
6296
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
6297
		if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) {
6298
			$result[] = $ppp;
6299
		}
6300
	}
6301

    
6302
	return $result;
6303
}
6304

    
6305
/*
6306
 * find_interface_ip($interface): return the interface ip (first found)
6307
 */
6308
function find_interface_ip($interface, $flush = false) {
6309
	global $interface_ip_arr_cache;
6310
	global $interface_sn_arr_cache;
6311

    
6312
	$interface = str_replace("\n", "", $interface);
6313

    
6314
	if (!does_interface_exist($interface)) {
6315
		return;
6316
	}
6317

    
6318
	/* Setup IP cache */
6319
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6320
		if (file_exists("/var/db/${interface}_ip")) {
6321
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6322
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6323
			foreach ($ifaddrs as $ifaddr) {
6324
				list($ip, $mask) = explode("/", $ifaddr);
6325
				if ($ip == $ifip) {
6326
					$interface_ip_arr_cache[$interface] = $ip;
6327
					$interface_sn_arr_cache[$interface] = $mask;
6328
					break;
6329
				}
6330
			}
6331
		}
6332
		if (!isset($interface_ip_arr_cache[$interface])) {
6333
			$ifinfo = get_interface_addresses($interface);
6334
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6335
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6336
		}
6337
	}
6338

    
6339
	return $interface_ip_arr_cache[$interface];
6340
}
6341

    
6342
/*
6343
 * find_interface_ipv6($interface): return the interface ip (first found)
6344
 */
6345
function find_interface_ipv6($interface, $flush = false) {
6346
	global $interface_ipv6_arr_cache;
6347
	global $interface_snv6_arr_cache;
6348

    
6349
	$interface = trim($interface);
6350
	$interface = get_real_interface($interface);
6351

    
6352
	if (!does_interface_exist($interface)) {
6353
		return;
6354
	}
6355

    
6356
	/* Setup IP cache */
6357
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6358
		$ifinfo = get_interface_addresses($interface);
6359
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6360
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6361
	}
6362

    
6363
	return $interface_ipv6_arr_cache[$interface];
6364
}
6365

    
6366
/*
6367
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6368
 */
6369
function find_interface_ipv6_ll($interface, $flush = false) {
6370
	global $interface_llv6_arr_cache;
6371

    
6372
	$interface = str_replace("\n", "", $interface);
6373

    
6374
	if (!does_interface_exist($interface)) {
6375
		return;
6376
	}
6377

    
6378
	/* Setup IP cache */
6379
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6380
		$ifinfo = pfSense_getall_interface_addresses($interface);
6381
		foreach ($ifinfo as $line) {
6382
			if (strstr($line, ":")) {
6383
				$parts = explode("/", $line);
6384
				if (is_linklocal($parts[0])) {
6385
					$ifinfo['linklocal'] = $parts[0];
6386
				}
6387
			}
6388
		}
6389
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6390
	}
6391
	return $interface_llv6_arr_cache[$interface];
6392
}
6393

    
6394
function find_interface_subnet($interface, $flush = false) {
6395
	global $interface_sn_arr_cache;
6396
	global $interface_ip_arr_cache;
6397

    
6398
	$interface = str_replace("\n", "", $interface);
6399
	if (does_interface_exist($interface) == false) {
6400
		return;
6401
	}
6402

    
6403
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6404
		$ifinfo = get_interface_addresses($interface);
6405
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6406
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6407
	}
6408

    
6409
	return $interface_sn_arr_cache[$interface];
6410
}
6411

    
6412
function find_interface_subnetv6($interface, $flush = false) {
6413
	global $interface_snv6_arr_cache;
6414
	global $interface_ipv6_arr_cache;
6415

    
6416
	$interface = str_replace("\n", "", $interface);
6417
	if (does_interface_exist($interface) == false) {
6418
		return;
6419
	}
6420

    
6421
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6422
		$ifinfo = get_interface_addresses($interface);
6423
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6424
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6425
	}
6426

    
6427
	return $interface_snv6_arr_cache[$interface];
6428
}
6429

    
6430
function ip_in_interface_alias_subnet($interface, $ipalias) {
6431
	if (empty($interface) || !is_ipaddr($ipalias)) {
6432
		return false;
6433
	}
6434
	foreach (config_get_path('virtualip/vip',[]) as $vip) {
6435
		switch ($vip['mode']) {
6436
		case "ipalias":
6437
			if ($vip['interface'] <> $interface) {
6438
				break;
6439
			}
6440
			$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6441
			if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6442
				return true;
6443
			}
6444
			break;
6445
		}
6446
	}
6447

    
6448
	return false;
6449
}
6450

    
6451
function get_possible_listen_ips($include_ipv6_link_local=false) {
6452

    
6453
	$interfaces = get_configured_interface_with_descr();
6454
	foreach ($interfaces as $iface => $ifacename) {
6455
		if ($include_ipv6_link_local) {
6456
			/* This is to avoid going though added ll below */
6457
			if (substr($iface, 0, 5) == '_lloc') {
6458
				continue;
6459
			}
6460
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6461
			if (!empty($llip)) {
6462
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6463
			}
6464
		}
6465
	}
6466
	$viplist = get_configured_vip_list();
6467
	foreach ($viplist as $vip => $address) {
6468
		$interfaces[$vip] = $address;
6469
		if (get_vip_descr($address)) {
6470
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6471
		}
6472
	}
6473

    
6474
	$interfaces['lo0'] = 'Localhost';
6475

    
6476
	return $interfaces;
6477
}
6478

    
6479
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6480
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6481
	foreach (array('server', 'client') as $mode) {
6482
		foreach (config_get_path("openvpn/openvpn-{$mode}", []) as $setting) {
6483
			if (!isset($setting['disable'])) {
6484
				$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6485
				$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6486
			}
6487
		}
6488
	}
6489

    
6490
	init_config_arr(array('ipsec', 'phase1'));
6491
	foreach (config_get_path('ipsec/phase1') as $p1) {
6492
		if ($p1['disabled']) {
6493
			continue;
6494
		}
6495
		if (ipsec_vti($p1)) {
6496
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6497
			if (!empty($vtiiflist)) {
6498
				$sourceips = array_merge($sourceips, $vtiiflist);
6499
			}
6500
		}
6501
	}
6502
	return $sourceips;
6503
}
6504

    
6505
function get_interface_ip($interface = "wan", $gateways_status = false) {
6506
	if (substr($interface, 0, 4) == '_vip') {
6507
		return get_configured_vip_ipv4($interface);
6508
	} elseif (substr($interface, 0, 5) == '_lloc') {
6509
		/* No link-local address for v4. */
6510
		return null;
6511
	}
6512

    
6513
	$realif = get_failover_interface($interface, 'inet', $gateways_status);
6514
	if (!$realif) {
6515
		return null;
6516
	}
6517

    
6518
	if (substr($realif, 0, 4) == '_vip') {
6519
		return get_configured_vip_ipv4($realif);
6520
	} elseif (substr($realif, 0, 5) == '_lloc') {
6521
		/* No link-local address for v4. */
6522
		return null;
6523
	}
6524

    
6525
	$iface = config_get_path("interfaces/{$interface}");
6526
	if (is_array($iface) && is_ipaddr($iface['ipaddr'])) {
6527
		return ($iface['ipaddr']);
6528
	}
6529

    
6530
	/*
6531
	 * Beware that find_interface_ip() is our last option, it will
6532
	 * return the first IP it find on interface, not necessarily the
6533
	 * main IP address.
6534
	 */
6535
	$curip = find_interface_ip($realif);
6536
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6537
		return $curip;
6538
	} else {
6539
		return null;
6540
	}
6541
}
6542

    
6543
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false, $gateways_status = false) {
6544
	if (substr($interface, 0, 4) == '_vip') {
6545
		return get_configured_vip_ipv6($interface);
6546
	} elseif (substr($interface, 0, 5) == '_lloc') {
6547
		return get_interface_linklocal($interface);
6548
	}
6549

    
6550
	$realif = get_failover_interface($interface, 'inet6', $gateways_status);
6551
	if (!$realif) {
6552
		return null;
6553
	}
6554

    
6555
	if (substr($realif, 0, 4) == '_vip') {
6556
		return get_configured_vip_ipv6($realif);
6557
	} elseif (substr($realif, 0, 5) == '_lloc') {
6558
		return get_interface_linklocal($realif);
6559
	}
6560

    
6561
	$iface = config_get_path("interfaces/{$interface}");
6562
	if (is_array($iface)) {
6563
		switch ($iface['ipaddr']) {
6564
			case 'pppoe':
6565
			case 'l2tp':
6566
			case 'pptp':
6567
			case 'ppp':
6568
				if (($iface['ipaddrv6'] == 'dhcp6') ||
6569
				    ($iface['ipaddrv6'] == 'slaac')) {
6570
					$realif = get_real_interface($interface, 'inet6', false);
6571
				}
6572
				break;
6573
		}
6574
		if (is_ipaddrv6($iface['ipaddrv6'])) {
6575
			return ($iface['ipaddrv6']);
6576
		}
6577
	}
6578

    
6579
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6580
	$checkif = is_array($iface) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6581
	if (config_get_path("interfaces/{$checkif}/ipaddrv6", "") == 'track6') {
6582
		$curip = get_interface_track6ip($checkif);
6583
		if ($curip) {
6584
			return $curip[0];
6585
		}
6586
	}
6587

    
6588
	/*
6589
	 * Beware that find_interface_ip() is our last option, it will
6590
	 * return the first IP it find on interface, not necessarily the
6591
	 * main IP address.
6592
	 */
6593
	$curip = find_interface_ipv6($realif, $flush);
6594
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6595
		return $curip;
6596
	} else {
6597
		/*
6598
		 * NOTE: On the case when only the prefix is requested,
6599
		 * the communication on WAN will be done over link-local.
6600
		 */
6601
		$iface = config_get_path("interfaces/{$interface}");
6602
		if ($linklocal_fallback || (is_array($iface) && isset($iface['dhcp6prefixonly']))) {
6603
			$curip = find_interface_ipv6_ll($realif, $flush);
6604
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6605
				return $curip;
6606
			}
6607
		}
6608
	}
6609
	return null;
6610
}
6611

    
6612
function get_interface_linklocal($interface = "wan") {
6613

    
6614
	$realif = get_failover_interface($interface, 'inet6');
6615
	if (!$realif) {
6616
		return null;
6617
	}
6618

    
6619
	if (substr($interface, 0, 4) == '_vip') {
6620
		$realif = get_real_interface($interface);
6621
	} elseif (substr($interface, 0, 5) == '_lloc') {
6622
		$realif = get_real_interface(substr($interface, 5));
6623
	}
6624

    
6625
	$curip = find_interface_ipv6_ll($realif);
6626
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6627
		return $curip;
6628
	} else {
6629
		return null;
6630
	}
6631
}
6632

    
6633
function get_interface_track6ip($interface = "wan") {
6634
	$realif = get_real_interface($interface);
6635
	$vips = get_configured_vip_list('inet6');
6636

    
6637
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6638
		list($ip, $bits) = explode("/", $ifaddr);
6639
		$ip = text_to_compressed_ip6($ip);
6640
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6641
			if (is_array($vips) && !empty($vips)) {
6642
				foreach ($vips as $vip) {
6643
					if ($ip == text_to_compressed_ip6($vip)) {
6644
						continue 2;
6645
					}
6646
				}
6647
			}
6648
			return array($ip, $bits);
6649
		}
6650
	}
6651
	return false;
6652
}
6653

    
6654
function get_interface_subnet($interface = "wan") {
6655
	if (substr($interface, 0, 4) == '_vip') {
6656
		return (get_configured_vip_subnetv4($interface));
6657
	}
6658

    
6659
	$iface = config_get_path("interfaces/{$interface}");
6660
	if (is_array($iface) && !empty($iface['subnet']) && is_ipaddrv4($iface['ipaddr'])) {
6661
		return ($iface['subnet']);
6662
	}
6663

    
6664
	$realif = get_real_interface($interface);
6665
	if (!$realif) {
6666
		return (NULL);
6667
	}
6668

    
6669
	$cursn = find_interface_subnet($realif);
6670
	if (!empty($cursn)) {
6671
		return ($cursn);
6672
	}
6673

    
6674
	return (NULL);
6675
}
6676

    
6677
function get_interface_subnetv6($interface = "wan") {
6678
	if (substr($interface, 0, 4) == '_vip') {
6679
		return (get_configured_vip_subnetv6($interface));
6680
	} elseif (substr($interface, 0, 5) == '_lloc') {
6681
		$interface = substr($interface, 5);
6682
	}
6683

    
6684
	$iface = config_get_path("interfaces/{$interface}");
6685
	if (is_array($iface) && !empty($iface['subnetv6']) && is_ipaddrv6($iface['ipaddrv6'])) {
6686
		return ($iface['subnetv6']);
6687
	}
6688

    
6689
	$realif = get_real_interface($interface, 'inet6');
6690
	if (!$realif) {
6691
		return (NULL);
6692
	}
6693

    
6694
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6695
	if (config_get_path("interfaces/{$interface}/ipaddrv6") == 'track6') {
6696
		$curip = get_interface_track6ip($interface);
6697
		if ($curip) {
6698
			return $curip[1];
6699
		}
6700
	}
6701

    
6702
	$cursn = find_interface_subnetv6($realif);
6703
	if (!empty($cursn)) {
6704
		return ($cursn);
6705
	}
6706

    
6707
	return (NULL);
6708
}
6709

    
6710
/* return outside interfaces with a gateway */
6711
function get_interfaces_with_gateway() {
6712

    
6713
	$ints = array();
6714

    
6715
	/* loop interfaces, check config for outbound */
6716
	foreach (config_get_path('interfaces', []) as $ifdescr => $ifname) {
6717
		switch ($ifname['ipaddr']) {
6718
			case "dhcp":
6719
			case "pppoe":
6720
			case "pptp":
6721
			case "l2tp":
6722
			case "ppp":
6723
				$ints[$ifdescr] = $ifdescr;
6724
				break;
6725
			default:
6726
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6727
				    !empty($ifname['gateway'])) {
6728
					$ints[$ifdescr] = $ifdescr;
6729
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6730
				    !empty($ifname['gateway'])) {
6731
					$ints[$ifdescr] = $ifdescr;
6732
				}
6733

    
6734
				break;
6735
		}
6736
	}
6737
	return $ints;
6738
}
6739

    
6740
/* return true if interface has a gateway */
6741
function interface_has_gateway($friendly) {
6742
	$ifname = config_get_path("interfaces/{$friendly}");
6743
	if (!empty($ifname)) {
6744
		switch ($ifname['ipaddr']) {
6745
			case "dhcp":
6746
				/* see https://redmine.pfsense.org/issues/5135 */
6747
				if (get_interface_gateway($friendly)) {
6748
					return true;
6749
				}
6750
				break;
6751
			case "pppoe":
6752
			case "pptp":
6753
			case "l2tp":
6754
			case "ppp":
6755
				return true;
6756
				break;
6757
			default:
6758
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6759
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6760
					return true;
6761
				}
6762
				$tunnelif = substr($ifname['if'], 0, 3);
6763
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6764
					if (find_interface_ip($ifname['if'])) {
6765
						return true;
6766
					}
6767
				}
6768
				if (!empty($ifname['gateway'])) {
6769
					return true;
6770
				}
6771
				break;
6772
		}
6773
	}
6774

    
6775
	return false;
6776
}
6777

    
6778
/* return true if interface has a gateway */
6779
function interface_has_gatewayv6($friendly) {
6780
	$ifname = config_get_path("interfaces/{$friendly}");
6781
	if (!empty($ifname)) {
6782
		switch ($ifname['ipaddrv6']) {
6783
			case "slaac":
6784
			case "dhcp6":
6785
			case "6to4":
6786
			case "6rd":
6787
				return true;
6788
				break;
6789
			default:
6790
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6791
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6792
					return true;
6793
				}
6794
				$tunnelif = substr($ifname['if'], 0, 3);
6795
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6796
					if (find_interface_ipv6($ifname['if'])) {
6797
						return true;
6798
					}
6799
				}
6800
				if (!empty($ifname['gatewayv6'])) {
6801
					return true;
6802
				}
6803
				break;
6804
		}
6805
	}
6806

    
6807
	return false;
6808
}
6809

    
6810
/****f* interfaces/is_altq_capable
6811
 * NAME
6812
 *   is_altq_capable - Test if interface is capable of using ALTQ
6813
 * INPUTS
6814
 *   $int            - string containing interface name
6815
 * RESULT
6816
 *   boolean         - true or false
6817
 ******/
6818

    
6819
function is_altq_capable($int) {
6820
	/* Per:
6821
	 * https://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+11.0-RELEASE&arch=default&format=html
6822
	 * Only the following drivers have ALTQ support
6823
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
6824
	 */
6825
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
6826
			"bfe", "bge", "bnxt", "bridge", "bxe", "cas", "cpsw", "dc", "de",
6827
			"ed", "em", "ep", "epair", "et", "fxp", "gem", "hme", "hn",
6828
			"igb", "igc", "ix", "jme", "l2tp", "le", "lem", "msk", "mxge", "my",
6829
			"ndis", "nfe", "ng", "nge", "npe", "nve", "ql", "ovpnc",
6830
			"ovpns", "ppp", "pppoe", "pptp", "re", "rl", "sf", "sge",
6831
			"sis", "sk", "ste", "stge", "ti", "tun", "txp", "udav",
6832
			"ural", "vge", "vlan", "vmx", "vr", "vte", "vtnet", "xl");
6833

    
6834
	$int_family = remove_ifindex($int);
6835

    
6836
	if (in_array($int_family, $capable)) {
6837
		return true;
6838
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6839
		return true;
6840
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6841
		return true;
6842
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6843
		return true;
6844
	} else {
6845
		return false;
6846
	}
6847
}
6848

    
6849
/****f* interfaces/is_interface_wireless
6850
 * NAME
6851
 *   is_interface_wireless - Returns if an interface is wireless
6852
 * RESULT
6853
 *   $tmp       - Returns if an interface is wireless
6854
 ******/
6855
function is_interface_wireless($interface) {
6856
	global $g;
6857

    
6858
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6859
	if (config_get_path("interfaces/{$friendly}/wireless") === null) {
6860
		if (preg_match(g_get('wireless_regex'), $interface)) {
6861
			init_config_arr(['interfaces', $friendly, 'wireless']);
6862
			return true;
6863
		}
6864
		return false;
6865
	} else {
6866
		return true;
6867
	}
6868
}
6869

    
6870
function get_wireless_modes($interface) {
6871
	/* return wireless modes and channels */
6872
	$wireless_modes = array();
6873

    
6874
	$cloned_interface = get_real_interface($interface);
6875

    
6876
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6877
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6878
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6879
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6880

    
6881
		$interface_channels = [];
6882
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6883
		$interface_channel_count = count($interface_channels);
6884

    
6885
		$c = 0;
6886
		while ($c < $interface_channel_count) {
6887
			$channel_line = explode(",", $interface_channels["$c"]);
6888
			$wireless_mode = trim($channel_line[0]);
6889
			$wireless_channel = trim($channel_line[1]);
6890
			if (trim($wireless_mode) != "") {
6891
				/* if we only have 11g also set 11b channels */
6892
				if ($wireless_mode == "11g") {
6893
					if (!isset($wireless_modes["11b"])) {
6894
						$wireless_modes["11b"] = array();
6895
					}
6896
				} elseif ($wireless_mode == "11g ht") {
6897
					if (!isset($wireless_modes["11b"])) {
6898
						$wireless_modes["11b"] = array();
6899
					}
6900
					if (!isset($wireless_modes["11g"])) {
6901
						$wireless_modes["11g"] = array();
6902
					}
6903
					$wireless_mode = "11ng";
6904
				} elseif ($wireless_mode == "11a ht") {
6905
					if (!isset($wireless_modes["11a"])) {
6906
						$wireless_modes["11a"] = array();
6907
					}
6908
					$wireless_mode = "11na";
6909
				}
6910
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6911
			}
6912
			$c++;
6913
		}
6914
	}
6915
	return($wireless_modes);
6916
}
6917

    
6918
function get_wireless_channels($interface) {
6919
		$chan_list = "/sbin/ifconfig -v " . escapeshellarg($interface) . " list chan";
6920
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6921
		$format_list = "/usr/bin/awk '{print \$5 \",\" \$6 \",\" \$1}'";
6922

    
6923
		$interface_channels = [];
6924
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6925
		return $interface_channels;
6926
}
6927

    
6928
/* return wireless HT modes */
6929
function get_wireless_ht_modes($interface) {
6930
	$wireless_hts_supported = array(0 => gettext('Auto'));
6931

    
6932
	$cloned_interface = get_real_interface($interface);
6933

    
6934
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6935
		$interface_channels = get_wireless_channels($cloned_interface);
6936

    
6937
		foreach ($interface_channels as $channel) {
6938
			$channel_line = explode(",", $channel);
6939
			$wireless_ht = trim($channel_line[1]);
6940
			if (!empty($wireless_ht)) {
6941
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6942
			}
6943
		}
6944
	}
6945
	return($wireless_hts_supported);
6946
}
6947

    
6948
/* return wireless HT by channel/standard */
6949
function get_wireless_ht_list($interface) {
6950
	$wireless_hts = array();
6951

    
6952
	$cloned_interface = get_real_interface($interface);
6953

    
6954
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6955
		$interface_channels = get_wireless_channels($cloned_interface);
6956
		$interface_channel_count = count($interface_channels);
6957

    
6958
		$c = 0;
6959
		while ($c < $interface_channel_count) {
6960
			$channel_line = explode(",", $interface_channels["$c"]);
6961
			$wireless_mode = trim($channel_line[0]);
6962
			$wireless_ht = trim($channel_line[1]);
6963
			$wireless_channel = trim($channel_line[2]);
6964
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
6965
				if ($wireless_mode == "11g") {
6966
					if (!isset($wireless_modes["11g"])) {
6967
						$wireless_hts["11g"] = array();
6968
					}
6969
					$wireless_mode = "11ng";
6970
				} elseif ($wireless_mode == "11a") {
6971
					if (!isset($wireless_modes["11a"])) {
6972
						$wireless_hts["11a"] = array();
6973
					}
6974
					$wireless_mode = "11na";
6975
				}
6976
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
6977
			}
6978
			$c++;
6979
		}
6980
	}
6981
	return($wireless_hts);
6982
}
6983

    
6984
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6985
function get_wireless_channel_info($interface) {
6986
	$wireless_channels = array();
6987

    
6988
	$cloned_interface = get_real_interface($interface);
6989

    
6990
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6991
		$chan_list = "/sbin/ifconfig " . escapeshellarg($cloned_interface) . " list txpower";
6992
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6993
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
6994

    
6995
		$interface_channels = [];
6996
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6997

    
6998
		foreach ($interface_channels as $channel_line) {
6999
			$channel_line = explode(",", $channel_line);
7000
			if (!isset($wireless_channels[$channel_line[0]])) {
7001
				$wireless_channels[$channel_line[0]] = $channel_line;
7002
			}
7003
		}
7004
	}
7005
	return($wireless_channels);
7006
}
7007

    
7008
function set_interface_mtu($interface, $mtu) {
7009

    
7010
	/* LAGG interface must be destroyed and re-created to change MTU */
7011
	if ((substr($interface, 0, 4) == 'lagg') &&
7012
	    (!strstr($interface, "."))) {
7013
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
7014
			if ($lagg['laggif'] == $interface) {
7015
				interface_lagg_configure($lagg);
7016
				break;
7017
			}
7018
		}
7019
	} else {
7020
		pfSense_interface_mtu($interface, $mtu);
7021
		set_ipv6routes_mtu($interface, $mtu);
7022
	}
7023
}
7024

    
7025
/****f* interfaces/get_interface_mtu
7026
 * NAME
7027
 *   get_interface_mtu - Return the mtu of an interface
7028
 * RESULT
7029
 *   $tmp       - Returns the mtu of an interface
7030
 ******/
7031
function get_interface_mtu($interface) {
7032
	$mtu = pfSense_interface_getmtu($interface);
7033
	return $mtu['mtu'];
7034
}
7035

    
7036
function get_interface_mac($interface) {
7037
	$macinfo = get_interface_addresses($interface);
7038
	return $macinfo["macaddr"];
7039
}
7040

    
7041
function get_interface_vendor_mac($interface) {
7042
	global $g;
7043

    
7044
	$macinfo = get_interface_addresses($interface);
7045
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7046
	    "00:00:00:00:00:00") {
7047
		return ($macinfo["hwaddr"]);
7048
	}
7049

    
7050
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7051
	if (file_exists($hwaddr_file)) {
7052
		$macaddr = trim(file_get_contents($hwaddr_file));
7053
		if (is_macaddr($macaddr)) {
7054
			return ($macaddr);
7055
		}
7056
	} elseif (is_macaddr($macinfo['macaddr'])) {
7057
		/* Save original macaddress to be restored when necessary */
7058
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7059
	}
7060

    
7061
	return (NULL);
7062
}
7063

    
7064
/****f* pfsense-utils/generate_random_mac_address
7065
 * NAME
7066
 *   generate_random_mac - generates a random mac address
7067
 * INPUTS
7068
 *   none
7069
 * RESULT
7070
 *   $mac - a random mac address
7071
 ******/
7072
function generate_random_mac_address() {
7073
	$mac = "02";
7074
	for ($x = 0; $x < 5; $x++) {
7075
		$mac .= ":" . dechex(rand(16, 255));
7076
	}
7077
	return $mac;
7078
}
7079

    
7080
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7081
	global $g;
7082

    
7083
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7084

    
7085
	if (!empty($iface) && !empty($pppif)) {
7086
		$cron_cmd = <<<EOD
7087
#!/bin/sh
7088
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7089
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7090

    
7091
EOD;
7092

    
7093
		@file_put_contents($cron_file, $cron_cmd);
7094
		chmod($cron_file, 0755);
7095
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7096
	} else {
7097
		unlink_if_exists($cron_file);
7098
	}
7099
}
7100

    
7101
function get_interface_default_mtu($type = "ethernet") {
7102
	switch ($type) {
7103
		case "gre":
7104
			return 1476;
7105
			break;
7106
		case "gif":
7107
			return 1280;
7108
			break;
7109
		case "tun":
7110
		case "vlan":
7111
		case "tap":
7112
		case "ethernet":
7113
		default:
7114
			return 1500;
7115
			break;
7116
	}
7117

    
7118
	/* Never reached */
7119
	return 1500;
7120
}
7121

    
7122
function get_vip_descr($ipaddress) {
7123

    
7124
	foreach (config_get_path('virtualip/vip', []) as $vip) {
7125
		if ($vip['subnet'] == $ipaddress) {
7126
			return ($vip['descr']);
7127
		}
7128
	}
7129
	return "";
7130
}
7131

    
7132
function interfaces_staticarp_configure($if) {
7133
	if (config_get_path('system/developerspew')) {
7134
		$mt = microtime();
7135
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7136
	}
7137

    
7138
	$ifcfg = config_get_path("interfaces/{$if}");
7139

    
7140
	if (!$ifcfg['if'] || !$ifcfg['enable']) {
7141
		return 0;
7142
	}
7143

    
7144
	/* Enable staticarp, if enabled */
7145
	$staticarp = config_get_path("dhcpd/{$if}/staticarp");
7146
	if ($staticarp) {
7147
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7148
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7149
	} else {
7150
		/*
7151
		 * Interfaces do not have staticarp enabled by default
7152
		 * Let's not disable staticarp on freshly created interfaces
7153
		 */
7154
		if (!platform_booting()) {
7155
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7156
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7157
		}
7158
	}
7159

    
7160
	/* Enable static arp entries */
7161
	$staticmap = config_get_path("dhcpd/{$if}/staticmap", []);
7162
	if (is_array($staticmap)) {
7163
		foreach ($staticmap as $arpent) {
7164
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7165
				continue;
7166
			}
7167
			if ($staticarp || isset($arpent['arp_table_static_entry'])) {
7168
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7169
			}
7170
		}
7171
	}
7172

    
7173
	return 0;
7174
}
7175

    
7176
function get_failover_interface($interface, $family = "all", $gateways_status = false) {
7177
	/* shortcut to get_real_interface if we find it in the config */
7178
	if (is_array(config_get_path("interfaces/{$interface}"))) {
7179
		return get_real_interface($interface, $family);
7180
	}
7181

    
7182
	/* compare against gateway groups */
7183
	$a_groups = return_gateway_groups_array(true, $gateways_status);
7184
	if (is_array($a_groups[$interface])) {
7185
		/* we found a gateway group, fetch the interface or vip */
7186
		if (!empty($a_groups[$interface][0]['vip'])) {
7187
			return $a_groups[$interface][0]['vip'];
7188
		} else {
7189
			return $a_groups[$interface][0]['int'];
7190
		}
7191
	}
7192
	/* fall through to get_real_interface */
7193
	/* XXX: Really needed? */
7194
	return get_real_interface($interface, $family);
7195
}
7196

    
7197
/****f* interfaces/interface_has_dhcp
7198
 * NAME
7199
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7200
 * INPUTS
7201
 *   interface or gateway group name
7202
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7203
 * RESULT
7204
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7205
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7206
 ******/
7207
function interface_has_dhcp($interface, $family = 4) {
7208
	$iface = config_get_path("interfaces/{$interface}");
7209
	if ($iface) {
7210
		if (($family == 4) && ($iface['ipaddr'] == "dhcp")) {
7211
			return true;
7212
		} elseif (($family == 6) && ($iface['ipaddrv6'] == "dhcp6")) {
7213
			return true;
7214
		} else {
7215
			return false;
7216
		}
7217
	}
7218

    
7219
	if ($family == 6) {
7220
		$dhcp_string = "_DHCP6";
7221
	} else {
7222
		$dhcp_string = "_DHCP";
7223
	}
7224

    
7225
	foreach (config_get_path('gateways/gateway_group', []) as $group) {
7226
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7227
			continue;
7228
		}
7229
		foreach ($group['item'] as $item) {
7230
			$item_data = explode("|", $item);
7231
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7232
				return true;
7233
			}
7234
		}
7235
	}
7236

    
7237
	return false;
7238
}
7239

    
7240
function remove_ifindex($ifname) {
7241
	return preg_replace("/[0-9]+$/", "", $ifname);
7242
}
7243

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

    
7247
	$viplist = get_configured_vip_list($family, $type);
7248
	foreach ($viplist as $vipid => $address) {
7249
		$interfaces[$vipid] = $address;
7250
		if ($type = VIP_CARP) {
7251
			$vip = get_configured_vip($vipid);
7252
			if (isset($vip) && is_array($vip) ) {
7253
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7254
			}
7255
		}
7256
		if (get_vip_descr($address)) {
7257
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7258
		}
7259
	}
7260
	return $interfaces;
7261
}
7262

    
7263
function return_gateway_groups_array_with_descr() {
7264
	$interfaces = array();
7265
	$grouplist = return_gateway_groups_array();
7266
	foreach (array_keys($grouplist) as $name) {
7267
		$interfaces[$name] = "GW Group {$name}";
7268
	}
7269
	return $interfaces;
7270
}
7271

    
7272
function get_serial_ports($short=false) {
7273
	$linklist = array();
7274
	if (!is_dir("/var/spool/lock")) {
7275
		mwexec("/bin/mkdir -p /var/spool/lock");
7276
	}
7277
	$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);
7278
	foreach ($serialports as $port) {
7279
		$port = trim($port);
7280
		$port = ($short) ? basename($port) : $port;
7281
		$linklist[$port] = $port;
7282
	}
7283
	return $linklist;
7284
}
7285

    
7286
function get_interface_ports() {
7287
	$linklist = array();
7288
	$portlist = get_interface_list();
7289

    
7290
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
7291
		if (empty($vlan)) {
7292
			continue;
7293
		}
7294
		$portlist[$vlan['vlanif']] = $vlan;
7295
	}
7296

    
7297
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
7298
		if (empty($qinq)) {
7299
			continue;
7300
		}
7301
		$members = explode(" ", $qinq['members']);
7302
		foreach ($members as $mem) {
7303
			$qentry = $qinq['vlanif'] . "." . $mem;
7304
			$portlist[$qentry] = $qentry;
7305
		}
7306
	}
7307

    
7308
	foreach ($portlist as $ifn => $ifinfo) {
7309
		$string = "";
7310
		if (is_array($ifinfo)) {
7311
			$string .= $ifn;
7312
			if ($ifinfo['mac']) {
7313
				$string .= " ({$ifinfo['mac']})";
7314
			}
7315
			if ($ifinfo['friendly']) {
7316
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7317
			} elseif ($ifinfo['descr']) {
7318
				$string .= " - {$ifinfo['descr']}";
7319
			}
7320
		} else {
7321
			$string .= $ifinfo;
7322
		}
7323

    
7324
		$linklist[$ifn] = $string;
7325
	}
7326
	return $linklist;
7327
}
7328

    
7329
function build_ppps_link_list() {
7330
	global $pconfig;
7331

    
7332
	$linklist = array('list' => array(), 'selected' => array());
7333

    
7334
	if ($pconfig['type'] == 'ppp') {
7335
		$linklist['list'] = get_serial_ports();
7336
	} else {
7337
		$iflist = get_interface_ports();
7338

    
7339
		$viplist = array();
7340
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7341
		foreach ($carplist as $vid => $vaddr) {
7342
			$vip = get_configured_vip($vid);
7343
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7344
		}
7345

    
7346
		$linklist['list'] = array_merge($iflist, $viplist);
7347

    
7348
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7349
		$lagglist = get_lagg_interface_list();
7350
		foreach ($lagglist as $lagg) {
7351
			/* LAGG members cannot be assigned */
7352
			$laggmembers = explode(',', $lagg['members']);
7353
			foreach ($laggmembers as $lagm) {
7354
				if (isset($linklist['list'][$lagm])) {
7355
					unset($linklist['list'][$lagm]);
7356
				}
7357
			}
7358
		}
7359
	}
7360

    
7361
	$selected_ports = array();
7362
	if (is_array($pconfig['interfaces'])) {
7363
		$selected_ports = $pconfig['interfaces'];
7364
	} elseif (!empty($pconfig['interfaces'])) {
7365
		$selected_ports = explode(',', $pconfig['interfaces']);
7366
	}
7367
	foreach ($selected_ports as $port) {
7368
		if (isset($linklist['list'][$port])) {
7369
			array_push($linklist['selected'], $port);
7370
		}
7371
	}
7372
	return($linklist);
7373
}
7374

    
7375
function create_interface_list($open = false) {
7376
	$iflist = array();
7377

    
7378
	// add group interfaces
7379
	config_get_path('ifgroups/ifgroupentry', []);
7380
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7381
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7382
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7383
		}
7384
	}
7385

    
7386
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7387
		if ($open || have_ruleint_access($ifent)) {
7388
			$iflist[$ifent] = $ifdesc;
7389
		}
7390
	}
7391

    
7392
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7393
		$iflist['l2tp'] = gettext('L2TP VPN');
7394
	}
7395

    
7396
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7397
		$iflist['pppoe'] = gettext("PPPoE Server");
7398
	}
7399

    
7400
	// add ipsec interfaces
7401
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7402
		$iflist["enc0"] = gettext("IPsec");
7403
	}
7404

    
7405
	// add openvpn/tun interfaces
7406
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7407
		$iflist["openvpn"] = gettext("OpenVPN");
7408
	}
7409

    
7410
	return($iflist);
7411
}
7412

    
7413
function is_pseudo_interface($inf, $tap=true) {
7414
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7415
	foreach ($psifs as $pif) {
7416
		if (substr($inf, 0, strlen($pif)) == $pif) {
7417
			if (($pif == 'ovpn') && $tap) {
7418
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7419
				$type = ($m[1] == 'c') ? 'client' : 'server';
7420
				foreach (config_get_path("openvpn/openvpn-{$type}", []) as $ovpn) {
7421
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7422
						return false;
7423
					} elseif ($ovpn['vpnid'] == $m[2]) {
7424
						return true;
7425
					}
7426
				}
7427
			} else {
7428
				return true;
7429
			}
7430
		}
7431
	}
7432
	return false;
7433
}
7434

    
7435
function is_stf_interface($inf) {
7436
	switch (config_get_path("interfaces/{$inf}/ipaddrv6")) {
7437
		case '6rd':
7438
		case '6to4':
7439
			return true;
7440
		default:
7441
			return false;
7442
	}
7443
}
7444

    
7445
function restart_interface_services($interface, $ipv6type = "") {
7446

    
7447
	services_unbound_configure(true, $interface);
7448

    
7449
	services_igmpproxy_configure($interface);
7450
	services_snmpd_configure($interface);
7451
	vpn_l2tp_configure($interface);
7452

    
7453
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7454
		openvpn_resync_all($interface);
7455
	}
7456
	ipsec_force_reload($interface);
7457

    
7458
	/* restart RADVD to announce correct IPv6 prefix
7459
	 * see https://redmine.pfsense.org/issues/12604 */
7460
	if ((($ipv6type == "staticv6") || ($ipv6type == "track6")) &&
7461
	    (config_get_path("dhcpdv6/{$interface}/ramode", "disabled") != "disabled")) {
7462
		services_radvd_configure();
7463
	}
7464

    
7465
	if (config_path_enabled("dhcpd/{$interface}") ||
7466
	    config_path_enabled("dhcpdv6/{$interface}")) {
7467
		services_dhcpd_configure();
7468
	}
7469

    
7470
	init_config_arr(array('syslog'));
7471
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7472
		system_syslogd_start();
7473
	}
7474
}
7475

    
7476
/**
7477
 * Return interface parameters and primary ipv4 and ipv6 addresses for the real iface
7478
 * $interface, identified by exclusion of VIPs. Deprecates pfSense_get_interface_addresses()
7479
 *
7480
 * Result array contains keyed values:
7481
 * - ipaddr: ipv4 address
7482
 * - subnetbits: ipv4 subnet bits
7483
 * - subnet: ipv4 subnet
7484
 * - broadcast: ipv4 broadcast addr (if applicable)
7485
 * - tunnel: ipv4 PPP endpoint (if applicable)
7486
 * - ipaddr6: ipv6 address
7487
 * - tentative: ipv6 tentative flag (if applicable)
7488
 * - subnetbits6: ipv6 subnet bits
7489
 * - tunnel6: ipv6 tunnel endpoint
7490
 * - status: up or down interface status
7491
 * - link0: per link layer defined flag
7492
 * - link1: per link layer defined flag
7493
 * - link2: per link layer defined flag
7494
 * - multicast: multicast support
7495
 * - loopback: interface is a loopback interface
7496
 * - pointtopoint: interface is point-to-point
7497
 * - promisc: interface in promisc mode
7498
 * - permanentpromisc: interface permanently in promisc mode
7499
 * - oactive: interface tx hardware queue is full
7500
 * - allmulti: interface receives all multicast packets
7501
 * - simplex: interface is simplex
7502
 * - linkstateup: interface link is up
7503
 * - iftype: wireless, ether, vlan, bridge, virtual, other
7504
 * - mtu: mtu of interface
7505
 * - caps: interface capabilities array
7506
 * - encaps: enabled capabilities array
7507
 * - macaddr: interface configured ethernet address
7508
 * - hwaddr: hardware ethernet address
7509
 */
7510
function get_interface_addresses($interface) {
7511
	$v4addrs = array();
7512
	$v6addrs = array();
7513
	$v4vips = array();
7514
	$v6vips = array();
7515
	$ifaddrs = pfSense_get_ifaddrs($interface);
7516

    
7517
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7518
		$vip = get_configured_vip($viface);
7519
		if (is_ipaddrv4($vip['subnet'])) {
7520
			array_push($v4vips, $vip['subnet']);
7521
		} else if (is_ipaddrv6($vip['subnet'])) {
7522
			array_push($v6vips, $vip['subnet']);
7523
		}
7524
	}
7525

    
7526
	if ($ifaddrs['addrs']) {
7527
	   $v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7528
		  return (array_search($addr['addr'], $v4vips) === false);
7529
	   });
7530
	}
7531

    
7532
	if ($ifaddrs['addrs6']) {
7533
	   $v6addrs = array_filter($ifaddrs['addrs6'], function($addr) use ($v6vips){
7534
		  return (array_search($addr['addr'], $v6vips) === false);
7535
	   });
7536
	}
7537
	/* Transform output to conform to pfSense_get_interface_addresses() */
7538
	if ($v4addrs) {
7539
		$v4addr = array_pop($v4addrs);
7540
		$ifaddrs['ipaddr'] = $v4addr['addr'];
7541
		foreach(array("subnetbits", "subnet", "broadcast", "tunnel") as $key) {
7542
			if (array_key_exists($key, $v4addr)) {
7543
				$ifaddrs[$key] = $v4addr[$key];
7544
			}
7545
		}
7546
	}
7547

    
7548
	if ($v6addrs) {
7549
		$v6addr = array_pop($v6addrs);
7550
		$ifaddrs['ipaddr6'] = $v6addr['addr'];
7551
		foreach(array("subnetbits", "tunnel") as $key) {
7552
			if (array_key_exists($key, $v6addr)) {
7553
				$ifaddrs[$key.'6'] = $v6addr[$key];
7554
			}
7555
		}
7556
		if (array_key_exists('tentative', $v6addr)) {
7557
			$ifaddrs['tentative'] = $v6addr['tentative'];
7558
		}
7559
	}
7560
	unset($ifaddrs['addrs']);
7561
	unset($ifaddrs['addrs6']);
7562

    
7563
	return($ifaddrs);
7564
}
7565
?>
(23-23/62)