Project

General

Profile

Download (220 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2022 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 = 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 = 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 = 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 = 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
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
901
			pfSense_interface_mtu($interface, $mtu);
902
		}
903

    
904
		hardware_offloading_applyflags($interface);
905
		interfaces_bring_up($interface);
906
	}
907

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

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

    
946
function interface_lagg_configure($lagg, $flush = true) {
947
	if (!is_array($lagg)) {
948
		return -1;
949
	}
950

    
951
	$members = explode(',', $lagg['members']);
952
	if (!count($members)) {
953
		return -1;
954
	}
955

    
956
	if (platform_booting() || !(empty($lagg['laggif']))) {
957
		pfSense_interface_destroy($lagg['laggif']);
958
		pfSense_interface_create2($lagg['laggif']);
959
		$laggif = $lagg['laggif'];
960
	} else {
961
		$laggif = pfSense_interface_create2("lagg");
962
	}
963

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

    
976
	/* Just in case anything is not working well */
977
	if ($lagg_mtu == 0) {
978
		$lagg_mtu = 1500;
979
	}
980

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

    
988
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
989
	    ($lagg['lacptimeout'] != 'slow')) {
990
		$lacptimeout = 'lacp_fast_timeout';
991
	} else {
992
		$lacptimeout = '';
993
	}
994

    
995
	if ((($lagg['proto'] == 'lacp') || ($lagg['proto'] == 'loadbalance')) &&
996
	    isset($lagg['lagghash']) && !empty($lagg['lagghash'])) {
997
		$lagghash = 'lagghash ' . escapeshellarg($lagg['lagghash']);
998
	} else {
999
		$lagghash = '';
1000
	}
1001

    
1002
	foreach ($members as $member) {
1003
		if (!does_interface_exist($member)) {
1004
			continue;
1005
		}
1006

    
1007
		/* make sure the parent interface is up */
1008
		pfSense_interface_mtu($member, $lagg_mtu);
1009
		interfaces_bring_up($member);
1010
		hardware_offloading_applyflags($member);
1011

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

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

    
1020
	if ($flush) {
1021
		get_interface_arr(true);
1022
	}
1023

    
1024
	interfaces_bring_up($laggif);
1025

    
1026
	return $laggif;
1027
}
1028

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

    
1033
	if (!is_array($gre)) {
1034
		return -1;
1035
	}
1036

    
1037
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1038
	if (!interface_is_vlan($realif)) {
1039
		$realif = get_real_interface($gre['if']);
1040
	}
1041
	$realifip = get_interface_ip($gre['if']);
1042
	$realifip6 = get_interface_ipv6($gre['if']);
1043

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

    
1050
	/* make sure the parent interface is up */
1051
	interfaces_bring_up($realif);
1052

    
1053
	if (platform_booting() || !(empty($gre['greif']))) {
1054
		pfSense_interface_destroy($gre['greif']);
1055
		pfSense_interface_create2($gre['greif']);
1056
		$greif = $gre['greif'];
1057
	} else {
1058
		$greif = pfSense_interface_create2("gre");
1059
	}
1060

    
1061
	$tunnel_type = '';
1062
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1063
		$tunnel_type = 'v4';
1064
	}
1065
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1066
		$tunnel_type .= 'v6';
1067
	}
1068

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

    
1083
	$parentif = get_real_interface($gre['if']);
1084
	if ($parentif) {
1085
		interfaces_bring_up($parentif);
1086
	} else {
1087
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1088
	}
1089

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

    
1107
	if ($flush) {
1108
		get_interface_arr(true);
1109
	}
1110

    
1111
	interfaces_bring_up($greif);
1112

    
1113
	return $greif;
1114
}
1115

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

    
1137
	$entries = config_get_path("{$list}/{$entry}");
1138
	if (!is_array($entries)) {
1139
		return (NULL);
1140
	}
1141

    
1142
	foreach ($entries as $ent) {
1143
		if ($ent[$entif] == $if) {
1144
			return ($ent);
1145
		}
1146
	}
1147
	return (NULL);
1148
}
1149

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

    
1168
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1169
function interface_gif_configure(&$gif, $gifkey = "", $flush = true) {
1170
	if (!is_array($gif)) {
1171
		return -1;
1172
	}
1173

    
1174
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1175
	if (!interface_is_vlan($realif)) {
1176
		$realif = get_real_interface($gif['if']);
1177
	}
1178
	$ipaddr = get_interface_ip($gif['if']);
1179

    
1180
	if (is_ipaddrv4($gif['remote-addr'])) {
1181
		if (is_ipaddrv4($ipaddr)) {
1182
			$realifip = $ipaddr;
1183
		} else {
1184
			$realifip = get_interface_ip($gif['if']);
1185
		}
1186
		$realifgw = get_interface_gateway($gif['if']);
1187
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1188
		if (is_ipaddrv6($ipaddr)) {
1189
			$realifip = $ipaddr;
1190
		} else {
1191
			$realifip = get_interface_ipv6($gif['if']);
1192
		}
1193
		$realifgw = get_interface_gateway_v6($gif['if']);
1194
	}
1195

    
1196
	/* do not run ifconfig without correct $realifip */
1197
	if ((!is_ipaddrv4($realifip) && is_ipaddrv4($gif['remote-addr'])) || 
1198
	    (!is_ipaddrv6($realifip) && is_ipaddrv6($gif['remote-addr']))) {
1199
		return -1;
1200
	}
1201

    
1202
	/* make sure the parent interface is up */
1203
	$parentif = get_real_interface($gif['if']);
1204
	if ($parentif) {
1205
		interfaces_bring_up($parentif);
1206
	} else {
1207
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1208
	}
1209

    
1210
	if (platform_booting() || !(empty($gif['gifif']))) {
1211
		pfSense_interface_destroy($gif['gifif']);
1212
		pfSense_interface_create2($gif['gifif']);
1213
		$gifif = $gif['gifif'];
1214
	} else {
1215
		$gifif = pfSense_interface_create2("gif");
1216
	}
1217

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

    
1257
	if (!platform_booting()) {
1258
		$iflist = get_configured_interface_list();
1259
		foreach ($iflist as $ifname) {
1260
			$if = config_get_path("interfaces/{$ifname}/if", "");
1261
			if ($if == $gifif) {
1262
				if (get_interface_gateway($ifname)) {
1263
					system_routing_configure($ifname);
1264
					break;
1265
				}
1266
				if (get_interface_gateway_v6($ifname)) {
1267
					system_routing_configure($ifname);
1268
					break;
1269
				}
1270
			}
1271
		}
1272
	}
1273

    
1274

    
1275
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1276
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1277
		    $gif['tunnel-remote-addr']);
1278
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_router.last");
1279
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1280
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1281
		    $gif['tunnel-remote-addr']);
1282
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_routerv6.last");
1283
	}
1284

    
1285
	route_add_or_change($gif['remote-addr'], $realifgw);
1286

    
1287
	if ($flush) {
1288
		get_interface_arr(true);
1289
	}
1290

    
1291
	interfaces_bring_up($gifif);
1292

    
1293
	return $gifif;
1294
}
1295

    
1296
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1297
	if (!in_array($type, array('gre', 'gif'))) {
1298
		return;
1299
	}
1300

    
1301
	$tuns = config_get_path("{$type}s/{$type}");
1302
	if (!is_array($tuns) || !count($tuns)) {
1303
		return;
1304
	}
1305

    
1306
	foreach ($tuns as $i => $tunnel) {
1307
		if (empty($tunnel["{$type}if"])) {
1308
			$tunnel["{$type}if"] = $type . $i;
1309
		}
1310
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1311
			continue;
1312
		}
1313

    
1314
		$ipaddrv6 = config_get_path("interfaces/{$tunnel}/if/ipaddrv6");
1315
		if ($checkparent == 1) {
1316
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1317
				continue;
1318
			}
1319
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1320
				continue;
1321
			}
1322

    
1323
			if ($ipaddrv6 == "track6") {
1324
				continue;
1325
			}
1326
		} elseif ($checkparent == 2) {
1327
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1328
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1329
				$ipaddrv6 != "track6") {
1330
				continue;
1331
			}
1332
		}
1333
		if ($type == 'gif') {
1334
			interface_gif_configure($tunnel, "", false);
1335
		} elseif ($type == 'gre') {
1336
			interface_gre_configure($tunnel, "", false);
1337
		}
1338
	}
1339

    
1340
	/* Invalidate cache */
1341
	get_interface_arr(true);
1342
}
1343

    
1344
/* Build a list of IPsec interfaces */
1345
function interface_ipsec_vti_list_p1($ph1ent) {
1346
	$iface_list = array();
1347

    
1348
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array(config_get_path('ipsec/phase2'))) {
1349
		return $iface_list;
1350
	}
1351

    
1352
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1353
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1354
		return $iface_list;
1355
	}
1356

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

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

    
1407
	if (empty($ph1ent) || !is_array($ph1ent) || empty(config_get_path('ipsec/phase2'))) {
1408
		return false;
1409
	}
1410

    
1411
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1412
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1413
		return false;
1414
	}
1415

    
1416
	$left_spec = ipsec_get_phase1_src($ph1ent, $gateways_status);
1417

    
1418
	/* Attempt to resolve the remote gateway if needed */
1419
	$right_spec = ipsec_get_phase1_dst($ph1ent);
1420
	if (empty($right_spec)) {
1421
		/* Far end cannot be resolved */
1422
		return false;
1423
	}
1424

    
1425
	$iface_addrs = array();
1426
	$reqids = array();
1427

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

    
1468
	foreach ($iface_addrs as $ipsecif => $addrs) {
1469
		if (!is_array($addrs)) {
1470
			continue;
1471
		}
1472
		// Create IPsec interface
1473
		if (does_interface_exist($ipsecif)) {
1474
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1475
		}
1476
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
1477

    
1478
		/* Apply the outer tunnel addresses to the interface */
1479
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1480
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1481

    
1482
		/* Loop through all of the addresses for this interface and apply them as needed */
1483
		foreach ($addrs as $addr) {
1484
			// apply interface addresses
1485
			if (is_v6($addr['left'])) {
1486
				$inet = "inet6";
1487
				$gwtype = "v6";
1488
				$right = '';
1489
			} else {
1490
				$inet = "inet";
1491
				$gwtype = "";
1492
				$right = escapeshellarg($addr['right']);
1493
			}
1494

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

    
1522
function interfaces_ipsec_vti_configure($gateways_status = false) {
1523
	$bootmsg = false;
1524

    
1525
	/* Fetch gateway status if not passed */
1526
	if (!is_array($gateways_status)) {
1527
		$gateways_status = return_gateways_status(true);
1528
	}
1529
	foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
1530
		if ($ph1ent['disabled']) {
1531
			continue;
1532
		}
1533
		if (interface_ipsec_vti_configure($ph1ent, $gateways_status) &&
1534
			!$bootmsg && platform_booting()) {
1535
			echo gettext("Configuring IPsec VTI interfaces...");
1536
			$bootmsg = true;
1537
		}
1538
	}
1539
	if (platform_booting() && $bootmsg) {
1540
		echo gettext("done.") . "\n";
1541
	}
1542
}
1543

    
1544
function interfaces_configure() {
1545
	global $g;
1546

    
1547
	/* Set up our loopback interface */
1548
	interfaces_loopback_configure();
1549

    
1550
	/* create the unconfigured wireless clones */
1551
	interfaces_create_wireless_clones();
1552

    
1553
	/* set up LAGG virtual interfaces */
1554
	interfaces_lagg_configure();
1555

    
1556
	/* set up VLAN virtual interfaces */
1557
	interfaces_vlan_configure();
1558

    
1559
	interfaces_qinq_configure(false);
1560

    
1561
	$iflist = get_configured_interface_with_descr();
1562
	$delayed_list = array();
1563
	$bridge_list = array();
1564
	$track6_list = array();
1565
	$dhcp6c_list = array();
1566

    
1567
	/* This is needed to speedup interfaces on bootup. */
1568
	$reload = false;
1569
	if (!platform_booting()) {
1570
		$reload = true;
1571
	}
1572

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

    
1604
			if ($g['debug']) {
1605
				log_error(sprintf(gettext("Configuring %s"),
1606
				    $ifname));
1607
			}
1608
			interface_configure($if, $reload);
1609
			if (platform_booting()) {
1610
				echo gettext("done.") . "\n";
1611
			}
1612
		}
1613
	}
1614

    
1615
	/*
1616
	 * NOTE: The following function parameter consists of
1617
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1618
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1619
	 */
1620

    
1621
	/* set up GRE virtual interfaces */
1622
	interfaces_tunnel_configure(1,'','gre');
1623

    
1624
	/* set up GIF virtual interfaces */
1625
	interfaces_tunnel_configure(1,'','gif');
1626

    
1627
	/* set up BRIDGE virtual interfaces */
1628
	interfaces_bridge_configure(1);
1629

    
1630
	foreach ($track6_list as $if => $ifname) {
1631
		if (platform_booting()) {
1632
			printf(gettext("Configuring %s interface..."), $ifname);
1633
		}
1634
		if ($g['debug']) {
1635
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1636
		}
1637

    
1638
		interface_configure($if, $reload);
1639

    
1640
		if (platform_booting()) {
1641
			echo gettext("done.") . "\n";
1642
		}
1643
	}
1644

    
1645
	/* bring up vip interfaces */
1646
	interfaces_vips_configure();
1647

    
1648
	/* set up GRE virtual interfaces */
1649
	interfaces_tunnel_configure(2,'','gre');
1650

    
1651
	/* set up GIF virtual interfaces */
1652
	interfaces_tunnel_configure(2,'','gif');
1653

    
1654
	foreach ($delayed_list as $if => $ifname) {
1655
		if (platform_booting()) {
1656
			printf(gettext("Configuring %s interface..."), $ifname);
1657
		}
1658
		if ($g['debug']) {
1659
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1660
		}
1661

    
1662
		interface_configure($if, $reload);
1663

    
1664
		if (platform_booting()) {
1665
			echo gettext("done.") . "\n";
1666
		}
1667
	}
1668

    
1669
	/* set up BRIDGE virtual interfaces */
1670
	interfaces_bridge_configure(2);
1671

    
1672
	foreach ($bridge_list as $if => $ifname) {
1673
		if (platform_booting()) {
1674
			printf(gettext("Configuring %s interface..."), $ifname);
1675
		}
1676
		if ($g['debug']) {
1677
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1678
		}
1679

    
1680
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1681
		// redmine #3997
1682
		interface_reconfigure($if, $reload);
1683
		interfaces_vips_configure($if);
1684

    
1685
		if (platform_booting()) {
1686
			echo gettext("done.") . "\n";
1687
		}
1688
	}
1689

    
1690
	foreach ($dhcp6c_list as $if => $ifname) {
1691
		if (platform_booting()) {
1692
			printf(gettext("Configuring %s interface..."), $ifname);
1693
		}
1694
		if ($g['debug']) {
1695
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1696
		}
1697

    
1698
		interface_configure($if, $reload);
1699

    
1700
		if (platform_booting()) {
1701
			echo gettext("done.") . "\n";
1702
		}
1703
	}
1704

    
1705
	/* set up IPsec VTI interfaces */
1706
	interfaces_ipsec_vti_configure();
1707

    
1708
	/* configure interface groups */
1709
	interfaces_group_setup();
1710

    
1711
	if (!platform_booting()) {
1712
		/* reconfigure static routes (kernel may have deleted them) */
1713
		system_routing_configure();
1714

    
1715
		/* reload IPsec tunnels */
1716
		ipsec_configure();
1717

    
1718
		/* restart dns servers (defering dhcpd reload) */
1719
		if (config_get_path('dnsmasq/enable')) {
1720
			services_dnsmasq_configure(false);
1721
		}
1722
		if (config_get_path('unbound/enable')) {
1723
			services_unbound_configure(false);
1724
		}
1725

    
1726
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1727
		services_dhcpd_configure();
1728
	}
1729

    
1730
	return 0;
1731
}
1732

    
1733
function interface_reconfigure($interface = "wan", $reloadall = false) {
1734
	interface_bring_down($interface);
1735
	interface_configure($interface, $reloadall);
1736
}
1737

    
1738
function interface_vip_bring_down($vip) {
1739
	global $g;
1740

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

    
1770
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1771
	global $g;
1772

    
1773
	$iface = config_get_path("interfaces/{$interface}");
1774
	if (!$iface) {
1775
		return;
1776
	}
1777

    
1778
	if ($g['debug']) {
1779
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1780
	}
1781

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

    
1811
	/* check all gateways, including dynamic,
1812
	 * see https://redmine.pfsense.org/issues/12920 */
1813
	foreach (return_gateways_array(true) as $gw) {
1814
		if ($gw['friendlyiface'] == $interface) {
1815
			$restart_gateways_monitor = true;
1816
			break;
1817
		}
1818
	}
1819

    
1820
	switch ($ifcfg['ipaddr']) {
1821
		case "ppp":
1822
		case "pppoe":
1823
		case "pptp":
1824
		case "l2tp":
1825
			if (is_array($ppps) && count($ppps)) {
1826
				foreach ($ppps as  $ppp) {
1827
					if ($realif == $ppp['if']) {
1828
						if (isset($ppp['ondemand']) && !$destroy) {
1829
							send_event("interface reconfigure {$interface}");
1830
							break;
1831
						}
1832
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1833
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1834
							sleep(2);
1835
						}
1836
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1837
						break;
1838
					}
1839
				}
1840
			}
1841
			break;
1842
		case "dhcp":
1843
			kill_dhclient_process($realif);
1844
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1845
			if (does_interface_exist("$realif")) {
1846
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1847
				interface_vip_cleanup($interface, "inet4");
1848
				if ($destroy == true) {
1849
					pfSense_interface_flags($realif, -IFF_UP);
1850
				}
1851
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1852
			}
1853
			break;
1854
		default:
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
	}
1865

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

    
1925
	if (!empty($track6) && is_array($track6)) {
1926
		if (!function_exists('services_dhcpd_configure')) {
1927
			require_once('services.inc');
1928
		}
1929
		/* Bring down radvd and dhcp6 on these interfaces */
1930
		services_dhcpd_configure('inet6', $track6);
1931
	}
1932

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

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

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

    
1963
			/* Invalidate cache */
1964
			get_interface_arr(true);
1965
		}
1966
	}
1967

    
1968
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
1969
	if ($restart_gateways_monitor) {
1970
		setup_gateways_monitor();
1971
	}
1972

    
1973
	return;
1974
}
1975

    
1976
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
1977
	if (config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == false)) {
1978
		config_del_path('virtualip_carp_maintenancemode');
1979
		write_config("Leave CARP maintenance mode");
1980
	} elseif (!config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == true)) {
1981
		config_set_path('virtualip_carp_maintenancemode', true);
1982
		write_config(gettext("Enter CARP maintenance mode"));
1983
	}
1984
	init_config_arr(array('virtualip', 'vip'));
1985

    
1986
	foreach (config_get_path('virtualip/vip', []) as $vip) {
1987
		if ($vip['mode'] == "carp") {
1988
			interface_carp_configure($vip, true);
1989
		}
1990
	}
1991
}
1992

    
1993
function interface_wait_tentative($interface, $timeout = 10) {
1994
	if (!does_interface_exist($interface)) {
1995
		return false;
1996
	}
1997

    
1998
	$time = 0;
1999
	while ($time <= $timeout) {
2000
		$if = get_interface_addresses($interface);
2001
		if (!isset($if['tentative'])) {
2002
			return true;
2003
		}
2004
		sleep(1);
2005
		$time++;
2006
	}
2007

    
2008
	return false;
2009
}
2010

    
2011
function interface_isppp_type($interface) {
2012
	$iface = config_get_path("interfaces/{$interface}");
2013
	if (!is_array($iface)) {
2014
		return false;
2015
	}
2016

    
2017
	switch ($iface['ipaddr']) {
2018
		case 'pptp':
2019
		case 'l2tp':
2020
		case 'pppoe':
2021
		case 'ppp':
2022
			return true;
2023
			break;
2024
		default:
2025
			return false;
2026
			break;
2027
	}
2028
}
2029

    
2030
function interfaces_ptpid_used($ptpid) {
2031
	$ppps = config_get_path('ppps/ppp');
2032
	if (is_array($ppps)) {
2033
		foreach ($ppps as $settings) {
2034
			if ($ptpid == $settings['ptpid']) {
2035
				return true;
2036
			}
2037
		}
2038
	}
2039

    
2040
	return false;
2041
}
2042

    
2043
function interfaces_ptpid_next() {
2044
	$ptpid = 0;
2045
	while (interfaces_ptpid_used($ptpid)) {
2046
		$ptpid++;
2047
	}
2048

    
2049
	return $ptpid;
2050
}
2051

    
2052
function getMPDCRONSettings($pppif) {
2053
	global $g;
2054

    
2055
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2056
	foreach (config_get_path('cron/item', []) as $i => $item) {
2057
		if (stripos($item['command'], $cron_cmd_file) !== false) {
2058
			return array("ID" => $i, "ITEM" => $item);
2059
		}
2060
	}
2061

    
2062
	return NULL;
2063
}
2064

    
2065
function handle_pppoe_reset($post_array) {
2066
	global $g;
2067

    
2068
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2069
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2070

    
2071
	if (!is_array(config_get_path('cron/item'))) {
2072
		if (config_set_path('cron/item', array()) === null)
2073
			log_error(gettext('Cron section in config root is invalid.'));
2074
			return;
2075
	}
2076

    
2077
	$itemhash = getMPDCRONSettings($pppif);
2078

    
2079
	// reset cron items if necessary and return
2080
	if (empty($post_array['pppoe-reset-type'])) {
2081
		if (isset($itemhash)) {
2082
			config_del_path("cron/item/{$itemhash['ID']}");
2083
		}
2084
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2085
		return;
2086
	}
2087

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

    
2152
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2153
	$ppp_list = array();
2154
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
2155
		$ports = explode(",", $ppp['ports']);
2156
		foreach($ports as $port) {
2157
			foreach($triggerinterfaces as $vip) {
2158
				if ($port == "_vip{$vip['uniqid']}") {
2159
					$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2160
					$ppp_list[$if] = 1;
2161
				}
2162
			}
2163
		}
2164
	}
2165
	foreach(array_keys($ppp_list) as $pppif) {
2166
		interface_ppps_configure($pppif);
2167
	}
2168
}
2169

    
2170
/*
2171
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2172
 * It writes the mpd config file to /var/etc every time the link is opened.
2173
 */
2174
function interface_ppps_configure($interface) {
2175
	global $g;
2176

    
2177
	$iface = config_get_path("interfaces/{$interface}");
2178
	/* Return for unassigned interfaces. This is a minimum requirement. */
2179
	if (empty($iface)) {
2180
		return 0;
2181
	}
2182
	$ifcfg = $iface;
2183
	if (!isset($ifcfg['enable'])) {
2184
		return 0;
2185
	}
2186

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

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

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

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

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

    
2285
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2286
	    (is_array($ports) && count($ports) > 1)) {
2287
		$multilink = "enable";
2288
	} else {
2289
		$multilink = "disable";
2290
	}
2291

    
2292
	if ($type == "modem") {
2293
		if (is_ipaddr($ppp['localip'])) {
2294
			$localip = $ppp['localip'];
2295
		} else {
2296
			$localip = '0.0.0.0';
2297
		}
2298

    
2299
		if (is_ipaddr($ppp['gateway'])) {
2300
			$gateway = $ppp['gateway'];
2301
		} else {
2302
			$gateway = "10.64.64.{$pppid}";
2303
		}
2304
		$ranges = "{$localip}/0 {$gateway}/0";
2305

    
2306
		if (empty($ppp['apnum'])) {
2307
			$ppp['apnum'] = 1;
2308
		}
2309
	} else {
2310
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2311
	}
2312

    
2313
	if (isset($ppp['ondemand'])) {
2314
		$ondemand = "enable";
2315
	} else {
2316
		$ondemand = "disable";
2317
	}
2318
	if (!isset($ppp['idletimeout'])) {
2319
		$ppp['idletimeout'] = 0;
2320
	}
2321

    
2322
	if (empty($ppp['username']) && $type == "modem") {
2323
		$ppp['username'] = "user";
2324
		$ppp['password'] = "none";
2325
	}
2326
	if (empty($ppp['password']) && $type == "modem") {
2327
		$passwd = "none";
2328
	} else {
2329
		$passwd = base64_decode($ppp['password']);
2330
	}
2331

    
2332
	$bandwidths = explode(',', $ppp['bandwidth']);
2333
	$defaultmtu = "1492";
2334
	if (!empty($ifcfg['mtu'])) {
2335
		$defaultmtu = intval($ifcfg['mtu']);
2336
	}
2337
	if (isset($ppp['mtu'])) {
2338
		$mtus = explode(',', $ppp['mtu']);
2339
	}
2340
	if (isset($ppp['mru'])) {
2341
		$mrus = explode(',', $ppp['mru']);
2342
	}
2343
	if (isset($ppp['mrru'])) {
2344
		$mrrus = explode(',', $ppp['mrru']);
2345
	}
2346
	if (!empty($ifcfg['ipaddrv6'])) {
2347
		$ipv6cp = "set bundle enable ipv6cp";
2348
	}
2349

    
2350
	// Construct the mpd.conf file
2351
	$mpdconf = <<<EOD
2352
startup:
2353
	# configure the console
2354
	set console close
2355
	# configure the web server
2356
	set web close
2357

    
2358
default:
2359
{$ppp['type']}client:
2360
	create bundle static {$interface}
2361
	set bundle period 6
2362
	set bundle lowat 0
2363
	set bundle hiwat 0
2364
	set bundle min-con 3
2365
	set bundle min-dis 6
2366
	set bundle enable bw-manage
2367
	{$ipv6cp}
2368
	set iface name {$pppif}
2369

    
2370
EOD;
2371

    
2372
	if (isset($ifcfg['descr'])) {
2373
		$mpdconf .= <<<EOD
2374
	set iface description "{$ifcfg['descr']}"
2375

    
2376
EOD;
2377
	}
2378
	$setdefaultgw = false;
2379
	$defgw4 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw4'));
2380
//	$defgw6 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw6'));
2381
	if ($defgw4['interface'] == $interface) {
2382
		$setdefaultgw = true;
2383
	}
2384

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

    
2394
EOD;
2395
	}
2396

    
2397
	$mpdconf .= <<<EOD
2398
	set iface {$ondemand} on-demand
2399
	set iface idle {$ppp['idletimeout']}
2400

    
2401
EOD;
2402

    
2403
	if (isset($ppp['ondemand'])) {
2404
		$mpdconf .= <<<EOD
2405
	set iface addrs 10.10.1.1 10.10.1.2
2406

    
2407
EOD;
2408
	}
2409

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

    
2430
EOD;
2431
	}
2432

    
2433
	if (isset($ppp['tcpmssfix'])) {
2434
		$tcpmss = "disable";
2435
	} else {
2436
		$tcpmss = "enable";
2437
	}
2438
	$mpdconf .= <<<EOD
2439
	set iface {$tcpmss} tcpmssfix
2440

    
2441
EOD;
2442

    
2443
	$mpdconf .= <<<EOD
2444
	set iface up-script /usr/local/sbin/ppp-linkup
2445
	set iface down-script /usr/local/sbin/ppp-linkdown
2446
	set ipcp ranges {$ranges}
2447

    
2448
EOD;
2449
	if (isset($ppp['vjcomp'])) {
2450
		$mpdconf .= <<<EOD
2451
	set ipcp no vjcomp
2452

    
2453
EOD;
2454
	}
2455

    
2456
	if (config_get_path('system/dnsallowoverride')) {
2457
		$mpdconf .= <<<EOD
2458
	set ipcp enable req-pri-dns
2459
	set ipcp enable req-sec-dns
2460

    
2461
EOD;
2462
	}
2463

    
2464
	if (!isset($ppp['verbose_log'])) {
2465
		$mpdconf .= <<<EOD
2466
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2467

    
2468
EOD;
2469
	}
2470

    
2471
	foreach ($ports as $pid => $port) {
2472
		$port = get_real_interface($port);
2473
		$mpdconf .= <<<EOD
2474

    
2475
	create link static {$interface}_link{$pid} {$type}
2476
	set link action bundle {$interface}
2477
	set link {$multilink} multilink
2478
	set link keep-alive 10 60
2479
	set link max-redial 0
2480

    
2481
EOD;
2482
		if (isset($ppp['shortseq'])) {
2483
			$mpdconf .= <<<EOD
2484
	set link no shortseq
2485

    
2486
EOD;
2487
		}
2488

    
2489
		if (isset($ppp['acfcomp'])) {
2490
			$mpdconf .= <<<EOD
2491
	set link no acfcomp
2492

    
2493
EOD;
2494
		}
2495

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

    
2500
EOD;
2501
		}
2502

    
2503
		$mpdconf .= <<<EOD
2504
	set link disable chap pap
2505
	set link accept chap pap eap
2506
	set link disable incoming
2507

    
2508
EOD;
2509

    
2510

    
2511
		if (!empty($bandwidths[$pid])) {
2512
			$mpdconf .= <<<EOD
2513
	set link bandwidth {$bandwidths[$pid]}
2514

    
2515
EOD;
2516
		}
2517

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

    
2533
EOD;
2534
		}
2535

    
2536
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2537
		    !isset($ppp['mtu-override']) &&
2538
		    !empty($mrus[$pid])) {
2539
			$mpdconf .= <<<EOD
2540
	set link mru {$mrus[$pid]}
2541

    
2542
EOD;
2543
		}
2544

    
2545
		if (!empty($mrrus[$pid])) {
2546
			$mpdconf .= <<<EOD
2547
	set link mrru {$mrrus[$pid]}
2548

    
2549
EOD;
2550
		}
2551

    
2552
		$mpdconf .= <<<EOD
2553
	set auth authname "{$ppp['username']}"
2554
	set auth password {$passwd}
2555

    
2556
EOD;
2557
		if ($type == "modem") {
2558
			$mpdconf .= <<<EOD
2559
	set modem device {$ppp['ports']}
2560
	set modem script DialPeer
2561
	set modem idle-script Ringback
2562
	set modem watch -cd
2563
	set modem var \$DialPrefix "DT"
2564
	set modem var \$Telephone "{$ppp['phone']}"
2565

    
2566
EOD;
2567
		}
2568
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2569
			$mpdconf .= <<<EOD
2570
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2571

    
2572
EOD;
2573
		}
2574
		if (isset($ppp['initstr']) && $type == "modem") {
2575
			$initstr = base64_decode($ppp['initstr']);
2576
			$mpdconf .= <<<EOD
2577
	set modem var \$InitString "{$initstr}"
2578

    
2579
EOD;
2580
		}
2581
		if (isset($ppp['simpin']) && $type == "modem") {
2582
			if ($ppp['pin-wait'] == "") {
2583
				$ppp['pin-wait'] = 0;
2584
			}
2585
			$mpdconf .= <<<EOD
2586
	set modem var \$SimPin "{$ppp['simpin']}"
2587
	set modem var \$PinWait "{$ppp['pin-wait']}"
2588

    
2589
EOD;
2590
		}
2591
		if (isset($ppp['apn']) && $type == "modem") {
2592
			$mpdconf .= <<<EOD
2593
	set modem var \$APN "{$ppp['apn']}"
2594
	set modem var \$APNum "{$ppp['apnum']}"
2595

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

    
2612
EOD;
2613
		}
2614
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2615
			$mpdconf .= <<<EOD
2616
	set pppoe max-payload {$mtus[$pid]}
2617

    
2618
EOD;
2619
		}
2620
		if ($type == "pppoe") {
2621
			$mpdconf .= <<<EOD
2622
	set pppoe iface {$port}
2623

    
2624
EOD;
2625
		}
2626

    
2627
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2628
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2629
			$mpdconf .= <<<EOD
2630
	set l2tp secret "{$secret}"
2631

    
2632
EOD;
2633
		}
2634

    
2635
		if (($type == "pptp") || ($type == "l2tp")) {
2636
			$mpdconf .= <<<EOD
2637
	set {$type} self {$localips[$pid]}
2638
	set {$type} peer {$gateways[$pid]}
2639

    
2640
EOD;
2641
		}
2642

    
2643
		$mpdconf .= "\topen\n";
2644
	} //end foreach ($port)
2645

    
2646

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

    
2662
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2663
	if (isset($ppp['uptime'])) {
2664
		if (!file_exists("/conf/{$pppif}.log")) {
2665
			file_put_contents("/conf/{$pppif}.log", '');
2666
		}
2667
	} else {
2668
		if (file_exists("/conf/{$pppif}.log")) {
2669
			@unlink("/conf/{$pppif}.log");
2670
		}
2671
	}
2672

    
2673
	/* clean up old lock files */
2674
	foreach ($ports as $port) {
2675
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2676
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2677
		}
2678
	}
2679

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

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

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

    
2723
	/* Remove all temporary bogon IPv4 addresses */
2724
	if (is_array($tempaddr)) {
2725
		foreach ($tempaddr as $tempiface) {
2726
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2727
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2728
			}
2729
		}
2730
		unset ($tempaddr);
2731
	}
2732

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

    
2753
	return 1;
2754
}
2755

    
2756
function interfaces_sync_setup() {
2757

    
2758
	if (config_get_path('system/developerspew')) {
2759
		$mt = microtime();
2760
		echo "interfaces_sync_setup() being called $mt\n";
2761
	}
2762

    
2763
	if (platform_booting()) {
2764
		echo gettext("Configuring CARP settings...");
2765
		mute_kernel_msgs();
2766
	}
2767

    
2768
	/* suck in configuration items */
2769
	if (!empty(config_get_path('hasync'))) {
2770
		$pfsyncenabled = config_get_path('hasync/pfsyncenabled');
2771
		$pfsyncinterface = config_get_path('hasync/pfsyncinterface');
2772
		$pfsyncpeerip = config_get_path('hasync/pfsyncpeerip');
2773
	}
2774

    
2775
	set_sysctl(array(
2776
		"net.inet.carp.preempt" => "1",
2777
		"net.inet.carp.log" => "1")
2778
	);
2779

    
2780
	if (!empty($pfsyncinterface)) {
2781
		$carp_sync_int = get_real_interface($pfsyncinterface);
2782
	}
2783

    
2784
	/* setup pfsync interface */
2785
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2786
		if (is_ipaddr($pfsyncpeerip)) {
2787
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2788
		} else {
2789
			$syncpeer = "-syncpeer";
2790
		}
2791

    
2792
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2793
		    "{$syncpeer} up");
2794
		mwexec("/sbin/ifconfig pfsync0 -defer");
2795

    
2796
		/*
2797
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2798
		 * cluster carp will come up before pfsync(4) has updated and
2799
		 * so will cause issues for existing sessions.
2800
		 */
2801
		log_error(gettext("waiting for pfsync..."));
2802

    
2803
		$i = 0;
2804
		do {
2805
			sleep(1);
2806
			exec('/sbin/ifconfig pfsync0 | ' .
2807
				 '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2808
				 $rc);
2809
			$i++;
2810
		} while ($rc != 0 && $i <= 30);
2811

    
2812
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2813
		log_error(gettext("Configuring CARP settings finalize..."));
2814
	} else {
2815
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2816
	}
2817

    
2818
	$carplist = get_configured_vip_list('all', VIP_CARP);
2819
	if (is_array($carplist) && count($carplist) > 0) {
2820
		set_single_sysctl("net.inet.carp.allow", "1");
2821
	} else {
2822
		set_single_sysctl("net.inet.carp.allow", "0");
2823
	}
2824

    
2825
	if (platform_booting()) {
2826
		unmute_kernel_msgs();
2827
		echo gettext("done.") . "\n";
2828
	}
2829
}
2830

    
2831
function interface_proxyarp_configure($interface = "") {
2832
	global $g;
2833
	if (config_get_path('system/developerspew')) {
2834
		$mt = microtime();
2835
		echo "interface_proxyarp_configure() being called $mt\n";
2836
	}
2837

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

    
2848
	$paa = array();
2849
	$vips = config_get_path('virtualip/vip');
2850
	if (is_array($vips)) {
2851

    
2852
		/* group by interface */
2853
		foreach ($vips as $vipent) {
2854
			if ($vipent['mode'] === "proxyarp") {
2855
				if ($vipent['interface']) {
2856
					$proxyif = $vipent['interface'];
2857
				} else {
2858
					$proxyif = "wan";
2859
				}
2860

    
2861
				if (!empty($interface) && $interface != $proxyif) {
2862
					continue;
2863
				}
2864

    
2865
				if (!is_array($paa[$proxyif])) {
2866
					$paa[$proxyif] = array();
2867
				}
2868

    
2869
				$paa[$proxyif][] = $vipent;
2870
			}
2871
		}
2872
	}
2873

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

    
2913
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2914
	$vips = config_get_path('virtualip/vip');
2915
	if (is_array($vips)) {
2916
		foreach ($vips as $vip) {
2917

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

    
2934
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2935
				interface_vip_bring_down($vip);
2936
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2937
				interface_vip_bring_down($vip);
2938
			elseif ($inet == "all")
2939
				interface_vip_bring_down($vip);
2940
		}
2941
	}
2942
}
2943

    
2944
function interfaces_vips_configure($interface = "") {
2945
	if (config_get_path('system/developerspew')) {
2946
		$mt = microtime();
2947
		echo "interfaces_vips_configure() being called $mt\n";
2948
	}
2949

    
2950
	$vips = config_get_path('virtualip/vip');
2951
	if (!is_array($vips)) {
2952
		return;
2953
	}
2954

    
2955
	$carp_setuped = false;
2956
	$anyproxyarp = false;
2957
	foreach ($vips as $vip) {
2958
		if ($interface <> "" &&
2959
		    get_root_interface($vip['interface']) <> $interface) {
2960
			continue;
2961
		}
2962
		switch ($vip['mode']) {
2963
			case "proxyarp":
2964
				/*
2965
				 * nothing it is handled on
2966
				 * interface_proxyarp_configure()
2967
				 */
2968
				$anyproxyarp = true;
2969
				break;
2970
			case "ipalias":
2971
				interface_ipalias_configure($vip);
2972
				break;
2973
			case "carp":
2974
				if ($carp_setuped == false) {
2975
					$carp_setuped = true;
2976
				}
2977
				interface_carp_configure($vip);
2978
				break;
2979
		}
2980
	}
2981
	if ($carp_setuped == true) {
2982
		interfaces_sync_setup();
2983
	}
2984
	if ($anyproxyarp == true) {
2985
		interface_proxyarp_configure();
2986
	}
2987
}
2988

    
2989
function interface_ipalias_configure(&$vip) {
2990
	$gateway = '';
2991
	if ($vip['mode'] != 'ipalias') {
2992
		return;
2993
	}
2994

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

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

    
3025
function interface_carp_configure(&$vip, $maintenancemode_only = false, $ipalias_reload = false) {
3026
	if (config_get_path('system/developerspew')) {
3027
		$mt = microtime();
3028
		echo "interface_carp_configure() being called $mt\n";
3029
	}
3030

    
3031
	if ($vip['mode'] != "carp") {
3032
		return;
3033
	}
3034

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

    
3048
	$vip_password = $vip['password'];
3049
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3050
	    $vip_password)));
3051
	if ($vip['password'] != "") {
3052
		$password = " pass {$vip_password}";
3053
	}
3054

    
3055
	$advbase = "";
3056
	if (!empty($vip['advbase'])) {
3057
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3058
	}
3059

    
3060
	$carp_maintenancemode = config_path_enabled('/','virtualip_carp_maintenancemode');
3061
	if ($carp_maintenancemode) {
3062
		$advskew = "advskew 254";
3063
	} else {
3064
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3065
	}
3066

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

    
3070
	if (!$maintenancemode_only) {
3071
		if (is_ipaddrv4($vip['subnet'])) {
3072
			mwexec("/sbin/ifconfig {$realif} " .
3073
			    escapeshellarg($vip['subnet']) . "/" .
3074
			    escapeshellarg($vip['subnet_bits']) .
3075
			    " alias vhid " . escapeshellarg($vip['vhid']));
3076
		} elseif (is_ipaddrv6($vip['subnet'])) {
3077
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3078
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3079
			    escapeshellarg($vip['subnet_bits']) .
3080
			    " alias vhid " . escapeshellarg($vip['vhid']));
3081
		}
3082
	}
3083

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

    
3097
	return $realif;
3098
}
3099

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

    
3142
	if ($needs_clone == true) {
3143
		/* remove previous instance if it exists */
3144
		if (does_interface_exist($realif)) {
3145
			pfSense_interface_destroy($realif);
3146

    
3147
			/* Invalidate cache */
3148
			get_interface_arr(true);
3149
		}
3150

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

    
3167
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3168

    
3169
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3170
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3171
				 'regdomain', 'regcountry', 'reglocation');
3172

    
3173
	if (!is_interface_wireless($ifcfg['if'])) {
3174
		return;
3175
	}
3176

    
3177
	$baseif = interface_get_wireless_base($ifcfg['if']);
3178

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

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

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

    
3245
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3246
	global $g;
3247

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

    
3255
	// Remove script file
3256
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3257

    
3258
	// Clone wireless nic if needed.
3259
	interface_wireless_clone($if, $wl);
3260

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

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

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

    
3270
	/* set values for /path/program */
3271
	if (file_exists("/usr/local/sbin/hostapd")) {
3272
		$hostapd = "/usr/local/sbin/hostapd";
3273
	} else {
3274
		$hostapd = "/usr/sbin/hostapd";
3275
	}
3276
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3277
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3278
	} else {
3279
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3280
	}
3281
	$ifconfig = "/sbin/ifconfig";
3282
	$sysctl = "/sbin/sysctl";
3283
	$sysctl_args = "-q";
3284

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

    
3287
	$wlcmd = array();
3288
	$wl_sysctl = array();
3289
	/* Set a/b/g standard */
3290
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3291
	/* skip mode entirely for "auto" */
3292
	if ($wlcfg['standard'] != "auto") {
3293
		$wlcmd[] = "mode " . escapeshellarg($standard);
3294
	}
3295

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

    
3302
	/* Set ssid */
3303
	if ($wlcfg['ssid']) {
3304
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3305
	}
3306

    
3307
	/* Set 802.11g protection mode */
3308
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3309

    
3310
	/* set wireless channel value */
3311
	if (isset($wlcfg['channel'])) {
3312
		if ($wlcfg['channel'] == "0") {
3313
			$wlcmd[] = "channel any";
3314
		} else {
3315
			if ($wlcfg['channel_width'] != "0") {
3316
				$channel_width = ":" . $wlcfg['channel_width'];
3317
			} else {
3318
				$channel_width = '';
3319
			}
3320
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3321
		}
3322
	}
3323

    
3324
	/* Set antenna diversity value */
3325
	if (isset($wlcfg['diversity'])) {
3326
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3327
	}
3328

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

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

    
3339
	/* set Distance value */
3340
	if ($wlcfg['distance']) {
3341
		$distance = escapeshellarg($wlcfg['distance']);
3342
	}
3343

    
3344
	/* Set wireless hostap mode */
3345
	if ($wlcfg['mode'] == "hostap") {
3346
		$wlcmd[] = "mediaopt hostap";
3347
	} else {
3348
		$wlcmd[] = "-mediaopt hostap";
3349
	}
3350

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

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

    
3360
	/* handle hide ssid option */
3361
	if (isset($wlcfg['hidessid']['enable'])) {
3362
		$wlcmd[] = "hidessid";
3363
	} else {
3364
		$wlcmd[] = "-hidessid";
3365
	}
3366

    
3367
	/* handle pureg (802.11g) only option */
3368
	if (isset($wlcfg['pureg']['enable'])) {
3369
		$wlcmd[] = "mode 11g pureg";
3370
	} else {
3371
		$wlcmd[] = "-pureg";
3372
	}
3373

    
3374
	/* handle puren (802.11n) only option */
3375
	if (isset($wlcfg['puren']['enable'])) {
3376
		$wlcmd[] = "puren";
3377
	} else {
3378
		$wlcmd[] = "-puren";
3379
	}
3380

    
3381
	/* enable apbridge option */
3382
	if (isset($wlcfg['apbridge']['enable'])) {
3383
		$wlcmd[] = "apbridge";
3384
	} else {
3385
		$wlcmd[] = "-apbridge";
3386
	}
3387

    
3388
	/* handle turbo option */
3389
	if (isset($wlcfg['turbo']['enable'])) {
3390
		$wlcmd[] = "mediaopt turbo";
3391
	} else {
3392
		$wlcmd[] = "-mediaopt turbo";
3393
	}
3394

    
3395
	/* handle txpower setting */
3396
	// or don't. this has issues at the moment.
3397
	/*
3398
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3399
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3400
	}*/
3401

    
3402
	/* handle wme option */
3403
	if (isset($wlcfg['wme']['enable'])) {
3404
		$wlcmd[] = "wme";
3405
	} else {
3406
		$wlcmd[] = "-wme";
3407
	}
3408

    
3409
	/* Enable wpa if it's configured. No WEP support anymore. */
3410
	if (isset($wlcfg['wpa']['enable'])) {
3411
		$wlcmd[] = "authmode wpa wepmode off ";
3412
	} else {
3413
		$wlcmd[] = "authmode open wepmode off ";
3414
	}
3415

    
3416
	kill_hostapd($if);
3417
	mwexec(kill_wpasupplicant("{$if}"));
3418

    
3419
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3420
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3421

    
3422
	unlink_if_exists("{$wpa_supplicant_file}*");
3423
	unlink_if_exists($hostapd_conf);
3424

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

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

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

    
3512
EOD;
3513

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

    
3520
EOD;
3521
				}
3522
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3523
					$wpa .= "ieee8021x=1\n";
3524

    
3525
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3526
						$auth_server_port = "1812";
3527
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3528
							$auth_server_port = intval($wlcfg['auth_server_port']);
3529
						}
3530
						$wpa .= <<<EOD
3531

    
3532
auth_server_addr={$wlcfg['auth_server_addr']}
3533
auth_server_port={$auth_server_port}
3534
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3535

    
3536
EOD;
3537
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3538
							$auth_server_port2 = "1812";
3539
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3540
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3541
							}
3542

    
3543
							$wpa .= <<<EOD
3544
auth_server_addr={$wlcfg['auth_server_addr2']}
3545
auth_server_port={$auth_server_port2}
3546
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3547

    
3548
EOD;
3549
						}
3550
					}
3551
				}
3552

    
3553
				@file_put_contents($hostapd_conf, $wpa);
3554
				unset($wpa);
3555
			}
3556
			break;
3557
	}
3558

    
3559
	/*
3560
	 *    all variables are set, lets start up everything
3561
	 */
3562

    
3563
	$baseif = interface_get_wireless_base($if);
3564
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3565
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3566

    
3567
	/* set sysctls for the wireless interface */
3568
	if (!empty($wl_sysctl)) {
3569
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3570
		foreach ($wl_sysctl as $wl_sysctl_line) {
3571
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3572
		}
3573
	}
3574

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

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

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

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

    
3609
	fclose($fd_set);
3610

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

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

    
3632
	if ($reg_changing) {
3633
		/* set regulatory domain */
3634
		if ($wlcfg['regdomain']) {
3635
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3636
		}
3637

    
3638
		/* set country */
3639
		if ($wlcfg['regcountry']) {
3640
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3641
		}
3642

    
3643
		/* set location */
3644
		if ($wlcfg['reglocation']) {
3645
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3646
		}
3647

    
3648
		$wlregcmd_args = implode(" ", $wlregcmd);
3649

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

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

    
3671
		/* apply the regulatory settings */
3672
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3673
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3674

    
3675
		/* bring the clones back up that were previously up */
3676
		foreach ($clones_up as $clone_if) {
3677
			interfaces_bring_up($clone_if);
3678

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

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

    
3704
	/* configure wireless */
3705
	$wlcmd_args = implode(" ", $wlcmd);
3706
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3707
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3708
	/* Bring the interface up only after setting up all the other parameters. */
3709
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3710
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3711
	fclose($wlan_setup_log);
3712

    
3713
	unset($wlcmd_args, $wlcmd);
3714

    
3715

    
3716
	sleep(1);
3717
	/* execute hostapd and wpa_supplicant if required in shell */
3718
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3719

    
3720
	return 0;
3721

    
3722
}
3723

    
3724
function kill_hostapd($interface) {
3725
	global $g;
3726

    
3727
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3728
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3729
	}
3730
}
3731

    
3732
function kill_wpasupplicant($interface) {
3733
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3734
}
3735

    
3736
function find_dhclient_process($interface) {
3737
	if ($interface) {
3738
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3739
	} else {
3740
		$pid = 0;
3741
	}
3742

    
3743
	return intval($pid);
3744
}
3745

    
3746
function kill_dhclient_process($interface) {
3747
	if (empty($interface) || !does_interface_exist($interface)) {
3748
		return;
3749
	}
3750

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

    
3762
function find_dhcp6c_process() {
3763
	global $g;
3764

    
3765
	if (isvalidpid("{$g['varrun_path']}/dhcp6c.pid")) {
3766
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c.pid"), " \n");
3767
	} else {
3768
		return(false);
3769
	}
3770

    
3771
	return intval($pid);
3772
}
3773

    
3774
function kill_dhcp6client_process($force, $release = false) {
3775
	global $g;
3776

    
3777
	$i = 0;
3778

    
3779
	/*
3780
	Beware of the following: Reason, the interface may be down, but
3781
	dhcp6c may still be running, it just complains it cannot send
3782
	and carries on. Commented out as will stop the call to kill.
3783

    
3784
	if (empty($interface) || !does_interface_exist($interface)) {
3785
		return;
3786
	}
3787
	*/
3788

    
3789
	/*********** Notes on signals for dhcp6c and this function *************
3790

    
3791
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3792
	a release and waiting for the response that never comes.
3793
	So we need to tell it that the interface is down and to just die quickly
3794
	otherwise a new client may launch and we have duplicate proceses.
3795
	In this case use SIGUSR1.
3796

    
3797
	If we want to exit normally obeying the no release flag then use SIGTERM.
3798
	If we want to exit with a release overiding the no release flag then
3799
	use SIGUSR2.
3800

    
3801
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3802
	exit quickly without sending release signals.
3803

    
3804
	If $Force is set to false and $release is also set to false dhcp6c will
3805
	follow the no-release flag.
3806

    
3807
	If $Force is set to false and $release is true then dhcp6c will send a
3808
	release regardless of the no-release flag.
3809
	***********************************************************************/
3810

    
3811
	if ($force == true) {
3812
		$psig=SIGUSR1;
3813
	} elseif ($release == false) {
3814
		$psig=SIGTERM;
3815
	} else {
3816
		$psig=SIGUSR2;
3817
	}
3818

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

    
3832
	$pid = find_dhcp6c_process();
3833

    
3834
	if($pid != 0) {
3835
		posix_kill($pid, SIGHUP);
3836
	}
3837
}
3838

    
3839
function run_dhcp6client_process($interfaces, $debugOption, $noreleaseOption) {
3840
	global $g;
3841

    
3842
	/*
3843
	 * Only run this if the lock does not exist. In theory the lock being
3844
	 * there in this mode means the user has selected dhcp6withoutRA while
3845
	 * a session is active in the other mode.
3846
	 *
3847
	 * It should not happen as the process should have been killed and the
3848
	 * lock deleted.
3849
	 */
3850

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

    
3866
function interface_virtual_create($interface, $gateways_status = false) {
3867

    
3868
	/* Fetch gateway status if not passed */
3869
	if (!is_array($gateways_status)) {
3870
		$gateways_status = return_gateways_status(true);
3871
	}
3872

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

    
3915
function interface_vlan_mtu_configured($iface) {
3916

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

    
3920
		if ($vlan['vlanif'] != $iface)
3921
			continue;
3922

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

    
3934
	return $mtu;
3935
}
3936

    
3937
function interface_mtu_wanted_for_pppoe($realif) {
3938

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

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

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

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

    
3973
	return $mtu;
3974
}
3975

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

    
3981
	$wancfg = config_get_path("interfaces/{$interface}");
3982

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

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

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

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

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

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

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

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

    
4056
	$current_mac = get_interface_mac($realhwif);
4057
	$vendor_mac = get_interface_vendor_mac($realhwif);
4058

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

    
4062
		interface_set_macaddr($realhwif, $mac_addr);
4063

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

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

    
4105
	/* Apply hw offloading policies as configured */
4106
	enable_hardware_offloading($interface);
4107

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

    
4115
	$tunnelif = substr($realif, 0, 3);
4116

    
4117
	$mtuif = $realif;
4118
	$mtuhwif = $realhwif;
4119

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

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

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

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

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

    
4168
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4169

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

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

    
4201
	if (does_interface_exist($wancfg['if'])) {
4202
		interfaces_bring_up($wancfg['if']);
4203
	}
4204

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

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

    
4259
	if (!platform_booting()) {
4260
		link_interface_to_vips($interface, "update");
4261

    
4262
		if ($tunnelif != 'gre') {
4263
			$gre = link_interface_to_tunnelif($interface, 'gre');
4264
			array_walk($gre, 'interface_gre_configure');
4265
		}
4266

    
4267
		if ($tunnelif != 'gif') {
4268
			$gif = link_interface_to_tunnelif($interface, 'gif');
4269
			array_walk($gif, 'interface_gif_configure');
4270
		}
4271

    
4272
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4273
			unset($bridgetmp);
4274
			$bridgetmp = link_interface_to_bridge($interface);
4275
			if (!empty($bridgetmp)) {
4276
				interface_bridge_add_member($bridgetmp, $realif);
4277
			}
4278
		}
4279

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

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

    
4290
		if ($reloadall == true) {
4291

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

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

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

    
4302
			if (config_path_enabled('unbound')) {
4303
				services_unbound_configure();
4304
			}
4305

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4399
	return 0;
4400
}
4401

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

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

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

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

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

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

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

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

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

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

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

    
4462
	return 0;
4463
}
4464

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

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

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

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

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

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

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

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

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

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

    
4521
	return 0;
4522
}
4523

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

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

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

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

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

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

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

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

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

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

    
4576

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

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

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

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

    
4615
	return 0;
4616
}
4617

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4727
	return 0;
4728
}
4729

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

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

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

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

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

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

    
4763
		$dhcp6cinterfaces[$interface] = $wancfg;
4764

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

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

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

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

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

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

    
4813
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4814
				$dhcp6cconf .= "\trequest domain-name;\n";
4815

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

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

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

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

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

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

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

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

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

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

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

    
4998
EOD;
4999

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

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

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

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

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

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

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

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

    
5127
	return 0;
5128
}
5129

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5256
	$key_info_statement = "";
5257
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5258
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5259
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5260
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5261
		$key_info_statement .= "keyinfo";
5262
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5263
		$key_info_statement .= " {\n";
5264
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5265
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5266
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5267
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
5268
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5269
		}
5270
		$key_info_statement .= "};\n";
5271
	}
5272

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

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

    
5281
	return $dhcp6cconf;
5282
}
5283

    
5284

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

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

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

    
5297

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

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

    
5302
	return $dhcp6cconf;
5303
}
5304

    
5305

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

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

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

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

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

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

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

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

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

    
5360
}
5361

    
5362
EOD;
5363

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

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

    
5378
EOD;
5379
	}
5380

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

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

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

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

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

    
5400
	return 0;
5401
}
5402

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

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

    
5410
	/* DHCP Protocol Timings */
5411
	$protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
5412
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5413
		$pt_variable = "{$Protocol_Timing}";
5414
		${$pt_variable} = "";
5415
		if ($ifcfg[$Protocol_Timing] != "") {
5416
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5417
		}
5418
	}
5419

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

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

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

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

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

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

    
5472
	return $dhclientconf;
5473
}
5474

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

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

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

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

    
5492

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

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

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

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

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

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

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

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

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

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

    
5545
	return $dhclientconf;
5546
}
5547

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

    
5553
	return;
5554
}
5555

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

    
5568
	return;
5569
}
5570

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

    
5578
	return false;
5579
}
5580

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5709
	return $ifdesc;
5710
}
5711

    
5712
function convert_real_interface_to_friendly_descr($interface) {
5713

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

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

    
5720
	return $interface;
5721
}
5722

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

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

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

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

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

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

    
5797
	return $parents;
5798
}
5799

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

    
5807
	$realif = get_parent_interface($interface);
5808

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

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

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

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

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

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

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

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

    
5862
	return $result;
5863
}
5864

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

    
5868
	$wanif = NULL;
5869

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

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

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

    
5974
	return $wanif;
5975
}
5976

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

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

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

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

    
5993
	return false;
5994
}
5995

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

    
6005
	$isv6ip = is_ipaddrv6($ip);
6006

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

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

    
6028
	return false;
6029
}
6030

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

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

    
6041
	$isv6ip = is_ipaddrv6($ip);
6042

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

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

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

    
6084
function interface_find_child_cfgmtu($realiface) {
6085
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6086
	$vlans = link_interface_to_vlans($realiface);
6087
	$qinqs = link_interface_to_qinqs($realiface);
6088
	$bridge = link_interface_to_bridge($realiface);
6089
	$gifs = link_interface_to_tunnelif($interface, 'gif');
6090
	$gres = link_interface_to_tunnelif($interface, 'gre');
6091

    
6092
	$mtu = 0;
6093
	if (is_array($vlans)) {
6094
		foreach ($vlans as $vlan) {
6095
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6096
			if (empty($ifass)) {
6097
				continue;
6098
			}
6099
			$vlanmtu = config_get_path("interfaces/{$ifass}/mtu");
6100
			if ($vlanmtu && (intval($vlanmtu) > $mtu)) {
6101
				$mtu = $vlanmtu;
6102
			}
6103
		}
6104
	}
6105
	if (is_array($qinqs)) {
6106
		foreach ($qinqs as $qinq) {
6107
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6108
			if (empty($ifass)) {
6109
				continue;
6110
			}
6111

    
6112
			$qinqmtu = config_get_path("interfaces/{$ifass}/mtu");
6113
			if ($qinqmtu && (intval($qinqmtu) > $mtu)) {
6114
				$mtu = $qinqmtu;
6115
			}
6116
		}
6117
	}
6118
	foreach ($gifs as $gif) {
6119
		$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6120
		if (empty($ifass)) {
6121
			continue;
6122
		}
6123

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

    
6148
	return $mtu;
6149
}
6150

    
6151
function link_interface_to_vlans($int, $action = "") {
6152
	if (empty($int)) {
6153
		return;
6154
	}
6155

    
6156
	$ifaces = array();
6157
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
6158
		if ($int == $vlan['if']) {
6159
			if ($action == "update") {
6160
				interfaces_bring_up($int);
6161
			} else {
6162
				$ifaces[$vlan['tag']] = $vlan;
6163
			}
6164
		}
6165
	}
6166
	if (!empty($ifaces)) {
6167
		return $ifaces;
6168
	}
6169
}
6170

    
6171
function link_interface_to_qinqs($int, $action = "") {
6172
	if (empty($int)) {
6173
		return;
6174
	}
6175

    
6176
	$ifaces = array();
6177
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
6178
		if ($int == $qinq['if']) {
6179
			if ($action == "update") {
6180
				interfaces_bring_up($int);
6181
			} else {
6182
				$ifaces[$qinq['tag']] = $qinq;
6183
			}
6184
		}
6185
	}
6186
	if (!empty($ifaces)) {
6187
		return $ifaces;
6188
	}
6189
}
6190

    
6191
function link_interface_to_vips($int, $action = "", $vhid = '') {
6192
	$updatevips = false;
6193

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

    
6218
	return NULL;
6219
}
6220

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

    
6237
function link_interface_to_lagg($int) {
6238
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
6239
		if (in_array($int, explode(',', $lagg['members']))) {
6240
			return "{$lagg['laggif']}";
6241
		}
6242
	}
6243
}
6244

    
6245
function link_interface_to_group($int) {
6246
	$result = array();
6247

    
6248
	foreach (config_get_path('ifgroups/ifgroupentry') as $group) {
6249
		if (in_array($int, explode(" ", $group['members']))) {
6250
			$result[$group['ifname']] = $int;
6251
		}
6252
	}
6253

    
6254
	return $result;
6255
}
6256

    
6257
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6258
	$result = array();
6259

    
6260
	if (empty($interface)) {
6261
		return $result;
6262
	}
6263

    
6264
	if (!in_array($type, array('gre', 'gif'))) {
6265
		return $result;
6266
	}
6267

    
6268
	foreach (config_get_path("{$type}s/{$type}", []) as $tunnel) {
6269
		if (($tunnel['if'] == $interface) &&
6270
			(($remote == 'any') ||
6271
			 (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6272
			 (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) { 
6273
			$result[] = $tunnel;
6274
		}
6275
	}
6276

    
6277
	return $result;
6278
}
6279

    
6280
function link_interface_to_ppp_tunnelif($interface) {
6281
	$result = array();
6282

    
6283
	if (empty($interface)) {
6284
		return $result;
6285
	}
6286

    
6287
	init_config_arr(array('ppps', 'ppp'));
6288
	$realif = get_real_interface($interface);
6289
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
6290
		if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) { 
6291
			$result[] = $ppp;
6292
		}
6293
	}
6294

    
6295
	return $result;
6296
}
6297

    
6298
/*
6299
 * find_interface_ip($interface): return the interface ip (first found)
6300
 */
6301
function find_interface_ip($interface, $flush = false) {
6302
	global $interface_ip_arr_cache;
6303
	global $interface_sn_arr_cache;
6304

    
6305
	$interface = str_replace("\n", "", $interface);
6306

    
6307
	if (!does_interface_exist($interface)) {
6308
		return;
6309
	}
6310

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

    
6332
	return $interface_ip_arr_cache[$interface];
6333
}
6334

    
6335
/*
6336
 * find_interface_ipv6($interface): return the interface ip (first found)
6337
 */
6338
function find_interface_ipv6($interface, $flush = false) {
6339
	global $interface_ipv6_arr_cache;
6340
	global $interface_snv6_arr_cache;
6341

    
6342
	$interface = trim($interface);
6343
	$interface = get_real_interface($interface);
6344

    
6345
	if (!does_interface_exist($interface)) {
6346
		return;
6347
	}
6348

    
6349
	/* Setup IP cache */
6350
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6351
		$ifinfo = get_interface_addresses($interface);
6352
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6353
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6354
	}
6355

    
6356
	return $interface_ipv6_arr_cache[$interface];
6357
}
6358

    
6359
/*
6360
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6361
 */
6362
function find_interface_ipv6_ll($interface, $flush = false) {
6363
	global $interface_llv6_arr_cache;
6364

    
6365
	$interface = str_replace("\n", "", $interface);
6366

    
6367
	if (!does_interface_exist($interface)) {
6368
		return;
6369
	}
6370

    
6371
	/* Setup IP cache */
6372
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6373
		$ifinfo = pfSense_getall_interface_addresses($interface);
6374
		foreach ($ifinfo as $line) {
6375
			if (strstr($line, ":")) {
6376
				$parts = explode("/", $line);
6377
				if (is_linklocal($parts[0])) {
6378
					$ifinfo['linklocal'] = $parts[0];
6379
				}
6380
			}
6381
		}
6382
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6383
	}
6384
	return $interface_llv6_arr_cache[$interface];
6385
}
6386

    
6387
function find_interface_subnet($interface, $flush = false) {
6388
	global $interface_sn_arr_cache;
6389
	global $interface_ip_arr_cache;
6390

    
6391
	$interface = str_replace("\n", "", $interface);
6392
	if (does_interface_exist($interface) == false) {
6393
		return;
6394
	}
6395

    
6396
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6397
		$ifinfo = get_interface_addresses($interface);
6398
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6399
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6400
	}
6401

    
6402
	return $interface_sn_arr_cache[$interface];
6403
}
6404

    
6405
function find_interface_subnetv6($interface, $flush = false) {
6406
	global $interface_snv6_arr_cache;
6407
	global $interface_ipv6_arr_cache;
6408

    
6409
	$interface = str_replace("\n", "", $interface);
6410
	if (does_interface_exist($interface) == false) {
6411
		return;
6412
	}
6413

    
6414
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6415
		$ifinfo = get_interface_addresses($interface);
6416
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6417
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6418
	}
6419

    
6420
	return $interface_snv6_arr_cache[$interface];
6421
}
6422

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

    
6441
	return false;
6442
}
6443

    
6444
function get_possible_listen_ips($include_ipv6_link_local=false) {
6445

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

    
6467
	$interfaces['lo0'] = 'Localhost';
6468

    
6469
	return $interfaces;
6470
}
6471

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

    
6483
	init_config_arr(array('ipsec', 'phase1'));
6484
	foreach (config_get_path('ipsec/phase1') as $p1) {
6485
		if ($p1['disabled']) {
6486
			continue;
6487
		}
6488
		if (ipsec_vti($p1)) {
6489
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6490
			if (!empty($vtiiflist)) {
6491
				$sourceips = array_merge($sourceips, $vtiiflist);
6492
			}
6493
		}
6494
	}
6495
	return $sourceips;
6496
}
6497

    
6498
function get_interface_ip($interface = "wan", $gateways_status = false) {
6499
	if (substr($interface, 0, 4) == '_vip') {
6500
		return get_configured_vip_ipv4($interface);
6501
	} elseif (substr($interface, 0, 5) == '_lloc') {
6502
		/* No link-local address for v4. */
6503
		return null;
6504
	}
6505

    
6506
	$realif = get_failover_interface($interface, 'inet', $gateways_status);
6507
	if (!$realif) {
6508
		return null;
6509
	}
6510

    
6511
	if (substr($realif, 0, 4) == '_vip') {
6512
		return get_configured_vip_ipv4($realif);
6513
	} elseif (substr($realif, 0, 5) == '_lloc') {
6514
		/* No link-local address for v4. */
6515
		return null;
6516
	}
6517

    
6518
	$iface = config_get_path("interfaces/{$interface}");
6519
	if (is_array($iface) && is_ipaddr($iface['ipaddr'])) {
6520
		return ($iface['ipaddr']);
6521
	}
6522

    
6523
	/*
6524
	 * Beaware that find_interface_ip() is our last option, it will
6525
	 * return the first IP it find on interface, not necessarily the
6526
	 * main IP address.
6527
	 */
6528
	$curip = find_interface_ip($realif);
6529
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6530
		return $curip;
6531
	} else {
6532
		return null;
6533
	}
6534
}
6535

    
6536
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false, $gateways_status = false) {
6537
	if (substr($interface, 0, 4) == '_vip') {
6538
		return get_configured_vip_ipv6($interface);
6539
	} elseif (substr($interface, 0, 5) == '_lloc') {
6540
		return get_interface_linklocal($interface);
6541
	}
6542

    
6543
	$realif = get_failover_interface($interface, 'inet6', $gateways_status);
6544
	if (!$realif) {
6545
		return null;
6546
	}
6547

    
6548
	if (substr($realif, 0, 4) == '_vip') {
6549
		return get_configured_vip_ipv6($realif);
6550
	} elseif (substr($realif, 0, 5) == '_lloc') {
6551
		return get_interface_linklocal($realif);
6552
	}
6553

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

    
6572
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6573
	$checkif = is_array($iface) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6574
	if (config_get_path("interfaces/{$checkif}/ipaddrv6", "") == 'track6') { 
6575
		$curip = get_interface_track6ip($checkif);
6576
		if ($curip) {
6577
			return $curip[0];
6578
		}
6579
	}
6580

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

    
6605
function get_interface_linklocal($interface = "wan") {
6606

    
6607
	$realif = get_failover_interface($interface, 'inet6');
6608
	if (!$realif) {
6609
		return null;
6610
	}
6611

    
6612
	if (substr($interface, 0, 4) == '_vip') {
6613
		$realif = get_real_interface($interface);
6614
	} elseif (substr($interface, 0, 5) == '_lloc') {
6615
		$realif = get_real_interface(substr($interface, 5));
6616
	}
6617

    
6618
	$curip = find_interface_ipv6_ll($realif);
6619
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6620
		return $curip;
6621
	} else {
6622
		return null;
6623
	}
6624
}
6625

    
6626
function get_interface_track6ip($interface = "wan") {
6627
	$realif = get_real_interface($interface);
6628
	$vips = get_configured_vip_list('inet6');
6629

    
6630
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6631
		list($ip, $bits) = explode("/", $ifaddr);
6632
		$ip = text_to_compressed_ip6($ip);
6633
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6634
			if (is_array($vips) && !empty($vips)) {
6635
				foreach ($vips as $vip) {
6636
					if ($ip == text_to_compressed_ip6($vip)) {
6637
						continue 2;
6638
					}
6639
				}
6640
			}
6641
			return array($ip, $bits);
6642
		}
6643
	}
6644
	return false;
6645
}
6646

    
6647
function get_interface_subnet($interface = "wan") {
6648
	if (substr($interface, 0, 4) == '_vip') {
6649
		return (get_configured_vip_subnetv4($interface));
6650
	}
6651

    
6652
	$iface = config_get_path("interfaces/{$interface}");
6653
	if (is_array($iface) && !empty($iface['subnet']) && is_ipaddrv4($iface['ipaddr'])) {
6654
		return ($iface['subnet']);
6655
	}
6656

    
6657
	$realif = get_real_interface($interface);
6658
	if (!$realif) {
6659
		return (NULL);
6660
	}
6661

    
6662
	$cursn = find_interface_subnet($realif);
6663
	if (!empty($cursn)) {
6664
		return ($cursn);
6665
	}
6666

    
6667
	return (NULL);
6668
}
6669

    
6670
function get_interface_subnetv6($interface = "wan") {
6671
	if (substr($interface, 0, 4) == '_vip') {
6672
		return (get_configured_vip_subnetv6($interface));
6673
	} elseif (substr($interface, 0, 5) == '_lloc') {
6674
		$interface = substr($interface, 5);
6675
	}
6676

    
6677
	$iface = config_get_path("interfaces/{$interface}");
6678
	if (is_array($iface) && !empty($iface['subnetv6']) && is_ipaddrv6($iface['ipaddrv6'])) {
6679
		return ($iface['subnetv6']);
6680
	}
6681

    
6682
	$realif = get_real_interface($interface, 'inet6');
6683
	if (!$realif) {
6684
		return (NULL);
6685
	}
6686

    
6687
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6688
	if (config_get_path("interfaces/{$interface}/ipaddrv6") == 'track6') {
6689
		$curip = get_interface_track6ip($interface);
6690
		if ($curip) {
6691
			return $curip[1];
6692
		}
6693
	}
6694

    
6695
	$cursn = find_interface_subnetv6($realif);
6696
	if (!empty($cursn)) {
6697
		return ($cursn);
6698
	}
6699

    
6700
	return (NULL);
6701
}
6702

    
6703
/* return outside interfaces with a gateway */
6704
function get_interfaces_with_gateway() {
6705

    
6706
	$ints = array();
6707

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

    
6727
				break;
6728
		}
6729
	}
6730
	return $ints;
6731
}
6732

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

    
6768
	return false;
6769
}
6770

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

    
6800
	return false;
6801
}
6802

    
6803
/****f* interfaces/is_altq_capable
6804
 * NAME
6805
 *   is_altq_capable - Test if interface is capable of using ALTQ
6806
 * INPUTS
6807
 *   $int            - string containing interface name
6808
 * RESULT
6809
 *   boolean         - true or false
6810
 ******/
6811

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

    
6827
	$int_family = remove_ifindex($int);
6828

    
6829
	if (in_array($int_family, $capable)) {
6830
		return true;
6831
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6832
		return true;
6833
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6834
		return true;
6835
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6836
		return true;
6837
	} else {
6838
		return false;
6839
	}
6840
}
6841

    
6842
/****f* interfaces/is_interface_wireless
6843
 * NAME
6844
 *   is_interface_wireless - Returns if an interface is wireless
6845
 * RESULT
6846
 *   $tmp       - Returns if an interface is wireless
6847
 ******/
6848
function is_interface_wireless($interface) {
6849
	global $g;
6850

    
6851
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6852
	if (config_get_path("interfaces/{$friendly}/wireless") === null) {
6853
		if (preg_match($g['wireless_regex'], $interface)) {
6854
			init_config_arr(['interfaces', $friendly, 'wireless']);
6855
			return true;
6856
		}
6857
		return false;
6858
	} else {
6859
		return true;
6860
	}
6861
}
6862

    
6863
function get_wireless_modes($interface) {
6864
	/* return wireless modes and channels */
6865
	$wireless_modes = array();
6866

    
6867
	$cloned_interface = get_real_interface($interface);
6868

    
6869
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6870
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6871
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6872
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6873

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

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

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

    
6916
		$interface_channels = [];
6917
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6918
		return $interface_channels;
6919
}
6920

    
6921
/* return wireless HT modes */
6922
function get_wireless_ht_modes($interface) {
6923
	$wireless_hts_supported = array(0 => gettext('Auto'));
6924

    
6925
	$cloned_interface = get_real_interface($interface);
6926

    
6927
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6928
		$interface_channels = get_wireless_channels($cloned_interface);
6929

    
6930
		foreach ($interface_channels as $channel) {
6931
			$channel_line = explode(",", $channel);
6932
			$wireless_ht = trim($channel_line[1]);
6933
			if (!empty($wireless_ht)) {
6934
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6935
			}
6936
		}
6937
	}
6938
	return($wireless_hts_supported);
6939
}
6940

    
6941
/* return wireless HT by channel/standard */
6942
function get_wireless_ht_list($interface) {
6943
	$wireless_hts = array();
6944

    
6945
	$cloned_interface = get_real_interface($interface);
6946

    
6947
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6948
		$interface_channels = get_wireless_channels($cloned_interface);
6949
		$interface_channel_count = count($interface_channels);
6950

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

    
6977
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6978
function get_wireless_channel_info($interface) {
6979
	$wireless_channels = array();
6980

    
6981
	$cloned_interface = get_real_interface($interface);
6982

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

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

    
6991
		foreach ($interface_channels as $channel_line) {
6992
			$channel_line = explode(",", $channel_line);
6993
			if (!isset($wireless_channels[$channel_line[0]])) {
6994
				$wireless_channels[$channel_line[0]] = $channel_line;
6995
			}
6996
		}
6997
	}
6998
	return($wireless_channels);
6999
}
7000

    
7001
function set_interface_mtu($interface, $mtu) {
7002

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

    
7018
/****f* interfaces/get_interface_mtu
7019
 * NAME
7020
 *   get_interface_mtu - Return the mtu of an interface
7021
 * RESULT
7022
 *   $tmp       - Returns the mtu of an interface
7023
 ******/
7024
function get_interface_mtu($interface) {
7025
	$mtu = pfSense_interface_getmtu($interface);
7026
	return $mtu['mtu'];
7027
}
7028

    
7029
function get_interface_mac($interface) {
7030
	$macinfo = get_interface_addresses($interface);
7031
	return $macinfo["macaddr"];
7032
}
7033

    
7034
function get_interface_vendor_mac($interface) {
7035
	global $g;
7036

    
7037
	$macinfo = get_interface_addresses($interface);
7038
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7039
	    "00:00:00:00:00:00") {
7040
		return ($macinfo["hwaddr"]);
7041
	}
7042

    
7043
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7044
	if (file_exists($hwaddr_file)) {
7045
		$macaddr = trim(file_get_contents($hwaddr_file));
7046
		if (is_macaddr($macaddr)) {
7047
			return ($macaddr);
7048
		}
7049
	} elseif (is_macaddr($macinfo['macaddr'])) {
7050
		/* Save original macaddress to be restored when necessary */
7051
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7052
	}
7053

    
7054
	return (NULL);
7055
}
7056

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

    
7073
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7074
	global $g;
7075

    
7076
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7077

    
7078
	if (!empty($iface) && !empty($pppif)) {
7079
		$cron_cmd = <<<EOD
7080
#!/bin/sh
7081
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7082
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7083

    
7084
EOD;
7085

    
7086
		@file_put_contents($cron_file, $cron_cmd);
7087
		chmod($cron_file, 0755);
7088
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7089
	} else {
7090
		unlink_if_exists($cron_file);
7091
	}
7092
}
7093

    
7094
function get_interface_default_mtu($type = "ethernet") {
7095
	switch ($type) {
7096
		case "gre":
7097
			return 1476;
7098
			break;
7099
		case "gif":
7100
			return 1280;
7101
			break;
7102
		case "tun":
7103
		case "vlan":
7104
		case "tap":
7105
		case "ethernet":
7106
		default:
7107
			return 1500;
7108
			break;
7109
	}
7110

    
7111
	/* Never reached */
7112
	return 1500;
7113
}
7114

    
7115
function get_vip_descr($ipaddress) {
7116

    
7117
	foreach (config_get_path('virtualip/vip', []) as $vip) {
7118
		if ($vip['subnet'] == $ipaddress) {
7119
			return ($vip['descr']);
7120
		}
7121
	}
7122
	return "";
7123
}
7124

    
7125
function interfaces_staticarp_configure($if) {
7126
	if (config_get_path('system/developerspew')) {
7127
		$mt = microtime();
7128
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7129
	}
7130

    
7131
	$ifcfg = config_get_path("interfaces/{$if}");
7132

    
7133
	if (!$ifcfg['if'] || !$ifcfg['enable']) {
7134
		return 0;
7135
	}
7136

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

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

    
7166
	return 0;
7167
}
7168

    
7169
function get_failover_interface($interface, $family = "all", $gateways_status = false) {
7170
	/* shortcut to get_real_interface if we find it in the config */
7171
	if (is_array(config_get_path("interfaces/{$interface}"))) {
7172
		return get_real_interface($interface, $family);
7173
	}
7174

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

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

    
7212
	if ($family == 6) {
7213
		$dhcp_string = "_DHCP6";
7214
	} else {
7215
		$dhcp_string = "_DHCP";
7216
	}
7217

    
7218
	foreach (config_get_path('gateways/gateway_group', []) as $group) {
7219
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7220
			continue;
7221
		}
7222
		foreach ($group['item'] as $item) {
7223
			$item_data = explode("|", $item);
7224
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7225
				return true;
7226
			}
7227
		}
7228
	}
7229

    
7230
	return false;
7231
}
7232

    
7233
function remove_ifindex($ifname) {
7234
	return preg_replace("/[0-9]+$/", "", $ifname);
7235
}
7236

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

    
7240
	$viplist = get_configured_vip_list($family, $type);
7241
	foreach ($viplist as $vipid => $address) {
7242
		$interfaces[$vipid] = $address;
7243
		if ($type = VIP_CARP) {
7244
			$vip = get_configured_vip($vipid);
7245
			if (isset($vip) && is_array($vip) ) {
7246
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7247
			}
7248
		}
7249
		if (get_vip_descr($address)) {
7250
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7251
		}
7252
	}
7253
	return $interfaces;
7254
}
7255

    
7256
function return_gateway_groups_array_with_descr() {
7257
	$interfaces = array();
7258
	$grouplist = return_gateway_groups_array();
7259
	foreach (array_keys($grouplist) as $name) {
7260
		$interfaces[$name] = "GW Group {$name}";
7261
	}
7262
	return $interfaces;
7263
}
7264

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

    
7279
function get_interface_ports() {
7280
	$linklist = array();
7281
	$portlist = get_interface_list();
7282

    
7283
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
7284
		if (empty($vlan)) {
7285
			continue;
7286
		}
7287
		$portlist[$vlan['vlanif']] = $vlan;
7288
	}
7289

    
7290
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
7291
		if (empty($qinq)) {
7292
			continue;
7293
		}
7294
		$members = explode(" ", $qinq['members']);
7295
		foreach ($members as $mem) {
7296
			$qentry = $qinq['vlanif'] . "." . $mem;
7297
			$portlist[$qentry] = $qentry;
7298
		}
7299
	}
7300

    
7301
	foreach ($portlist as $ifn => $ifinfo) {
7302
		$string = "";
7303
		if (is_array($ifinfo)) {
7304
			$string .= $ifn;
7305
			if ($ifinfo['mac']) {
7306
				$string .= " ({$ifinfo['mac']})";
7307
			}
7308
			if ($ifinfo['friendly']) {
7309
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7310
			} elseif ($ifinfo['descr']) {
7311
				$string .= " - {$ifinfo['descr']}";
7312
			}
7313
		} else {
7314
			$string .= $ifinfo;
7315
		}
7316

    
7317
		$linklist[$ifn] = $string;
7318
	}
7319
	return $linklist;
7320
}
7321

    
7322
function build_ppps_link_list() {
7323
	global $pconfig;
7324

    
7325
	$linklist = array('list' => array(), 'selected' => array());
7326

    
7327
	if ($pconfig['type'] == 'ppp') {
7328
		$linklist['list'] = get_serial_ports();
7329
	} else {
7330
		$iflist = get_interface_ports();
7331

    
7332
		$viplist = array();
7333
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7334
		foreach ($carplist as $vid => $vaddr) {
7335
			$vip = get_configured_vip($vid);
7336
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7337
		}
7338

    
7339
		$linklist['list'] = array_merge($iflist, $viplist);
7340

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

    
7354
	$selected_ports = array();
7355
	if (is_array($pconfig['interfaces'])) {
7356
		$selected_ports = $pconfig['interfaces'];
7357
	} elseif (!empty($pconfig['interfaces'])) {
7358
		$selected_ports = explode(',', $pconfig['interfaces']);
7359
	}
7360
	foreach ($selected_ports as $port) {
7361
		if (isset($linklist['list'][$port])) {
7362
			array_push($linklist['selected'], $port);
7363
		}
7364
	}
7365
	return($linklist);
7366
}
7367

    
7368
function create_interface_list($open = false) {
7369
	$iflist = array();
7370

    
7371
	// add group interfaces
7372
	config_get_path('ifgroups/ifgroupentry', []);
7373
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7374
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7375
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7376
		}
7377
	}
7378

    
7379
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7380
		if ($open || have_ruleint_access($ifent)) {
7381
			$iflist[$ifent] = $ifdesc;
7382
		}
7383
	}
7384

    
7385
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7386
		$iflist['l2tp'] = gettext('L2TP VPN');
7387
	}
7388

    
7389
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7390
		$iflist['pppoe'] = gettext("PPPoE Server");
7391
	}
7392

    
7393
	// add ipsec interfaces
7394
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7395
		$iflist["enc0"] = gettext("IPsec");
7396
	}
7397

    
7398
	// add openvpn/tun interfaces
7399
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7400
		$iflist["openvpn"] = gettext("OpenVPN");
7401
	}
7402

    
7403
	return($iflist);
7404
}
7405

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

    
7428
function is_stf_interface($inf) {
7429
	switch (config_get_path("interfaces/{$inf}/ipaddrv6")) {
7430
		case '6rd':
7431
		case '6to4':
7432
			return true;
7433
		default:
7434
			return false;
7435
	}
7436
}
7437

    
7438
function restart_interface_services($interface, $ipv6type = "") {
7439

    
7440
	services_unbound_configure(true, $interface);
7441

    
7442
	services_igmpproxy_configure($interface);
7443
	services_snmpd_configure($interface);
7444
	vpn_l2tp_configure($interface);
7445

    
7446
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7447
		openvpn_resync_all($interface);
7448
	}
7449
	ipsec_force_reload($interface);
7450

    
7451
	/* restart RADVD to announce correct IPv6 prefix
7452
	 * see https://redmine.pfsense.org/issues/12604 */ 
7453
	if ((($ipv6type == "staticv6") || ($ipv6type == "track6")) &&
7454
	    (config_get_path("dhcpdv6/{$interface}/ramode", "disabled") != "disabled")) {
7455
		services_radvd_configure();
7456
	}
7457

    
7458
	if (config_path_enabled("dhcpd/{$interface}") ||
7459
	    config_path_enabled("dhcpdv6/{$interface}")) {
7460
		services_dhcpd_configure();
7461
	}
7462

    
7463
	init_config_arr(array('syslog'));
7464
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7465
		system_syslogd_start();
7466
	}
7467
}
7468

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

    
7510
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7511
		$vip = get_configured_vip($viface);
7512
		if (is_ipaddrv4($vip['subnet'])) {
7513
			array_push($v4vips, $vip['subnet']);
7514
		} else if (is_ipaddrv6($vip['subnet'])) {
7515
			array_push($v6vips, $vip['subnet']);
7516
		}
7517
	}
7518

    
7519
	if ($ifaddrs['addrs']) {
7520
	   $v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7521
		  return (array_search($addr['addr'], $v4vips) === false);
7522
	   });
7523
	}
7524

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

    
7541
	if ($v6addrs) {
7542
		$v6addr = array_pop($v6addrs);
7543
		$ifaddrs['ipaddr6'] = $v6addr['addr'];
7544
		foreach(array("subnetbits", "tunnel") as $key) {
7545
			if (array_key_exists($key, $v6addr)) {
7546
				$ifaddrs[$key.'6'] = $v6addr[$key];
7547
			}
7548
		}
7549
		if (array_key_exists('tentative', $v6addr)) {
7550
			$ifaddrs['tentative'] = $v6addr['tentative'];
7551
		}
7552
	}
7553
	unset($ifaddrs['addrs']);
7554
	unset($ifaddrs['addrs6']);
7555

    
7556
	return($ifaddrs);
7557
}
7558
?>
(23-23/62)