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 " . escapeshellarg($greif) . " inet6 tunnel " . escapeshellarg($realifip6) . " " . escapeshellarg($gre['remote-addr']));
1076
	} else {
1077
		mwexec("/sbin/ifconfig " . escapeshellarg($greif) . " tunnel " . escapeshellarg($realifip) . " " . escapeshellarg($gre['remote-addr']));
1078
	}
1079
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1080
		mwexec("/sbin/ifconfig " . escapeshellarg($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 " . escapeshellarg($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 " . escapeshellarg($gifif) . " inet6 tunnel " . escapeshellarg($realifip) . " " . escapeshellarg($gif['remote-addr']));
1231
	} else {
1232
		mwexec("/sbin/ifconfig " . escapeshellarg($gifif) . " tunnel " . escapeshellarg($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 " . escapeshellarg($gifif) . " inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1238
	} else {
1239
		mwexec("/sbin/ifconfig " . escapeshellarg($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 " . escapeshellarg($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) {
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);
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() {
1533
	$bootmsg = false;
1534

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

    
1550
function interfaces_configure() {
1551
	global $g;
1552

    
1553
	/* Set up our loopback interface */
1554
	interfaces_loopback_configure();
1555

    
1556
	/* create the unconfigured wireless clones */
1557
	interfaces_create_wireless_clones();
1558

    
1559
	/* set up LAGG virtual interfaces */
1560
	interfaces_lagg_configure();
1561

    
1562
	/* set up VLAN virtual interfaces */
1563
	interfaces_vlan_configure();
1564

    
1565
	interfaces_qinq_configure(false);
1566

    
1567
	$iflist = get_configured_interface_with_descr();
1568
	$delayed_list = array();
1569
	$bridge_list = array();
1570
	$track6_list = array();
1571
	$dhcp6c_list = array();
1572

    
1573
	/* This is needed to speedup interfaces on bootup. */
1574
	$reload = false;
1575
	if (!platform_booting()) {
1576
		$reload = true;
1577
	}
1578

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

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

    
1621
	/*
1622
	 * NOTE: The following function parameter consists of
1623
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1624
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1625
	 */
1626

    
1627
	/* set up GRE virtual interfaces */
1628
	interfaces_tunnel_configure(1,'','gre');
1629

    
1630
	/* set up GIF virtual interfaces */
1631
	interfaces_tunnel_configure(1,'','gif');
1632

    
1633
	/* set up BRIDGE virtual interfaces */
1634
	interfaces_bridge_configure(1);
1635

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

    
1644
		interface_configure($if, $reload);
1645

    
1646
		if (platform_booting()) {
1647
			echo gettext("done.") . "\n";
1648
		}
1649
	}
1650

    
1651
	/* bring up vip interfaces */
1652
	interfaces_vips_configure();
1653

    
1654
	/* set up GRE virtual interfaces */
1655
	interfaces_tunnel_configure(2,'','gre');
1656

    
1657
	/* set up GIF virtual interfaces */
1658
	interfaces_tunnel_configure(2,'','gif');
1659

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

    
1668
		interface_configure($if, $reload);
1669

    
1670
		if (platform_booting()) {
1671
			echo gettext("done.") . "\n";
1672
		}
1673
	}
1674

    
1675
	/* set up BRIDGE virtual interfaces */
1676
	interfaces_bridge_configure(2);
1677

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

    
1686
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1687
		// redmine #3997
1688
		interface_reconfigure($if, $reload);
1689
		interfaces_vips_configure($if);
1690

    
1691
		if (platform_booting()) {
1692
			echo gettext("done.") . "\n";
1693
		}
1694
	}
1695

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

    
1704
		interface_configure($if, $reload);
1705

    
1706
		if (platform_booting()) {
1707
			echo gettext("done.") . "\n";
1708
		}
1709
	}
1710

    
1711
	/* set up IPsec VTI interfaces */
1712
	interfaces_ipsec_vti_configure();
1713

    
1714
	/* configure interface groups */
1715
	interfaces_group_setup();
1716

    
1717
	if (!platform_booting()) {
1718
		/* reconfigure static routes (kernel may have deleted them) */
1719
		system_routing_configure();
1720

    
1721
		/* reload IPsec tunnels */
1722
		ipsec_configure();
1723

    
1724
		/* restart dns servers (defering dhcpd reload) */
1725
		if (config_get_path('dnsmasq/enable')) {
1726
			services_dnsmasq_configure(false);
1727
		}
1728
		if (config_get_path('unbound/enable')) {
1729
			services_unbound_configure(false);
1730
		}
1731

    
1732
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1733
		services_dhcpd_configure();
1734
	}
1735

    
1736
	return 0;
1737
}
1738

    
1739
function interface_reconfigure($interface = "wan", $reloadall = false) {
1740
	interface_bring_down($interface);
1741
	interface_configure($interface, $reloadall);
1742
}
1743

    
1744
function interface_vip_bring_down($vip) {
1745
	global $g;
1746

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

    
1776
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1777
	global $g;
1778

    
1779
	$iface = config_get_path("interfaces/{$interface}");
1780
	if (!$iface) {
1781
		return;
1782
	}
1783

    
1784
	if (g_get('debug')) {
1785
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1786
	}
1787

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

    
1817
	/* check all gateways, including dynamic,
1818
	 * see https://redmine.pfsense.org/issues/12920 */
1819
	foreach (get_gateways(GW_CACHE_DISABLED) as $gw) {
1820
		if ($gw['friendlyiface'] == $interface) {
1821
			$restart_gateways_monitor = true;
1822
			break;
1823
		}
1824
	}
1825

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

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

    
1931
	if (!empty($track6) && is_array($track6)) {
1932
		if (!function_exists('services_dhcpd_configure')) {
1933
			require_once('services.inc');
1934
		}
1935
		/* Bring down radvd and dhcp6 on these interfaces */
1936
		services_dhcpd_configure('inet6');
1937
	}
1938

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

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

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

    
1969
			/* Invalidate cache */
1970
			get_interface_arr(true);
1971
		}
1972
	}
1973

    
1974
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
1975
	if ($restart_gateways_monitor) {
1976
		setup_gateways_monitor();
1977
	}
1978

    
1979
	return;
1980
}
1981

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

    
1992
	foreach (config_get_path('virtualip/vip', []) as $vip) {
1993
		if ($vip['mode'] == "carp") {
1994
			interface_carp_configure($vip, true);
1995
		}
1996
	}
1997
}
1998

    
1999
function interface_wait_tentative($interface, $timeout = 10) {
2000
	if (!does_interface_exist($interface)) {
2001
		return false;
2002
	}
2003

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

    
2014
	return false;
2015
}
2016

    
2017
function interface_isppp_type($interface) {
2018
	$iface = config_get_path("interfaces/{$interface}");
2019
	if (!is_array($iface)) {
2020
		return false;
2021
	}
2022

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

    
2036
function interfaces_ptpid_used($ptpid) {
2037
	$ppps = config_get_path('ppps/ppp');
2038
	if (is_array($ppps)) {
2039
		foreach ($ppps as $settings) {
2040
			if ($ptpid == $settings['ptpid']) {
2041
				return true;
2042
			}
2043
		}
2044
	}
2045

    
2046
	return false;
2047
}
2048

    
2049
function interfaces_ptpid_next() {
2050
	$ptpid = 0;
2051
	while (interfaces_ptpid_used($ptpid)) {
2052
		$ptpid++;
2053
	}
2054

    
2055
	return $ptpid;
2056
}
2057

    
2058
function getMPDCRONSettings($pppif) {
2059
	global $g;
2060

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

    
2068
	return NULL;
2069
}
2070

    
2071
function handle_pppoe_reset($post_array) {
2072
	global $g;
2073

    
2074
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2075
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2076

    
2077
	if (!is_array(config_get_path('cron/item'))) {
2078
		if (config_set_path('cron/item', array()) === null)
2079
			log_error(gettext('Cron section in config root is invalid.'));
2080
			return;
2081
	}
2082

    
2083
	$itemhash = getMPDCRONSettings($pppif);
2084

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

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

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

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

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

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

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

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

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

    
2267
				if (!is_ipaddr($localips[$pid])) {
2268
					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));
2269
					$localips[$pid] = "0.0.0.0";
2270
				}
2271
				if (!g_get('booting') && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2272
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2273
				}
2274
				if (!is_ipaddr($gateways[$pid])) {
2275
					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']));
2276
					return 0;
2277
				}
2278
				break;
2279
			case "ppp":
2280
				if (!file_exists("{$port}")) {
2281
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2282
					return 0;
2283
				}
2284
				break;
2285
			default:
2286
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2287
				break;
2288
		}
2289
	}
2290

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

    
2298
	if ($type == "modem") {
2299
		if (is_ipaddr($ppp['localip'])) {
2300
			$localip = $ppp['localip'];
2301
		} else {
2302
			$localip = '0.0.0.0';
2303
		}
2304

    
2305
		if (is_ipaddr($ppp['gateway'])) {
2306
			$gateway = $ppp['gateway'];
2307
		} else {
2308
			$gateway = "10.64.64.{$pppid}";
2309
		}
2310
		$ranges = "{$localip}/0 {$gateway}/0";
2311

    
2312
		if (empty($ppp['apnum'])) {
2313
			$ppp['apnum'] = 1;
2314
		}
2315
	} else {
2316
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2317
	}
2318

    
2319
	if (isset($ppp['ondemand'])) {
2320
		$ondemand = "enable";
2321
	} else {
2322
		$ondemand = "disable";
2323
	}
2324
	if (!isset($ppp['idletimeout'])) {
2325
		$ppp['idletimeout'] = 0;
2326
	}
2327

    
2328
	if (empty($ppp['username']) && $type == "modem") {
2329
		$ppp['username'] = "user";
2330
		$ppp['password'] = "none";
2331
	}
2332
	if (empty($ppp['password']) && $type == "modem") {
2333
		$passwd = "none";
2334
	} else {
2335
		$passwd = base64_decode($ppp['password']);
2336
	}
2337

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

    
2356
	// Construct the mpd.conf file
2357
	$mpdconf = <<<EOD
2358
startup:
2359
	# configure the console
2360
	set console close
2361
	# configure the web server
2362
	set web close
2363

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

    
2376
EOD;
2377

    
2378
	if (isset($ifcfg['descr'])) {
2379
		$mpdconf .= <<<EOD
2380
	set iface description "{$ifcfg['descr']}"
2381

    
2382
EOD;
2383
	}
2384
	$setdefaultgw = false;
2385
	$defgw4 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw4'));
2386
//	$defgw6 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw6'));
2387
	if ($defgw4['interface'] == $interface) {
2388
		$setdefaultgw = true;
2389
	}
2390

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

    
2400
EOD;
2401
	}
2402

    
2403
	$mpdconf .= <<<EOD
2404
	set iface {$ondemand} on-demand
2405
	set iface idle {$ppp['idletimeout']}
2406

    
2407
EOD;
2408

    
2409
	if (isset($ppp['ondemand'])) {
2410
		$mpdconf .= <<<EOD
2411
	set iface addrs 10.10.1.1 10.10.1.2
2412

    
2413
EOD;
2414
	}
2415

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

    
2436
EOD;
2437
	}
2438

    
2439
	if (isset($ppp['tcpmssfix'])) {
2440
		$tcpmss = "disable";
2441
	} else {
2442
		$tcpmss = "enable";
2443
	}
2444
	$mpdconf .= <<<EOD
2445
	set iface {$tcpmss} tcpmssfix
2446

    
2447
EOD;
2448

    
2449
	$mpdconf .= <<<EOD
2450
	set iface up-script /usr/local/sbin/ppp-linkup
2451
	set iface down-script /usr/local/sbin/ppp-linkdown
2452
	set ipcp ranges {$ranges}
2453

    
2454
EOD;
2455
	if (isset($ppp['vjcomp'])) {
2456
		$mpdconf .= <<<EOD
2457
	set ipcp no vjcomp
2458

    
2459
EOD;
2460
	}
2461

    
2462
	if (config_path_enabled('system', 'dnsallowoverride')) {
2463
		$mpdconf .= <<<EOD
2464
	set ipcp enable req-pri-dns
2465
	set ipcp enable req-sec-dns
2466

    
2467
EOD;
2468
	}
2469

    
2470
	if (!isset($ppp['verbose_log'])) {
2471
		$mpdconf .= <<<EOD
2472
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2473

    
2474
EOD;
2475
	}
2476

    
2477
	foreach ($ports as $pid => $port) {
2478
		$port = get_real_interface($port);
2479
		$mpdconf .= <<<EOD
2480

    
2481
	create link static {$interface}_link{$pid} {$type}
2482
	set link action bundle {$interface}
2483
	set link {$multilink} multilink
2484
	set link keep-alive 10 60
2485
	set link max-redial 0
2486

    
2487
EOD;
2488
		if (isset($ppp['shortseq'])) {
2489
			$mpdconf .= <<<EOD
2490
	set link no shortseq
2491

    
2492
EOD;
2493
		}
2494

    
2495
		if (isset($ppp['acfcomp'])) {
2496
			$mpdconf .= <<<EOD
2497
	set link no acfcomp
2498

    
2499
EOD;
2500
		}
2501

    
2502
		if (isset($ppp['protocomp'])) {
2503
			$mpdconf .= <<<EOD
2504
	set link no protocomp
2505

    
2506
EOD;
2507
		}
2508

    
2509
		$mpdconf .= <<<EOD
2510
	set link disable chap pap
2511
	set link accept chap pap eap
2512
	set link disable incoming
2513

    
2514
EOD;
2515

    
2516

    
2517
		if (!empty($bandwidths[$pid])) {
2518
			$mpdconf .= <<<EOD
2519
	set link bandwidth {$bandwidths[$pid]}
2520

    
2521
EOD;
2522
		}
2523

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

    
2539
EOD;
2540
		}
2541

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

    
2548
EOD;
2549
		}
2550

    
2551
		if (!empty($mrrus[$pid])) {
2552
			$mpdconf .= <<<EOD
2553
	set link mrru {$mrrus[$pid]}
2554

    
2555
EOD;
2556
		}
2557

    
2558
		$mpdconf .= <<<EOD
2559
	set auth authname "{$ppp['username']}"
2560
	set auth password {$passwd}
2561

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

    
2572
EOD;
2573
		}
2574
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2575
			$mpdconf .= <<<EOD
2576
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2577

    
2578
EOD;
2579
		}
2580
		if (isset($ppp['initstr']) && $type == "modem") {
2581
			$initstr = base64_decode($ppp['initstr']);
2582
			$mpdconf .= <<<EOD
2583
	set modem var \$InitString "{$initstr}"
2584

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

    
2595
EOD;
2596
		}
2597
		if (isset($ppp['apn']) && $type == "modem") {
2598
			$mpdconf .= <<<EOD
2599
	set modem var \$APN "{$ppp['apn']}"
2600
	set modem var \$APNum "{$ppp['apnum']}"
2601

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

    
2618
EOD;
2619
		}
2620
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2621
			$mpdconf .= <<<EOD
2622
	set pppoe max-payload {$mtus[$pid]}
2623

    
2624
EOD;
2625
		}
2626
		if ($type == "pppoe") {
2627
			$mpdconf .= <<<EOD
2628
	set pppoe iface {$port}
2629

    
2630
EOD;
2631
		}
2632

    
2633
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2634
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2635
			$mpdconf .= <<<EOD
2636
	set l2tp secret "{$secret}"
2637

    
2638
EOD;
2639
		}
2640

    
2641
		if (($type == "pptp") || ($type == "l2tp")) {
2642
			$mpdconf .= <<<EOD
2643
	set {$type} self {$localips[$pid]}
2644
	set {$type} peer {$gateways[$pid]}
2645

    
2646
EOD;
2647
		}
2648

    
2649
		$mpdconf .= "\topen\n";
2650
	} //end foreach ($port)
2651

    
2652

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

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

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

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

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

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

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

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

    
2759
	return 1;
2760
}
2761

    
2762
function interfaces_sync_setup() {
2763

    
2764
	if (config_get_path('system/developerspew')) {
2765
		$mt = microtime();
2766
		echo "interfaces_sync_setup() being called $mt\n";
2767
	}
2768

    
2769
	if (platform_booting()) {
2770
		echo gettext("Configuring CARP settings...");
2771
		mute_kernel_msgs();
2772
	}
2773

    
2774
	/* suck in configuration items */
2775
	if (!empty(config_get_path('hasync'))) {
2776
		$pfsyncenabled = config_get_path('hasync/pfsyncenabled');
2777
		$pfsyncinterface = config_get_path('hasync/pfsyncinterface');
2778
		$pfsyncpeerip = config_get_path('hasync/pfsyncpeerip');
2779
	}
2780

    
2781
	set_sysctl(array(
2782
		"net.inet.carp.preempt" => "1",
2783
		"net.inet.carp.log" => "1")
2784
	);
2785

    
2786
	if (!empty($pfsyncinterface)) {
2787
		$carp_sync_int = get_real_interface($pfsyncinterface);
2788
	}
2789

    
2790
	/* setup pfsync interface */
2791
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2792
		if (is_ipaddr($pfsyncpeerip)) {
2793
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2794
		} else {
2795
			$syncpeer = "-syncpeer";
2796
		}
2797

    
2798
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2799
		    "{$syncpeer} up");
2800
		mwexec("/sbin/ifconfig pfsync0 -defer");
2801

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

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

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

    
2824
	/* Don't enable CARP if we haven't booted */
2825
	if (!is_platform_booting()) {
2826
		enable_carp();
2827
	}
2828

    
2829
	if (platform_booting()) {
2830
		unmute_kernel_msgs();
2831
		echo gettext("done.") . "\n";
2832
	}
2833
}
2834

    
2835
function interface_proxyarp_configure($interface = "") {
2836
	global $g;
2837
	if (config_get_path('system/developerspew')) {
2838
		$mt = microtime();
2839
		echo "interface_proxyarp_configure() being called $mt\n";
2840
	}
2841

    
2842
	/* kill any running choparp */
2843
	if (empty($interface)) {
2844
		killbyname("choparp");
2845
	} else {
2846
		$vipif = get_real_interface($interface);
2847
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2848
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2849
		}
2850
	}
2851

    
2852
	$paa = array();
2853
	$vips = config_get_path('virtualip/vip');
2854
	if (is_array($vips)) {
2855

    
2856
		/* group by interface */
2857
		foreach ($vips as $vipent) {
2858
			if ($vipent['mode'] === "proxyarp") {
2859
				if ($vipent['interface']) {
2860
					$proxyif = $vipent['interface'];
2861
				} else {
2862
					$proxyif = "wan";
2863
				}
2864

    
2865
				if (!empty($interface) && $interface != $proxyif) {
2866
					continue;
2867
				}
2868

    
2869
				if (!is_array($paa[$proxyif])) {
2870
					$paa[$proxyif] = array();
2871
				}
2872

    
2873
				$paa[$proxyif][] = $vipent;
2874
			}
2875
		}
2876
	}
2877

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

    
2917
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2918
	$vips = config_get_path('virtualip/vip');
2919
	if (is_array($vips)) {
2920
		foreach ($vips as $vip) {
2921

    
2922
			$iface = $vip['interface'];
2923
			if (substr($iface, 0, 4) == "_vip")
2924
				$iface = get_configured_vip_interface($vip['interface']);
2925
			if ($iface != $interface)
2926
				continue;
2927
			if ($type == VIP_CARP) {
2928
				if ($vip['mode'] != "carp")
2929
					continue;
2930
			} elseif ($type == VIP_IPALIAS) {
2931
				if ($vip['mode'] != "ipalias")
2932
					continue;
2933
			} else {
2934
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2935
					continue;
2936
			}
2937

    
2938
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2939
				interface_vip_bring_down($vip);
2940
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2941
				interface_vip_bring_down($vip);
2942
			elseif ($inet == "all")
2943
				interface_vip_bring_down($vip);
2944
		}
2945
	}
2946
}
2947

    
2948
function interfaces_vips_configure($interface = "") {
2949
	if (config_get_path('system/developerspew')) {
2950
		$mt = microtime();
2951
		echo "interfaces_vips_configure() being called $mt\n";
2952
	}
2953

    
2954
	$vips = config_get_path('virtualip/vip');
2955
	if (!is_array($vips)) {
2956
		return;
2957
	}
2958

    
2959
	$carp_configured = false;
2960
	$anyproxyarp = false;
2961
	foreach ($vips as $vip) {
2962
		if ($interface <> "" &&
2963
		    get_root_interface($vip['interface']) <> $interface) {
2964
			continue;
2965
		}
2966
		switch ($vip['mode']) {
2967
			case "proxyarp":
2968
				/*
2969
				 * nothing it is handled on
2970
				 * interface_proxyarp_configure()
2971
				 */
2972
				$anyproxyarp = true;
2973
				break;
2974
			case "ipalias":
2975
				interface_ipalias_configure($vip);
2976
				break;
2977
			case "carp":
2978
				if ($carp_configured == false) {
2979
					$carp_configured = true;
2980
				}
2981
				interface_carp_configure($vip);
2982
				break;
2983
		}
2984
	}
2985
	/* interfaces_sync_setup() is directly called in rc.bootup*/
2986
	if (!is_platform_booting() && $carp_configured == true) {
2987
		interfaces_sync_setup();
2988
	}
2989
	if ($anyproxyarp == true) {
2990
		interface_proxyarp_configure();
2991
	}
2992
}
2993

    
2994
function interface_ipalias_configure(&$vip) {
2995
	$gateway = '';
2996
	if ($vip['mode'] != 'ipalias') {
2997
		return;
2998
	}
2999

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

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

    
3030
function interface_carp_configure(&$vip, $maintenancemode_only = false, $ipalias_reload = false) {
3031
	if (config_get_path('system/developerspew')) {
3032
		$mt = microtime();
3033
		echo "interface_carp_configure() being called $mt\n";
3034
	}
3035

    
3036
	if ($vip['mode'] != "carp") {
3037
		return;
3038
	}
3039

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

    
3053
	$vip_password = $vip['password'];
3054
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3055
	    $vip_password)));
3056
	if ($vip['password'] != "") {
3057
		$password = " pass {$vip_password}";
3058
	}
3059

    
3060
	$advbase = "";
3061
	if (!empty($vip['advbase'])) {
3062
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3063
	}
3064

    
3065
	$carp_maintenancemode = config_path_enabled('/','virtualip_carp_maintenancemode');
3066
	if ($carp_maintenancemode) {
3067
		$advskew = "advskew 254";
3068
	} else {
3069
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3070
	}
3071

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

    
3075
	if (!$maintenancemode_only) {
3076
		if (is_ipaddrv4($vip['subnet'])) {
3077
			mwexec("/sbin/ifconfig {$realif} " .
3078
			    escapeshellarg($vip['subnet']) . "/" .
3079
			    escapeshellarg($vip['subnet_bits']) .
3080
			    " alias vhid " . escapeshellarg($vip['vhid']));
3081
		} elseif (is_ipaddrv6($vip['subnet'])) {
3082
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3083
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3084
			    escapeshellarg($vip['subnet_bits']) .
3085
			    " alias vhid " . escapeshellarg($vip['vhid']));
3086
		}
3087
	}
3088

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

    
3102
	return $realif;
3103
}
3104

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

    
3147
	if ($needs_clone == true) {
3148
		/* remove previous instance if it exists */
3149
		if (does_interface_exist($realif)) {
3150
			pfSense_interface_destroy($realif);
3151

    
3152
			/* Invalidate cache */
3153
			get_interface_arr(true);
3154
		}
3155

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

    
3172
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3173

    
3174
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3175
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3176
				 'regdomain', 'regcountry', 'reglocation');
3177

    
3178
	if (!is_interface_wireless($ifcfg['if'])) {
3179
		return;
3180
	}
3181

    
3182
	$baseif = interface_get_wireless_base($ifcfg['if']);
3183

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

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

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

    
3250
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3251
	global $g;
3252

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

    
3260
	// Remove script file
3261
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3262

    
3263
	// Clone wireless nic if needed.
3264
	interface_wireless_clone($if, $wl);
3265

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

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

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

    
3275
	/* set values for /path/program */
3276
	if (file_exists("/usr/local/sbin/hostapd")) {
3277
		$hostapd = "/usr/local/sbin/hostapd";
3278
	} else {
3279
		$hostapd = "/usr/sbin/hostapd";
3280
	}
3281
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3282
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3283
	} else {
3284
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3285
	}
3286
	$ifconfig = "/sbin/ifconfig";
3287
	$sysctl = "/sbin/sysctl";
3288
	$sysctl_args = "-q";
3289

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

    
3292
	$wlcmd = array();
3293
	$wl_sysctl = array();
3294
	/* Set a/b/g standard */
3295
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3296
	/* skip mode entirely for "auto" */
3297
	if ($wlcfg['standard'] != "auto") {
3298
		$wlcmd[] = "mode " . escapeshellarg($standard);
3299
	}
3300

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

    
3307
	/* Set ssid */
3308
	if ($wlcfg['ssid']) {
3309
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3310
	}
3311

    
3312
	/* Set 802.11g protection mode */
3313
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3314

    
3315
	/* set wireless channel value */
3316
	if (isset($wlcfg['channel'])) {
3317
		if ($wlcfg['channel'] == "0") {
3318
			$wlcmd[] = "channel any";
3319
		} else {
3320
			if ($wlcfg['channel_width'] != "0") {
3321
				$channel_width = ":" . $wlcfg['channel_width'];
3322
			} else {
3323
				$channel_width = '';
3324
			}
3325
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3326
		}
3327
	}
3328

    
3329
	/* Set antenna diversity value */
3330
	if (isset($wlcfg['diversity'])) {
3331
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3332
	}
3333

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

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

    
3344
	/* set Distance value */
3345
	if ($wlcfg['distance']) {
3346
		$distance = escapeshellarg($wlcfg['distance']);
3347
	}
3348

    
3349
	/* Set wireless hostap mode */
3350
	if ($wlcfg['mode'] == "hostap") {
3351
		$wlcmd[] = "mediaopt hostap";
3352
	} else {
3353
		$wlcmd[] = "-mediaopt hostap";
3354
	}
3355

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

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

    
3365
	/* handle hide ssid option */
3366
	if (isset($wlcfg['hidessid']['enable'])) {
3367
		$wlcmd[] = "hidessid";
3368
	} else {
3369
		$wlcmd[] = "-hidessid";
3370
	}
3371

    
3372
	/* handle pureg (802.11g) only option */
3373
	if (isset($wlcfg['pureg']['enable'])) {
3374
		$wlcmd[] = "mode 11g pureg";
3375
	} else {
3376
		$wlcmd[] = "-pureg";
3377
	}
3378

    
3379
	/* handle puren (802.11n) only option */
3380
	if (isset($wlcfg['puren']['enable'])) {
3381
		$wlcmd[] = "puren";
3382
	} else {
3383
		$wlcmd[] = "-puren";
3384
	}
3385

    
3386
	/* enable apbridge option */
3387
	if (isset($wlcfg['apbridge']['enable'])) {
3388
		$wlcmd[] = "apbridge";
3389
	} else {
3390
		$wlcmd[] = "-apbridge";
3391
	}
3392

    
3393
	/* handle turbo option */
3394
	if (isset($wlcfg['turbo']['enable'])) {
3395
		$wlcmd[] = "mediaopt turbo";
3396
	} else {
3397
		$wlcmd[] = "-mediaopt turbo";
3398
	}
3399

    
3400
	/* handle txpower setting */
3401
	// or don't. this has issues at the moment.
3402
	/*
3403
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3404
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3405
	}*/
3406

    
3407
	/* handle wme option */
3408
	if (isset($wlcfg['wme']['enable'])) {
3409
		$wlcmd[] = "wme";
3410
	} else {
3411
		$wlcmd[] = "-wme";
3412
	}
3413

    
3414
	/* Enable wpa if it's configured. No WEP support anymore. */
3415
	if (isset($wlcfg['wpa']['enable'])) {
3416
		$wlcmd[] = "authmode wpa wepmode off ";
3417
	} else {
3418
		$wlcmd[] = "authmode open wepmode off ";
3419
	}
3420

    
3421
	kill_hostapd($if);
3422
	mwexec(kill_wpasupplicant("{$if}"));
3423

    
3424
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3425
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3426

    
3427
	unlink_if_exists("{$wpa_supplicant_file}*");
3428
	unlink_if_exists($hostapd_conf);
3429

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

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

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

    
3517
EOD;
3518

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

    
3525
EOD;
3526
				}
3527
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3528
					$wpa .= "ieee8021x=1\n";
3529

    
3530
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3531
						$auth_server_port = "1812";
3532
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3533
							$auth_server_port = intval($wlcfg['auth_server_port']);
3534
						}
3535
						$wpa .= <<<EOD
3536

    
3537
auth_server_addr={$wlcfg['auth_server_addr']}
3538
auth_server_port={$auth_server_port}
3539
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3540

    
3541
EOD;
3542
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3543
							$auth_server_port2 = "1812";
3544
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3545
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3546
							}
3547

    
3548
							$wpa .= <<<EOD
3549
auth_server_addr={$wlcfg['auth_server_addr2']}
3550
auth_server_port={$auth_server_port2}
3551
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3552

    
3553
EOD;
3554
						}
3555
					}
3556
				}
3557

    
3558
				@file_put_contents($hostapd_conf, $wpa);
3559
				unset($wpa);
3560
			}
3561
			break;
3562
	}
3563

    
3564
	/*
3565
	 *    all variables are set, lets start up everything
3566
	 */
3567

    
3568
	$baseif = interface_get_wireless_base($if);
3569
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3570
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3571

    
3572
	/* set sysctls for the wireless interface */
3573
	if (!empty($wl_sysctl)) {
3574
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3575
		foreach ($wl_sysctl as $wl_sysctl_line) {
3576
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3577
		}
3578
	}
3579

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

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

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

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

    
3614
	fclose($fd_set);
3615

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

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

    
3637
	if ($reg_changing) {
3638
		/* set regulatory domain */
3639
		if ($wlcfg['regdomain']) {
3640
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3641
		}
3642

    
3643
		/* set country */
3644
		if ($wlcfg['regcountry']) {
3645
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3646
		}
3647

    
3648
		/* set location */
3649
		if ($wlcfg['reglocation']) {
3650
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3651
		}
3652

    
3653
		$wlregcmd_args = implode(" ", $wlregcmd);
3654

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

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

    
3676
		/* apply the regulatory settings */
3677
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3678
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3679

    
3680
		/* bring the clones back up that were previously up */
3681
		foreach ($clones_up as $clone_if) {
3682
			interfaces_bring_up($clone_if);
3683

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

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

    
3709
	/* configure wireless */
3710
	$wlcmd_args = implode(" ", $wlcmd);
3711
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3712
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3713
	/* Bring the interface up only after setting up all the other parameters. */
3714
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3715
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3716
	fclose($wlan_setup_log);
3717

    
3718
	unset($wlcmd_args, $wlcmd);
3719

    
3720

    
3721
	sleep(1);
3722
	/* execute hostapd and wpa_supplicant if required in shell */
3723
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3724

    
3725
	return 0;
3726

    
3727
}
3728

    
3729
function kill_hostapd($interface) {
3730
	global $g;
3731

    
3732
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3733
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3734
	}
3735
}
3736

    
3737
function kill_wpasupplicant($interface) {
3738
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3739
}
3740

    
3741
function find_dhclient_process($interface) {
3742
	if ($interface) {
3743
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3744
	} else {
3745
		$pid = 0;
3746
	}
3747

    
3748
	return intval($pid);
3749
}
3750

    
3751
function kill_dhclient_process($interface) {
3752
	if (empty($interface) || !does_interface_exist($interface)) {
3753
		return;
3754
	}
3755

    
3756
	$i = 0;
3757
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3758
		/* 3rd time make it die for sure */
3759
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3760
		posix_kill($pid, $sig);
3761
		sleep(1);
3762
		$i++;
3763
	}
3764
	unset($i);
3765

    
3766
	unlink_if_exists(g_get('vardb_path') . "/{$interface}_cacheip");
3767
}
3768

    
3769
function find_dhcp6c_process() {
3770
	global $g;
3771

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

    
3778
	return intval($pid);
3779
}
3780

    
3781
function kill_dhcp6client_process($force, $release = false) {
3782
	global $g;
3783

    
3784
	$i = 0;
3785

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

    
3791
	if (empty($interface) || !does_interface_exist($interface)) {
3792
		return;
3793
	}
3794
	*/
3795

    
3796
	/*********** Notes on signals for dhcp6c and this function *************
3797

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

    
3804
	If we want to exit normally obeying the no release flag then use SIGTERM.
3805
	If we want to exit with a release overriding the no release flag then
3806
	use SIGUSR2.
3807

    
3808
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3809
	exit quickly without sending release signals.
3810

    
3811
	If $Force is set to false and $release is also set to false dhcp6c will
3812
	follow the no-release flag.
3813

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

    
3818
	if ($force == true) {
3819
		$psig=SIGUSR1;
3820
	} elseif ($release == false) {
3821
		$psig=SIGTERM;
3822
	} else {
3823
		$psig=SIGUSR2;
3824
	}
3825

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

    
3839
	$pid = find_dhcp6c_process();
3840

    
3841
	if($pid != 0) {
3842
		posix_kill($pid, SIGHUP);
3843
	}
3844
}
3845

    
3846
function run_dhcp6client_process($interfaces, $debugOption, $noreleaseOption) {
3847
	global $g;
3848

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

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

    
3873
function interface_virtual_create($interface) {
3874

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

    
3917
function interface_vlan_mtu_configured($iface) {
3918

    
3919
	$mtu = 0;
3920
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
3921

    
3922
		if ($vlan['vlanif'] != $iface)
3923
			continue;
3924

    
3925
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3926
		$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
3927
		if (!empty($assignedport) && !empty(config_get_path("interfaces/{$assignedport}/mtu"))) {
3928
			/* VLAN MTU */
3929
			$mtu = config_get_path("interfaces/{$assignedport}/mtu");
3930
		} elseif (!empty(config_get_path("interfaces/{$parentinf}/mtu"))) {
3931
			/* Parent MTU */
3932
			$mtu = config_get_path("interfaces/{$parentinf}/mtu");
3933
		}
3934
	}
3935

    
3936
	return $mtu;
3937
}
3938

    
3939
function interface_mtu_wanted_for_pppoe($realif) {
3940

    
3941
	$mtu = 0;
3942
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
3943
		if ($ppp['type'] != "pppoe") {
3944
			continue;
3945
		}
3946

    
3947
		$mtus = array();
3948
		if (!empty($ppp['mtu'])) {
3949
			$mtus = explode(',', $ppp['mtu']);
3950
		}
3951
		$ports = explode(',', $ppp['ports']);
3952

    
3953
		foreach ($ports as $pid => $port) {
3954
			$parentifa = get_parent_interface($port);
3955
			$parentif = $parentifa[0];
3956
			if ($parentif != $realif)
3957
				continue;
3958

    
3959
			// there is an MTU configured on the port in question
3960
			if (!empty($mtus[$pid])) {
3961
				$mtu = intval($mtus[$pid]) + 8;
3962
			// or use the MTU configured on the interface ...
3963
			} else {
3964
				foreach (config_get_path('interfaces', []) as $interface) {
3965
					if ($interface['if'] == $ppp['if'] &&
3966
					    !empty($interface['mtu'])) {
3967
						$mtu = intval($interface['mtu']) + 8;
3968
						break;
3969
					}
3970
				}
3971
			}
3972
		}
3973
	}
3974

    
3975
	return $mtu;
3976
}
3977

    
3978
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
3979
	global $g;
3980
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
3981
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
3982

    
3983
	$wancfg = config_get_path("interfaces/{$interface}");
3984

    
3985
	if (!isset($wancfg['enable'])) {
3986
		return;
3987
	}
3988

    
3989
	$realif = get_real_interface($interface);
3990
	$realhwif_array = get_parent_interface($interface);
3991
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
3992
	$realhwif = $realhwif_array[0];
3993

    
3994
	$mac_if_cfg = $wancfg;
3995
	if (interface_is_vlan($realif)) {
3996
		$mac_if = convert_real_interface_to_friendly_interface_name(
3997
		    $realhwif);
3998
		if (is_array(config_get_path("interfaces/{$mac_if}"))) {
3999
			$mac_if_cfg = config_get_path("interfaces/{$mac_if}");
4000
		} else {
4001
			$mac_if = $interface;
4002
		}
4003
	}
4004

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

    
4028
		/* only bring down the interface when both v4 and v6 are set to NONE */
4029
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4030
			interface_bring_down($interface);
4031
		}
4032
	}
4033

    
4034
	$interface_to_check = $realif;
4035
	if (interface_isppp_type($interface)) {
4036
		$interface_to_check = $realhwif;
4037
	}
4038

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

    
4045
	/* Disable Accepting router advertisements unless specifically requested */
4046
	if (g_get('debug')) {
4047
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4048
	}
4049
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4050
	{
4051
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4052
	}
4053
	/* wireless configuration? */
4054
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4055
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4056
	}
4057

    
4058
	$current_mac = get_interface_mac($realhwif);
4059
	$vendor_mac = get_interface_vendor_mac($realhwif);
4060

    
4061
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4062
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4063

    
4064
		interface_set_macaddr($realhwif, $mac_addr);
4065

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

    
4095
	/* media */
4096
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4097
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4098
		if ($wancfg['media']) {
4099
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4100
		}
4101
		if ($wancfg['mediaopt']) {
4102
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4103
		}
4104
		mwexec($cmd);
4105
	}
4106

    
4107
	/* Apply hw offloading policies as configured */
4108
	enable_hardware_offloading($interface);
4109

    
4110
	/* invalidate interface/ip/sn cache */
4111
	get_interface_arr(true);
4112
	unset($interface_ip_arr_cache[$realif]);
4113
	unset($interface_sn_arr_cache[$realif]);
4114
	unset($interface_ipv6_arr_cache[$realif]);
4115
	unset($interface_snv6_arr_cache[$realif]);
4116

    
4117
	$tunnelif = substr($realif, 0, 3);
4118

    
4119
	$mtuif = $realif;
4120
	$mtuhwif = $realhwif;
4121

    
4122
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4123
	if (interface_isppp_type($interface)) {
4124
		$mtuif = $realhwif;
4125
		$mtuhwif_array = get_parent_interface($mtuif);
4126
		$mtuhwif = $mtuhwif_array[0];
4127
	}
4128

    
4129
	$wantedmtu = 0;
4130
	foreach (config_get_path('interfaces', []) as $tmpinterface) {
4131
		if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4132
			$wantedmtu = $tmpinterface['mtu'];
4133
			break;
4134
		}
4135
	}
4136

    
4137
	/* MTU is not specified for interface, try the pppoe settings. */
4138
	if ($wantedmtu == 0) {
4139
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4140
	}
4141
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4142
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4143
	}
4144
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4145
		/* set MTU to 1400 for GRE over IPsec */
4146
		if (is_greipsec($mtuif)) {
4147
			$wantedmtu = 1400;
4148
		} else {
4149
			$wantedmtu = 1476;
4150
		}
4151
	}
4152
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4153
		$wantedmtu = 1280;
4154
	}
4155

    
4156
	/* Set the MTU to 1500 if no explicit MTU configured. */
4157
	if ($wantedmtu == 0) {
4158
		$wantedmtu = 1500; /* Default */
4159
	}
4160

    
4161
	if (interface_is_vlan($mtuif) != NULL) {
4162
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4163
		if (!empty($assignedparent) && !empty(config_get_path("interfaces/{$assignedparent}/mtu"))) {
4164
			$parentmtu = config_get_path("interfaces/{$assignedparent}/mtu");
4165
			if ($wancfg['mtu'] > $parentmtu) {
4166
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4167
			}
4168
		}
4169

    
4170
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4171

    
4172
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4173
			$configuredmtu = $parentmtu;
4174
		if ($configuredmtu != 0)
4175
			$mtu = $configuredmtu;
4176
		else
4177
			$mtu = $wantedmtu;
4178

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

    
4203
	if (does_interface_exist($wancfg['if'])) {
4204
		interfaces_bring_up($wancfg['if']);
4205
	}
4206

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

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

    
4261
	if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4262
		$bridgetmp = link_interface_to_bridge($interface);
4263
		if (!empty($bridgetmp)) {
4264
			interface_bridge_add_member($bridgetmp, $realif);
4265
		}
4266
	}
4267

    
4268
	if (!platform_booting()) {
4269
		link_interface_to_vips($interface, "update");
4270

    
4271
		if ($tunnelif != 'gre') {
4272
			$gre = link_interface_to_tunnelif($interface, 'gre');
4273
			array_walk($gre, 'interface_gre_configure');
4274
		}
4275

    
4276
		if ($tunnelif != 'gif') {
4277
			$gif = link_interface_to_tunnelif($interface, 'gif');
4278
			array_walk($gif, 'interface_gif_configure');
4279
		}
4280

    
4281
		$grouptmp = link_interface_to_group($interface);
4282
		if (!empty($grouptmp)) {
4283
			array_walk($grouptmp, 'interface_group_add_member');
4284
		}
4285

    
4286
		if ($interface == "lan") {
4287
			/* make new hosts file */
4288
			system_hosts_generate();
4289
		}
4290

    
4291
		if ($reloadall == true) {
4292

    
4293
			/* reconfigure static routes (kernel may have deleted them) */
4294
			system_routing_configure($interface);
4295

    
4296
			/* reload ipsec tunnels */
4297
			send_event("service reload ipsecdns");
4298

    
4299
			if (config_path_enabled('dnsmasq')) {
4300
				services_dnsmasq_configure();
4301
			}
4302

    
4303
			if (config_path_enabled('unbound')) {
4304
				services_unbound_configure(true, $interface);
4305
			}
4306

    
4307
			/* update dyndns */
4308
			send_event("service reload dyndns {$interface}");
4309
		}
4310
	}
4311

    
4312
	if (!platform_booting() && (substr($realif, 0, 5) == 'l2tps')) {
4313
		vpn_l2tp_configure();
4314
	};
4315

    
4316
	if (!empty($wancfg['descr'])) {
4317
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4318
	};
4319

    
4320
	interfaces_staticarp_configure($interface);
4321
	return 0;
4322
}
4323

    
4324
function interface_track6_configure($interface, $wancfg, $linkupevent = false) {
4325
	global $g;
4326

    
4327
	if (!is_array($wancfg)) {
4328
		return;
4329
	}
4330

    
4331
	if (!isset($wancfg['enable'])) {
4332
		return;
4333
	}
4334

    
4335
	/* If the interface is not configured via another, exit */
4336
	if (empty($wancfg['track6-interface'])) {
4337
		return;
4338
	}
4339

    
4340
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4341
	$realif = get_real_interface($interface);
4342
	$linklocal = find_interface_ipv6_ll($realif, true);
4343
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4344
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4345
	}
4346

    
4347
	$trackcfg = config_get_path("interfaces/{$wancfg['track6-interface']}");
4348
	if (!isset($trackcfg['enable'])) {
4349
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4350
		return;
4351
	}
4352

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

    
4383
	if ($linkupevent == false && !platform_booting()) {
4384
		if (!function_exists('services_dhcpd_configure')) {
4385
			require_once("services.inc");
4386
		}
4387

    
4388
		/* restart dns servers (defering dhcpd reload) */
4389
		if (config_path_enabled('unbound')) {
4390
			services_unbound_configure(false, $interface);
4391
		}
4392
		if (config_path_enabled('dnsmasq')) {
4393
			services_dnsmasq_configure(false);
4394
		}
4395

    
4396
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4397
		services_dhcpd_configure("inet6");
4398
	}
4399

    
4400
	return 0;
4401
}
4402

    
4403
function interface_track6_6rd_configure($interface, $lancfg) {
4404
	global $interface_ipv6_arr_cache;
4405
	global $interface_snv6_arr_cache;
4406

    
4407
	if (!is_array($lancfg)) {
4408
		return;
4409
	}
4410

    
4411
	/* If the interface is not configured via another, exit */
4412
	if (empty($lancfg['track6-interface'])) {
4413
		return;
4414
	}
4415

    
4416
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4417
	if (empty($wancfg)) {
4418
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4419
		return;
4420
	}
4421

    
4422
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4423
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4424
		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']));
4425
		return;
4426
	}
4427
	$hexwanv4 = return_hex_ipv4($ip4address);
4428

    
4429
	/* create the long prefix notation for math, save the prefix length */
4430
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4431
	$rd6prefixlen = $rd6prefix[1];
4432
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4433

    
4434
	/* binary presentation of the prefix for all 128 bits. */
4435
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4436

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

    
4442
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4443
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4444
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4445
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4446
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4447
	/* fill the rest out with zeros */
4448
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4449

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

    
4453
	$lanif = get_real_interface($interface);
4454
	$oip = find_interface_ipv6($lanif);
4455
	if (is_ipaddrv6($oip)) {
4456
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4457
	}
4458
	unset($interface_ipv6_arr_cache[$lanif]);
4459
	unset($interface_snv6_arr_cache[$lanif]);
4460
	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));
4461
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4462

    
4463
	return 0;
4464
}
4465

    
4466
function interface_track6_6to4_configure($interface, $lancfg) {
4467
	global $interface_ipv6_arr_cache;
4468
	global $interface_snv6_arr_cache;
4469

    
4470
	if (!is_array($lancfg)) {
4471
		return;
4472
	}
4473

    
4474
	/* If the interface is not configured via another, exit */
4475
	if (empty($lancfg['track6-interface'])) {
4476
		return;
4477
	}
4478

    
4479
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4480
	if (empty($wancfg)) {
4481
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4482
		return;
4483
	}
4484

    
4485
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4486
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4487
		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']));
4488
		return;
4489
	}
4490
	$hexwanv4 = return_hex_ipv4($ip4address);
4491

    
4492
	/* create the long prefix notation for math, save the prefix length */
4493
	$sixto4prefix = "2002::";
4494
	$sixto4prefixlen = 16;
4495
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4496

    
4497
	/* binary presentation of the prefix for all 128 bits. */
4498
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4499

    
4500
	/* just save the left prefix length bits */
4501
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4502
	/* add the v4 address */
4503
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4504
	/* add the custom prefix id */
4505
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4506
	/* fill the rest out with zeros */
4507
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4508

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

    
4512
	$lanif = get_real_interface($interface);
4513
	$oip = find_interface_ipv6($lanif);
4514
	if (is_ipaddrv6($oip)) {
4515
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4516
	}
4517
	unset($interface_ipv6_arr_cache[$lanif]);
4518
	unset($interface_snv6_arr_cache[$lanif]);
4519
	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));
4520
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4521

    
4522
	return 0;
4523
}
4524

    
4525
function interface_6rd_configure($interface, $wancfg) {
4526
	global $g;
4527

    
4528
	/* because this is a tunnel interface we can only function
4529
	 *	with a public IPv4 address on the interface */
4530

    
4531
	if (!is_array($wancfg)) {
4532
		return;
4533
	}
4534

    
4535
	if (!is_module_loaded('if_stf.ko')) {
4536
		mwexec('/sbin/kldload if_stf.ko');
4537
	}
4538

    
4539
	$wanif = get_real_interface($interface);
4540
	$ip4address = find_interface_ip($wanif);
4541
	if (!is_ipaddrv4($ip4address)) {
4542
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4543
		return false;
4544
	}
4545
	$hexwanv4 = return_hex_ipv4($ip4address);
4546

    
4547
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4548
		$wancfg['prefix-6rd-v4plen'] = 0;
4549
	}
4550

    
4551
	/* create the long prefix notation for math, save the prefix length */
4552
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4553
	$rd6prefixlen = $rd6prefix[1];
4554
	$brgw = explode('.', $wancfg['gateway-6rd']);
4555
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4556
	$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);
4557
	if (strlen($rd6brgw) < 128) {
4558
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4559
	}
4560
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4561
	unset($brgw);
4562
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4563

    
4564
	/* binary presentation of the prefix for all 128 bits. */
4565
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4566

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

    
4574
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4575
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4576

    
4577

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

    
4601
	/* write out a default router file */
4602
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4603
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4604
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4605

    
4606
	$ip4gateway = get_interface_gateway($interface);
4607
	if (is_ipaddrv4($ip4gateway)) {
4608
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4609
	}
4610

    
4611
	/* configure dependent interfaces */
4612
	if (!platform_booting()) {
4613
		link_interface_to_track6($interface, "update");
4614
	}
4615

    
4616
	return 0;
4617
}
4618

    
4619
function interface_6to4_configure($interface, $wancfg) {
4620
	global $g;
4621

    
4622
	/* because this is a tunnel interface we can only function
4623
	 *	with a public IPv4 address on the interface */
4624

    
4625
	if (!is_array($wancfg)) {
4626
		return;
4627
	}
4628

    
4629
	$wanif = get_real_interface($interface);
4630
	$ip4address = find_interface_ip($wanif);
4631
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4632
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4633
		return false;
4634
	}
4635

    
4636
	/* create the long prefix notation for math, save the prefix length */
4637
	$stfprefixlen = 16;
4638
	$stfprefix = Net_IPv6::uncompress("2002::");
4639
	$stfarr = explode(":", $stfprefix);
4640
	$v4prefixlen = "0";
4641

    
4642
	/* we need the hex form of the interface IPv4 address */
4643
	$ip4arr = explode(".", $ip4address);
4644
	$hexwanv4 = "";
4645
	foreach ($ip4arr as $octet) {
4646
		$hexwanv4 .= sprintf("%02x", $octet);
4647
	}
4648

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

    
4656
	/* binary presentation of the prefix for all 128 bits. */
4657
	$stfprefixbin = "";
4658
	foreach ($stfarr as $element) {
4659
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4660
	}
4661
	/* just save the left prefix length bits */
4662
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4663

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

    
4668
	/* for the local subnet too. */
4669
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4670
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4671

    
4672
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4673
	$stfbrarr = array();
4674
	$stfbrbinarr = array();
4675
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4676
	foreach ($stfbrbinarr as $bin) {
4677
		$stfbrarr[] = dechex(bindec($bin));
4678
	}
4679
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4680

    
4681
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4682
	$stflanarr = array();
4683
	$stflanbinarr = array();
4684
	$stflanbinarr = str_split($stflanbin, 16);
4685
	foreach ($stflanbinarr as $bin) {
4686
		$stflanarr[] = dechex(bindec($bin));
4687
	}
4688
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4689
	$stflanarr[7] = 1;
4690

    
4691
	/* setup the stf interface */
4692
	if (!is_module_loaded("if_stf")) {
4693
		mwexec("/sbin/kldload if_stf.ko");
4694
	}
4695
	$stfiface = "{$interface}_stf";
4696
	if (does_interface_exist($stfiface)) {
4697
		pfSense_interface_destroy($stfiface);
4698
	}
4699
	$tmpstfiface = pfSense_interface_create2("stf");
4700
	pfSense_interface_rename($tmpstfiface, $stfiface);
4701
	pfSense_interface_flags($stfiface, IFF_LINK2);
4702
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4703

    
4704
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4705
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4706
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4707
	} elseif ($parentmtu > 1300) {
4708
		set_interface_mtu($stfiface, $parentmtu - 20);
4709
	}
4710
	if (g_get('debug')) {
4711
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4712
	}
4713

    
4714
	/* write out a default router file */
4715
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4716
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4717
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4718

    
4719
	$ip4gateway = get_interface_gateway($interface);
4720
	if (is_ipaddrv4($ip4gateway)) {
4721
		route_add_or_change("192.88.99.1", $ip4gateway);
4722
	}
4723

    
4724
	if (!platform_booting()) {
4725
		link_interface_to_track6($interface, "update");
4726
	}
4727

    
4728
	return 0;
4729
}
4730

    
4731
function interface_dhcpv6_configure($ifconf, $ifcfg, $destroy = false) {
4732
	global $g;
4733

    
4734
	$dhcp6cconf = "";
4735
	$id = "0";
4736
	$dhcp6cinterfaces = array();
4737
	$dhcp6cifs_descr = array();
4738
	$dhcp6crealifs = array();
4739
	$debugOption = "-d";
4740
	$noreleaseOption = "";
4741

    
4742
	if (!empty(config_get_path('system/global-v6duid'))) {
4743
		// Write the DUID file
4744
		if(!write_dhcp6_duid(config_get_path('system/global-v6duid'))) {
4745
		    log_error(gettext("Failed to write user DUID file!"));
4746
		}
4747
	}
4748

    
4749
	foreach (config_get_path('interfaces', []) as $interface => $wancfg) {
4750
		$wanif = get_real_interface($interface, "inet6");
4751

    
4752
		if (($ifconf == $interface) && $destroy) {
4753
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
4754
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
4755
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$wanif}_script.sh");
4756
			unlink_if_exists(g_get('vardb_path') . "/{$wanif}_cacheipv6");
4757
			continue;
4758
		}
4759

    
4760
		if (!isset($wancfg['enable']) || (($ifconf == $interface) && $destroy) ||
4761
		    (($wancfg['ipaddrv6'] != 'dhcp6') && ($wancfg['ipaddrv6'] != 'slaac'))) {
4762
			continue;
4763
		}
4764

    
4765
		$dhcp6cinterfaces[$interface] = $wancfg;
4766

    
4767
		if (config_path_enabled('system','dhcp6debug')) {
4768
			$debugOption = "-D";
4769
		}
4770
		if (config_path_enabled('system','dhcp6norelease')) {
4771
			$noreleaseOption = "-n";
4772
		}
4773

    
4774
		/* accept router advertisements for this interface                 */
4775
		/* Moved to early in the function as sometimes interface not ready */
4776
		/* RTSOLD fails as interface does not accept .....                 */
4777

    
4778
		log_error("Accept router advertisements on interface {$wanif} ");
4779
		mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4780

    
4781
		if ($wancfg['adv_dhcp6_config_file_override']) {
4782
			// DHCP6 Config File Override
4783
			$dhcp6cconf .= DHCP6_Config_File_Override($wancfg, $wanif);
4784
		} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4785
			// DHCP6 Config File Advanced
4786
			$dhcp6cconf .= DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4787
		} else {
4788
			// DHCP6 Config File Basic
4789
			$dhcp6cconf .= "interface {$wanif} {\n";
4790

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

    
4807
				/* skip address request if this is set */
4808
				if (!isset($wancfg['dhcp6prefixonly'])) {
4809
					$dhcp6cconf .= "\tsend ia-na {$id};\t# request stateful address\n";
4810
				}
4811
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4812
					$dhcp6cconf .= "\tsend ia-pd {$id};\t# request prefix delegation\n";
4813
				}
4814

    
4815
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4816
				$dhcp6cconf .= "\trequest domain-name;\n";
4817

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

    
4829
				if (!isset($wancfg['dhcp6prefixonly'])) {
4830
					$dhcp6cconf .= "id-assoc na {$id} { };\n";
4831
				}
4832

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

    
4858
		/*************** Script Debug Logging ***************************
4859
		Both dhcp6 scripts now have a logging message built in.
4860
		These logging messages ONLY appear if dhcp6c debug logging is set.
4861
		The logging messages appear in the dhcp section of the logs,
4862
		not in system.
4863

    
4864
		These scripts now also take advantage of the REASON= env vars
4865
		supplied by dhcp6c.
4866
		****************************************************************/
4867

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

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

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

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

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

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

    
4999
EOD;
5000

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

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

    
5051
		$realif = get_real_interface($ifconf, "inet6");
5052
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$realif}.pid")) {
5053
			killbypid("{$g['varrun_path']}/rtsold_{$realif}.pid");
5054
			log_error("Killing running rtsold process");
5055
			sleep(2);
5056
		}
5057

    
5058
		if (file_exists("{$g['tmp_path']}/dhcp6c_ifs")) {
5059
			$dhcp6crealifs_run = unserialize(file_get_contents("{$g['tmp_path']}/dhcp6c_ifs"));
5060
		} else {
5061
			$dhcp6crealifs_run = array();
5062
		}
5063

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

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

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

    
5122
	/*
5123
	 * NOTE: will be called from rtsold invoked script
5124
	 * link_interface_to_track6($interface, "update");
5125
	 */
5126

    
5127
	return 0;
5128
}
5129

    
5130
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5131
	global $g;
5132

    
5133
	$send_options = "";
5134
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5135
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5136
		foreach ($options as $option) {
5137
			$send_options .= "\tsend " . trim($option) . ";\n";
5138
		}
5139
	}
5140

    
5141
	$request_options = "";
5142
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5143
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5144
		foreach ($options as $option) {
5145
			$request_options .= "\trequest " . trim($option) . ";\n";
5146
		}
5147
	}
5148

    
5149
	$information_only = "";
5150
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5151
		$information_only = "\tinformation-only;\n";
5152
	}
5153

    
5154
	if (isset($wancfg['dhcp6withoutra'])) {
5155
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\";\n";
5156
	} else {
5157
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5158
	}
5159
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5160
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5161
	}
5162

    
5163
	$interface_statement  = "interface";
5164
	$interface_statement .= " {$wanif}";
5165
	$interface_statement .= " {\n";
5166
	$interface_statement .= "$send_options";
5167
	$interface_statement .= "$request_options";
5168
	$interface_statement .= "$information_only";
5169
	$interface_statement .= "$script";
5170
	$interface_statement .= "};\n";
5171

    
5172
	$id_assoc_statement_address = "";
5173
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5174
		$id_assoc_statement_address .= "id-assoc";
5175
		$id_assoc_statement_address .= " na";
5176
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5177
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5178
		}
5179
		$id_assoc_statement_address .= " { ";
5180

    
5181
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5182
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5183
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5184
			$id_assoc_statement_address .= "\n\taddress";
5185
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5186
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5187
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5188
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5189
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5190
			}
5191
			$id_assoc_statement_address .= ";\n";
5192
		}
5193

    
5194
		$id_assoc_statement_address .= "};\n";
5195
	}
5196

    
5197
	$id_assoc_statement_prefix = "";
5198
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5199
		$id_assoc_statement_prefix .= "id-assoc";
5200
		$id_assoc_statement_prefix .= " pd";
5201
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5202
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5203
		}
5204
		$id_assoc_statement_prefix .= " { ";
5205

    
5206
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5207
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5208
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5209
			$id_assoc_statement_prefix .= "\n\tprefix";
5210
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5211
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5212
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5213
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5214
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5215
			}
5216
			$id_assoc_statement_prefix .= ";";
5217
		}
5218

    
5219
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5220
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5221
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5222
			$id_assoc_statement_prefix .= " {$realif}";
5223
			$id_assoc_statement_prefix .= " {\n";
5224
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5225
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5226
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5227
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5228
			}
5229
			$id_assoc_statement_prefix .= "\t};";
5230
		}
5231

    
5232
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5233
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5234
			$id_assoc_statement_prefix .= "\n";
5235
		}
5236

    
5237
		$id_assoc_statement_prefix .= "};\n";
5238
	}
5239

    
5240
	$authentication_statement = "";
5241
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5242
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5243
		$authentication_statement .= "authentication";
5244
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5245
		$authentication_statement .= " {\n";
5246
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5247
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5248
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5249
		}
5250
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5251
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5252
		}
5253
		$authentication_statement .= "};\n";
5254
	}
5255

    
5256
	$key_info_statement = "";
5257
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5258
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5259
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5260
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5261
		$key_info_statement .= "keyinfo";
5262
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5263
		$key_info_statement .= " {\n";
5264
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5265
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5266
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5267
		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'])) {
5268
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5269
		}
5270
		$key_info_statement .= "};\n";
5271
	}
5272

    
5273
	$dhcp6cconf  = $interface_statement;
5274
	$dhcp6cconf .= $id_assoc_statement_address;
5275
	$dhcp6cconf .= $id_assoc_statement_prefix;
5276
	$dhcp6cconf .= $authentication_statement;
5277
	$dhcp6cconf .= $key_info_statement;
5278

    
5279
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5280

    
5281
	return $dhcp6cconf;
5282
}
5283

    
5284

    
5285
function DHCP6_Config_File_Override($wancfg, $wanif) {
5286

    
5287
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5288

    
5289
	if ($dhcp6cconf === false) {
5290
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5291
		return '';
5292
	} else {
5293
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5294
	}
5295
}
5296

    
5297

    
5298
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5299

    
5300
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5301

    
5302
	return $dhcp6cconf;
5303
}
5304

    
5305

    
5306
function interface_dhcp_configure($interface) {
5307
	global $g, $vlanprio_values;
5308

    
5309
	$ifcfg = config_get_path("interfaces/{$interface}");
5310
	if (empty($ifcfg)) {
5311
		$ifcfg = array();
5312
	}
5313

    
5314
	$dhclientconf_vlantag = "";
5315
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5316
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5317
	}
5318

    
5319
	/* generate dhclient_wan.conf */
5320
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5321
	if (!$fd) {
5322
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5323
		return 1;
5324
	}
5325

    
5326
	if ($ifcfg['dhcphostname']) {
5327
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5328
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5329
	} else {
5330
		$dhclientconf_hostname = "";
5331
	}
5332

    
5333
	$realif = get_real_interface($interface);
5334
	if (empty($realif)) {
5335
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5336
		return 0;
5337
	}
5338
	$dhclientconf = "";
5339

    
5340
	$dhclientconf .= <<<EOD
5341
interface "{$realif}" {
5342
	supersede interface-mtu 0;
5343
	timeout 60;
5344
	retry 15;
5345
	select-timeout 0;
5346
	initial-interval 1;
5347
	{$dhclientconf_vlantag}
5348
	{$dhclientconf_hostname}
5349
	script "/usr/local/sbin/pfSense-dhclient-script";
5350
EOD;
5351

    
5352
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5353
		$dhclientconf .= <<<EOD
5354

    
5355
	reject {$ifcfg['dhcprejectfrom']};
5356
EOD;
5357
	}
5358
	$dhclientconf .= <<<EOD
5359

    
5360
}
5361

    
5362
EOD;
5363

    
5364
	// DHCP Config File Advanced
5365
	if ($ifcfg['adv_dhcp_config_advanced']) {
5366
		$dhclientconf = DHCP_Config_File_Advanced($ifcfg, $realif);
5367
	}
5368

    
5369
	if (is_ipaddr($ifcfg['alias-address'])) {
5370
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5371
		$dhclientconf .= <<<EOD
5372
alias {
5373
	interface "{$realif}";
5374
	fixed-address {$ifcfg['alias-address']};
5375
	option subnet-mask {$subnetmask};
5376
}
5377

    
5378
EOD;
5379
	}
5380

    
5381
	// DHCP Config File Override
5382
	if ($ifcfg['adv_dhcp_config_file_override']) {
5383
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5384
	}
5385

    
5386
	fwrite($fd, $dhclientconf);
5387
	fclose($fd);
5388

    
5389
	/* bring wan interface up before starting dhclient */
5390
	if ($realif) {
5391
		interfaces_bring_up($realif);
5392
	}
5393

    
5394
	/* Make sure dhclient is not running */
5395
	kill_dhclient_process($realif);
5396

    
5397
	/* fire up dhclient */
5398
	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");
5399

    
5400
	return 0;
5401
}
5402

    
5403
function DHCP_Config_File_Advanced($ifcfg, $realif) {
5404

    
5405
	$hostname = "";
5406
	if ($ifcfg['dhcphostname'] != '') {
5407
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5408
	}
5409

    
5410
	/* DHCP Protocol Timings */
5411
	$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");
5412
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5413
		$pt_variable = "{$Protocol_Timing}";
5414
		${$pt_variable} = "";
5415
		if ($ifcfg[$Protocol_Timing] != "") {
5416
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5417
		}
5418
	}
5419

    
5420
	$send_options = "";
5421
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5422
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5423
		foreach ($options as $option) {
5424
			$send_options .= "\tsend " . trim($option) . ";\n";
5425
		}
5426
	}
5427

    
5428
	$request_options = "";
5429
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5430
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5431
	}
5432

    
5433
	$required_options = "";
5434
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5435
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5436
	}
5437

    
5438
	$option_modifiers = "";
5439
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5440
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5441
		foreach ($modifiers as $modifier) {
5442
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5443
		}
5444
	}
5445

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

    
5470
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5471

    
5472
	return $dhclientconf;
5473
}
5474

    
5475
function DHCP_Config_Option_Split($option_string) {
5476
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5477
	return $matches ? $matches[0] : [];
5478
}
5479

    
5480
function DHCP_Config_File_Override($ifcfg, $realif) {
5481

    
5482
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5483

    
5484
	if ($dhclientconf === false) {
5485
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5486
		return '';
5487
	} else {
5488
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5489
	}
5490
}
5491

    
5492

    
5493
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5494

    
5495
	/* Apply Interface Substitutions */
5496
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5497

    
5498
	/* Apply Hostname Substitutions */
5499
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5500

    
5501
	/* Arrays of MAC Address Types, Cases, Delimiters */
5502
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5503
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5504
	$various_mac_cases      = array("U", "L");
5505
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5506

    
5507
	/* Apply MAC Address Substitutions */
5508
	foreach ($various_mac_types as $various_mac_type) {
5509
		foreach ($various_mac_cases as $various_mac_case) {
5510
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5511

    
5512
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5513
				if ($res !== false) {
5514

    
5515
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5516
					if ("$various_mac_case" == "U") {
5517
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5518
					}
5519
					if ("$various_mac_case" == "L") {
5520
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5521
					}
5522

    
5523
					if ("$various_mac_type" == "mac_addr_hex") {
5524
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5525
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5526
						$dhcpclientconf_mac_hex = "";
5527
						$delimiter = "";
5528
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5529
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5530
							$delimiter = ":";
5531
						}
5532
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5533
					}
5534

    
5535
					/* MAC Address Delimiter Substitutions */
5536
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5537

    
5538
					/* Apply MAC Address Substitutions */
5539
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5540
				}
5541
			}
5542
		}
5543
	}
5544

    
5545
	return $dhclientconf;
5546
}
5547

    
5548
function interfaces_group_setup() {
5549
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupar) {
5550
		interface_group_setup($groupar);
5551
	}
5552

    
5553
	return;
5554
}
5555

    
5556
function interface_group_setup(&$groupname /* The parameter is an array */) {
5557
	if (!is_array($groupname)) {
5558
		return;
5559
	}
5560
	$members = explode(" ", $groupname['members']);
5561
	foreach ($members as $ifs) {
5562
		$realif = get_real_interface($ifs);
5563
		if ($realif && does_interface_exist($realif)) {
5564
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5565
		}
5566
	}
5567

    
5568
	return;
5569
}
5570

    
5571
function is_interface_group($if) {
5572
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupentry) {
5573
		if ($groupentry['ifname'] === $if) {
5574
			return true;
5575
		}
5576
	}
5577

    
5578
	return false;
5579
}
5580

    
5581
function interface_group_add_member($interface, $groupname) {
5582
	$interface = get_real_interface($interface);
5583
	if (does_interface_exist($interface)) {
5584
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5585
	}
5586
}
5587

    
5588
/* COMPAT Function */
5589
function convert_friendly_interface_to_real_interface_name($interface) {
5590
	return get_real_interface($interface);
5591
}
5592

    
5593
/* COMPAT Function */
5594
function get_real_wan_interface($interface = "wan") {
5595
	return get_real_interface($interface);
5596
}
5597

    
5598
/* COMPAT Function */
5599
function get_current_wan_address($interface = "wan") {
5600
	return get_interface_ip($interface);
5601
}
5602

    
5603
/*
5604
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5605
 */
5606
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5607

    
5608
	/* XXX: For speed reasons reference directly the interface array */
5609
	init_config_arr(array('interfaces'));
5610
	$ifdescrs = config_get_path('interfaces');
5611
	//$ifdescrs = get_configured_interface_list(true);
5612

    
5613
	foreach ($ifdescrs as $if => $ifname) {
5614
		if ($if == $interface || $ifname['if'] == $interface) {
5615
			return $if;
5616
		}
5617

    
5618
		if (get_real_interface($if) == $interface) {
5619
			return $if;
5620
		}
5621

    
5622
		if ($checkparent == false) {
5623
			continue;
5624
		}
5625

    
5626
		$int = get_parent_interface($if, true);
5627
		if (is_array($int)) {
5628
			foreach ($int as $iface) {
5629
				if ($iface == $interface) {
5630
					return $if;
5631
				}
5632
			}
5633
		}
5634
	}
5635

    
5636
	if ($interface == "enc0") {
5637
		return 'IPsec';
5638
	}
5639
}
5640

    
5641
/* attempt to resolve interface to friendly descr */
5642
function convert_friendly_interface_to_friendly_descr($interface) {
5643

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

    
5698
				/* if list */
5699
				$ifdescrs = get_configured_interface_with_descr(true);
5700
				foreach ($ifdescrs as $if => $ifname) {
5701
					if ($if == $interface || $ifname == $interface) {
5702
						return $ifname;
5703
					}
5704
				}
5705
			}
5706
			break;
5707
	}
5708

    
5709
	return $ifdesc;
5710
}
5711

    
5712
function convert_real_interface_to_friendly_descr($interface) {
5713

    
5714
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5715

    
5716
	if (!empty($ifdesc)) {
5717
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5718
	}
5719

    
5720
	return $interface;
5721
}
5722

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

    
5740
	// If we got a real interface, find it's friendly assigned name
5741
	if ($interface == $realif && $avoidrecurse == false) {
5742
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5743
	}
5744

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

    
5777
	if (empty($parents)) {
5778
		// Handle _vlans not assigned to an interface
5779
		$vlan = interface_is_vlan($realif);
5780
		if ($vlan != NULL) {
5781
			$parents[0] = $vlan['if'];
5782
		}
5783
	}
5784

    
5785
	if (empty($parents)) {
5786
		/* Handle LAGGs. */
5787
		$lagg = interface_is_type($realif, 'lagg');
5788
		if ($lagg != NULL && isset($lagg['members'])) {
5789
			$parents = explode(",", $lagg['members']);
5790
		}
5791
	}
5792

    
5793
	if (empty($parents)) {
5794
		$parents[0] = $realif;
5795
	}
5796

    
5797
	return $parents;
5798
}
5799

    
5800
/*
5801
 *  get_parent_physical_interface($interface):
5802
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5803
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5804
 */
5805
function get_parent_physical_interface($interface) {
5806

    
5807
	$realif = get_parent_interface($interface);
5808

    
5809
	if (substr($realif[0], 0, 4) == "lagg") {
5810
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
5811
			if ($realif[0] == $lagg['laggif']) {
5812
				return explode(",", $lagg['members']);
5813
			}
5814
		}
5815
	} else {
5816
		return $realif;
5817
	}
5818
}
5819

    
5820
function interface_is_wireless_clone($wlif) {
5821
	if (!stristr($wlif, "_wlan")) {
5822
		return false;
5823
	} else {
5824
		return true;
5825
	}
5826
}
5827

    
5828
function interface_get_wireless_base($wlif) {
5829
	if (!stristr($wlif, "_wlan")) {
5830
		return $wlif;
5831
	} else {
5832
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5833
	}
5834
}
5835

    
5836
function interface_get_wireless_clone($wlif) {
5837
	if (!stristr($wlif, "_wlan")) {
5838
		return $wlif . "_wlan0";
5839
	} else {
5840
		return $wlif;
5841
	}
5842
}
5843

    
5844
function interface_list_wireless() {
5845
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5846

    
5847
	$result = array();
5848
	foreach ($portlist as $port) {
5849
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5850
			continue;
5851
		}
5852

    
5853
		$desc = $port . " ( " . get_single_sysctl(
5854
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5855

    
5856
		$result[] = array(
5857
		    "if" => $port,
5858
		    "descr" => $desc
5859
		);
5860
	}
5861

    
5862
	return $result;
5863
}
5864

    
5865
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5866
	global $g;
5867

    
5868
	$wanif = NULL;
5869

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

    
5912
			$cfg = config_get_path("interfaces/{$interface}");
5913
			if (empty($cfg))
5914
				break;
5915

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

    
5974
	return $wanif;
5975
}
5976

    
5977
/* Guess the physical interface by providing a IP address */
5978
function guess_interface_from_ip($ipaddress) {
5979

    
5980
	if (!is_ipaddr($ipaddress)) {
5981
		return false;
5982
	}
5983

    
5984
	$route = route_get($ipaddress, '', true);
5985
	if (empty($route)) {
5986
		return false;
5987
	}
5988

    
5989
	if (!empty($route[0]['interface-name'])) {
5990
		return $route[0]['interface-name'];
5991
	}
5992

    
5993
	return false;
5994
}
5995

    
5996
/*
5997
 * find_ip_interface($ip): return the interface where an ip is defined
5998
 *   (or if $bits is specified, where an IP within the subnet is defined)
5999
 */
6000
function find_ip_interface($ip, $bits = null) {
6001
	if (!is_ipaddr($ip)) {
6002
		return false;
6003
	}
6004

    
6005
	$isv6ip = is_ipaddrv6($ip);
6006

    
6007
	/* if list */
6008
	$ifdescrs = get_configured_interface_list();
6009

    
6010
	foreach ($ifdescrs as $ifname) {
6011
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6012
		if (is_null($ifip)) {
6013
			continue;
6014
		}
6015
		if (is_null($bits)) {
6016
			if ($ip == $ifip) {
6017
				$int = get_real_interface($ifname);
6018
				return $int;
6019
			}
6020
		} else {
6021
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6022
				$int = get_real_interface($ifname);
6023
				return $int;
6024
			}
6025
		}
6026
	}
6027

    
6028
	return false;
6029
}
6030

    
6031
/*
6032
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6033
 *   (or if $bits is specified, where an IP within the subnet is found)
6034
 */
6035
function find_virtual_ip_alias($ip, $bits = null) {
6036

    
6037
	if (!is_ipaddr($ip)) {
6038
		return false;
6039
	}
6040

    
6041
	$isv6ip = is_ipaddrv6($ip);
6042

    
6043
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6044
		if ($vip['mode'] === "ipalias") {
6045
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6046
				continue;
6047
			}
6048
			if (is_null($bits)) {
6049
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6050
					return $vip;
6051
				}
6052
			} else {
6053
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6054
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6055
					return $vip;
6056
				}
6057
			}
6058
		}
6059
	}
6060
	return false;
6061
}
6062

    
6063
function link_interface_to_track6($int, $action = "") {
6064
	$list = array();
6065
	if (empty($int)) {
6066
		return $list;
6067
	}
6068

    
6069
	foreach (config_get_path('interfaces', []) as $ifname => $ifcfg) {
6070
		if (!isset($ifcfg['enable'])) {
6071
			continue;
6072
		}
6073
		if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6074
			if ($action == "update") {
6075
				interface_track6_configure($ifname, $ifcfg);
6076
			} elseif ($action == "") {
6077
				$list[$ifname] = $ifcfg;
6078
			}
6079
		}
6080
	}
6081
	return $list;
6082
}
6083

    
6084
function interface_find_child_cfgmtu($realiface) {
6085
	$vlans = link_interface_to_vlans($realiface);
6086
	$qinqs = link_interface_to_qinqs($realiface);
6087
	$bridge = link_interface_to_bridge($realiface);
6088
	$mtu = 0;
6089

    
6090
	foreach ([$vlans, $qinqs, ['bridge' => $bridge]] as $ints) {
6091
		if (is_array($ints)) {
6092
			foreach ($ints as $int) {
6093
				$ifass = convert_real_interface_to_friendly_interface_name($int['vlanif']);
6094
				if (!empty($ifass) &&
6095
				    config_path_enabled("interfaces/{$ifass}") &&
6096
				    (intval(config_get_path("interfaces/{$ifass}/mtu")) > $mtu)) {
6097
					$mtu = config_get_path("interfaces/{$ifass}/mtu");
6098
				}
6099
			}
6100
		}
6101
	}
6102

    
6103
	unset($vlans, $qinqs, $bridge);
6104
	return $mtu;
6105
}
6106

    
6107
function link_interface_to_vlans($int, $action = "") {
6108
	if (empty($int)) {
6109
		return;
6110
	}
6111

    
6112
	$ifaces = array();
6113
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
6114
		if ($int == $vlan['if']) {
6115
			if ($action == "update") {
6116
				interfaces_bring_up($int);
6117
			} else {
6118
				$ifaces[$vlan['tag']] = $vlan;
6119
			}
6120
		}
6121
	}
6122
	if (!empty($ifaces)) {
6123
		return $ifaces;
6124
	}
6125
}
6126

    
6127
function link_interface_to_qinqs($int, $action = "") {
6128
	if (empty($int)) {
6129
		return;
6130
	}
6131

    
6132
	$ifaces = array();
6133
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
6134
		if ($int == $qinq['if']) {
6135
			if ($action == "update") {
6136
				interfaces_bring_up($int);
6137
			} else {
6138
				$ifaces[$qinq['tag']] = $qinq;
6139
			}
6140
		}
6141
	}
6142
	if (!empty($ifaces)) {
6143
		return $ifaces;
6144
	}
6145
}
6146

    
6147
function link_interface_to_vips($int, $action = "", $vhid = '') {
6148
	$updatevips = false;
6149

    
6150
	$result = array();
6151
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6152
		if (substr($vip['interface'], 0, 4) == "_vip") {
6153
			$iface = get_configured_vip_interface($vip['interface']);
6154
		} else {
6155
			$iface = $vip['interface'];
6156
		}
6157
		if ($int != $iface) {
6158
			continue;
6159
		}
6160
		if ($action == "update") {
6161
			$updatevips = true;
6162
		} else {
6163
			if (empty($vhid) || ($vhid == $vip['vhid']) ||
6164
				substr($vip['interface'], 0, 4) == "_vip") {
6165
				$result[] = $vip;
6166
			}
6167
		}
6168
	}
6169
	if ($updatevips === true) {
6170
		interfaces_vips_configure($int);
6171
	}
6172
	return $result;
6173

    
6174
	return NULL;
6175
}
6176

    
6177
/****f* interfaces/link_interface_to_bridge
6178
 * NAME
6179
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6180
 * INPUTS
6181
 *   $ip
6182
 * RESULT
6183
 *   bridge[0-99]
6184
 ******/
6185
function link_interface_to_bridge($int) {
6186
	foreach (config_get_path('bridges/bridged', []) as $bridge) {
6187
		if (in_array($int, explode(',', $bridge['members']))) {
6188
			return "{$bridge['bridgeif']}";
6189
		}
6190
	}
6191
}
6192

    
6193
function link_interface_to_lagg($int) {
6194
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
6195
		if (in_array($int, explode(',', $lagg['members']))) {
6196
			return "{$lagg['laggif']}";
6197
		}
6198
	}
6199
}
6200

    
6201
function link_interface_to_group($int) {
6202
	$result = array();
6203

    
6204
	foreach (config_get_path('ifgroups/ifgroupentry') as $group) {
6205
		if (in_array($int, explode(" ", $group['members']))) {
6206
			$result[$group['ifname']] = $int;
6207
		}
6208
	}
6209

    
6210
	return $result;
6211
}
6212

    
6213
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6214
	$result = array();
6215

    
6216
	if (empty($interface)) {
6217
		return $result;
6218
	}
6219

    
6220
	if (!in_array($type, array('gre', 'gif'))) {
6221
		return $result;
6222
	}
6223

    
6224
	foreach (config_get_path("{$type}s/{$type}", []) as $tunnel) {
6225
		if (($tunnel['if'] == $interface) &&
6226
			(($remote == 'any') ||
6227
			 (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6228
			 (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) {
6229
			$result[] = $tunnel;
6230
		}
6231
	}
6232

    
6233
	return $result;
6234
}
6235

    
6236
function link_interface_to_ppp_tunnelif($interface) {
6237
	$result = array();
6238

    
6239
	if (empty($interface)) {
6240
		return $result;
6241
	}
6242

    
6243
	init_config_arr(array('ppps', 'ppp'));
6244
	$realif = get_real_interface($interface);
6245
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
6246
		if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) {
6247
			$result[] = $ppp;
6248
		}
6249
	}
6250

    
6251
	return $result;
6252
}
6253

    
6254
/*
6255
 * find_interface_ip($interface): return the interface ip (first found)
6256
 */
6257
function find_interface_ip($interface, $flush = false) {
6258
	global $interface_ip_arr_cache;
6259
	global $interface_sn_arr_cache;
6260

    
6261
	$interface = str_replace("\n", "", $interface);
6262

    
6263
	if (!does_interface_exist($interface)) {
6264
		return;
6265
	}
6266

    
6267
	/* Setup IP cache */
6268
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6269
		if (file_exists("/var/db/${interface}_ip")) {
6270
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6271
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6272
			foreach ($ifaddrs as $ifaddr) {
6273
				list($ip, $mask) = explode("/", $ifaddr);
6274
				if ($ip == $ifip) {
6275
					$interface_ip_arr_cache[$interface] = $ip;
6276
					$interface_sn_arr_cache[$interface] = $mask;
6277
					break;
6278
				}
6279
			}
6280
		}
6281
		if (!isset($interface_ip_arr_cache[$interface])) {
6282
			$ifinfo = get_interface_addresses($interface);
6283
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6284
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6285
		}
6286
	}
6287

    
6288
	return $interface_ip_arr_cache[$interface];
6289
}
6290

    
6291
/*
6292
 * find_interface_ipv6($interface): return the interface ip (first found)
6293
 */
6294
function find_interface_ipv6($interface, $flush = false) {
6295
	global $interface_ipv6_arr_cache;
6296
	global $interface_snv6_arr_cache;
6297

    
6298
	$interface = trim($interface);
6299
	$interface = get_real_interface($interface);
6300

    
6301
	if (!does_interface_exist($interface)) {
6302
		return;
6303
	}
6304

    
6305
	/* Setup IP cache */
6306
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6307
		$ifinfo = get_interface_addresses($interface);
6308
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6309
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6310
	}
6311

    
6312
	return $interface_ipv6_arr_cache[$interface];
6313
}
6314

    
6315
/*
6316
 * Return the interface ipv6 link local address
6317
 */
6318
function find_interface_ipv6_ll($interface, $flush = false, $usefirst = true) {
6319
	global $interface_llv6_arr_cache;
6320

    
6321
	$interface = str_replace("\n", "", $interface);
6322

    
6323
	if (!does_interface_exist($interface)) {
6324
		return;
6325
	}
6326

    
6327
	/* Setup IP cache */
6328
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6329
		$ifinfo = pfSense_getall_interface_addresses($interface);
6330
		foreach ($ifinfo as $line) {
6331
			if (strstr($line, ":")) {
6332
				$parts = explode("/", $line);
6333
				if (is_linklocal($parts[0])) {
6334
					$ifinfo['linklocal'] = $parts[0];
6335
					if ($usefirst) {
6336
						break;
6337
					}
6338
				}
6339
			}
6340
		}
6341
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6342
	}
6343
	return $interface_llv6_arr_cache[$interface];
6344
}
6345

    
6346
function find_interface_subnet($interface, $flush = false) {
6347
	global $interface_sn_arr_cache;
6348
	global $interface_ip_arr_cache;
6349

    
6350
	$interface = str_replace("\n", "", $interface);
6351
	if (does_interface_exist($interface) == false) {
6352
		return;
6353
	}
6354

    
6355
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6356
		$ifinfo = get_interface_addresses($interface);
6357
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6358
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6359
	}
6360

    
6361
	return $interface_sn_arr_cache[$interface];
6362
}
6363

    
6364
function find_interface_subnetv6($interface, $flush = false) {
6365
	global $interface_snv6_arr_cache;
6366
	global $interface_ipv6_arr_cache;
6367

    
6368
	$interface = str_replace("\n", "", $interface);
6369
	if (does_interface_exist($interface) == false) {
6370
		return;
6371
	}
6372

    
6373
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6374
		$ifinfo = get_interface_addresses($interface);
6375
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6376
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6377
	}
6378

    
6379
	return $interface_snv6_arr_cache[$interface];
6380
}
6381

    
6382
function ip_in_interface_alias_subnet($interface, $ipalias) {
6383
	if (empty($interface) || !is_ipaddr($ipalias)) {
6384
		return false;
6385
	}
6386
	foreach (config_get_path('virtualip/vip',[]) as $vip) {
6387
		switch ($vip['mode']) {
6388
		case "ipalias":
6389
			if ($vip['interface'] <> $interface) {
6390
				break;
6391
			}
6392
			$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6393
			if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6394
				return true;
6395
			}
6396
			break;
6397
		}
6398
	}
6399

    
6400
	return false;
6401
}
6402

    
6403
function get_possible_listen_ips($include_ipv6_link_local=false) {
6404

    
6405
	$interfaces = get_configured_interface_with_descr();
6406
	foreach ($interfaces as $iface => $ifacename) {
6407
		if ($include_ipv6_link_local) {
6408
			/* This is to avoid going though added ll below */
6409
			if (substr($iface, 0, 5) == '_lloc') {
6410
				continue;
6411
			}
6412
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6413
			if (!empty($llip)) {
6414
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6415
			}
6416
		}
6417
	}
6418
	$viplist = get_configured_vip_list();
6419
	foreach ($viplist as $vip => $address) {
6420
		$interfaces[$vip] = $address;
6421
		if (get_vip_descr($address)) {
6422
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6423
		}
6424
	}
6425

    
6426
	$interfaces['lo0'] = 'Localhost';
6427

    
6428
	return $interfaces;
6429
}
6430

    
6431
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6432
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6433
	foreach (array('server', 'client') as $mode) {
6434
		foreach (config_get_path("openvpn/openvpn-{$mode}", []) as $setting) {
6435
			if (!isset($setting['disable'])) {
6436
				$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6437
				$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6438
			}
6439
		}
6440
	}
6441

    
6442
	init_config_arr(array('ipsec', 'phase1'));
6443
	foreach (config_get_path('ipsec/phase1') as $p1) {
6444
		if ($p1['disabled']) {
6445
			continue;
6446
		}
6447
		if (ipsec_vti($p1)) {
6448
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6449
			if (!empty($vtiiflist)) {
6450
				$sourceips = array_merge($sourceips, $vtiiflist);
6451
			}
6452
		}
6453
	}
6454
	return $sourceips;
6455
}
6456

    
6457
function get_interface_ip($interface = "wan") {
6458
	if (substr($interface, 0, 4) == '_vip') {
6459
		return get_configured_vip_ipv4($interface);
6460
	} elseif (substr($interface, 0, 5) == '_lloc') {
6461
		/* No link-local address for v4. */
6462
		return null;
6463
	}
6464

    
6465
	$realif = get_failover_interface($interface, 'inet');
6466
	if (!$realif) {
6467
		return null;
6468
	}
6469

    
6470
	if (substr($realif, 0, 4) == '_vip') {
6471
		return get_configured_vip_ipv4($realif);
6472
	} elseif (substr($realif, 0, 5) == '_lloc') {
6473
		/* No link-local address for v4. */
6474
		return null;
6475
	}
6476

    
6477
	$iface = config_get_path("interfaces/{$interface}");
6478
	if (is_array($iface) && is_ipaddr($iface['ipaddr'])) {
6479
		return ($iface['ipaddr']);
6480
	}
6481

    
6482
	/*
6483
	 * Beware that find_interface_ip() is our last option, it will
6484
	 * return the first IP it find on interface, not necessarily the
6485
	 * main IP address.
6486
	 */
6487
	$curip = find_interface_ip($realif);
6488
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6489
		return $curip;
6490
	} else {
6491
		return null;
6492
	}
6493
}
6494

    
6495
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6496
	if (substr($interface, 0, 4) == '_vip') {
6497
		return get_configured_vip_ipv6($interface);
6498
	} elseif (substr($interface, 0, 5) == '_lloc') {
6499
		return get_interface_linklocal($interface);
6500
	}
6501

    
6502
	$realif = get_failover_interface($interface, 'inet6');
6503
	if (!$realif) {
6504
		return null;
6505
	}
6506

    
6507
	if (substr($realif, 0, 4) == '_vip') {
6508
		return get_configured_vip_ipv6($realif);
6509
	} elseif (substr($realif, 0, 5) == '_lloc') {
6510
		return get_interface_linklocal($realif);
6511
	}
6512

    
6513
	$iface = config_get_path("interfaces/{$interface}");
6514
	if (is_array($iface)) {
6515
		switch ($iface['ipaddr']) {
6516
			case 'pppoe':
6517
			case 'l2tp':
6518
			case 'pptp':
6519
			case 'ppp':
6520
				if (($iface['ipaddrv6'] == 'dhcp6') ||
6521
				    ($iface['ipaddrv6'] == 'slaac')) {
6522
					$realif = get_real_interface($interface, 'inet6', false);
6523
				}
6524
				break;
6525
		}
6526
		if (is_ipaddrv6($iface['ipaddrv6'])) {
6527
			return ($iface['ipaddrv6']);
6528
		}
6529
	}
6530

    
6531
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6532
	$checkif = is_array($iface) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6533
	if (config_get_path("interfaces/{$checkif}/ipaddrv6", "") == 'track6') {
6534
		$curip = get_interface_track6ip($checkif);
6535
		if ($curip) {
6536
			return $curip[0];
6537
		}
6538
	}
6539

    
6540
	/*
6541
	 * Beware that find_interface_ip() is our last option, it will
6542
	 * return the first IP it find on interface, not necessarily the
6543
	 * main IP address.
6544
	 */
6545
	$curip = find_interface_ipv6($realif, $flush);
6546
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6547
		return $curip;
6548
	} else {
6549
		/*
6550
		 * NOTE: On the case when only the prefix is requested,
6551
		 * the communication on WAN will be done over link-local.
6552
		 */
6553
		$iface = config_get_path("interfaces/{$interface}");
6554
		if ($linklocal_fallback || (is_array($iface) && isset($iface['dhcp6prefixonly']))) {
6555
			$curip = find_interface_ipv6_ll($realif, $flush);
6556
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6557
				return $curip;
6558
			}
6559
		}
6560
	}
6561
	return null;
6562
}
6563

    
6564
function get_interface_linklocal($interface = "wan") {
6565

    
6566
	$realif = get_failover_interface($interface, 'inet6');
6567
	if (!$realif) {
6568
		return null;
6569
	}
6570

    
6571
	if (substr($interface, 0, 4) == '_vip') {
6572
		$realif = get_real_interface($interface);
6573
	} elseif (substr($interface, 0, 5) == '_lloc') {
6574
		$realif = get_real_interface(substr($interface, 5));
6575
	}
6576

    
6577
	$curip = find_interface_ipv6_ll($realif);
6578
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6579
		return $curip;
6580
	} else {
6581
		return null;
6582
	}
6583
}
6584

    
6585
function get_interface_track6ip($interface = "wan") {
6586
	$realif = get_real_interface($interface);
6587
	$vips = get_configured_vip_list('inet6');
6588

    
6589
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6590
		list($ip, $bits) = explode("/", $ifaddr);
6591
		$ip = text_to_compressed_ip6($ip);
6592
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6593
			if (is_array($vips) && !empty($vips)) {
6594
				foreach ($vips as $vip) {
6595
					if ($ip == text_to_compressed_ip6($vip)) {
6596
						continue 2;
6597
					}
6598
				}
6599
			}
6600
			return array($ip, $bits);
6601
		}
6602
	}
6603
	return false;
6604
}
6605

    
6606
function get_interface_subnet($interface = "wan") {
6607
	if (substr($interface, 0, 4) == '_vip') {
6608
		return (get_configured_vip_subnetv4($interface));
6609
	}
6610

    
6611
	$iface = config_get_path("interfaces/{$interface}");
6612
	if (is_array($iface) && !empty($iface['subnet']) && is_ipaddrv4($iface['ipaddr'])) {
6613
		return ($iface['subnet']);
6614
	}
6615

    
6616
	$realif = get_real_interface($interface);
6617
	if (!$realif) {
6618
		return (NULL);
6619
	}
6620

    
6621
	$cursn = find_interface_subnet($realif);
6622
	if (!empty($cursn)) {
6623
		return ($cursn);
6624
	}
6625

    
6626
	return (NULL);
6627
}
6628

    
6629
function get_interface_subnetv6($interface = "wan") {
6630
	if (substr($interface, 0, 4) == '_vip') {
6631
		return (get_configured_vip_subnetv6($interface));
6632
	} elseif (substr($interface, 0, 5) == '_lloc') {
6633
		$interface = substr($interface, 5);
6634
	}
6635

    
6636
	$iface = config_get_path("interfaces/{$interface}");
6637
	if (is_array($iface) && !empty($iface['subnetv6']) && is_ipaddrv6($iface['ipaddrv6'])) {
6638
		return ($iface['subnetv6']);
6639
	}
6640

    
6641
	$realif = get_real_interface($interface, 'inet6');
6642
	if (!$realif) {
6643
		return (NULL);
6644
	}
6645

    
6646
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6647
	if (config_get_path("interfaces/{$interface}/ipaddrv6") == 'track6') {
6648
		$curip = get_interface_track6ip($interface);
6649
		if ($curip) {
6650
			return $curip[1];
6651
		}
6652
	}
6653

    
6654
	$cursn = find_interface_subnetv6($realif);
6655
	if (!empty($cursn)) {
6656
		return ($cursn);
6657
	}
6658

    
6659
	return (NULL);
6660
}
6661

    
6662
/* return outside interfaces with a gateway */
6663
function get_interfaces_with_gateway() {
6664

    
6665
	$ints = array();
6666

    
6667
	/* loop interfaces, check config for outbound */
6668
	foreach (config_get_path('interfaces', []) as $ifdescr => $ifname) {
6669
		switch ($ifname['ipaddr']) {
6670
			case "dhcp":
6671
			case "pppoe":
6672
			case "pptp":
6673
			case "l2tp":
6674
			case "ppp":
6675
				$ints[$ifdescr] = $ifdescr;
6676
				break;
6677
			default:
6678
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6679
				    !empty($ifname['gateway'])) {
6680
					$ints[$ifdescr] = $ifdescr;
6681
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6682
				    !empty($ifname['gateway'])) {
6683
					$ints[$ifdescr] = $ifdescr;
6684
				}
6685

    
6686
				break;
6687
		}
6688
	}
6689
	return $ints;
6690
}
6691

    
6692
/* return true if interface has a gateway */
6693
function interface_has_gateway($friendly) {
6694
	$ifname = config_get_path("interfaces/{$friendly}");
6695
	if (!empty($ifname)) {
6696
		switch ($ifname['ipaddr']) {
6697
			case "dhcp":
6698
				/* see https://redmine.pfsense.org/issues/5135 */
6699
				if (get_interface_gateway($friendly)) {
6700
					return true;
6701
				}
6702
				break;
6703
			case "pppoe":
6704
			case "pptp":
6705
			case "l2tp":
6706
			case "ppp":
6707
				return true;
6708
				break;
6709
			default:
6710
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6711
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6712
					return true;
6713
				}
6714
				$tunnelif = substr($ifname['if'], 0, 3);
6715
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6716
					if (find_interface_ip($ifname['if'])) {
6717
						return true;
6718
					}
6719
				}
6720
				if (!empty($ifname['gateway'])) {
6721
					return true;
6722
				}
6723
				break;
6724
		}
6725
	}
6726

    
6727
	return false;
6728
}
6729

    
6730
/* return true if interface has a gateway */
6731
function interface_has_gatewayv6($friendly) {
6732
	$ifname = config_get_path("interfaces/{$friendly}");
6733
	if (!empty($ifname)) {
6734
		switch ($ifname['ipaddrv6']) {
6735
			case "slaac":
6736
			case "dhcp6":
6737
			case "6to4":
6738
			case "6rd":
6739
				return true;
6740
				break;
6741
			default:
6742
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6743
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6744
					return true;
6745
				}
6746
				$tunnelif = substr($ifname['if'], 0, 3);
6747
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6748
					if (find_interface_ipv6($ifname['if'])) {
6749
						return true;
6750
					}
6751
				}
6752
				if (!empty($ifname['gatewayv6'])) {
6753
					return true;
6754
				}
6755
				break;
6756
		}
6757
	}
6758

    
6759
	return false;
6760
}
6761

    
6762
/****f* interfaces/is_altq_capable
6763
 * NAME
6764
 *   is_altq_capable - Test if interface is capable of using ALTQ
6765
 * INPUTS
6766
 *   $int            - string containing interface name
6767
 * RESULT
6768
 *   boolean         - true or false
6769
 ******/
6770

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

    
6786
	$int_family = remove_ifindex($int);
6787

    
6788
	if (in_array($int_family, $capable)) {
6789
		return true;
6790
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6791
		return true;
6792
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6793
		return true;
6794
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6795
		return true;
6796
	} else {
6797
		return false;
6798
	}
6799
}
6800

    
6801
/****f* interfaces/is_interface_wireless
6802
 * NAME
6803
 *   is_interface_wireless - Returns if an interface is wireless
6804
 * RESULT
6805
 *   $tmp       - Returns if an interface is wireless
6806
 ******/
6807
function is_interface_wireless($interface) {
6808
	global $g;
6809

    
6810
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6811
	if (config_get_path("interfaces/{$friendly}/wireless") === null) {
6812
		if (preg_match(g_get('wireless_regex'), $interface)) {
6813
			init_config_arr(['interfaces', $friendly, 'wireless']);
6814
			return true;
6815
		}
6816
		return false;
6817
	} else {
6818
		return true;
6819
	}
6820
}
6821

    
6822
function get_wireless_modes($interface) {
6823
	/* return wireless modes and channels */
6824
	$wireless_modes = array();
6825

    
6826
	$cloned_interface = get_real_interface($interface);
6827

    
6828
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6829
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6830
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6831
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6832

    
6833
		$interface_channels = [];
6834
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6835
		$interface_channel_count = count($interface_channels);
6836

    
6837
		$c = 0;
6838
		while ($c < $interface_channel_count) {
6839
			$channel_line = explode(",", $interface_channels["$c"]);
6840
			$wireless_mode = trim($channel_line[0]);
6841
			$wireless_channel = trim($channel_line[1]);
6842
			if (trim($wireless_mode) != "") {
6843
				/* if we only have 11g also set 11b channels */
6844
				if ($wireless_mode == "11g") {
6845
					if (!isset($wireless_modes["11b"])) {
6846
						$wireless_modes["11b"] = array();
6847
					}
6848
				} elseif ($wireless_mode == "11g ht") {
6849
					if (!isset($wireless_modes["11b"])) {
6850
						$wireless_modes["11b"] = array();
6851
					}
6852
					if (!isset($wireless_modes["11g"])) {
6853
						$wireless_modes["11g"] = array();
6854
					}
6855
					$wireless_mode = "11ng";
6856
				} elseif ($wireless_mode == "11a ht") {
6857
					if (!isset($wireless_modes["11a"])) {
6858
						$wireless_modes["11a"] = array();
6859
					}
6860
					$wireless_mode = "11na";
6861
				}
6862
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6863
			}
6864
			$c++;
6865
		}
6866
	}
6867
	return($wireless_modes);
6868
}
6869

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

    
6875
		$interface_channels = [];
6876
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6877
		return $interface_channels;
6878
}
6879

    
6880
/* return wireless HT modes */
6881
function get_wireless_ht_modes($interface) {
6882
	$wireless_hts_supported = array(0 => gettext('Auto'));
6883

    
6884
	$cloned_interface = get_real_interface($interface);
6885

    
6886
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6887
		$interface_channels = get_wireless_channels($cloned_interface);
6888

    
6889
		foreach ($interface_channels as $channel) {
6890
			$channel_line = explode(",", $channel);
6891
			$wireless_ht = trim($channel_line[1]);
6892
			if (!empty($wireless_ht)) {
6893
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6894
			}
6895
		}
6896
	}
6897
	return($wireless_hts_supported);
6898
}
6899

    
6900
/* return wireless HT by channel/standard */
6901
function get_wireless_ht_list($interface) {
6902
	$wireless_hts = array();
6903

    
6904
	$cloned_interface = get_real_interface($interface);
6905

    
6906
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6907
		$interface_channels = get_wireless_channels($cloned_interface);
6908
		$interface_channel_count = count($interface_channels);
6909

    
6910
		$c = 0;
6911
		while ($c < $interface_channel_count) {
6912
			$channel_line = explode(",", $interface_channels["$c"]);
6913
			$wireless_mode = trim($channel_line[0]);
6914
			$wireless_ht = trim($channel_line[1]);
6915
			$wireless_channel = trim($channel_line[2]);
6916
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
6917
				if ($wireless_mode == "11g") {
6918
					if (!isset($wireless_modes["11g"])) {
6919
						$wireless_hts["11g"] = array();
6920
					}
6921
					$wireless_mode = "11ng";
6922
				} elseif ($wireless_mode == "11a") {
6923
					if (!isset($wireless_modes["11a"])) {
6924
						$wireless_hts["11a"] = array();
6925
					}
6926
					$wireless_mode = "11na";
6927
				}
6928
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
6929
			}
6930
			$c++;
6931
		}
6932
	}
6933
	return($wireless_hts);
6934
}
6935

    
6936
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6937
function get_wireless_channel_info($interface) {
6938
	$wireless_channels = array();
6939

    
6940
	$cloned_interface = get_real_interface($interface);
6941

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

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

    
6950
		foreach ($interface_channels as $channel_line) {
6951
			$channel_line = explode(",", $channel_line);
6952
			if (!isset($wireless_channels[$channel_line[0]])) {
6953
				$wireless_channels[$channel_line[0]] = $channel_line;
6954
			}
6955
		}
6956
	}
6957
	return($wireless_channels);
6958
}
6959

    
6960
function set_interface_mtu($interface, $mtu) {
6961

    
6962
	/* LAGG interface must be destroyed and re-created to change MTU */
6963
	if ((substr($interface, 0, 4) == 'lagg') &&
6964
	    (!strstr($interface, "."))) {
6965
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
6966
			if ($lagg['laggif'] == $interface) {
6967
				interface_lagg_configure($lagg);
6968
				break;
6969
			}
6970
		}
6971
	} else {
6972
		pfSense_interface_mtu($interface, $mtu);
6973
		set_ipv6routes_mtu($interface, $mtu);
6974
	}
6975
}
6976

    
6977
/****f* interfaces/get_interface_mtu
6978
 * NAME
6979
 *   get_interface_mtu - Return the mtu of an interface
6980
 * RESULT
6981
 *   $tmp       - Returns the mtu of an interface
6982
 ******/
6983
function get_interface_mtu($interface) {
6984
	$mtu = pfSense_interface_getmtu($interface);
6985
	return $mtu['mtu'];
6986
}
6987

    
6988
function get_interface_mac($interface) {
6989
	$macinfo = get_interface_addresses($interface);
6990
	return $macinfo["macaddr"];
6991
}
6992

    
6993
function get_interface_vendor_mac($interface) {
6994
	global $g;
6995

    
6996
	$macinfo = get_interface_addresses($interface);
6997
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
6998
	    "00:00:00:00:00:00") {
6999
		return ($macinfo["hwaddr"]);
7000
	}
7001

    
7002
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7003
	if (file_exists($hwaddr_file)) {
7004
		$macaddr = trim(file_get_contents($hwaddr_file));
7005
		if (is_macaddr($macaddr)) {
7006
			return ($macaddr);
7007
		}
7008
	} elseif (is_macaddr($macinfo['macaddr'])) {
7009
		/* Save original macaddress to be restored when necessary */
7010
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7011
	}
7012

    
7013
	return (NULL);
7014
}
7015

    
7016
/****f* pfsense-utils/generate_random_mac_address
7017
 * NAME
7018
 *   generate_random_mac - generates a random mac address
7019
 * INPUTS
7020
 *   none
7021
 * RESULT
7022
 *   $mac - a random mac address
7023
 ******/
7024
function generate_random_mac_address() {
7025
	$mac = "02";
7026
	for ($x = 0; $x < 5; $x++) {
7027
		$mac .= ":" . dechex(rand(16, 255));
7028
	}
7029
	return $mac;
7030
}
7031

    
7032
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7033
	global $g;
7034

    
7035
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7036

    
7037
	if (!empty($iface) && !empty($pppif)) {
7038
		$cron_cmd = <<<EOD
7039
#!/bin/sh
7040
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7041
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7042

    
7043
EOD;
7044

    
7045
		@file_put_contents($cron_file, $cron_cmd);
7046
		chmod($cron_file, 0755);
7047
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7048
	} else {
7049
		unlink_if_exists($cron_file);
7050
	}
7051
}
7052

    
7053
function get_interface_default_mtu($type = "ethernet") {
7054
	switch ($type) {
7055
		case "gre":
7056
			return 1476;
7057
			break;
7058
		case "gif":
7059
			return 1280;
7060
			break;
7061
		case "tun":
7062
		case "vlan":
7063
		case "tap":
7064
		case "ethernet":
7065
		default:
7066
			return 1500;
7067
			break;
7068
	}
7069

    
7070
	/* Never reached */
7071
	return 1500;
7072
}
7073

    
7074
function get_vip_descr($ipaddress) {
7075

    
7076
	foreach (config_get_path('virtualip/vip', []) as $vip) {
7077
		if ($vip['subnet'] == $ipaddress) {
7078
			return ($vip['descr']);
7079
		}
7080
	}
7081
	return "";
7082
}
7083

    
7084
function interfaces_staticarp_configure($if) {
7085
	if (config_get_path('system/developerspew')) {
7086
		$mt = microtime();
7087
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7088
	}
7089

    
7090
	if (!config_path_enabled("interfaces/{$if}")) {
7091
		return 0;
7092
	}
7093

    
7094
	$ifcfg = config_get_path("interfaces/{$if}");
7095

    
7096
	/* Enable staticarp, if enabled */
7097
	$staticarp = config_get_path("dhcpd/{$if}/staticarp");
7098
	if ($staticarp) {
7099
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7100
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7101
	} else {
7102
		/*
7103
		 * Interfaces do not have staticarp enabled by default
7104
		 * Let's not disable staticarp on freshly created interfaces
7105
		 */
7106
		if (!platform_booting()) {
7107
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7108
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7109
		}
7110
	}
7111

    
7112
	/* Enable static arp entries */
7113
	$staticmap = config_get_path("dhcpd/{$if}/staticmap", []);
7114
	if (is_array($staticmap)) {
7115
		foreach ($staticmap as $arpent) {
7116
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7117
				continue;
7118
			}
7119
			if ($staticarp || isset($arpent['arp_table_static_entry'])) {
7120
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7121
			}
7122
		}
7123
	}
7124

    
7125
	return 0;
7126
}
7127

    
7128
function get_failover_interface($interface, $family = "all") {
7129
	/* shortcut to get_real_interface if we find it in the config */
7130
	if (is_array(config_get_path("interfaces/{$interface}"))) {
7131
		return get_real_interface($interface, $family);
7132
	}
7133

    
7134
	/* compare against gateway groups */
7135
	$a_groups = return_gateway_groups_array(true);
7136
	if (is_array($a_groups[$interface])) {
7137
		/* we found a gateway group, fetch the interface or vip */
7138
		if (!empty($a_groups[$interface][0]['vip'])) {
7139
			return $a_groups[$interface][0]['vip'];
7140
		} else {
7141
			return $a_groups[$interface][0]['int'];
7142
		}
7143
	}
7144
	/* fall through to get_real_interface */
7145
	/* XXX: Really needed? */
7146
	return get_real_interface($interface, $family);
7147
}
7148

    
7149
/****f* interfaces/interface_has_dhcp
7150
 * NAME
7151
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7152
 * INPUTS
7153
 *   interface or gateway group name
7154
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7155
 * RESULT
7156
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7157
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7158
 ******/
7159
function interface_has_dhcp($interface, $family = 4) {
7160
	$iface = config_get_path("interfaces/{$interface}");
7161
	if ($iface) {
7162
		if (($family == 4) && ($iface['ipaddr'] == "dhcp")) {
7163
			return true;
7164
		} elseif (($family == 6) && ($iface['ipaddrv6'] == "dhcp6")) {
7165
			return true;
7166
		} else {
7167
			return false;
7168
		}
7169
	}
7170

    
7171
	if ($family == 6) {
7172
		$dhcp_string = "_DHCP6";
7173
	} else {
7174
		$dhcp_string = "_DHCP";
7175
	}
7176

    
7177
	foreach (config_get_path('gateways/gateway_group', []) as $group) {
7178
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7179
			continue;
7180
		}
7181
		foreach ($group['item'] as $item) {
7182
			$item_data = explode("|", $item);
7183
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7184
				return true;
7185
			}
7186
		}
7187
	}
7188

    
7189
	return false;
7190
}
7191

    
7192
function remove_ifindex($ifname) {
7193
	return preg_replace("/[0-9]+$/", "", $ifname);
7194
}
7195

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

    
7199
	$viplist = get_configured_vip_list($family, $type);
7200
	foreach ($viplist as $vipid => $address) {
7201
		$interfaces[$vipid] = $address;
7202
		if ($type = VIP_CARP) {
7203
			$vip = get_configured_vip($vipid);
7204
			if (isset($vip) && is_array($vip) ) {
7205
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7206
			}
7207
		}
7208
		if (get_vip_descr($address)) {
7209
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7210
		}
7211
	}
7212
	return $interfaces;
7213
}
7214

    
7215
function return_gateway_groups_array_with_descr() {
7216
	$interfaces = array();
7217
	$grouplist = return_gateway_groups_array();
7218
	foreach (array_keys($grouplist) as $name) {
7219
		$interfaces[$name] = "GW Group {$name}";
7220
	}
7221
	return $interfaces;
7222
}
7223

    
7224
function get_serial_ports($short=false) {
7225
	$linklist = array();
7226
	if (!is_dir("/var/spool/lock")) {
7227
		mwexec("/bin/mkdir -p /var/spool/lock");
7228
	}
7229
	$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);
7230
	foreach ($serialports as $port) {
7231
		$port = trim($port);
7232
		$port = ($short) ? basename($port) : $port;
7233
		$linklist[$port] = $port;
7234
	}
7235
	return $linklist;
7236
}
7237

    
7238
function get_interface_ports() {
7239
	$linklist = array();
7240
	$portlist = get_interface_list();
7241

    
7242
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
7243
		if (empty($vlan)) {
7244
			continue;
7245
		}
7246
		$portlist[$vlan['vlanif']] = $vlan;
7247
	}
7248

    
7249
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
7250
		if (empty($qinq)) {
7251
			continue;
7252
		}
7253
		$members = explode(" ", $qinq['members']);
7254
		foreach ($members as $mem) {
7255
			$qentry = $qinq['vlanif'] . "." . $mem;
7256
			$portlist[$qentry] = $qentry;
7257
		}
7258
	}
7259

    
7260
	foreach ($portlist as $ifn => $ifinfo) {
7261
		$string = "";
7262
		if (is_array($ifinfo)) {
7263
			$string .= $ifn;
7264
			if ($ifinfo['mac']) {
7265
				$string .= " ({$ifinfo['mac']})";
7266
			}
7267
			if ($ifinfo['friendly']) {
7268
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7269
			} elseif ($ifinfo['descr']) {
7270
				$string .= " - {$ifinfo['descr']}";
7271
			}
7272
		} else {
7273
			$string .= $ifinfo;
7274
		}
7275

    
7276
		$linklist[$ifn] = $string;
7277
	}
7278
	return $linklist;
7279
}
7280

    
7281
function build_ppps_link_list() {
7282
	global $pconfig;
7283

    
7284
	$linklist = array('list' => array(), 'selected' => array());
7285

    
7286
	if ($pconfig['type'] == 'ppp') {
7287
		$linklist['list'] = get_serial_ports();
7288
	} else {
7289
		$iflist = get_interface_ports();
7290

    
7291
		$viplist = array();
7292
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7293
		foreach ($carplist as $vid => $vaddr) {
7294
			$vip = get_configured_vip($vid);
7295
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7296
		}
7297

    
7298
		$linklist['list'] = array_merge($iflist, $viplist);
7299

    
7300
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7301
		$lagglist = get_lagg_interface_list();
7302
		foreach ($lagglist as $lagg) {
7303
			/* LAGG members cannot be assigned */
7304
			$laggmembers = explode(',', $lagg['members']);
7305
			foreach ($laggmembers as $lagm) {
7306
				if (isset($linklist['list'][$lagm])) {
7307
					unset($linklist['list'][$lagm]);
7308
				}
7309
			}
7310
		}
7311
	}
7312

    
7313
	$selected_ports = array();
7314
	if (is_array($pconfig['interfaces'])) {
7315
		$selected_ports = $pconfig['interfaces'];
7316
	} elseif (!empty($pconfig['interfaces'])) {
7317
		$selected_ports = explode(',', $pconfig['interfaces']);
7318
	}
7319
	foreach ($selected_ports as $port) {
7320
		if (isset($linklist['list'][$port])) {
7321
			array_push($linklist['selected'], $port);
7322
		}
7323
	}
7324
	return($linklist);
7325
}
7326

    
7327
function create_interface_list($open = false) {
7328
	$iflist = array();
7329

    
7330
	// add group interfaces
7331
	config_get_path('ifgroups/ifgroupentry', []);
7332
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7333
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7334
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7335
		}
7336
	}
7337

    
7338
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7339
		if ($open || have_ruleint_access($ifent)) {
7340
			$iflist[$ifent] = $ifdesc;
7341
		}
7342
	}
7343

    
7344
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7345
		$iflist['l2tp'] = gettext('L2TP VPN');
7346
	}
7347

    
7348
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7349
		$iflist['pppoe'] = gettext("PPPoE Server");
7350
	}
7351

    
7352
	// add ipsec interfaces
7353
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7354
		$iflist["enc0"] = gettext("IPsec");
7355
	}
7356

    
7357
	// add openvpn/tun interfaces
7358
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7359
		$iflist["openvpn"] = gettext("OpenVPN");
7360
	}
7361

    
7362
	return($iflist);
7363
}
7364

    
7365
function is_pseudo_interface($inf, $tap=true) {
7366
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7367
	foreach ($psifs as $pif) {
7368
		if (substr($inf, 0, strlen($pif)) == $pif) {
7369
			if (($pif == 'ovpn') && $tap) {
7370
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7371
				$type = ($m[1] == 'c') ? 'client' : 'server';
7372
				foreach (config_get_path("openvpn/openvpn-{$type}", []) as $ovpn) {
7373
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7374
						return false;
7375
					} elseif ($ovpn['vpnid'] == $m[2]) {
7376
						return true;
7377
					}
7378
				}
7379
			} else {
7380
				return true;
7381
			}
7382
		}
7383
	}
7384
	return false;
7385
}
7386

    
7387
function is_stf_interface($inf) {
7388
	switch (config_get_path("interfaces/{$inf}/ipaddrv6")) {
7389
		case '6rd':
7390
		case '6to4':
7391
			return true;
7392
		default:
7393
			return false;
7394
	}
7395
}
7396

    
7397
function restart_interface_services($interface, $ipv6type = "") {
7398

    
7399
	services_unbound_configure(true, $interface);
7400

    
7401
	services_igmpproxy_configure($interface);
7402
	services_snmpd_configure($interface);
7403
	vpn_l2tp_configure($interface);
7404

    
7405
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7406
		openvpn_resync_all($interface);
7407
	}
7408
	ipsec_force_reload($interface);
7409

    
7410
	/* restart RADVD to announce correct IPv6 prefix
7411
	 * see https://redmine.pfsense.org/issues/12604 */
7412
	if ((is_ipaddrv6($ipv6type) || ($ipv6type == "track6")) &&
7413
	    (config_get_path("dhcpdv6/{$interface}/ramode", "disabled") != "disabled")) {
7414
		services_radvd_configure();
7415
	}
7416

    
7417
	if (config_path_enabled("dhcpd/{$interface}") ||
7418
	    config_path_enabled("dhcpdv6/{$interface}")) {
7419
		services_dhcpd_configure();
7420
	}
7421

    
7422
	init_config_arr(array('syslog'));
7423
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7424
		system_syslogd_start();
7425
	}
7426
}
7427

    
7428
/**
7429
 * Return interface parameters and primary ipv4 and ipv6 addresses for the real iface
7430
 * $interface, identified by exclusion of VIPs. Deprecates pfSense_get_interface_addresses()
7431
 *
7432
 * Result array contains keyed values:
7433
 * - ipaddr: ipv4 address
7434
 * - subnetbits: ipv4 subnet bits
7435
 * - subnet: ipv4 subnet
7436
 * - broadcast: ipv4 broadcast addr (if applicable)
7437
 * - tunnel: ipv4 PPP endpoint (if applicable)
7438
 * - ipaddr6: ipv6 address
7439
 * - tentative: ipv6 tentative flag (if applicable)
7440
 * - subnetbits6: ipv6 subnet bits
7441
 * - tunnel6: ipv6 tunnel endpoint
7442
 * - status: up or down interface status
7443
 * - link0: per link layer defined flag
7444
 * - link1: per link layer defined flag
7445
 * - link2: per link layer defined flag
7446
 * - multicast: multicast support
7447
 * - loopback: interface is a loopback interface
7448
 * - pointtopoint: interface is point-to-point
7449
 * - promisc: interface in promisc mode
7450
 * - permanentpromisc: interface permanently in promisc mode
7451
 * - oactive: interface tx hardware queue is full
7452
 * - allmulti: interface receives all multicast packets
7453
 * - simplex: interface is simplex
7454
 * - linkstateup: interface link is up
7455
 * - iftype: wireless, ether, vlan, bridge, virtual, other
7456
 * - mtu: mtu of interface
7457
 * - caps: interface capabilities array
7458
 * - encaps: enabled capabilities array
7459
 * - macaddr: interface configured ethernet address
7460
 * - hwaddr: hardware ethernet address
7461
 */
7462
function get_interface_addresses($interface) {
7463
	$v4addrs = array();
7464
	$v6addrs = array();
7465
	$v4vips = array();
7466
	$v6vips = array();
7467
	$ifaddrs = pfSense_get_ifaddrs($interface);
7468

    
7469
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7470
		$vip = get_configured_vip($viface);
7471
		if (is_ipaddrv4($vip['subnet'])) {
7472
			array_push($v4vips, $vip['subnet']);
7473
		} else if (is_ipaddrv6($vip['subnet'])) {
7474
			array_push($v6vips, Net_IPv6::Uncompress($vip['subnet']));
7475
		}
7476
	}
7477

    
7478
	if ($ifaddrs['addrs']) {
7479
		$v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7480
			return (array_search($addr['addr'], $v4vips) === false);
7481
		});
7482
	}
7483

    
7484
	if ($ifaddrs['addrs6']) {
7485
		$v6addrs = array_filter($ifaddrs['addrs6'], function($addr) use ($v6vips){
7486
			return (array_search(Net_IPv6::Uncompress($addr['addr']), $v6vips) === false);
7487
		});
7488
	}
7489
	/* Transform output to conform to pfSense_get_interface_addresses() */
7490
	if ($v4addrs) {
7491
		$v4addr = array_shift($v4addrs);
7492
		$ifaddrs['ipaddr'] = $v4addr['addr'];
7493
		foreach(array("subnetbits", "subnet", "broadcast", "tunnel") as $key) {
7494
			if (array_key_exists($key, $v4addr)) {
7495
				$ifaddrs[$key] = $v4addr[$key];
7496
			}
7497
		}
7498
	}
7499

    
7500
	if ($v6addrs) {
7501
		// use the first IPv6 GUA address if one exists, otherwise the first address
7502
		$v6addr = $v6addrs[array_key_first($v6addrs)];
7503
		foreach ($v6addrs as $addr) {
7504
			if (is_v6gua($addr['addr'])) {
7505
				$v6addr = $addr;
7506
				break;
7507
			}
7508
		}
7509
		$ifaddrs['ipaddr6'] = $v6addr['addr'];
7510
		foreach(array("subnetbits", "tunnel") as $key) {
7511
			if (array_key_exists($key, $v6addr)) {
7512
				$ifaddrs[$key.'6'] = $v6addr[$key];
7513
			}
7514
		}
7515
		if (array_key_exists('tentative', $v6addr)) {
7516
			$ifaddrs['tentative'] = $v6addr['tentative'];
7517
		}
7518
	}
7519
	unset($ifaddrs['addrs']);
7520
	unset($ifaddrs['addrs6']);
7521

    
7522
	return($ifaddrs);
7523
}
7524

    
7525
/**
7526
 * Returns all interface addresses, including IPv6 LL addresses.
7527
 * XXX: Review/refactor functions used to retrieve interfaces addresses.
7528
 */
7529
function get_interface_addresses_all(string $interface): array {
7530
	$addresses = [];
7531

    
7532
	// Get primary IPv4/6 addresses
7533
	$addresses_primary = get_interface_addresses($interface);
7534
	if (!empty($addresses_primary['ipaddr'])) {
7535
		$addresses[] = $addresses_primary['ipaddr'];
7536
	}
7537
	if (!empty($addresses_primary['ipaddr6'])) {
7538
		$addresses[] = $addresses_primary['ipaddr6'];
7539
	}
7540

    
7541
	// Get IPv6 link-local address
7542
	$addresses_linklocal = find_interface_ipv6_ll($interface);
7543
	if (!empty($addresses_linklocal)) {
7544
		$addresses_linklocal_pos = strpos($addresses_linklocal, '%');
7545
		if ($addresses_linklocal_pos !== false) {
7546
			$addresses_linklocal = substr($addresses_linklocal, 0, $addresses_linklocal_pos);
7547
		}
7548
		$addresses[] = $addresses_linklocal;
7549
	}
7550

    
7551
	// Get VIPs
7552
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7553
		$vip = get_configured_vip($viface);
7554
		if ($vip['interface'] == $interface && !empty($vip['subnet'])) {
7555
			$addresses[] = $vip['subnet'];
7556
		}
7557
	}
7558

    
7559
	return $addresses;
7560
}
7561
?>
(22-22/61)