Project

General

Profile

Download (221 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, $gateways_status = false) {
1415
	global $ipsec_reqid_base;
1416

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1569
	interfaces_qinq_configure(false);
1570

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

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

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

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

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

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

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

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

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

    
1648
		interface_configure($if, $reload);
1649

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

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

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

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

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

    
1672
		interface_configure($if, $reload);
1673

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

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

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

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

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

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

    
1708
		interface_configure($if, $reload);
1709

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

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

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

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

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

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

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

    
1740
	return 0;
1741
}
1742

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1983
	return;
1984
}
1985

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

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

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

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

    
2018
	return false;
2019
}
2020

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

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

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

    
2050
	return false;
2051
}
2052

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

    
2059
	return $ptpid;
2060
}
2061

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

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

    
2072
	return NULL;
2073
}
2074

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

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

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

    
2087
	$itemhash = getMPDCRONSettings($pppif);
2088

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2380
EOD;
2381

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

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

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

    
2404
EOD;
2405
	}
2406

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

    
2411
EOD;
2412

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

    
2417
EOD;
2418
	}
2419

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

    
2440
EOD;
2441
	}
2442

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

    
2451
EOD;
2452

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

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

    
2463
EOD;
2464
	}
2465

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

    
2471
EOD;
2472
	}
2473

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

    
2478
EOD;
2479
	}
2480

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

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

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

    
2496
EOD;
2497
		}
2498

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

    
2503
EOD;
2504
		}
2505

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

    
2510
EOD;
2511
		}
2512

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

    
2518
EOD;
2519

    
2520

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

    
2525
EOD;
2526
		}
2527

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

    
2543
EOD;
2544
		}
2545

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

    
2552
EOD;
2553
		}
2554

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

    
2559
EOD;
2560
		}
2561

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

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

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

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

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

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

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

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

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

    
2634
EOD;
2635
		}
2636

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

    
2642
EOD;
2643
		}
2644

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

    
2650
EOD;
2651
		}
2652

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

    
2656

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

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

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

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

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

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

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

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

    
2763
	return 1;
2764
}
2765

    
2766
function interfaces_sync_setup() {
2767

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

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

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

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

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

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

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

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

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

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

    
2828
	/* Don't enable CARP if we haven't booted */
2829
	if (!is_platform_booting()) {
2830
		enable_carp();
2831
	}
2832

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

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

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

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

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

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

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

    
2877
				$paa[$proxyif][] = $vipent;
2878
			}
2879
		}
2880
	}
2881

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3106
	return $realif;
3107
}
3108

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3521
EOD;
3522

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

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

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

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

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

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

    
3557
EOD;
3558
						}
3559
					}
3560
				}
3561

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

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

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

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

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

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

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

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

    
3618
	fclose($fd_set);
3619

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3722
	unset($wlcmd_args, $wlcmd);
3723

    
3724

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

    
3729
	return 0;
3730

    
3731
}
3732

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

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

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

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

    
3752
	return intval($pid);
3753
}
3754

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

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

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

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

    
3780
	return intval($pid);
3781
}
3782

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

    
3786
	$i = 0;
3787

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

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

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

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

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

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

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

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

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

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

    
3841
	$pid = find_dhcp6c_process();
3842

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

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

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

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

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

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

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

    
3924
function interface_vlan_mtu_configured($iface) {
3925

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

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

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

    
3943
	return $mtu;
3944
}
3945

    
3946
function interface_mtu_wanted_for_pppoe($realif) {
3947

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

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

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

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

    
3982
	return $mtu;
3983
}
3984

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

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

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

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

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

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

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

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

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

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

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

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

    
4071
		interface_set_macaddr($realhwif, $mac_addr);
4072

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

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

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

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

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

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

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

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

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

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

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

    
4177
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4178

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

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

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

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

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

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

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

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

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

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

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

    
4298
		if ($reloadall == true) {
4299

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4407
	return 0;
4408
}
4409

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

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

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

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

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

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

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

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

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

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

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

    
4470
	return 0;
4471
}
4472

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

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

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

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

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

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

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

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

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

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

    
4529
	return 0;
4530
}
4531

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

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

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

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

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

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

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

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

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

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

    
4584

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

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

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

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

    
4623
	return 0;
4624
}
4625

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4735
	return 0;
4736
}
4737

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5005
EOD;
5006

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

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

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

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

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

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

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

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

    
5133
	return 0;
5134
}
5135

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5287
	return $dhcp6cconf;
5288
}
5289

    
5290

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

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

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

    
5303

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

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

    
5308
	return $dhcp6cconf;
5309
}
5310

    
5311

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

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

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

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

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

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

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

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

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

    
5366
}
5367

    
5368
EOD;
5369

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

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

    
5384
EOD;
5385
	}
5386

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

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

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

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

    
5403
	/* fire up dhclient */
5404
	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");
5405

    
5406
	return 0;
5407
}
5408

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

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

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

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

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

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

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

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

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

    
5478
	return $dhclientconf;
5479
}
5480

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

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

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

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

    
5498

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

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

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

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

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

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

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

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

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

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

    
5551
	return $dhclientconf;
5552
}
5553

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

    
5559
	return;
5560
}
5561

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

    
5574
	return;
5575
}
5576

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

    
5584
	return false;
5585
}
5586

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5715
	return $ifdesc;
5716
}
5717

    
5718
function convert_real_interface_to_friendly_descr($interface) {
5719

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

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

    
5726
	return $interface;
5727
}
5728

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

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

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

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

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

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

    
5803
	return $parents;
5804
}
5805

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

    
5813
	$realif = get_parent_interface($interface);
5814

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

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

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

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

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

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

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

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

    
5868
	return $result;
5869
}
5870

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

    
5874
	$wanif = NULL;
5875

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

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

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

    
5980
	return $wanif;
5981
}
5982

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

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

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

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

    
5999
	return false;
6000
}
6001

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

    
6011
	$isv6ip = is_ipaddrv6($ip);
6012

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

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

    
6034
	return false;
6035
}
6036

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

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

    
6047
	$isv6ip = is_ipaddrv6($ip);
6048

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

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

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

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

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

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

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

    
6154
	return $mtu;
6155
}
6156

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

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

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

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

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

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

    
6224
	return NULL;
6225
}
6226

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

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

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

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

    
6260
	return $result;
6261
}
6262

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

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

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

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

    
6283
	return $result;
6284
}
6285

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

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

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

    
6301
	return $result;
6302
}
6303

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
6447
	return false;
6448
}
6449

    
6450
function get_possible_listen_ips($include_ipv6_link_local=false) {
6451

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

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

    
6475
	return $interfaces;
6476
}
6477

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
6673
	return (NULL);
6674
}
6675

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

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

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

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

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

    
6706
	return (NULL);
6707
}
6708

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

    
6712
	$ints = array();
6713

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

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

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

    
6774
	return false;
6775
}
6776

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

    
6806
	return false;
6807
}
6808

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

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

    
6833
	$int_family = remove_ifindex($int);
6834

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

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

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

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

    
6873
	$cloned_interface = get_real_interface($interface);
6874

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

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

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

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

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

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

    
6931
	$cloned_interface = get_real_interface($interface);
6932

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

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

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

    
6951
	$cloned_interface = get_real_interface($interface);
6952

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

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

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

    
6987
	$cloned_interface = get_real_interface($interface);
6988

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

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

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

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

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

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

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

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

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

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

    
7060
	return (NULL);
7061
}
7062

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

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

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

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

    
7090
EOD;
7091

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

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

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

    
7121
function get_vip_descr($ipaddress) {
7122

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

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

    
7137
	if (!config_path_enabled("interfaces/{$if}")) {
7138
		return 0;
7139
	}
7140

    
7141
	$ifcfg = config_get_path("interfaces/{$if}");
7142

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

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

    
7172
	return 0;
7173
}
7174

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

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

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

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

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

    
7236
	return false;
7237
}
7238

    
7239
function remove_ifindex($ifname) {
7240
	return preg_replace("/[0-9]+$/", "", $ifname);
7241
}
7242

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

    
7246
	$viplist = get_configured_vip_list($family, $type);
7247
	foreach ($viplist as $vipid => $address) {
7248
		$interfaces[$vipid] = $address;
7249
		if ($type = VIP_CARP) {
7250
			$vip = get_configured_vip($vipid);
7251
			if (isset($vip) && is_array($vip) ) {
7252
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7253
			}
7254
		}
7255
		if (get_vip_descr($address)) {
7256
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7257
		}
7258
	}
7259
	return $interfaces;
7260
}
7261

    
7262
function return_gateway_groups_array_with_descr() {
7263
	$interfaces = array();
7264
	$grouplist = return_gateway_groups_array();
7265
	foreach (array_keys($grouplist) as $name) {
7266
		$interfaces[$name] = "GW Group {$name}";
7267
	}
7268
	return $interfaces;
7269
}
7270

    
7271
function get_serial_ports($short=false) {
7272
	$linklist = array();
7273
	if (!is_dir("/var/spool/lock")) {
7274
		mwexec("/bin/mkdir -p /var/spool/lock");
7275
	}
7276
	$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);
7277
	foreach ($serialports as $port) {
7278
		$port = trim($port);
7279
		$port = ($short) ? basename($port) : $port;
7280
		$linklist[$port] = $port;
7281
	}
7282
	return $linklist;
7283
}
7284

    
7285
function get_interface_ports() {
7286
	$linklist = array();
7287
	$portlist = get_interface_list();
7288

    
7289
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
7290
		if (empty($vlan)) {
7291
			continue;
7292
		}
7293
		$portlist[$vlan['vlanif']] = $vlan;
7294
	}
7295

    
7296
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
7297
		if (empty($qinq)) {
7298
			continue;
7299
		}
7300
		$members = explode(" ", $qinq['members']);
7301
		foreach ($members as $mem) {
7302
			$qentry = $qinq['vlanif'] . "." . $mem;
7303
			$portlist[$qentry] = $qentry;
7304
		}
7305
	}
7306

    
7307
	foreach ($portlist as $ifn => $ifinfo) {
7308
		$string = "";
7309
		if (is_array($ifinfo)) {
7310
			$string .= $ifn;
7311
			if ($ifinfo['mac']) {
7312
				$string .= " ({$ifinfo['mac']})";
7313
			}
7314
			if ($ifinfo['friendly']) {
7315
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7316
			} elseif ($ifinfo['descr']) {
7317
				$string .= " - {$ifinfo['descr']}";
7318
			}
7319
		} else {
7320
			$string .= $ifinfo;
7321
		}
7322

    
7323
		$linklist[$ifn] = $string;
7324
	}
7325
	return $linklist;
7326
}
7327

    
7328
function build_ppps_link_list() {
7329
	global $pconfig;
7330

    
7331
	$linklist = array('list' => array(), 'selected' => array());
7332

    
7333
	if ($pconfig['type'] == 'ppp') {
7334
		$linklist['list'] = get_serial_ports();
7335
	} else {
7336
		$iflist = get_interface_ports();
7337

    
7338
		$viplist = array();
7339
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7340
		foreach ($carplist as $vid => $vaddr) {
7341
			$vip = get_configured_vip($vid);
7342
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7343
		}
7344

    
7345
		$linklist['list'] = array_merge($iflist, $viplist);
7346

    
7347
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7348
		$lagglist = get_lagg_interface_list();
7349
		foreach ($lagglist as $lagg) {
7350
			/* LAGG members cannot be assigned */
7351
			$laggmembers = explode(',', $lagg['members']);
7352
			foreach ($laggmembers as $lagm) {
7353
				if (isset($linklist['list'][$lagm])) {
7354
					unset($linklist['list'][$lagm]);
7355
				}
7356
			}
7357
		}
7358
	}
7359

    
7360
	$selected_ports = array();
7361
	if (is_array($pconfig['interfaces'])) {
7362
		$selected_ports = $pconfig['interfaces'];
7363
	} elseif (!empty($pconfig['interfaces'])) {
7364
		$selected_ports = explode(',', $pconfig['interfaces']);
7365
	}
7366
	foreach ($selected_ports as $port) {
7367
		if (isset($linklist['list'][$port])) {
7368
			array_push($linklist['selected'], $port);
7369
		}
7370
	}
7371
	return($linklist);
7372
}
7373

    
7374
function create_interface_list($open = false) {
7375
	$iflist = array();
7376

    
7377
	// add group interfaces
7378
	config_get_path('ifgroups/ifgroupentry', []);
7379
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7380
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7381
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7382
		}
7383
	}
7384

    
7385
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7386
		if ($open || have_ruleint_access($ifent)) {
7387
			$iflist[$ifent] = $ifdesc;
7388
		}
7389
	}
7390

    
7391
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7392
		$iflist['l2tp'] = gettext('L2TP VPN');
7393
	}
7394

    
7395
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7396
		$iflist['pppoe'] = gettext("PPPoE Server");
7397
	}
7398

    
7399
	// add ipsec interfaces
7400
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7401
		$iflist["enc0"] = gettext("IPsec");
7402
	}
7403

    
7404
	// add openvpn/tun interfaces
7405
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7406
		$iflist["openvpn"] = gettext("OpenVPN");
7407
	}
7408

    
7409
	return($iflist);
7410
}
7411

    
7412
function is_pseudo_interface($inf, $tap=true) {
7413
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7414
	foreach ($psifs as $pif) {
7415
		if (substr($inf, 0, strlen($pif)) == $pif) {
7416
			if (($pif == 'ovpn') && $tap) {
7417
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7418
				$type = ($m[1] == 'c') ? 'client' : 'server';
7419
				foreach (config_get_path("openvpn/openvpn-{$type}", []) as $ovpn) {
7420
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7421
						return false;
7422
					} elseif ($ovpn['vpnid'] == $m[2]) {
7423
						return true;
7424
					}
7425
				}
7426
			} else {
7427
				return true;
7428
			}
7429
		}
7430
	}
7431
	return false;
7432
}
7433

    
7434
function is_stf_interface($inf) {
7435
	switch (config_get_path("interfaces/{$inf}/ipaddrv6")) {
7436
		case '6rd':
7437
		case '6to4':
7438
			return true;
7439
		default:
7440
			return false;
7441
	}
7442
}
7443

    
7444
function restart_interface_services($interface, $ipv6type = "") {
7445

    
7446
	services_unbound_configure(true, $interface);
7447

    
7448
	services_igmpproxy_configure($interface);
7449
	services_snmpd_configure($interface);
7450
	vpn_l2tp_configure($interface);
7451

    
7452
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7453
		openvpn_resync_all($interface);
7454
	}
7455
	ipsec_force_reload($interface);
7456

    
7457
	/* restart RADVD to announce correct IPv6 prefix
7458
	 * see https://redmine.pfsense.org/issues/12604 */
7459
	if ((($ipv6type == "staticv6") || ($ipv6type == "track6")) &&
7460
	    (config_get_path("dhcpdv6/{$interface}/ramode", "disabled") != "disabled")) {
7461
		services_radvd_configure();
7462
	}
7463

    
7464
	if (config_path_enabled("dhcpd/{$interface}") ||
7465
	    config_path_enabled("dhcpdv6/{$interface}")) {
7466
		services_dhcpd_configure();
7467
	}
7468

    
7469
	init_config_arr(array('syslog'));
7470
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7471
		system_syslogd_start();
7472
	}
7473
}
7474

    
7475
/**
7476
 * Return interface parameters and primary ipv4 and ipv6 addresses for the real iface
7477
 * $interface, identified by exclusion of VIPs. Deprecates pfSense_get_interface_addresses()
7478
 *
7479
 * Result array contains keyed values:
7480
 * - ipaddr: ipv4 address
7481
 * - subnetbits: ipv4 subnet bits
7482
 * - subnet: ipv4 subnet
7483
 * - broadcast: ipv4 broadcast addr (if applicable)
7484
 * - tunnel: ipv4 PPP endpoint (if applicable)
7485
 * - ipaddr6: ipv6 address
7486
 * - tentative: ipv6 tentative flag (if applicable)
7487
 * - subnetbits6: ipv6 subnet bits
7488
 * - tunnel6: ipv6 tunnel endpoint
7489
 * - status: up or down interface status
7490
 * - link0: per link layer defined flag
7491
 * - link1: per link layer defined flag
7492
 * - link2: per link layer defined flag
7493
 * - multicast: multicast support
7494
 * - loopback: interface is a loopback interface
7495
 * - pointtopoint: interface is point-to-point
7496
 * - promisc: interface in promisc mode
7497
 * - permanentpromisc: interface permanently in promisc mode
7498
 * - oactive: interface tx hardware queue is full
7499
 * - allmulti: interface receives all multicast packets
7500
 * - simplex: interface is simplex
7501
 * - linkstateup: interface link is up
7502
 * - iftype: wireless, ether, vlan, bridge, virtual, other
7503
 * - mtu: mtu of interface
7504
 * - caps: interface capabilities array
7505
 * - encaps: enabled capabilities array
7506
 * - macaddr: interface configured ethernet address
7507
 * - hwaddr: hardware ethernet address
7508
 */
7509
function get_interface_addresses($interface) {
7510
	$v4addrs = array();
7511
	$v6addrs = array();
7512
	$v4vips = array();
7513
	$v6vips = array();
7514
	$ifaddrs = pfSense_get_ifaddrs($interface);
7515

    
7516
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7517
		$vip = get_configured_vip($viface);
7518
		if (is_ipaddrv4($vip['subnet'])) {
7519
			array_push($v4vips, $vip['subnet']);
7520
		} else if (is_ipaddrv6($vip['subnet'])) {
7521
			array_push($v6vips, $vip['subnet']);
7522
		}
7523
	}
7524

    
7525
	if ($ifaddrs['addrs']) {
7526
	   $v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7527
		  return (array_search($addr['addr'], $v4vips) === false);
7528
	   });
7529
	}
7530

    
7531
	if ($ifaddrs['addrs6']) {
7532
	   $v6addrs = array_filter($ifaddrs['addrs6'], function($addr) use ($v6vips){
7533
		  return (array_search($addr['addr'], $v6vips) === false);
7534
	   });
7535
	}
7536
	/* Transform output to conform to pfSense_get_interface_addresses() */
7537
	if ($v4addrs) {
7538
		$v4addr = array_pop($v4addrs);
7539
		$ifaddrs['ipaddr'] = $v4addr['addr'];
7540
		foreach(array("subnetbits", "subnet", "broadcast", "tunnel") as $key) {
7541
			if (array_key_exists($key, $v4addr)) {
7542
				$ifaddrs[$key] = $v4addr[$key];
7543
			}
7544
		}
7545
	}
7546

    
7547
	if ($v6addrs) {
7548
		$v6addr = array_pop($v6addrs);
7549
		$ifaddrs['ipaddr6'] = $v6addr['addr'];
7550
		foreach(array("subnetbits", "tunnel") as $key) {
7551
			if (array_key_exists($key, $v6addr)) {
7552
				$ifaddrs[$key.'6'] = $v6addr[$key];
7553
			}
7554
		}
7555
		if (array_key_exists('tentative', $v6addr)) {
7556
			$ifaddrs['tentative'] = $v6addr['tentative'];
7557
		}
7558
	}
7559
	unset($ifaddrs['addrs']);
7560
	unset($ifaddrs['addrs6']);
7561

    
7562
	return($ifaddrs);
7563
}
7564

    
7565
/**
7566
 * Returns all interface addresses, including IPv6 LL addresses.
7567
 * XXX: Review/refactor functions used to retrieve interfaces addresses.
7568
 */
7569
function get_interface_addresses_all(string $interface): array {
7570
	$addresses = [];
7571

    
7572
	// Get primary IPv4/6 addresses
7573
	$addresses_primary = get_interface_addresses($interface);
7574
	if (!empty($addresses_primary['ipaddr'])) {
7575
		$addresses[] = $addresses_primary['ipaddr'];
7576
	}
7577
	if (!empty($addresses_primary['ipaddr6'])) {
7578
		$addresses[] = $addresses_primary['ipaddr6'];
7579
	}
7580

    
7581
	// Get IPv6 link-local address
7582
	$addresses_linklocal = find_interface_ipv6_ll($interface);
7583
	if (!empty($addresses_linklocal)) {
7584
		$addresses_linklocal_pos = strpos($addresses_linklocal, '%');
7585
		if ($addresses_linklocal_pos !== false) {
7586
			$addresses_linklocal = substr($addresses_linklocal, 0, $addresses_linklocal_pos);
7587
		}
7588
		$addresses[] = $addresses_linklocal;
7589
	}
7590

    
7591
	// Get VIPs
7592
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7593
		$vip = get_configured_vip($viface);
7594
		if ($vip['interface'] == $interface && !empty($vip['subnet'])) {
7595
			$addresses[] = $vip['subnet'];
7596
		}
7597
	}
7598

    
7599
	return $addresses;
7600
}
7601
?>
(22-22/61)