Project

General

Profile

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

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

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

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

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

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

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

    
64
	return true;
65
}
66

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

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

    
78
	return $interface_arr_cache;
79
}
80

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

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

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

    
107

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

    
123
	$ifacedata = pfSense_getall_interface_addresses($realif);
124

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

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

    
141
	return false;
142
}
143

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

    
158
function vlan_valid_tag($tag = NULL) {
159

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

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

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

    
180
        return (false);
181
}
182

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

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

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

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

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

    
219
	return (NULL);
220
}
221

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

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

    
234
	return (false);
235
}
236

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

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

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

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

    
264
	return (NULL);
265
}
266

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

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

    
280
	$current_mac = get_interface_mac($interface);
281

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

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

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

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

    
340
	return (FALSE);
341
}
342

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

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

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

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

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

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

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

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

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

    
414
	interfaces_bring_up($vlanif);
415

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

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

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

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

    
436
	return $vlanif;
437
}
438

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

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

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

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

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

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

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

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

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

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

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

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

    
529
	return $vlanif;
530
}
531

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

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

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

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

    
576
	return $vlanif;
577
}
578

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
716
	$checklist = get_configured_interface_list();
717

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

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

    
739
	interface_bridge_configure_advanced($bridge);
740

    
741
	interface_bridge_configure_ip6linklocal($bridge);
742

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1028
	interfaces_bring_up($laggif);
1029

    
1030
	return $laggif;
1031
}
1032

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

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

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

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

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

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

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

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

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

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

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

    
1115
	interfaces_bring_up($greif);
1116

    
1117
	return $greif;
1118
}
1119

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1284

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

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

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

    
1301
	interfaces_bring_up($gifif);
1302

    
1303
	return $gifif;
1304
}
1305

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1569
	interfaces_qinq_configure(false);
1570

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

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

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

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

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

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

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

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

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

    
1648
		interface_configure($if, $reload);
1649

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

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

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

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

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

    
1672
		interface_configure($if, $reload);
1673

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

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

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

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

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

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

    
1708
		interface_configure($if, $reload);
1709

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

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

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

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

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

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

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

    
1740
	return 0;
1741
}
1742

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1983
	return;
1984
}
1985

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

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

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

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

    
2018
	return false;
2019
}
2020

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

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

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

    
2050
	return false;
2051
}
2052

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

    
2059
	return $ptpid;
2060
}
2061

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

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

    
2072
	return NULL;
2073
}
2074

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

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

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

    
2087
	$itemhash = getMPDCRONSettings($pppif);
2088

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2380
EOD;
2381

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

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

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

    
2404
EOD;
2405
	}
2406

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

    
2411
EOD;
2412

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

    
2417
EOD;
2418
	}
2419

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

    
2440
EOD;
2441
	}
2442

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

    
2451
EOD;
2452

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

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

    
2463
EOD;
2464
	}
2465

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

    
2471
EOD;
2472
	}
2473

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

    
2478
EOD;
2479
	}
2480

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

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

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

    
2496
EOD;
2497
		}
2498

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

    
2503
EOD;
2504
		}
2505

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

    
2510
EOD;
2511
		}
2512

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

    
2518
EOD;
2519

    
2520

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

    
2525
EOD;
2526
		}
2527

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

    
2543
EOD;
2544
		}
2545

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

    
2552
EOD;
2553
		}
2554

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

    
2559
EOD;
2560
		}
2561

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

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

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

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

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

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

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

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

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

    
2634
EOD;
2635
		}
2636

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

    
2642
EOD;
2643
		}
2644

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

    
2650
EOD;
2651
		}
2652

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

    
2656

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

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

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

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

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

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

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

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

    
2763
	return 1;
2764
}
2765

    
2766
function interfaces_sync_setup() {
2767

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3106
	return $realif;
3107
}
3108

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3521
EOD;
3522

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

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

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

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

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

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

    
3557
EOD;
3558
						}
3559
					}
3560
				}
3561

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

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

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

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

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

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

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

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

    
3618
	fclose($fd_set);
3619

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3722
	unset($wlcmd_args, $wlcmd);
3723

    
3724

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

    
3729
	return 0;
3730

    
3731
}
3732

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

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

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

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

    
3752
	return intval($pid);
3753
}
3754

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

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

    
3770
	unlink_if_exists(g_get('vardb_path') . "/{$interface}_cacheip");
3771
}
3772

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

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

    
3782
	return intval($pid);
3783
}
3784

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

    
3788
	$i = 0;
3789

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

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

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

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

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

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

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

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

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

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

    
3843
	$pid = find_dhcp6c_process();
3844

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

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

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

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

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

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

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

    
3926
function interface_vlan_mtu_configured($iface) {
3927

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

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

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

    
3945
	return $mtu;
3946
}
3947

    
3948
function interface_mtu_wanted_for_pppoe($realif) {
3949

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

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

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

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

    
3984
	return $mtu;
3985
}
3986

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

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

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

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

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

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

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

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

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

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

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

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

    
4073
		interface_set_macaddr($realhwif, $mac_addr);
4074

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

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

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

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

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

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

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

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

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

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

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

    
4179
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4180

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

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

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

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

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

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

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

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

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

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

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

    
4300
		if ($reloadall == true) {
4301

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4409
	return 0;
4410
}
4411

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

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

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

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

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

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

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

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

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

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

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

    
4472
	return 0;
4473
}
4474

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

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

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

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

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

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

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

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

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

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

    
4531
	return 0;
4532
}
4533

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

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

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

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

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

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

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

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

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

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

    
4586

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

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

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

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

    
4625
	return 0;
4626
}
4627

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4737
	return 0;
4738
}
4739

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

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

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

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

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

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

    
4774
		$dhcp6cinterfaces[$interface] = $wancfg;
4775

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

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

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

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

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

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

    
4824
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4825
				$dhcp6cconf .= "\trequest domain-name;\n";
4826

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

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

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

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

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

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

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

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

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

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

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

    
5008
EOD;
5009

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

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

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

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

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

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

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

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

    
5136
	return 0;
5137
}
5138

    
5139
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5140
	global $g;
5141

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

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

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

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

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

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

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

    
5203
		$id_assoc_statement_address .= "};\n";
5204
	}
5205

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

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

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

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

    
5246
		$id_assoc_statement_prefix .= "};\n";
5247
	}
5248

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

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

    
5282
	$dhcp6cconf  = $interface_statement;
5283
	$dhcp6cconf .= $id_assoc_statement_address;
5284
	$dhcp6cconf .= $id_assoc_statement_prefix;
5285
	$dhcp6cconf .= $authentication_statement;
5286
	$dhcp6cconf .= $key_info_statement;
5287

    
5288
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5289

    
5290
	return $dhcp6cconf;
5291
}
5292

    
5293

    
5294
function DHCP6_Config_File_Override($wancfg, $wanif) {
5295

    
5296
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5297

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

    
5306

    
5307
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5308

    
5309
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5310

    
5311
	return $dhcp6cconf;
5312
}
5313

    
5314

    
5315
function interface_dhcp_configure($interface) {
5316
	global $g, $vlanprio_values;
5317

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

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

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

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

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

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

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

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

    
5369
}
5370

    
5371
EOD;
5372

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

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

    
5387
EOD;
5388
	}
5389

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

    
5395
	fwrite($fd, $dhclientconf);
5396
	fclose($fd);
5397

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

    
5403
	/* Make sure dhclient is not running */
5404
	kill_dhclient_process($realif);
5405

    
5406
	/* fire up dhclient */
5407
	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");
5408

    
5409
	return 0;
5410
}
5411

    
5412
function DHCP_Config_File_Advanced($ifcfg, $realif) {
5413

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

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

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

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

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

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

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

    
5479
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5480

    
5481
	return $dhclientconf;
5482
}
5483

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

    
5489
function DHCP_Config_File_Override($ifcfg, $realif) {
5490

    
5491
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5492

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

    
5501

    
5502
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5503

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

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

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

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

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

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

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

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

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

    
5554
	return $dhclientconf;
5555
}
5556

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

    
5562
	return;
5563
}
5564

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

    
5577
	return;
5578
}
5579

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

    
5587
	return false;
5588
}
5589

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

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

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

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

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

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

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

    
5627
		if (get_real_interface($if) == $interface) {
5628
			return $if;
5629
		}
5630

    
5631
		if ($checkparent == false) {
5632
			continue;
5633
		}
5634

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

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

    
5650
/* attempt to resolve interface to friendly descr */
5651
function convert_friendly_interface_to_friendly_descr($interface) {
5652

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

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

    
5718
	return $ifdesc;
5719
}
5720

    
5721
function convert_real_interface_to_friendly_descr($interface) {
5722

    
5723
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5724

    
5725
	if (!empty($ifdesc)) {
5726
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5727
	}
5728

    
5729
	return $interface;
5730
}
5731

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

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

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

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

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

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

    
5806
	return $parents;
5807
}
5808

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

    
5816
	$realif = get_parent_interface($interface);
5817

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

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

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

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

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

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

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

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

    
5871
	return $result;
5872
}
5873

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

    
5877
	$wanif = NULL;
5878

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

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

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

    
5983
	return $wanif;
5984
}
5985

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

    
5989
	if (!is_ipaddr($ipaddress)) {
5990
		return false;
5991
	}
5992

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

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

    
6002
	return false;
6003
}
6004

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

    
6014
	$isv6ip = is_ipaddrv6($ip);
6015

    
6016
	/* if list */
6017
	$ifdescrs = get_configured_interface_list();
6018

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

    
6037
	return false;
6038
}
6039

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

    
6046
	if (!is_ipaddr($ip)) {
6047
		return false;
6048
	}
6049

    
6050
	$isv6ip = is_ipaddrv6($ip);
6051

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

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

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

    
6093
function interface_find_child_cfgmtu($realiface) {
6094
	$vlans = link_interface_to_vlans($realiface);
6095
	$qinqs = link_interface_to_qinqs($realiface);
6096
	$bridge = link_interface_to_bridge($realiface);
6097
	$mtu = 0;
6098

    
6099
	foreach ([$vlans, $qinqs, ['bridge' => $bridge]] as $ints) {
6100
		if (is_array($ints)) {
6101
			foreach ($ints as $int) {
6102
				$ifass = convert_real_interface_to_friendly_interface_name($int['vlanif']);
6103
				if (!empty($ifass) &&
6104
				    config_path_enabled("interfaces/{$ifass}") &&
6105
				    (intval(config_get_path("interfaces/{$ifass}/mtu")) > $mtu)) {
6106
					$mtu = config_get_path("interfaces/{$ifass}/mtu");
6107
				}
6108
			}
6109
		}
6110
	}
6111

    
6112
	unset($vlans, $qinqs, $bridge);
6113
	return $mtu;
6114
}
6115

    
6116
function link_interface_to_vlans($int, $action = "") {
6117
	if (empty($int)) {
6118
		return;
6119
	}
6120

    
6121
	$ifaces = array();
6122
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
6123
		if ($int == $vlan['if']) {
6124
			if ($action == "update") {
6125
				interfaces_bring_up($int);
6126
			} else {
6127
				$ifaces[$vlan['tag']] = $vlan;
6128
			}
6129
		}
6130
	}
6131
	if (!empty($ifaces)) {
6132
		return $ifaces;
6133
	}
6134
}
6135

    
6136
function link_interface_to_qinqs($int, $action = "") {
6137
	if (empty($int)) {
6138
		return;
6139
	}
6140

    
6141
	$ifaces = array();
6142
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
6143
		if ($int == $qinq['if']) {
6144
			if ($action == "update") {
6145
				interfaces_bring_up($int);
6146
			} else {
6147
				$ifaces[$qinq['tag']] = $qinq;
6148
			}
6149
		}
6150
	}
6151
	if (!empty($ifaces)) {
6152
		return $ifaces;
6153
	}
6154
}
6155

    
6156
function link_interface_to_vips($int, $action = "", $vhid = '') {
6157
	$updatevips = false;
6158

    
6159
	$result = array();
6160
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6161
		if (substr($vip['interface'], 0, 4) == "_vip") {
6162
			$iface = get_configured_vip_interface($vip['interface']);
6163
		} else {
6164
			$iface = $vip['interface'];
6165
		}
6166
		if ($int != $iface) {
6167
			continue;
6168
		}
6169
		if ($action == "update") {
6170
			$updatevips = true;
6171
		} else {
6172
			if (empty($vhid) || ($vhid == $vip['vhid']) ||
6173
				substr($vip['interface'], 0, 4) == "_vip") {
6174
				$result[] = $vip;
6175
			}
6176
		}
6177
	}
6178
	if ($updatevips === true) {
6179
		interfaces_vips_configure($int);
6180
	}
6181
	return $result;
6182

    
6183
	return NULL;
6184
}
6185

    
6186
/****f* interfaces/link_interface_to_bridge
6187
 * NAME
6188
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6189
 * INPUTS
6190
 *   $ip
6191
 * RESULT
6192
 *   bridge[0-99]
6193
 ******/
6194
function link_interface_to_bridge($int) {
6195
	foreach (config_get_path('bridges/bridged', []) as $bridge) {
6196
		if (in_array($int, explode(',', $bridge['members']))) {
6197
			return "{$bridge['bridgeif']}";
6198
		}
6199
	}
6200
}
6201

    
6202
function link_interface_to_lagg($int) {
6203
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
6204
		if (in_array($int, explode(',', $lagg['members']))) {
6205
			return "{$lagg['laggif']}";
6206
		}
6207
	}
6208
}
6209

    
6210
function link_interface_to_group($int) {
6211
	$result = array();
6212

    
6213
	foreach (config_get_path('ifgroups/ifgroupentry') as $group) {
6214
		if (in_array($int, explode(" ", $group['members']))) {
6215
			$result[$group['ifname']] = $int;
6216
		}
6217
	}
6218

    
6219
	return $result;
6220
}
6221

    
6222
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6223
	$result = array();
6224

    
6225
	if (empty($interface)) {
6226
		return $result;
6227
	}
6228

    
6229
	if (!in_array($type, array('gre', 'gif'))) {
6230
		return $result;
6231
	}
6232

    
6233
	foreach (config_get_path("{$type}s/{$type}", []) as $tunnel) {
6234
		if (($tunnel['if'] == $interface) &&
6235
			(($remote == 'any') ||
6236
			 (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6237
			 (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) {
6238
			$result[] = $tunnel;
6239
		}
6240
	}
6241

    
6242
	return $result;
6243
}
6244

    
6245
function link_interface_to_ppp_tunnelif($interface) {
6246
	$result = array();
6247

    
6248
	if (empty($interface)) {
6249
		return $result;
6250
	}
6251

    
6252
	init_config_arr(array('ppps', 'ppp'));
6253
	$realif = get_real_interface($interface);
6254
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
6255
		if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) {
6256
			$result[] = $ppp;
6257
		}
6258
	}
6259

    
6260
	return $result;
6261
}
6262

    
6263
/*
6264
 * find_interface_ip($interface): return the interface ip (first found)
6265
 */
6266
function find_interface_ip($interface, $flush = false) {
6267
	global $interface_ip_arr_cache;
6268
	global $interface_sn_arr_cache;
6269

    
6270
	$interface = str_replace("\n", "", $interface);
6271

    
6272
	if (!does_interface_exist($interface)) {
6273
		return;
6274
	}
6275

    
6276
	/* Setup IP cache */
6277
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6278
		if (file_exists("/var/db/${interface}_ip")) {
6279
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6280
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6281
			foreach ($ifaddrs as $ifaddr) {
6282
				list($ip, $mask) = explode("/", $ifaddr);
6283
				if ($ip == $ifip) {
6284
					$interface_ip_arr_cache[$interface] = $ip;
6285
					$interface_sn_arr_cache[$interface] = $mask;
6286
					break;
6287
				}
6288
			}
6289
		}
6290
		if (!isset($interface_ip_arr_cache[$interface])) {
6291
			$ifinfo = get_interface_addresses($interface);
6292
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6293
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6294
		}
6295
	}
6296

    
6297
	return $interface_ip_arr_cache[$interface];
6298
}
6299

    
6300
/*
6301
 * find_interface_ipv6($interface): return the interface ip (first found)
6302
 */
6303
function find_interface_ipv6($interface, $flush = false) {
6304
	global $interface_ipv6_arr_cache;
6305
	global $interface_snv6_arr_cache;
6306

    
6307
	$interface = trim($interface);
6308
	$interface = get_real_interface($interface);
6309

    
6310
	if (!does_interface_exist($interface)) {
6311
		return;
6312
	}
6313

    
6314
	/* Setup IP cache */
6315
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6316
		$ifinfo = get_interface_addresses($interface);
6317
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6318
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6319
	}
6320

    
6321
	return $interface_ipv6_arr_cache[$interface];
6322
}
6323

    
6324
/*
6325
 * Return the interface ipv6 link local address
6326
 */
6327
function find_interface_ipv6_ll($interface, $flush = false, $usefirst = true) {
6328
	global $interface_llv6_arr_cache;
6329

    
6330
	$interface = str_replace("\n", "", $interface);
6331

    
6332
	if (!does_interface_exist($interface)) {
6333
		return;
6334
	}
6335

    
6336
	/* Setup IP cache */
6337
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6338
		$ifinfo = pfSense_getall_interface_addresses($interface);
6339
		foreach ($ifinfo as $line) {
6340
			if (strstr($line, ":")) {
6341
				$parts = explode("/", $line);
6342
				if (is_linklocal($parts[0])) {
6343
					$ifinfo['linklocal'] = $parts[0];
6344
					if ($usefirst) {
6345
						break;
6346
					}
6347
				}
6348
			}
6349
		}
6350
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6351
	}
6352
	return $interface_llv6_arr_cache[$interface];
6353
}
6354

    
6355
function find_interface_subnet($interface, $flush = false) {
6356
	global $interface_sn_arr_cache;
6357
	global $interface_ip_arr_cache;
6358

    
6359
	$interface = str_replace("\n", "", $interface);
6360
	if (does_interface_exist($interface) == false) {
6361
		return;
6362
	}
6363

    
6364
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6365
		$ifinfo = get_interface_addresses($interface);
6366
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6367
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6368
	}
6369

    
6370
	return $interface_sn_arr_cache[$interface];
6371
}
6372

    
6373
function find_interface_subnetv6($interface, $flush = false) {
6374
	global $interface_snv6_arr_cache;
6375
	global $interface_ipv6_arr_cache;
6376

    
6377
	$interface = str_replace("\n", "", $interface);
6378
	if (does_interface_exist($interface) == false) {
6379
		return;
6380
	}
6381

    
6382
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6383
		$ifinfo = get_interface_addresses($interface);
6384
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6385
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6386
	}
6387

    
6388
	return $interface_snv6_arr_cache[$interface];
6389
}
6390

    
6391
function ip_in_interface_alias_subnet($interface, $ipalias) {
6392
	if (empty($interface) || !is_ipaddr($ipalias)) {
6393
		return false;
6394
	}
6395
	foreach (config_get_path('virtualip/vip',[]) as $vip) {
6396
		switch ($vip['mode']) {
6397
		case "ipalias":
6398
			if ($vip['interface'] <> $interface) {
6399
				break;
6400
			}
6401
			$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6402
			if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6403
				return true;
6404
			}
6405
			break;
6406
		}
6407
	}
6408

    
6409
	return false;
6410
}
6411

    
6412
function get_possible_listen_ips($include_ipv6_link_local=false) {
6413

    
6414
	$interfaces = get_configured_interface_with_descr();
6415
	foreach ($interfaces as $iface => $ifacename) {
6416
		if ($include_ipv6_link_local) {
6417
			/* This is to avoid going though added ll below */
6418
			if (substr($iface, 0, 5) == '_lloc') {
6419
				continue;
6420
			}
6421
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6422
			if (!empty($llip)) {
6423
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6424
			}
6425
		}
6426
	}
6427
	$viplist = get_configured_vip_list();
6428
	foreach ($viplist as $vip => $address) {
6429
		$interfaces[$vip] = $address;
6430
		if (get_vip_descr($address)) {
6431
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6432
		}
6433
	}
6434

    
6435
	$interfaces['lo0'] = 'Localhost';
6436

    
6437
	return $interfaces;
6438
}
6439

    
6440
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6441
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6442
	foreach (array('server', 'client') as $mode) {
6443
		foreach (config_get_path("openvpn/openvpn-{$mode}", []) as $setting) {
6444
			if (!isset($setting['disable'])) {
6445
				$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6446
				$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6447
			}
6448
		}
6449
	}
6450

    
6451
	init_config_arr(array('ipsec', 'phase1'));
6452
	foreach (config_get_path('ipsec/phase1') as $p1) {
6453
		if ($p1['disabled']) {
6454
			continue;
6455
		}
6456
		if (ipsec_vti($p1)) {
6457
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6458
			if (!empty($vtiiflist)) {
6459
				$sourceips = array_merge($sourceips, $vtiiflist);
6460
			}
6461
		}
6462
	}
6463
	return $sourceips;
6464
}
6465

    
6466
function get_interface_ip($interface = "wan", $gateways_status = false) {
6467
	if (substr($interface, 0, 4) == '_vip') {
6468
		return get_configured_vip_ipv4($interface);
6469
	} elseif (substr($interface, 0, 5) == '_lloc') {
6470
		/* No link-local address for v4. */
6471
		return null;
6472
	}
6473

    
6474
	$realif = get_failover_interface($interface, 'inet', $gateways_status);
6475
	if (!$realif) {
6476
		return null;
6477
	}
6478

    
6479
	if (substr($realif, 0, 4) == '_vip') {
6480
		return get_configured_vip_ipv4($realif);
6481
	} elseif (substr($realif, 0, 5) == '_lloc') {
6482
		/* No link-local address for v4. */
6483
		return null;
6484
	}
6485

    
6486
	$iface = config_get_path("interfaces/{$interface}");
6487
	if (is_array($iface) && is_ipaddr($iface['ipaddr'])) {
6488
		return ($iface['ipaddr']);
6489
	}
6490

    
6491
	/*
6492
	 * Beware that find_interface_ip() is our last option, it will
6493
	 * return the first IP it find on interface, not necessarily the
6494
	 * main IP address.
6495
	 */
6496
	$curip = find_interface_ip($realif);
6497
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6498
		return $curip;
6499
	} else {
6500
		return null;
6501
	}
6502
}
6503

    
6504
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false, $gateways_status = false) {
6505
	if (substr($interface, 0, 4) == '_vip') {
6506
		return get_configured_vip_ipv6($interface);
6507
	} elseif (substr($interface, 0, 5) == '_lloc') {
6508
		return get_interface_linklocal($interface);
6509
	}
6510

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

    
6516
	if (substr($realif, 0, 4) == '_vip') {
6517
		return get_configured_vip_ipv6($realif);
6518
	} elseif (substr($realif, 0, 5) == '_lloc') {
6519
		return get_interface_linklocal($realif);
6520
	}
6521

    
6522
	$iface = config_get_path("interfaces/{$interface}");
6523
	if (is_array($iface)) {
6524
		switch ($iface['ipaddr']) {
6525
			case 'pppoe':
6526
			case 'l2tp':
6527
			case 'pptp':
6528
			case 'ppp':
6529
				if (($iface['ipaddrv6'] == 'dhcp6') ||
6530
				    ($iface['ipaddrv6'] == 'slaac')) {
6531
					$realif = get_real_interface($interface, 'inet6', false);
6532
				}
6533
				break;
6534
		}
6535
		if (is_ipaddrv6($iface['ipaddrv6'])) {
6536
			return ($iface['ipaddrv6']);
6537
		}
6538
	}
6539

    
6540
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6541
	$checkif = is_array($iface) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6542
	if (config_get_path("interfaces/{$checkif}/ipaddrv6", "") == 'track6') {
6543
		$curip = get_interface_track6ip($checkif);
6544
		if ($curip) {
6545
			return $curip[0];
6546
		}
6547
	}
6548

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

    
6573
function get_interface_linklocal($interface = "wan") {
6574

    
6575
	$realif = get_failover_interface($interface, 'inet6');
6576
	if (!$realif) {
6577
		return null;
6578
	}
6579

    
6580
	if (substr($interface, 0, 4) == '_vip') {
6581
		$realif = get_real_interface($interface);
6582
	} elseif (substr($interface, 0, 5) == '_lloc') {
6583
		$realif = get_real_interface(substr($interface, 5));
6584
	}
6585

    
6586
	$curip = find_interface_ipv6_ll($realif);
6587
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6588
		return $curip;
6589
	} else {
6590
		return null;
6591
	}
6592
}
6593

    
6594
function get_interface_track6ip($interface = "wan") {
6595
	$realif = get_real_interface($interface);
6596
	$vips = get_configured_vip_list('inet6');
6597

    
6598
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6599
		list($ip, $bits) = explode("/", $ifaddr);
6600
		$ip = text_to_compressed_ip6($ip);
6601
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6602
			if (is_array($vips) && !empty($vips)) {
6603
				foreach ($vips as $vip) {
6604
					if ($ip == text_to_compressed_ip6($vip)) {
6605
						continue 2;
6606
					}
6607
				}
6608
			}
6609
			return array($ip, $bits);
6610
		}
6611
	}
6612
	return false;
6613
}
6614

    
6615
function get_interface_subnet($interface = "wan") {
6616
	if (substr($interface, 0, 4) == '_vip') {
6617
		return (get_configured_vip_subnetv4($interface));
6618
	}
6619

    
6620
	$iface = config_get_path("interfaces/{$interface}");
6621
	if (is_array($iface) && !empty($iface['subnet']) && is_ipaddrv4($iface['ipaddr'])) {
6622
		return ($iface['subnet']);
6623
	}
6624

    
6625
	$realif = get_real_interface($interface);
6626
	if (!$realif) {
6627
		return (NULL);
6628
	}
6629

    
6630
	$cursn = find_interface_subnet($realif);
6631
	if (!empty($cursn)) {
6632
		return ($cursn);
6633
	}
6634

    
6635
	return (NULL);
6636
}
6637

    
6638
function get_interface_subnetv6($interface = "wan") {
6639
	if (substr($interface, 0, 4) == '_vip') {
6640
		return (get_configured_vip_subnetv6($interface));
6641
	} elseif (substr($interface, 0, 5) == '_lloc') {
6642
		$interface = substr($interface, 5);
6643
	}
6644

    
6645
	$iface = config_get_path("interfaces/{$interface}");
6646
	if (is_array($iface) && !empty($iface['subnetv6']) && is_ipaddrv6($iface['ipaddrv6'])) {
6647
		return ($iface['subnetv6']);
6648
	}
6649

    
6650
	$realif = get_real_interface($interface, 'inet6');
6651
	if (!$realif) {
6652
		return (NULL);
6653
	}
6654

    
6655
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6656
	if (config_get_path("interfaces/{$interface}/ipaddrv6") == 'track6') {
6657
		$curip = get_interface_track6ip($interface);
6658
		if ($curip) {
6659
			return $curip[1];
6660
		}
6661
	}
6662

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

    
6668
	return (NULL);
6669
}
6670

    
6671
/* return outside interfaces with a gateway */
6672
function get_interfaces_with_gateway() {
6673

    
6674
	$ints = array();
6675

    
6676
	/* loop interfaces, check config for outbound */
6677
	foreach (config_get_path('interfaces', []) as $ifdescr => $ifname) {
6678
		switch ($ifname['ipaddr']) {
6679
			case "dhcp":
6680
			case "pppoe":
6681
			case "pptp":
6682
			case "l2tp":
6683
			case "ppp":
6684
				$ints[$ifdescr] = $ifdescr;
6685
				break;
6686
			default:
6687
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6688
				    !empty($ifname['gateway'])) {
6689
					$ints[$ifdescr] = $ifdescr;
6690
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6691
				    !empty($ifname['gateway'])) {
6692
					$ints[$ifdescr] = $ifdescr;
6693
				}
6694

    
6695
				break;
6696
		}
6697
	}
6698
	return $ints;
6699
}
6700

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

    
6736
	return false;
6737
}
6738

    
6739
/* return true if interface has a gateway */
6740
function interface_has_gatewayv6($friendly) {
6741
	$ifname = config_get_path("interfaces/{$friendly}");
6742
	if (!empty($ifname)) {
6743
		switch ($ifname['ipaddrv6']) {
6744
			case "slaac":
6745
			case "dhcp6":
6746
			case "6to4":
6747
			case "6rd":
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_ipv6($ifname['if'])) {
6758
						return true;
6759
					}
6760
				}
6761
				if (!empty($ifname['gatewayv6'])) {
6762
					return true;
6763
				}
6764
				break;
6765
		}
6766
	}
6767

    
6768
	return false;
6769
}
6770

    
6771
/****f* interfaces/is_altq_capable
6772
 * NAME
6773
 *   is_altq_capable - Test if interface is capable of using ALTQ
6774
 * INPUTS
6775
 *   $int            - string containing interface name
6776
 * RESULT
6777
 *   boolean         - true or false
6778
 ******/
6779

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

    
6795
	$int_family = remove_ifindex($int);
6796

    
6797
	if (in_array($int_family, $capable)) {
6798
		return true;
6799
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6800
		return true;
6801
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6802
		return true;
6803
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6804
		return true;
6805
	} else {
6806
		return false;
6807
	}
6808
}
6809

    
6810
/****f* interfaces/is_interface_wireless
6811
 * NAME
6812
 *   is_interface_wireless - Returns if an interface is wireless
6813
 * RESULT
6814
 *   $tmp       - Returns if an interface is wireless
6815
 ******/
6816
function is_interface_wireless($interface) {
6817
	global $g;
6818

    
6819
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6820
	if (config_get_path("interfaces/{$friendly}/wireless") === null) {
6821
		if (preg_match(g_get('wireless_regex'), $interface)) {
6822
			init_config_arr(['interfaces', $friendly, 'wireless']);
6823
			return true;
6824
		}
6825
		return false;
6826
	} else {
6827
		return true;
6828
	}
6829
}
6830

    
6831
function get_wireless_modes($interface) {
6832
	/* return wireless modes and channels */
6833
	$wireless_modes = array();
6834

    
6835
	$cloned_interface = get_real_interface($interface);
6836

    
6837
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6838
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6839
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6840
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6841

    
6842
		$interface_channels = [];
6843
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6844
		$interface_channel_count = count($interface_channels);
6845

    
6846
		$c = 0;
6847
		while ($c < $interface_channel_count) {
6848
			$channel_line = explode(",", $interface_channels["$c"]);
6849
			$wireless_mode = trim($channel_line[0]);
6850
			$wireless_channel = trim($channel_line[1]);
6851
			if (trim($wireless_mode) != "") {
6852
				/* if we only have 11g also set 11b channels */
6853
				if ($wireless_mode == "11g") {
6854
					if (!isset($wireless_modes["11b"])) {
6855
						$wireless_modes["11b"] = array();
6856
					}
6857
				} elseif ($wireless_mode == "11g ht") {
6858
					if (!isset($wireless_modes["11b"])) {
6859
						$wireless_modes["11b"] = array();
6860
					}
6861
					if (!isset($wireless_modes["11g"])) {
6862
						$wireless_modes["11g"] = array();
6863
					}
6864
					$wireless_mode = "11ng";
6865
				} elseif ($wireless_mode == "11a ht") {
6866
					if (!isset($wireless_modes["11a"])) {
6867
						$wireless_modes["11a"] = array();
6868
					}
6869
					$wireless_mode = "11na";
6870
				}
6871
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6872
			}
6873
			$c++;
6874
		}
6875
	}
6876
	return($wireless_modes);
6877
}
6878

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

    
6884
		$interface_channels = [];
6885
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6886
		return $interface_channels;
6887
}
6888

    
6889
/* return wireless HT modes */
6890
function get_wireless_ht_modes($interface) {
6891
	$wireless_hts_supported = array(0 => gettext('Auto'));
6892

    
6893
	$cloned_interface = get_real_interface($interface);
6894

    
6895
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6896
		$interface_channels = get_wireless_channels($cloned_interface);
6897

    
6898
		foreach ($interface_channels as $channel) {
6899
			$channel_line = explode(",", $channel);
6900
			$wireless_ht = trim($channel_line[1]);
6901
			if (!empty($wireless_ht)) {
6902
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6903
			}
6904
		}
6905
	}
6906
	return($wireless_hts_supported);
6907
}
6908

    
6909
/* return wireless HT by channel/standard */
6910
function get_wireless_ht_list($interface) {
6911
	$wireless_hts = array();
6912

    
6913
	$cloned_interface = get_real_interface($interface);
6914

    
6915
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6916
		$interface_channels = get_wireless_channels($cloned_interface);
6917
		$interface_channel_count = count($interface_channels);
6918

    
6919
		$c = 0;
6920
		while ($c < $interface_channel_count) {
6921
			$channel_line = explode(",", $interface_channels["$c"]);
6922
			$wireless_mode = trim($channel_line[0]);
6923
			$wireless_ht = trim($channel_line[1]);
6924
			$wireless_channel = trim($channel_line[2]);
6925
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
6926
				if ($wireless_mode == "11g") {
6927
					if (!isset($wireless_modes["11g"])) {
6928
						$wireless_hts["11g"] = array();
6929
					}
6930
					$wireless_mode = "11ng";
6931
				} elseif ($wireless_mode == "11a") {
6932
					if (!isset($wireless_modes["11a"])) {
6933
						$wireless_hts["11a"] = array();
6934
					}
6935
					$wireless_mode = "11na";
6936
				}
6937
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
6938
			}
6939
			$c++;
6940
		}
6941
	}
6942
	return($wireless_hts);
6943
}
6944

    
6945
/* return channel numbers, frequency, max txpower, and max regulation txpower */
6946
function get_wireless_channel_info($interface) {
6947
	$wireless_channels = array();
6948

    
6949
	$cloned_interface = get_real_interface($interface);
6950

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

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

    
6959
		foreach ($interface_channels as $channel_line) {
6960
			$channel_line = explode(",", $channel_line);
6961
			if (!isset($wireless_channels[$channel_line[0]])) {
6962
				$wireless_channels[$channel_line[0]] = $channel_line;
6963
			}
6964
		}
6965
	}
6966
	return($wireless_channels);
6967
}
6968

    
6969
function set_interface_mtu($interface, $mtu) {
6970

    
6971
	/* LAGG interface must be destroyed and re-created to change MTU */
6972
	if ((substr($interface, 0, 4) == 'lagg') &&
6973
	    (!strstr($interface, "."))) {
6974
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
6975
			if ($lagg['laggif'] == $interface) {
6976
				interface_lagg_configure($lagg);
6977
				break;
6978
			}
6979
		}
6980
	} else {
6981
		pfSense_interface_mtu($interface, $mtu);
6982
		set_ipv6routes_mtu($interface, $mtu);
6983
	}
6984
}
6985

    
6986
/****f* interfaces/get_interface_mtu
6987
 * NAME
6988
 *   get_interface_mtu - Return the mtu of an interface
6989
 * RESULT
6990
 *   $tmp       - Returns the mtu of an interface
6991
 ******/
6992
function get_interface_mtu($interface) {
6993
	$mtu = pfSense_interface_getmtu($interface);
6994
	return $mtu['mtu'];
6995
}
6996

    
6997
function get_interface_mac($interface) {
6998
	$macinfo = get_interface_addresses($interface);
6999
	return $macinfo["macaddr"];
7000
}
7001

    
7002
function get_interface_vendor_mac($interface) {
7003
	global $g;
7004

    
7005
	$macinfo = get_interface_addresses($interface);
7006
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7007
	    "00:00:00:00:00:00") {
7008
		return ($macinfo["hwaddr"]);
7009
	}
7010

    
7011
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7012
	if (file_exists($hwaddr_file)) {
7013
		$macaddr = trim(file_get_contents($hwaddr_file));
7014
		if (is_macaddr($macaddr)) {
7015
			return ($macaddr);
7016
		}
7017
	} elseif (is_macaddr($macinfo['macaddr'])) {
7018
		/* Save original macaddress to be restored when necessary */
7019
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7020
	}
7021

    
7022
	return (NULL);
7023
}
7024

    
7025
/****f* pfsense-utils/generate_random_mac_address
7026
 * NAME
7027
 *   generate_random_mac - generates a random mac address
7028
 * INPUTS
7029
 *   none
7030
 * RESULT
7031
 *   $mac - a random mac address
7032
 ******/
7033
function generate_random_mac_address() {
7034
	$mac = "02";
7035
	for ($x = 0; $x < 5; $x++) {
7036
		$mac .= ":" . dechex(rand(16, 255));
7037
	}
7038
	return $mac;
7039
}
7040

    
7041
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7042
	global $g;
7043

    
7044
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7045

    
7046
	if (!empty($iface) && !empty($pppif)) {
7047
		$cron_cmd = <<<EOD
7048
#!/bin/sh
7049
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7050
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7051

    
7052
EOD;
7053

    
7054
		@file_put_contents($cron_file, $cron_cmd);
7055
		chmod($cron_file, 0755);
7056
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7057
	} else {
7058
		unlink_if_exists($cron_file);
7059
	}
7060
}
7061

    
7062
function get_interface_default_mtu($type = "ethernet") {
7063
	switch ($type) {
7064
		case "gre":
7065
			return 1476;
7066
			break;
7067
		case "gif":
7068
			return 1280;
7069
			break;
7070
		case "tun":
7071
		case "vlan":
7072
		case "tap":
7073
		case "ethernet":
7074
		default:
7075
			return 1500;
7076
			break;
7077
	}
7078

    
7079
	/* Never reached */
7080
	return 1500;
7081
}
7082

    
7083
function get_vip_descr($ipaddress) {
7084

    
7085
	foreach (config_get_path('virtualip/vip', []) as $vip) {
7086
		if ($vip['subnet'] == $ipaddress) {
7087
			return ($vip['descr']);
7088
		}
7089
	}
7090
	return "";
7091
}
7092

    
7093
function interfaces_staticarp_configure($if) {
7094
	if (config_get_path('system/developerspew')) {
7095
		$mt = microtime();
7096
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7097
	}
7098

    
7099
	if (!config_path_enabled("interfaces/{$if}")) {
7100
		return 0;
7101
	}
7102

    
7103
	$ifcfg = config_get_path("interfaces/{$if}");
7104

    
7105
	/* Enable staticarp, if enabled */
7106
	$staticarp = config_get_path("dhcpd/{$if}/staticarp");
7107
	if ($staticarp) {
7108
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7109
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7110
	} else {
7111
		/*
7112
		 * Interfaces do not have staticarp enabled by default
7113
		 * Let's not disable staticarp on freshly created interfaces
7114
		 */
7115
		if (!platform_booting()) {
7116
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7117
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7118
		}
7119
	}
7120

    
7121
	/* Enable static arp entries */
7122
	$staticmap = config_get_path("dhcpd/{$if}/staticmap", []);
7123
	if (is_array($staticmap)) {
7124
		foreach ($staticmap as $arpent) {
7125
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7126
				continue;
7127
			}
7128
			if ($staticarp || isset($arpent['arp_table_static_entry'])) {
7129
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7130
			}
7131
		}
7132
	}
7133

    
7134
	return 0;
7135
}
7136

    
7137
function get_failover_interface($interface, $family = "all", $gateways_status = false) {
7138
	/* shortcut to get_real_interface if we find it in the config */
7139
	if (is_array(config_get_path("interfaces/{$interface}"))) {
7140
		return get_real_interface($interface, $family);
7141
	}
7142

    
7143
	/* compare against gateway groups */
7144
	$a_groups = return_gateway_groups_array(true, $gateways_status);
7145
	if (is_array($a_groups[$interface])) {
7146
		/* we found a gateway group, fetch the interface or vip */
7147
		if (!empty($a_groups[$interface][0]['vip'])) {
7148
			return $a_groups[$interface][0]['vip'];
7149
		} else {
7150
			return $a_groups[$interface][0]['int'];
7151
		}
7152
	}
7153
	/* fall through to get_real_interface */
7154
	/* XXX: Really needed? */
7155
	return get_real_interface($interface, $family);
7156
}
7157

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

    
7180
	if ($family == 6) {
7181
		$dhcp_string = "_DHCP6";
7182
	} else {
7183
		$dhcp_string = "_DHCP";
7184
	}
7185

    
7186
	foreach (config_get_path('gateways/gateway_group', []) as $group) {
7187
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7188
			continue;
7189
		}
7190
		foreach ($group['item'] as $item) {
7191
			$item_data = explode("|", $item);
7192
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7193
				return true;
7194
			}
7195
		}
7196
	}
7197

    
7198
	return false;
7199
}
7200

    
7201
function remove_ifindex($ifname) {
7202
	return preg_replace("/[0-9]+$/", "", $ifname);
7203
}
7204

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

    
7208
	$viplist = get_configured_vip_list($family, $type);
7209
	foreach ($viplist as $vipid => $address) {
7210
		$interfaces[$vipid] = $address;
7211
		if ($type = VIP_CARP) {
7212
			$vip = get_configured_vip($vipid);
7213
			if (isset($vip) && is_array($vip) ) {
7214
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7215
			}
7216
		}
7217
		if (get_vip_descr($address)) {
7218
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7219
		}
7220
	}
7221
	return $interfaces;
7222
}
7223

    
7224
function return_gateway_groups_array_with_descr() {
7225
	$interfaces = array();
7226
	$grouplist = return_gateway_groups_array();
7227
	foreach (array_keys($grouplist) as $name) {
7228
		$interfaces[$name] = "GW Group {$name}";
7229
	}
7230
	return $interfaces;
7231
}
7232

    
7233
function get_serial_ports($short=false) {
7234
	$linklist = array();
7235
	if (!is_dir("/var/spool/lock")) {
7236
		mwexec("/bin/mkdir -p /var/spool/lock");
7237
	}
7238
	$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);
7239
	foreach ($serialports as $port) {
7240
		$port = trim($port);
7241
		$port = ($short) ? basename($port) : $port;
7242
		$linklist[$port] = $port;
7243
	}
7244
	return $linklist;
7245
}
7246

    
7247
function get_interface_ports() {
7248
	$linklist = array();
7249
	$portlist = get_interface_list();
7250

    
7251
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
7252
		if (empty($vlan)) {
7253
			continue;
7254
		}
7255
		$portlist[$vlan['vlanif']] = $vlan;
7256
	}
7257

    
7258
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
7259
		if (empty($qinq)) {
7260
			continue;
7261
		}
7262
		$members = explode(" ", $qinq['members']);
7263
		foreach ($members as $mem) {
7264
			$qentry = $qinq['vlanif'] . "." . $mem;
7265
			$portlist[$qentry] = $qentry;
7266
		}
7267
	}
7268

    
7269
	foreach ($portlist as $ifn => $ifinfo) {
7270
		$string = "";
7271
		if (is_array($ifinfo)) {
7272
			$string .= $ifn;
7273
			if ($ifinfo['mac']) {
7274
				$string .= " ({$ifinfo['mac']})";
7275
			}
7276
			if ($ifinfo['friendly']) {
7277
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7278
			} elseif ($ifinfo['descr']) {
7279
				$string .= " - {$ifinfo['descr']}";
7280
			}
7281
		} else {
7282
			$string .= $ifinfo;
7283
		}
7284

    
7285
		$linklist[$ifn] = $string;
7286
	}
7287
	return $linklist;
7288
}
7289

    
7290
function build_ppps_link_list() {
7291
	global $pconfig;
7292

    
7293
	$linklist = array('list' => array(), 'selected' => array());
7294

    
7295
	if ($pconfig['type'] == 'ppp') {
7296
		$linklist['list'] = get_serial_ports();
7297
	} else {
7298
		$iflist = get_interface_ports();
7299

    
7300
		$viplist = array();
7301
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7302
		foreach ($carplist as $vid => $vaddr) {
7303
			$vip = get_configured_vip($vid);
7304
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7305
		}
7306

    
7307
		$linklist['list'] = array_merge($iflist, $viplist);
7308

    
7309
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7310
		$lagglist = get_lagg_interface_list();
7311
		foreach ($lagglist as $lagg) {
7312
			/* LAGG members cannot be assigned */
7313
			$laggmembers = explode(',', $lagg['members']);
7314
			foreach ($laggmembers as $lagm) {
7315
				if (isset($linklist['list'][$lagm])) {
7316
					unset($linklist['list'][$lagm]);
7317
				}
7318
			}
7319
		}
7320
	}
7321

    
7322
	$selected_ports = array();
7323
	if (is_array($pconfig['interfaces'])) {
7324
		$selected_ports = $pconfig['interfaces'];
7325
	} elseif (!empty($pconfig['interfaces'])) {
7326
		$selected_ports = explode(',', $pconfig['interfaces']);
7327
	}
7328
	foreach ($selected_ports as $port) {
7329
		if (isset($linklist['list'][$port])) {
7330
			array_push($linklist['selected'], $port);
7331
		}
7332
	}
7333
	return($linklist);
7334
}
7335

    
7336
function create_interface_list($open = false) {
7337
	$iflist = array();
7338

    
7339
	// add group interfaces
7340
	config_get_path('ifgroups/ifgroupentry', []);
7341
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7342
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7343
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7344
		}
7345
	}
7346

    
7347
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7348
		if ($open || have_ruleint_access($ifent)) {
7349
			$iflist[$ifent] = $ifdesc;
7350
		}
7351
	}
7352

    
7353
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7354
		$iflist['l2tp'] = gettext('L2TP VPN');
7355
	}
7356

    
7357
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7358
		$iflist['pppoe'] = gettext("PPPoE Server");
7359
	}
7360

    
7361
	// add ipsec interfaces
7362
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7363
		$iflist["enc0"] = gettext("IPsec");
7364
	}
7365

    
7366
	// add openvpn/tun interfaces
7367
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7368
		$iflist["openvpn"] = gettext("OpenVPN");
7369
	}
7370

    
7371
	return($iflist);
7372
}
7373

    
7374
function is_pseudo_interface($inf, $tap=true) {
7375
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7376
	foreach ($psifs as $pif) {
7377
		if (substr($inf, 0, strlen($pif)) == $pif) {
7378
			if (($pif == 'ovpn') && $tap) {
7379
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7380
				$type = ($m[1] == 'c') ? 'client' : 'server';
7381
				foreach (config_get_path("openvpn/openvpn-{$type}", []) as $ovpn) {
7382
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7383
						return false;
7384
					} elseif ($ovpn['vpnid'] == $m[2]) {
7385
						return true;
7386
					}
7387
				}
7388
			} else {
7389
				return true;
7390
			}
7391
		}
7392
	}
7393
	return false;
7394
}
7395

    
7396
function is_stf_interface($inf) {
7397
	switch (config_get_path("interfaces/{$inf}/ipaddrv6")) {
7398
		case '6rd':
7399
		case '6to4':
7400
			return true;
7401
		default:
7402
			return false;
7403
	}
7404
}
7405

    
7406
function restart_interface_services($interface, $ipv6type = "") {
7407

    
7408
	services_unbound_configure(true, $interface);
7409

    
7410
	services_igmpproxy_configure($interface);
7411
	services_snmpd_configure($interface);
7412
	vpn_l2tp_configure($interface);
7413

    
7414
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7415
		openvpn_resync_all($interface);
7416
	}
7417
	ipsec_force_reload($interface);
7418

    
7419
	/* restart RADVD to announce correct IPv6 prefix
7420
	 * see https://redmine.pfsense.org/issues/12604 */
7421
	if ((($ipv6type == "staticv6") || ($ipv6type == "track6")) &&
7422
	    (config_get_path("dhcpdv6/{$interface}/ramode", "disabled") != "disabled")) {
7423
		services_radvd_configure();
7424
	}
7425

    
7426
	if (config_path_enabled("dhcpd/{$interface}") ||
7427
	    config_path_enabled("dhcpdv6/{$interface}")) {
7428
		services_dhcpd_configure();
7429
	}
7430

    
7431
	init_config_arr(array('syslog'));
7432
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7433
		system_syslogd_start();
7434
	}
7435
}
7436

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

    
7478
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7479
		$vip = get_configured_vip($viface);
7480
		if (is_ipaddrv4($vip['subnet'])) {
7481
			array_push($v4vips, $vip['subnet']);
7482
		} else if (is_ipaddrv6($vip['subnet'])) {
7483
			array_push($v6vips, Net_IPv6::Uncompress($vip['subnet']));
7484
		}
7485
	}
7486

    
7487
	if ($ifaddrs['addrs']) {
7488
		$v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7489
			return (array_search($addr['addr'], $v4vips) === false);
7490
		});
7491
	}
7492

    
7493
	if ($ifaddrs['addrs6']) {
7494
		$v6addrs = array_filter($ifaddrs['addrs6'], function($addr) use ($v6vips){
7495
			return (array_search(Net_IPv6::Uncompress($addr['addr']), $v6vips) === false);
7496
		});
7497
	}
7498
	/* Transform output to conform to pfSense_get_interface_addresses() */
7499
	if ($v4addrs) {
7500
		$v4addr = array_shift($v4addrs);
7501
		$ifaddrs['ipaddr'] = $v4addr['addr'];
7502
		foreach(array("subnetbits", "subnet", "broadcast", "tunnel") as $key) {
7503
			if (array_key_exists($key, $v4addr)) {
7504
				$ifaddrs[$key] = $v4addr[$key];
7505
			}
7506
		}
7507
	}
7508

    
7509
	if ($v6addrs) {
7510
		// use the first IPv6 GUA address if one exists, otherwise the first address
7511
		$v6addr = $v6addrs[array_key_first($v6addrs)];
7512
		foreach ($v6addrs as $addr) {
7513
			if (is_v6gua($addr['addr'])) {
7514
				$v6addr = $addr;
7515
				break;
7516
			}
7517
		}
7518
		$ifaddrs['ipaddr6'] = $v6addr['addr'];
7519
		foreach(array("subnetbits", "tunnel") as $key) {
7520
			if (array_key_exists($key, $v6addr)) {
7521
				$ifaddrs[$key.'6'] = $v6addr[$key];
7522
			}
7523
		}
7524
		if (array_key_exists('tentative', $v6addr)) {
7525
			$ifaddrs['tentative'] = $v6addr['tentative'];
7526
		}
7527
	}
7528
	unset($ifaddrs['addrs']);
7529
	unset($ifaddrs['addrs6']);
7530

    
7531
	return($ifaddrs);
7532
}
7533

    
7534
/**
7535
 * Returns all interface addresses, including IPv6 LL addresses.
7536
 * XXX: Review/refactor functions used to retrieve interfaces addresses.
7537
 */
7538
function get_interface_addresses_all(string $interface): array {
7539
	$addresses = [];
7540

    
7541
	// Get primary IPv4/6 addresses
7542
	$addresses_primary = get_interface_addresses($interface);
7543
	if (!empty($addresses_primary['ipaddr'])) {
7544
		$addresses[] = $addresses_primary['ipaddr'];
7545
	}
7546
	if (!empty($addresses_primary['ipaddr6'])) {
7547
		$addresses[] = $addresses_primary['ipaddr6'];
7548
	}
7549

    
7550
	// Get IPv6 link-local address
7551
	$addresses_linklocal = find_interface_ipv6_ll($interface);
7552
	if (!empty($addresses_linklocal)) {
7553
		$addresses_linklocal_pos = strpos($addresses_linklocal, '%');
7554
		if ($addresses_linklocal_pos !== false) {
7555
			$addresses_linklocal = substr($addresses_linklocal, 0, $addresses_linklocal_pos);
7556
		}
7557
		$addresses[] = $addresses_linklocal;
7558
	}
7559

    
7560
	// Get VIPs
7561
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7562
		$vip = get_configured_vip($viface);
7563
		if ($vip['interface'] == $interface && !empty($vip['subnet'])) {
7564
			$addresses[] = $vip['subnet'];
7565
		}
7566
	}
7567

    
7568
	return $addresses;
7569
}
7570
?>
(22-22/61)